00001
00002
00003
00004
00005
00006
00007
00008
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <algorithm>
00023 #include <cmath>
00024
00025 #include "vehicletype.h"
00026 #include "buildingtype.h"
00027 #include "buildings.h"
00028 #include "viewcalculation.h"
00029 #include "errors.h"
00030 #include "spfst.h"
00031 #include "resourcenet.h"
00032 #include "itemrepository.h"
00033 #include "containercontrols.h"
00034 #include "misc.h"
00035
00036
00037 #ifndef BUILDINGVERSIONLIMIT
00038 # define BUILDINGVERSIONLIMIT -1000000000
00039 #endif
00040
00041
00042 const float repairEfficiencyBuilding[resourceTypeNum*resourceTypeNum] = { 1./3., 0, 1. / 3. ,
00043 0, 1./3., 0,
00044 0, 0, 0 };
00045
00046 Building :: Building ( GameMap* actmap, const MapCoordinate& _entryPosition, const BuildingType* type, int player, bool setupImages, bool chainToField )
00047 : ContainerBase ( type, actmap, player ), typ ( type ), repairEfficiency ( repairEfficiencyBuilding )
00048 {
00049
00050 viewOnMap = false;
00051
00052 int i;
00053 for ( i = 0; i < 8; i++ )
00054 aiparam[i] = NULL;
00055
00056 _completion = 0;
00057 connection = 0;
00058
00059 lastmineddist= 0;
00060
00061 for ( i = 0; i < waffenanzahl; i++ )
00062 ammo[i] = 0;
00063
00064 netcontrol = 0;
00065
00066 visible = 1;
00067 damage = 0;
00068
00069 entryPosition = _entryPosition;
00070
00071 gamemap->player[player].buildingList.push_back ( this );
00072
00073 if ( chainToField )
00074 chainbuildingtofield ( entryPosition, setupImages );
00075 }
00076
00077
00078 int Building::repairableDamage() const
00079 {
00080 int d = getMap()->getgameparameter ( cgp_maxbuildingrepair ) - repairedThisTurn;
00081 if ( d < 0 )
00082 d = 0;
00083 if ( d > damage )
00084 d = damage;
00085 return d;
00086 }
00087
00088 void Building::postRepair ( int oldDamage )
00089 {
00090 repairedThisTurn += oldDamage - damage;
00091 }
00092
00093 bool Building::canRepair ( const ContainerBase* item ) const
00094 {
00095 return typ->hasFunction( ContainerBaseType::InternalUnitRepair ) ||
00096 typ->hasFunction( ContainerBaseType::ExternalRepair ) ||
00097 (item == this ) ;
00098 }
00099
00100 int Building::getIdentification() const
00101 {
00102 return -(getPosition().x + (getPosition().y << 16));
00103 }
00104
00105 void Building :: convert ( int player, bool recursive )
00106 {
00107 if (player > 8)
00108 fatalError("convertbuilding: \n player must be in range 0..8 sein ");
00109
00110 #ifdef sgmain
00111 if ( typ->hasFunction( ContainerBaseType::SelfDestructOnConquer ) ) {
00112 delete this;
00113 return;
00114 }
00115
00116
00117 int oldnetcontrol = netcontrol;
00118 netcontrol = cnet_stopenergyinput + (cnet_stopenergyinput << 1) + (cnet_stopenergyinput << 2);
00119 Resources put = putResource( actstorage, false );
00120 actstorage -= put;
00121
00122 netcontrol = oldnetcontrol;
00123
00124 #endif
00125
00126 int oldcol = getOwner();
00127
00128 #ifdef sgmain
00129 if ( oldcol == 8 )
00130 for ( int r = 0; r < 3; r++ )
00131 if ( gamemap->isResourceGlobal( r )) {
00132 gamemap->bi_resource[player].resource(r) += actstorage.resource(r);
00133 actstorage.resource(r) = 0;
00134 }
00135
00136 #endif
00137 bool hadViewOnMap = viewOnMap;
00138 if ( color < 8*8 && hadViewOnMap)
00139 removeview();
00140
00141 Player::BuildingList::iterator i = find ( gamemap->player[oldcol].buildingList.begin(), gamemap->player[oldcol].buildingList.end(), this );
00142 if ( i != gamemap->player[oldcol].buildingList.end())
00143 gamemap->player[oldcol].buildingList.erase ( i );
00144
00145 gamemap->player[player].buildingList.push_back( this );
00146
00147 color = player * 8;
00148
00149 if ( hadViewOnMap && player < 8 )
00150 addview();
00151
00152 if ( recursive )
00153 for ( Cargo::iterator i = cargo.begin(); i != cargo.end(); ++i )
00154 if ( *i )
00155 (*i)->convert( player );
00156
00157 conquered();
00158 anyContainerConquered(this);
00159 }
00160
00161
00162 void Building :: registerForNewOwner( int player )
00163 {
00164 int oldcol = getOwner();
00165
00166 if ( oldcol < 8 )
00167 removeview();
00168
00169 Player::BuildingList::iterator i = find ( gamemap->player[oldcol].buildingList.begin(), gamemap->player[oldcol].buildingList.end(), this );
00170 if ( i != gamemap->player[oldcol].buildingList.end())
00171 gamemap->player[oldcol].buildingList.erase ( i );
00172
00173 gamemap->player[player].buildingList.push_back( this );
00174
00175 color = player * 8;
00176
00177 if ( player < 8 )
00178 addview();
00179
00180 conquered();
00181 anyContainerConquered(this);
00182
00183 }
00184
00185
00186
00187
00188 const Surface& Building :: getPicture ( const BuildingType::LocalCoordinate& localCoordinate ) const
00189 {
00190 static Surface emptySurface;
00191 MapField* fld = getField ( localCoordinate );
00192 if ( fld ) {
00193 return typ->getPicture(localCoordinate, fld->getWeather(), _completion);
00194 } else
00195 return emptySurface;
00196 }
00197
00198 void Building::paintSingleField ( Surface& s, SPoint imgpos, BuildingType::LocalCoordinate pos ) const
00199 {
00200 if ( getHeight() <= chfahrend )
00201 paintField( getPicture( pos ), s, imgpos, 0, false, 0 );
00202 else
00203 paintField( getPicture( pos ), s, imgpos, 0, false );
00204 }
00205
00206
00207
00208
00209
00210 template<typename T>
00211 T ASC_min ( T a, T b )
00212 {
00213 if ( a > b )
00214 return b;
00215 else
00216 return a;
00217 }
00218 template<typename T>
00219 T ASC_max ( T a, T b )
00220 {
00221 if ( a > b )
00222 return a;
00223 else
00224 return b;
00225 }
00226
00227
00228
00229 Surface Building::getImage() const
00230 {
00231 int minx = maxint;
00232 int maxx = 0;
00233 int maxy = 0;
00234 int miny = maxint;
00235
00236 for ( int x = 0; x < 4; x++ )
00237 for ( int y = 0; y < 6; y++ )
00238 if ( typ->fieldExists(BuildingType::LocalCoordinate(x,y) )) {
00239 SPoint pos ( x * fielddistx + ( y & 1 ) * fielddisthalfx, y * fielddisty);
00240 minx = ASC_min( minx, int(pos.x) );
00241 maxx = ASC_max( maxx, int(pos.x) + fieldsizex );
00242 miny = ASC_min ( miny, int(pos.y) );
00243 maxy = ASC_max ( maxy, int(pos.y) + fieldsizey );
00244 }
00245
00246 Surface s = Surface::createSurface(maxx-minx+1,maxy-miny+1, 32,Surface::transparent << 24 );
00247
00248 typ->paint ( s, SPoint(-minx,-miny), getOwningPlayer().getPlayerColor() );
00249 return s;
00250 }
00251
00252 #ifndef sgmain
00253 void Building :: execnetcontrol ( void ) {}
00254 int Building :: putResource ( int amount, int resourcetype, bool queryonly, int scope, int player ) { return 0; };
00255 int Building :: getResource ( int amount, int resourcetype, bool queryonly, int scope, int player ) { return actstorage.resource(resourcetype); };
00256 int Building :: getAvailableResource ( int amount, int resourcetype, int scope ) const { return actstorage.resource(resourcetype); };
00257 #endif
00258
00259 void Building :: setCompletion ( int completion, bool setupImages )
00260 {
00261 _completion = completion;
00262 }
00263
00264
00265
00266
00267
00268 int Building :: chainbuildingtofield ( const MapCoordinate& entryPos, bool setupImages )
00269 {
00270 MapCoordinate oldpos = entryPosition;
00271 entryPosition = entryPos;
00272
00273 for ( int a = 0; a < 4; a++)
00274 for ( int b = 0; b < 6; b++)
00275 if ( typ->fieldExists ( BuildingType::LocalCoordinate( a, b) )) {
00276 MapField* f = getField( BuildingType::LocalCoordinate( a, b) );
00277 if ( !f || f->building ) {
00278 entryPosition = oldpos;
00279 return 1;
00280 }
00281 }
00282
00283 for ( int a = 0; a < 4; a++)
00284 for ( int b = 0; b < 6; b++)
00285 if ( typ->fieldExists ( BuildingType::LocalCoordinate( a , b ) )) {
00286 MapField* field = getField( BuildingType::LocalCoordinate( a, b) );
00287
00288 if ( visible ) {
00289 MapField::ObjectContainer::iterator i = field->objects.begin();
00290 while ( i != field->objects.end()) {
00291 if ( !i->typ->canExistBeneathBuildings )
00292 i = field->objects.erase ( i );
00293 else
00294 i++;
00295 };
00296 }
00297
00298 if ( field->vehicle && (field->vehicle->height < chtieffliegend )) {
00299 delete field->vehicle;
00300 field->vehicle = NULL;
00301 }
00302
00303 field->building = this;
00304 }
00305
00306 for ( Cargo::iterator i = cargo.begin(); i != cargo.end(); ++i )
00307 if ( *i )
00308 (*i)->setnewposition ( entryPos.x, entryPos.y );
00309
00310 MapField* field = getField( typ->entry );
00311 if ( field )
00312 field->bdt |= getTerrainBitType(cbbuildingentry) ;
00313
00314 if ( setupImages )
00315 gamemap->calculateAllObjects();
00316
00317
00318 for ( int a = 0; a < 4; a++)
00319 for ( int b = 0; b < 6; b++)
00320 if ( typ->fieldExists(BuildingType::LocalCoordinate(a,b))) {
00321 MapCoordinate p = getFieldCoordinates( BuildingType::LocalCoordinate(a,b));
00322 BuildingType::LocalCoordinate lc = getLocalCoordinate(p);
00323 if ( lc.x != a || lc.y!= b )
00324 warningMessage( "bug in building coordinate calculation");
00325 }
00326
00327
00328 return 0;
00329 }
00330
00331
00332 int Building :: unchainbuildingfromfield ( void )
00333 {
00334 int set = 0;
00335 for (int i = 0; i <= 3; i++)
00336 for (int j = 0; j <= 5; j++)
00337 if ( typ->fieldExists ( BuildingType::LocalCoordinate(i,j) ) ) {
00338 MapField* fld = getField( BuildingType::LocalCoordinate(i,j) );
00339 if ( fld && fld->building == this ) {
00340 set = 1;
00341 fld->building = NULL;
00342
00343 TerrainBits t = getTerrainBitType(cbbuildingentry);
00344 t.flip();
00345 fld->bdt &= t;
00346 }
00347 }
00348
00349 return set;
00350 }
00351
00352
00353 void Building :: addview ( void )
00354 {
00355 if ( viewOnMap )
00356 fatalError ("void Building :: addview - the building is already viewing the map");
00357
00358 viewOnMap = true;
00359
00360 tcomputebuildingview bes ( gamemap );
00361 bes.init( this, +1 );
00362 bes.startsearch();
00363 }
00364
00365 void Building :: resetview()
00366 {
00367 viewOnMap = false;
00368 }
00369
00370
00371 void Building :: removeview ( void )
00372 {
00373 if ( color != 64 ) {
00374 if ( !viewOnMap )
00375 fatalError ("void Building :: removeview - the building is not viewing the map");
00376
00377 tcomputebuildingview bes ( gamemap );
00378 bes.init( this, -1 );
00379 bes.startsearch();
00380
00381 viewOnMap = false;
00382 }
00383 }
00384
00385 MapCoordinate3D Building::getPosition3D() const
00386 {
00387 MapCoordinate3D e = getEntry();
00388 MapCoordinate3D p3;
00389 p3.setnum ( e.x, e.y, -1 );
00390 return p3;
00391 }
00392
00393 int Building :: getArmor ( ) const
00394 {
00395 return typ->_armor * gamemap->getgameparameter( cgp_buildingarmor ) / 100;
00396 }
00397
00398
00399 MapField* Building :: getField( const BuildingType::LocalCoordinate& lc ) const
00400 {
00401 return gamemap->getField ( getFieldCoordinates ( lc ));
00402 }
00403
00404
00405 MapField* Building :: getEntryField( ) const
00406 {
00407 return getField ( typ->entry );
00408 }
00409
00410 MapCoordinate3D Building :: getEntry( ) const
00411 {
00412 return MapCoordinate3D( entryPosition, typ->height);
00413 }
00414
00415
00416
00417 MapCoordinate Building :: getFieldCoordinates ( const BuildingType::LocalCoordinate& lc ) const
00418 {
00419 return typ->getFieldCoordinate ( entryPosition, lc );
00420 }
00421
00422
00423 BuildingType::LocalCoordinate Building::getLocalCoordinate( const MapCoordinate& field ) const
00424 {
00425 return typ->getLocalCoordinate( entryPosition, field );
00426 }
00427
00428
00429 Building :: ~Building ()
00430 {
00431 if ( gamemap ) {
00432 int c = color/8;
00433
00434 Player::BuildingList::iterator i = find ( gamemap->player[c].buildingList.begin(), gamemap->player[c].buildingList.end(), this );
00435 if ( i != gamemap->player[c].buildingList.end() )
00436 gamemap->player[c].buildingList.erase ( i );
00437 }
00438
00439 for ( int i = 0; i < 8; ++i ) {
00440 delete aiparam[ i ] ;
00441 aiparam[ i ] = NULL;
00442 }
00443
00444 unchainbuildingfromfield();
00445 }
00446
00447
00448 const int buildingstreamversion = -7;
00449
00450
00451 void Building :: write ( tnstream& stream, bool includeLoadedUnits ) const
00452 {
00453 stream.writeInt ( max( buildingstreamversion, BUILDINGVERSIONLIMIT ));
00454
00455 stream.writeInt ( typ->id );
00456 int i;
00457 for ( i = 0; i< resourceTypeNum; i++ )
00458 stream.writeInt ( bi_resourceplus.resource(i) );
00459 stream.writeChar ( color );
00460 stream.writeWord ( getEntry().x );
00461 stream.writeWord ( getEntry().y );
00462 stream.writeChar ( getCompletion() );
00463 for ( i = 0; i < waffenanzahl; i++ )
00464 stream.writeWord ( 0 );
00465
00466 for ( i = 0; i< resourceTypeNum; i++ )
00467 stream.writeInt ( plus.resource(i) );
00468
00469 for ( i = 0; i< resourceTypeNum; i++ )
00470 stream.writeInt ( maxplus.resource(i) );
00471
00472 for ( i = 0; i< resourceTypeNum; i++ )
00473 stream.writeInt ( actstorage.resource(i) );
00474
00475 for ( i = 0; i< waffenanzahl; i++ )
00476 stream.writeWord ( ammo[i] );
00477
00478 stream.writeWord ( maxresearchpoints );
00479 stream.writeWord ( researchpoints );
00480 stream.writeChar ( visible );
00481 stream.writeChar ( damage );
00482 stream.writeInt ( netcontrol );
00483 stream.writeString ( name );
00484
00485 stream.writeInt ( repairedThisTurn );
00486
00487 int c = 0;
00488
00489 if ( includeLoadedUnits )
00490 for ( Cargo::const_iterator i = cargo.begin(); i != cargo.end(); ++i )
00491 if ( *i )
00492 ++c;
00493
00494 if ( BUILDINGVERSIONLIMIT >= -3 )
00495 stream.writeChar( c );
00496 else
00497 stream.writeInt ( c );
00498
00499 if ( c )
00500 for ( Cargo::const_iterator i = cargo.begin(); i != cargo.end(); ++i )
00501 if ( *i )
00502 (*i)->write ( stream );
00503
00504
00505 if ( BUILDINGVERSIONLIMIT >= -4 )
00506 stream.writeChar( internalUnitProduction.size() );
00507 else
00508 stream.writeInt( internalUnitProduction.size() );
00509
00510 for (int k = 0; k < internalUnitProduction.size(); k++ ) {
00511 assert( internalUnitProduction[k] );
00512 stream.writeInt( internalUnitProduction[k]->id );
00513 }
00514
00515 if ( BUILDINGVERSIONLIMIT >= -3 )
00516 stream.writeChar(0);
00517
00518 stream.writeInt( view );
00519 stream.writeString( privateName );
00520 }
00521
00522
00523 Building* Building::newFromStream ( GameMap* gamemap, tnstream& stream, bool chainToField )
00524 {
00525 int version = stream.readInt();
00526 int xpos, ypos, color;
00527 Resources res;
00528
00529 BuildingType* typ;
00530
00531 if ( version < buildingstreamversion )
00532 throw tinvalidversion( stream.getDeviceName(), buildingstreamversion, version );
00533
00534 if ( version >= buildingstreamversion && version <= -1 ) {
00535
00536 int id = stream.readInt ();
00537 typ = gamemap->getbuildingtype_byid ( id );
00538 if ( !typ )
00539 throw InvalidID ( "building", id );
00540
00541 for ( int i = 0; i < 3; i++ )
00542 res.resource(i) = stream.readInt();
00543
00544 color = stream.readChar();
00545 xpos = stream.readWord() ;
00546 } else {
00547 int id = version;
00548
00549 typ = gamemap->getbuildingtype_byid ( id );
00550 if ( !typ )
00551 throw InvalidID ( "building", id );
00552
00553 color = stream.readChar();
00554 xpos = stream.readWord();
00555 }
00556
00557 ypos = stream.readWord();
00558
00559 Building* bld = new Building ( gamemap, MapCoordinate(xpos,ypos), typ, color/8, false, chainToField );
00560 bld->bi_resourceplus = res;
00561 bld->readData ( stream, version );
00562 return bld;
00563 }
00564
00565
00566
00567 void Building:: read ( tnstream& stream )
00568 {
00569 int version = stream.readInt();
00570
00571 if ( version >= buildingstreamversion && version <= -1 ) {
00572 stream.readInt ();
00573 for ( int i = 0; i < 3; i++ )
00574 bi_resourceplus.resource(i) = stream.readInt();
00575
00576 stream.readChar();
00577 stream.readWord();
00578 stream.readWord();
00579 } else {
00580
00581 stream.readChar();
00582 stream.readWord();
00583 stream.readWord();
00584 bi_resourceplus = Resources ( 0, 0, 0);
00585 }
00586
00587 readData ( stream, version );
00588 }
00589
00590
00591 void Building :: readData ( tnstream& stream, int version )
00592 {
00593 setCompletion ( stream.readChar(), false );
00594
00595 int i;
00596 for ( i = 0; i < waffenanzahl; i++)
00597 stream.readWord();
00598
00599 for ( i = 0; i< 3; i++ )
00600 plus.resource(i) = stream.readInt();
00601
00602 for ( i = 0; i< 3; i++ )
00603 maxplus.resource(i) = stream.readInt();
00604
00605
00606 for ( i = 0; i< 3; i++ )
00607 actstorage.resource(i) = min(stream.readInt(), getStorageCapacity().resource(i) );
00608
00609 for ( i = 0; i < waffenanzahl; i++)
00610 ammo[i] = stream.readWord();
00611
00612 maxresearchpoints = stream.readWord();
00613 researchpoints = stream.readWord();
00614
00615 if ( (researchpoints < typ->maxresearchpoints && !typ->hasFunction(ContainerBaseType::Research)) || (researchpoints > typ->maxresearchpoints))
00616 researchpoints = typ->maxresearchpoints;
00617
00618
00619 visible = stream.readChar();
00620 damage = stream.readChar();
00621
00622 netcontrol = stream.readInt();
00623 netcontrol = 0;
00624
00625 name = stream.readString ();
00626
00627 if ( version <= -2 )
00628 repairedThisTurn = stream.readInt ( );
00629 else
00630 repairedThisTurn = 0;
00631
00632 int c;
00633 if ( version <= -4 )
00634 c = stream.readInt();
00635 else
00636 c = stream.readChar();
00637
00638 if ( c ) {
00639 for ( int k = 0; k < c; k++) {
00640 Vehicle* v = Vehicle::newFromStream ( gamemap, stream );
00641 v->setnewposition ( getEntry().x, getEntry().y );
00642 addToCargo(v);
00643
00644 if ( v && v->reactionfire.getStatus() != Vehicle::ReactionFire::off && !v->baseType->hasFunction( ContainerBaseType::MoveWithReactionFire ))
00645 v->reactionfire.disable();
00646
00647 }
00648 }
00649
00650
00651 internalUnitProduction.clear();
00652 if ( version <= -5 )
00653 c = stream.readInt();
00654 else
00655 c = stream.readChar();
00656
00657 if ( c ) {
00658 for ( int k = 0; k < c ; k++) {
00659
00660 int id;
00661 if ( version <= -3 )
00662 id = stream.readInt();
00663 else
00664 id = stream.readWord();
00665
00666 internalUnitProduction.push_back ( gamemap->getvehicletype_byid ( id ) );
00667 if ( !internalUnitProduction[k] )
00668 throw InvalidID ( "unit", id );
00669 }
00670 }
00671
00672 if ( version >= -3 ) {
00673 c = stream.readChar();
00674 if ( c ) {
00675 for ( int k = 0; k < c ; k++) {
00676 if ( version <= -3 )
00677 stream.readInt();
00678 else
00679 stream.readWord();
00680 }
00681 }
00682 }
00683
00684 for ( i = 0; i< 3; i++ ) {
00685 if ( typ->maxplus.resource(i) > 0 ) {
00686 if ( plus.resource(i) > typ->maxplus.resource(i) )
00687 plus.resource(i) = typ->maxplus.resource(i);
00688
00689 if ( maxplus.resource(i) > typ->maxplus.resource(i) )
00690 maxplus.resource(i) = typ->maxplus.resource(i);
00691 } else {
00692 if ( plus.resource(i) < typ->maxplus.resource(i) )
00693 plus.resource(i) = typ->maxplus.resource(i);
00694
00695 if ( maxplus.resource(i) < typ->maxplus.resource(i) )
00696 maxplus.resource(i) = typ->maxplus.resource(i);
00697 }
00698 }
00699
00700 if ( version <= -6 )
00701 view = stream.readInt();
00702 else
00703 view = typ->view;
00704
00705 if ( version <= -7 )
00706 privateName = stream.readString();
00707 else
00708 privateName = "";
00709 }
00710
00711 ASCString Building::getName ( ) const
00712 {
00713 if ( name.empty())
00714 return typ->name;
00715 else
00716 return name;
00717 }
00718
00719 int Building::getAmmo( int type, int num, bool queryOnly )
00720 {
00721 assert( type >= 0 && type < waffenanzahl );
00722 int got = min( ammo[type], num );
00723 if ( !queryOnly ) {
00724 ammo[type] -= got;
00725
00726 }
00727 return got;
00728 }
00729
00730 int Building::getAmmo( int type, int num ) const
00731 {
00732 assert( type >= 0 && type < waffenanzahl );
00733 return min( ammo[type], num );
00734 }
00735
00736
00737 int Building::putAmmo( int type, int num, bool queryOnly )
00738 {
00739 assert( type >= 0 && type < waffenanzahl );
00740 if ( !queryOnly ) {
00741 ammo[type] += num;
00742
00743 }
00744 return num;
00745 }
00746
00747
00748
00749
00750 void Building::endRound( )
00751 {
00752 ContainerBase::endRound();
00753 repairedThisTurn = 0;
00754 }
00755
00756
00757 vector<MapCoordinate> Building::getCoveredFields()
00758 {
00759 vector<MapCoordinate> fields;
00760 for ( int x = 0; x < 4; x++ )
00761 for ( int y = 0; y < 6; y++)
00762 if ( typ->fieldExists ( BuildingType::LocalCoordinate(x, y) ) )
00763 fields.push_back ( getFieldCoordinates( BuildingType::LocalCoordinate(x, y)));
00764 return fields;
00765 }
00766
00767
00768 int Building::getMemoryFootprint() const
00769 {
00770 return sizeof(*this);
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792 struct ResearchEfficiency {
00793 float eff;
00794 Building* bld;
00795 bool operator<( const ResearchEfficiency& re) const { return eff > re.eff; };
00796 };
00797
00798
00799 void doresearch ( GameMap* actmap, int player )
00800 {
00801 Research& research = actmap->getPlayer(player).research;
00802
00803 if ( research.activetechnology == NULL && research.progress ) {
00804
00805
00806
00807 return;
00808 }
00809
00810
00811 typedef vector<ResearchEfficiency> VRE;
00812 VRE vre;
00813
00814 for ( Player::BuildingList::iterator bi = actmap->player[player].buildingList.begin(); bi != actmap->player[player].buildingList.end(); bi++ ) {
00815 Building* bld = *bi;
00816 if ( bld->typ->hasFunction( ContainerBaseType::Research ) ) {
00817 Resources res = returnResourcenUseForResearch ( bld, bld->researchpoints );
00818
00819 int m = max ( res.energy, max ( res.material, res.fuel));
00820
00821 ResearchEfficiency re;
00822 if ( m )
00823 re.eff = float(bld->researchpoints) / float(m);
00824 else
00825 re.eff = maxint;
00826
00827 re.bld = bld;
00828
00829 vre.push_back(re);
00830 } else
00831 if ( bld->researchpoints > 0 )
00832 research.progress += bld->researchpoints * research.getMultiplier();
00833 }
00834 sort( vre.begin(), vre.end());
00835
00836 for ( VRE::iterator i = vre.begin(); i != vre.end(); ++i ) {
00837 Building* bld = i->bld;
00838 Resources r = returnResourcenUseForResearch ( bld, bld->researchpoints );
00839 Resources got = bld->getResource ( r, true, 1, player );
00840
00841 int res = bld->researchpoints;
00842 if ( got < r ) {
00843 int diff = bld->researchpoints / 2;
00844 while ( got < r || diff > 1) {
00845 if ( got < r )
00846 res -= diff;
00847 else
00848 res += diff;
00849
00850 if ( res < 0 )
00851 res = 0;
00852
00853 if ( diff > 1 )
00854 diff /=2;
00855 else
00856 diff = 1;
00857
00858 r = returnResourcenUseForResearch ( bld, res );
00859 }
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870 }
00871
00872 got = bld->getResource ( r, false, 1, player );
00873
00874 if ( got < r )
00875 fatalError( "controls : doresearch : inconsistency in getting energy or material for building" );
00876
00877 research.progress += res * research.getMultiplier();
00878 }
00879 }
00880
00881 ASCString getBuildingReference ( Building* bld )
00882 {
00883 ASCString s = "The building " + bld->getName();
00884 s += " (position: "+ bld->getPosition().toString() + ") ";
00885 return s;
00886 }
00887