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