/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. ### File Specific: main-programmer: Silvan Nellen co-programmer: Benjamin Grauer */ #include "script.h" #include "script_class.h" #include "luaincl.h" #include "util/loading/resource_manager.h" #include "loading/load_param.h" #include "parser/tinyxml/tinyxml.h" #include "class_list.h" CREATE_SCRIPTABLE_CLASS(Script, CL_SCRIPT, addMethod("addObject", ExecutorLua2(&Script::addObject)) ->addMethod("selectFunction", ExecutorLua2ret(&Script::selectFunction)) ->addMethod("executeFunction", ExecutorLua0ret(&Script::executeFunction)) ); Script::Script(const TiXmlElement* root) { this->setClassID(CL_SCRIPT, "Script"); returnCount = argumentCount = 0; luaState = lua_open(); luaopen_base(luaState); luaopen_table(luaState); luaopen_io(luaState); luaopen_string(luaState); luaopen_math(luaState); luaopen_debug(luaState); if (root != NULL) this->loadParams(root); } Script::~Script() { lua_setgcthreshold(luaState, 0); // collected garbage lua_close(luaState); } void Script::loadParams(const TiXmlElement* root) { //printf("Loading params for %p \n",this); BaseObject::loadParams(root); LOAD_PARAM_START_CYCLE(root, object); { LoadParam_CYCLE(object, "object", this, Script, addObject) .describe("The name of an object that is needed by a script"); } LOAD_PARAM_END_CYCLE(object); LoadParam(root, "file", this, Script, loadFileNoRet) .describe("the fileName of the script, that should be loaded into this world") .defaultValues(""); } bool Script::loadFile(const std::string& filename) { this->setName(filename); std::string filedest(ResourceManager::getInstance()->getDataDir()); filedest += "scripts/" + filename; this->addThisScript(); this->registerStandartClasses(); if(currentFile.length() != 0) { printf("Could not load %s because an other file is already loaded: %s\n",filename.c_str(), currentFile.c_str()); return false; } int error = luaL_loadfile (luaState, filedest.c_str()); if(error == 0) { error = lua_pcall(luaState, 0, 0, 0); if(error == 0) { currentFile = filename; return true; } else { printf("ERROR while loading file %s: \n",filename.c_str()); reportError(error); } } else { printf("ERROR while loading file %s: \n",filename.c_str()); reportError(error); } return false; } void Script::addObject(const std::string& className, const std::string& objectName) { //printf("Script %s: I am about to add %s of class %s\n",this->getName(),objectName.c_str(),className.c_str()); BaseObject* scriptClass = ClassList::getObject(className, CL_SCRIPT_CLASS); // printf("The script class for %s is at %p \n",className.c_str(),scriptClass); WorldObject tmpObj; if (scriptClass != NULL) { tmpObj.type = className; if( !classIsRegistered(className) ) { static_cast(scriptClass)->registerClass(this); } BaseObject* object = ClassList::getObject(objectName, className); // printf("%s is at %p \n",objectName.c_str(),object); if (object != NULL && !objectIsAdded(objectName)) { static_cast(scriptClass)->insertObject(this, object, false); tmpObj.name = objectName; registeredObjects.push_back(tmpObj); } } } bool Script::executeFile() { printf("WARNING: script.executeFile is not implemented yet"); /*if(currentFile.length() != 0) { int error = lua_pcall(luaState, 0, 0, 0); if( error == 0) return true; else { reportError(error); return false; } }*/ return false; } bool Script::selectFunction(const std::string& functionName, int retCount) { if(returnCount == 0 && currentFunction.length() == 0) //no return values left on the stack and no other function selected { lua_pushlstring(luaState, functionName.c_str(), functionName.size() ); lua_gettable(luaState, LUA_GLOBALSINDEX); if(lua_isfunction( luaState , -1)) { returnCount = retCount; argumentCount = 0; currentFunction = functionName; return true; } else return false; } else printf("There is an other function active ( %s ) or there are unremoved return values on the stack. Please remove them first.\n",currentFunction.c_str()); return false; } //return number of returned values bool Script::executeFunction() { if(currentFunction.length() != 0 ) { int error = lua_pcall(luaState, argumentCount, returnCount,0); if(error != 0) { printf("ERROR while executing function %s: \n",currentFunction.c_str()); reportError(error); //clean up currentFunction.assign(""); argumentCount = returnCount = 0; return false; } else { currentFunction.assign("");//a function gets unusable after beeing called for the first time argumentCount = 0; return true; } } else printf("Error: no function selected.\n"); return false; } //overload this function to add different types bool Script::pushParam(int param, std::string& toFunction) { if(currentFunction == toFunction) { lua_pushnumber(luaState, (lua_Number) param); argumentCount++; return true; } else { printf("Couldn't add parameter because the wrong function is selected: %s instead of %s\n", currentFunction.c_str(), toFunction.c_str()); return false; } } bool Script::pushParam(float param, std::string& toFunction) { if(currentFunction.compare(toFunction) == 0) { lua_pushnumber(luaState,(lua_Number) param); argumentCount++; return true; } else { printf("Couldn't add parameter because the wrong function is selected: %s instead of %s\n", currentFunction.c_str(), toFunction.c_str()); return false; } } bool Script::pushParam(double param, std::string& toFunction) { if(currentFunction.compare(toFunction) == 0) { lua_pushnumber(luaState,(lua_Number) param); argumentCount++; return true; } else { printf("Couldn't add parameter because the wrong function is selected: %s instead of %s\n", currentFunction.c_str(), toFunction.c_str()); return false; } } int Script::getReturnedInt() { int returnValue = 0; if(returnCount > 0) { if(lua_isnumber(luaState, -1*returnCount)) { returnValue = (int)lua_tonumber(luaState, -1*returnCount); lua_remove(luaState,-1*returnCount); returnCount--; } } return returnValue; } bool Script::getReturnedBool() { bool returnValue = false; if(returnCount > 0) { if(lua_isboolean(luaState, -1*returnCount)) { returnValue = (bool)lua_toboolean(luaState, -1*returnCount); lua_remove(luaState,-1*returnCount); returnCount--; } else printf("ERROR: Form %s : trying to retreive non bolean value",this->currentFile.c_str()); } return returnValue; } float Script::getReturnedFloat() { float returnValue = 0.0f; if(returnCount > 0) { if(lua_isnumber(luaState, -1*returnCount)) { returnValue = (float)lua_tonumber(luaState, -1*returnCount); lua_remove(luaState,-1*returnCount); returnCount--; } } return returnValue; } void Script::getReturnedString(std::string& string) { const char* returnValue = ""; if(returnCount > 0) { if(lua_isstring(luaState, -1*returnCount)) { returnValue = lua_tostring(luaState, -1*returnCount); lua_remove(luaState,-1*returnCount); returnCount--; } } string.assign(returnValue); } void Script::addThisScript() { BaseObject* scriptClass = ClassList::getObject("Script", CL_SCRIPT_CLASS); if (scriptClass != NULL) { static_cast(scriptClass)->registerClass(this); static_cast(scriptClass)->insertObject(this, this,"thisscript", false); } } int Script::reportError(int error) { if(error != 0) { const char *msg = lua_tostring(luaState, -1); if (msg == NULL) msg = "(error with no message)"; fprintf(stderr, "ERROR: %s\n", msg); lua_pop(luaState, 1); } return error; } bool Script::registerStandartClasses() { bool success = false; //success = this->registerClass(std::string("Vector")); success = this->registerClass("ScriptTrigger"); return success; } bool Script::registerClass( const std::string& className) { BaseObject* scriptClass = ClassList::getObject(className, CL_SCRIPT_CLASS); //printf("The script class for %s is at %p \n",className.c_str(),scriptClass); WorldObject tmpObj; if (scriptClass != NULL) { tmpObj.type = className; if( !classIsRegistered(className) ) { static_cast(scriptClass)->registerClass(this); tmpObj.name = ""; registeredObjects.push_back(tmpObj); return true; } } return false; } bool Script::classIsRegistered(const std::string& type) { for(std::list::const_iterator it = registeredObjects.begin(); it != registeredObjects.end(); it++ ) { if( (*it).type == type) { return true; } } return false; } bool Script::objectIsAdded(const std::string& name) { for(std::list::const_iterator it = registeredObjects.begin(); it != registeredObjects.end(); it++ ) { if( (*it).name == name) { return true; } } return false; }