#include "scriptable_controller.h" #include "luatb.h" #include "infos/PlayerInfo.h" #include "core/command/Executor.h" #include "worldentities/pawns/Pawn.h" namespace orxonox { // Used https://csl.name/post/lua-and-cpp/ as a reference int ScriptableController::runScript(const std::string &file_path) { int ret; // Not having a script specified at all is not an error if(file_path.empty()) return 0; // Create a lua object lua_State *lua = luaL_newstate(); if(lua == nullptr) { orxout(internal_warning) << "ScriptableController: Falied to load script " << file_path << std::endl; return LUA_ERRMEM; } // Make standard libraries available in the Lua object luaL_openlibs(lua); // Register the API ScriptableControllerAPI *api = new ScriptableControllerAPI(lua, this); // Load the program; this supports both source code and bytecode files. if((ret = luaL_loadfile(lua, file_path.c_str())) != 0) { this->printLuaError(lua); delete api; return ret; } // Execute the script if((ret = lua_pcall(lua, 0, LUA_MULTRET, 0)) != 0) { this->printLuaError(lua); delete api; return ret; } // Remeber the api this->apis_.push_back(std::unique_ptr(api)); return 0; } void ScriptableController::setPlayer(PlayerInfo *player) { this->player_ = player; } void ScriptableController::registerWorldEntity(std::string id, WorldEntity *entity) { this->worldEntities_[id] = entity; } void ScriptableController::registerMobileEntity(std::string id, MobileEntity *entity) { this->mobileEntities_[id] = entity; } void ScriptableController::registerPawn(std::string id, Pawn *pawn) { this->worldEntities_[id] = pawn; this->pawns_[id] = pawn; this->pawnsReverse_[pawn] = id; } void ScriptableController::pawnKilled(Pawn *pawn) { auto pawn_id_iter = this->pawnsReverse_.find(pawn); if(pawn_id_iter == this->pawnsReverse_.end()) { orxout(internal_warning) << "Unregistered pawn reported that it's destroyed" << std::endl; return; } for(auto &api : this->apis_) api->pawnKilled(pawn_id_iter->second); this->pawns_.erase(pawn_id_iter->second); this->pawnsReverse_.erase(pawn_id_iter); } void ScriptableController::pawnHit(Pawn *target, Pawn *source, double new_health, double new_shield) { auto target_id_iter = this->pawnsReverse_.find(target); auto source_id_iter = this->pawnsReverse_.find(source); if(target_id_iter == this->pawnsReverse_.end() || source_id_iter == this->pawnsReverse_.end() ) { orxout(internal_warning) << "Unregistered pawn reported that it's hit" << std::endl; return; } for(auto &api : this->apis_) api->pawnHit(target_id_iter->second, source_id_iter->second, new_health, new_shield); } void ScriptableController::killPawn(std::string id) { auto pawn = this->pawns_.find(id); if(pawn == this->pawns_.end()) { orxout(user_warning) << "Tried to destroy unknown pawn " << id << std::endl; return; } pawn->second->kill(); } WorldEntity *ScriptableController::getWorldEntityByID(std::string id) const { if(id == "player" || id == "Player" || id == "PLAYER") return this->player_->getControllableEntity(); auto entity = this->worldEntities_.find(id); return entity != this->worldEntities_.end() ? entity->second : nullptr; } MobileEntity *ScriptableController::getMobileEntityByID(std::string id) const { if(id == "player" || id == "Player" || id == "PLAYER") return this->player_->getControllableEntity(); auto entity = this->mobileEntities_.find(id); return entity != this->mobileEntities_.end() ? entity->second : nullptr; } Pawn *ScriptableController::getPawnByID(std::string id) const { auto pawn = this->pawns_.find(id); return pawn != this->pawns_.end() ? pawn->second : nullptr; } void ScriptableController::printLuaError(lua_State *lua) { // The error message is on top of the stack. // Fetch it, print it and then pop it off the stack. // Yes, this is 'const char*' and not 'std::string' because that's what lua gives us. const char* message = lua_tostring(lua, -1); std::cout << message << std::endl; lua_pop(lua, 1); } }