Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

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

Generated on Tue Jun 24 01:27:46 2008 for Advanced Strategic Command by  doxygen 1.4.2