Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Apr 18, 2009, 6:14:52 PM (16 years ago)
Author:
landauf
Message:

Added many new features in the Munition class:

  • there are now 3 modes: a) every weapon has it's own magazine b) all weapons use the same magazin c) no magazines, just a big munition pool
  • the Munition class handles the reloading of the magazine

Split the Weapon class into Weapon and WeaponMode. WeaponMode creates the fire of the Weapon. A weapon can own several WeaponModes (for example primary and secondary fire). But it's also possible to have a weapon with several muzzles which all fire at the same time (there's a WeaponMode for each muzzle).

Renamed LaserGun to LaserFire and Fusion to FusionFire. They inherit now from WeaponMode.

Changed the code in the Weapon class to use the new Munition functionality.

Added ReplenishingMunition, a subclass of Munition that replenishes itself (used for LaserGunMunition).

Added a reload command to reload magazines.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • code/branches/weapons/src/orxonox/objects/weaponSystem/Munition.cc

    r2912 r2918  
    2020 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    2121 *
    22  *   Author:
     22 *   Authors:
    2323 *      Martin Polak
     24 *      Fabian 'x3n' Landau
    2425 *   Co-authors:
    2526 *      ...
     
    4041        RegisterObject(Munition);
    4142
     43        this->maxMunitionPerMagazine_ = 10;
     44        this->maxMagazines_ = 10;
     45        this->magazines_ = 10;
     46
     47        this->bUseSeparateMagazines_ = false;
     48        this->bStackMunition_ = true;
     49        this->bAllowMunitionRefilling_ = true;
     50        this->bAllowMultiMunitionRemovementUnderflow_ = true;
     51
     52        this->reloadTime_ = 0;
     53
    4254COUT(0) << "+Munition" << std::endl;
    4355    }
     
    4557    Munition::~Munition()
    4658    {
     59        for (std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.begin(); it != this->currentMagazines_.end(); ++it)
     60            delete it->second;
     61
    4762COUT(0) << "~Munition" << std::endl;
    4863    }
    4964
    50     unsigned int Munition::bullets()
    51     {
    52         if (this->bullets_ > 0)
    53             return bullets_;
     65    Munition::Magazine* Munition::getMagazine(WeaponMode* user) const
     66    {
     67        if (this->bUseSeparateMagazines_)
     68        {
     69            // For separated magazines we definitively need a given user
     70            if (!user)
     71                return 0;
     72
     73            // Use the map to get the magazine assigned to the given user
     74            std::map<WeaponMode*, Magazine*>::const_iterator it = this->currentMagazines_.find(user);
     75            if (it != this->currentMagazines_.end())
     76                return it->second;
     77        }
     78        else
     79        {
     80            // We don't use separate magazines for each user, so just take the first magazine
     81            if (this->currentMagazines_.size() > 0)
     82                return this->currentMagazines_.begin()->second;
     83        }
     84
     85        return 0;
     86    }
     87
     88    unsigned int Munition::getNumMunition(WeaponMode* user) const
     89    {
     90        Magazine* magazine = this->getMagazine(user);
     91        if (magazine)
     92        {
     93            if (this->bStackMunition_)
     94                // With stacked munition every magazine contributes to the total amount
     95                return this->maxMunitionPerMagazine_ * this->magazines_ + magazine->munition_;
     96            else
     97                // Wihtout stacked munition we just consider the current magazine
     98                return magazine->munition_;
     99        }
     100        return 0;
     101    }
     102
     103    unsigned int Munition::getNumMunitionInCurrentMagazine(WeaponMode* user) const
     104    {
     105        // In contrast to getNumMunition() we really just consider the current magazine, even if we're stacking munition
     106        Magazine* magazine = this->getMagazine(user);
     107        if (magazine)
     108            return magazine->munition_;
    54109        else
    55110            return 0;
    56111    }
    57112
    58     unsigned int Munition::magazines()
    59     {
    60         if (this->magazines_ > 0)
    61             return magazines_;
    62         else
    63             return 0;
    64     }
    65 
    66     void Munition::setMaxBullets(unsigned int amount)
    67     { this->maxBullets_ = amount; }
    68 
    69     void Munition::setMaxMagazines(unsigned int amount)
    70     { this->maxMagazines_ = amount; }
    71 
    72     void Munition::removeBullets(unsigned int amount)
    73     {
    74         if ( this->bullets_ != 0 )
    75             this->bullets_ = this->bullets_ - amount;
    76     }
    77 
    78     void Munition::removeMagazines(unsigned int amount)
    79     {
    80         if ( this->magazines_ != 0 )
    81             this->magazines_ = this->magazines_ - amount;
    82     }
    83 
    84     void Munition::addBullets(unsigned int amount)
    85     {
    86         if ( this->bullets_ == this->maxBullets_ )
    87         {
    88             //cannot add bullets to actual magazine
    89         }
    90         else
    91             this->bullets_ = this->bullets_ + amount;
    92     }
    93 
    94     void Munition::addMagazines(unsigned int amount)
    95     {
    96         if ( this->magazines_ == this->maxMagazines_ )
    97         {
    98             //no more capacity for another magazine
    99         }
    100         else
    101             this->magazines_ = this->magazines_ + amount;
    102     }
    103 
    104 
    105     void Munition::fillBullets()
    106     {
    107         this->bullets_ = this->maxBullets_;
    108     }
    109 
    110     void Munition::fillMagazines()
    111     {
    112         this->magazines_ = this->maxMagazines_;
     113    unsigned int Munition::getNumMagazines() const
     114    {
     115        if (this->bStackMunition_)
     116        {
     117            // If we stack munition and the current magazine is still full, it counts too
     118            Magazine* magazine = this->getMagazine(0);
     119            if (magazine && magazine->munition_ == this->maxMunitionPerMagazine_)
     120                return this->magazines_ + 1;
     121        }
     122
     123        return this->magazines_;
     124    }
     125
     126    unsigned int Munition::getMaxMunition() const
     127    {
     128        if (this->bStackMunition_)
     129            return this->maxMunitionPerMagazine_ * this->maxMagazines_;
     130        else
     131            return this->maxMunitionPerMagazine_;
     132    }
     133
     134    bool Munition::canTakeMunition(unsigned int amount, WeaponMode* user) const
     135    {
     136        Magazine* magazine = this->getMagazine(user);
     137        if (magazine && magazine->bLoaded_)
     138        {
     139            unsigned int munition = magazine->munition_;
     140
     141            // If we stack munition, we con't care about the current magazine - we just need enough munition in total
     142            if (this->bStackMunition_)
     143                munition += this->maxMunitionPerMagazine_ * this->magazines_;
     144
     145            if (munition == 0)
     146                // Absolutely no munition - no chance to take munition
     147                return false;
     148            else if (this->bAllowMultiMunitionRemovementUnderflow_)
     149                // We're not empty AND we allow underflow, so this will always work
     150                return true;
     151            else
     152                // We don't allow underflow, so we have to check the amount
     153                return (munition >= amount);
     154        }
     155        return false;
     156    }
     157
     158    bool Munition::takeMunition(unsigned int amount, WeaponMode* user)
     159    {
     160        if (!this->canTakeMunition(amount, user))
     161            return false;
     162
     163        Magazine* magazine = this->getMagazine(user);
     164        if (magazine && magazine->bLoaded_)
     165        {
     166            if (magazine->munition_ >= amount)
     167            {
     168                // Enough munition
     169                magazine->munition_ -= amount;
     170                return true;
     171            }
     172            else
     173            {
     174                // Not enough munition
     175                if (this->bStackMunition_)
     176                {
     177                    // We stack munition, so just take what we can and then load the next magazine
     178                    amount -= magazine->munition_;
     179                    magazine->munition_ = 0;
     180
     181                    if (this->reload(0))
     182                        // Successfully reloaded, continue recursively
     183                        return this->takeMunition(amount, 0);
     184                    else
     185                        // We don't have more magazines, so let's just hope we allow underflow
     186                        return this->bAllowMultiMunitionRemovementUnderflow_;
     187                }
     188                else
     189                {
     190                    // We don't stack, so we can only take munition if this is allowed
     191                    if (magazine->munition_ > 0 && this->bAllowMultiMunitionRemovementUnderflow_)
     192                    {
     193                        magazine->munition_ -= 0;
     194                        return true;
     195                    }
     196                }
     197            }
     198        }
     199        return false;
     200    }
     201
     202    bool Munition::canReload() const
     203    {
     204        // As long as we have enough magazines (and don't stack munition) we can reload
     205        return (this->magazines_ > 0 && !this->bStackMunition_);
     206    }
     207
     208    bool Munition::needReload(WeaponMode* user) const
     209    {
     210        Magazine* magazine = this->getMagazine(user);
     211        if (magazine)
     212        {
     213            if (this->bStackMunition_)
     214                // With stacked munition, we never have to reload
     215                return false;
     216            else
     217                // We need to reload if an already loaded magazine is empty
     218                return (magazine->bLoaded_ && magazine->munition_ == 0);
     219        }
     220        else
     221            // No magazine - we definitively need to reload
     222            return true;
     223    }
     224
     225    bool Munition::reload(WeaponMode* user, bool bUseReloadTime)
     226    {
     227        // Don't reload if we're already reloading
     228        Magazine* magazine = this->getMagazine(user);
     229        if (magazine && !magazine->bLoaded_)
     230            return false;
     231
     232        // Check if we actually can reload
     233        if (this->magazines_ == 0)
     234            return false;
     235
     236        // If we use separate magazines for each user, we definitively need a user given
     237        if (this->bUseSeparateMagazines_ && !user)
     238            return false;
     239
     240        // If we don't use separate magazines, set user to 0
     241        if (!this->bUseSeparateMagazines_)
     242            user = 0;
     243
     244        // Remove the current magazine for the given user
     245        std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.find(user);
     246        if (it != this->currentMagazines_.end())
     247        {
     248            delete it->second;
     249            this->currentMagazines_.erase(it);
     250        }
     251
     252        // Load a new magazine
     253        this->currentMagazines_[user] = new Magazine(this, bUseReloadTime);
     254        this->magazines_--;
     255
     256        return true;
     257    }
     258
     259    bool Munition::canAddMunition(unsigned int amount) const
     260    {
     261        if (!this->bAllowMunitionRefilling_)
     262            return false;
     263
     264        if (this->bStackMunition_)
     265        {
     266            // If we stack munition, we can always add munition until we reach the limit
     267            return (this->getNumMunition(0) < this->getMaxMunition());
     268        }
     269        else
     270        {
     271            // Return true if any of the current magazines is not full (loading counts as full although it returns 0 munition)
     272            for (std::map<WeaponMode*, Magazine*>::const_iterator it = this->currentMagazines_.begin(); it != this->currentMagazines_.end(); ++it)
     273                if (it->second->munition_ < this->maxMunitionPerMagazine_ && it->second->bLoaded_)
     274                    return true;
     275        }
     276
     277        return false;
     278    }
     279
     280    bool Munition::addMunition(unsigned int amount)
     281    {
     282        if (!this->canAddMunition(amount))
     283            return false;
     284
     285        if (this->bStackMunition_)
     286        {
     287            // Stacking munition means, if a magazine gets full, the munition adds to a new magazine
     288            Magazine* magazine = this->getMagazine(0);
     289            if (magazine)
     290            {
     291                // Add the whole amount
     292                magazine->munition_ += amount;
     293
     294                // Add new magazines if the current magazine is overfull
     295                while (magazine->munition_ > this->maxMunitionPerMagazine_)
     296                {
     297                    magazine->munition_ -= this->maxMunitionPerMagazine_;
     298                    this->magazines_++;
     299                }
     300
     301                // If we reached the limit, reduze both magazines and munition to the maximum
     302                if (this->magazines_ >= this->maxMagazines_)
     303                {
     304                    this->magazines_ = this->maxMagazines_ - 1;
     305                    magazine->munition_ = this->maxMunitionPerMagazine_;
     306                }
     307
     308                return true;
     309            }
     310
     311            // Something went wrong
     312            return false;
     313        }
     314        else
     315        {
     316            // Share the munition equally to the current magazines
     317            while (amount > 0)
     318            {
     319                bool change = false;
     320                for (std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.begin(); it != this->currentMagazines_.end(); ++it)
     321                {
     322                    // Add munition if the magazine isn't full (but only to loaded magazines)
     323                    if (amount > 0 && it->second->munition_ < this->maxMunitionPerMagazine_ && it->second->bLoaded_)
     324                    {
     325                        it->second->munition_++;
     326                        amount--;
     327                        change = true;
     328                    }
     329                }
     330
     331                // If there was no change in a loop, all magazines are full (or locked due to loading)
     332                if (!change)
     333                    break;
     334            }
     335
     336            return true;
     337        }
     338    }
     339
     340    bool Munition::canAddMagazines(unsigned int amount) const
     341    {
     342        if (this->bStackMunition_)
     343            // If we stack munition, we can always add new magazines because they contribute directly to the munition
     344            return (this->getNumMunition(0) < this->getMaxMunition());
     345        else
     346            // If we don't stack munition, we're more limited
     347            return ((this->currentMagazines_.size() + this->magazines_) < this->maxMagazines_);
     348    }
     349
     350    bool Munition::addMagazines(unsigned int amount)
     351    {
     352        if (!this->canAddMagazines(amount))
     353            return false;
     354
     355        // Calculate how many magazines are needed
     356        int needed_magazines = this->maxMagazines_ - this->magazines_ - this->currentMagazines_.size();
     357
     358        // 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)
     359        if (needed_magazines <= 0 && !this->bStackMunition_)
     360            return false;
     361
     362        if (amount <= needed_magazines)
     363        {
     364            // We need more magazines than we get, so just add them
     365            this->magazines_ += amount;
     366        }
     367        else
     368        {
     369            // We get more magazines than we need, so just add the needed amount
     370            this->magazines_ += needed_magazines;
     371            if (this->bStackMunition_)
     372            {
     373                // We stack munition, so the additional amount contributes directly to the munition of the current magazine
     374                Magazine* magazine = this->getMagazine(0);
     375                if (magazine)
     376                    magazine->munition_ = this->maxMunitionPerMagazine_;
     377            }
     378        }
     379
     380        return true;
     381    }
     382
     383    bool Munition::canRemoveMagazines(unsigned int amount) const
     384    {
     385        if (this->bStackMunition_)
     386        {
     387            if (this->magazines_ >= amount)
     388            {
     389                // We have enough magazines
     390                return true;
     391            }
     392            else if (this->magazines_ == amount - 1)
     393            {
     394                // We lack one magazine, check if the current magazine is still full, if yes we're fine
     395                Magazine* magazine = this->getMagazine(0);
     396                if (magazine && magazine->munition_ == this->maxMunitionPerMagazine_)
     397                    return true;
     398            }
     399            else
     400            {
     401                // We don't have enough magazines
     402                return false;
     403            }
     404        }
     405        else
     406        {
     407            // In case we're not stacking munition, just check the number of magazines
     408            return (this->magazines_ >= amount);
     409        }
     410    }
     411
     412    bool Munition::removeMagazines(unsigned int amount)
     413    {
     414        if (!this->canRemoveMagazines(amount))
     415            return false;
     416
     417        if (this->magazines_ >= amount)
     418        {
     419            // We have enough magazines, just remove the amount
     420            this->magazines_ -= amount;
     421        }
     422        else if (this->bStackMunition_)
     423        {
     424            // We don't have enough magazines, but we're stacking munition, so additionally remove the bullets from the current magazine
     425            this->magazines_ = 0;
     426            Magazine* magazine = this->getMagazine(0);
     427            if (magazine)
     428                magazine->munition_ = 0;
     429        }
     430
     431        return true;
     432    }
     433
     434    bool Munition::dropMagazine(WeaponMode* user)
     435    {
     436        // If we use separate magazines, we need a user
     437        if (this->bUseSeparateMagazines_ && !user)
     438            return false;
     439
     440        // If we don't use separate magazines, set user to 0
     441        if (!this->bUseSeparateMagazines_)
     442            user = 0;
     443
     444        // Remove the current magazine for the given user
     445        std::map<WeaponMode*, Magazine*>::iterator it = this->currentMagazines_.find(user);
     446        if (it != this->currentMagazines_.end())
     447        {
     448            delete it->second;
     449            this->currentMagazines_.erase(it);
     450            return true;
     451        }
     452
     453        return false;
     454    }
     455
     456
     457    /////////////////////
     458    // Magazine struct //
     459    /////////////////////
     460    Munition::Magazine::Magazine(Munition* munition, bool bUseReloadTime)
     461    {
     462        this->munition_ = 0;
     463        this->bLoaded_ = false;
     464
     465        if (bUseReloadTime && (munition->reloadTime_ > 0 || munition->bStackMunition_))
     466        {
     467            ExecutorMember<Magazine>* executor = createExecutor(createFunctor(&Magazine::loaded));
     468            executor->setDefaultValues(munition);
     469
     470            this->loadTimer_.setTimer(munition->reloadTime_, false, this, executor);
     471        }
     472        else
     473            this->loaded(munition);
     474    }
     475
     476    void Munition::Magazine::loaded(Munition* munition)
     477    {
     478        this->bLoaded_ = true;
     479        this->munition_ = munition->maxMunitionPerMagazine_;
    113480    }
    114481}
Note: See TracChangeset for help on using the changeset viewer.