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