misc.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           misc.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 
00019 #include <iostream>
00020 #include "ai_common.h"
00021 #include "../actions/attackcommand.h"
00022 #include "../actions/constructunitcommand.h"
00023 #include "../actions/moveunitcommand.h"
00024 #include "../actions/servicecommand.h"
00025 
00026 bool AI :: runUnitTask ( Vehicle* veh )
00027 {
00028    if ( veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_move || veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_serviceRetreat ) {
00029       bool moveIntoBuildings = false;
00030       if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer ||
00031          veh->aiparam[getPlayerNum()]->getTask() == AiParameter::tsk_serviceRetreat ||
00032          veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_script )
00033          moveIntoBuildings = true;
00034 
00035       int nwid = veh->networkid;
00036       moveUnit ( veh, veh->aiparam[getPlayerNum()]->dest, moveIntoBuildings );
00037       if ( getMap()->getUnit( nwid ))
00038          if ( veh->getPosition() == veh->aiparam[getPlayerNum()]->dest ) {
00039             veh->aiparam[getPlayerNum()]->resetTask ();
00040             return true;
00041          }
00042    }
00043 
00044    return false;
00045 }
00046 
00047 
00048 
00049 int  AI :: getBestHeight (  Vehicle* veh )
00050 {
00051    int heightNum = 0;
00052    for ( int i = 0; i < 8; i++ )
00053       if ( veh->typ->height & ( 1 << i ))
00054          heightNum++;
00055    if ( heightNum == 1 )
00056       return veh->typ->height;
00057 
00058    int bestHeight = -1;
00059    float bestHeightValue = minfloat;
00060 
00061    float maxAvgFieldThreat = minfloat;
00062    float minAvgFieldThreat = maxfloat;
00063    float secminAvgFieldThreat = maxfloat;
00064 
00065 
00066    for ( int k = 0; k < 8; k++ )
00067       if ( veh->typ->height & ( 1 << k )) {
00068          float t = sections.getForCoordinate( veh->xpos, veh->ypos ).avgFieldThreat.threat[ veh->getValueType(1<<k) ];
00069 
00070          if ( maxAvgFieldThreat < t )
00071             maxAvgFieldThreat = t;
00072 
00073          if ( minAvgFieldThreat > t )
00074             minAvgFieldThreat = t;
00075 
00076          if ( t )
00077            if ( secminAvgFieldThreat > t )
00078               secminAvgFieldThreat = t;
00079       }
00080 
00081 
00082    for ( int j = 0; j < 8; j++ )
00083       if ( veh->typ->height & ( 1 << j )) {
00084          // we save the unit, because we modify a lot of it that should be undone later
00085          TemporaryContainerStorage tus (veh);
00086          veh->height = 1<<j;
00087 
00088          // calculating the new threat of the unit
00089          calculateThreat ( veh );
00090          Section& sec = sections.getForCoordinate( veh->xpos, veh->ypos );
00091 
00092          float value = veh->aiparam[getPlayerNum()]->getValue();
00093          if ( veh->typ->movement[j] )
00094             value *=  log( double(veh->typ->movement[j]) );
00095 
00096          float threat = sec.avgFieldThreat.threat[ veh->aiparam[getPlayerNum()]->valueType ];
00097          if ( minAvgFieldThreat > 0 ) {
00098             if ( threat && threat != 1 )
00099                value *= ( log ( minAvgFieldThreat ) / log ( threat ) );
00100          } else {
00101             if ( secminAvgFieldThreat < maxfloat) {
00102                if ( threat && threat != 1 )
00103                   value *= ( log ( secminAvgFieldThreat ) / log ( threat ) );
00104                else
00105                   value *= 1.5; // no threat
00106             }
00107          }
00108 
00109          if ( value > bestHeightValue ) {
00110             bestHeightValue = value;
00111             bestHeight = 1 << j;
00112          }
00113          tus.restore();
00114       }
00115 
00116    return bestHeight;
00117 }
00118 
00119 
00120 
00121 class SaveUnitMovement {
00122        int m;
00123        Vehicle* unit;
00124     public:
00125        SaveUnitMovement ( Vehicle* veh ) {
00126           unit = veh;
00127           npush ( unit->xpos );
00128           npush ( unit->ypos );
00129           npush ( unit->height );
00130           m = unit->getMovement();
00131           npush ( unit->attacked );
00132        };
00133        ~SaveUnitMovement ( ) {
00134           npop ( unit->attacked );
00135           unit->setMovement ( m, 0 );
00136           npop ( unit->height );
00137           npop ( unit->ypos );
00138           npop ( unit->xpos );
00139        };
00140 };
00141 
00142 
00143 
00144 void AI::RefuelConstraint::findPath()
00145 {
00146    if ( !ast ) {
00147 
00148       int dist;
00149       if ( maxMove == -1 ) {
00150          if ( veh->typ->fuelConsumption )
00151             dist = veh->getResource(maxint, 2, true)  / veh->typ->fuelConsumption * maxmalq;
00152          else
00153             dist = maxint;
00154 
00155          dist = min( dist, 1000 );
00156       } else
00157          dist = maxMove;
00158 
00159       ast = new AStar3D ( ai.getMap(), veh, true, dist );
00160       ast->findAllAccessibleFields ( );
00161       // tanker planes may have a very large range; that's why we top the distance at 100 fields
00162    }
00163 }
00164 
00165 MapCoordinate3D AI::RefuelConstraint::getNearestRefuellingPosition ( bool buildingRequired, bool refuel, bool repair )
00166 {
00167    findPath();
00168 
00169    /*
00170    int fuel = veh->getResource(maxint, 2, true);
00171    int x1,y1,x2,y2;
00172    x1 = max(veh->xpos - fuel / veh->typ->fuelConsumption, 0 );
00173    y1 = max(veh->ypos - fuel / veh->typ->fuelConsumption, 0 );
00174    x2 = min(veh->xpos + fuel / veh->typ->fuelConsumption, ai.getMap()->xsize );
00175    y2 = min(veh->ypos + fuel / veh->typ->fuelConsumption, ai.getMap()->ysize );
00176    */
00177 
00178    for ( AStar3D::Container::iterator i = ast->visited.begin(); i != ast->visited.end(); i++ ) {
00179       int dist = int(i->gval );
00180       if ( i->h.getNumericalHeight() == -1 ) {
00181           MapField* fld = ai.getMap()->getField( i->h.x, i->h.y );
00182           if ( fld->building && fld->building->color == veh->color )
00183              reachableBuildings[ dist ] = fld->building;
00184       }
00185           // aircraft carriers should be supported too....
00186           // external loading of buildings too....
00187           // turrets too .....
00188 
00189 
00190        // let's check for landing
00191        if ((veh->height > chfahrend) && (i->h.getNumericalHeight() == chfahrend) ) {
00192           // we don't want to land in hostile territory
00193           FieldInformation& fi = ai.getFieldInformation ( i->h.x, i->h.y );
00194           if ( fi.control == -1 || !ai.getMap()->player[fi.control].diplomacy.isHostile( ai.getPlayerNum() ) )
00195               landingPositions[dist] = i->h;
00196        }
00197    }
00198 
00199 
00200    /*
00201    for ( int x = x1; x < x2; x++ )
00202       for ( int y = y1; y < y2; y++ )
00203          for ( int h = 0; h < 8; h++ )
00204             if ( veh->typ->height & ( 1 << h)) {
00205 
00206                 tfield* fld = getfield( x,y );
00207                 const AStar3D::Node* node = ast->fieldVisited( MapCoordinate3D( x,y, 1 << h));
00208                 if ( node ) {
00209                    int dist = int(node->gval);
00210                    if ( fld->building && fld->building->color == veh->color )
00211                       reachableBuildings[ dist ] = fld->building;
00212 
00213                    // aircraft carriers should be supported too....
00214                    // external loading of buildings too....
00215                    // turrets too .....
00216 
00217 
00218                    // let's check for landing
00219                    if ((veh->height > chfahrend) && (fld->a.temp & chfahrend) && ( 1 << h) == chfahrend ) {
00220                       // we don't want to land in hostile territory
00221                       FieldInformation& fi = ai.getFieldInformation ( x, y );
00222                       if ( fi.control == -1 || getdiplomaticstatus2 ( fi.control * 8, ai.getPlayerNum()*8 ) == capeace )
00223                           landingPositions[dist] = MapCoordinate3D( x,y,chfahrend);
00224                    }
00225                 }
00226             }
00227             */
00228 
00229    if ( buildingRequired ) {
00230       for ( ReachableBuildings::iterator rb = reachableBuildings.begin(); rb != reachableBuildings.end(); rb++  ) {
00231          if ( !repair || (rb->second->typ->hasFunction( ContainerBaseType::InternalUnitRepair )))
00232             return rb->second->getPosition3D();
00233       }
00234    }
00235    if ( !reachableBuildings.empty() && !landingPositions.empty()) {
00236       if ( reachableBuildings.begin()->first < landingPositions.begin()->first )
00237          return reachableBuildings.begin()->second->getPosition3D();
00238       else
00239          return landingPositions.begin()->second;
00240    }
00241 
00242    if ( !landingPositions.empty() )
00243       return landingPositions.begin()->second;
00244    else
00245       return MapCoordinate3D();
00246 }
00247 
00248 bool AI::RefuelConstraint::returnFromPositionPossible ( const MapCoordinate3D& pos, int theoreticalFuel )
00249 {
00250    if ( !veh->typ->fuelConsumption )
00251       return true;
00252 
00253    if ( theoreticalFuel < 0 )
00254       theoreticalFuel = veh->getResource(maxint, 2, true );
00255 
00256    findPath();
00257    if ( !positionsCalculated ) {
00258       getNearestRefuellingPosition ( true, true, false );
00259       positionsCalculated = true;
00260    }
00261 
00262    if ( !ast->fieldVisited(pos) )
00263       return false;
00264 
00265    int dist  = int( ast->fieldVisited(pos)->gval );
00266    int dist2;
00267    if ( !reachableBuildings.empty() ) {
00268       ReachableBuildings::iterator rb = reachableBuildings.begin();
00269       dist2 = beeline ( pos, rb->second->getPosition() );
00270       rb++;
00271       while ( rb != reachableBuildings.end() ) {
00272          int d = beeline ( pos, rb->second->getPosition() );
00273          if ( d < dist2 ) {
00274             dist2 = d;
00275          }
00276          rb++;
00277       }
00278    } else {
00279       if ( !landingPositions.empty() ) {
00280          LandingPositions::iterator lp = landingPositions.begin();
00281          dist2 = beeline ( pos, lp->second );
00282          MapCoordinate3D dest = lp->second;
00283          lp++;
00284          while ( lp != landingPositions.end() ) {
00285             int d = beeline ( pos, lp->second );
00286             if ( d < dist2 ) {
00287                dist2 = d;
00288                dest = lp->second;
00289             }
00290             lp++;
00291          }
00292       } else /*
00293          if ( veh->height > chfahrend )
00294             dist2 = maxint;
00295          else  */
00296             return true;
00297    }
00298 
00299    if ( theoreticalFuel - (dist + dist2) / maxmalq * veh->typ->fuelConsumption > 0.2 * veh->getStorageCapacity().fuel )
00300       return true;
00301    else
00302       return false;
00303 
00304 }
00305 
00306 bool AI::RefuelConstraint::necessary (const Vehicle* veh, AI& ai )
00307 {
00308    if ( !veh->typ->fuelConsumption )
00309       return false;
00310    if ( !(veh->height & (chtieffliegend | chfliegend | chhochfliegend))) {
00311       ServiceOrder so  ( &ai, ServiceOrder::srv_resource, veh->networkid, 2 );
00312       if ( so.serviceUnitExists() )
00313          return false;
00314       else
00315          return true;
00316    }
00317 
00318    return true;
00319 }
00320 
00321 
00322 AI::VehicleTypeEfficiencyCalculator::VehicleTypeEfficiencyCalculator( AI& _ai, Vehicle* _attacker, Vehicle* _target )
00323                                 : ai ( _ai ), attacker( _attacker ), target( _target)
00324 {
00325    ownValue = attacker->aiparam[ai.getPlayerNum()]->getValue();
00326    ownTypeID = attacker->typ->id;
00327    enemyValue = target->aiparam[ai.getPlayerNum()]->getValue();
00328    orgOwnDamage = attacker->damage;
00329    orgEnemyDamage = target->damage;
00330    enemyID = target->networkid;
00331    ownID = attacker->networkid;
00332 }
00333 
00334 
00335 void AI::VehicleTypeEfficiencyCalculator::calc()
00336 {
00337    int newOwnDamage;
00338    if ( ai.getMap()->getUnit(ownID) )
00339       newOwnDamage = attacker->damage;
00340    else
00341       newOwnDamage = 100;
00342 
00343    int newEnemyDamage;
00344    if ( ai.getMap()->getUnit(enemyID) )
00345       newEnemyDamage = target->damage;
00346    else
00347       newEnemyDamage = 100;
00348 
00349    ai.unitTypeSuccess[ownTypeID].first  += enemyValue * (newEnemyDamage - orgEnemyDamage) * 0.01;
00350    ai.unitTypeSuccess[ownTypeID].second += ownValue   * (newOwnDamage   - orgOwnDamage  ) * 0.01;
00351 }
00352 
00353 AI::AiResult  AI :: container ( ContainerBase* cb )
00354 {
00355    AiResult result;
00356 
00357    // move idle units out
00358    std::vector<Vehicle*> idleUnits;
00359    for ( vector<Vehicle*>::const_iterator j = cb->getCargo().begin(); j != cb->getCargo().end(); ++j ) {
00360       Vehicle* veh = *j;
00361       if ( veh )
00362          if ( veh->canMove() && veh->getOwner() == getPlayerNum() )
00363             if ( veh->aiparam[ getPlayerNum() ]->getTask() == AiParameter::tsk_nothing
00364                || veh->aiparam[ getPlayerNum() ]->getJob() == AiParameter::job_script  )
00365             idleUnits.push_back ( veh );
00366    }
00367    
00368    // move the most important unit first, to get the best position
00369    sort ( idleUnits.begin(), idleUnits.end(), vehicleValueComp );
00370 
00371    for ( std::vector<Vehicle*>::iterator i = idleUnits.begin(); i != idleUnits.end(); i++ ) {
00372 
00373       checkKeys();
00374 
00375       // Vehicle* veh = *i;
00376 
00377       int preferredHeight = getBestHeight ( *i );
00378 
00379       auto_ptr<MoveUnitCommand> muc ( new MoveUnitCommand( *i ));
00380       muc->searchFields();
00381       
00382       if ( muc->getReachableFields().size() ) {
00383          
00384          int moved = 0;
00385          if ( AttackCommand::avail ( *i )) {
00386             TargetVector tv;
00387 
00388             AStar3D ast ( getMap(), *i, false, (*i)->getMovement() );
00389             ast.findAllAccessibleFields ();
00390 
00391             getAttacks ( ast, *i, tv, 0 );
00392 
00393             if ( tv.size() ) {
00394                AiResult res = executeMoveAttack ( *i, tv );
00395                result += res;
00396                if ( !res.unitsDestroyed )
00397                   (*i)->aiparam[ getPlayerNum() ]->setTask( AiParameter::tsk_tactics );
00398 
00399                moved = 1;
00400             } else {
00401                AStar3D ast ( getMap(), *i, false, (*i)->maxMovement()*3 );
00402                ast.findAllAccessibleFields ();
00403 
00404                getAttacks ( ast, *i, tv, 0 );
00405 
00406                if ( tv.size() ) {
00407                   MoveVariant* mv = *max_element( tv.begin(), tv.end(), moveVariantComp );
00408                   if ( moveUnit ( *i, mv->movePos ) )
00409                      moved = 1;
00410                }
00411             }
00412 
00413          }
00414          if ( !moved ) {
00415             AiResult res =  moveToSavePlace ( *i, preferredHeight );
00416             result += res;
00417             if ( !res.unitsDestroyed )
00418                (*i)->aiparam[ getPlayerNum() ]->resetTask();
00419          }
00420       }
00421    }
00422    return result;
00423 }
00424 
00425 
00426 AI::AiResult AI::buildings( int process )
00427 {
00428    AiResult result;
00429 
00430    displaymessage2("checking buildings ... ");
00431 
00432    int buildingCounter = 0;
00433    for ( Player::BuildingList::iterator bi = getPlayer().buildingList.begin(); bi != getPlayer().buildingList.end(); bi++ ) {
00434       buildingCounter++;
00435       displaymessage2("processing building %d", buildingCounter );
00436 
00437       int unitCounter = 0;
00438       for ( vector<Vehicle*>::const_iterator j=  (*bi)->getCargo().begin(); j != (*bi)->getCargo().end(); j++ ) {
00439          Vehicle* veh = *j;
00440          if ( veh ) {
00441             ++unitCounter;
00442             displaymessage2("processing building %d (unit %d)", buildingCounter, unitCounter );
00443             
00444             auto_ptr<ServiceCommand> sc ( new ServiceCommand( *bi ));
00445             sc->setDestination( veh );
00446             if ( veh->aiparam[ getPlayerNum() ]->getJob() != AiParameter::job_supply )
00447                sc->getTransferHandler().fillDestAmmo();
00448             else
00449                sc->getTransferHandler().fillDest();
00450             
00451             sc->saveTransfers();
00452             ActionResult res = sc->execute( getContext() );
00453             if ( res.successful() )
00454                sc.release();
00455             
00456          }
00457       }
00458 
00459       result += container ( *bi );
00460 
00461       checkKeys();
00462    }
00463 
00464    displaymessage2("building check completed... ");
00465    return result;
00466 }
00467 
00468 
00469 AI::AiResult AI::transports( int process )
00470 {
00471    AiResult result;
00472 
00473    displaymessage2("checking transports ... ");
00474 
00475    int transportCounter = 0;
00476    for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); vi++ ) {
00477       Vehicle* veh = *vi;
00478       transportCounter++;
00479       displaymessage2("processing unit %d for transportation ", transportCounter );
00480 
00481       result += container ( veh );
00482 
00483       checkKeys();
00484    }
00485 
00486    displaymessage2("transport check completed... ");
00487    return result;
00488 }
00489 
00490 
00491 
00492 bool AI :: moveUnit ( Vehicle* veh, const MapCoordinate3D& destination, bool intoBuildings, bool intoTransports )
00493 {
00494    // are we operating in 3D space or 2D space? Pathfinding in 3D has not
00495    // been available at the beginning of the AI work; and it is faster anyway
00496    #if 0
00497    if ( destination.getNumericalHeight() == -1 ) {
00498 
00499       Vehicle!!Movement vm ( mapDisplay, NULL );
00500       vm.execute ( veh, -1, -1, 0, -1, -1 );
00501 
00502       std::vector<MapCoordinate> path;
00503       AStar* ast = NULL;
00504       if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer )
00505          ast = new HiddenAStar ( this, veh );
00506       else
00507          ast = new StratAStar ( this, veh );
00508 
00509       auto_ptr<AStar> ap ( ast );
00510 
00511       ast->findPath ( AStar::HexCoord ( veh->xpos, veh->ypos ), AStar::HexCoord ( destination.x, destination.y ), path );
00512 
00513       int xtogo = veh->xpos;
00514       int ytogo = veh->ypos;
00515 
00516       for ( unsigned int i = 0; i < path.size(); i++ ) {
00517          int x = path[i].x;
00518          int y = path[i].y;
00519 
00520          MapField* fld = getfield ( x, y );
00521          if ( !fld)
00522             break;
00523 
00524 
00525          if ( vm.reachableFields.isMember ( x, y )
00526               && fieldaccessible ( fld, veh ) == 2
00527               && (!fld->building  || intoBuildings)
00528               && (!fld->vehicle || intoTransports )) {
00529             xtogo = x;
00530             ytogo = y;
00531          }
00532       }
00533 
00534       if ( xtogo != veh->xpos || ytogo != veh->ypos ) {
00535          if (  getfield ( xtogo, ytogo )->building )
00536             if ( checkReConquer ( getfield ( xtogo, ytogo )->building, veh ))
00537                return false;
00538 
00539          int nwid  = veh->networkid;
00540          vm.execute ( NULL, xtogo, ytogo, 2, -1, -1 );
00541          if ( vm.getStatus() != 3 )
00542             displaymessage ( "AI :: moveUnit \n error in movement step 2 with unit %d", 1, veh->networkid );
00543 
00544          vm.execute ( NULL, xtogo, ytogo, 3, -1,  1 );
00545          if ( vm.getStatus() != 1000 )
00546             displaymessage ( "AI :: moveUnit \n error in movement step 3 with unit %d", 1, veh->networkid );
00547 
00548          if ( getMap()->getUnit(nwid) )
00549             if ( destination.x == xtogo && destination.y == ytogo )
00550                if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer )
00551                   if ( getfield ( xtogo, ytogo)->building )
00552                      veh->aiparam[getPlayerNum()]->clearJobs();
00553 
00554 
00555          return true;
00556       }
00557       return false;
00558    } else {
00559    #endif
00560       if ( veh->getPosition3D() == destination )
00561          return true;
00562          
00563       AStar3D* ast = NULL;
00564       if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer )
00565          ast = new HiddenAStar3D ( this, veh );
00566       else
00567          if ( beeline ( veh->getPosition(), destination) > veh->maxMovement() )
00568             ast = new StratAStar3D ( this, veh );
00569          else
00570             ast = new AntiMineAStar3D ( this, veh );
00571 
00572       auto_ptr<AStar3D> ap ( ast );
00573 
00574       AStar3D::Path path;
00575       ast->findPath ( path, destination );
00576 
00577       return moveUnit ( veh, path, intoBuildings, intoTransports ) == 1 ;
00578 //   }
00579 }
00580 
00581 int AI::moveUnit ( Vehicle* veh, const AStar3D::Path& path, bool intoBuildings, bool intoTransports )
00582 {
00583    auto_ptr<MoveUnitCommand> mum ( new MoveUnitCommand( veh ));
00584    mum->searchFields();
00585    
00586    
00587    int oldHeight = veh->getPosition3D().getNumericalHeight();
00588    AStar3D::Path::const_iterator pi = path.begin();
00589    if ( pi == path.end() )
00590       return 0;
00591 
00592    int nwid = veh->networkid;
00593 
00594    AStar3D::Path::const_iterator lastmatch = pi;
00595    while ( pi != path.end() ) {
00596       MapField* fld = getMap()->getField ( pi->x, pi->y );
00597       bool ok = true;
00598       if ( fld->getContainer() ) {
00599          if ( pi+1 !=path.end() )
00600              ok = false;
00601          else {
00602             if ( fld->building && !intoBuildings )
00603                ok = false;
00604             if ( fld->vehicle && !intoTransports )
00605                ok = false;
00606          }
00607       }
00608 
00609       if ( ok )
00610          if ( mum->isFieldReachable3D(*pi, true) )
00611             lastmatch = pi;
00612 
00613       ++pi;
00614    }
00615 
00616    if ( getMap()->getField ( lastmatch->x, lastmatch->y )->building )
00617       if ( checkReConquer ( getMap()->getField ( lastmatch->x, lastmatch->y )->building, veh ))
00618          return false;
00619 
00620    if ( lastmatch == path.begin() )
00621       return 0;
00622   
00623    mum->setDestination( *lastmatch );
00624    mum->setFlags( MoveUnitCommand::NoInterrupt );
00625    
00626    
00627    ActionResult res = mum->execute( getContext() );
00628    if ( res.successful() ) {
00629       mum.release();
00630       if ( getMap()->getUnit ( nwid ) && (oldHeight != veh->getPosition3D().getNumericalHeight()) )
00631          veh->aiparam[ getPlayerNum()]->setNewHeight();
00632    } else {
00633       displaymessage ( "AI :: moveUnit (path) \n error in movement step 3 with unit %d", 1, veh->networkid );
00634       return -1;
00635    }
00636 
00638    if ( ! getMap()->getUnit ( nwid ))
00639       return 1;
00640 
00641    if ( pi == path.end() ) 
00642       if ( veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_conquer )
00643          if ( getMap()->getField ( veh->getPosition() )->building )
00644             veh->aiparam[getPlayerNum()]->clearJobs();
00645 
00646    return 1;
00647 }
00648 
00649 
00650 
00651 
00652 
00653 AI:: CheckFieldRecon :: CheckFieldRecon ( AI* _ai ) : SearchFields ( _ai->getMap() ), player(_ai->getPlayerNum()), ai ( _ai )
00654 {
00655    for( int i = 0; i < 3; i++ ) {
00656       ownFields[i] = 0;
00657       enemyFields[i] = 0;
00658    }
00659 }
00660 
00661 int AI:: CheckFieldRecon :: run ( int x, int y)
00662 {
00663    initsearch ( MapCoordinate(x, y), 1 , 2 );
00664    startsearch();
00665    if ( ownFields[1] && !enemyFields[1] ) {
00666       if ( enemyFields[2] > ownFields[2] )
00667          return 0;
00668       else
00669          if ( enemyFields[2] )
00670             return 1;
00671    }
00672    return -1;
00673 }
00674 
00675 void AI::CheckFieldRecon :: testfield ( const MapCoordinate& mc )
00676 {
00677    FieldInformation& fi = ai->getFieldInformation ( mc.x, mc.y );
00678    if( fi.control != -1 ) {
00679       if ( !ai->getMap()->player[player].diplomacy.isHostile( fi.control )  )
00680          ownFields[dist]++;
00681       else
00682          enemyFields[dist]++;
00683    }
00684 }
00685 
00686 void AI :: calcReconPositions()
00687 {
00688    displaymessage2("calculating reconnaissance positions ... ");
00689    for ( int y = 0; y < getMap()->ysize; y++ )
00690       for ( int x = 0; x < getMap()->xsize; x++ ) {
00691          FieldInformation& fi = getFieldInformation ( x, y );
00692          MapField* fld = getMap()->getField(x,y);
00693          if ( fi.control == getPlayerNum() && !fld->building && ( !fld->vehicle || fld->vehicle->aiparam[getPlayerNum()]->getJob() == AiParameter::job_recon )) {
00694             CheckFieldRecon cfr ( this );
00695             int qual = cfr.run(x,y);
00696             if ( qual>= 0 )
00697                reconPositions[MapCoordinate ( x, y )] = qual;
00698 
00699          }
00700       }
00701 }
00702 
00703 void AI ::  runReconUnits ( )
00704 {
00705    
00706    vector<int> reconUnits;
00707    
00708    Player::VehicleList::iterator nvi;
00709    for ( Player::VehicleList::iterator vi = getPlayer().vehicleList.begin(); vi != getPlayer().vehicleList.end(); ++vi) {
00710       Vehicle* veh = *vi;
00711       if ( veh->aiparam[getPlayerNum()] && veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_recon ) 
00712          reconUnits.push_back( veh->networkid );
00713    }
00714       
00715    for ( vector<int>::iterator ru = reconUnits.begin(); ru != reconUnits.end(); ++ru ) {
00716       Vehicle* veh = getMap()->getUnit(*ru);
00717       if ( veh ) {
00718          int maxUnitMovement = veh->typ->maxSpeed();
00719    
00720          // the threat posed should be enemy units should be considered for position choosing too...
00721          if ( veh->aiparam[getPlayerNum()] && veh->aiparam[getPlayerNum()]->getJob() == AiParameter::job_recon ) {
00722             if ( reconPositions.find ( veh->getPosition()) == reconPositions.end()) {
00723                // the unit is not standing on a reconposition
00724                int mindist = maxint;
00725                MapCoordinate mc;
00726                for ( ReconPositions::iterator i = reconPositions.begin(); i != reconPositions.end(); i++ ) {
00727                   MapField* fld = getMap()->getField( i->first );
00728                   if ( !fld->vehicle && !fld->building ) {
00729                      AStar ast ( getMap(), veh );
00730                      ast.findAllAccessibleFields( maxUnitMovement );
00731                      if ( fld->a.temp ) {
00732                         int vdist = beeline ( veh->getPosition(), i->first )*(1+i->second/2);
00733                         if( vdist < mindist ) {
00734                            mindist = vdist;
00735                            mc = i->first;
00736                         }
00737                      }
00738                   }
00739                }
00740                if( mindist < maxint ) {
00741                   veh->aiparam[getPlayerNum()]->dest = MapCoordinate3D(mc, veh->height);
00742                   veh->aiparam[getPlayerNum()]->setTask( AiParameter::tsk_move );
00743                   runUnitTask ( veh );
00744                }
00745             }
00746          }
00747       }
00748    }
00749 }
00750 
00751 AI::UnitDistribution::Group AI::getUnitDistributionGroup ( VehicleType* vt )
00752 {
00753    switch ( chooseJob ( vt ).front() ) {
00754       case AiParameter::job_supply : return UnitDistribution::service;
00755       case AiParameter::job_recon  : return UnitDistribution::recon;
00756       case AiParameter::job_conquer: return UnitDistribution::conquer;
00757       case AiParameter::job_fight:
00758       case AiParameter::job_guard: {
00759                                       bool range = false;
00760                                       for ( int w = 0; w < vt->weapons.count; w++ )
00761                                          if ( vt->weapons.weapon[w].offensive() )
00762                                             if ( vt->weapons.weapon[w].maxdistance >= 2 * minmalq )
00763                                                range = true;
00764                                       if ( range )
00765                                          return UnitDistribution::rangeattack;
00766                                       else
00767                                          return UnitDistribution::attack;
00768                                     }
00769       default:;
00770     } //switch job
00771     return UnitDistribution::other;
00772 }
00773 
00774 
00775 AI::UnitDistribution::Group AI::getUnitDistributionGroup ( Vehicle* veh )
00776 {
00777    if ( veh->aiparam[getPlayerNum()] )
00778       switch ( veh->aiparam[getPlayerNum()]->getJob() ) {
00779          case AiParameter::job_supply : return UnitDistribution::service;
00780          case AiParameter::job_recon  : return UnitDistribution::recon;
00781          case AiParameter::job_conquer: return UnitDistribution::conquer;
00782          case AiParameter::job_fight:
00783          case AiParameter::job_guard: {
00784                                          bool range = false;
00785                                          for ( int w = 0; w < veh->typ->weapons.count; w++ )
00786                                             if ( veh->typ->weapons.weapon[w].offensive() )
00787                                                if ( veh->typ->weapons.weapon[w].maxdistance >= 2 * minmalq )
00788                                                   range = true;
00789                                          if ( range )
00790                                             return UnitDistribution::rangeattack;
00791                                          else
00792                                             return UnitDistribution::attack;
00793                                        }
00794          default:;
00795        } //switch job
00796     return UnitDistribution::other;
00797 }
00798 
00799 void AI::UnitDistribution::read ( tnstream& stream )
00800 {
00801    int version = stream.readInt();
00802    if ( version == 15000 ) {
00803       int gc = stream.readInt();
00804       calculated = stream.readInt();
00805       for ( int i = 0; i<  gc; i++ )
00806          group[i] = stream.readFloat();
00807 
00808       for ( int i = gc; i < groupCount; i++ )
00809          group[i] = 0;
00810    }
00811 }
00812 
00813 void AI::UnitDistribution::write ( tnstream& stream ) const
00814 {
00815    stream.writeInt ( 15000 );
00816    stream.writeInt ( groupCount );
00817    stream.writeInt ( calculated );
00818    for ( int i = 0; i < groupCount; i++ )
00819       stream.writeFloat ( group[i] );
00820 }
00821 
00822 
00823 AI::UnitDistribution AI::calcUnitDistribution ()
00824 {
00825    UnitDistribution unitDistribution;
00826    int unitCount = getPlayer().vehicleList.size();
00827    if ( unitCount ) {
00828       float inc = float(1) / float(unitCount);
00829       for ( Player::VehicleList::iterator i = getPlayer().vehicleList.begin(); i != getPlayer().vehicleList.end(); i++ )
00830          unitDistribution.group[ getUnitDistributionGroup ( *i )] += inc;
00831 
00832    }
00833    unitDistribution.calculated = true;
00834    return unitDistribution;
00835 }
00836 
00837 
00838 void AI::production()
00839 {
00840    float inc;
00841    int unitCount = getPlayer().vehicleList.size();
00842    if ( unitCount ) 
00843       inc = float(1) / float(unitCount);
00844    else
00845       inc = 1;
00846 
00847    UnitDistribution currentUnitDistribution = calcUnitDistribution();
00848 
00849    // we can't have enough attacking units
00850    currentUnitDistribution.group[ UnitDistribution::attack ] = 0;
00851    
00852    displaymessage2("producing units ... ");
00853 
00854    AiThreat enemyThreat;
00855    float    enemyValue[aiValueTypeNum];
00856    for ( int i = 0; i < aiValueTypeNum; i++ )
00857       enemyValue[i] = 0;
00858 
00859    for ( int p = 0; p < 8; p++ )
00860       if ( getMap()->player[p].diplomacy.isHostile( getPlayerNum() ) )
00861           for ( Player::VehicleList::iterator vli = getMap()->player[p].vehicleList.begin(); vli != getMap()->player[p].vehicleList.end(); vli++ ) {
00862              if ( (*vli)->aiparam[getPlayerNum()] ) {
00863                 enemyThreat += (*vli)->aiparam[getPlayerNum()]->threat;
00864                 enemyValue[(*vli)->aiparam[getPlayerNum()]->valueType] += (*vli)->aiparam[getPlayerNum()]->getValue();
00865              }
00866           }
00867 
00868 
00869    int emptyCount = 0;
00870    for ( int i = 0; i < aiValueTypeNum; i++ )
00871       if ( enemyValue[i] == 0)
00872          emptyCount++;
00873 
00874    // there are no enemies; the ai doesn't know what to produce
00875    if ( emptyCount == aiValueTypeNum )
00876       return ;
00877 
00878 
00879 
00880    typedef multimap<float,ProductionRating> Produceable;
00881    Produceable produceable;
00882 
00883    for ( Player::BuildingList::iterator bli = getPlayer().buildingList.begin(); bli != getPlayer().buildingList.end(); bli ++ ) {
00884       Building* bld = *bli;
00885       for ( int i = 0; i < bld->getProduction().size(); i++ )
00886          if ( bld->getProduction()[i] && bld->vehicleUnloadable ( bld->getProduction()[i] )) {
00887             const VehicleType* typ = bld->getProduction()[i];
00888             float rating = 0;
00889             for ( int j = 0; j < aiValueTypeNum; j++ )
00890                rating += enemyValue[j] * typ->aiparam[getPlayerNum()]->threat.threat[j];
00891 
00892             int danger = 1;
00893             if ( typ->aiparam[getPlayerNum()]->getValue() ) {
00894                if ( typ->aiparam[getPlayerNum()]->getValue() < enemyThreat.threat[ typ->aiparam[getPlayerNum()]->valueType] )
00895                   danger = enemyThreat.threat[ typ->aiparam[getPlayerNum()]->valueType] / typ->aiparam[getPlayerNum()]->getValue();
00896             }
00897 
00898             rating /= 1 + log ( double(danger) );
00899 
00900             UnitTypeSuccess::iterator uts = unitTypeSuccess.find ( bld->getProduction()[i]->id  );
00901             if ( uts != unitTypeSuccess.end() ) {
00902                if ( uts->second.second >= 1 )
00903                   rating *= uts->second.first / uts->second.second;
00904             }
00905 
00906 
00907             int cost = 0;
00908             for ( int j = 0; j < resourceTypeNum; j++ )
00909                cost += typ->productionCost.resource(j);
00910 
00911             if ( cost )
00912                rating /= cost;
00913 
00914             ProductionRating pr = { typ, bld, rating };
00915             produceable.insert ( make_pair(rating, pr));
00916          }
00917    }
00918 
00919    if ( !produceable.empty() ) {
00920 
00921       GetConnectedBuildings::BuildingContainer lockedBuildings;
00922 
00923       bool produced;
00924       do {
00925           produced = false;
00926 //           for ( int i = 0; i < UnitDistribution::groupCount; i++ ) {
00927 //              if ( currentUnitDistribution.group[i] < originalUnitDistribution.group[i] ) {
00928                 for ( Produceable::reverse_iterator p = produceable.rbegin(); p != produceable.rend(); p++ ) {
00929 //                    if ( getUnitDistributionGroup ( p->second.vt) == i ) {
00930                       ProductionRating& pr = p->second;
00931 
00932                       if ( find ( lockedBuildings.begin(), lockedBuildings.end(), pr.bld ) == lockedBuildings.end()) {
00933                          ContainerConstControls bc( pr.bld );
00934                          int lack = bc.unitProductionPrerequisites( pr.vt, true );
00935                          if  ( !lack && pr.bld->vehicleUnloadSystem ( pr.vt, 255 ) ) {
00936                             try {
00937                                ConstructUnitCommand* cuc = new ConstructUnitCommand( pr.bld );
00938                                cuc->setMode(ConstructUnitCommand::internal );
00939                                cuc->setVehicleType( pr.vt );
00940                                cuc->execute( getContext() );
00941                                Vehicle* veh = cuc->getProducedUnit();
00942                                if ( veh ) {
00943                                   
00944                                   auto_ptr<ServiceCommand> sc ( new ServiceCommand( pr.bld ));
00945                                   sc->setDestination( veh );
00946                                   sc->getTransferHandler().fillDest();
00947                                   sc->saveTransfers();
00948                                   ActionResult res = sc->execute( getContext() );
00949                                   if ( res.successful() )
00950                                      sc.release();
00951                                   
00952                                   calculateThreat ( veh );
00953                                   container ( pr.bld );
00954                                   // currentUnitDistribution.group[i] += inc;
00955                                   produced = true;
00956                                   break;  // exit produceable loop
00957                               }
00958                             } catch ( ActionResult res ) {
00959                                // just ignore any errors 
00960                             }
00961                          } else {
00962 
00963                             // the ai will save for move expensive units
00964                             if ( !(lack & ( 1<<10 ))) {
00965                                if ( pr.bld->getResource ( pr.vt->productionCost, 1 ) + pr.bld->netResourcePlus( ) * config.waitForResourcePlus >= pr.vt->productionCost )
00966                                   for ( int r = 0; r < resourceTypeNum; r++ )
00967                                      if ( lack & (1 << r )) {
00968                                         GetConnectedBuildings gcb ( lockedBuildings, getMap(), r );
00969                                         gcb.start ( pr.bld->getEntry().x, pr.bld->getEntry().y );
00970                                      }
00971                                sort  ( lockedBuildings.begin(), lockedBuildings.end());
00972                                unique( lockedBuildings.begin(), lockedBuildings.end());
00973                             }
00974                          }
00975                       }
00976                    // } // else
00977                      //  printf(" %s \n", p->second.vt->description );
00978                 }
00979              // }
00980           // }
00981       } while ( produced );
00982    }
00983 
00984 }
00985 
00986 

Generated on Mon May 14 01:31:57 2012 for Advanced Strategic Command by  doxygen 1.5.1