valuation.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           valuation.cpp  -  description
00003                              -------------------
00004     begin                : Fri Mar 30 2001
00005     copyright            : (C) 2001 by Martin Bickel
00006     email                : bickel@asc-hq.org
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
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;    //  basic threatvalues for buildings
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++ ) {    // the distance between two fields is maxmalq
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                   if ( !(getheight() & ( 1 << j )))
00094                      m /= 2;
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    generatethreatvalue();
00181    int l = 0;
00182    for ( int b = 0; b <= 7; b++) {
00183       eht->threatvalue[b] = weapthreatvalue[b];
00184       if (weapthreatvalue[b] > l)
00185          l = weapthreatvalue[b];
00186    }                         <Zwischenablage leer>
00187    eht->completethreatvalue = threatvalue2 + l;
00188    eht->completethreatvaluesurr = threatvalue2 + l;
00189    eht->threats = 0;
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       /* if ( functions & cf_trooper )  {
00223          if ( typ->height & chfahrend )
00224             jobList.push_back ( AiParameter::job_conquer );
00225       } else { */
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 //   calculateThreat ( bld, 8 );
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    // Since we have two different resource modes now, this calculation should be rewritten....
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    // we now check the whole map
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                   // The unit may have already moved this turn.
00363                   // So we give it the maximum movementrange
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    // Calculates the basethreats for all vehicle types
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    // Some further calculations that only need to be done once.
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 )   // buildings can only be conquered on ground level, or by moving to adjecent field which is less
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++) // cycle through all levels of height
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; // It may be possible that there is no weapon to shoot to a specific height
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 ))   // targ is a bitmap, each bit standing for a level of height
00460                          maxWeapDist[height] = fzt->weapons.weapon[w].maxdistance;
00461          }
00462       }
00463 
00464 
00465 
00466 
00467    // There are only 8 players in ASC, but there may be neutral units (player == 8)
00468    for ( int v = 0; v < 9; v++)
00469       if (activemap->player[v].exist() || v == 8) {
00470 
00471          // Now we cycle through all units of this player
00472          for ( Player::VehicleList::iterator vi = getPlayer(v).vehicleList.begin(); vi != getPlayer(v).vehicleList.end(); vi++ ) {
00473             Vehicle* veh = *vi;
00474             // if ( !veh->aiparam[ getPlayerNum() ] )
00475                calculateThreat ( veh );
00476          }
00477 
00478          // Now we cycle through all buildings
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 ]; //  ( ai );
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   This is like some ball rolling down from some high potential spike
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       In the first pass wwe check were all the units would go if there wouldn't be
00665       a threat anywhere.
00666       In the second pass the threat of a section is devided by the number of units that
00667       are going there
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    // float nd = minfloat;
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(); // to make sure the wait-for-attack flag doesn't hinder the attack
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                 if ( sec.avgUnitThreat.threat[aip.valueType] >= 0 )
00728                    f = t / log( sec.avgUnitThreat.threat[aip.valueType] );
00729                 else
00730                    f = t;
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                                   /* we are checking if there are too many units heading for this field already 
00754                                      check how many are for neighbouringfields */
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 ) {   // less than 85% of fields not accessible
00788                             float nf = f * ( 100-notAccessible) / 100; // *  ( 100 - notAccessible );
00789                             if ( nf > d ) {
00790                                d = nf;
00791                                // nd = nf;
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 

Generated on Mon May 21 01:26:39 2012 for Advanced Strategic Command by  doxygen 1.5.1