PageRenderTime 83ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/source/buildings.cpp

https://bitbucket.org/val_haris/asc-ai
C++ | 887 lines | 619 code | 221 blank | 47 comment | 161 complexity | 39274ca467ad313196bad96e5e158dde MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. /***************************************************************************
  2. buildings.cpp - description
  3. -------------------
  4. begin : Sat Feb 17 2001
  5. copyright : (C) 2001 by Martin Bickel
  6. email : bickel@asc-hq.org
  7. ***************************************************************************/
  8. /*! \file buildings.cpp
  9. \brief The buildings which a placed on the map
  10. */
  11. /***************************************************************************
  12. * *
  13. * This program is free software; you can redistribute it and/or modify *
  14. * it under the terms of the GNU General Public License as published by *
  15. * the Free Software Foundation; either version 2 of the License, or *
  16. * (at your option) any later version. *
  17. * *
  18. ***************************************************************************/
  19. #include <algorithm>
  20. #include <cmath>
  21. #include "vehicletype.h"
  22. #include "buildingtype.h"
  23. #include "buildings.h"
  24. #include "viewcalculation.h"
  25. #include "errors.h"
  26. #include "spfst.h"
  27. #include "resourcenet.h"
  28. #include "itemrepository.h"
  29. #include "containercontrols.h"
  30. #include "misc.h"
  31. #ifndef BUILDINGVERSIONLIMIT
  32. # define BUILDINGVERSIONLIMIT -1000000000
  33. #endif
  34. const float repairEfficiencyBuilding[resourceTypeNum*resourceTypeNum] = { 1./3., 0, 1. / 3. ,
  35. 0, 1./3., 0,
  36. 0, 0, 0 };
  37. Building :: Building ( GameMap* actmap, const MapCoordinate& _entryPosition, const BuildingType* type, int player, bool setupImages, bool chainToField )
  38. : ContainerBase ( type, actmap, player ), typ ( type ), repairEfficiency ( repairEfficiencyBuilding )
  39. {
  40. viewOnMap = false;
  41. int i;
  42. for ( i = 0; i < 8; i++ )
  43. aiparam[i] = NULL;
  44. _completion = 0;
  45. connection = 0;
  46. lastmineddist= 0;
  47. for ( i = 0; i < waffenanzahl; i++ )
  48. ammo[i] = 0;
  49. netcontrol = 0;
  50. visible = 1;
  51. damage = 0;
  52. entryPosition = _entryPosition;
  53. gamemap->player[player].buildingList.push_back ( this );
  54. if ( chainToField )
  55. chainbuildingtofield ( entryPosition, setupImages );
  56. }
  57. int Building::repairableDamage() const
  58. {
  59. int d = getMap()->getgameparameter ( cgp_maxbuildingrepair ) - repairedThisTurn;
  60. if ( d < 0 )
  61. d = 0;
  62. if ( d > damage )
  63. d = damage;
  64. return d;
  65. }
  66. void Building::postRepair ( int oldDamage )
  67. {
  68. repairedThisTurn += oldDamage - damage;
  69. }
  70. bool Building::canRepair ( const ContainerBase* item ) const
  71. {
  72. return typ->hasFunction( ContainerBaseType::InternalUnitRepair ) ||
  73. typ->hasFunction( ContainerBaseType::ExternalRepair ) ||
  74. (item == this ) ;
  75. }
  76. int Building::getIdentification() const
  77. {
  78. return -(getPosition().x + (getPosition().y << 16));
  79. }
  80. void Building :: convert ( int player, bool recursive )
  81. {
  82. if (player > 8)
  83. fatalError("convertbuilding: \n player must be in range 0..8 sein ");
  84. #ifdef sgmain
  85. if ( typ->hasFunction( ContainerBaseType::SelfDestructOnConquer ) ) {
  86. delete this;
  87. return;
  88. }
  89. int oldnetcontrol = netcontrol;
  90. netcontrol = cnet_stopenergyinput + (cnet_stopenergyinput << 1) + (cnet_stopenergyinput << 2);
  91. Resources put = putResource( actstorage, false );
  92. actstorage -= put;
  93. netcontrol = oldnetcontrol;
  94. #endif
  95. int oldcol = getOwner();
  96. #ifdef sgmain
  97. if ( oldcol == 8 )
  98. for ( int r = 0; r < 3; r++ )
  99. if ( gamemap->isResourceGlobal( r )) {
  100. gamemap->bi_resource[player].resource(r) += actstorage.resource(r);
  101. actstorage.resource(r) = 0;
  102. }
  103. #endif
  104. bool hadViewOnMap = viewOnMap;
  105. if ( color < 8*8 && hadViewOnMap)
  106. removeview();
  107. Player::BuildingList::iterator i = find ( gamemap->player[oldcol].buildingList.begin(), gamemap->player[oldcol].buildingList.end(), this );
  108. if ( i != gamemap->player[oldcol].buildingList.end())
  109. gamemap->player[oldcol].buildingList.erase ( i );
  110. gamemap->player[player].buildingList.push_back( this );
  111. color = player * 8;
  112. if ( hadViewOnMap && player < 8 )
  113. addview();
  114. if ( recursive )
  115. for ( Cargo::iterator i = cargo.begin(); i != cargo.end(); ++i )
  116. if ( *i )
  117. (*i)->convert( player );
  118. conquered();
  119. anyContainerConquered(this);
  120. }
  121. void Building :: registerForNewOwner( int player )
  122. {
  123. int oldcol = getOwner();
  124. if ( oldcol < 8 )
  125. removeview();
  126. Player::BuildingList::iterator i = find ( gamemap->player[oldcol].buildingList.begin(), gamemap->player[oldcol].buildingList.end(), this );
  127. if ( i != gamemap->player[oldcol].buildingList.end())
  128. gamemap->player[oldcol].buildingList.erase ( i );
  129. gamemap->player[player].buildingList.push_back( this );
  130. color = player * 8;
  131. if ( player < 8 )
  132. addview();
  133. conquered();
  134. anyContainerConquered(this);
  135. }
  136. const Surface& Building :: getPicture ( const BuildingType::LocalCoordinate& localCoordinate ) const
  137. {
  138. static Surface emptySurface;
  139. MapField* fld = getField ( localCoordinate );
  140. if ( fld ) {
  141. return typ->getPicture(localCoordinate, fld->getWeather(), _completion);
  142. } else
  143. return emptySurface;
  144. }
  145. void Building::paintSingleField ( Surface& s, SPoint imgpos, BuildingType::LocalCoordinate pos ) const
  146. {
  147. if ( getHeight() <= chfahrend )
  148. paintField( getPicture( pos ), s, imgpos, 0, false, 0 );
  149. else
  150. paintField( getPicture( pos ), s, imgpos, 0, false );
  151. }
  152. // fucking namespace pollution, we are defining our own...
  153. template<typename T>
  154. T ASC_min ( T a, T b )
  155. {
  156. if ( a > b )
  157. return b;
  158. else
  159. return a;
  160. }
  161. template<typename T>
  162. T ASC_max ( T a, T b )
  163. {
  164. if ( a > b )
  165. return a;
  166. else
  167. return b;
  168. }
  169. Surface Building::getImage() const
  170. {
  171. int minx = maxint;
  172. int maxx = 0;
  173. int maxy = 0;
  174. int miny = maxint;
  175. for ( int x = 0; x < 4; x++ )
  176. for ( int y = 0; y < 6; y++ )
  177. if ( typ->fieldExists(BuildingType::LocalCoordinate(x,y) )) {
  178. SPoint pos ( x * fielddistx + ( y & 1 ) * fielddisthalfx, y * fielddisty);
  179. minx = ASC_min( minx, int(pos.x) );
  180. maxx = ASC_max( maxx, int(pos.x) + fieldsizex );
  181. miny = ASC_min ( miny, int(pos.y) );
  182. maxy = ASC_max ( maxy, int(pos.y) + fieldsizey );
  183. }
  184. Surface s = Surface::createSurface(maxx-minx+1,maxy-miny+1, 32,Surface::transparent << 24 );
  185. typ->paint ( s, SPoint(-minx,-miny), getOwningPlayer().getPlayerColor() );
  186. return s;
  187. }
  188. #ifndef sgmain
  189. void Building :: execnetcontrol ( void ) {}
  190. int Building :: putResource ( int amount, int resourcetype, bool queryonly, int scope, int player ) { return 0; };
  191. int Building :: getResource ( int amount, int resourcetype, bool queryonly, int scope, int player ) { return actstorage.resource(resourcetype); };
  192. int Building :: getAvailableResource ( int amount, int resourcetype, int scope ) const { return actstorage.resource(resourcetype); };
  193. #endif
  194. void Building :: setCompletion ( int completion, bool setupImages )
  195. {
  196. _completion = completion;
  197. }
  198. int Building :: chainbuildingtofield ( const MapCoordinate& entryPos, bool setupImages )
  199. {
  200. MapCoordinate oldpos = entryPosition;
  201. entryPosition = entryPos;
  202. for ( int a = 0; a < 4; a++)
  203. for ( int b = 0; b < 6; b++)
  204. if ( typ->fieldExists ( BuildingType::LocalCoordinate( a, b) )) {
  205. MapField* f = getField( BuildingType::LocalCoordinate( a, b) );
  206. if ( !f || f->building ) {
  207. entryPosition = oldpos;
  208. return 1;
  209. }
  210. }
  211. for ( int a = 0; a < 4; a++)
  212. for ( int b = 0; b < 6; b++)
  213. if ( typ->fieldExists ( BuildingType::LocalCoordinate( a , b ) )) {
  214. MapField* field = getField( BuildingType::LocalCoordinate( a, b) );
  215. if ( visible ) {
  216. MapField::ObjectContainer::iterator i = field->objects.begin();
  217. while ( i != field->objects.end()) {
  218. if ( !i->typ->canExistBeneathBuildings )
  219. i = field->objects.erase ( i );
  220. else
  221. i++;
  222. };
  223. }
  224. if ( field->vehicle && (field->vehicle->height < chtieffliegend )) {
  225. delete field->vehicle;
  226. field->vehicle = NULL;
  227. }
  228. field->building = this;
  229. }
  230. for ( Cargo::iterator i = cargo.begin(); i != cargo.end(); ++i )
  231. if ( *i )
  232. (*i)->setnewposition ( entryPos.x, entryPos.y );
  233. MapField* field = getField( typ->entry );
  234. if ( field )
  235. field->bdt |= getTerrainBitType(cbbuildingentry) ;
  236. if ( setupImages )
  237. gamemap->calculateAllObjects();
  238. for ( int a = 0; a < 4; a++)
  239. for ( int b = 0; b < 6; b++)
  240. if ( typ->fieldExists(BuildingType::LocalCoordinate(a,b))) {
  241. MapCoordinate p = getFieldCoordinates( BuildingType::LocalCoordinate(a,b));
  242. BuildingType::LocalCoordinate lc = getLocalCoordinate(p);
  243. if ( lc.x != a || lc.y!= b )
  244. warningMessage( "bug in building coordinate calculation");
  245. }
  246. return 0;
  247. }
  248. int Building :: unchainbuildingfromfield ( void )
  249. {
  250. int set = 0;
  251. for (int i = 0; i <= 3; i++)
  252. for (int j = 0; j <= 5; j++)
  253. if ( typ->fieldExists ( BuildingType::LocalCoordinate(i,j) ) ) {
  254. MapField* fld = getField( BuildingType::LocalCoordinate(i,j) );
  255. if ( fld && fld->building == this ) {
  256. set = 1;
  257. fld->building = NULL;
  258. TerrainBits t = getTerrainBitType(cbbuildingentry);
  259. t.flip();
  260. fld->bdt &= t;
  261. }
  262. }
  263. return set;
  264. }
  265. void Building :: addview ( void )
  266. {
  267. if ( viewOnMap )
  268. fatalError ("void Building :: addview - the building is already viewing the map");
  269. viewOnMap = true;
  270. tcomputebuildingview bes ( gamemap );
  271. bes.init( this, +1 );
  272. bes.startsearch();
  273. }
  274. void Building :: resetview()
  275. {
  276. viewOnMap = false;
  277. }
  278. void Building :: removeview ( void )
  279. {
  280. if ( color != 64 ) {
  281. if ( !viewOnMap )
  282. fatalError ("void Building :: removeview - the building is not viewing the map");
  283. tcomputebuildingview bes ( gamemap );
  284. bes.init( this, -1 );
  285. bes.startsearch();
  286. viewOnMap = false;
  287. }
  288. }
  289. MapCoordinate3D Building::getPosition3D() const
  290. {
  291. MapCoordinate3D e = getEntry();
  292. MapCoordinate3D p3;
  293. p3.setnum ( e.x, e.y, -1 );
  294. return p3;
  295. }
  296. int Building :: getArmor ( ) const
  297. {
  298. return typ->_armor * gamemap->getgameparameter( cgp_buildingarmor ) / 100;
  299. }
  300. MapField* Building :: getField( const BuildingType::LocalCoordinate& lc ) const
  301. {
  302. return gamemap->getField ( getFieldCoordinates ( lc ));
  303. }
  304. MapField* Building :: getEntryField( ) const
  305. {
  306. return getField ( typ->entry );
  307. }
  308. MapCoordinate3D Building :: getEntry( ) const
  309. {
  310. return MapCoordinate3D( entryPosition, typ->height);
  311. }
  312. MapCoordinate Building :: getFieldCoordinates ( const BuildingType::LocalCoordinate& lc ) const
  313. {
  314. return typ->getFieldCoordinate ( entryPosition, lc );
  315. }
  316. BuildingType::LocalCoordinate Building::getLocalCoordinate( const MapCoordinate& field ) const
  317. {
  318. return typ->getLocalCoordinate( entryPosition, field );
  319. }
  320. Building :: ~Building ()
  321. {
  322. if ( gamemap ) {
  323. int c = color/8;
  324. Player::BuildingList::iterator i = find ( gamemap->player[c].buildingList.begin(), gamemap->player[c].buildingList.end(), this );
  325. if ( i != gamemap->player[c].buildingList.end() )
  326. gamemap->player[c].buildingList.erase ( i );
  327. }
  328. for ( int i = 0; i < 8; ++i ) {
  329. delete aiparam[ i ] ;
  330. aiparam[ i ] = NULL;
  331. }
  332. unchainbuildingfromfield();
  333. }
  334. const int buildingstreamversion = -7;
  335. void Building :: write ( tnstream& stream, bool includeLoadedUnits ) const
  336. {
  337. stream.writeInt ( max( buildingstreamversion, BUILDINGVERSIONLIMIT ));
  338. stream.writeInt ( typ->id );
  339. int i;
  340. for ( i = 0; i< resourceTypeNum; i++ )
  341. stream.writeInt ( bi_resourceplus.resource(i) );
  342. stream.writeChar ( color );
  343. stream.writeWord ( getEntry().x );
  344. stream.writeWord ( getEntry().y );
  345. stream.writeChar ( getCompletion() );
  346. for ( i = 0; i < waffenanzahl; i++ )
  347. stream.writeWord ( 0 ); // was: ammoautoproduction
  348. for ( i = 0; i< resourceTypeNum; i++ )
  349. stream.writeInt ( plus.resource(i) );
  350. for ( i = 0; i< resourceTypeNum; i++ )
  351. stream.writeInt ( maxplus.resource(i) );
  352. for ( i = 0; i< resourceTypeNum; i++ )
  353. stream.writeInt ( actstorage.resource(i) );
  354. for ( i = 0; i< waffenanzahl; i++ )
  355. stream.writeWord ( ammo[i] );
  356. stream.writeWord ( maxresearchpoints );
  357. stream.writeWord ( researchpoints );
  358. stream.writeChar ( visible );
  359. stream.writeChar ( damage );
  360. stream.writeInt ( netcontrol );
  361. stream.writeString ( name );
  362. stream.writeInt ( repairedThisTurn );
  363. int c = 0;
  364. if ( includeLoadedUnits )
  365. for ( Cargo::const_iterator i = cargo.begin(); i != cargo.end(); ++i )
  366. if ( *i )
  367. ++c;
  368. if ( BUILDINGVERSIONLIMIT >= -3 )
  369. stream.writeChar( c );
  370. else
  371. stream.writeInt ( c );
  372. if ( c )
  373. for ( Cargo::const_iterator i = cargo.begin(); i != cargo.end(); ++i )
  374. if ( *i )
  375. (*i)->write ( stream );
  376. if ( BUILDINGVERSIONLIMIT >= -4 )
  377. stream.writeChar( internalUnitProduction.size() );
  378. else
  379. stream.writeInt( internalUnitProduction.size() );
  380. for (int k = 0; k < internalUnitProduction.size(); k++ ) {
  381. assert( internalUnitProduction[k] );
  382. stream.writeInt( internalUnitProduction[k]->id );
  383. }
  384. if ( BUILDINGVERSIONLIMIT >= -3 )
  385. stream.writeChar(0);
  386. stream.writeInt( view );
  387. stream.writeString( privateName );
  388. }
  389. Building* Building::newFromStream ( GameMap* gamemap, tnstream& stream, bool chainToField )
  390. {
  391. int version = stream.readInt();
  392. int xpos, ypos, color;
  393. Resources res;
  394. BuildingType* typ;
  395. if ( version < buildingstreamversion )
  396. throw tinvalidversion( stream.getDeviceName(), buildingstreamversion, version );
  397. if ( version >= buildingstreamversion && version <= -1 ) {
  398. int id = stream.readInt ();
  399. typ = gamemap->getbuildingtype_byid ( id );
  400. if ( !typ )
  401. throw InvalidID ( "building", id );
  402. for ( int i = 0; i < 3; i++ )
  403. res.resource(i) = stream.readInt();
  404. color = stream.readChar();
  405. xpos = stream.readWord() ;
  406. } else {
  407. int id = version;
  408. typ = gamemap->getbuildingtype_byid ( id );
  409. if ( !typ )
  410. throw InvalidID ( "building", id );
  411. color = stream.readChar();
  412. xpos = stream.readWord();
  413. }
  414. ypos = stream.readWord();
  415. Building* bld = new Building ( gamemap, MapCoordinate(xpos,ypos), typ, color/8, false, chainToField );
  416. bld->bi_resourceplus = res;
  417. bld->readData ( stream, version );
  418. return bld;
  419. }
  420. void Building:: read ( tnstream& stream )
  421. {
  422. int version = stream.readInt();
  423. if ( version >= buildingstreamversion && version <= -1 ) {
  424. stream.readInt (); // id
  425. for ( int i = 0; i < 3; i++ )
  426. bi_resourceplus.resource(i) = stream.readInt();
  427. stream.readChar(); // color
  428. stream.readWord(); // xpos
  429. stream.readWord(); // ypos
  430. } else {
  431. // int id = version;
  432. stream.readChar(); // color
  433. stream.readWord(); // xpos
  434. stream.readWord(); // ypos
  435. bi_resourceplus = Resources ( 0, 0, 0);
  436. }
  437. readData ( stream, version );
  438. }
  439. void Building :: readData ( tnstream& stream, int version )
  440. {
  441. setCompletion ( stream.readChar(), false );
  442. int i;
  443. for ( i = 0; i < waffenanzahl; i++)
  444. stream.readWord(); // was : ammoautoproduction
  445. for ( i = 0; i< 3; i++ )
  446. plus.resource(i) = stream.readInt();
  447. for ( i = 0; i< 3; i++ )
  448. maxplus.resource(i) = stream.readInt();
  449. for ( i = 0; i< 3; i++ )
  450. actstorage.resource(i) = min(stream.readInt(), getStorageCapacity().resource(i) );
  451. for ( i = 0; i < waffenanzahl; i++)
  452. ammo[i] = stream.readWord();
  453. maxresearchpoints = stream.readWord();
  454. researchpoints = stream.readWord();
  455. if ( (researchpoints < typ->maxresearchpoints && !typ->hasFunction(ContainerBaseType::Research)) || (researchpoints > typ->maxresearchpoints))
  456. researchpoints = typ->maxresearchpoints;
  457. visible = stream.readChar();
  458. damage = stream.readChar();
  459. netcontrol = stream.readInt();
  460. netcontrol = 0;
  461. name = stream.readString ();
  462. if ( version <= -2 )
  463. repairedThisTurn = stream.readInt ( );
  464. else
  465. repairedThisTurn = 0;
  466. int c;
  467. if ( version <= -4 )
  468. c = stream.readInt();
  469. else
  470. c = stream.readChar();
  471. if ( c ) {
  472. for ( int k = 0; k < c; k++) {
  473. Vehicle* v = Vehicle::newFromStream ( gamemap, stream );
  474. v->setnewposition ( getEntry().x, getEntry().y );
  475. addToCargo(v);
  476. if ( v && v->reactionfire.getStatus() != Vehicle::ReactionFire::off && !v->baseType->hasFunction( ContainerBaseType::MoveWithReactionFire ))
  477. v->reactionfire.disable();
  478. }
  479. }
  480. internalUnitProduction.clear();
  481. if ( version <= -5 )
  482. c = stream.readInt();
  483. else
  484. c = stream.readChar();
  485. if ( c ) {
  486. for ( int k = 0; k < c ; k++) {
  487. int id;
  488. if ( version <= -3 )
  489. id = stream.readInt();
  490. else
  491. id = stream.readWord();
  492. internalUnitProduction.push_back ( gamemap->getvehicletype_byid ( id ) );
  493. if ( !internalUnitProduction[k] )
  494. throw InvalidID ( "unit", id );
  495. }
  496. }
  497. if ( version >= -3 ) {
  498. c = stream.readChar();
  499. if ( c ) {
  500. for ( int k = 0; k < c ; k++) {
  501. if ( version <= -3 )
  502. stream.readInt();
  503. else
  504. stream.readWord();
  505. }
  506. }
  507. }
  508. for ( i = 0; i< 3; i++ ) {
  509. if ( typ->maxplus.resource(i) > 0 ) {
  510. if ( plus.resource(i) > typ->maxplus.resource(i) )
  511. plus.resource(i) = typ->maxplus.resource(i);
  512. if ( maxplus.resource(i) > typ->maxplus.resource(i) )
  513. maxplus.resource(i) = typ->maxplus.resource(i);
  514. } else {
  515. if ( plus.resource(i) < typ->maxplus.resource(i) )
  516. plus.resource(i) = typ->maxplus.resource(i);
  517. if ( maxplus.resource(i) < typ->maxplus.resource(i) )
  518. maxplus.resource(i) = typ->maxplus.resource(i);
  519. }
  520. }
  521. if ( version <= -6 )
  522. view = stream.readInt();
  523. else
  524. view = typ->view;
  525. if ( version <= -7 )
  526. privateName = stream.readString();
  527. else
  528. privateName = "";
  529. }
  530. ASCString Building::getName ( ) const
  531. {
  532. if ( name.empty())
  533. return typ->name;
  534. else
  535. return name;
  536. }
  537. int Building::getAmmo( int type, int num, bool queryOnly )
  538. {
  539. assert( type >= 0 && type < waffenanzahl );
  540. int got = min( ammo[type], num );
  541. if ( !queryOnly ) {
  542. ammo[type] -= got;
  543. // ammoChanged();
  544. }
  545. return got;
  546. }
  547. int Building::getAmmo( int type, int num ) const
  548. {
  549. assert( type >= 0 && type < waffenanzahl );
  550. return min( ammo[type], num );
  551. }
  552. int Building::putAmmo( int type, int num, bool queryOnly )
  553. {
  554. assert( type >= 0 && type < waffenanzahl );
  555. if ( !queryOnly ) {
  556. ammo[type] += num;
  557. // ammoChanged();
  558. }
  559. return num;
  560. }
  561. void Building::endRound( )
  562. {
  563. ContainerBase::endRound();
  564. repairedThisTurn = 0;
  565. }
  566. vector<MapCoordinate> Building::getCoveredFields()
  567. {
  568. vector<MapCoordinate> fields;
  569. for ( int x = 0; x < 4; x++ )
  570. for ( int y = 0; y < 6; y++)
  571. if ( typ->fieldExists ( BuildingType::LocalCoordinate(x, y) ) )
  572. fields.push_back ( getFieldCoordinates( BuildingType::LocalCoordinate(x, y)));
  573. return fields;
  574. }
  575. int Building::getMemoryFootprint() const
  576. {
  577. return sizeof(*this);
  578. }
  579. /*
  580. void Building :: getresourceusage ( Resources* usage )
  581. {
  582. returnresourcenuseforpowerplant ( this, 100, usage, 0 );
  583. if ( typ->special & cgresearchb ) {
  584. int material;
  585. int energy;
  586. returnresourcenuseforresearch ( this, researchpoints, &energy, &material );
  587. usage->material += material;
  588. usage->energy += energy;
  589. usage->fuel = 0;
  590. }
  591. }
  592. */
  593. struct ResearchEfficiency {
  594. float eff;
  595. Building* bld;
  596. bool operator<( const ResearchEfficiency& re) const { return eff > re.eff; };
  597. };
  598. void doresearch ( GameMap* actmap, int player )
  599. {
  600. Research& research = actmap->getPlayer(player).research;
  601. if ( research.activetechnology == NULL && research.progress ) {
  602. // we don't accumulate research if there is not technology to research
  603. // this is to prevent player from accumulating lots of unused research points and then
  604. // developing several technologies at once
  605. return;
  606. }
  607. typedef vector<ResearchEfficiency> VRE;
  608. VRE vre;
  609. for ( Player::BuildingList::iterator bi = actmap->player[player].buildingList.begin(); bi != actmap->player[player].buildingList.end(); bi++ ) {
  610. Building* bld = *bi;
  611. if ( bld->typ->hasFunction( ContainerBaseType::Research ) ) {
  612. Resources res = returnResourcenUseForResearch ( bld, bld->researchpoints );
  613. int m = max ( res.energy, max ( res.material, res.fuel));
  614. ResearchEfficiency re;
  615. if ( m )
  616. re.eff = float(bld->researchpoints) / float(m);
  617. else
  618. re.eff = maxint;
  619. re.bld = bld;
  620. vre.push_back(re);
  621. } else
  622. if ( bld->researchpoints > 0 )
  623. research.progress += bld->researchpoints * research.getMultiplier();
  624. }
  625. sort( vre.begin(), vre.end());
  626. for ( VRE::iterator i = vre.begin(); i != vre.end(); ++i ) {
  627. Building* bld = i->bld;
  628. Resources r = returnResourcenUseForResearch ( bld, bld->researchpoints );
  629. Resources got = bld->getResource ( r, true, 1, player );
  630. int res = bld->researchpoints;
  631. if ( got < r ) {
  632. int diff = bld->researchpoints / 2;
  633. while ( got < r || diff > 1) {
  634. if ( got < r )
  635. res -= diff;
  636. else
  637. res += diff;
  638. if ( res < 0 )
  639. res = 0;
  640. if ( diff > 1 )
  641. diff /=2;
  642. else
  643. diff = 1;
  644. r = returnResourcenUseForResearch ( bld, res );
  645. }
  646. /*
  647. res = returnResourcenUseForResearch ( bld, res+1 );
  648. if ( ena >= energy && maa >= material )
  649. res++;
  650. else
  651. returnresourcenuseforresearch ( bld, res, &energy, &material );
  652. */
  653. }
  654. got = bld->getResource ( r, false, 1, player );
  655. if ( got < r )
  656. fatalError( "controls : doresearch : inconsistency in getting energy or material for building" );
  657. research.progress += res * research.getMultiplier();
  658. }
  659. }
  660. ASCString getBuildingReference ( Building* bld )
  661. {
  662. ASCString s = "The building " + bld->getName();
  663. s += " (position: "+ bld->getPosition().toString() + ") ";
  664. return s;
  665. }