////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool BaseKeyboardState::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // IsKeyDown ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "IsKeyDown") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); int vKey; if (val->_type == VAL_STRING && strlen(val->getString()) > 0) { const char *str = val->getString(); char temp = str[0]; if (temp >= 'A' && temp <= 'Z') { temp += ('a' - 'A'); } vKey = (int)temp; } else { vKey = val->getInt(); } bool isDown = _keyStates[vKeyToKeyCode(vKey)]; stack->pushBool(isDown); return STATUS_OK; } else { return BaseScriptable::scCallMethod(script, stack, thisStack, name); } }
void ScStack::correctParams(uint32 expectedParams) { uint32 nuParams = (uint32)pop()->getInt(); if (expectedParams < nuParams) { // too many params while (expectedParams < nuParams) { //Pop(); delete _values[_sP - expectedParams]; _values.remove_at(_sP - expectedParams); nuParams--; _sP--; } } else if (expectedParams > nuParams) { // need more params while (expectedParams > nuParams) { //Push(null_val); ScValue *nullVal = new ScValue(_gameRef); nullVal->setNULL(); _values.insert_at(_sP - nuParams + 1, nullVal); nuParams++; _sP++; if ((int32)_values.size() > _sP + 1) { delete _values[_values.size() - 1]; _values.remove_at(_values.size() - 1); } } } }
void ScStack::push(ScValue *val) { _sP++; if (_sP < (int32)_values.size()) { _values[_sP]->cleanup(); _values[_sP]->copy(val); } else { ScValue *copyVal = new ScValue(_gameRef); copyVal->copy(val); _values.add(copyVal); } }
bool Console::Cmd_Set(int argc, const char **argv) { if (argc == 4 && !strncmp("=", argv[2], 1)) { ScValue *val = nullptr; Error error = CONTROLLER->setValue(argv[1], argv[3], val); if (error.getErrorLevel() == SUCCESS) { assert(val); debugPrintf("%s = %s\n", argv[1], val->getString()); } else { printError(argv[0], error); } } else { printUsage(argv[0]); } return true; }
SXFile::SXFile(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) { stack->correctParams(1); ScValue *val = stack->pop(); _filename = nullptr; if (!val->isNULL()) { BaseUtils::setString(&_filename, val->getString()); } _readFile = nullptr; _writeFile = nullptr; _mode = 0; _textMode = false; }
bool ScValue::setProp(const char *name, ScValue *val, bool copyWhole, bool setAsConst) { if (_type == VAL_VARIABLE_REF) { return _valRef->setProp(name, val); } bool ret = STATUS_FAILED; if (_type == VAL_NATIVE && _valNative) { ret = _valNative->scSetProperty(name, val); } if (DID_FAIL(ret)) { ScValue *newVal = nullptr; _valIter = _valObject.find(name); if (_valIter != _valObject.end()) { newVal = _valIter->_value; } if (!newVal) { newVal = new ScValue(_gameRef); } else { newVal->cleanup(); } newVal->copy(val, copyWhole); newVal->_isConstVar = setAsConst; _valObject[name] = newVal; if (_type != VAL_NATIVE) { _type = VAL_OBJECT; } /* _valIter = _valObject.find(Name); if (_valIter != _valObject.end()) { delete _valIter->_value; _valIter->_value = nullptr; } ScValue* val = new ScValue(_gameRef); val->Copy(Val, CopyWhole); val->_isConstVar = SetAsConst; _valObject[Name] = val; if (_type!=VAL_NATIVE) _type = VAL_OBJECT; */ } return STATUS_OK; }
SXDate::SXDate(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) { stack->correctParams(6); memset(&_tm, 0, sizeof(_tm)); ScValue *valYear = stack->pop(); _tm.tm_year = valYear->getInt() - 1900; _tm.tm_mon = stack->pop()->getInt() - 1; _tm.tm_mday = stack->pop()->getInt(); _tm.tm_hour = stack->pop()->getInt(); _tm.tm_min = stack->pop()->getInt(); _tm.tm_sec = stack->pop()->getInt(); if (valYear->isNULL()) { g_system->getTimeAndDate(_tm); } }
ScValue *ScScript::getVar(char *name) { ScValue *ret = nullptr; // scope locals if (_scopeStack->_sP >= 0) { if (_scopeStack->getTop()->propExists(name)) { ret = _scopeStack->getTop()->getProp(name); } } // script globals if (ret == nullptr) { if (_globals->propExists(name)) { ret = _globals->getProp(name); } } // engine globals if (ret == nullptr) { if (_engine->_globals->propExists(name)) { ret = _engine->_globals->getProp(name); } } if (ret == nullptr) { //RuntimeError("Variable '%s' is inaccessible in the current block. Consider changing the script.", name); _gameRef->LOG(0, "Warning: variable '%s' is inaccessible in the current block. Consider changing the script (script:%s, line:%d)", name, _filename, _currentLine); ScValue *val = new ScValue(_gameRef); ScValue *scope = _scopeStack->getTop(); if (scope) { scope->setProp(name, val); ret = _scopeStack->getTop()->getProp(name); } else { _globals->setProp(name, val); ret = _globals->getProp(name); } delete val; } return ret; }
SXString::SXString(BaseGame *inGame, ScStack *stack) : BaseScriptable(inGame) { _string = nullptr; _capacity = 0; stack->correctParams(1); ScValue *val = stack->pop(); if (val->isInt()) { _capacity = MAX(0, val->getInt()); if (_capacity > 0) { _string = new char[_capacity]; memset(_string, 0, _capacity); } } else { setStringVal(val->getString()); } if (_capacity == 0) { setStringVal(""); } }
bool ScScript::executeInstruction() { bool ret = STATUS_OK; uint32 dw; const char *str = nullptr; //ScValue* op = new ScValue(_gameRef); _operand->cleanup(); ScValue *op1; ScValue *op2; uint32 inst = getDWORD(); switch (inst) { case II_DEF_VAR: _operand->setNULL(); dw = getDWORD(); if (_scopeStack->_sP < 0) { _globals->setProp(_symbols[dw], _operand); } else { _scopeStack->getTop()->setProp(_symbols[dw], _operand); } break; case II_DEF_GLOB_VAR: case II_DEF_CONST_VAR: { dw = getDWORD(); /* char *temp = _symbols[dw]; // TODO delete */ // only create global var if it doesn't exist if (!_engine->_globals->propExists(_symbols[dw])) { _operand->setNULL(); _engine->_globals->setProp(_symbols[dw], _operand, false, inst == II_DEF_CONST_VAR); } break; } case II_RET: if (_scopeStack->_sP >= 0 && _callStack->_sP >= 0) { _scopeStack->pop(); _iP = (uint32)_callStack->pop()->getInt(); } else { if (_thread) { _state = SCRIPT_THREAD_FINISHED; } else { if (_numEvents == 0 && _numMethods == 0) { _state = SCRIPT_FINISHED; } else { _state = SCRIPT_PERSISTENT; } } } break; case II_RET_EVENT: _state = SCRIPT_FINISHED; break; case II_CALL: dw = getDWORD(); _operand->setInt(_iP); _callStack->push(_operand); _iP = dw; break; case II_CALL_BY_EXP: { // push var // push string str = _stack->pop()->getString(); char *methodName = new char[strlen(str) + 1]; strcpy(methodName, str); ScValue *var = _stack->pop(); if (var->_type == VAL_VARIABLE_REF) { var = var->_valRef; } bool res = STATUS_FAILED; bool triedNative = false; // we are already calling this method, try native if (_thread && _methodThread && strcmp(methodName, _threadEvent) == 0 && var->_type == VAL_NATIVE && _owner == var->getNative()) { triedNative = true; res = var->_valNative->scCallMethod(this, _stack, _thisStack, methodName); } if (DID_FAIL(res)) { if (var->isNative() && var->getNative()->canHandleMethod(methodName)) { if (!_unbreakable) { _waitScript = var->getNative()->invokeMethodThread(methodName); if (!_waitScript) { _stack->correctParams(0); runtimeError("Error invoking method '%s'.", methodName); _stack->pushNULL(); } else { _state = SCRIPT_WAITING_SCRIPT; _waitScript->copyParameters(_stack); } } else { // can call methods in unbreakable mode _stack->correctParams(0); runtimeError("Cannot call method '%s'. Ignored.", methodName); _stack->pushNULL(); } delete[] methodName; break; } /* ScValue* val = var->getProp(MethodName); if (val) { dw = GetFuncPos(val->getString()); if (dw==0) { TExternalFunction* f = GetExternal(val->getString()); if (f) { ExternalCall(_stack, _thisStack, f); } else{ // not an internal nor external, try for native function _gameRef->ExternalCall(this, _stack, _thisStack, val->getString()); } } else{ _operand->setInt(_iP); _callStack->Push(_operand); _iP = dw; } } */ else { res = STATUS_FAILED; if (var->_type == VAL_NATIVE && !triedNative) { res = var->_valNative->scCallMethod(this, _stack, _thisStack, methodName); } if (DID_FAIL(res)) { _stack->correctParams(0); runtimeError("Call to undefined method '%s'. Ignored.", methodName); _stack->pushNULL(); } } } delete[] methodName; } break; case II_EXTERNAL_CALL: { uint32 symbolIndex = getDWORD(); TExternalFunction *f = getExternal(_symbols[symbolIndex]); if (f) { externalCall(_stack, _thisStack, f); } else { _gameRef->externalCall(this, _stack, _thisStack, _symbols[symbolIndex]); } break; } case II_SCOPE: _operand->setNULL(); _scopeStack->push(_operand); break; case II_CORRECT_STACK: dw = getDWORD(); // params expected _stack->correctParams(dw); break; case II_CREATE_OBJECT: _operand->setObject(); _stack->push(_operand); break; case II_POP_EMPTY: _stack->pop(); break; case II_PUSH_VAR: { ScValue *var = getVar(_symbols[getDWORD()]); if (false && /*var->_type==VAL_OBJECT ||*/ var->_type == VAL_NATIVE) { _operand->setReference(var); _stack->push(_operand); } else { _stack->push(var); } break; } case II_PUSH_VAR_REF: { ScValue *var = getVar(_symbols[getDWORD()]); _operand->setReference(var); _stack->push(_operand); break; } case II_POP_VAR: { char *varName = _symbols[getDWORD()]; ScValue *var = getVar(varName); if (var) { ScValue *val = _stack->pop(); if (!val) { runtimeError("Script stack corruption detected. Please report this script at WME bug reports forum."); var->setNULL(); } else { if (val->getType() == VAL_VARIABLE_REF) { val = val->_valRef; } if (val->_type == VAL_NATIVE) { var->setValue(val); } else { var->copy(val); } } } break; } case II_PUSH_VAR_THIS: _stack->push(_thisStack->getTop()); break; case II_PUSH_INT: _stack->pushInt((int)getDWORD()); break; case II_PUSH_FLOAT: _stack->pushFloat(getFloat()); break; case II_PUSH_BOOL: _stack->pushBool(getDWORD() != 0); break; case II_PUSH_STRING: _stack->pushString(getString()); break; case II_PUSH_NULL: _stack->pushNULL(); break; case II_PUSH_THIS_FROM_STACK: _operand->setReference(_stack->getTop()); _thisStack->push(_operand); break; case II_PUSH_THIS: _operand->setReference(getVar(_symbols[getDWORD()])); _thisStack->push(_operand); break; case II_POP_THIS: _thisStack->pop(); break; case II_PUSH_BY_EXP: { str = _stack->pop()->getString(); ScValue *val = _stack->pop()->getProp(str); if (val) { _stack->push(val); } else { _stack->pushNULL(); } break; } case II_POP_BY_EXP: { str = _stack->pop()->getString(); ScValue *var = _stack->pop(); ScValue *val = _stack->pop(); if (val == nullptr) { runtimeError("Script stack corruption detected. Please report this script at WME bug reports forum."); var->setNULL(); } else { var->setProp(str, val); } break; } case II_PUSH_REG1: _stack->push(_reg1); break; case II_POP_REG1: _reg1->copy(_stack->pop()); break; case II_JMP: _iP = getDWORD(); break; case II_JMP_FALSE: { dw = getDWORD(); //if (!_stack->pop()->getBool()) _iP = dw; ScValue *val = _stack->pop(); if (!val) { runtimeError("Script corruption detected. Did you use '=' instead of '==' for comparison?"); } else { if (!val->getBool()) { _iP = dw; } } break; } case II_ADD: op2 = _stack->pop(); op1 = _stack->pop(); if (op1->isNULL() || op2->isNULL()) { _operand->setNULL(); } else if (op1->getType() == VAL_STRING || op2->getType() == VAL_STRING) { char *tempStr = new char [strlen(op1->getString()) + strlen(op2->getString()) + 1]; strcpy(tempStr, op1->getString()); strcat(tempStr, op2->getString()); _operand->setString(tempStr); delete[] tempStr; } else if (op1->getType() == VAL_INT && op2->getType() == VAL_INT) { _operand->setInt(op1->getInt() + op2->getInt()); } else { _operand->setFloat(op1->getFloat() + op2->getFloat()); } _stack->push(_operand); break; case II_SUB: op2 = _stack->pop(); op1 = _stack->pop(); if (op1->isNULL() || op2->isNULL()) { _operand->setNULL(); } else if (op1->getType() == VAL_INT && op2->getType() == VAL_INT) { _operand->setInt(op1->getInt() - op2->getInt()); } else { _operand->setFloat(op1->getFloat() - op2->getFloat()); } _stack->push(_operand); break; case II_MUL: op2 = _stack->pop(); op1 = _stack->pop(); if (op1->isNULL() || op2->isNULL()) { _operand->setNULL(); } else if (op1->getType() == VAL_INT && op2->getType() == VAL_INT) { _operand->setInt(op1->getInt() * op2->getInt()); } else { _operand->setFloat(op1->getFloat() * op2->getFloat()); } _stack->push(_operand); break; case II_DIV: op2 = _stack->pop(); op1 = _stack->pop(); if (op2->getFloat() == 0.0f) { runtimeError("Division by zero."); } if (op1->isNULL() || op2->isNULL() || op2->getFloat() == 0.0f) { _operand->setNULL(); } else { _operand->setFloat(op1->getFloat() / op2->getFloat()); } _stack->push(_operand); break; case II_MODULO: op2 = _stack->pop(); op1 = _stack->pop(); if (op2->getInt() == 0) { runtimeError("Division by zero."); } if (op1->isNULL() || op2->isNULL() || op2->getInt() == 0) { _operand->setNULL(); } else { _operand->setInt(op1->getInt() % op2->getInt()); } _stack->push(_operand); break; case II_NOT: op1 = _stack->pop(); //if (op1->isNULL()) _operand->setNULL(); if (op1->isNULL()) { _operand->setBool(true); } else { _operand->setBool(!op1->getBool()); } _stack->push(_operand); break; case II_AND: op2 = _stack->pop(); op1 = _stack->pop(); if (op1 == nullptr || op2 == nullptr) { runtimeError("Script corruption detected. Did you use '=' instead of '==' for comparison?"); _operand->setBool(false); } else { _operand->setBool(op1->getBool() && op2->getBool()); } _stack->push(_operand); break; case II_OR: op2 = _stack->pop(); op1 = _stack->pop(); if (op1 == nullptr || op2 == nullptr) { runtimeError("Script corruption detected. Did you use '=' instead of '==' for comparison?"); _operand->setBool(false); } else { _operand->setBool(op1->getBool() || op2->getBool()); } _stack->push(_operand); break; case II_CMP_EQ: op2 = _stack->pop(); op1 = _stack->pop(); /* if ((op1->isNULL() && !op2->isNULL()) || (!op1->isNULL() && op2->isNULL())) _operand->setBool(false); else if (op1->isNative() && op2->isNative()) { _operand->setBool(op1->getNative() == op2->getNative()); } else if (op1->getType()==VAL_STRING || op2->getType()==VAL_STRING) { _operand->setBool(scumm_stricmp(op1->getString(), op2->getString())==0); } else if (op1->getType()==VAL_FLOAT && op2->getType()==VAL_FLOAT) { _operand->setBool(op1->getFloat() == op2->getFloat()); } else{ _operand->setBool(op1->getInt() == op2->getInt()); } */ _operand->setBool(ScValue::compare(op1, op2) == 0); _stack->push(_operand); break; case II_CMP_NE: op2 = _stack->pop(); op1 = _stack->pop(); /* if ((op1->isNULL() && !op2->isNULL()) || (!op1->isNULL() && op2->isNULL())) _operand->setBool(true); else if (op1->isNative() && op2->isNative()) { _operand->setBool(op1->getNative() != op2->getNative()); } else if (op1->getType()==VAL_STRING || op2->getType()==VAL_STRING) { _operand->setBool(scumm_stricmp(op1->getString(), op2->getString())!=0); } else if (op1->getType()==VAL_FLOAT && op2->getType()==VAL_FLOAT) { _operand->setBool(op1->getFloat() != op2->getFloat()); } else{ _operand->setBool(op1->getInt() != op2->getInt()); } */ _operand->setBool(ScValue::compare(op1, op2) != 0); _stack->push(_operand); break; case II_CMP_L: op2 = _stack->pop(); op1 = _stack->pop(); /* if (op1->getType()==VAL_FLOAT && op2->getType()==VAL_FLOAT) { _operand->setBool(op1->getFloat() < op2->getFloat()); } else _operand->setBool(op1->getInt() < op2->getInt()); */ _operand->setBool(ScValue::compare(op1, op2) < 0); _stack->push(_operand); break; case II_CMP_G: op2 = _stack->pop(); op1 = _stack->pop(); /* if (op1->getType()==VAL_FLOAT && op2->getType()==VAL_FLOAT) { _operand->setBool(op1->getFloat() > op2->getFloat()); } else _operand->setBool(op1->getInt() > op2->getInt()); */ _operand->setBool(ScValue::compare(op1, op2) > 0); _stack->push(_operand); break; case II_CMP_LE: op2 = _stack->pop(); op1 = _stack->pop(); /* if (op1->getType()==VAL_FLOAT && op2->getType()==VAL_FLOAT) { _operand->setBool(op1->getFloat() <= op2->getFloat()); } else _operand->setBool(op1->getInt() <= op2->getInt()); */ _operand->setBool(ScValue::compare(op1, op2) <= 0); _stack->push(_operand); break; case II_CMP_GE: op2 = _stack->pop(); op1 = _stack->pop(); /* if (op1->getType()==VAL_FLOAT && op2->getType()==VAL_FLOAT) { _operand->setBool(op1->getFloat() >= op2->getFloat()); } else _operand->setBool(op1->getInt() >= op2->getInt()); */ _operand->setBool(ScValue::compare(op1, op2) >= 0); _stack->push(_operand); break; case II_CMP_STRICT_EQ: op2 = _stack->pop(); op1 = _stack->pop(); //_operand->setBool(op1->getType()==op2->getType() && op1->getFloat()==op2->getFloat()); _operand->setBool(ScValue::compareStrict(op1, op2) == 0); _stack->push(_operand); break; case II_CMP_STRICT_NE: op2 = _stack->pop(); op1 = _stack->pop(); //_operand->setBool(op1->getType()!=op2->getType() || op1->getFloat()!=op2->getFloat()); _operand->setBool(ScValue::compareStrict(op1, op2) != 0); _stack->push(_operand); break; case II_DBG_LINE: { int newLine = getDWORD(); if (newLine != _currentLine) { _currentLine = newLine; } break; } default: _gameRef->LOG(0, "Fatal: Invalid instruction %d ('%s', line %d, IP:0x%x)\n", inst, _filename, _currentLine, _iP - sizeof(uint32)); _state = SCRIPT_FINISHED; ret = STATUS_FAILED; } // switch(instruction) //delete op; return ret; }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool AdActor::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // GoTo / GoToAsync ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "GoTo") == 0 || strcmp(name, "GoToAsync") == 0) { stack->correctParams(2); int x = stack->pop()->getInt(); int y = stack->pop()->getInt(); goTo(x, y); if (strcmp(name, "GoToAsync") != 0) { script->waitForExclusive(this); } stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GoToObject / GoToObjectAsync ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GoToObject") == 0 || strcmp(name, "GoToObjectAsync") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); if (!val->isNative()) { script->runtimeError("actor.%s method accepts an entity refrence only", name); stack->pushNULL(); return STATUS_OK; } AdObject *obj = (AdObject *)val->getNative(); if (!obj || obj->getType() != OBJECT_ENTITY) { script->runtimeError("actor.%s method accepts an entity refrence only", name); stack->pushNULL(); return STATUS_OK; } AdEntity *ent = (AdEntity *)obj; if (ent->getWalkToX() == 0 && ent->getWalkToY() == 0) { goTo(ent->_posX, ent->_posY); } else { goTo(ent->getWalkToX(), ent->getWalkToY(), ent->getWalkToDir()); } if (strcmp(name, "GoToObjectAsync") != 0) { script->waitForExclusive(this); } stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // TurnTo / TurnToAsync ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "TurnTo") == 0 || strcmp(name, "TurnToAsync") == 0) { stack->correctParams(1); int dir; ScValue *val = stack->pop(); // turn to object? if (val->isNative() && _gameRef->validObject((BaseObject *)val->getNative())) { BaseObject *obj = (BaseObject *)val->getNative(); int angle = (int)(atan2((double)(obj->_posY - _posY), (double)(obj->_posX - _posX)) * (180 / 3.14)); dir = (int)angleToDirection(angle); } // otherwise turn to direction else { dir = val->getInt(); } if (dir >= 0 && dir < NUM_DIRECTIONS) { turnTo((TDirection)dir); if (strcmp(name, "TurnToAsync") != 0) { script->waitForExclusive(this); } } stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // IsWalking ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "IsWalking") == 0) { stack->correctParams(0); stack->pushBool(_state == STATE_FOLLOWING_PATH); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // MergeAnims ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "MergeAnims") == 0) { stack->correctParams(1); stack->pushBool(DID_SUCCEED(mergeAnims(stack->pop()->getString()))); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // UnloadAnim ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "UnloadAnim") == 0) { stack->correctParams(1); const char *animName = stack->pop()->getString(); bool found = false; for (uint32 i = 0; i < _anims.size(); i++) { if (scumm_stricmp(_anims[i]->getName(), animName) == 0) { // invalidate sprites in use if (_anims[i]->containsSprite(_tempSprite2)) { _tempSprite2 = nullptr; } if (_anims[i]->containsSprite(_currentSprite)) { _currentSprite = nullptr; } if (_anims[i]->containsSprite(_animSprite2)) { _animSprite2 = nullptr; } delete _anims[i]; _anims[i] = nullptr; _anims.remove_at(i); i--; found = true; } } stack->pushBool(found); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // HasAnim ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "HasAnim") == 0) { stack->correctParams(1); const char *animName = stack->pop()->getString(); stack->pushBool(getAnimByName(animName) != nullptr); return STATUS_OK; } else { return AdTalkHolder::scCallMethod(script, stack, thisStack, name); } }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool AdObject::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // PlayAnim / PlayAnimAsync ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "PlayAnim") == 0 || strcmp(name, "PlayAnimAsync") == 0) { stack->correctParams(1); if (DID_FAIL(playAnim(stack->pop()->getString()))) { stack->pushBool(false); } else { if (strcmp(name, "PlayAnimAsync") != 0) { script->waitFor(this); } stack->pushBool(true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Reset ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Reset") == 0) { stack->correctParams(0); reset(); stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // IsTalking ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "IsTalking") == 0) { stack->correctParams(0); stack->pushBool(_state == STATE_TALKING); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // StopTalk / StopTalking ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "StopTalk") == 0 || strcmp(name, "StopTalking") == 0) { stack->correctParams(0); if (_sentence) { _sentence->finish(); } if (_state == STATE_TALKING) { _state = _nextState; _nextState = STATE_READY; stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // ForceTalkAnim ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "ForceTalkAnim") == 0) { stack->correctParams(1); const char *animName = stack->pop()->getString(); delete[] _forcedTalkAnimName; _forcedTalkAnimName = new char[strlen(animName) + 1]; strcpy(_forcedTalkAnimName, animName); _forcedTalkAnimUsed = false; stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Talk / TalkAsync ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Talk") == 0 || strcmp(name, "TalkAsync") == 0) { stack->correctParams(5); const char *text = stack->pop()->getString(); ScValue *soundVal = stack->pop(); int duration = stack->pop()->getInt(); ScValue *valStances = stack->pop(); const char *stances = valStances->isNULL() ? nullptr : valStances->getString(); int align = 0; ScValue *val = stack->pop(); if (val->isNULL()) { align = TAL_CENTER; } else { align = val->getInt(); } align = MIN(MAX(0, align), NUM_TEXT_ALIGN - 1); const char *sound = soundVal->isNULL() ? nullptr : soundVal->getString(); talk(text, sound, duration, stances, (TTextAlign)align); if (strcmp(name, "TalkAsync") != 0) { script->waitForExclusive(this); } stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // StickToRegion ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "StickToRegion") == 0) { stack->correctParams(1); AdLayer *main = ((AdGame *)_gameRef)->_scene->_mainLayer; bool regFound = false; uint32 i; ScValue *val = stack->pop(); if (val->isNULL() || !main) { _stickRegion = nullptr; regFound = true; } else if (val->isString()) { const char *regionName = val->getString(); for (i = 0; i < main->_nodes.size(); i++) { if (main->_nodes[i]->_type == OBJECT_REGION && main->_nodes[i]->_region->getName() && scumm_stricmp(main->_nodes[i]->_region->getName(), regionName) == 0) { _stickRegion = main->_nodes[i]->_region; regFound = true; break; } } } else if (val->isNative()) { BaseScriptable *obj = val->getNative(); for (i = 0; i < main->_nodes.size(); i++) { if (main->_nodes[i]->_type == OBJECT_REGION && main->_nodes[i]->_region == obj) { _stickRegion = main->_nodes[i]->_region; regFound = true; break; } } } if (!regFound) { _stickRegion = nullptr; } stack->pushBool(regFound); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetFont ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetFont") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); if (val->isNULL()) { setFont(nullptr); } else { setFont(val->getString()); } stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetFont ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetFont") == 0) { stack->correctParams(0); if (_font && _font->getFilename()) { stack->pushString(_font->getFilename()); } else { stack->pushNULL(); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // TakeItem ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "TakeItem") == 0) { stack->correctParams(2); if (!_inventory) { _inventory = new AdInventory(_gameRef); ((AdGame *)_gameRef)->registerInventory(_inventory); } ScValue *val = stack->pop(); if (!val->isNULL()) { const char *itemName = val->getString(); val = stack->pop(); const char *insertAfter = val->isNULL() ? nullptr : val->getString(); if (DID_FAIL(_inventory->insertItem(itemName, insertAfter))) { script->runtimeError("Cannot add item '%s' to inventory", itemName); } else { // hide associated entities ((AdGame *)_gameRef)->_scene->handleItemAssociations(itemName, false); } } else { script->runtimeError("TakeItem: item name expected"); } stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // DropItem ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DropItem") == 0) { stack->correctParams(1); if (!_inventory) { _inventory = new AdInventory(_gameRef); ((AdGame *)_gameRef)->registerInventory(_inventory); } ScValue *val = stack->pop(); if (!val->isNULL()) { if (DID_FAIL(_inventory->removeItem(val->getString()))) { script->runtimeError("Cannot remove item '%s' from inventory", val->getString()); } else { // show associated entities ((AdGame *)_gameRef)->_scene->handleItemAssociations(val->getString(), true); } } else { script->runtimeError("DropItem: item name expected"); } stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetItem ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetItem") == 0) { stack->correctParams(1); if (!_inventory) { _inventory = new AdInventory(_gameRef); ((AdGame *)_gameRef)->registerInventory(_inventory); } ScValue *val = stack->pop(); if (val->_type == VAL_STRING) { AdItem *item = ((AdGame *)_gameRef)->getItemByName(val->getString()); if (item) { stack->pushNative(item, true); } else { stack->pushNULL(); } } else if (val->isNULL() || val->getInt() < 0 || val->getInt() >= (int32)_inventory->_takenItems.size()) { stack->pushNULL(); } else { stack->pushNative(_inventory->_takenItems[val->getInt()], true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // HasItem ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "HasItem") == 0) { stack->correctParams(1); if (!_inventory) { _inventory = new AdInventory(_gameRef); ((AdGame *)_gameRef)->registerInventory(_inventory); } ScValue *val = stack->pop(); if (!val->isNULL()) { for (uint32 i = 0; i < _inventory->_takenItems.size(); i++) { if (val->getNative() == _inventory->_takenItems[i]) { stack->pushBool(true); return STATUS_OK; } else if (scumm_stricmp(val->getString(), _inventory->_takenItems[i]->getName()) == 0) { stack->pushBool(true); return STATUS_OK; } } } else { script->runtimeError("HasItem: item name expected"); } stack->pushBool(false); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // CreateParticleEmitter ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "CreateParticleEmitter") == 0) { stack->correctParams(3); bool followParent = stack->pop()->getBool(); int offsetX = stack->pop()->getInt(); int offsetY = stack->pop()->getInt(); PartEmitter *emitter = createParticleEmitter(followParent, offsetX, offsetY); if (emitter) { stack->pushNative(_partEmitter, true); } else { stack->pushNULL(); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // DeleteParticleEmitter ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DeleteParticleEmitter") == 0) { stack->correctParams(0); if (_partEmitter) { _gameRef->unregisterObject(_partEmitter); _partEmitter = nullptr; } stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // AddAttachment ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "AddAttachment") == 0) { stack->correctParams(4); const char *filename = stack->pop()->getString(); bool preDisplay = stack->pop()->getBool(true); int offsetX = stack->pop()->getInt(); int offsetY = stack->pop()->getInt(); bool res; AdEntity *ent = new AdEntity(_gameRef); if (DID_FAIL(res = ent->loadFile(filename))) { delete ent; ent = nullptr; script->runtimeError("AddAttachment() failed loading entity '%s'", filename); stack->pushBool(false); } else { _gameRef->registerObject(ent); ent->_posX = offsetX; ent->_posY = offsetY; ent->_active = true; if (preDisplay) { _attachmentsPre.add(ent); } else { _attachmentsPost.add(ent); } stack->pushBool(true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // RemoveAttachment ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "RemoveAttachment") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); bool found = false; if (val->isNative()) { BaseScriptable *obj = val->getNative(); for (uint32 i = 0; i < _attachmentsPre.size(); i++) { if (_attachmentsPre[i] == obj) { found = true; _gameRef->unregisterObject(_attachmentsPre[i]); _attachmentsPre.remove_at(i); i--; } } for (uint32 i = 0; i < _attachmentsPost.size(); i++) { if (_attachmentsPost[i] == obj) { found = true; _gameRef->unregisterObject(_attachmentsPost[i]); _attachmentsPost.remove_at(i); i--; } } } else { const char *attachmentName = val->getString(); for (uint32 i = 0; i < _attachmentsPre.size(); i++) { if (_attachmentsPre[i]->getName() && scumm_stricmp(_attachmentsPre[i]->getName(), attachmentName) == 0) { found = true; _gameRef->unregisterObject(_attachmentsPre[i]); _attachmentsPre.remove_at(i); i--; } } for (uint32 i = 0; i < _attachmentsPost.size(); i++) { if (_attachmentsPost[i]->getName() && scumm_stricmp(_attachmentsPost[i]->getName(), attachmentName) == 0) { found = true; _gameRef->unregisterObject(_attachmentsPost[i]); _attachmentsPost.remove_at(i); i--; } } } stack->pushBool(found); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetAttachment ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetAttachment") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); AdObject *ret = nullptr; if (val->isInt()) { int index = val->getInt(); int currIndex = 0; for (uint32 i = 0; i < _attachmentsPre.size(); i++) { if (currIndex == index) { ret = _attachmentsPre[i]; } currIndex++; } for (uint32 i = 0; i < _attachmentsPost.size(); i++) { if (currIndex == index) { ret = _attachmentsPost[i]; } currIndex++; } } else { const char *attachmentName = val->getString(); for (uint32 i = 0; i < _attachmentsPre.size(); i++) { if (_attachmentsPre[i]->getName() && scumm_stricmp(_attachmentsPre[i]->getName(), attachmentName) == 0) { ret = _attachmentsPre[i]; break; } } if (!ret) { for (uint32 i = 0; i < _attachmentsPost.size(); i++) { if (_attachmentsPost[i]->getName() && scumm_stricmp(_attachmentsPost[i]->getName(), attachmentName) == 0) { ret = _attachmentsPre[i]; break; } } } } if (ret != nullptr) { stack->pushNative(ret, true); } else { stack->pushNULL(); } return STATUS_OK; } else { return BaseObject::scCallMethod(script, stack, thisStack, name); } }
bool SXString::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // Substring ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "Substring") == 0) { stack->correctParams(2); int start = stack->pop()->getInt(); int end = stack->pop()->getInt(); if (end < start) { BaseUtils::swap(&start, &end); } //try { WideString str; if (_gameRef->_textEncoding == TEXT_UTF8) { str = StringUtil::utf8ToWide(_string); } else { str = StringUtil::ansiToWide(_string); } //WideString subStr = str.substr(start, end - start + 1); WideString subStr(str.c_str() + start, end - start + 1); if (_gameRef->_textEncoding == TEXT_UTF8) { stack->pushString(StringUtil::wideToUtf8(subStr).c_str()); } else { stack->pushString(StringUtil::wideToAnsi(subStr).c_str()); } // } catch (std::exception &) { // stack->pushNULL(); // } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Substr ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Substr") == 0) { stack->correctParams(2); int start = stack->pop()->getInt(); ScValue *val = stack->pop(); int len = val->getInt(); if (!val->isNULL() && len <= 0) { stack->pushString(""); return STATUS_OK; } if (val->isNULL()) { len = strlen(_string) - start; } // try { WideString str; if (_gameRef->_textEncoding == TEXT_UTF8) { str = StringUtil::utf8ToWide(_string); } else { str = StringUtil::ansiToWide(_string); } // WideString subStr = str.substr(start, len); WideString subStr(str.c_str() + start, len); if (_gameRef->_textEncoding == TEXT_UTF8) { stack->pushString(StringUtil::wideToUtf8(subStr).c_str()); } else { stack->pushString(StringUtil::wideToAnsi(subStr).c_str()); } // } catch (std::exception &) { // stack->pushNULL(); // } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // ToUpperCase ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "ToUpperCase") == 0) { stack->correctParams(0); WideString str; if (_gameRef->_textEncoding == TEXT_UTF8) { str = StringUtil::utf8ToWide(_string); } else { str = StringUtil::ansiToWide(_string); } str.toUppercase(); if (_gameRef->_textEncoding == TEXT_UTF8) { stack->pushString(StringUtil::wideToUtf8(str).c_str()); } else { stack->pushString(StringUtil::wideToAnsi(str).c_str()); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // ToLowerCase ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "ToLowerCase") == 0) { stack->correctParams(0); WideString str; if (_gameRef->_textEncoding == TEXT_UTF8) { str = StringUtil::utf8ToWide(_string); } else { str = StringUtil::ansiToWide(_string); } str.toLowercase(); if (_gameRef->_textEncoding == TEXT_UTF8) { stack->pushString(StringUtil::wideToUtf8(str).c_str()); } else { stack->pushString(StringUtil::wideToAnsi(str).c_str()); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // IndexOf ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "IndexOf") == 0) { stack->correctParams(2); const char *strToFind = stack->pop()->getString(); int index = stack->pop()->getInt(); WideString str; if (_gameRef->_textEncoding == TEXT_UTF8) { str = StringUtil::utf8ToWide(_string); } else { str = StringUtil::ansiToWide(_string); } WideString toFind; if (_gameRef->_textEncoding == TEXT_UTF8) { toFind = StringUtil::utf8ToWide(strToFind); } else { toFind = StringUtil::ansiToWide(strToFind); } int indexOf = StringUtil::indexOf(str, toFind, index); stack->pushInt(indexOf); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Split ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Split") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); char separators[MAX_PATH_LENGTH] = ","; if (!val->isNULL()) { strcpy(separators, val->getString()); } SXArray *array = new SXArray(_gameRef); if (!array) { stack->pushNULL(); return STATUS_OK; } WideString str; if (_gameRef->_textEncoding == TEXT_UTF8) { str = StringUtil::utf8ToWide(_string); } else { str = StringUtil::ansiToWide(_string); } WideString delims; if (_gameRef->_textEncoding == TEXT_UTF8) { delims = StringUtil::utf8ToWide(separators); } else { delims = StringUtil::ansiToWide(separators); } Common::Array<WideString> parts; uint32 start = 0; for(uint32 i = 0; i < str.size() + 1; i++) { char ch = str.c_str()[i]; if(ch=='\0' || delims.contains(ch)) { char *part = new char[i - start + 1]; if(i != start) { Common::strlcpy(part, str.c_str() + start, i - start + 1); part[i - start] = '\0'; } else { part[0] = '\0'; } val = new ScValue(_gameRef, part); array->push(val); delete[] part; delete val; val = nullptr; start = i + 1; } } for (Common::Array<WideString>::iterator it = parts.begin(); it != parts.end(); ++it) { WideString &part = (*it); if (_gameRef->_textEncoding == TEXT_UTF8) { val = new ScValue(_gameRef, StringUtil::wideToUtf8(part).c_str()); } else { val = new ScValue(_gameRef, StringUtil::wideToAnsi(part).c_str()); } array->push(val); delete val; val = nullptr; } stack->pushNative(array, false); return STATUS_OK; } else { return STATUS_FAILED; } }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool UIObject::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // SetFont ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "SetFont") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); if (_font) { _gameRef->_fontStorage->removeFont(_font); } if (val->isNULL()) { _font = nullptr; stack->pushBool(true); } else { _font = _gameRef->_fontStorage->addFont(val->getString()); stack->pushBool(_font != nullptr); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetImage") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); /* const char *filename = */ val->getString(); delete _image; _image = nullptr; if (val->isNULL()) { stack->pushBool(true); return STATUS_OK; } _image = new BaseSprite(_gameRef); if (!_image || DID_FAIL(_image->loadFile(val->getString()))) { delete _image; _image = nullptr; stack->pushBool(false); } else { stack->pushBool(true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetImage") == 0) { stack->correctParams(0); if (!_image || !_image->getFilename()) { stack->pushNULL(); } else { stack->pushString(_image->getFilename()); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetImageObject ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetImageObject") == 0) { stack->correctParams(0); if (!_image) { stack->pushNULL(); } else { stack->pushNative(_image, true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Focus ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Focus") == 0) { stack->correctParams(0); focus(); stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // MoveAfter / MoveBefore ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "MoveAfter") == 0 || strcmp(name, "MoveBefore") == 0) { stack->correctParams(1); if (_parent && _parent->_type == UI_WINDOW) { UIWindow *win = (UIWindow *)_parent; uint32 i; bool found = false; ScValue *val = stack->pop(); // find directly if (val->isNative()) { UIObject *widget = (UIObject *)val->getNative(); for (i = 0; i < win->_widgets.size(); i++) { if (win->_widgets[i] == widget) { found = true; break; } } } // find by name else { const char *findName = val->getString(); for (i = 0; i < win->_widgets.size(); i++) { if (scumm_stricmp(win->_widgets[i]->getName(), findName) == 0) { found = true; break; } } } if (found) { bool done = false; for (uint32 j = 0; j < win->_widgets.size(); j++) { if (win->_widgets[j] == this) { if (strcmp(name, "MoveAfter") == 0) { i++; } if (j >= i) { j++; } win->_widgets.insert_at(i, this); win->_widgets.remove_at(j); done = true; stack->pushBool(true); break; } } if (!done) { stack->pushBool(false); } } else { stack->pushBool(false); } } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // MoveToBottom ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "MoveToBottom") == 0) { stack->correctParams(0); if (_parent && _parent->_type == UI_WINDOW) { UIWindow *win = (UIWindow *)_parent; for (uint32 i = 0; i < win->_widgets.size(); i++) { if (win->_widgets[i] == this) { win->_widgets.remove_at(i); win->_widgets.insert_at(0, this); break; } } stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // MoveToTop ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "MoveToTop") == 0) { stack->correctParams(0); if (_parent && _parent->_type == UI_WINDOW) { UIWindow *win = (UIWindow *)_parent; for (uint32 i = 0; i < win->_widgets.size(); i++) { if (win->_widgets[i] == this) { win->_widgets.remove_at(i); win->_widgets.add(this); break; } } stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } else { return BaseObject::scCallMethod(script, stack, thisStack, name); } }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool AdTalkHolder::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // SetSprite ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "SetSprite") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); bool setCurrent = false; if (_currentSprite && _currentSprite == _sprite) { setCurrent = true; } delete _sprite; _sprite = nullptr; if (val->isNULL()) { _sprite = nullptr; if (setCurrent) { _currentSprite = nullptr; } stack->pushBool(true); } else { const char *filename = val->getString(); BaseSprite *spr = new BaseSprite(_gameRef, this); if (!spr || DID_FAIL(spr->loadFile(filename))) { script->runtimeError("SetSprite method failed for file '%s'", filename); stack->pushBool(false); } else { _sprite = spr; if (setCurrent) { _currentSprite = _sprite; } stack->pushBool(true); } } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetSprite ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetSprite") == 0) { stack->correctParams(0); if (!_sprite || !_sprite->getFilename()) { stack->pushNULL(); } else { stack->pushString(_sprite->getFilename()); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetSpriteObject ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetSpriteObject") == 0) { stack->correctParams(0); if (!_sprite) { stack->pushNULL(); } else { stack->pushNative(_sprite, true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // AddTalkSprite ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "AddTalkSprite") == 0) { stack->correctParams(2); const char *filename = stack->pop()->getString(); bool ex = stack->pop()->getBool(); BaseSprite *spr = new BaseSprite(_gameRef, this); if (!spr || DID_FAIL(spr->loadFile(filename))) { stack->pushBool(false); script->runtimeError("AddTalkSprite method failed for file '%s'", filename); } else { if (ex) { _talkSpritesEx.add(spr); } else { _talkSprites.add(spr); } stack->pushBool(true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // RemoveTalkSprite ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "RemoveTalkSprite") == 0) { stack->correctParams(2); const char *filename = stack->pop()->getString(); bool ex = stack->pop()->getBool(); bool setCurrent = false; bool setTemp2 = false; if (ex) { for (uint32 i = 0; i < _talkSpritesEx.size(); i++) { if (scumm_stricmp(_talkSpritesEx[i]->getFilename(), filename) == 0) { if (_currentSprite == _talkSpritesEx[i]) { setCurrent = true; } if (_tempSprite2 == _talkSpritesEx[i]) { setTemp2 = true; } delete _talkSpritesEx[i]; _talkSpritesEx.remove_at(i); break; } } } else { for (uint32 i = 0; i < _talkSprites.size(); i++) { if (scumm_stricmp(_talkSprites[i]->getFilename(), filename) == 0) { if (_currentSprite == _talkSprites[i]) { setCurrent = true; } if (_tempSprite2 == _talkSprites[i]) { setTemp2 = true; } delete _talkSprites[i]; _talkSprites.remove_at(i); break; } } } stack->pushBool(true); if (setCurrent) { _currentSprite = _sprite; } if (setTemp2) { _tempSprite2 = _sprite; } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetTalkSprite ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetTalkSprite") == 0) { stack->correctParams(2); const char *filename = stack->pop()->getString(); bool ex = stack->pop()->getBool(); bool setCurrent = false; bool setTemp2 = false; BaseSprite *spr = new BaseSprite(_gameRef, this); if (!spr || DID_FAIL(spr->loadFile(filename))) { stack->pushBool(false); script->runtimeError("SetTalkSprite method failed for file '%s'", filename); } else { // delete current if (ex) { for (uint32 i = 0; i < _talkSpritesEx.size(); i++) { if (_talkSpritesEx[i] == _currentSprite) { setCurrent = true; } if (_talkSpritesEx[i] == _tempSprite2) { setTemp2 = true; } delete _talkSpritesEx[i]; } _talkSpritesEx.clear(); } else { for (uint32 i = 0; i < _talkSprites.size(); i++) { if (_talkSprites[i] == _currentSprite) { setCurrent = true; } if (_talkSprites[i] == _tempSprite2) { setTemp2 = true; } delete _talkSprites[i]; } _talkSprites.clear(); } // set new if (ex) { _talkSpritesEx.add(spr); } else { _talkSprites.add(spr); } stack->pushBool(true); if (setCurrent) { _currentSprite = spr; } if (setTemp2) { _tempSprite2 = spr; } } return STATUS_OK; } else { return AdObject::scCallMethod(script, stack, thisStack, name); } }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool UIButton::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // SetDisabledFont ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "SetDisabledFont") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); if (_fontDisable) { _gameRef->_fontStorage->removeFont(_fontDisable); } if (val->isNULL()) { _fontDisable = nullptr; stack->pushBool(true); } else { _fontDisable = _gameRef->_fontStorage->addFont(val->getString()); stack->pushBool(_fontDisable != nullptr); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetHoverFont ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetHoverFont") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); if (_fontHover) { _gameRef->_fontStorage->removeFont(_fontHover); } if (val->isNULL()) { _fontHover = nullptr; stack->pushBool(true); } else { _fontHover = _gameRef->_fontStorage->addFont(val->getString()); stack->pushBool(_fontHover != nullptr); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetPressedFont ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetPressedFont") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); if (_fontPress) { _gameRef->_fontStorage->removeFont(_fontPress); } if (val->isNULL()) { _fontPress = nullptr; stack->pushBool(true); } else { _fontPress = _gameRef->_fontStorage->addFont(val->getString()); stack->pushBool(_fontPress != nullptr); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetFocusedFont ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetFocusedFont") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); if (_fontFocus) { _gameRef->_fontStorage->removeFont(_fontFocus); } if (val->isNULL()) { _fontFocus = nullptr; stack->pushBool(true); } else { _fontFocus = _gameRef->_fontStorage->addFont(val->getString()); stack->pushBool(_fontFocus != nullptr); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetDisabledImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetDisabledImage") == 0) { stack->correctParams(1); delete _imageDisable; _imageDisable = new BaseSprite(_gameRef); const char *filename = stack->pop()->getString(); if (!_imageDisable || DID_FAIL(_imageDisable->loadFile(filename))) { delete _imageDisable; _imageDisable = nullptr; stack->pushBool(false); } else { stack->pushBool(true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetDisabledImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetDisabledImage") == 0) { stack->correctParams(0); if (!_imageDisable || !_imageDisable->getFilename()) { stack->pushNULL(); } else { stack->pushString(_imageDisable->getFilename()); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetDisabledImageObject ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetDisabledImageObject") == 0) { stack->correctParams(0); if (!_imageDisable) { stack->pushNULL(); } else { stack->pushNative(_imageDisable, true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetHoverImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetHoverImage") == 0) { stack->correctParams(1); delete _imageHover; _imageHover = new BaseSprite(_gameRef); const char *filename = stack->pop()->getString(); if (!_imageHover || DID_FAIL(_imageHover->loadFile(filename))) { delete _imageHover; _imageHover = nullptr; stack->pushBool(false); } else { stack->pushBool(true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetHoverImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetHoverImage") == 0) { stack->correctParams(0); if (!_imageHover || !_imageHover->getFilename()) { stack->pushNULL(); } else { stack->pushString(_imageHover->getFilename()); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetHoverImageObject ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetHoverImageObject") == 0) { stack->correctParams(0); if (!_imageHover) { stack->pushNULL(); } else { stack->pushNative(_imageHover, true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetPressedImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetPressedImage") == 0) { stack->correctParams(1); delete _imagePress; _imagePress = new BaseSprite(_gameRef); const char *filename = stack->pop()->getString(); if (!_imagePress || DID_FAIL(_imagePress->loadFile(filename))) { delete _imagePress; _imagePress = nullptr; stack->pushBool(false); } else { stack->pushBool(true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetPressedImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetPressedImage") == 0) { stack->correctParams(0); if (!_imagePress || !_imagePress->getFilename()) { stack->pushNULL(); } else { stack->pushString(_imagePress->getFilename()); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetPressedImageObject ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetPressedImageObject") == 0) { stack->correctParams(0); if (!_imagePress) { stack->pushNULL(); } else { stack->pushNative(_imagePress, true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetFocusedImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetFocusedImage") == 0) { stack->correctParams(1); delete _imageFocus; _imageFocus = new BaseSprite(_gameRef); const char *filename = stack->pop()->getString(); if (!_imageFocus || DID_FAIL(_imageFocus->loadFile(filename))) { delete _imageFocus; _imageFocus = nullptr; stack->pushBool(false); } else { stack->pushBool(true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetFocusedImage ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetFocusedImage") == 0) { stack->correctParams(0); if (!_imageFocus || !_imageFocus->getFilename()) { stack->pushNULL(); } else { stack->pushString(_imageFocus->getFilename()); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetFocusedImageObject ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetFocusedImageObject") == 0) { stack->correctParams(0); if (!_imageFocus) { stack->pushNULL(); } else { stack->pushNative(_imageFocus, true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // Press ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "Press") == 0) { stack->correctParams(0); if (_visible && !_disable) { _oneTimePress = true; _oneTimePressTime = g_system->getMillis(); } stack->pushNULL(); return STATUS_OK; } else { return UIObject::scCallMethod(script, stack, thisStack, name); } }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool BaseScriptHolder::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // DEBUG_CrashMe ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "DEBUG_CrashMe") == 0) { stack->correctParams(0); byte *p = 0; *p = 10; stack->pushNULL(); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // ApplyEvent ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "ApplyEvent") == 0) { stack->correctParams(1); ScValue *val = stack->pop(); bool ret; ret = applyEvent(val->getString()); if (DID_SUCCEED(ret)) { stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // CanHandleEvent ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "CanHandleEvent") == 0) { stack->correctParams(1); stack->pushBool(canHandleEvent(stack->pop()->getString())); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // CanHandleMethod ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "CanHandleMethod") == 0) { stack->correctParams(1); stack->pushBool(canHandleMethod(stack->pop()->getString())); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // AttachScript ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "AttachScript") == 0) { stack->correctParams(1); stack->pushBool(DID_SUCCEED(addScript(stack->pop()->getString()))); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // DetachScript ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DetachScript") == 0) { stack->correctParams(2); const char *filename = stack->pop()->getString(); bool killThreads = stack->pop()->getBool(false); bool ret = false; for (uint32 i = 0; i < _scripts.size(); i++) { if (scumm_stricmp(_scripts[i]->_filename, filename) == 0) { _scripts[i]->finish(killThreads); ret = true; break; } } stack->pushBool(ret); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // IsScriptRunning ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "IsScriptRunning") == 0) { stack->correctParams(1); const char *filename = stack->pop()->getString(); bool ret = false; for (uint32 i = 0; i < _scripts.size(); i++) { if (scumm_stricmp(_scripts[i]->_filename, filename) == 0 && _scripts[i]->_state != SCRIPT_FINISHED && _scripts[i]->_state != SCRIPT_ERROR) { ret = true; break; } } stack->pushBool(ret); return STATUS_OK; } else { return BaseScriptable::scCallMethod(script, stack, thisStack, name); } }
TOKEN_DEF_END ////////////////////////////////////////////////////////////////////////// bool BaseScriptHolder::parseProperty(byte *buffer, bool complete) { TOKEN_TABLE_START(commands) TOKEN_TABLE(PROPERTY) TOKEN_TABLE(NAME) TOKEN_TABLE(VALUE) TOKEN_TABLE_END byte *params; int cmd; BaseParser parser; if (complete) { if (parser.getCommand((char **)&buffer, commands, (char **)¶ms) != TOKEN_PROPERTY) { _gameRef->LOG(0, "'PROPERTY' keyword expected."); return STATUS_FAILED; } buffer = params; } char *propName = NULL; char *propValue = NULL; while ((cmd = parser.getCommand((char **)&buffer, commands, (char **)¶ms)) > 0) { switch (cmd) { case TOKEN_NAME: delete[] propName; propName = new char[strlen((char *)params) + 1]; if (propName) { strcpy(propName, (char *)params); } else { cmd = PARSERR_GENERIC; } break; case TOKEN_VALUE: delete[] propValue; propValue = new char[strlen((char *)params) + 1]; if (propValue) { strcpy(propValue, (char *)params); } else { cmd = PARSERR_GENERIC; } break; } } if (cmd == PARSERR_TOKENNOTFOUND) { delete[] propName; delete[] propValue; propName = NULL; propValue = NULL; _gameRef->LOG(0, "Syntax error in PROPERTY definition"); return STATUS_FAILED; } if (cmd == PARSERR_GENERIC || propName == NULL || propValue == NULL) { delete[] propName; delete[] propValue; propName = NULL; propValue = NULL; _gameRef->LOG(0, "Error loading PROPERTY definition"); return STATUS_FAILED; } ScValue *val = new ScValue(_gameRef); val->setString(propValue); scSetProperty(propName, val); delete val; delete[] propName; delete[] propValue; propName = NULL; propValue = NULL; return STATUS_OK; }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool BaseRegion::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // AddPoint ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "AddPoint") == 0) { stack->correctParams(2); int x = stack->pop()->getInt(); int y = stack->pop()->getInt(); _points.add(new BasePoint(x, y)); createRegion(); stack->pushBool(true); return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // InsertPoint ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "InsertPoint") == 0) { stack->correctParams(3); int index = stack->pop()->getInt(); int x = stack->pop()->getInt(); int y = stack->pop()->getInt(); if (index >= 0 && index < (int32)_points.size()) { _points.insert_at(index, new BasePoint(x, y)); createRegion(); stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // SetPoint ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "SetPoint") == 0) { stack->correctParams(3); int index = stack->pop()->getInt(); int x = stack->pop()->getInt(); int y = stack->pop()->getInt(); if (index >= 0 && index < (int32)_points.size()) { _points[index]->x = x; _points[index]->y = y; createRegion(); stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // RemovePoint ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "RemovePoint") == 0) { stack->correctParams(1); int index = stack->pop()->getInt(); if (index >= 0 && index < (int32)_points.size()) { delete _points[index]; _points[index] = nullptr; _points.remove_at(index); createRegion(); stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // GetPoint ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "GetPoint") == 0) { stack->correctParams(1); int index = stack->pop()->getInt(); if (index >= 0 && index < (int32)_points.size()) { ScValue *val = stack->getPushValue(); if (val) { val->setProperty("X", _points[index]->x); val->setProperty("Y", _points[index]->y); } } else { stack->pushNULL(); } return STATUS_OK; } else { return BaseObject::scCallMethod(script, stack, thisStack, name); } }
////////////////////////////////////////////////////////////////////////// // high level scripting interface ////////////////////////////////////////////////////////////////////////// bool AdEntity::scCallMethod(ScScript *script, ScStack *stack, ScStack *thisStack, const char *name) { ////////////////////////////////////////////////////////////////////////// // StopSound ////////////////////////////////////////////////////////////////////////// if (strcmp(name, "StopSound") == 0 && _subtype == ENTITY_SOUND) { stack->correctParams(0); if (DID_FAIL(stopSFX(false))) { stack->pushBool(false); } else { stack->pushBool(true); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // PlayTheora ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "PlayTheora") == 0) { stack->correctParams(4); const char *filename = stack->pop()->getString(); bool looping = stack->pop()->getBool(false); ScValue *valAlpha = stack->pop(); int startTime = stack->pop()->getInt(); delete _theora; _theora = new VideoTheoraPlayer(_gameRef); if (_theora && DID_SUCCEED(_theora->initialize(filename))) { if (!valAlpha->isNULL()) { _theora->setAlphaImage(valAlpha->getString()); } _theora->play(VID_PLAY_POS, 0, 0, false, false, looping, startTime, _scale >= 0.0f ? _scale : -1.0f, _sFXVolume); //if (_scale>=0) _theora->_playZoom = _scale; stack->pushBool(true); } else { script->runtimeError("Entity.PlayTheora - error playing video '%s'", filename); stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // StopTheora ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "StopTheora") == 0) { stack->correctParams(0); if (_theora) { _theora->stop(); delete _theora; _theora = nullptr; stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // IsTheoraPlaying ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "IsTheoraPlaying") == 0) { stack->correctParams(0); if (_theora && _theora->isPlaying()) { stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // PauseTheora ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "PauseTheora") == 0) { stack->correctParams(0); if (_theora && _theora->isPlaying()) { _theora->pause(); stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // ResumeTheora ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "ResumeTheora") == 0) { stack->correctParams(0); if (_theora && _theora->isPaused()) { _theora->resume(); stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // IsTheoraPaused ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "IsTheoraPaused") == 0) { stack->correctParams(0); if (_theora && _theora->isPaused()) { stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // CreateRegion ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "CreateRegion") == 0) { stack->correctParams(0); if (!_region) { _region = new BaseRegion(_gameRef); _gameRef->registerObject(_region); } if (_region) { stack->pushNative(_region, true); } else { stack->pushNULL(); } return STATUS_OK; } ////////////////////////////////////////////////////////////////////////// // DeleteRegion ////////////////////////////////////////////////////////////////////////// else if (strcmp(name, "DeleteRegion") == 0) { stack->correctParams(0); if (_region) { _gameRef->unregisterObject(_region); _region = nullptr; stack->pushBool(true); } else { stack->pushBool(false); } return STATUS_OK; } else { return AdTalkHolder::scCallMethod(script, stack, thisStack, name); } }