/* * ORXONOX - the hottest 3D action shooter ever to exist * > www.orxonox.net < * * * License notice: * * 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 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: * Fabian 'x3n' Landau * Reto Grieder * Co-authors: * ... * */ #include "MultiStateEngine.h" extern "C" { #include } #include "util/Convert.h" #include "core/CoreIncludes.h" #include "core/GameMode.h" #include "core/LuaState.h" #include "core/XMLPort.h" #include "worldentities/EffectContainer.h" #include "worldentities/pawns/SpaceShip.h" #include "sound/WorldSound.h" namespace orxonox { static const float FORWARD_EFFECT_VELOCITY_THRESHOLD = 0; static const float MAX_VELOCITY_NORMAL = 111; static const float MAX_VELOCITY_BOOST = 221; RegisterClass(MultiStateEngine); MultiStateEngine::MultiStateEngine(Context* context) : Engine(context) { RegisterObject(MultiStateEngine); if (GameMode::isMaster()) { this->defEngineSndNormal_ = new WorldSound(this->getContext()); this->defEngineSndBoost_ = new WorldSound(this->getContext()); this->defEngineSndNormal_->setLooping(true); this->defEngineSndBoost_->setLooping(true); this->defEngineSndNormal_->setVolume(0.8f); this->defEngineSndBoost_->setVolume(0.5f); this->lua_ = new LuaState(); } else { this->defEngineSndBoost_ = nullptr; this->defEngineSndNormal_ = nullptr; this->lua_ = nullptr; } this->state_ = 0; this->oldState_ = 0; this->setSyncMode(ObjectDirection::Bidirectional); this->registerVariables(); } MultiStateEngine::~MultiStateEngine() { if (this->isInitialized()) { if (!this->getShip()) { // We have no ship, so the effects are not attached and won't be destroyed automatically for (EffectContainer* container : this->effectContainers_) for (WorldEntity* effect : container->getEffects()) effect->destroy(); if (this->defEngineSndNormal_) this->defEngineSndNormal_->destroy(); if (this->defEngineSndBoost_) this->defEngineSndBoost_->destroy(); } if (this->lua_) delete this->lua_; } } void MultiStateEngine::XMLPort(Element& xmlelement, XMLPort::Mode mode) { SUPER(MultiStateEngine, XMLPort, xmlelement, mode); XMLPortObject(MultiStateEngine, EffectContainer, "", addEffectContainer, getEffectContainer, xmlelement, mode); XMLPortParam(MultiStateEngine, "defEngineSndNormal", setDefEngSndNormal, getDefEngSndNormal, xmlelement, mode); XMLPortParam(MultiStateEngine, "defEngineSndBoost", setDefEngSndBoost, getDefEngSndBoost, xmlelement, mode); } void MultiStateEngine::registerVariables() { registerVariable(this->state_, VariableDirection::ToServer); } void MultiStateEngine::run(float dt) { if (this->getShip()) { const Vector3& velocity = this->getShip()->getLocalVelocity(); if (this->getShip()->hasLocalController()) { const Vector3& direction = this->getSteering(); bool forward = (direction.z < 0.0 && velocity.z < -FORWARD_EFFECT_VELOCITY_THRESHOLD); this->state_ = 0; if (this->getShip()->isBoosting() && forward) this->state_ = EngineState::Boost; else if (forward && !this->state_) // this->state_ == Boost this->state_ = EngineState::Normal; else if (direction.z > 0.0 && velocity.z < 0.0) this->state_ = EngineState::Brake; else this->state_ = EngineState::Idle; if (this->state_ == EngineState::Idle && this->getSpeedAdd() > 0) this->state_ = EngineState::Normal; } if (GameMode::isMaster()) { int changes = this->state_ | this->oldState_; float pitch = velocity.length(); if (this->state_ & EngineState::Normal) defEngineSndNormal_->setPitch(clamp(pitch/MAX_VELOCITY_NORMAL + 1, 0.5f, 2.0f)); if (this->state_ & EngineState::Boost) defEngineSndBoost_->setPitch(clamp(pitch/MAX_VELOCITY_BOOST + 1, 0.5f, 2.0f)); if (changes & EngineState::Idle) { lua_pushboolean(this->lua_->getInternalLuaState(), this->state_ & EngineState::Idle); lua_setglobal(this->lua_->getInternalLuaState(), "idle"); } if (changes & EngineState::Normal) { lua_pushboolean(this->lua_->getInternalLuaState(), this->state_ & EngineState::Normal); lua_setglobal(this->lua_->getInternalLuaState(), "normal"); if (this->state_ & EngineState::Normal) defEngineSndNormal_->play(); else defEngineSndNormal_->stop(); } if (changes & EngineState::Brake) { lua_pushboolean(this->lua_->getInternalLuaState(), this->state_ & EngineState::Brake); lua_setglobal(this->lua_->getInternalLuaState(), "brake"); } if (changes & EngineState::Boost) { lua_pushboolean(this->lua_->getInternalLuaState(), this->state_ & EngineState::Boost); lua_setglobal(this->lua_->getInternalLuaState(), "boost"); if (this->state_ & EngineState::Boost) defEngineSndBoost_->play(); else defEngineSndBoost_->stop(); } this->oldState_ = this->state_; // Update all effect conditions for (EffectContainer* container : this->effectContainers_) container->updateCondition(); } } Engine::run(dt); } void MultiStateEngine::addToSpaceShip(SpaceShip* ship) { Engine::addToSpaceShip(ship); if (!ship) return; if( this->defEngineSndNormal_ ) this->getShip()->attach(defEngineSndNormal_); if( this->defEngineSndBoost_ ) this->getShip()->attach(defEngineSndBoost_); for (EffectContainer* container : this->effectContainers_) for (WorldEntity* effect : container->getEffects()) this->getShip()->attach(effect); } void MultiStateEngine::addEffectContainer(EffectContainer* container) { if (container == nullptr) return; container->setLuaState(this->lua_, 'f' + multi_cast(this->effectContainers_.size())); this->effectContainers_.push_back(container); if (this->getShip()) { for (WorldEntity* effect : container->getEffects()) this->getShip()->attach(effect); } } EffectContainer* MultiStateEngine::getEffectContainer(unsigned int index) const { unsigned int i = 0; for (EffectContainer* effectContainer : this->effectContainers_) { if (i == index) return effectContainer; i++; } return nullptr; } void MultiStateEngine::setDefEngSndNormal(const std::string &engineSound) { if( defEngineSndNormal_ ) defEngineSndNormal_->setSource(engineSound); else assert(0); // This should never happen, because soundpointer is only available on master } const std::string& MultiStateEngine::getDefEngSndNormal() { if( defEngineSndNormal_ ) return defEngineSndNormal_->getSource(); else assert(0); return BLANKSTRING; } void MultiStateEngine::setDefEngSndBoost(const std::string &engineSound) { if( defEngineSndBoost_ ) defEngineSndBoost_->setSource(engineSound); else assert(0); } const std::string& MultiStateEngine::getDefEngSndBoost() { if( this->defEngineSndBoost_ ) return defEngineSndBoost_->getSource(); else assert(0); return BLANKSTRING; } }