Index: code/trunk/src/orxonox/interfaces/Pickupable.cc
===================================================================
--- code/trunk/src/orxonox/interfaces/Pickupable.cc	(revision 6901)
+++ code/trunk/src/orxonox/interfaces/Pickupable.cc	(revision 7163)
@@ -34,12 +34,17 @@
 #include "Pickupable.h"
 
+#include "core/LuaState.h"
+#include "core/GUIManager.h"
 #include "core/Identifier.h"
 #include "core/CoreIncludes.h"
+#include "util/Convert.h"
+#include "infos/PlayerInfo.h"
 #include "pickup/PickupIdentifier.h"
+#include "worldentities/pawns/Pawn.h"
 #include "PickupCarrier.h"
 
 namespace orxonox
 {
-    
+
     /**
     @brief
@@ -47,31 +52,59 @@
     */
     Pickupable::Pickupable() : pickupIdentifier_(NULL), used_(false), pickedUp_(false)
-    {        
+    {
         RegisterRootObject(Pickupable);
-        
+
         this->carrier_ = NULL;
-        
+
         this->pickupIdentifier_ = new PickupIdentifier(this);
-    }
-    
-    /**
-    @brief
-        Destructor. 
+        this->beingDestroyed_ = false;
+        this->enabled_ = true;
+    }
+
+    /**
+    @brief
+        Destructor.
     */
     Pickupable::~Pickupable()
     {
-        if(this->isUsed())
-            this->setUsed(false);
-        
-        if(this->isPickedUp() && this->getCarrier() != NULL)
-        {
-            this->getCarrier()->drop(this, false);
-            this->setCarrier(NULL);
-        }
-        
+        COUT(4) << "Pickupable (" << this->getIdentifier()->getName() << ") (&" << this << ") destroyed." << std::endl;
         if(this->pickupIdentifier_ != NULL)
             this->pickupIdentifier_->destroy();
     }
-    
+
+    /**
+    @brief
+        A method that is called by OrxonoxClass::destroy() before the object is actually destroyed.
+    */
+    void Pickupable::preDestroy(void)
+    {
+        this->beingDestroyed_ = true;
+
+        if(this->isPickedUp())
+            this->drop(false); // Drops the pickup without creating a PickupSpawner.
+    }
+
+    /**
+    @brief
+        Is called internally within the pickup module to destroy pickups.
+    */
+    void Pickupable::destroy(void)
+    {
+        this->destroyPickup();
+    }
+
+    /**
+    @brief
+        Destroys a Pickupable.
+        If the Pickupable is already in the process of being destroyed a warning is displayed and this method is skipped.
+    */
+    void Pickupable::destroyPickup(void)
+    {
+        if(!this->beingDestroyed_)
+            this->OrxonoxClass::destroy();
+        else
+            COUT(2) << this->getIdentifier()->getName() << " may be unsafe. " << std::endl;
+    }
+
     /**
     @brief
@@ -84,14 +117,19 @@
     bool Pickupable::setUsed(bool used)
     {
-        if(this->used_ == used)
-            return false;
-        
+        if(this->used_ == used || !this->isPickedUp()) // If either the used status of the Pickupable doesn't change or it isn't picked up.
+            return false;
+
+        if((!this->isUsable() && used) || (!this->isUnusable() && !used)) // If either the Pickupable is requested to be used but it is not usable or the Pickupable is requested to be unused, while it is not unusable.
+            return false;
+
         COUT(4) << "Pickupable (&" << this << ") set to used " << used << "." << std::endl;
-        
+
         this->used_ = used;
         this->changedUsed();
-        return true;
-    }
-    
+
+        GUIManager::getInstance().getLuaState()->doString("PickupInventory.update()");
+        return true;
+    }
+
     /**
     @brief
@@ -106,7 +144,8 @@
         if(carrier == NULL)
             return false;
+
         return this->isTarget(carrier->getIdentifier());
     }
-    
+
     /**
     @brief
@@ -125,7 +164,8 @@
                 return true;
         }
+
         return false;
     }
-        
+
     /**
     @brief
@@ -140,5 +180,5 @@
         return this->addTarget(target->getIdentifier());
     }
-    
+
     /**
     @brief
@@ -153,30 +193,67 @@
         if(this->isTarget(target)) //!< If the input target is already present in the list of targets.
             return false;
-        
+
         COUT(4) << "Target " << target->getName() << " added to Pickupable (&" << this << ")." << std::endl;
         this->targets_.push_back(target);
         return true;
     }
-    
-    /**
-    @brief  
-        Sets the Pickupable to picked up.
-        This method will be called by the PickupCarrier picking the Pickupable up.
+
+    /**
+    @brief
+        Can be called to pick up a Pickupable.
     @param carrier
-        The PickupCarrier that picked the Pickupable up.
-    @return
-        Returns false if, for some reason, the pickup could not be picked up, e.g. it was picked up already.
-    */
-    bool Pickupable::pickedUp(PickupCarrier* carrier)
-    {
-        if(this->isPickedUp()) //!< If the Pickupable is already picked up.
-            return false;
+        A pointer to the PickupCarrier that picks up the Pickupable.
+    @return
+        Returns true if the Pickupable was picked up, false if not.
+    */
+    bool Pickupable::pickup(PickupCarrier* carrier)
+    {
+        if(carrier == NULL || this->isPickedUp()) //!< If carrier is NULL or the Pickupable is already picked up.
+            return false;
+
+        if(!this->setCarrier(carrier))
+        {
+            COUT(3) << "A Pickupable (&" << this << ") was trying to be added to a PickupCarrier, but was already present." << std::endl;
+            return false;
+        }
         
+        this->setPickedUp(true);
         COUT(4) << "Pickupable (&" << this << ") got picked up by a PickupCarrier (&" << carrier << ")." << std::endl;
-        this->setCarrier(carrier);
-        this->setPickedUp(true);
-        return true;
-    }
-    
+        return true;
+    }
+
+    /**
+    @brief
+        Can be called to drop a Pickupable.
+    @param createSpawner
+        If true a spawner is to be created for the dropped Pickupable. True is default.
+    @return
+        Returns true if the Pickupable has been dropped, false if not.
+    */
+    bool Pickupable::drop(bool createSpawner)
+    {
+        if(!this->isPickedUp()) // If the Pickupable is not picked up.
+            return false;
+
+        assert(this->getCarrier()); // The Carrier cannot be NULL at this point.
+        if(!this->getCarrier()->removePickup(this)) //TODO Shouldn't this be a little later?
+            COUT(2) << "Pickupable (&" << this << ", " << this->getIdentifier()->getName() << ") is being dropped, but it was not present in the PickupCarriers list of pickups." << std::endl;
+
+        COUT(4) << "Pickupable (&" << this << ") got dropped up by a PickupCarrier (&" << this->getCarrier() << ")." << std::endl;
+        this->setUsed(false);
+        this->setPickedUp(false);
+
+        bool created = false;
+        if(createSpawner)
+            created = this->createSpawner();
+
+        this->setCarrier(NULL);
+
+        if(!created && createSpawner) // If a PickupSpawner should have been created but wasn't.
+            this->destroy();
+
+        return true;
+    }
+
     /**
     @brief
@@ -189,14 +266,17 @@
     bool Pickupable::setPickedUp(bool pickedUp)
     {
-        if(this->pickedUp_ == pickedUp)
-            return false;
-        
+        if(this->pickedUp_ == pickedUp) // If the picked up status has not changed.
+            return false;
+
         COUT(4) << "Pickupable (&" << this << ") set to pickedUp " << pickedUp << "." << std::endl;
-        
+
         this->pickedUp_ = pickedUp;
+        if(!pickedUp) // if the Pickupable has been dropped it unregisters itself with its PickupCarrier.
+            this->getCarrier()->removePickup(this);
         this->changedPickedUp();
-        return true;
-    }
-        
+        GUIManager::getInstance().getLuaState()->doString("PickupInventory.update()");
+        return true;
+    }
+
     /**
     @brief
@@ -204,11 +284,21 @@
     @param carrier
         Sets the input PickupCarrier as the carrier of the pickup.
-    */
-    inline bool Pickupable::setCarrier(PickupCarrier* carrier)
-    {
-        if(this->carrier_ == carrier)
-            return false;
-        
+    @param tell
+        If true (default) the pickup is added to the list of pickups in the PickupCarrier.
+    @return
+        Returns true if successful, false if not.
+    */
+    bool Pickupable::setCarrier(orxonox::PickupCarrier* carrier, bool tell)
+    {
+        if(this->carrier_ == carrier) // If the PickupCarrier doesn't change.
+            return false;
+
         COUT(4) << "Pickupable (&" << this << ") changed Carrier (& " << carrier << ")." << std::endl;
+
+        if(carrier != NULL && tell)
+        {
+            if(!carrier->addPickup(this))
+                return false;
+        }
         
         this->carrier_ = carrier;
@@ -216,33 +306,14 @@
         return true;
     }
-    
-    /**
-    @brief 
-        Sets the Pickupable to not picked up or dropped.
-        This method will be called by the PickupCarrier dropping the Pickupable.
-    @return
-        Returns false if the pickup could not be dropped.
-    */
-    bool Pickupable::dropped(void)
-    {
-        if(!this->isPickedUp()) //!< If the Pickupable is not picked up.
-            return false;
-        
-        COUT(4) << "Pickupable (&" << this << ") got dropped up by a PickupCarrier (&" << this->getCarrier() << ")." << std::endl;
-        this->setUsed(false);
-        this->setPickedUp(false);
-        
-        bool created = this->createSpawner();
-        
-        this->setCarrier(NULL);
-        
-        if(!created)
-        {
-            this->destroy();
-        }
-        
-        return true;
-    }
-    
+
+    /**
+    @brief
+        Is called by the PickupCarrier when it is being destroyed.
+    */
+    void Pickupable::carrierDestroyed(void)
+    {
+        this->destroy();
+    }
+
     /**
     @brief
@@ -255,11 +326,11 @@
         OrxonoxClass* item = NULL;
         this->clone(item);
-        
+
         Pickupable* pickup = dynamic_cast<Pickupable*>(item);
-        
+
         COUT(4) << "Pickupable (&" << this << ") cloned. Clone is new Pickupable (&" << pickup << ")." << std::endl;
         return pickup;
     }
-    
+
     /**
     @brief
@@ -273,4 +344,20 @@
         SUPER(Pickupable, clone, item);
     }
-    
+
+    /**
+    @brief
+        Method to transcribe a Pickupable as a Rewardable to the player.
+    @param player
+        A pointer to the PlayerInfo, do whatever you want with it.
+    @return
+        Return true if successful.
+    */
+    bool Pickupable::reward(PlayerInfo* player)
+    {
+        ControllableEntity* entity = player->getControllableEntity();
+        Pawn* pawn = static_cast<Pawn*>(entity);
+        PickupCarrier* carrier = static_cast<PickupCarrier*>(pawn);
+        return this->pickup(carrier);
+    }
+
 }
