#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()){ orxout(internal_warning) << "No script specified!" << std::endl; return 0; } // Create a lua object lua_State *lua = luaL_newstate(); if(lua == nullptr) { orxout(internal_warning) << "ScriptableController: Failed 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) { orxout(user_error) << "Failed to load level script " + file_path << std::endl; this->printLuaError(lua); delete api; return ret; } // Execute the script if((ret = lua_pcall(lua, 0, LUA_MULTRET, 0)) != 0) { orxout(user_error) << "Level script returned an error" << std::endl; this->printLuaError(lua); delete api; return ret; } // Remember 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->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; } // The ID of the pawn should already be invalid when we call the callback std::string id = pawn_id_iter->second; this->pawns_.erase(pawn_id_iter->second); this->pawnsReverse_.erase(pawn_id_iter); for(auto &api : this->apis_) api->pawnKilled(id, pawn); } 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); } 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 { if(id == "player" || id == "Player" || id == "PLAYER") { return orxonox_cast(this->player_->getControllableEntity()); orxout(user_status) << "Pawn is player!?" << std::endl; } auto pawn = this->pawns_.find(id); if(pawn != this->pawns_.end()) { orxout(user_status) << "Requested Pawn is available!" << std::endl; } 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); orxout(user_error) << message << std::endl; lua_pop(lua, 1); } }