constructbuildingcommand.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 "constructbuildingcommand.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 "changeunitproperty.h"
00034 #include "spawnbuilding.h"
00035 #include "changeunitmovement.h"
00036 #include "consumeresource.h"
00037 
00038 
00039 
00040 
00041 bool ConstructBuildingCommand :: avail ( const Vehicle* eht )
00042 {
00043    if ( !eht )
00044       return false;
00045 
00046    if ( eht->getMap()->getgameparameter(cgp_forbid_building_construction) )
00047       return false;
00048 
00049    if ( eht->attacked == false && !eht->hasMoved() )
00050       if ( eht->getOwner() == eht->getMap()->actplayer )
00051          if ( eht->typ->hasFunction( ContainerBaseType::ConstructBuildings  ))
00052             return true;
00053 
00054    return false;
00055 }
00056 
00057 
00058 ConstructBuildingCommand :: ConstructBuildingCommand ( Vehicle* container )
00059       : UnitCommand ( container ), buildingTypeID(-1)
00060 {
00061 
00062 }
00063 
00064 
00065 Resources ConstructBuildingCommand::getProductionCost( const BuildingType* bld ) const
00066 {
00067    int mf = getMap()->getgameparameter ( cgp_building_material_factor );
00068    int ff = getMap()->getgameparameter ( cgp_building_fuel_factor );
00069 
00070    if ( !mf )
00071       mf = 100;
00072    if ( !ff )
00073       ff = 100;
00074 
00075    return Resources( 0, bld->productionCost.material * mf / 100, bld->productionCost.fuel * ff / 100 );
00076 }
00077 
00078 
00079 ConstructBuildingCommand::Lack ConstructBuildingCommand::buildingProductionPrerequisites( const BuildingType* type ) const
00080 {
00081    int l = 0;
00082 
00083    if ( !type->techDependency.available ( getMap()->getPlayer(getUnit()).research))
00084       l |= Lack::Research;
00085 
00086 
00087    int hd = getheightdelta ( getFirstBit ( getUnit()->height ), getFirstBit ( type->height ));
00088 
00089    if ( hd != 0 )
00090       l |= Lack::Level;
00091 
00092 
00093    Resources cost = getProductionCost( type );
00094    Resources avail = getUnit()->getResource( cost );
00095    for ( int r = 0; r < Resources::count ; ++r )
00096       if ( cost.resource(r) > avail.resource(r) )
00097          l |= 1 << r;
00098 
00099    return Lack(l);
00100 }
00101 
00102 ConstructBuildingCommand::Producables ConstructBuildingCommand :: getProduceableBuildings( )
00103 {
00104    Producables entries;
00105    if ( !avail( getUnit() ) )
00106       return entries;
00107 
00108    for ( int i = 0; i < buildingTypeRepository.getNum(); i++) {
00109       const BuildingType* bld =  buildingTypeRepository.getObject_byPos( i );
00110 
00111       for ( int j = 0; j < getUnit()->typ->buildingsBuildable.size(); j++ )
00112          if ( getUnit()->typ->buildingsBuildable[j].from <= bld->id &&
00113                getUnit()->typ->buildingsBuildable[j].to   >= bld->id ) {
00114 
00115             entries.push_back ( ProductionEntry ( bld, getProductionCost( bld ), buildingProductionPrerequisites( bld  ) ));
00116 
00117          }
00118    }
00119    return entries;
00120 }
00121 
00122 void ConstructBuildingCommand :: fieldChecker( const MapCoordinate& pos )
00123 {
00124    MapField* fld = getMap()->getField(pos);
00125    if ( !fld )
00126       return;
00127 
00128    if ( fld->vehicle || fld->building )
00129       return;
00130 }
00131 
00132 bool ConstructBuildingCommand::buildingFits( const MapCoordinate& entry )
00133 {
00134 
00135    MapField* entryfield =  getMap()->getField(entry);
00136    if ( !entryfield )
00137       return false;
00138 
00139    BuildingType* bld = buildingTypeRepository.getObject_byID( buildingTypeID );
00140 
00141    if ( bld ) {
00142       bool b = true;
00143       for ( int y1 = 0; y1 <= 5; y1++)
00144          for ( int x1 = 0; x1 <= 3; x1++)
00145             if ( bld->fieldExists ( BuildingType::LocalCoordinate(x1, y1)) ) {
00146                MapField* fld = getMap()->getField ( bld->getFieldCoordinate( entry, BuildingType::LocalCoordinate(x1,y1) ));
00147                if ( fld ) {
00148                   if ( fld->vehicle != NULL ) // && fld->vehicle->height <= chfahrend )
00149                      b = false;
00150                   
00151                   if ( bld->height <= chfahrend )
00152                      if ( bld->terrainaccess.accessible ( fld->bdt ) <= 0 )
00153                         b = false;
00154                   
00155                   if (fld->building != NULL) {
00156                      if (fld->building->typ != bld)
00157                         b = false;
00158                      if (fld->building->getCompletion() == fld->building->typ->construction_steps - 1)
00159                         b = false;
00160                      if ( (entryfield->bdt & getTerrainBitType(cbbuildingentry) ).none() )
00161                         b = false;
00162                   }
00163                   if (entryfield->building != fld->building)
00164                      b = false;
00165                } else
00166                   b = false;
00167             }
00168       return b;
00169    }
00170    
00171    return false;
00172 }
00173 
00174 
00175 vector<MapCoordinate> ConstructBuildingCommand::getFields()
00176 {
00177    vector<MapCoordinate> fields;
00178    Vehicle* veh = getUnit();
00179    BuildingType* bld = buildingTypeRepository.getObject_byID( buildingTypeID );
00180    if ( bld ) {
00181       for ( int d = 0; d < 6; ++d ) {
00182          MapCoordinate pos = getNeighbouringFieldCoordinate( veh->getPosition(), d );
00183          if ( buildingFits( pos ))
00184             fields.push_back( pos );
00185       }
00186    }
00187 
00188    return fields;
00189 }
00190 
00191 bool ConstructBuildingCommand :: isFieldUsable( const MapCoordinate& pos )
00192 {
00193    vector<MapCoordinate> fields = getFields();
00194    return find( fields.begin(), fields.end(), pos ) != fields.end() ;
00195 }
00196 
00197 
00198 void ConstructBuildingCommand :: setTargetPosition( const MapCoordinate& pos )
00199 {
00200    this->target = pos;
00201    MapField* fld = getMap()->getField(target);
00202 
00203    if ( !fld )
00204       throw ActionResult(21002);
00205 
00206    if ( buildingTypeID > 0  )
00207       setState( SetUp );
00208 
00209 }
00210 
00211 
00212 
00213 ActionResult ConstructBuildingCommand::go ( const Context& context )
00214 {
00215    if ( getState() != SetUp )
00216       return ActionResult(22000);
00217    
00218    if ( !avail( getUnit() ))
00219       return ActionResult(22506);
00220    
00221    BuildingType* bld = buildingTypeRepository.getObject_byID( buildingTypeID );
00222 
00223    if ( !bld )
00224       return ActionResult( 22504 );
00225    
00226    Lack l = buildingProductionPrerequisites( bld );
00227    if ( !l.ok() )
00228       return ActionResult(22505);
00229    
00230    if ( !isFieldUsable( target ))
00231       return ActionResult(22503);
00232    
00233    
00234    
00235    auto_ptr<SpawnBuilding> sb ( new SpawnBuilding( getMap(), target, buildingTypeID, getUnit()->getOwner() ));
00236    ActionResult res = sb->execute( context );
00237    if ( res.successful() )
00238       sb.release();
00239    else
00240       return res;
00241 
00242    Resources cost = getProductionCost( bld );
00243    
00244    auto_ptr<ConsumeResource> cr ( new ConsumeResource( getUnit(), cost ));
00245    res = cr->execute( context );
00246    if ( res.successful() )
00247       cr.release();
00248    else
00249       return res;
00250    
00251    auto_ptr<ChangeUnitMovement> cum ( new ChangeUnitMovement( getUnit(), 0 ));
00252    res = cum->execute( context );
00253    if ( res.successful() )
00254       cum.release();
00255    else
00256       return res;
00257 
00258    auto_ptr<ChangeUnitProperty> cup ( new ChangeUnitProperty( getUnit(), ChangeUnitProperty::AttackedFlag, 1 ));
00259    res = cup->execute( context );
00260    if ( res.successful() )
00261       cup.release();
00262    else
00263       return res;
00264    
00265    if ( context.display )
00266       context.display->repaintDisplay();
00267 
00268    return ActionResult(0);
00269 }
00270 
00271 Building* ConstructBuildingCommand :: getProducedBuilding()
00272 {
00273    return NULL;
00274 }
00275 
00276 
00277 static const int ConstructBuildingCommandVersion = 1;
00278 
00279       void ConstructBuildingCommand :: readData ( tnstream& stream )
00280 {
00281    UnitCommand::readData( stream );
00282    int version = stream.readInt();
00283    if ( version > ConstructBuildingCommandVersion )
00284       throw tinvalidversion ( "ConstructBuildingCommand", ConstructBuildingCommandVersion, version );
00285    target.read( stream );
00286    buildingTypeID = stream.readInt();
00287 }
00288 
00289 void ConstructBuildingCommand :: writeData ( tnstream& stream ) const
00290 {
00291    UnitCommand::writeData( stream );
00292    stream.writeInt( ConstructBuildingCommandVersion );
00293    target.write( stream );
00294    stream.writeInt( buildingTypeID );
00295 }
00296 
00297 void ConstructBuildingCommand :: setBuildingType( const BuildingType* type )
00298 {
00299    buildingTypeID = type->id;
00300 }
00301 
00302 
00303 ASCString ConstructBuildingCommand :: getCommandString() const
00304 {
00305    ASCString c;
00306    c.format("constructBuilding ( map, %d, asc.MapCoordinate(%d, %d), %d )", getUnitID(), target.x, target.y, buildingTypeID );
00307    return c;
00308 }
00309 
00310 GameActionID ConstructBuildingCommand::getID() const
00311 {
00312    return ActionRegistry::ConstructBuildingCommand;
00313 }
00314 
00315 ASCString ConstructBuildingCommand::getDescription() const
00316 {
00317    ASCString s = "Construct ";
00318 
00319    const BuildingType* bt = getMap()->getbuildingtype_byid( buildingTypeID );
00320    if ( bt )
00321       s += bt->name;
00322    else
00323       s += "building";
00324 
00325    if ( getUnit() ) {
00326       s += " by " + getUnit()->getName();
00327    }
00328    s += " at " + target.toString();
00329    return s;
00330 }
00331 
00332 namespace
00333 {
00334 const bool r1 = registerAction<ConstructBuildingCommand> ( ActionRegistry::ConstructBuildingCommand );
00335 }
00336 

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