00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <iostream>
00019 #include "ai_common.h"
00020 #include "../actions/attackcommand.h"
00021 #include "../actions/moveunitcommand.h"
00022
00023 const int value_armorfactor = 100;
00024 const int value_weaponfactor = 3000;
00025
00026 const int ccbt_repairfacility = 200;
00027 const int ccbt_hq = 10000;
00028 const int ccbt_recycling = 50;
00029 const int ccbt_training = 150;
00030
00031
00032
00033
00034
00035 class CalculateThreat_VehicleType {
00036 protected:
00037 AI* ai;
00038
00039 const VehicleType* fzt;
00040 int weapthreat[8];
00041 int value;
00042
00043 virtual int getdamage ( void ) { return 0; };
00044 virtual int getexpirience ( void ) { return 0; };
00045 virtual int getammunition( int i ) { return 1; };
00046 virtual int getheight ( void ) { return 255; };
00047 public:
00048 void calc_threat_vehicletype ( const VehicleType* _fzt );
00049 CalculateThreat_VehicleType ( AI* _ai ) { ai = _ai; };
00050 virtual ~CalculateThreat_VehicleType() {};
00051 };
00052
00053 class CalculateThreat_Vehicle : public CalculateThreat_VehicleType {
00054 protected:
00055 Vehicle* eht;
00056 virtual int getdamage ( void );
00057 virtual int getexpirience ( void );
00058 virtual int getammunition( int i );
00059 virtual int getheight ( void );
00060 public:
00061 void calc_threat_vehicle ( Vehicle* _eht );
00062 CalculateThreat_Vehicle ( AI* _ai ) : CalculateThreat_VehicleType ( _ai ) {};
00063 };
00064
00065
00066 void CalculateThreat_VehicleType :: calc_threat_vehicletype ( const VehicleType* _fzt )
00067 {
00068 fzt = _fzt;
00069
00070 for ( int j = 0; j < 8; j++ )
00071 weapthreat[j] = 0;
00072
00073 for ( int i = 0; i < fzt->weapons.count; i++)
00074 if ( fzt->weapons.weapon[i].shootable() )
00075 if ( fzt->weapons.weapon[i].offensive() )
00076 for ( int j = 0; j < 8; j++)
00077 if ( fzt->weapons.weapon[i].targ & (1 << j) ) {
00078 int d = 0;
00079 int m = 0;
00080 AttackFormula af( ai->getMap() );
00081 for ( int e = (fzt->weapons.weapon[i].mindistance + maxmalq - 1)/ maxmalq; e <= fzt->weapons.weapon[i].maxdistance / maxmalq; e++ ) {
00082 d++;
00083 int n = int( WeapDist::getWeaponStrength( &fzt->weapons.weapon[i], 0, e*maxmalq ) * fzt->weapons.weapon[i].maxstrength * af.strength_damage(getdamage()) * ( 1 + af.strength_experience(getexpirience())) );
00084 m += int( n / log10(double(10*d)));
00085 }
00086 if (getammunition(i) == 0)
00087 m /= 2;
00088
00089 if ( (fzt->weapons.weapon[i].sourceheight & getheight()) == 0)
00090 m /= 2;
00091
00092
00093
00094
00095
00096
00097 if (m > weapthreat[j])
00098 weapthreat[j] = m;
00099 }
00100
00101
00102 if ( !fzt->aiparam[ai->getPlayerNum()] )
00103 fzt->aiparam[ ai->getPlayerNum() ] = new AiValue ( getFirstBit ( fzt->height ));
00104
00105 for ( int l = 0; l < 8; l++ )
00106 fzt->aiparam[ ai->getPlayerNum() ]->threat.threat[l] = weapthreat[l];
00107
00108 value = fzt->armor * value_armorfactor * (100 - getdamage()) / 100;
00109
00110 for ( int s = 0; s < 7; )
00111 if ( weapthreat[s] < weapthreat[s+1] ) {
00112 int temp = weapthreat[s];
00113 weapthreat[s] = weapthreat[s+1];
00114 weapthreat[s+1] = temp;
00115 if ( s > 0 )
00116 s--;
00117 } else
00118 s++;
00119
00120 for ( int k = 0; k < 8; k++ )
00121 value += weapthreat[k] * value_weaponfactor / (k+1);
00122
00123 fzt->aiparam[ ai->getPlayerNum() ]->setValue ( value );
00124 fzt->aiparam[ ai->getPlayerNum() ]->valueType = 0;
00125 }
00126
00127
00128 int CalculateThreat_Vehicle :: getammunition( int i )
00129 {
00130 return eht->ammo[i];
00131 }
00132
00133 int CalculateThreat_Vehicle :: getheight(void)
00134 {
00135 return eht->height;
00136 }
00137
00138 int CalculateThreat_Vehicle :: getdamage(void)
00139 {
00140 return eht->damage;
00141 }
00142
00143 int CalculateThreat_Vehicle :: getexpirience(void)
00144 {
00145 return eht->experience;
00146 }
00147
00148
00149 void CalculateThreat_Vehicle :: calc_threat_vehicle ( Vehicle* _eht )
00150 {
00151
00152 eht = _eht;
00153 calc_threat_vehicletype ( vehicleTypeRepository.getObject_byID ( eht->typ->id ) );
00154
00155 if ( !eht->aiparam[ai->getPlayerNum()] )
00156 eht->aiparam[ai->getPlayerNum()] = new AiParameter ( eht );
00157
00158 AiParameter* aip = eht->aiparam[ai->getPlayerNum()];
00159 for ( int l = 0; l < 8; l++ )
00160 aip->threat.threat[l] = eht->typ->aiparam[ ai->getPlayerNum() ]->threat.threat[l];
00161
00162 int value = eht->typ->aiparam[ ai->getPlayerNum() ]->getValue();
00163 for ( ContainerBase::Cargo::const_iterator i = eht->getCargo().begin(); i != eht->getCargo().end(); ++i )
00164 if ( *i ) {
00165 if ( !(*i)->aiparam[ai->getPlayerNum()] ) {
00166 CalculateThreat_Vehicle ctv ( ai );
00167 ctv.calc_threat_vehicle( *i );
00168 }
00169 value += (*i)->aiparam[ai->getPlayerNum()]->getValue();
00170 }
00171
00172
00173 aip->setValue ( value );
00174
00175
00176 if ( aip->getJob() == AiParameter::job_undefined )
00177 if ( eht->canMove() )
00178 aip->setJob( AI::chooseJob ( eht->typ ));
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191 }
00192
00193 AiParameter::JobList AI::chooseJob ( const VehicleType* typ )
00194 {
00195 AiParameter::JobList jobList;
00196
00197 if ( typ->recommendedAIJob != AiParameter::job_undefined ) {
00198 jobList.push_back ( typ->recommendedAIJob );
00199 return jobList;
00200 }
00201
00202 int maxmove = minint;
00203 for ( int i = 0; i< 8; i++ )
00204 if ( typ->height & ( 1 << i ))
00205 maxmove = max ( typ->movement[i] , maxmove );
00206
00207 int maxstrength = minint;
00208 for ( int w = 0; w < typ->weapons.count; w++ )
00209 if ( typ->weapons.weapon[w].offensive() )
00210 maxstrength= max ( typ->weapons.weapon[w].maxstrength, maxstrength );
00211
00212 bool service = false;
00213 for ( int w = 0; w < typ->weapons.count; w++ )
00214 if ( typ->weapons.weapon[w].service() )
00215 service = true;
00216
00217 if ( ( typ->hasFunction( ContainerBaseType::ExternalRepair ) || service) && maxmove >= minmalq && maxstrength < 45)
00218 jobList.push_back ( AiParameter::job_supply );
00219
00220
00221 if ( typ->hasFunction( ContainerBaseType::ConquerBuildings ) ) {
00222
00223
00224
00225
00226 if ( maxstrength < maxmove )
00227 jobList.push_back ( AiParameter::job_conquer );
00228
00229 }
00230
00231 if ( ( maxstrength*1.5 < typ->view
00232 || (maxstrength*1.5 < typ->jamming && !typ->hasFunction( ContainerBaseType::JamsOnlyOwnField )))
00233 && maxmove > minmalq )
00234 jobList.push_back ( AiParameter::job_recon );
00235
00236 if ( maxstrength > 0 )
00237 jobList.push_back ( AiParameter::job_fight );
00238
00239 jobList.push_back ( AiParameter::job_undefined );
00240 return jobList;
00241 }
00242
00243
00244
00245 void AI :: calculateThreat ( const VehicleType* vt)
00246 {
00247 CalculateThreat_VehicleType ctvt ( this );
00248 ctvt.calc_threat_vehicletype( vt );
00249 }
00250
00251
00252 void AI :: calculateThreat ( Vehicle* eht )
00253 {
00254 CalculateThreat_Vehicle ctv ( this );
00255 ctv.calc_threat_vehicle( eht );
00256 }
00257
00258
00259 void AI :: calculateThreat ( Building* bld )
00260 {
00261 calculateThreat ( bld, getPlayerNum());
00262
00263 }
00264
00265 void AI :: calculateThreat ( Building* bld, int player )
00266 {
00267 if ( !bld->aiparam[ player ] )
00268 bld->aiparam[ player ] = new AiValue ( getFirstBit ( bld->typ->height ) );
00269
00270 int b;
00271
00272
00273
00274 int value = (bld->plus.energy / 10) + (bld->plus.fuel / 10) + (bld->plus.material / 10) + (bld->actstorage.energy / 20) + (bld->actstorage.fuel / 20) + (bld->actstorage.material / 20);
00275
00276 for ( ContainerBase::Cargo::const_iterator i = bld->getCargo().begin(); i != bld->getCargo().end(); ++i )
00277 if ( *i ) {
00278 if ( !(*i)->aiparam[ player ] )
00279 calculateThreat ( *i );
00280 value += (*i)->aiparam[ player ]->getValue();
00281 }
00282
00283 for (b = 0; b < bld->getProduction().size(); b++)
00284 if ( bld->getProduction()[b] ) {
00285 if ( !bld->getProduction()[b]->aiparam[ player ] )
00286 calculateThreat ( bld->getProduction()[b] );
00287 value += bld->getProduction()[b]->aiparam[ player ]->getValue() / 10;
00288 }
00289
00290 if (bld->typ->hasFunction( ContainerBaseType::InternalUnitRepair ))
00291 value += ccbt_repairfacility;
00292
00293 if (bld->typ->hasFunction( ContainerBaseType::TrainingCenter ) )
00294 value += ccbt_training;
00295 if (bld->typ->hasFunction( ContainerBaseType::RecycleUnits ) )
00296 value += ccbt_recycling;
00297
00298 bld->aiparam[ player ]->setValue ( value );
00299 }
00300
00301
00302
00303 void AI :: WeaponThreatRange :: run ( Vehicle* _veh, int x, int y, AiThreat* _threat )
00304 {
00305 threat = _threat;
00306 veh = _veh;
00307 for ( height = 0; height < 8; height++ )
00308 for ( weap = 0; weap < veh->typ->weapons.count; weap++ )
00309 if ( veh->height & veh->typ->weapons.weapon[weap].sourceheight )
00310 if ( (1 << height) & veh->typ->weapons.weapon[weap].targ )
00311 if ( veh->typ->weapons.weapon[weap].shootable() && veh->typ->weapons.weapon[weap].offensive() ) {
00312 initsearch ( MapCoordinate(x, y), veh->typ->weapons.weapon[weap].maxdistance/maxmalq, veh->typ->weapons.weapon[weap].mindistance/maxmalq );
00313 startsearch();
00314 }
00315 }
00316
00317 void AI :: WeaponThreatRange :: testfield ( const MapCoordinate& mc )
00318 {
00319 if ( dist*maxmalq <= veh->typ->weapons.weapon[weap].maxdistance )
00320 if ( dist*maxmalq >= veh->typ->weapons.weapon[weap].mindistance ) {
00321 AttackFormula af ( ai->getMap() );
00322 int strength = int ( WeapDist::getWeaponStrength( &veh->typ->weapons.weapon[weap], ai->getMap()->getField(mc)->getWeather(), dist*maxmalq, veh->height, 1 << height )
00323 * veh->typ->weapons.weapon[weap].maxstrength
00324 * (1 + af.strength_experience ( veh->experience ) + af.strength_attackbonus ( gamemap->getField(startPos)->getattackbonus() ))
00325 * af.strength_damage ( veh->damage )
00326 );
00327
00328 if ( strength ) {
00329 int pos = mc.x + mc.y * ai->getMap()->xsize;
00330 if ( strength > threat[pos].threat[height] )
00331 threat[pos].threat[height] = strength;
00332 }
00333 }
00334 }
00335
00336 void AI :: calculateFieldInformation ( void )
00337 {
00338 if ( fieldNum && fieldNum != activemap->xsize * activemap->ysize ) {
00339 delete[] fieldInformation;
00340 fieldInformation = NULL;
00341 fieldNum = 0;
00342 }
00343 if ( !fieldInformation ) {
00344 fieldNum = activemap->xsize * activemap->ysize;
00345 fieldInformation = new FieldInformation[ fieldNum ];
00346 } else
00347 for ( int a = 0; a < fieldNum; a++ )
00348 fieldInformation[ a ].reset();
00349
00350 AiThreat* singleUnitThreat = new AiThreat[fieldNum];
00351
00352
00353 for ( int y = 0; y < activemap->ysize; y++ ) {
00354 checkKeys();
00355 for ( int x = 0; x < activemap->xsize; x++ ) {
00356 MapField* fld = activemap->getField ( x, y );
00357 if ( config.wholeMapVisible || fieldvisiblenow ( fld, getPlayerNum() ) )
00358 if ( fld->vehicle && getPlayer().diplomacy.isHostile( fld->vehicle->getOwner() )) {
00359 WeaponThreatRange wr ( this );
00360 if ( !fld->vehicle->typ->wait ) {
00361
00362
00363
00364
00365 TemporaryContainerStorage tus ( fld->vehicle );
00366
00367 fld->vehicle->setMovement ( fld->vehicle->maxMovement(), 0);
00368
00369 if ( MoveUnitCommand::avail ( fld->vehicle )) {
00370 MoveUnitCommand muc ( fld->vehicle );
00371 muc.searchFields();
00372
00373 const set<MapCoordinate3D>& fields = muc.getReachableFields();
00374 for ( set<MapCoordinate3D>::const_iterator i = fields.begin(); i != fields.end(); ++i )
00375 wr.run ( fld->vehicle, i->x, i->y, singleUnitThreat );
00376
00377 const set<MapCoordinate3D>& ifields = muc.getReachableFieldsIndirect();
00378 for ( set<MapCoordinate3D>::const_iterator i = ifields.begin(); i != ifields.end(); ++i )
00379 wr.run ( fld->vehicle, i->x, i->y, singleUnitThreat );
00380
00381 }
00382 tus.restore();
00383 } else
00384 wr.run ( fld->vehicle, x, y, singleUnitThreat );
00385
00386
00387 for ( int a = 0; a < fieldNum; a++ ) {
00388 for ( int b = 0; b < 8; b++ )
00389 fieldInformation[a].threat.threat[b] += singleUnitThreat[a].threat[b];
00390
00391 singleUnitThreat[ a ].reset();
00392 }
00393 }
00394
00395 FieldInformation& fi = fieldInformation[y*getMap()->xsize+x];
00396 for ( int i = 0; i< sidenum; i++ ) {
00397 MapField* f = getMap()->getField ( getNeighbouringFieldCoordinate ( MapCoordinate(x,y), i ));
00398 if ( f && f->vehicle && f->vehicle->weapexist() && f->vehicle->color < 8*8 )
00399 fi.units[f->vehicle->color/8] += 1;
00400 }
00401 int n = 0;
00402 int c = -1;
00403 for ( int i = 0; i < 8; i++ ) {
00404 if ( fi.units[i] > n ) {
00405 n = fi.units[i];
00406 c = i;
00407 }
00408 }
00409 fi.control = c;
00410 }
00411 }
00412 delete[] singleUnitThreat;
00413 }
00414
00415
00416 void AI :: calculateAllThreats( void )
00417 {
00418
00419 if ( !baseThreatsCalculated ) {
00420 for ( int w = 0; w < vehicleTypeRepository.getNum(); w++) {
00421 VehicleType* fzt = vehicleTypeRepository.getObject_byPos(w);
00422 if ( fzt )
00423 calculateThreat( fzt );
00424
00425 }
00426 baseThreatsCalculated = 1;
00427 }
00428
00429
00430 if ( maxTrooperMove == 0) {
00431 for ( int v = 0; v < vehicleTypeRepository.getNum(); v++) {
00432 VehicleType* fzt = vehicleTypeRepository.getObject_byPos( v );
00433 if ( fzt )
00434 if ( fzt->hasFunction( ContainerBaseType::ConquerBuildings ) )
00435 if ( fzt->movement[getFirstBit(chfahrend)] > maxTrooperMove )
00436 maxTrooperMove = fzt->movement[getFirstBit(chfahrend)];
00437 }
00438 }
00439 if ( maxTransportMove == 0 ) {
00440 for (int v = 0; v < vehicleTypeRepository.getNum(); v++) {
00441 VehicleType* fzt = vehicleTypeRepository.getObject_byPos( v );
00442 if ( fzt )
00443 for ( int w = 0; w <= 7; w++)
00444 if (fzt->movement[w] > maxTransportMove)
00445 maxTransportMove = fzt->movement[w];
00446 }
00447 maxUnitMove = maxTransportMove;
00448 }
00449 for ( int height = 0; height < 8; height++ )
00450 if ( maxWeapDist[height] < 0 ) {
00451
00452 maxWeapDist[height] = 0;
00453
00454 for ( int v = 0; v < vehicleTypeRepository.getNum(); v++) {
00455 VehicleType* fzt = vehicleTypeRepository.getObject_byPos( v );
00456 if ( fzt )
00457 for ( int w = 0; w < fzt->weapons.count ; w++)
00458 if ( fzt->weapons.weapon[w].maxdistance > maxWeapDist[height] )
00459 if ( fzt->weapons.weapon[w].targ & ( 1 << height ))
00460 maxWeapDist[height] = fzt->weapons.weapon[w].maxdistance;
00461 }
00462 }
00463
00464
00465
00466
00467
00468 for ( int v = 0; v < 9; v++)
00469 if (activemap->player[v].exist() || v == 8) {
00470
00471
00472 for ( Player::VehicleList::iterator vi = getPlayer(v).vehicleList.begin(); vi != getPlayer(v).vehicleList.end(); vi++ ) {
00473 Vehicle* veh = *vi;
00474
00475 calculateThreat ( veh );
00476 }
00477
00478
00479 for ( Player::BuildingList::iterator bi = getPlayer(v).buildingList.begin(); bi != getPlayer(v).buildingList.end(); bi++ )
00480 calculateThreat ( *bi );
00481 }
00482
00483 }
00484
00485 void AI :: FieldInformation :: reset ( )
00486 {
00487 threat.reset();
00488 for ( int i = 0; i< 8; i++ )
00489 units[i] = 0;
00490 control = -1;
00491 }
00492
00493
00494 AiThreat& AI :: getFieldThreat ( int x, int y )
00495 {
00496 if ( !fieldInformation )
00497 calculateFieldInformation ();
00498 return fieldInformation[y * activemap->xsize + x ].threat;
00499 }
00500
00501 AI::FieldInformation& AI :: getFieldInformation ( int x, int y )
00502 {
00503 if ( !fieldInformation )
00504 calculateFieldInformation ();
00505 return fieldInformation[y * activemap->xsize + x ];
00506 }
00507
00508
00509 void AI :: Section :: init ( AI* _ai, int _x, int _y, int xsize, int ysize, int _xp, int _yp )
00510 {
00511 ai = _ai;
00512 init ( _x, _y, xsize, ysize, _xp, _yp );
00513 }
00514
00515 void AI :: Section :: init ( int _x, int _y, int xsize, int ysize, int _xp, int _yp )
00516 {
00517 x1 = _x;
00518 y1 = _y;
00519 x2 = _x + xsize;
00520 y2 = _y + ysize;
00521
00522 xp = _xp;
00523 yp = _yp;
00524
00525 if ( x1 < 0 ) x1 = 0;
00526 if ( y1 < 0 ) y1 = 0;
00527 if ( x2 >= ai->activemap->xsize ) x2 = ai->activemap->xsize-1;
00528 if ( y2 >= ai->activemap->ysize ) y2 = ai->activemap->ysize-1;
00529
00530
00531 centerx = (x1 + x2) / 2;
00532 centery = (y1 + y2) / 2;
00533 numberOfFields = (x2-x1+1) * ( y2-y1+1);
00534
00535 absUnitThreat.reset();
00536 absFieldThreat.reset();
00537
00538 for ( int j = 0; j < aiValueTypeNum; j++ )
00539 value[j] = 0;
00540
00541 for ( int y = y1; y <= y2; y++ )
00542 for ( int x = x1; x <= x2; x++ ) {
00543 absFieldThreat += ai->getFieldThreat ( x, y );
00544 MapField* fld = ai->activemap->getField ( x, y );
00545 if ( fld->vehicle && ai->getPlayer().diplomacy.isHostile( fld->vehicle->getOwner() ) ) {
00546 if ( !fld->vehicle->aiparam[ ai->getPlayerNum() ] )
00547 ai->calculateThreat ( fld->vehicle );
00548 AiParameter& aip = * fld->vehicle->aiparam[ ai->getPlayerNum() ];
00549 absUnitThreat += aip.threat;
00550 value[ aip.valueType ] += aip.getValue();
00551 }
00552 }
00553
00554 for ( int i = 0; i < absUnitThreat.threatTypes; i++ ) {
00555 avgUnitThreat.threat[i] = absUnitThreat.threat[i] / numberOfFields;
00556 avgFieldThreat.threat[i] = absFieldThreat.threat[i] / numberOfFields;
00557 }
00558
00559 }
00560
00561 int AI :: Section :: numberOfAccessibleFields ( const Vehicle* veh )
00562 {
00563 int num = 0;
00564 for ( int y = y1; y <= y2; y++ )
00565 for ( int x = x1; x <= x2; x++ )
00566 if ( fieldAccessible ( ai->activemap->getField ( x, y ), veh ) == 2)
00567 num++;
00568
00569 return num;
00570 }
00571
00572 AI :: Sections :: Sections ( AI* _ai ) : ai ( _ai ) , section ( NULL )
00573 {
00574 sizeX = 8;
00575 sizeY = 16;
00576 numX = ai->activemap->xsize * 2 / sizeX + 1;
00577 numY = ai->activemap->ysize * 2 / sizeY + 1;
00578 }
00579
00580 void AI :: Sections :: reset ()
00581 {
00582 if ( section ) {
00583 delete[] section;
00584 section = NULL;
00585 }
00586 }
00587
00588 AI :: Sections :: ~Sections()
00589 {
00590 reset();
00591 }
00592
00593
00594 void AI :: Sections :: calculate ( void )
00595 {
00596 if ( !section ) {
00597 section = new Section[ numX*numY ];
00598 for ( int x = 0; x < numX; x++ )
00599 for ( int y = 0; y < numY; y++ )
00600 section[ x + numX * y ].init ( ai, x * ai->activemap->xsize / numX, y * ai->activemap->ysize / numY, sizeX, sizeY, x, y );
00601
00602 }
00603 }
00604
00605 AI::Section& AI :: Sections :: getForCoordinate ( int xc, int yc )
00606 {
00607 if ( !section )
00608 calculate();
00609
00610 int dist = maxint;
00611 Section* sec = NULL;
00612 for ( int x = 0; x < numX; x++ )
00613 for ( int y = 0; y < numY; y++ ) {
00614 Section& s2 = getForPos ( x, y );
00615 int d = beeline ( xc, yc, s2.centerx, s2.centery);
00616 if ( d < dist ) {
00617 dist = d;
00618 sec = &getForPos ( x, y );
00619 }
00620 }
00621
00622 return *sec;
00623 }
00624
00625 AI::Section& AI :: Sections :: getForPos ( int xn, int yn )
00626 {
00627 if ( xn >= numX || yn >= numY || xn < 0 || yn < 0 )
00628 displaymessage( "AI :: Sections :: getForPos - invalid parameters: %d %d", 2, xn, yn );
00629
00630 return section[xn+yn*numX];
00631 }
00632
00633
00634
00635
00636 MapCoordinate AI :: Sections :: getAlternativeField( const MapCoordinate& pos, map<MapCoordinate,int>* destinationCounter, int height )
00637 {
00638 MapCoordinate result = pos;
00639 int potential = destinationCounter->operator[](pos);
00640 for ( int d = 0; d< 6; ++d ) {
00641 MapCoordinate m = getNeighbouringFieldCoordinate( pos, d );
00642 MapField* fld = ai->getMap()->getField(m );
00643 if ( fld && (fld->a.temp & height) ) {
00644 if ( destinationCounter->find( m ) == destinationCounter->end() )
00645 return m;
00646 else {
00647 if ( (destinationCounter->find(m)->second * 11 / 10) < potential ) {
00648 result = m;
00649 potential = destinationCounter->find(m)->second;
00650 }
00651 }
00652 }
00653 }
00654 if ( result == pos )
00655 return result;
00656 else
00657 return getAlternativeField( result , destinationCounter, height );
00658 }
00659
00660
00661 AI::Section* AI :: Sections :: getBest ( int pass, Vehicle* veh, MapCoordinate3D* dest, bool allowRefuellOrder, bool secondRun, map<MapCoordinate,int>* destinationCounter )
00662 {
00663
00664
00665
00666
00667
00668
00669
00670 AStar3D* ast = 0;
00671 RefuelConstraint* rfc = NULL;
00672 if ( RefuelConstraint::necessary ( veh, *ai )) {
00673 if ( secondRun )
00674 rfc = new RefuelConstraint ( *ai, veh, veh->maxMovement()*5 );
00675 else
00676 rfc = new RefuelConstraint ( *ai, veh );
00677
00678 rfc->findPath();
00679 } else {
00680 ast = new AStar3D ( ai->getMap(), veh );
00681 ast->findAllAccessibleFields ( );
00682 }
00683
00684
00685 AiParameter& aip = *veh->aiparam[ ai->getPlayerNum() ];
00686
00687 float d = minfloat;
00688
00689 AI::Section* frst = NULL;
00690
00691 float maxSectionThread = 0;
00692 for ( int y = 0; y < numY; y++ )
00693 for ( int x = 0; x < numX; x++ ) {
00694 AI::Section& sec = getForPos( x, y );
00695 int threat = sec.avgUnitThreat.threat[aip.valueType];
00696 if ( threat > maxSectionThread )
00697 maxSectionThread = threat;
00698 }
00699
00700
00701 TemporaryContainerStorage tus ( veh );
00702 veh->resetMovement();
00703 veh->attacked = 0;
00704
00705 int sectionsPossibleWithMaxFuell = 0;
00706
00707 for ( int h = 1; h < 0xff; h<<= 1 )
00708 if ( veh->typ->height & h )
00709 for ( int y = 0; y < numY; y++ )
00710 for ( int x = 0; x < numX; x++ ) {
00711 int xtogoSec = -1;
00712 int ytogoSec = -1;
00713
00714 AI::Section& sec = getForPos( x, y );
00715 float t = 0;
00716 for ( int i = 0; i < aiValueTypeNum; i++ )
00717 t += aip.threat.threat[i] * sec.value[i];
00718
00719 float f = t;
00720
00721 if ( sec.avgUnitThreat.threat[ veh->getValueType(h) ] ) {
00722 int relThreat = int( 4*maxSectionThread / sec.avgUnitThreat.threat[veh->getValueType(h)] + 1);
00723 f /= relThreat;
00724 }
00725
00726
00727
00728
00729
00730
00731
00732
00733 int dist = beeline ( veh->xpos, veh->ypos, sec.centerx, sec.centery ) + 3 * veh->maxMovement();
00734 if ( dist )
00735 f /= log(double(dist));
00736
00737 if ( f > d ) {
00738 int ac = 0;
00739 int nac = 0;
00740 int mindist = maxint;
00741 int targets = 0;
00742
00743
00744 for ( int yp = sec.y1; yp <= sec.y2; yp++ )
00745 for ( int xp = sec.x1; xp <= sec.x2; xp++ ) {
00746 MapField* fld = ai->getMap()->getField(xp, yp );
00747 if ( fld->a.temp & h ) {
00748 int mandist = abs( sec.centerx - xp ) + 2*abs ( sec.centery - yp );
00749 if ( mandist < mindist ) {
00750 mindist = mandist;
00751
00752 if ( destinationCounter && destinationCounter->find( MapCoordinate(xp,yp)) != destinationCounter->end() ) {
00753
00754
00755
00756
00757 MapCoordinate alt = getAlternativeField( MapCoordinate(xp,yp), destinationCounter, h );
00758 xtogoSec = alt.x;
00759 ytogoSec = alt.y;
00760 } else {
00761 xtogoSec = xp;
00762 ytogoSec = yp;
00763 }
00764 }
00765
00766 ai->_vision = visible_all;
00767
00768 ac++;
00769
00770 veh->xpos = xp;
00771 veh->ypos = yp;
00772 veh->height = h;
00773
00774 if ( AttackCommand::avail( veh )) {
00775 AttackCommand attack ( veh );
00776 attack.searchTargets();
00777 targets += attack.getAttackableUnits().size();
00778 }
00779 ai->_vision = visible_ago;
00780 } else
00781 nac++;
00782 }
00783
00784 if ( xtogoSec >= 0 && ytogoSec >= 0 ) {
00785 if ( !rfc || rfc->returnFromPositionPossible ( MapCoordinate3D( xtogoSec, ytogoSec, h ))) {
00786 int notAccessible = 100 * nac / (nac+ac);
00787 if ( notAccessible < 85 && targets ) {
00788 float nf = f * ( 100-notAccessible) / 100;
00789 if ( nf > d ) {
00790 d = nf;
00791
00792 frst = &getForPos ( x, y );
00793 if ( dest )
00794 *dest = MapCoordinate3D ( xtogoSec, ytogoSec, h );
00795 }
00796 }
00797 } else
00798 if ( allowRefuellOrder ) {
00799 if ( rfc && rfc->returnFromPositionPossible ( MapCoordinate3D( xtogoSec, ytogoSec, h ), veh->getStorageCapacity().fuel ))
00800 sectionsPossibleWithMaxFuell++;
00801 }
00802 }
00803 }
00804 }
00805
00806 tus.restore();
00807 delete ast;
00808 delete rfc;
00809
00810 if ( !frst ) {
00811 if ( sectionsPossibleWithMaxFuell && allowRefuellOrder )
00812 ai->issueRefuelOrder ( veh, false );
00813 else
00814 if ( RefuelConstraint::necessary ( veh, *ai ) && !secondRun )
00815 return getBest ( pass, veh, dest, allowRefuellOrder, true );
00816
00817 }
00818 return frst;
00819
00820 }
00821