servicing.cpp

Go to the documentation of this file.
00001 /*
00002      This file is part of Advanced Strategic Command; http://www.asc-hq.de
00003      Copyright (C) 1994-2010  Martin Bickel  and  Marc Schellenberger
00004  
00005      This program is free software; you can redistribute it and/or modify
00006      it under the terms of the GNU General Public License as published by
00007      the Free Software Foundation; either version 2 of the License, or
00008      (at your option) any later version.
00009  
00010      This program is distributed in the hope that it will be useful,
00011      but WITHOUT ANY WARRANTY; without even the implied warranty of
00012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013      GNU General Public License for more details.
00014  
00015      You should have received a copy of the GNU General Public License
00016      along with this program; see the file COPYING. If not, write to the 
00017      Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
00018      Boston, MA  02111-1307  USA
00019 */
00020 
00021 #include <sigc++/sigc++.h>
00022 
00023 #include "servicing.h"
00024 
00025 #include "../vehicle.h"
00026 #include "../spfst.h"
00027 #include "../containercontrols.h"
00028 #include "../gameoptions.h"
00029 
00030 #include "consumeresource.h"
00031 #include "consumeammo.h"
00032 
00033 #include "context.h"
00034 
00035 enum TransferLimitation { NONE, GET, ALL };
00036 
00037 TransferLimitation getTransferLimitation( const ContainerBase* target )
00038 {
00039    if ( target->getOwner() == target->getMap()->actplayer )
00040       return NONE;
00041 
00042    if ( target->getMap()->player[target->getMap()->actplayer].diplomacy.isAllied( target->getOwner() ))
00043       return NONE;
00044 
00045    if ( target->getMap()->player[target->getMap()->actplayer].diplomacy.getState( target->getOwner() ) >= PEACE )
00046       return GET;
00047 
00048    return ALL;
00049 }
00050 
00051 
00052 
00053 ResourceWatch::ResourceWatch( ContainerBase* container )
00054 {
00055    this->container = container;
00056    orgAmount = available = container->getResource( Resources( maxint, maxint, maxint), true );
00057    storagelimit = container->putResource( Resources( maxint, maxint, maxint), true );
00058    for ( int r = 0; r < 3; ++r )
00059       if ( maxint - available.resource(r) > storagelimit.resource(r))
00060          storagelimit.resource(r) += available.resource(r);
00061       else
00062          storagelimit.resource(r) = maxint;
00063 };
00064 
00065 ContainerBase* ResourceWatch::getContainer()
00066 {
00067    return container;
00068 };
00069 
00070 const Resources ResourceWatch::amount()
00071 {
00072    return available;
00073 }
00074 
00075 
00076 const Resources ResourceWatch::avail() {
00077    TransferLimitation limit = getTransferLimitation( container );
00078    if ( limit == ALL )
00079       return Resources();
00080 
00081    if ( limit == GET ) {
00082       Resources res = available - orgAmount;
00083       for ( int r = 0; r < resourceTypeNum; ++r )
00084          if ( res.resource(r) < 0 )
00085             res.resource(r) = 0;
00086 
00087       return res;
00088    }
00089 
00090    return available;
00091 };
00092 
00093 const Resources ResourceWatch::limit() {
00094    if(  getTransferLimitation( container ) == ALL )
00095       return available;
00096    else
00097       return storagelimit;
00098 };
00099 
00100 bool ResourceWatch::putResource( int resourcetype, int amount )
00101 {
00102    Resources rr = available;
00103    rr.resource(resourcetype) += amount;
00104 
00105    for ( int r = 0; r < resourceTypeNum; ++r)
00106       if ( rr.resource(r) > storagelimit.resource(r))
00107          return false;
00108    available = rr;
00109    sigChanged( resourcetype );
00110    return true;
00111 }
00112 
00113 
00114 bool ResourceWatch::getResource( int resourcetype, int amount )
00115 {
00116    if ( available.resource(resourcetype) >= amount ) {
00117       available.resource(resourcetype) -= amount;
00118       sigChanged( resourcetype );
00119       return true;
00120    }
00121    return false;
00122 }
00123 
00124 bool ResourceWatch::getResources( Resources res )
00125 {
00126    bool b = true;
00127    for ( int r = 0; r < resourceTypeNum; ++r)
00128       if ( res.resource(r) > 0 )
00129          if ( !getResource( r, res.resource(r) ))
00130             b = false;
00131    return b;
00132 }
00133 
00134 
00135       
00136    ResourceWatch& Transferrable::getResourceWatch( const ContainerBase* unit )
00137    {
00138       assert( unit == source.getContainer() || unit == dest.getContainer() );
00139       if ( unit == source.getContainer() )
00140          return source;
00141       else
00142          return dest;
00143    }
00144 
00145    ResourceWatch& Transferrable::getOpposingResourceWatch( const ContainerBase* unit )
00146    {
00147       return getResourceWatch ( opposingContainer( unit ));
00148    }
00149 
00150    ContainerBase* Transferrable::opposingContainer( const ContainerBase* unit )
00151    {
00152       assert( unit == source.getContainer() || unit == dest.getContainer() );
00153       if ( unit == dest.getContainer() )
00154          return source.getContainer();
00155       else
00156          return dest.getContainer();
00157    }
00158 
00159    void Transferrable::show( const ContainerBase* unit )
00160    {
00161       assert( unit == source.getContainer() || unit == dest.getContainer() );
00162       if ( unit == dest.getContainer() )
00163          return sigDestAmount( ASCString::toString( getAmount( unit )));
00164       else
00165          return sigSourceAmount( ASCString::toString( getAmount( unit )));
00166    }
00167 
00168 
00169    Transferrable::Transferrable( ResourceWatch& s, ResourceWatch& d ) : source( s ) , dest( d ) {};
00170 
00171    ContainerBase* Transferrable::getSrcContainer()
00172    {
00173       return source.getContainer();
00174    }
00175 
00176    ContainerBase* Transferrable::getDstContainer()
00177    {
00178       return dest.getContainer();
00179    }
00180 
00181    bool Transferrable::setDestAmount( long amount )
00182    {
00183       return setAmount( getDstContainer(), amount ) == amount;
00184    }
00185 
00186    void Transferrable::showAll()
00187    {
00188       show( source.getContainer() );
00189       show( dest.getContainer() );
00190    }
00191 
00192    int Transferrable::setAmount( ContainerBase* target, int newamount )
00193    {
00194       transfer( target, newamount - getAmount( target ) );
00195       return getAmount( target );
00196    }
00197 
00198    void Transferrable::fill( ContainerBase* target )
00199    {
00200       setAmount( target, getMax( target, true ));
00201    }
00202 
00203 
00204    void Transferrable::empty( ContainerBase* target )
00205    {
00206       setAmount( target, 0 );
00207    }
00208 
00209 
00210 
00211    class AmmoTransferrable : public Transferrable {
00212       private:
00213          int ammoType;
00214          int sourceAmmo;
00215          int destAmmo;
00216          map<const ContainerBase*,int> produced;
00217          map<const ContainerBase*,int> orgAmmo;
00218          bool& allowAmmoProduction;
00219 
00220 
00221          int& getAmmo( const ContainerBase* unit );
00222          int put( ContainerBase* c, int toPut, bool queryOnly );
00223          int get( ContainerBase* c, int toGet, bool queryOnly );
00224          void executeTransfer( ContainerBase* from, ContainerBase* to, int amount, const Context& context );
00225       
00226       public:
00227          AmmoTransferrable( int ammo, ResourceWatch& src, ResourceWatch& dst, bool& allowProduction );      
00228          ASCString getName();
00229       
00230          int getID();
00231          int getMax( ContainerBase* c, bool avail );
00232          int getMin( ContainerBase* c, bool avail );
00233          int getAmount ( const ContainerBase* target );
00234          int transfer( ContainerBase* target, int delta );
00235          bool isExchangable() const;
00236          void commit( const Context& context );
00237    };
00238 
00239    class ResourceTransferrable : public Transferrable {
00240       private:
00241          int resourceType;
00242          bool exchangable;
00243          void warn();
00244          void srcChanged( int res );
00245          void dstChanged( int res );
00246          void executeTransfer( ContainerBase* from, ContainerBase* to, int amount, const Context& context );
00247       public:
00248          ResourceTransferrable( int resource, ResourceWatch& src, ResourceWatch& dst, bool isExchangable = true );
00249          ASCString getName();
00250          int getID();
00251          int getMax( ContainerBase* c, bool avail );
00252          int getMin( ContainerBase* c, bool avail );
00253          int getAmount ( const ContainerBase* target );
00254          int getAvail ( const ContainerBase* target );
00255          int transfer( ContainerBase* target, int delta );
00256          bool isExchangable() const;
00257          void commit(const Context& context);
00258    };
00259    
00260    
00261       
00262 
00263 
00264    void ResourceTransferrable::warn()
00265       {
00266          warningMessage( "Inconsistency in ResourceTransfer");
00267       };
00268 
00269       void ResourceTransferrable::srcChanged( int res )
00270       {
00271          if ( res == resourceType ) {
00272             show( source.getContainer() );
00273          }
00274       }
00275       
00276       void ResourceTransferrable::dstChanged( int res )
00277       {
00278          if ( res == resourceType ) {
00279             show( dest.getContainer() );
00280          }
00281       }
00282             
00283          
00284       void ResourceTransferrable::executeTransfer( ContainerBase* from, ContainerBase* to, int amount, const Context& context )
00285       {
00286          if ( amount == 0 )
00287             return;
00288          
00289          if ( amount < 0 )
00290             executeTransfer( to, from, -amount, context );
00291          else 
00292             if ( amount > 0 ) {
00293                Resources r;
00294                r.resource(resourceType) = amount;
00295                
00296                ActionResult res = (new ConsumeResource( from, r ))->execute( context );
00297                if ( !res.successful() )
00298                   throw res;
00299                
00300                res = (new ConsumeResource( to, -r))->execute( context );
00301                if ( !res.successful() )
00302                   throw res;
00303                
00304             }
00305       }
00306       
00307       
00308 ResourceTransferrable::ResourceTransferrable( int resource, ResourceWatch& src, ResourceWatch& dst, bool isExchangable  ) 
00309    : Transferrable( src, dst ), resourceType ( resource ), exchangable( isExchangable )
00310       {
00311          source.sigChanged.connect( SigC::slot( *this, &ResourceTransferrable::srcChanged ));
00312          dest.sigChanged.connect( SigC::slot( *this, &ResourceTransferrable::dstChanged ));
00313       };
00314       
00315       ASCString ResourceTransferrable::getName() 
00316       { 
00317          return Resources::name( resourceType ); 
00318       }
00319       
00320       int ResourceTransferrable::getID()
00321       {
00322          return resourceType + 1000; 
00323       };
00324       
00325       int ResourceTransferrable::getMax( ContainerBase* c, bool avail )
00326       {
00327          if ( avail ) {
00328             int needed = getResourceWatch( c ).limit().resource(resourceType) - getAvail( c );
00329             int av = min ( needed, getOpposingResourceWatch( c ).avail().resource(resourceType) );
00330 
00331             return getAvail( c ) + av;
00332          } else
00333             return getResourceWatch( c ).limit().resource(resourceType);
00334       }
00335       
00336       int ResourceTransferrable::getMin( ContainerBase* c, bool avail )
00337       {
00338          if ( avail ) {
00339             int space = getOpposingResourceWatch( c ).limit().resource(resourceType) - getOpposingResourceWatch( c ).avail().resource(resourceType);
00340             if ( space > getAvail( c ) )
00341                return 0;
00342             else
00343                return getAvail( c ) - space;
00344          } else
00345             return 0;
00346       }
00347       
00348       int ResourceTransferrable::getAmount ( const ContainerBase* target )
00349       {
00350          return getResourceWatch( target ).amount().resource(resourceType);
00351       }
00352       
00353       int ResourceTransferrable::getAvail ( const ContainerBase* target )
00354       {
00355          return getResourceWatch( target ).avail().resource(resourceType);
00356       }
00357       
00358       int ResourceTransferrable::transfer( ContainerBase* target, int delta )
00359       {
00360          if ( delta < 0 )
00361             return transfer( opposingContainer( target ), -delta );
00362          else {
00363             delta = min( delta, getOpposingResourceWatch( target ).avail().resource(resourceType) );
00364             delta = min( delta, getResourceWatch( target ).limit().resource(resourceType) - getAvail( target ));
00365             getOpposingResourceWatch( target ).getResource( resourceType, delta );
00366             getResourceWatch( target ).putResource(resourceType, delta);
00367             return delta;
00368          }
00369       }
00370 
00371       bool ResourceTransferrable::isExchangable() const
00372       {
00373          return exchangable;
00374       }
00375       
00376       void ResourceTransferrable::commit(const Context& context)
00377       {
00378          ContainerBase* target = dest.getContainer();
00379          executeTransfer( source.getContainer(), target, getAmount( target ) - target->getResource( maxint, resourceType, true ), context );
00380       }
00381       
00382       
00383       
00384       
00385       
00386       
00387       
00388 
00389 
00390       int& AmmoTransferrable::getAmmo( const ContainerBase* unit )
00391       {
00392          assert( unit == source.getContainer() || unit == dest.getContainer() );
00393          if ( unit == source.getContainer() )
00394             return sourceAmmo;
00395          else
00396             return destAmmo;
00397       }
00398       
00399       int AmmoTransferrable::put( ContainerBase* c, int toPut, bool queryOnly )
00400       {
00401          TransferLimitation limit = getTransferLimitation( c );
00402 
00403          if ( limit == ALL )
00404             return 0;
00405          
00406          int undoProduction = min( toPut, produced[c]);
00407          if ( undoProduction > 0 ) {
00408             if ( !queryOnly ) {
00409                for ( int r = 0; r < resourceTypeNum; ++r )
00410                   getResourceWatch( c ).putResource(  r, ammoProductionCost[ammoType][r] * undoProduction );
00411                
00412                produced[c] -= undoProduction;
00413             }
00414          }
00415          toPut -= undoProduction;
00416 
00417          toPut = min( toPut, c->maxAmmo(ammoType) - getAmmo( c ));
00418 
00419          if( !queryOnly ) {
00420             getAmmo(c) += toPut;
00421             show(c);
00422          }
00423          
00424          return toPut + undoProduction;
00425       }
00426             
00427       int AmmoTransferrable::get( ContainerBase* c, int toGet, bool queryOnly )
00428       {
00429          TransferLimitation limit = getTransferLimitation( c );
00430 
00431          if ( limit == ALL )
00432             return 0;
00433          
00434          int gettable;
00435          
00436          if ( limit == GET ) {
00437             gettable = getAmmo(c) - orgAmmo[c];
00438             if ( gettable < 0 )
00439                gettable = 0;
00440          } else
00441             gettable = getAmmo( c );
00442          
00443          int got = min ( toGet, gettable);
00444          int toProduce = toGet - got;
00445 
00446          if ( allowAmmoProduction && toProduce > 0 && weaponAmmo[ammoType] && c->baseType->hasFunction(ContainerBaseType::AmmoProduction) ) {
00447             for ( int r = 0; r < resourceTypeNum; ++r ) {
00448                if ( ammoProductionCost[ammoType][r] ) {
00449                   int produceable = getResourceWatch(c).avail().resource(r) / ammoProductionCost[ammoType][r];
00450                   if ( produceable < toProduce )
00451                      toProduce = produceable;
00452                }
00453             }
00454             if ( !queryOnly ) {
00455                Resources res;
00456                for ( int r = 0; r < resourceTypeNum; ++r )
00457                   res.resource(r) = ammoProductionCost[ammoType][r] * toProduce;
00458 
00459                getResourceWatch( c ).getResources( res );
00460                produced[c] += toProduce;
00461                
00462                getAmmo(c) -= got;
00463             }
00464             got += toProduce;
00465          } else {
00466             if ( !queryOnly ) {
00467                getAmmo(c) -= got;
00468                show( c );
00469             }
00470                
00471          }
00472          return got;
00473       }
00474 
00475      
00476       void AmmoTransferrable::executeTransfer( ContainerBase* from, ContainerBase* to, int amount, const Context& context )
00477       {
00478          if ( amount < 0 )
00479             executeTransfer( to, from, -amount, context );
00480          else 
00481             if ( amount > 0 ) {
00482                auto_ptr<ConsumeAmmo> ca1 ( new ConsumeAmmo( from, ammoType, -1, amount ));
00483                ca1->setAmmoProduction( allowAmmoProduction );
00484                
00485                ActionResult res = ca1->execute( context );
00486                if( res.successful() )
00487                   ca1.release();
00488                else
00489                   throw res;
00490                
00491                auto_ptr<ConsumeAmmo> ca2 ( new ConsumeAmmo( to, ammoType, -1, -amount ));
00492                res = ca2->execute( context );
00493                if( res.successful() )
00494                   ca2.release();
00495                else
00496                   throw res;
00497             }
00498       }
00499       
00500       AmmoTransferrable::AmmoTransferrable( int ammo, ResourceWatch& src, ResourceWatch& dst, bool& allowProduction ) : Transferrable( src, dst ), ammoType ( ammo ), allowAmmoProduction( allowProduction )
00501       {
00502          sourceAmmo = src.getContainer()->getAmmo( ammoType, maxint, true );
00503          destAmmo   = dst.getContainer()->getAmmo( ammoType, maxint, true );
00504          
00505          orgAmmo[src.getContainer()] = sourceAmmo;
00506          orgAmmo[dst.getContainer()] = destAmmo;
00507       };
00508       
00509       ASCString AmmoTransferrable::getName() 
00510       { 
00511          return cwaffentypen[ ammoType ]; 
00512       }
00513       
00514       int AmmoTransferrable::getID()
00515       {
00516          // the AI depends on this value and ID scheme!
00517          return ammoType + 2000; 
00518       };
00519       
00520       int AmmoTransferrable::getMax( ContainerBase* c, bool avail )
00521       {
00522          if ( avail ) {
00523             int needed = c->maxAmmo( ammoType ) - getAmount( c );
00524             int av = get( opposingContainer( c ), needed, true );
00525             return getAmount( c ) + av;
00526          } else
00527             return c->maxAmmo( ammoType );
00528       }
00529       
00530       int AmmoTransferrable::getMin( ContainerBase* c, bool avail )
00531       {
00532          if ( avail ) {
00533             int storable = opposingContainer(c)->maxAmmo(ammoType) - getAmmo( opposingContainer(c) );
00534             int transferable = min( getAmmo(c), storable );
00535             return getAmmo(c) - transferable;
00536          } else
00537             return 0;
00538       }
00539       
00540       int AmmoTransferrable::getAmount ( const ContainerBase* target )
00541       {
00542          return getAmmo( target );
00543       }
00544       
00545       int AmmoTransferrable::transfer( ContainerBase* target, int delta )
00546       {
00547          if ( delta < 0 )
00548             return transfer( opposingContainer( target ), -delta );
00549          else {
00550             delta = min( delta, put( target, delta, true ));
00551             int got = get( opposingContainer( target ), delta, false );
00552             put( target, got, false );
00553             return got;
00554          }
00555       }
00556       
00557       bool AmmoTransferrable::isExchangable() const
00558       {
00559          return true;
00560       };
00561       
00562       void AmmoTransferrable::commit( const Context& context )
00563       {
00564          executeTransfer( source.getContainer(), dest.getContainer(), destAmmo - orgAmmo[dest.getContainer()], context );
00565       }
00566 
00567 
00568 
00569 
00570 const SingleWeapon* ServiceChecker :: getServiceWeapon()
00571 {
00572    Vehicle* srcVehicle = dynamic_cast<Vehicle*>(source);
00573    if ( !srcVehicle )
00574       return false;
00575 
00576    const SingleWeapon* serviceWeapon = NULL;
00577    for (int i = 0; i < srcVehicle->typ->weapons.count ; i++)
00578       if ( srcVehicle->typ->weapons.weapon[i].service() )
00579          serviceWeapon = &srcVehicle->typ->weapons.weapon[i];
00580 
00581    return serviceWeapon;
00582 }
00583 
00584 bool ServiceChecker::serviceWeaponFits( ContainerBase* dest )
00585 {
00586    const SingleWeapon* serviceWeapon = getServiceWeapon();
00587    if ( serviceWeapon )
00588       if ( (ignoreChecks & ignoreHeight) || (serviceWeapon->sourceheight & source->getHeight()) )
00589          if ( (ignoreChecks & ignoreHeight) || (serviceWeapon->targ & dest->getHeight() )) {
00590             int dist = beeline( source->getPosition(), dest->getPosition() );
00591             if ( (ignoreChecks & ignoreDistance) || (serviceWeapon->mindistance <= dist && serviceWeapon->maxdistance >= dist) )
00592                if ( serviceWeapon->targetingAccuracy[dest->baseType->getMoveMalusType()] > 0  )
00593                   if ( (ignoreChecks & ignoreHeight) || (serviceWeapon->efficiency[6+getheightdelta(source,dest)] > 0  ))
00594                      if ( ! ((source->getHeight() & (chtieffliegend | chfliegend | chhochfliegend)) && dest->baseType->hasFunction(ContainerBaseType::NoInairRefuelling)))
00595                         return true;
00596 
00597          }
00598 
00599    return false;
00600 }
00601 
00602 ServiceChecker :: ServiceChecker( ContainerBase* src, int skipChecks ) : source(src), ignoreChecks( skipChecks )
00603 {
00604 }
00605 
00606 
00607 void ServiceChecker :: check( ContainerBase* dest )
00608 {
00609    MapCoordinate spos = source->getPosition();
00610    MapCoordinate dpos = dest->getPosition();
00611    bool externalTransfer = spos != dpos;
00612 
00613    if ( source->isBuilding() && dest->isBuilding() )
00614       return; 
00615 
00616    if ( getTransferLimitation( dest ) == ALL )
00617       return;
00618 
00619 
00620    if ( source->getMap()->getPlayer(source).diplomacy.getState(dest->getOwner()) < PEACE )
00621       return;
00622 
00623    static ContainerBaseType::ContainerFunctions resourceVehicleFunctions[resourceTypeNum] = { ContainerBaseType::ExternalEnergyTransfer,
00624       ContainerBaseType::ExternalMaterialTransfer,
00625       ContainerBaseType::ExternalFuelTransfer };
00626 
00627 
00628       for ( int r = 0; r < resourceTypeNum; r++ ) {
00629          if (  externalTransfer ) {
00630             Vehicle* srcVehicle = dynamic_cast<Vehicle*>(source);
00631             if ( !srcVehicle ) {// it's a building
00632                Building* bld = dynamic_cast<Building*>(source);
00633                assert(bld);
00634                bool active = source->baseType->hasFunction( resourceVehicleFunctions[r] ) ||  dest->baseType->hasFunction( resourceVehicleFunctions[r] );
00635                if ( (ignoreChecks & ignoreHeight) || (bld->typ->externalloadheight & dest->getHeight()) )
00636                   if ( (ignoreChecks & ignoreDistance) || beeline(source->getPosition(), dest->getPosition()) < 20 )
00637                      resource( dest, r, active );
00638             } else {
00639                if ( serviceWeaponFits( dest )) {
00640                   bool active = source->baseType->hasFunction( resourceVehicleFunctions[r] ) ||  dest->baseType->hasFunction( resourceVehicleFunctions[r] );
00641                   resource( dest, r, active );
00642                }
00643             }
00644 
00645          } else {
00646             bool active =  (source->getStorageCapacity().resource(r) || source->isBuilding() )
00647                         && (dest->getStorageCapacity().resource(r) || dest->isBuilding());
00648             resource( dest, r, active );
00649          }
00650       }
00651 
00652    /* it is important that the ammo transfers are in front of the resource transfers, because ammo production affects resource amounts
00653       and their prelimarny commitment would cause inconsistencies */
00654 
00655       for ( int a = 0; a < weaponTypeNum; ++a ) {
00656          if ( source->maxAmmo( a ) && dest->maxAmmo( a )) {
00657             if ( weaponAmmo[a] ) {
00658                if ( externalTransfer ) {
00659                   if ( source->baseType->hasFunction( ContainerBaseType::ExternalAmmoTransfer ) ||  dest->baseType->hasFunction( ContainerBaseType::ExternalAmmoTransfer ) ) {
00660                      Vehicle* srcVehicle = dynamic_cast<Vehicle*>(source);
00661                      if ( !srcVehicle ) {// it's a building
00662                         Building* bld = dynamic_cast<Building*>(source);
00663                         assert(bld);
00664                         if ( (ignoreChecks & ignoreHeight) || (bld->typ->externalloadheight & dest->getHeight()) )
00665                            if ( (ignoreChecks & ignoreDistance) || beeline(source->getPosition(), dest->getPosition()) < 20 )
00666                               ammo(dest, a);
00667                      } else {
00668                         if ( serviceWeaponFits( dest ) )
00669                            ammo(dest, a);
00670                      }
00671                   }
00672                } else {
00673                   ammo(dest, a);
00674                }
00675             }
00676          }
00677       }
00678 
00679       
00680       
00681       if (  externalTransfer ) {
00682          Vehicle* srcVehicle = dynamic_cast<Vehicle*>(source);
00683          if ( srcVehicle ) {// it's a unit
00684             if ( srcVehicle->baseType->hasFunction( ContainerBaseType::ExternalRepair ))
00685                if ( serviceWeaponFits( dest ) && dest->damage > 0 ) {
00686                   repair( dest );
00687                }
00688          }
00689 
00690       } else {
00691          if ( source->baseType->hasFunction( ContainerBaseType::InternalUnitRepair ))
00692             repair( dest );
00693       }
00694       
00695       
00696       
00697 }
00698 
00699 
00700 
00701 void ServiceTargetSearcher::fieldChecker( const MapCoordinate& pos )
00702 {
00703    MapField* fld = gamemap->getField( pos );
00704    if ( fld && fld->getContainer() )
00705       check( fld->getContainer() );
00706 }
00707 
00708 void ServiceTargetSearcher::addTarget( ContainerBase* target )
00709 {
00710    if ( find( targets.begin(), targets.end(), target ) == targets.end() )
00711       targets.push_back( target );
00712 }
00713 
00714 void ServiceTargetSearcher::ammo( ContainerBase* dest, int type )
00715 {
00716    if ( checks & checkAmmo )
00717       addTarget ( dest );
00718 }
00719 
00720 void ServiceTargetSearcher::resource( ContainerBase* dest, int type, bool active )
00721 {
00722    if ( checks & checkResources )
00723       if ( active )
00724          addTarget ( dest );
00725 }
00726       
00727 void ServiceTargetSearcher::repair( ContainerBase* dest)
00728 {
00729    if ( checks & checkRepair )
00730       addTarget ( dest );
00731 }
00732       
00733       
00734 ServiceTargetSearcher::ServiceTargetSearcher( ContainerBase* src, int checkFlags ) : ServiceChecker( src ), checks ( checkFlags )
00735 {
00736    gamemap = src->getMap();
00737 }
00738 
00739 
00740 bool ServiceTargetSearcher::externallyAvailable()
00741 {
00742    Vehicle* srcVehicle = dynamic_cast<Vehicle*>(source);
00743    if ( srcVehicle ) {
00744       if ( srcVehicle->attacked ) 
00745          return false;
00746 
00747 
00748       if ( srcVehicle->reactionfire.getStatus() == Vehicle::ReactionFire::off || srcVehicle->baseType->hasFunction(ContainerBaseType::MoveWithReactionFire))
00749          if ( source->getMap()->getField( source->getPosition() )->unitHere( srcVehicle )) {
00750             const SingleWeapon* weap = getServiceWeapon();
00751             if( weap ) 
00752                if ( source->baseType->hasFunction( ContainerBaseType::ExternalEnergyTransfer  ) || 
00753                     source->baseType->hasFunction( ContainerBaseType::ExternalMaterialTransfer  ) || 
00754                     source->baseType->hasFunction( ContainerBaseType::ExternalFuelTransfer  ) || 
00755                     source->baseType->hasFunction( ContainerBaseType::ExternalAmmoTransfer  )) 
00756                     return true;
00757             
00758          }         
00759    } else {
00760       if ( source->baseType->hasFunction( ContainerBaseType::ExternalEnergyTransfer  ) )
00761          // if ( source->getStorageCapacity().energy )
00762             return true;
00763 
00764       if ( source->baseType->hasFunction( ContainerBaseType::ExternalMaterialTransfer  ) )
00765          // if ( source->getStorageCapacity().material )
00766             return true;
00767 
00768       if ( source->baseType->hasFunction( ContainerBaseType::ExternalFuelTransfer  ) )
00769          // if ( source->getStorageCapacity().fuel )
00770             return true;
00771 
00772    }
00773    return false;
00774 }
00775 
00776 
00777 void ServiceTargetSearcher::startSearch()
00778 {
00779    Vehicle* srcVehicle = dynamic_cast<Vehicle*>(source);
00780    if ( srcVehicle ) {
00781       if ( source->getMap()->getField( source->getPosition() )->unitHere( srcVehicle )) {
00782          const SingleWeapon* weap = getServiceWeapon();
00783          if( weap )
00784             circularFieldIterator(source->getMap(), source->getPosition(), weap->maxdistance / maxmalq, (weap->mindistance + maxmalq - 1) / maxmalq, FieldIterationFunctor( this, &ServiceTargetSearcher::fieldChecker ) );
00785       }
00786    } else
00787       circularFieldIterator(source->getMap(), source->getPosition(), 1, 1, FieldIterationFunctor( this, &ServiceTargetSearcher::fieldChecker ) );
00788 
00789       for ( ContainerBase::Cargo::const_iterator i = source->getCargo().begin(); i != source->getCargo().end(); ++i )
00790          if ( *i )
00791             check( *i );
00792 };
00793 
00794 
00795 
00796 void TransferHandler::ammo( ContainerBase* dest, int type )
00797 {
00798    transfers.push_back ( new AmmoTransferrable( type, sourceRes, destRes, allowProduction ));
00799 }
00800 
00801 void TransferHandler::resource( ContainerBase* dest, int type, bool active )
00802 {
00803    transfers.push_back(  new ResourceTransferrable( type, sourceRes, destRes, active ));
00804 }
00805 
00806 TransferHandler::TransferHandler( ContainerBase* src, ContainerBase* dst, int flags ) : ServiceChecker( src, flags ), sourceRes( src ), destRes( dst ), source(src), dest(dst)
00807 {
00808    allowProduction = CGameOptions::Instance()->autoproduceammunition ;
00809 
00810    if ( dest->getMap()->player[dest->getMap()->actplayer].diplomacy.getState( dest->getOwner() ) <= TRUCE )
00811       return;
00812 
00813    check( dst );
00814 };
00815 
00816 bool TransferHandler::allowAmmoProduction( bool allow )
00817 {
00818    if ( ammoProductionPossible() ) {
00819       allowProduction = allow;
00820       updateRanges();
00821       return true;
00822    } else
00823       return false;
00824 }
00825 
00826 
00827 TransferHandler::~TransferHandler()
00828 {
00829    if ( allowProduction != CGameOptions::Instance()->autoproduceammunition  ) {
00830       CGameOptions::Instance()->autoproduceammunition = allowProduction ;
00831       CGameOptions::Instance()->setChanged();
00832    }
00833 }
00834 
00835 bool TransferHandler::ammoProductionPossible()
00836 {
00837    return source->baseType->hasFunction( ContainerBaseType::AmmoProduction ) ||  dest->baseType->hasFunction( ContainerBaseType::AmmoProduction );
00838 }
00839 
00840 TransferHandler::Transfers& TransferHandler::getTransfers()
00841 {
00842    return transfers;
00843 }
00844 
00845 void TransferHandler::fillDest()
00846 {
00847    for ( Transfers::iterator i = transfers.begin(); i != transfers.end(); ++i )
00848       if ( (*i)->isExchangable())
00849          (*i)->fill( dest );
00850 }
00851 
00852 void TransferHandler::fillDestAmmo()
00853 {
00854    for ( Transfers::iterator i = transfers.begin(); i != transfers.end(); ++i )
00855       if ( (*i)->isExchangable())
00856          if ( dynamic_cast<AmmoTransferrable*>(*i))
00857             (*i)->fill( dest );
00858 }
00859 
00860 void TransferHandler::fillDestResource()
00861 {
00862    for ( Transfers::iterator i = transfers.begin(); i != transfers.end(); ++i )
00863       if ( (*i)->isExchangable())
00864          if ( dynamic_cast<ResourceTransferrable*>(*i))
00865             (*i)->fill( dest );
00866 }
00867 
00868 
00869 void TransferHandler::emptyDest()
00870 {
00871    for ( Transfers::iterator i = transfers.begin(); i != transfers.end(); ++i )
00872       (*i)->empty( dest );
00873 
00874 }
00875 
00876 
00877 bool TransferHandler::commit( const Context& context )
00878 {
00879    for ( Transfers::iterator i = transfers.begin(); i != transfers.end(); ++i )
00880       (*i)->commit( context );
00881 
00882    return true;
00883 }
00884 
00885 
00886 

Generated on Mon May 21 01:26:37 2012 for Advanced Strategic Command by  doxygen 1.5.1