Index: code/branches/pickup2/src/orxonox/items/MultiStateEngine.cc
===================================================================
--- code/branches/pickup2/src/orxonox/items/MultiStateEngine.cc	(revision 5942)
+++ code/branches/pickup2/src/orxonox/items/MultiStateEngine.cc	(revision 6412)
@@ -22,4 +22,5 @@
  *   Author:
  *      Fabian 'x3n' Landau
+ *      Reto Grieder
  *   Co-authors:
  *      ...
@@ -29,17 +30,22 @@
 #include "MultiStateEngine.h"
 
+extern "C" {
+#include <lua.h>
+}
+
+#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 = 20;
-
-    static const unsigned char STATE_ACTIVE  = 1;
-    static const unsigned char STATE_FORWARD = 2;
-    static const unsigned char STATE_BOOST   = 4;
-    static const unsigned char STATE_BRAKE   = 8;
+    static const float FORWARD_EFFECT_VELOCITY_THRESHOLD = 0;
+    static const float MAX_VELOCITY_NORMAL = 111;
+    static const float MAX_VELOCITY_BOOST = 221;
 
     CreateFactory(MultiStateEngine);
@@ -49,6 +55,22 @@
         RegisterObject(MultiStateEngine);
 
+        if (GameMode::isMaster())
+        {
+            this->defEngineSndNormal_ = new WorldSound(this);
+            this->defEngineSndBoost_  = new WorldSound(this);
+            this->defEngineSndNormal_->setLooping(true);
+            this->defEngineSndBoost_->setLooping(true);
+            this->lua_ = new LuaState();
+        }
+        else
+        {
+            this->defEngineSndBoost_ = 0;
+            this->defEngineSndNormal_ = 0;
+            this->lua_ = 0;
+        }
         this->state_ = 0;
-
+        this->oldState_ = 0;
+
+        this->setSyncMode(ObjectDirection::Bidirectional);
         this->registerVariables();
     }
@@ -56,15 +78,19 @@
     MultiStateEngine::~MultiStateEngine()
     {
-        if (this->isInitialized() && !this->getShip())
-        {
-            // We have no ship, so the effects are not attached and won't be destroyed automatically
-            for (std::list<WorldEntity*>::const_iterator it = this->activeEffects_.begin(); it != this->activeEffects_.end(); ++it)
-                (*it)->destroy();
-            for (std::list<WorldEntity*>::const_iterator it = this->forwardEffects_.begin(); it != this->forwardEffects_.end(); ++it)
-                (*it)->destroy();
-            for (std::list<WorldEntity*>::const_iterator it = this->boostEffects_.begin(); it != this->boostEffects_.end(); ++it)
-                (*it)->destroy();
-            for (std::list<WorldEntity*>::const_iterator it = this->brakeEffects_.begin(); it != this->brakeEffects_.end(); ++it)
-                (*it)->destroy();
+        if (this->isInitialized())
+        {
+            if (!this->getShip())
+            {
+                // We have no ship, so the effects are not attached and won't be destroyed automatically
+                for (std::vector<EffectContainer*>::const_iterator it = this->effectContainers_.begin(); it != this->effectContainers_.end(); ++it)
+                    for (std::vector<WorldEntity*>::const_iterator it2 = (*it)->getEffectsBegin(); it2 != (*it)->getEffectsBegin(); ++it2)
+                        (*it2)->destroy();
+                if (this->defEngineSndNormal_)
+                    this->defEngineSndNormal_->destroy();
+                if (this->defEngineSndBoost_)
+                    this->defEngineSndBoost_->destroy();
+            }
+            if (this->lua_)
+                delete this->lua_;
         }
     }
@@ -73,9 +99,7 @@
     {
         SUPER(MultiStateEngine, XMLPort, xmlelement, mode);
-
-        XMLPortObject(MultiStateEngine, WorldEntity, "active",  addActiveEffect,  getActiveEffect,  xmlelement, mode);
-        XMLPortObject(MultiStateEngine, WorldEntity, "forward", addForwardEffect, getForwardEffect, xmlelement, mode);
-        XMLPortObject(MultiStateEngine, WorldEntity, "boost",   addBoostEffect,   getBoostEffect,   xmlelement, mode);
-        XMLPortObject(MultiStateEngine, WorldEntity, "brake",   addBrakeEffect,   getBrakeEffect,   xmlelement, mode);
+        XMLPortObject(MultiStateEngine, EffectContainer, "",  addEffectContainer,  getEffectContainer,  xmlelement, mode);
+        XMLPortParam(MultiStateEngine, "defEngineSndNormal",  setDefEngSndNormal,  getDefEngSndNormal,  xmlelement, mode);
+        XMLPortParam(MultiStateEngine, "defEngineSndBoost",  setDefEngSndBoost,  getDefEngSndBoost,  xmlelement, mode);
     }
 
@@ -89,47 +113,66 @@
         if (this->getShip())
         {
+            const Vector3& velocity = this->getShip()->getLocalVelocity();
+
             if (this->getShip()->hasLocalController())
             {
-                this->setSyncMode(ObjectDirection::Bidirectional);
-
                 const Vector3& direction = this->getDirection();
-                const Vector3& velocity = this->getShip()->getLocalVelocity();
-
-                bool forward = (direction.z < 0 && velocity.z < -FORWARD_EFFECT_VELOCITY_THRESHOLD);
-                bool boost = (this->getShip()->getBoost() && forward);
-                bool brake = (direction.z > 0 && velocity.z < 0);
-                bool active = (direction != Vector3::ZERO && !brake);
-
-                if (active)
-                    this->state_ |= STATE_ACTIVE;
+                bool forward = (direction.z < 0.0 && velocity.z < -FORWARD_EFFECT_VELOCITY_THRESHOLD);
+
+                this->state_ = 0;
+                if (this->getShip()->getBoost() && forward)
+                    this->state_ = Boost;
+                else if (forward && !this->state_) // this->state_ == Boost
+                    this->state_ = Normal;
+                else if (direction.z > 0.0 && velocity.z < 0.0)
+                    this->state_ = Brake;
                 else
-                    this->state_ &= ~STATE_ACTIVE;
-
-                if (forward)
-                    this->state_ |= STATE_FORWARD;
-                else
-                    this->state_ &= ~STATE_FORWARD;
-
-                if (boost)
-                    this->state_ |= STATE_BOOST;
-                else
-                    this->state_ &= ~STATE_BOOST;
-
-                if (brake)
-                    this->state_ |= STATE_BRAKE;
-                else
-                    this->state_ &= ~STATE_BRAKE;
+                    this->state_ = Idle;
             }
 
             if (GameMode::isMaster())
             {
-                for (std::list<WorldEntity*>::const_iterator it = this->activeEffects_.begin(); it != this->activeEffects_.end(); ++it)
-                    (*it)->setMainState(this->state_ & STATE_ACTIVE);
-                for (std::list<WorldEntity*>::const_iterator it = this->forwardEffects_.begin(); it != this->forwardEffects_.end(); ++it)
-                    (*it)->setMainState(this->state_ & STATE_FORWARD);
-                for (std::list<WorldEntity*>::const_iterator it = this->boostEffects_.begin(); it != this->boostEffects_.end(); ++it)
-                    (*it)->setMainState(this->state_ & STATE_BOOST);
-                for (std::list<WorldEntity*>::const_iterator it = this->brakeEffects_.begin(); it != this->brakeEffects_.end(); ++it)
-                    (*it)->setMainState(this->state_ & STATE_BRAKE);
+                int changes = this->state_ | this->oldState_;
+
+                float pitch = velocity.length();
+                if (this->state_ & Normal)
+                    defEngineSndNormal_->setPitch(clamp(pitch/MAX_VELOCITY_NORMAL + 1, 0.5f, 2.0f));
+                if (this->state_ & Boost)
+                    defEngineSndBoost_->setPitch(clamp(pitch/MAX_VELOCITY_BOOST + 1, 0.5f, 2.0f));
+
+                if (changes & Idle)
+                {
+                    lua_pushboolean(this->lua_->getInternalLuaState(), this->state_ & Idle);
+                    lua_setglobal(this->lua_->getInternalLuaState(), "idle");
+                }
+                if (changes & Normal)
+                {
+                    lua_pushboolean(this->lua_->getInternalLuaState(), this->state_ & Normal);
+                    lua_setglobal(this->lua_->getInternalLuaState(), "normal");
+                    if (this->state_ & Normal)
+                        defEngineSndNormal_->play();
+                    else
+                        defEngineSndNormal_->stop();
+                }
+                if (changes & Brake)
+                {
+                    lua_pushboolean(this->lua_->getInternalLuaState(), this->state_ & Brake);
+                    lua_setglobal(this->lua_->getInternalLuaState(), "brake");
+                }
+                if (changes & Boost)
+                {
+                    lua_pushboolean(this->lua_->getInternalLuaState(), this->state_ & Boost);
+                    lua_setglobal(this->lua_->getInternalLuaState(), "boost");
+                    if (this->state_ & Boost)
+                        defEngineSndBoost_->play();
+                    else
+                        defEngineSndBoost_->stop();
+                }
+
+                this->oldState_ = this->state_;
+
+                // Update all effect conditions
+                for (std::vector<EffectContainer*>::const_iterator it = this->effectContainers_.begin(); it != this->effectContainers_.end(); ++it)
+                    (*it)->updateCondition();
             }
         }
@@ -145,88 +188,70 @@
             return;
 
-        for (std::list<WorldEntity*>::const_iterator it = this->activeEffects_.begin(); it != this->activeEffects_.end(); ++it)
-            ship->attach(*it);
-        for (std::list<WorldEntity*>::const_iterator it = this->forwardEffects_.begin(); it != this->forwardEffects_.end(); ++it)
-            ship->attach(*it);
-        for (std::list<WorldEntity*>::const_iterator it = this->boostEffects_.begin(); it != this->boostEffects_.end(); ++it)
-            ship->attach(*it);
-        for (std::list<WorldEntity*>::const_iterator it = this->brakeEffects_.begin(); it != this->brakeEffects_.end(); ++it)
-            ship->attach(*it);
-    }
-
-    void MultiStateEngine::addActiveEffect(WorldEntity* effect)
-    {
-        this->activeEffects_.push_back(effect);
+        if( this->defEngineSndNormal_ )
+            this->getShip()->attach(defEngineSndNormal_);
+        if( this->defEngineSndBoost_ )
+            this->getShip()->attach(defEngineSndBoost_);
+
+        for (std::vector<EffectContainer*>::const_iterator it = this->effectContainers_.begin(); it != this->effectContainers_.end(); ++it)
+            for (std::vector<WorldEntity*>::const_iterator it2 = (*it)->getEffectsBegin(); it2 != (*it)->getEffectsEnd(); ++it2)
+                this->getShip()->attach(*it2);
+    }
+
+    void MultiStateEngine::addEffectContainer(EffectContainer* effect)
+    {
+        if (effect == NULL)
+            return;
+        effect->setLuaState(this->lua_, 'f' + multi_cast<std::string>(this->effectContainers_.size()));
+        this->effectContainers_.push_back(effect);
         if (this->getShip())
-            this->getShip()->attach(effect);
-    }
-
-    void MultiStateEngine::addForwardEffect(WorldEntity* effect)
-    {
-        this->forwardEffects_.push_back(effect);
-        if (this->getShip())
-            this->getShip()->attach(effect);
-    }
-
-    void MultiStateEngine::addBoostEffect(WorldEntity* effect)
-    {
-        this->boostEffects_.push_back(effect);
-        if (this->getShip())
-            this->getShip()->attach(effect);
-    }
-
-    void MultiStateEngine::addBrakeEffect(WorldEntity* effect)
-    {
-        this->brakeEffects_.push_back(effect);
-        if (this->getShip())
-            this->getShip()->attach(effect);
-    }
-
-    WorldEntity* MultiStateEngine::getActiveEffect(unsigned int index) const
+        {
+            for (std::vector<WorldEntity*>::const_iterator it = effect->getEffectsBegin(); it != effect->getEffectsBegin(); ++it)
+                this->getShip()->attach(*it);
+        }
+    }
+
+    EffectContainer* MultiStateEngine::getEffectContainer(unsigned int index) const
     {
         unsigned int i = 0;
-        for (std::list<WorldEntity*>::const_iterator it = this->activeEffects_.begin(); it != this->activeEffects_.end(); ++it)
+        for (std::vector<EffectContainer*>::const_iterator it = this->effectContainers_.begin(); it != this->effectContainers_.end(); ++it)
         {
             if (i == index)
                 return (*it);
-            ++i;
-        }
-        return 0;
-    }
-
-    WorldEntity* MultiStateEngine::getForwardEffect(unsigned int index) const
-    {
-        unsigned int i = 0;
-        for (std::list<WorldEntity*>::const_iterator it = this->forwardEffects_.begin(); it != this->forwardEffects_.end(); ++it)
-        {
-            if (i == index)
-                return (*it);
-            ++i;
-        }
-        return 0;
-    }
-
-    WorldEntity* MultiStateEngine::getBoostEffect(unsigned int index) const
-    {
-        unsigned int i = 0;
-        for (std::list<WorldEntity*>::const_iterator it = this->boostEffects_.begin(); it != this->boostEffects_.end(); ++it)
-        {
-            if (i == index)
-                return (*it);
-            ++i;
-        }
-        return 0;
-    }
-
-    WorldEntity* MultiStateEngine::getBrakeEffect(unsigned int index) const
-    {
-        unsigned int i = 0;
-        for (std::list<WorldEntity*>::const_iterator it = this->brakeEffects_.begin(); it != this->brakeEffects_.end(); ++it)
-        {
-            if (i == index)
-                return (*it);
-            ++i;
-        }
-        return 0;
+        }
+        return NULL;
+    }
+
+    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;
     }
 }
