00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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 )
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