00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <algorithm>
00011 #include <cmath>
00012 #include "containerbase-functions.h"
00013 #include "typen.h"
00014 #include "containercontrols.h"
00015 #include "resourcenet.h"
00016 #include <iostream>
00017
00018
00019
00020 template <class T, ContainerBaseType::ContainerFunctions f>
00021 class GenericWorkerFactory : public ContainerBase::WorkClassFactory
00022 {
00023 bool available( const ContainerBase* cnt )
00024 {
00025 return cnt->baseType->hasFunction( f );
00026 };
00027
00028 ContainerBase::Work* produce( ContainerBase* cnt, bool queryOnly )
00029 {
00030 return new T(cnt);
00031 };
00032 };
00033
00034
00035 class BiResourceGenerationFactory : public ContainerBase::WorkClassFactory
00036 {
00037 bool available( const ContainerBase* cnt )
00038 {
00039 return true;
00040 };
00041
00042 ContainerBase::Work* produce( ContainerBase* cnt, bool queryOnly )
00043 {
00044 return new BiResourceGeneration(cnt);
00045 };
00046 };
00047
00048 class MiningStationFactory : public ContainerBase::WorkClassFactory
00049 {
00050 bool available( const ContainerBase* cnt )
00051 {
00052 return cnt->baseType->hasFunction( ContainerBaseType::MiningStation );
00053 };
00054
00055 ContainerBase::Work* produce( ContainerBase* cnt, bool queryOnly )
00056 {
00057 return new MiningStation(cnt, queryOnly);
00058 };
00059 };
00060
00061 class AutoHarvestObjectsFactory : public ContainerBase::WorkClassFactory
00062 {
00063 bool available( const ContainerBase* cnt )
00064 {
00065 return cnt->baseType->hasFunction( ContainerBaseType::AutoHarvestObjects );
00066 };
00067
00068 ContainerBase::Work* produce( ContainerBase* cnt, bool queryOnly )
00069 {
00070 return new AutoHarvestObjects(cnt, queryOnly);
00071 };
00072 };
00073
00074 namespace
00075 {
00076 const bool r5 = ContainerBase::registerWorkClassFactory( new BiResourceGenerationFactory, false );
00077 const bool r1 = ContainerBase::registerWorkClassFactory( new GenericWorkerFactory<MatterConverter, ContainerBaseType::MatterConverter>() );
00078 const bool r2 = ContainerBase::registerWorkClassFactory( new GenericWorkerFactory<ResourceSink, ContainerBaseType::ResourceSink> );
00079 const bool r3 = ContainerBase::registerWorkClassFactory( new GenericWorkerFactory<WindPowerplant, ContainerBaseType::WindPowerPlant> );
00080 const bool r4 = ContainerBase::registerWorkClassFactory( new GenericWorkerFactory<SolarPowerplant, ContainerBaseType::SolarPowerPlant> );
00081 const bool r6 = ContainerBase::registerWorkClassFactory( new MiningStationFactory );
00082 const bool r7 = ContainerBase::registerWorkClassFactory( new AutoHarvestObjectsFactory );
00083 }
00084
00085 AutoHarvestObjects::AutoHarvestObjects( ContainerBase* _bld, bool justQuery_ )
00086 {
00087 base = _bld;
00088 justQuery = justQuery_;
00089 hasRun = false;
00090 fieldCounter = 0;
00091 }
00092
00093 bool AutoHarvestObjects::finished()
00094 {
00095 return hasRun;
00096 }
00097
00098
00099 void AutoHarvestObjects::harvestObject( const MapCoordinate& pos, const ObjectType* obj )
00100 {
00101 tfield* currentField = base->getMap()->getField(pos);
00102 if ( !currentField )
00103 return;
00104
00105
00106
00107
00108 int regrowFields = 0;
00109 int spreadingFields = 0;
00110 for ( int i = 0; i < 6; ++i ) {
00111 MapCoordinate nextField = getNeighbouringFieldCoordinate( pos, i );
00112 if ( !harvestOnPosition(nextField)) {
00113 tfield* fld = base->getMap()->getField( nextField);
00114 if ( fld ) {
00115 if ( fld->checkforobject(obj))
00116 ++regrowFields ;
00117 else {
00118 if ( obj->buildable(fld))
00119 ++spreadingFields;
00120 }
00121 }
00122 }
00123 }
00124 if ( regrowFields <= 0 || spreadingFields > 0 )
00125 return;
00126
00127
00128 Object* object = currentField->checkforobject( obj );
00129
00130 if( object != NULL ) {
00131 Resources removeValue = object->typ->removecost;
00132 Resources removeCost;
00133 Resources removeBenefit;
00134
00135 if( removeValue.energy < 0 )
00136 removeBenefit.energy = -removeValue.energy;
00137 else
00138 removeCost.energy = removeValue.energy;
00139
00140 if( removeValue.material < 0 )
00141 removeBenefit.material = -removeValue.material;
00142 else
00143 removeCost.material = removeValue.material;
00144
00145 if( removeValue.fuel < 0 )
00146 removeBenefit.fuel = -removeValue.fuel;
00147 else
00148 removeCost.fuel = removeValue.fuel;
00149
00150 if( base->getResource( removeCost, true, 1, base->getOwner() ) == removeCost ) {
00151 cost += removeCost;
00152 harvested += removeBenefit;
00153 if( !justQuery ) {
00154 base->getResource( removeCost, false, 1, base->getOwner());
00155 base->putResource( removeBenefit, false, 1, base->getOwner() );
00156 currentField->removeobject( obj, true );
00157 }
00158 ++fieldCounter;
00159 }
00160 }
00161 }
00162
00163 void AutoHarvestObjects::processField( const MapCoordinate& pos )
00164 {
00165 tfield* currentField = base->getMap()->getField(pos);
00166 if ( !currentField )
00167 return;
00168
00169 if ( currentField->building )
00170 return;
00171
00172 if ( fieldCounter >= base->baseType->autoHarvest.maxFieldsPerTurn )
00173 return;
00174
00175 for ( vector<IntRange>::const_iterator i = base->baseType->autoHarvest.objectsHarvestable.begin(); i != base->baseType->autoHarvest.objectsHarvestable.end(); ++i )
00176 for( int id=i->from; id <= i->to; ++id ) {
00177 const ObjectType *obj = base->getMap()->getobjecttype_byid( id );
00178 if ( obj )
00179 harvestObject( pos, obj );
00180 }
00181
00182 for ( vector<IntRange>::const_iterator i = base->baseType->autoHarvest.objectGroupsHarvestable.begin(); i != base->baseType->autoHarvest.objectGroupsHarvestable.end(); ++i )
00183 for( int j = 0; j < base->getMap()->getObjectTypeNum(); ++j ) {
00184 const ObjectType *obj = base->getMap()->getobjecttype_bypos( j );
00185 if ( obj->groupID >= i->from && obj->groupID <= i->to )
00186 harvestObject( pos, obj );
00187 }
00188
00189 }
00190
00191
00192
00193 bool AutoHarvestObjects::harvestOnPosition( const MapCoordinate& pos )
00194 {
00195 if ((pos.y+1)%3)
00196 return true;
00197 else
00198 return false;
00199 }
00200
00201 void AutoHarvestObjects::iterateField( const MapCoordinate& pos )
00202 {
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214 if ( harvestOnPosition(pos ) )
00215
00216 processField(pos);
00217
00218 }
00219
00220
00221
00222
00223 bool AutoHarvestObjects::run()
00224 {
00225 hasRun = true;
00226 if( base->getCarrier() != NULL )
00227 return false;
00228
00229 circularFieldIterator( base->getMap(), base->getPosition(), 0, base->baseType->autoHarvest.range, FieldIterationFunctor( this, &AutoHarvestObjects::iterateField ));
00230
00231 return true;
00232 }
00233
00234 Resources AutoHarvestObjects::getPlus()
00235 {
00236 return harvested;
00237 }
00238
00239 Resources AutoHarvestObjects::getUsage()
00240 {
00241 return Resources();
00242 }
00243
00244
00245 float getminingstationeficency ( int dist )
00246 {
00247
00248
00249 double a,b,c,d;
00250
00251 a = 10426.400 ;
00252 b = 1.0710969 ;
00253 c = 568.88887 ;
00254 d = 6.1111109 ;
00255
00256 return (a / ( b * (dist + d)) - c) / 1024;
00257 }
00258
00259
00260 GetMiningInfo::MiningInfo::MiningInfo()
00261 {
00262 for ( int i = 0; i < maxminingrange+2; i++ )
00263 efficiency[i] = 0;
00264 nextMiningDistance = -1;
00265 }
00266
00267 GetMiningInfo :: GetMiningInfo ( const ContainerBase* container ) : SearchFields ( container->getMap() ), miningStation( container )
00268 {
00269 run();
00270 }
00271
00272 void GetMiningInfo :: testfield ( const MapCoordinate& mc )
00273 {
00274 tfield* fld = gamemap->getField ( mc );
00275 if ( miningInfo.efficiency[ dist ] == 0 )
00276 miningInfo.efficiency[ dist ] = int(getminingstationeficency ( dist ) * 1024);
00277
00278 miningInfo.avail[dist].material += fld->material * resource_material_factor;
00279 miningInfo.avail[dist].fuel += fld->fuel * resource_fuel_factor;
00280 miningInfo.max[dist].material += 255 * resource_material_factor;
00281 miningInfo.max[dist].fuel += 255 * resource_fuel_factor;
00282 if ( miningInfo.nextMiningDistance == -1 ) {
00283 if ( miningStation->maxplus.fuel > 0 && fld->fuel > 0 )
00284 miningInfo.nextMiningDistance = dist;
00285
00286 if ( miningStation->maxplus.material > 0 && fld->material > 0 )
00287 miningInfo.nextMiningDistance = dist;
00288 }
00289 }
00290
00291
00292 void GetMiningInfo :: run ()
00293 {
00294 initsearch ( miningStation->getPosition(), 0, maxminingrange );
00295 startsearch();
00296 }
00297
00298
00299
00300
00301 MatterConverter :: MatterConverter( ContainerBase* _bld ) : bld ( _bld ), percentage ( 100 )
00302 {}
00303
00304 bool MatterConverter :: run()
00305 {
00306 int perc = percentage;
00307
00308 int usageNum = 0;
00309 for ( int r = 0; r < 3; r++ )
00310 if ( bld->plus.resource(r) < 0 )
00311 ++usageNum;
00312
00313 if ( usageNum > 0 ) {
00314
00315
00316
00317 for ( int r = 0; r < 3; r++ )
00318 if ( bld->plus.resource(r) > 0 ) {
00319 int p = bld->putResource ( bld->plus.resource(r), r, true, 1, bld->getOwner() );
00320
00321 if ( perc > 100 * p / bld->plus.resource(r) )
00322 perc = 100 * p / bld->plus.resource(r) ;
00323 }
00324 }
00325
00326 Resources toGet = bld->plus * perc / 100 ;
00327 for ( int r = 0; r < 3; r++ )
00328 if ( toGet.resource(r) < 0 )
00329 toGet.resource(r) = - toGet.resource(r) ;
00330 else
00331 toGet.resource(r) = 0;
00332
00333
00334 Resources avail = bld->getResource ( toGet, true, 1, bld->getOwner() );
00335
00336 for ( int r = 0; r < 3; r++ ) {
00337 if ( bld->plus.resource(r) < 0 ) {
00338 int p = 100 * avail.resource(r) / -bld->plus.resource(r);
00339 if ( p < perc )
00340 perc = p;
00341 }
00342 }
00343
00344
00345 bool didSomething = false;
00346
00347 for ( int r = 0; r < 3; r++ )
00348 if ( bld->plus.resource(r) > 0 ) {
00349 bld->putResource( bld->plus.resource(r) * perc / 100, r , false, 1, bld->getOwner() );
00350 if ( bld->plus.resource(r) * perc / 100 > 0)
00351 didSomething = true;
00352
00353 } else {
00354 if ( bld->plus.resource(r) < 0 )
00355 bld->getResource( -bld->plus.resource(r) * perc / 100, r , false, 1, bld->getOwner());
00356 }
00357
00358 percentage -= perc;
00359 return didSomething;
00360 }
00361
00362
00363 bool MatterConverter :: finished()
00364 {
00365 return percentage == 0;
00366 }
00367
00368 Resources MatterConverter :: getPlus()
00369 {
00370 Resources r;
00371 for ( int i = 0; i < 3; i++ )
00372 if ( bld->plus.resource(i) > 0 )
00373 r.resource(i) = bld->plus.resource(i);
00374 return r;
00375 }
00376
00377 Resources MatterConverter :: getUsage()
00378 {
00379 Resources r;
00380 for ( int i = 0; i < 3; i++ )
00381 if ( bld->plus.resource(i) < 0 )
00382 r.resource(i) = -bld->plus.resource(i);
00383 return r;
00384 }
00385
00386
00387 ResourceSink :: ResourceSink( ContainerBase* _bld ) : bld ( _bld )
00388 {
00389 toGet = bld->plus;
00390 for ( int r = 0; r < 3; r++ )
00391 if ( toGet.resource(r) < 0 )
00392 toGet.resource(r) = - toGet.resource(r) ;
00393 else
00394 toGet.resource(r) = 0;
00395 }
00396
00397 bool ResourceSink :: run()
00398 {
00399 Resources got = bld->getResource( toGet, false, 1, bld->getOwner() );
00400 toGet -= got;
00401 for ( int r = 0; r < 3; r++ )
00402 if ( got.resource(r) > 0 )
00403 return true;
00404
00405 return false;
00406 }
00407
00408
00409 bool ResourceSink :: finished()
00410 {
00411 for ( int r = 0; r < 3; r++ )
00412 if ( toGet.resource(r) > 0 )
00413 return false;
00414 return true;
00415 }
00416
00417 Resources ResourceSink :: getPlus()
00418 {
00419 return Resources();
00420 }
00421
00422 Resources ResourceSink :: getUsage()
00423 {
00424 Resources r;
00425 for ( int i = 0; i < 3; i++ )
00426 if ( bld->plus.resource(i) < 0 )
00427 r.resource(i) = -bld->plus.resource(i);
00428 return r;
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510 RegenerativePowerPlant :: RegenerativePowerPlant( ContainerBase* _bld ) : bld ( _bld )
00511 {}
00512
00513 bool RegenerativePowerPlant :: finished()
00514 {
00515 for( int r = 0; r < 3; r++ )
00516 if ( toProduce.resource(r) > 0 )
00517 return false;
00518 return true;
00519 }
00520
00521 bool RegenerativePowerPlant :: run()
00522 {
00523 Resources tp = bld->putResource( toProduce , false, 1, bld->getOwner() );
00524 bool didSomething = false;
00525 for ( int r = 0; r < 3; r++ )
00526 if ( tp.resource(r) ) {
00527 didSomething = true;
00528 toProduce.resource(r) -= tp.resource(r);
00529 }
00530 return didSomething;
00531 }
00532
00533 Resources RegenerativePowerPlant :: getUsage()
00534 {
00535 return Resources();
00536 }
00537
00538 Resources WindPowerplant :: getPlus()
00539 {
00540 Resources p;
00541 for ( int r = 0; r < 3; r++ )
00542 p.resource(r) = bld->maxplus.resource(r) * bld->getMap()->weather.windSpeed / 255;
00543 return p;
00544 }
00545
00546 Resources SolarPowerplant :: getPlus()
00547 {
00548 int sum = 0;
00549 int num = 0;
00550 vector<MapCoordinate> fields = bld->getCoveredFields();
00551 for ( vector<MapCoordinate>::iterator i = fields.begin(); i != fields.end(); ++i ) {
00552 tfield* fld = bld->getMap()->getField ( *i );
00553 int weather = 0;
00554 while ( fld->typ != fld->typ->terraintype->weather[weather] )
00555 weather++;
00556
00557 sum += csolarkraftwerkleistung[weather];
00558 num ++;
00559 }
00560
00561 Resources rplus;
00562 for ( int r = 0; r < 3; r++ )
00563 rplus.resource(r) = bld->maxplus.resource(r) * sum / ( num * 1024 );
00564 return rplus;
00565 }
00566
00567
00568 Resources BiResourceGeneration::getPlus()
00569 {
00570 return bld->bi_resourceplus;
00571 }
00572
00573
00574
00575
00576 MiningStation :: MiningStation( ContainerBase* bld_ , bool justQuery_) : SearchFields ( bld_->getMap() ), bld ( bld_ ), justQuery( justQuery_ )
00577 {
00578 int counter = 0;
00579 for ( int r = 1; r < 3; r++ ) {
00580 if ( bld->plus.resource(r) > 0 ) {
00581 ++counter;
00582 if ( counter == 2 )
00583 fatalError( ASCString("A mining station can only produce ONE kind of resource; building ID" ) + strrr(bld->baseType->id) + " is violating this" );
00584
00585 toExtract_thisTurn.resource(r) = bld->plus.resource(r);
00586
00587 for ( int rr = 0; rr < 3; rr++ )
00588 if ( bld->plus.resource(rr) < 0 )
00589 usageRatio[rr] = -double(bld->plus.resource(rr)) / double(bld->plus.resource(r));
00590 else
00591 usageRatio[rr] = 0;
00592 }
00593 }
00594
00595 if( justQuery ) {
00596 hasRun = false;
00597 run();
00598 hasRun = true;
00599 } else
00600 hasRun = false;
00601 }
00602
00603 bool MiningStation :: run()
00604 {
00605 if ( justQuery && hasRun )
00606 return false;
00607
00608 actuallyExtracted = Resources();
00609
00610 for ( int r = 0; r < 3;++r)
00611 consumed[r] = 0;
00612
00613 if ( !justQuery ) {
00614 spaceAvail = bld->putResource( toExtract_thisTurn, true, 1, bld->getOwner() );
00615 for ( int r = 0; r <3; ++r )
00616 if ( spaceAvail.resource(r) < 0 ) {
00617 warning( ASCString("map corruption detected; building space availability is negative! ") + resourceNames[r] );
00618 spaceAvail.resource( r ) = 0;
00619 }
00620 } else
00621 spaceAvail = toExtract_thisTurn;
00622
00623 Resources toConsume;
00624 for ( int r = 0; r < 3; r++ )
00625 if ( bld->plus.resource(r) < 0 )
00626 toConsume.resource(r) = -bld->plus.resource(r);
00627
00628 if ( !justQuery ) {
00629 powerAvail = bld->getResource( toConsume, true, 1, bld->getOwner() );
00630 for ( int r = 0; r <3; ++r )
00631 if ( powerAvail.resource(r) < 0 ) {
00632 warning( ASCString("map corruption detected; available power for mining station is negative! ") + resourceNames[r] );
00633 powerAvail.resource( r ) = 0;
00634 }
00635 } else
00636 powerAvail = toConsume;
00637
00638
00639 initsearch( bld->getPosition(), 0, maxminingrange );
00640 startsearch();
00641
00642 if ( !justQuery) {
00643 for ( int r = 0; r < 3; ++r )
00644 bld->getResource( int(consumed[r]), r, false, 1, bld->getOwner() );
00645 bld->putResource(actuallyExtracted, false, 1, bld->getOwner() );
00646 }
00647
00648 for ( int r = 0; r < 3; r++ )
00649 if ( actuallyExtracted.resource(r) > 0 )
00650 return true;
00651
00652 return false;
00653 }
00654
00655 void MiningStation :: testfield ( const MapCoordinate& mc )
00656 {
00657 cancelSearch = true;
00658 for ( int r = 0; r < 3; r++ )
00659 if ( toExtract_thisTurn.resource(r) > 0 )
00660 cancelSearch = false;
00661
00662 if ( cancelSearch == false ) {
00663 tfield* fld = gamemap->getField ( mc );
00664 float distEfficiency = getminingstationeficency ( dist );
00665
00666 for ( int r = 1; r < 3; r++ ) {
00667 if ( toExtract_thisTurn.resource(r) > 0 ) {
00668
00669 float resourceFactor;
00670 char *fieldResource;
00671
00672 if ( r==1) {
00673
00674 resourceFactor = resource_material_factor;
00675 fieldResource = &fld->material;
00676 } else {
00677
00678 resourceFactor = resource_fuel_factor;
00679 fieldResource = &fld->fuel;
00680 }
00681
00682 float perc = 1;
00683
00684
00685 perc = min ( perc, (*fieldResource * resourceFactor) / (toExtract_thisTurn.resource(r) * distEfficiency));
00686
00687 perc = min ( perc, float( double(spaceAvail.resource(r)) / (toExtract_thisTurn.resource(r) * distEfficiency )));
00688
00689 for ( int i = 0; i < 3; ++i )
00690 if ( usageRatio[i] * toExtract_thisTurn.resource(r) > 0 )
00691 perc = min ( perc, float( double(powerAvail.resource(i)) / usageRatio[i] * toExtract_thisTurn.resource(r)));
00692
00693 if ( perc < 0 ) {
00694 warning("Warning: mining station inconsistency\n");
00695 perc = 0;
00696 }
00697
00698 if ( !justQuery )
00699 *fieldResource -= int( toExtract_thisTurn.resource(r) * perc * distEfficiency / resourceFactor );
00700
00701 int ex = int( ceil(toExtract_thisTurn.resource(r) * perc * distEfficiency));
00702 actuallyExtracted.resource(r) += ex;
00703 spaceAvail.resource(r) -= ex;
00704 for ( int i = 0; i < 3; ++i) {
00705 if ( spaceAvail.resource(i) < -2 )
00706 warning("Warning: mining station inconsistency 2!\n");
00707
00708 if ( spaceAvail.resource(i) < 0 )
00709 spaceAvail.resource(i) = 0;
00710 }
00711
00712
00713 for ( int i = 0; i < 3; i++ ) {
00714 float c = usageRatio[i] * toExtract_thisTurn.resource(r) * perc;
00715 consumed[i] += c;
00716 powerAvail.resource(i) -= int( ceil(c) );
00717 if ( powerAvail.resource(i) < 0 )
00718 powerAvail.resource(i) = 0;
00719
00720 }
00721
00722 toExtract_thisTurn.resource(r) -= int( toExtract_thisTurn.resource(r) * perc);
00723
00724
00725 if ( !justQuery ) {
00726 if ( !fld->resourceview )
00727 fld->resourceview = new tfield::Resourceview;
00728 fld->resourceview->visible |= 1 << bld->getOwner();
00729 fld->resourceview->fuelvisible[bld->getOwner()] = fld->fuel;
00730 fld->resourceview->materialvisible[bld->getOwner()] = fld->material;
00731 }
00732 }
00733 }
00734 }
00735 }
00736
00737 bool MiningStation :: finished()
00738 {
00739 for ( int r = 0; r < 3; r++ )
00740 if ( toExtract_thisTurn.resource(r) )
00741 return false;
00742 return true;
00743 }
00744
00745 Resources MiningStation :: getPlus()
00746 {
00747 return actuallyExtracted;
00748 }
00749
00750 Resources MiningStation :: getUsage()
00751 {
00752 Resources res;
00753 for ( int r = 0; r < 3; ++r)
00754 res.resource(r) = int( ceil(consumed[r]));
00755 return res;
00756 }
00757