00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "containercontrols.h"
00019 #include "unitctrl.h"
00020 #include "gamemap.h"
00021 #include "replay.h"
00022 #include "mapdisplayinterface.h"
00023 #include "itemrepository.h"
00024
00025
00026 const GameMap* ContainerConstControls::getMap() const
00027 {
00028 return container->getMap();
00029 }
00030
00031
00032 GameMap* ContainerControls::getMap()
00033 {
00034 return container->getMap();
00035 }
00036
00037 const Player& ContainerConstControls::getPlayer() const
00038 {
00039 return getMap()->player[ getMap()->actplayer ];
00040 }
00041
00042
00043 Player& ContainerControls::getPlayer()
00044 {
00045 return getMap()->player[ getMap()->actplayer ];
00046 }
00047
00048 int ContainerControls::getPlayerNum()
00049 {
00050 return getMap()->actplayer;
00051 }
00052
00053
00054 bool ContainerConstControls::unitProductionAvailable() const
00055 {
00056 if ( container->getOwner() == container->getMap()->actplayer )
00057 if ( container->vehiclesLoaded() < container->baseType->maxLoadableUnits )
00058 if ( container->baseType->hasFunction( ContainerBaseType::InternalVehicleProduction ))
00059 return true;
00060
00061 return false;
00062 }
00063
00064 int ContainerConstControls::unitProductionPrerequisites( const Vehicletype* type ) const
00065 {
00066 int l = 0;
00067 Resources cost = container->getProductionCost( type );
00068 if ( getPlayer().research.vehicletypeavailable ( type ) || !getMap()->getgameparameter( cgp_produceOnlyResearchedStuffInternally ) ) {
00069 for ( int r = 0; r < resourceTypeNum; r++ )
00070 if ( container->getAvailableResource( cost.resource(r), r ) < cost.resource(r) )
00071 l |= 1 << r;
00072 } else
00073 l |= 1 << 10;
00074
00075 if ( !container->vehicleUnloadable( type ) && !container->baseType->hasFunction( ContainerBaseType::ProduceNonLeavableUnits ))
00076 l |= 1 << 11;
00077
00078 return l;
00079 }
00080
00081
00082 Vehicle* ContainerControls::produceUnit( const Vehicletype* type, bool fillWithAmmo, bool fillWithResources )
00083 {
00084 if ( !unitProductionAvailable() )
00085 return NULL;
00086
00087 if ( unitProductionPrerequisites( type ))
00088 return NULL;
00089
00090
00091 Vehicle* vehicle = new Vehicle ( type, getMap(), getPlayerNum() );
00092
00093 logtoreplayinfo ( rpl_produceunit, type->id , getPlayerNum() * 8, container->getPosition().x, container->getPosition().y, 0, vehicle->networkid );
00094
00095 vehicle->setnewposition( container->getPosition() );
00096
00097 if ( getMap()->getgameparameter(cgp_bi3_training) >= 1 ) {
00098 int cnt = 0;
00099
00100 for ( Player::BuildingList::iterator bi = actmap->player[actmap->actplayer].buildingList.begin(); bi != actmap->player[actmap->actplayer].buildingList.end(); bi++ )
00101 if ( (*bi)->typ->hasFunction( ContainerBaseType::TrainingCenter ) )
00102 cnt++;
00103
00104 vehicle->experience += cnt * actmap->getgameparameter(cgp_bi3_training);
00105 if ( vehicle->experience > maxunitexperience )
00106 vehicle->experience = maxunitexperience;
00107 }
00108
00109 container->getResource( container->getProductionCost( type ), false );
00110
00111 container->addToCargo( vehicle );
00112
00113 if ( fillWithAmmo )
00114 refillAmmo( vehicle );
00115
00116 if( fillWithResources )
00117 refillResources( vehicle );
00118
00119 vehicle->setMovement(0);
00120 vehicle->setAttacked();
00121
00122 return vehicle;
00123 }
00124
00125
00126 Vehicle* ContainerControls::produceUnitHypothetically( const Vehicletype* type )
00127 {
00128 if ( !unitProductionAvailable() )
00129 return NULL;
00130
00131 if ( unitProductionPrerequisites( type ))
00132 return NULL;
00133
00134
00135 Vehicle* vehicle = new Vehicle ( type, getMap(), getPlayerNum() );
00136 vehicle->setnewposition( container->getPosition() );
00137
00138 if ( getMap()->getgameparameter(cgp_bi3_training) >= 1 ) {
00139 int cnt = 0;
00140
00141 for ( Player::BuildingList::iterator bi = actmap->player[actmap->actplayer].buildingList.begin(); bi != actmap->player[actmap->actplayer].buildingList.end(); bi++ )
00142 if ( (*bi)->typ->hasFunction( ContainerBaseType::TrainingCenter ) )
00143 cnt++;
00144
00145 vehicle->experience += cnt * actmap->getgameparameter(cgp_bi3_training);
00146 if ( vehicle->experience > maxunitexperience )
00147 vehicle->experience = maxunitexperience;
00148 }
00149 return vehicle;
00150 }
00151
00152
00153
00154 VehicleMovement* ContainerControls :: movement ( Vehicle* eht, bool simpleMode )
00155 {
00156 VehicleMovement* vehicleMovement = new VehicleMovement ( &getDefaultMapDisplay(), NULL );
00157 int mode = 0;
00158 if ( simpleMode )
00159 mode |= VehicleMovement::DisableHeightChange;
00160
00161 int status = vehicleMovement->execute ( eht, -1, -1, 0, -1, mode );
00162
00163 if ( status > 0 )
00164 return vehicleMovement;
00165 else {
00166 delete vehicleMovement;
00167 return NULL;
00168 }
00169 }
00170
00171
00172
00173
00174 int ContainerControls :: ammoProducable ( int weaptype, int num )
00175 {
00176 if ( container->baseType->hasFunction( ContainerBaseType::AmmoProduction ) ) {
00177 Resources needed = Resources( cwaffenproduktionskosten[weaptype][0] * num, cwaffenproduktionskosten[weaptype][1] * num, cwaffenproduktionskosten[weaptype][2] * num );
00178 Resources avail = container->getResource( needed, true );
00179
00180 int perc = 100;
00181 for ( int r = 0; r < 3; ++r )
00182 if ( needed.resource(r) > 0 )
00183 perc = min ( 100 * avail.resource(r) / needed.resource(r), perc);
00184
00185 if ( perc < 0 )
00186 perc = 0;
00187
00188 return num * perc / 100;
00189 } else {
00190 return 0;
00191 }
00192 }
00193
00194
00195 int ContainerControls :: produceAmmo ( int weaptype, int num )
00196 {
00197 int n = ammoProducable( weaptype, num );
00198 container->getResource ( Resources( cwaffenproduktionskosten[weaptype][0] * n, cwaffenproduktionskosten[weaptype][1] * n, cwaffenproduktionskosten[weaptype][2] * n ), false );
00199 container->putAmmo ( weaptype, n, false );
00200
00201 logtoreplayinfo ( rpl_produceAmmo, container->getPosition().x, container->getPosition().y, weaptype, n );
00202 return n;
00203 }
00204
00205
00206
00207 int ContainerControls :: getammunition ( int weapontype, int num, bool abbuchen, bool produceifrequired )
00208 {
00209 int got = container->getAmmo( weapontype, num, !abbuchen );
00210 if ( got < num && container->baseType->hasFunction( ContainerBaseType::AmmoProduction ) && produceifrequired ) {
00211 if ( abbuchen ) {
00212 produceAmmo ( weapontype, num - got );
00213 got += container->getAmmo( weapontype, num - got, !abbuchen );
00214 } else
00215 got += ammoProducable( weapontype, num - got );
00216 }
00217 return got;
00218 }
00219
00220 bool ContainerControls :: ammotypeavail ( int type )
00221 {
00222 return true;
00223 }
00224
00225
00226
00227 void ContainerControls :: fillResource (Vehicle* eht, int resourcetype, int newamount)
00228 {
00229 int oldamount = eht->getResource(maxint, resourcetype, true);
00230 int storable = eht->putResource(newamount - oldamount, resourcetype, true);
00231
00232 eht->putResource( container->getResource ( storable, resourcetype, false ), resourcetype, false );
00233
00234 logtoreplayinfo ( rpl_refuel2, eht->xpos, eht->ypos, eht->networkid, int(1000+resourcetype), eht->getTank().resource(resourcetype), oldamount );
00235 logtoreplayinfo ( rpl_refuel3, container->getIdentification(), int(1000+resourcetype), eht->getTank().resource(resourcetype) - oldamount );
00236 };
00237
00238
00239
00240 void ContainerControls :: fillAmmo (Vehicle* eht, int weapon, int newa )
00241 {
00242 if ( eht->typ->weapons.weapon[ weapon ].requiresAmmo() ) {
00243 if ( newa > eht->typ->weapons.weapon[ weapon ].count )
00244 newa = eht->typ->weapons.weapon[ weapon ].count;
00245
00246 if ( newa > eht->ammo[weapon] )
00247 eht->ammo[weapon] += getammunition ( eht->typ->weapons.weapon[ weapon ].getScalarWeaponType() , newa - eht->ammo[weapon], 1, true );
00248 else {
00249 container->putAmmo ( eht->typ->weapons.weapon[ weapon ].getScalarWeaponType() , eht->ammo[weapon] - newa, 1 );
00250 eht->ammo[weapon] = newa;
00251 }
00252 }
00253 logtoreplayinfo ( rpl_refuel, eht->xpos, eht->ypos, eht->networkid, weapon, newa );
00254
00255 };
00256
00257
00258
00259 void ContainerControls :: refillAmmo ( Vehicle* eht )
00260 {
00261 for (int i = 0; i < eht->typ->weapons.count; i++)
00262 if ( eht->typ->weapons.weapon[ i ].requiresAmmo() )
00263 fillAmmo ( eht, i, maxint );
00264 }
00265
00266 void ContainerControls :: refillResources ( Vehicle* veh )
00267 {
00268 fillResource ( veh, 1, maxint );
00269 fillResource ( veh, 2, maxint );
00270 }
00271
00272 void ContainerControls :: refilleverything ( Vehicle* eht )
00273 {
00274 refillResources( eht );
00275 refillAmmo( eht );
00276 }
00277
00278 void ContainerControls :: emptyeverything ( Vehicle* eht )
00279 {
00280 fillResource ( eht, 1, 0 );
00281 fillResource ( eht, 2, 0 );
00282 for (int i = 0; i < eht->typ->weapons.count; i++)
00283 if ( eht->typ->weapons.weapon[ i ].requiresAmmo() )
00284 fillAmmo ( eht, i, 0 );
00285
00286
00287
00288
00289
00290 }
00291
00292
00293
00294 Resources ContainerControls :: calcDestructionOutput( Vehicle* veh )
00295 {
00296 int output;
00297 if ( container->baseType->hasFunction( ContainerBaseType::RecycleUnits ) )
00298 output = recyclingoutput;
00299 else
00300 output = destructoutput;
00301
00302 Resources res;
00303
00304 for ( ContainerBase::Cargo::const_iterator i = veh->getCargo().begin(); i != veh->getCargo().end(); i++)
00305 if ( *i )
00306 res += calcDestructionOutput ( *i );
00307
00308 res.material += veh->typ->productionCost.material * (100 - veh->damage/2 ) / 100 / output;
00309 return res;
00310 }
00311
00312
00313 void ContainerControls :: destructUnit( Vehicle* veh )
00314 {
00315 Resources res = calcDestructionOutput ( veh );
00316 emptyeverything ( veh );
00317
00318 logtoreplayinfo ( rpl_recycleUnit, container->getIdentification(), veh->networkid );
00319
00320 container->putResource ( res.material, Resources::Material, false );
00321 container->removeUnitFromCargo( veh );
00322 delete veh;
00323 }
00324
00325
00326
00327 bool ContainerControls::unitTrainingAvailable( Vehicle* veh )
00328 {
00329 GameMap* actmap = container->getMap();
00330 if ( actmap->getgameparameter( cgp_bi3_training ) )
00331 return false;
00332
00333 if ( veh->experience < actmap->getgameparameter ( cgp_maxtrainingexperience ) )
00334 if ( !veh->attacked )
00335 if ( container->baseType->hasFunction( ContainerBaseType::TrainingCenter )) {
00336 int num = 0;
00337 int numsh = 0;
00338 for (int i = 0; i < veh->typ->weapons.count; i++ )
00339 if ( veh->typ->weapons.weapon[i].shootable() )
00340 if ( veh->ammo[i] )
00341 numsh++;
00342 else
00343 num++;
00344
00345 if ( num == 0 && numsh > 0 )
00346 return true;
00347 }
00348
00349 return false;
00350 }
00351
00352
00353 void ContainerControls::trainUnit( Vehicle* veh )
00354 {
00355 GameMap* actmap = container->getMap();
00356 if ( unitTrainingAvailable ( veh ) ) {
00357 veh->experience+= actmap->getgameparameter( cgp_trainingIncrement );
00358 for (int i = 0; i < veh->typ->weapons.count; i++ )
00359 if ( veh->typ->weapons.weapon[i].shootable() )
00360 veh->ammo[i]--;
00361
00362 if ( veh->experience > actmap->getgameparameter ( cgp_maxtrainingexperience ) )
00363 veh->experience = actmap->getgameparameter ( cgp_maxtrainingexperience );
00364
00365 veh->attacked = 1;
00366 veh->setMovement ( 0 );
00367 logtoreplayinfo ( rpl_trainunit, container->getPosition().x, container->getPosition().y, veh->experience, veh->networkid );
00368 }
00369 };
00370
00371
00372 Resources ContainerControls :: buildProductionLineResourcesNeeded( const Vehicletype* veh )
00373 {
00374 return veh->productionCost * productionLineConstructionCostFactor;
00375 }
00376
00377
00378 int ContainerControls :: buildProductionLine ( const Vehicletype* veh )
00379 {
00380 if ( container->baseType->hasFunction(ContainerBaseType::NoProductionCustomization))
00381 return -505;
00382
00383 if ( find( container->getProduction().begin(), container->getProduction().end(), veh ) != container->getProduction().end() )
00384 return -503;
00385
00386 if ( container->getResource( buildProductionLineResourcesNeeded(veh), 1 ) < buildProductionLineResourcesNeeded(veh))
00387 return -500;
00388
00389 container->getResource( buildProductionLineResourcesNeeded(veh), 0 );
00390 container->addProductionLine( veh );
00391
00392 logtoreplayinfo ( rpl_buildProdLine, container->getIdentification(), veh->id );
00393
00394 return 0;
00395 }
00396
00397
00398 Resources ContainerControls :: removeProductionLineResourcesNeeded( const Vehicletype* veh )
00399 {
00400 return veh->productionCost * productionLineRemovalCostFactor;
00401 }
00402
00403
00404 int ContainerControls :: removeProductionLine ( const Vehicletype* veh )
00405 {
00406 if ( container->baseType->hasFunction(ContainerBaseType::NoProductionCustomization))
00407 return -505;
00408
00409 if ( find( container->getProduction().begin(), container->getProduction().end(), veh ) == container->getProduction().end() )
00410 return -502;
00411
00412 if ( container->getResource( removeProductionLineResourcesNeeded(veh), 1 ) < removeProductionLineResourcesNeeded(veh))
00413 return -500;
00414
00415 container->getResource( removeProductionLineResourcesNeeded(veh), 0 );
00416 container->deleteProductionLine( veh );
00417
00418 logtoreplayinfo( rpl_removeProdLine, container->getIdentification(), veh->id );
00419 return 0;
00420 }
00421
00422
00423 vector<const Vehicletype*> ContainerControls :: productionLinesBuyable()
00424 {
00425
00426 vector<const Vehicletype*> list;
00427
00428 if ( container->baseType->hasFunction(ContainerBaseType::NoProductionCustomization))
00429 return list;
00430
00431 Resources r = container->getResource( Resources(maxint, maxint, maxint), 1 );
00432
00433 for ( int i = 0; i < vehicleTypeRepository.getNum(); ++i ) {
00434 Vehicletype* veh = actmap->getvehicletype_bypos ( i );
00435 if ( veh ) {
00436 bool found = find( container->getProduction().begin(), container->getProduction().end(), veh ) != container->getProduction().end();
00437 if ( container->baseType->vehicleFit ( veh ) && !found )
00438 if ( container->vehicleUnloadable(veh) || container->baseType->hasFunction( ContainerBaseType::ProduceNonLeavableUnits ))
00439 if ( veh->techDependency.available ( container->getMap()->getCurrentPlayer().research ))
00440 if ( container->baseType->vehicleCategoriesProduceable & (1 << veh->movemalustyp))
00441 list.push_back( veh );
00442 }
00443 }
00444 return list;
00445 }
00446
00447
00448
00449 bool ContainerControls :: moveUnitUpAvail( const Vehicle* veh )
00450 {
00451 ContainerBase* carr = veh->getCarrier();
00452 if ( carr ) {
00453 ContainerBase* carr2 = carr->getCarrier();
00454 if ( carr2 )
00455 return carr2->vehicleFit( veh );
00456 }
00457 return false;
00458 }
00459
00460 bool ContainerControls :: moveUnitUp( Vehicle* veh )
00461 {
00462 if ( !veh )
00463 return false;
00464
00465 if ( !moveUnitUpAvail( veh ) )
00466 return false;
00467
00468 ContainerBase* source = veh->getCarrier();
00469 if ( source ) {
00470 ContainerBase* target = source->getCarrier();
00471 if ( target ) {
00472 source->removeUnitFromCargo( veh, false );
00473 target->addToCargo( veh );
00474
00475 logtoreplayinfo ( rpl_moveUnitUp, target->getPosition().x, target->getPosition().y, veh->networkid );
00476 return true;
00477 }
00478 }
00479 return false;
00480 }
00481
00482
00483 bool ContainerControls::moveUnitDownAvail( const Vehicle* movingUnit )
00484 {
00485 return moveUnitDownTargets( movingUnit ).size() > 0;
00486 }
00487
00488 bool ContainerControls::moveUnitDownAvail( const Vehicle* movingUnit, const Vehicle* newTransport )
00489 {
00490 return newTransport->vehicleFit( movingUnit );
00491 }
00492
00493
00494 vector<Vehicle*> ContainerControls::moveUnitDownTargets( const Vehicle* movingUnit )
00495 {
00496 vector<Vehicle*> targets;
00497
00498 if ( !container )
00499 return targets;
00500
00501 for ( ContainerBase::Cargo::const_iterator i = container->getCargo().begin(); i != container->getCargo().end(); ++i )
00502 if ( *i != movingUnit && *i )
00503 if ( moveUnitDownAvail ( movingUnit, *i ))
00504 targets.push_back( *i );
00505
00506 return targets;
00507 }
00508
00509
00510 bool ContainerControls::moveUnitDown( Vehicle* veh, Vehicle* newTransport )
00511 {
00512 if ( !container || !veh || !newTransport )
00513 return false;
00514
00515 if ( !newTransport->vehicleFit( veh ))
00516 return false;
00517
00518 container->removeUnitFromCargo( veh );
00519 newTransport->addToCargo( veh );
00520
00521 logtoreplayinfo ( rpl_moveUnitUpDown, container->getPosition().x, container->getPosition().y, 0, newTransport->networkid, veh->networkid );
00522 return true;
00523 }