constructunitcommand.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 
00022 #include "constructunitcommand.h"
00023 
00024 #include "../vehicle.h"
00025 #include "../mapfield.h"
00026 #include "../gamemap.h"
00027 #include "../viewcalculation.h"
00028 #include "../spfst.h"
00029 #include "../mapdisplayinterface.h"
00030 #include "action-registry.h"
00031 #include "../itemrepository.h"
00032 #include "../containercontrols.h"
00033 #include "consumeresource.h"
00034 #include "spawnunit.h"
00035 #include "changeunitmovement.h"
00036 #include "consumeammo.h"
00037 #include "changeunitproperty.h"
00038 #include "viewregistration.h"
00039 
00040 
00041 bool ConstructUnitCommand :: externalConstructionAvail ( const ContainerBase* eht )
00042 {
00043    const Vehicle* vehicle = dynamic_cast<const Vehicle*>(eht);
00044    if ( !eht )
00045       return false;
00046    
00047    MapField* fld = vehicle->getMap()->getField ( vehicle->getPosition() );
00048    if ( fld && fld->vehicle == vehicle )
00049       if (vehicle->getOwner() == vehicle->getMap()->actplayer )
00050          if ( vehicle->typ->vehiclesBuildable.size() )
00051             if ( !vehicle->attacked )
00052                return true;
00053    return false;
00054 }
00055 
00056 bool ConstructUnitCommand :: internalConstructionAvail( const ContainerBase* eht )
00057 {
00058    if ( eht->getOwner() == eht->getMap()->actplayer )
00059       if ( eht->vehiclesLoaded() < eht->baseType->maxLoadableUnits )
00060          return eht->baseType->hasFunction( ContainerBaseType::InternalVehicleProduction );
00061    
00062    return false;
00063 }
00064 
00065 bool ConstructUnitCommand :: avail ( const ContainerBase* eht )
00066 {
00067    return internalConstructionAvail(eht) || externalConstructionAvail(eht);
00068 }
00069 
00070 
00071 ConstructUnitCommand :: ConstructUnitCommand ( ContainerBase* container )
00072    : ContainerCommand ( container ), mode( undefined ), vehicleTypeID(-1), newUnitID(-1)
00073 {
00074 
00075 }
00076 
00077 
00078 
00079 ConstructUnitCommand::Lack ConstructUnitCommand::unitProductionPrerequisites( const VehicleType* type ) const
00080 {
00081    int l = 0;
00082    
00083    if ( mode == internal ) {
00084       Resources cost = getContainer()->getProductionCost( type );
00085       for ( int r = 0; r < resourceTypeNum; r++ )
00086          if ( getContainer()->getAvailableResource( cost.resource(r), r ) < cost.resource(r) )
00087             l |= 1 << r;
00088       
00089       if ( !type->techDependency.available( getMap()->getPlayer(getContainer()).research ) && getMap()->getgameparameter( cgp_produceOnlyResearchedStuffInternally ) ) 
00090          l |= Lack::Research;
00091    
00092       if ( !getContainer()->vehicleUnloadable( type ) && !getContainer()->baseType->hasFunction( ContainerBaseType::ProduceNonLeavableUnits ))
00093          l |= Lack::Unloadability;
00094    } else 
00095       if ( mode == external ) {
00096       
00097          if ( !type->techDependency.available( getMap()->getPlayer(getContainer()).research ) && getMap()->getgameparameter( cgp_produceOnlyResearchedStuffExternally ) ) 
00098             l |= Lack::Research;
00099          
00100          const Vehicle* veh = dynamic_cast<const Vehicle*>(getContainer());
00101          if ( veh->getMovement() < veh->maxMovement() * veh->typ->unitConstructionMoveCostPercentage / 100 )
00102             l |= Lack::Movement;
00103          
00104          Resources cost = veh->getExternalVehicleConstructionCost( type );
00105          for ( int r = 0; r < resourceTypeNum; r++ )
00106             if ( getContainer()->getAvailableResource( cost.resource(r), r ) < cost.resource(r) )
00107                l |= 1 << r;
00108          
00109       }
00110       
00111    return Lack(l);
00112 }
00113 
00114 ConstructUnitCommand::Producables ConstructUnitCommand :: getProduceableVehicles( )
00115 {
00116    Producables entries;
00117    if ( mode == internal ) {
00118       const ContainerBase::Production& prod = getContainer()->getProduction();
00119       for ( ContainerBase::Production::const_iterator i = prod.begin(); i != prod.end(); ++i ) 
00120          entries.push_back ( ProductionEntry ( *i, getContainer()->getProductionCost( *i ), unitProductionPrerequisites( *i  ) ));
00121    } else 
00122       if ( mode == external ) {
00123          Vehicle* veh = dynamic_cast<Vehicle*>(getContainer());
00124          if ( veh ) {
00125             ContainerConstControls cc ( getContainer() );
00126             for ( int i = 0; i < veh->typ->vehiclesBuildable.size(); i++ )
00127                for ( int j = veh->typ->vehiclesBuildable[i].from; j <= veh->typ->vehiclesBuildable[i].to; j++ )
00128                   if ( veh->getMap()->getgameparameter(cgp_forbid_unitunit_construction) == 0 || veh->getMap()->unitProduction.check(j) ) {
00129                      VehicleType* v = veh->getMap()->getvehicletype_byid ( j );
00130                      if ( v ) 
00131                         entries.push_back ( ProductionEntry ( v, veh->getExternalVehicleConstructionCost( v ), unitProductionPrerequisites( v ) ));
00132                   }
00133          }
00134       }
00135    return entries;
00136 }
00137 
00138 void ConstructUnitCommand :: fieldChecker( const MapCoordinate& pos )
00139 {
00140    MapField* fld = getMap()->getField(pos);
00141    if ( !fld )
00142       return;
00143    
00144    if ( fld->vehicle || fld->building )
00145       return;
00146    
00147    VehicleType* vt = getContainer()->getMap()->getvehicletype_byid( vehicleTypeID );
00148    
00149    if ( fieldvisiblenow( getMap()->getField(pos)) && vt ) {
00150       Vehicle* veh = dynamic_cast<Vehicle*>(getContainer() );
00151       if ( veh && veh->vehicleconstructable( vt, pos.x, pos.y ))
00152          unitsConstructable[pos].push_back(vehicleTypeID);
00153    }
00154 }
00155 
00156 
00157 vector<MapCoordinate> ConstructUnitCommand::getFields()
00158 {
00159    vector<MapCoordinate> fields;
00160    Vehicle* veh = dynamic_cast<Vehicle*>(getContainer() );
00161    if ( vehicleTypeID > 0 && veh ) {
00162       circularFieldIterator( veh->getMap(), veh->getPosition(), veh->typ->unitConstructionMaxDistance, veh->typ->unitConstructionMinDistance, FieldIterationFunctor( this, &ConstructUnitCommand::fieldChecker ) );
00163       for ( map<MapCoordinate,vector<int> >::const_iterator i = unitsConstructable.begin(); i != unitsConstructable.end(); ++i )
00164          fields.push_back ( i->first );
00165    }
00166    
00167    return fields;
00168 }
00169 
00170 bool ConstructUnitCommand :: isFieldUsable( const MapCoordinate& pos )
00171 {
00172    vector<MapCoordinate> fields = getFields();
00173    return find( fields.begin(), fields.end(), pos ) != fields.end() ;
00174 }
00175 
00176 
00177 void ConstructUnitCommand :: setTargetPosition( const MapCoordinate& pos )
00178 {
00179    this->target = pos;
00180    MapField* fld = getMap()->getField(target);
00181    
00182    if( !fld )
00183       throw ActionResult(21002);
00184    
00185    if ( mode != undefined && vehicleTypeID > 0  )
00186       setState( SetUp );
00187    
00188 }
00189 
00190  
00191 
00192 ActionResult ConstructUnitCommand::go ( const Context& context )
00193 {
00194    if ( getState() != SetUp )
00195       return ActionResult(22000);
00196 
00197    
00198    Producables prods = getProduceableVehicles();
00199    
00200    const VehicleType* vehicleType = NULL;
00201    Resources cost;
00202    for ( Producables::const_iterator i = prods.begin(); i != prods.end(); ++i ) {
00203       if ( i->type->id == vehicleTypeID ) {
00204          if ( i->prerequisites.ok() ) {
00205             vehicleType = i->type;
00206             cost = i->cost;
00207          } else
00208             return ActionResult( 21702 );
00209       }
00210    }
00211    if ( !vehicleType )
00212       return ActionResult( 21701 );
00213    
00214    
00215    if ( mode == external && !isFieldUsable( target ))
00216       return ActionResult( 21703 );
00217   
00218    
00219    int height;
00220    for ( int j = 0; j < 8; j++ ) {
00221       int a = int( getContainer()->getHeight() ) << j;
00222       int b = int( getContainer()->getHeight() ) >> j;
00223       if ( vehicleType->height & a ) {
00224          height = a;
00225          break;
00226       }
00227       if ( vehicleType->height & b ) {
00228          height = b;
00229          break;
00230       }
00231    }
00232    MapCoordinate3D position ( target, height );
00233 
00234    if ( mode == external ) {
00235       
00236       SpawnUnit* spawnUnit = new SpawnUnit(getMap(), position, vehicleTypeID, getContainer()->getOwner() );
00237       ActionResult res = spawnUnit->execute( context );
00238       if ( !res.successful() )
00239          return res;
00240       
00241       spawnUnit->getUnit()->attacked = true;
00242       
00243       newUnitID = spawnUnit->getUnit()->networkid;
00244       
00245       
00246       if ( !res.successful() )
00247          return res;
00248       
00249       Vehicle* veh = dynamic_cast<Vehicle*>(getContainer() );
00250       if ( veh ) {      
00251          res = (new ChangeUnitMovement( veh, veh->maxMovement() * veh->typ->unitConstructionMoveCostPercentage/100, true ))->execute( context );
00252          if ( !res.successful() )
00253             return res;
00254       }
00255    } else {
00256       SpawnUnit* spawnUnit  = new SpawnUnit(getMap(), getContainer(), vehicleTypeID );
00257       ActionResult res = spawnUnit->execute( context );
00258       if ( !res.successful() )
00259          return res;
00260       
00261       spawnUnit->getUnit()->attacked = true;
00262       
00263       newUnitID = spawnUnit->getUnit()->networkid;
00264       
00265       if ( getMap()->getgameparameter(cgp_bi3_training) >= 1 ) {
00266          int cnt = 0;
00267 
00268          for ( Player::BuildingList::iterator bi = getMap()->player[getMap()->actplayer].buildingList.begin(); bi != getMap()->player[getMap()->actplayer].buildingList.end(); bi++ )
00269             if ( (*bi)->typ->hasFunction( ContainerBaseType::TrainingCenter  ) )
00270                cnt++;
00271 
00272          Vehicle* vehicle = spawnUnit->getUnit();
00273          vehicle->experience += cnt * getMap()->getgameparameter(cgp_bi3_training);
00274          if ( vehicle->experience > maxunitexperience )
00275             vehicle->experience = maxunitexperience;
00276       }
00277    }
00278    
00279    ActionResult res = (new ConsumeResource(getContainer(), cost ))->execute( context );
00280    
00281    if ( !res.successful() )
00282       return res;
00283    
00284    Vehicle* veh = dynamic_cast<Vehicle*>(getContainer());
00285    if ( veh )
00286       res = (new ChangeUnitProperty( veh, ChangeUnitProperty::AttackedFlag, 1 ))->execute(context);
00287    
00288    if ( context.display )
00289       context.display->repaintDisplay();
00290    
00291    if ( res.successful() )
00292       setState( Finished );
00293    else
00294       setState( Failed );
00295    
00296    return res;
00297 }
00298 
00299 Vehicle* ConstructUnitCommand :: getProducedUnit()
00300 {
00301    if ( newUnitID > 0 )
00302       return getMap()->getUnit( newUnitID );
00303    else
00304       return NULL;
00305 }
00306 
00307 void ConstructUnitCommand :: setMode( Mode mode ) 
00308 { 
00309    this->mode = mode; 
00310    if ( mode == internal )
00311       target = getContainer()->getPosition();
00312 };
00313 
00314 
00315 static const int ConstructUnitCommandVersion = 1;
00316 
00317 void ConstructUnitCommand :: readData ( tnstream& stream )
00318 {
00319    ContainerCommand::readData( stream );
00320    int version = stream.readInt();
00321    if ( version > ConstructUnitCommandVersion )
00322       throw tinvalidversion ( "ConstructUnitCommand", ConstructUnitCommandVersion, version );
00323    target.read( stream );
00324    vehicleTypeID = stream.readInt();
00325    mode = (Mode) stream.readInt();
00326    newUnitID = stream.readInt();
00327 }
00328 
00329 void ConstructUnitCommand :: writeData ( tnstream& stream ) const
00330 {
00331    ContainerCommand::writeData( stream );
00332    stream.writeInt( ConstructUnitCommandVersion );
00333    target.write( stream );
00334    stream.writeInt( vehicleTypeID );
00335    stream.writeInt( mode );
00336    stream.writeInt( newUnitID );
00337 }
00338 
00339 void ConstructUnitCommand :: setVehicleType( const VehicleType* type )
00340 {
00341    vehicleTypeID = type->id;
00342    
00343    VehicleType* vt = getMap()->getvehicletype_byid( vehicleTypeID );
00344    if( !vt )
00345       throw ActionResult(21701);
00346    
00347    if ( mode != undefined && target.valid())
00348       setState( SetUp );
00349    
00350 }
00351 
00352 
00353 ASCString ConstructUnitCommand :: getCommandString() const
00354 {
00355    ASCString c;
00356    c.format("constructUnit ( map, %d, asc.MapCoordinate( %d, %d), %d )", getContainerID(), target.x, target.y, vehicleTypeID );
00357    return c;
00358 }
00359 
00360 GameActionID ConstructUnitCommand::getID() const
00361 {
00362    return ActionRegistry::ConstructUnitCommand;
00363 }
00364 
00365 ASCString ConstructUnitCommand::getDescription() const
00366 {
00367    ASCString s = "Construct ";
00368    
00369    const VehicleType* vt = getMap()->getvehicletype_byid( vehicleTypeID );
00370    if ( vt )
00371       s += vt->name;
00372    else
00373       s += "unit";
00374    
00375    if ( getContainer() ) {
00376       s += " by " + getContainer()->getName();
00377    }
00378    s += " at " + target.toString();
00379    return s;
00380 }
00381 
00382 namespace
00383 {
00384    const bool r1 = registerAction<ConstructUnitCommand> ( ActionRegistry::ConstructUnitCommand );
00385 }
00386 

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