Index: code/trunk/src/orxonox/weaponsystem/Munition.cc
===================================================================
--- code/trunk/src/orxonox/weaponsystem/Munition.cc	(revision 9667)
+++ code/trunk/src/orxonox/weaponsystem/Munition.cc	(revision 11052)
@@ -24,5 +24,5 @@
  *      Fabian 'x3n' Landau
  *   Co-authors:
- *      ...
+ *      Fabien Vultier
  *
  */
@@ -32,4 +32,5 @@
 #include "core/CoreIncludes.h"
 #include "core/command/Executor.h"
+#include "core/XMLPort.h"
 
 namespace orxonox
@@ -43,23 +44,33 @@
         this->maxMunitionPerMagazine_ = 10;
         this->maxMagazines_ = 10;
-        this->magazines_ = 10;
-
-        this->bUseSeparateMagazines_ = false;
-        this->bStackMunition_ = true;
+        this->unassignedMagazines_ = 10;
+
+        this->deployment_ = MunitionDeployment::Stack;
         this->bAllowMunitionRefilling_ = true;
         this->bAllowMultiMunitionRemovementUnderflow_ = true;
 
-        this->reloadTime_ = 0;
+        this->reloadTime_ = 0.5f;
+
+        this->lastFilledWeaponMode_ = NULL;
     }
 
     Munition::~Munition()
     {
-        for (std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.begin(); it != this->currentMagazines_.end(); ++it)
+        for (std::map<WeaponMode*, Magazine*>::iterator it = this->assignedMagazines_.begin(); it != this->assignedMagazines_.end(); ++it)
             delete it->second;
     }
 
+    void Munition::XMLPort(Element& xmlelement, XMLPort::Mode mode)
+    {
+        SUPER(Munition, XMLPort, xmlelement, mode);
+
+        XMLPortParam(Munition, "initialmagazines", setNumMagazines, getNumMagazines, xmlelement, mode);
+        XMLPortParam(Munition, "maxmagazines", setMaxMagazines, getMaxMagazines, xmlelement, mode);
+        XMLPortParam(Munition, "munitionpermagazine", setMaxMunitionPerMagazine, getMaxMunitionPerMagazine, xmlelement, mode);
+    }
+
     Munition::Magazine* Munition::getMagazine(WeaponMode* user) const
     {
-        if (this->bUseSeparateMagazines_)
+        if (deployment_ == MunitionDeployment::Separate)
         {
             // For separated magazines we definitively need a given user
@@ -68,6 +79,6 @@
 
             // Use the map to get the magazine assigned to the given user
-            std::map<WeaponMode*, Magazine*>::const_iterator it = this->currentMagazines_.find(user);
-            if (it != this->currentMagazines_.end())
+            std::map<WeaponMode*, Magazine*>::const_iterator it = this->assignedMagazines_.find(user);
+            if (it != this->assignedMagazines_.end())
                 return it->second;
         }
@@ -75,6 +86,6 @@
         {
             // We don't use separate magazines for each user, so just take the first magazine
-            if (this->currentMagazines_.size() > 0)
-                return this->currentMagazines_.begin()->second;
+            if (this->assignedMagazines_.size() > 0)
+                return this->assignedMagazines_.begin()->second;
         }
 
@@ -87,7 +98,7 @@
         if (magazine)
         {
-            if (this->bStackMunition_)
+            if (deployment_ == MunitionDeployment::Stack)
                 // With stacked munition every magazine contributes to the total amount
-                return this->maxMunitionPerMagazine_ * this->magazines_ + magazine->munition_;
+                return this->maxMunitionPerMagazine_ * this->unassignedMagazines_ + magazine->munition_;
             else
                 // Wihtout stacked munition we just consider the current magazine
@@ -109,18 +120,23 @@
     unsigned int Munition::getNumMagazines() const
     {
-        if (this->bStackMunition_)
+        if (deployment_ == MunitionDeployment::Stack)
         {
             // If we stack munition and the current magazine is still full, it counts too
             Magazine* magazine = this->getMagazine(0);
             if (magazine && magazine->munition_ == this->maxMunitionPerMagazine_)
-                return this->magazines_ + 1;
-        }
-
-        return this->magazines_;
+                return this->unassignedMagazines_ + 1;
+        }
+
+        return this->unassignedMagazines_;
+    }
+
+    void Munition::setNumMagazines(unsigned int numMagazines)
+    {
+        this->unassignedMagazines_ = numMagazines;
     }
 
     unsigned int Munition::getMaxMunition() const
     {
-        if (this->bStackMunition_)
+        if (deployment_ == MunitionDeployment::Stack)
             return this->maxMunitionPerMagazine_ * this->maxMagazines_;
         else
@@ -135,17 +151,26 @@
             unsigned int munition = magazine->munition_;
 
-            // If we stack munition, we con't care about the current magazine - we just need enough munition in total
-            if (this->bStackMunition_)
-                munition += this->maxMunitionPerMagazine_ * this->magazines_;
+            // If we stack munition, we don't care about the current magazine - we just need enough munition in total
+            if (deployment_ == MunitionDeployment::Stack)
+            {
+                munition += this->maxMunitionPerMagazine_ * this->unassignedMagazines_;
+            }
 
             if (munition == 0)
+            {
                 // Absolutely no munition - no chance to take munition
                 return false;
+            }
             else if (this->bAllowMultiMunitionRemovementUnderflow_)
+            {
                 // We're not empty AND we allow underflow, so this will always work
                 return true;
+            }
             else
+            {
                 // We don't allow underflow, so we have to check the amount
                 return (munition >= amount);
+            }
+
         }
         return false;
@@ -169,5 +194,5 @@
             {
                 // Not enough munition
-                if (this->bStackMunition_)
+                if (deployment_ == MunitionDeployment::Stack)
                 {
                     // We stack munition, so just take what we can and then load the next magazine
@@ -175,5 +200,5 @@
                     magazine->munition_ = 0;
 
-                    if (this->reload(0))
+                    if (this->reload(NULL))
                         // Successfully reloaded, continue recursively
                         return this->takeMunition(amount, 0);
@@ -199,5 +224,5 @@
     {
         // As long as we have enough magazines (and don't stack munition) we can reload
-        return (this->magazines_ > 0 && !this->bStackMunition_);
+        return (this->unassignedMagazines_ > 0 && deployment_ != MunitionDeployment::Stack);
     }
 
@@ -207,5 +232,5 @@
         if (magazine)
         {
-            if (this->bStackMunition_)
+            if (deployment_ == MunitionDeployment::Stack)
                 // With stacked munition, we never have to reload
                 return false;
@@ -227,26 +252,32 @@
 
         // Check if we actually can reload
-        if (this->magazines_ == 0)
+        if (this->unassignedMagazines_ == 0)
             return false;
 
         // If we use separate magazines for each user, we definitively need a user given
-        if (this->bUseSeparateMagazines_ && !user)
+        if (deployment_ == MunitionDeployment::Separate && !user)
             return false;
 
         // If we don't use separate magazines, set user to 0
-        if (!this->bUseSeparateMagazines_)
-            user = 0;
+        if (deployment_ != MunitionDeployment::Separate)
+        {
+            user = NULL;
+        }
 
         // Remove the current magazine for the given user
-        std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.find(user);
-        if (it != this->currentMagazines_.end())
-        {
+        std::map<WeaponMode*, Magazine*>::iterator it = this->assignedMagazines_.find(user);
+        if (it != this->assignedMagazines_.end())
+        {
+            if (it->first == lastFilledWeaponMode_)
+            {
+                lastFilledWeaponMode_ = NULL;
+            }            
             delete it->second;
-            this->currentMagazines_.erase(it);
+            this->assignedMagazines_.erase(it);
         }
 
         // Load a new magazine
-        this->currentMagazines_[user] = new Magazine(this, bUseReloadTime);
-        this->magazines_--;
+        this->assignedMagazines_[user] = new Magazine(this, bUseReloadTime);
+        this->unassignedMagazines_--;
 
         return true;
@@ -260,5 +291,5 @@
             return false;
 
-        if (this->bStackMunition_)
+        if (deployment_ == MunitionDeployment::Stack)
         {
             // If we stack munition, we can always add munition until we reach the limit
@@ -268,5 +299,5 @@
         {
             // Return true if any of the current magazines is not full (loading counts as full although it returns 0 munition)
-            for (std::map<WeaponMode*, Magazine*>::const_iterator it = this->currentMagazines_.begin(); it != this->currentMagazines_.end(); ++it)
+            for (std::map<WeaponMode*, Magazine*>::const_iterator it = this->assignedMagazines_.begin(); it != this->assignedMagazines_.end(); ++it)
                 if (it->second->munition_ < this->maxMunitionPerMagazine_ && it->second->bLoaded_)
                     return true;
@@ -281,8 +312,8 @@
             return false;
 
-        if (this->bStackMunition_)
+        if (deployment_ == MunitionDeployment::Stack)
         {
             // Stacking munition means, if a magazine gets full, the munition adds to a new magazine
-            Magazine* magazine = this->getMagazine(0);
+            Magazine* magazine = this->getMagazine(NULL);
             if (magazine)
             {
@@ -294,11 +325,11 @@
                 {
                     magazine->munition_ -= this->maxMunitionPerMagazine_;
-                    this->magazines_++;
+                    this->unassignedMagazines_++;
                 }
 
-                // If we reached the limit, reduze both magazines and munition to the maximum
-                if (this->magazines_ >= this->maxMagazines_)
-                {
-                    this->magazines_ = this->maxMagazines_ - 1;
+                // If we reached the limit, reduce both magazines and munition to the maximum
+                if (this->unassignedMagazines_ >= this->maxMagazines_)
+                {
+                    this->unassignedMagazines_ = this->maxMagazines_;
                     magazine->munition_ = this->maxMunitionPerMagazine_;
                 }
@@ -312,9 +343,24 @@
         else
         {
+            std::map<WeaponMode*, Magazine*>::iterator it;
+
+            // If the pointer to the weapon mode whose magazine got munition added to is NULL, then set the iterator to the beginning of the map
+            // Otherwise set it to the next weapon mode
+            if (lastFilledWeaponMode_ == NULL)
+            {
+                it = this->assignedMagazines_.begin();
+            }
+            else
+            {
+                it = this->assignedMagazines_.find(lastFilledWeaponMode_);
+                ++ it;
+            }
+
             // Share the munition equally to the current magazines
+            bool firstLoop = true;
             while (amount > 0)
             {
                 bool change = false;
-                for (std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.begin(); it != this->currentMagazines_.end(); ++it)
+                while (it != this->assignedMagazines_.end())
                 {
                     // Add munition if the magazine isn't full (but only to loaded magazines)
@@ -323,11 +369,20 @@
                         it->second->munition_++;
                         amount--;
+                        lastFilledWeaponMode_ = it->first;
                         change = true;
                     }
+
+                    ++it;
                 }
 
                 // If there was no change in a loop, all magazines are full (or locked due to loading)
-                if (!change)
+                // Because the first loop does not start at the beginning of the map we have to treat is separately
+                if (!change && !firstLoop)
+                {
                     break;
+                }                    
+
+                it = this->assignedMagazines_.begin();
+                firstLoop = false;
             }
 
@@ -340,34 +395,38 @@
         // TODO: 'amount' is not used
 
-        if (this->bStackMunition_)
+        if (deployment_ == MunitionDeployment::Stack)
             // If we stack munition, we can always add new magazines because they contribute directly to the munition
             return (this->getNumMunition(0) < this->getMaxMunition());
         else
             // If we don't stack munition, we're more limited
-            return ((this->currentMagazines_.size() + this->magazines_) < this->maxMagazines_);
-    }
-
-    bool Munition::addMagazines(unsigned int amount)
-    {
+            return ((this->assignedMagazines_.size() + this->unassignedMagazines_) < this->maxMagazines_);
+    }
+
+    unsigned int Munition::addMagazines(unsigned int amount)
+    {
+        unsigned int addedMagazines = 0;
+
         if (!this->canAddMagazines(amount))
-            return false;
+            return 0;
 
         // Calculate how many magazines are needed
-        int needed_magazines = this->maxMagazines_ - this->magazines_ - this->currentMagazines_.size();
+        int needed_magazines = this->maxMagazines_ - this->unassignedMagazines_ - this->assignedMagazines_.size();
 
         // If zero or less magazines are needed, we definitively don't need more magazines (unless we stack munition - then a magazine contributes directly to the munition)
-        if (needed_magazines <= 0 && !this->bStackMunition_)
-            return false;
+        if (needed_magazines <= 0 && deployment_ != MunitionDeployment::Stack)
+            return 0;
 
         if (amount <= static_cast<unsigned int>(needed_magazines))
         {
             // We need more magazines than we get, so just add them
-            this->magazines_ += amount;
+            this->unassignedMagazines_ += amount;
+            addedMagazines = amount;
         }
         else
         {
             // We get more magazines than we need, so just add the needed amount
-            this->magazines_ += needed_magazines;
-            if (this->bStackMunition_)
+            this->unassignedMagazines_ += needed_magazines;
+            addedMagazines = needed_magazines;
+            if (deployment_ == MunitionDeployment::Stack)
             {
                 // We stack munition, so the additional amount contributes directly to the munition of the current magazine
@@ -378,17 +437,31 @@
         }
 
-        return true;
+        // Reload as many empty magazines as possible
+        // Double loop and break is needed because the reload function changes the assigned magazines. This may confuse the iterator.
+        for (unsigned int i = 0; i < addedMagazines; ++i)
+        {
+            for (std::map<WeaponMode*, Magazine*>::iterator it = this->assignedMagazines_.begin(); it != this->assignedMagazines_.end(); ++it)
+            {
+                if (needReload(it->first))
+                {
+                    reload(it->first);
+                    break;
+                }
+            }
+        }
+
+        return addedMagazines;
     }
 
     bool Munition::canRemoveMagazines(unsigned int amount) const
     {
-        if (this->bStackMunition_)
-        {
-            if (this->magazines_ >= amount)
+        if (deployment_ == MunitionDeployment::Stack)
+        {
+            if (this->unassignedMagazines_ >= amount)
             {
                 // We have enough magazines
                 return true;
             }
-            else if (this->magazines_ == amount - 1)
+            else if (this->unassignedMagazines_ == amount - 1)
             {
                 // We lack one magazine, check if the current magazine is still full, if yes we're fine
@@ -406,5 +479,5 @@
         {
             // In case we're not stacking munition, just check the number of magazines
-            return (this->magazines_ >= amount);
+            return (this->unassignedMagazines_ >= amount);
         }
 
@@ -417,13 +490,13 @@
             return false;
 
-        if (this->magazines_ >= amount)
+        if (this->unassignedMagazines_ >= amount)
         {
             // We have enough magazines, just remove the amount
-            this->magazines_ -= amount;
-        }
-        else if (this->bStackMunition_)
+            this->unassignedMagazines_ -= amount;
+        }
+        else if (deployment_ == MunitionDeployment::Stack)
         {
             // We don't have enough magazines, but we're stacking munition, so additionally remove the bullets from the current magazine
-            this->magazines_ = 0;
+            this->unassignedMagazines_ = 0;
             Magazine* magazine = this->getMagazine(0);
             if (magazine)
@@ -437,17 +510,21 @@
     {
         // If we use separate magazines, we need a user
-        if (this->bUseSeparateMagazines_ && !user)
+        if (deployment_ == MunitionDeployment::Separate && !user)
             return false;
 
         // If we don't use separate magazines, set user to 0
-        if (!this->bUseSeparateMagazines_)
-            user = 0;
+        if (deployment_ != MunitionDeployment::Separate)
+            user = NULL;
 
         // Remove the current magazine for the given user
-        std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.find(user);
-        if (it != this->currentMagazines_.end())
-        {
+        std::map<WeaponMode*, Magazine*>::iterator it = this->assignedMagazines_.find(user);
+        if (it != this->assignedMagazines_.end())
+        {
+            if (it->first == lastFilledWeaponMode_)
+            {
+                lastFilledWeaponMode_ = NULL;
+            }
             delete it->second;
-            this->currentMagazines_.erase(it);
+            this->assignedMagazines_.erase(it);           
             return true;
         }
@@ -465,5 +542,5 @@
         this->bLoaded_ = false;
 
-        if (bUseReloadTime && munition->reloadTime_ > 0 && !munition->bStackMunition_)
+        if (bUseReloadTime && munition->reloadTime_ > 0 && munition->deployment_ != MunitionDeployment::Stack)
         {
             const ExecutorPtr& executor = createExecutor(createFunctor(&Magazine::loaded, this));
