astar2.cpp

Go to the documentation of this file.
00001 
00007 #include <stack>
00008 #include <vector>
00009 #include <functional>
00010 #include <algorithm>
00011 #include <cmath>
00012 
00013 #include "vehicletype.h"
00014 #include "spfst.h"
00015 #include "controls.h"
00016 
00017 #include "astar2.h"
00018 
00019 
00020 // The mark array marks directions on the map.  The direction points
00021 // to the spot that is the previous spot along the path.  By starting
00022 // at the end, we can trace our way back to the start, and have a path.
00023 
00024 
00025 // mark -> temp3
00026 
00027 bool AStar::Node::operator< ( const AStar::Node& a ) const
00028 {
00029     // To compare two nodes, we compare the `f' value, which is the
00030     // sum of the g and h values.
00031     return (gval+hval) < (a.gval+a.hval);
00032 }
00033 
00034 bool AStar::Node::operator> ( const AStar::Node& a ) const
00035 {
00036     return (gval+hval) > (a.gval+a.hval);
00037 }
00038 
00039 
00040 bool operator == ( const AStar::HexCoord& a, const AStar::HexCoord& b )
00041 {
00042    return (a.m == b.m) && (a.n == b.n );
00043 }
00044 
00045 
00046 bool operator == ( const AStar::Node& a, const AStar::Node& b )
00047 {
00048     // Two nodes are equal if their components are equal
00049     return (a.h == b.h) && (a.gval == b.gval ) && (a.hval == b.hval );
00050 }
00051 
00052 
00053 
00054 HexDirection ReverseDirection( HexDirection d )
00055 {
00056     // With hexagons, I'm numbering the directions 0 = N, 1 = NE,
00057     // and so on (clockwise).  To flip the direction, I can just
00058     // add 3, mod 6.
00059     return HexDirection( ( 3+int(d) ) % 6 );
00060 }
00061 
00062 
00063 AStar :: AStar ( GameMap* actmap, Vehicle* veh )
00064 {
00065    tempsMarked = NULL;
00066    _path = NULL;
00067    _veh = veh;
00068    gamemap = actmap;
00069    MAXIMUM_PATH_LENGTH = maxint;
00070 }
00071 
00072 AStar :: ~AStar ( )
00073 {
00074    if ( tempsMarked )
00075       tempsMarked->cleartemps( 1 );
00076 }
00077 
00078 int AStar::dist( HexCoord a, HexCoord b )
00079 {
00080    /*
00081     // The **Manhattan** distance is what should be used in A*'s heuristic
00082     // distance estimate, *not* the straight-line distance.  This is because
00083     // A* wants to know the estimated distance for its paths, which involve
00084     // steps along the grid.  (Of course, if you assign 1.4 to the cost of
00085     // a diagonal, then you should use a distance function close to the
00086     // real distance.)
00087 
00088     // Here I compute a ``Manhattan'' distance for hexagons.  Nifty, eh?
00089     int a1 = a.m*2;
00090     int a2 = a.n*2-(a.m%2)-2*(a.m/2);
00091     int a3 = -a1-a2;
00092     int b1 = b.m*2;
00093     int b2 = b.n*2-(b.m%2)-2*(b.m/2);
00094     int b3 = -b1-b2;
00095 
00096 
00097     // 2*D/path_div lets me scale the value.  Scaling is nice because you
00098     // can adjust the accuracy/speed tradeoff.  If you want a faster
00099     // search, you can get an approximate answer.
00100     return 2*(abs(a1-b1)+abs(a2-b2)+abs(a3-b3))/path_div;
00101     */
00102     return beeline ( a.m, a.n, b.m, b.n );
00103 }
00104 
00105 int AStar::getMoveCost ( int x1, int y1, int x2, int y2, const Vehicle* vehicle )
00106 {
00107     if ( !fieldAccessible ( gamemap->getField ( x2, y2 ), vehicle ))
00108        return MAXIMUM_PATH_LENGTH;
00109 
00110     return calcMoveMalus ( MapCoordinate3D(x1, y1, vehicle->height), MapCoordinate3D(x2, y2, vehicle->height), vehicle ).first;
00111 }
00112 
00113 
00114 
00115 // greater(Node) is an STL thing to create a 'comparison' object out of
00116 // the greater-than operator, and call it comp.
00117 
00118 
00119 // I'm using a priority queue implemented as a heap.  STL has some nice
00120 // heap manipulation functions.  (Look at the source to `priority_queue'
00121 // for details.)  I didn't use priority_queue because later on, I need
00122 // to traverse the entire data structure to update certain elements; the
00123 // abstraction layer on priority_queue wouldn't let me do that.
00124 
00125 inline void AStar::get_first( Container& v, Node& n )
00126 {
00127     n = v.front();
00128     pop_heap( v.begin(), v.end(), comp );
00129     v.pop_back();
00130 }
00131 
00132 
00133 
00134 // Here's the algorithm.  I take a map, two points (A and B), and then
00135 // output the path in the `path' vector.
00136 
00137 
00138 
00139 void AStar::findPath( HexCoord A, HexCoord B, Path& path )
00140 {
00141     _path = &path;
00142     Vehicle* veh = _veh;
00143 
00144     if ( gamemap->getField(A.m, A.n)->unitHere(veh) )
00145        if ( !veh->canMove() )
00146           return;
00147 
00148     for ( int y = gamemap->xsize * gamemap->ysize -1; y >= 0; y-- )
00149        gamemap->field[y].temp3 = DirNone;
00150 
00151     Node N;
00152     Container open;
00153     {
00154         // insert the original node
00155         N.h = A;
00156         N.gval = 0;
00157         N.hval = dist(A,B);
00158         open.push_back(N);
00159     }
00160 
00161 
00162     // Remember which nodes we visited, so that we can clear the mark array
00163     // at the end.
00164 
00165     // While there are still nodes to visit, visit them!
00166     while( !open.empty() )
00167     {
00168         get_first( open, N );
00169         visited.push_back( N );
00170         // If we're at the goal, then exit
00171         if( N.h == B )
00172             break;
00173 
00174         // Every other column gets a different order of searching dirs
00175         // (Alternatively, you could pick one at random).  I don't want
00176         // to be too biased by my choice of order in which I look at the
00177         // neighboring grid spots.
00178 
00179         int directions1[6] = {0,1,2,3,4,5};
00180         int directions2[6] = {5,4,3,2,1,0};
00181         int *directions;
00182         if( N.h.m % 2 == 0 )
00183             directions = directions1;
00184         else
00185             directions = directions2;
00186 
00187         // Look at your neighbors.
00188         for( int dci = 0; dci < 6; dci++ )
00189         {
00190 #if 0
00191             {
00192                 // Random permutation of directions
00193                 int i = random(6-dci);
00194                 swap( directions[dci+i], directions[dci] );
00195             }
00196 #endif
00197 
00198             HexDirection d = HexDirection(directions[dci]);
00199             HexCoord hn = N.h;
00200             getnextfield ( hn.m, hn.n, d );
00201             // If it's off the end of the map, then don't keep scanning
00202             if( hn.m < 0 || hn.n < 0 || hn.m >= gamemap->xsize || hn.n >= gamemap->ysize || !fieldAccessible ( gamemap->getField ( hn.m, hn.n ), veh ))
00203                 continue;
00204 
00205             // cursor.gotoxy ( hn.m, hn.n );
00206             int k = getMoveCost( N.h.m, N.h.n, hn.m, hn.n, veh );
00207             if ( k > veh->maxMovement() )
00208                k = MAXIMUM_PATH_LENGTH;
00209 
00210             Node N2;
00211             N2.h = hn;
00212 
00213             if ( k == MAXIMUM_PATH_LENGTH )
00214                N2.gval = k;
00215             else
00216                N2.gval = N.gval + k;
00217 
00218             N2.hval = dist( hn, B );
00219             // If this spot (hn) hasn't been visited, its mark is DirNone
00220             if( gamemap->getField (hn.m,hn.n)->temp3 == DirNone ) {
00221 
00222                 // The space is not marked
00223 
00224                 if ( N.gval < MAXIMUM_PATH_LENGTH ) {
00225                    gamemap->getField (hn.m,hn.n)->temp3 = ReverseDirection(d);
00226                    open.push_back( N2 );
00227                    push_heap( open.begin(), open.end(), comp );
00228                 }
00229             }
00230             else
00231             {
00232                 // Search for hn in open
00233                 Container::iterator find1 = open.end();
00234                 for( Container::iterator i = open.begin(); i != open.end(); i++ )
00235                     if( (*i).h == hn )
00236                     {
00237                         find1 = i;
00238                         break;
00239                     }
00240                 // if found, call it N3
00241                 if( find1 != open.end() )
00242                 {
00243                     Node N3 = *find1;
00244                     if( N3.gval > N2.gval )
00245                     {
00246                         gamemap->getField (hn.m,hn.n)->temp3 = ReverseDirection(d);
00247                         // Replace N3 with N2 in the open list
00248                         Container::iterator last = open.end() - 1;
00249                         *find1 = *last;
00250                         *last = N2;
00251                         push_heap( open.begin(), open.end(), comp );
00252                     }
00253                 }
00254             }
00255         }
00256     }
00257 
00258     if( N.h == B && N.gval < MAXIMUM_PATH_LENGTH )
00259     {
00260         // We have found a path, so let's copy it into `path'
00261         std::vector<int> tempPath;
00262 
00263         HexCoord h = B;
00264         while( !(h == A) )
00265         {
00266             HexDirection dir = HexDirection ( gamemap->getField (h.m, h.n)->temp3 );
00267             tempPath.push_back( int( ReverseDirection( dir ) ) );
00268             getnextfield ( h.m, h.n, dir );
00269         }
00270 
00271         // tempPath now contains the directions the unit must travel .. backwards
00272         // (like a stack)
00273 
00274         int x = A.m;
00275         int y = A.n;
00276 
00277         for ( int i = tempPath.size()-1; i >= 0 ; i-- ) {
00278            getnextfield ( x, y, tempPath[i] );
00279            path.push_back ( MapCoordinate ( x, y ));
00280         }
00281     }
00282     else
00283     {
00284         // No path
00285     }
00286 
00287     gamemap->cleartemps ( 4 ); 
00288 }
00289 
00290 int AStar::getDistance ( )
00291 {
00292    if ( !_path || !_veh || ! gamemap )
00293       return -1;
00294 
00295    if ( _path->size() <= 0 )
00296       return -1;
00297 
00298    int dist = 0;
00299    for ( Path::iterator i = _path->begin(); i != _path->end(); i++ )
00300       dist += gamemap->getField ( *i )->getmovemalus ( _veh->typ->movemalustyp );
00301 
00302    return dist;
00303 }
00304 
00305 int AStar::getTravelTime( )
00306 {
00307    int dist = getDistance();
00308    if ( dist < 0 )
00309       return dist;
00310    else
00311       return dist / _veh->typ->movement[ getFirstBit ( _veh->height ) ];
00312 }
00313 
00314 bool AStar::fieldVisited ( int x, int y)
00315 {
00316    HexCoord hn ( x,y );
00317    for( Container::iterator i = visited.begin(); i != visited.end(); i++ )
00318        if( (*i).h == hn )
00319           return true;
00320 
00321    return false;
00322 }
00323 
00324 void AStar::findAllAccessibleFields ( int maxDist )
00325 {
00326    gamemap->cleartemps ( 1 );
00327 
00328    MAXIMUM_PATH_LENGTH = maxDist;
00329 
00330    Path dummy;
00331    findPath ( dummy, gamemap->xsize, gamemap->ysize );  //this field does not exist...
00332    for ( Container::iterator i = visited.begin(); i != visited.end(); i++ )
00333       gamemap->getField ( (*i).h.m, (*i).h.n )->a.temp = 1;
00334 
00335    tempsMarked = gamemap;
00336 }
00337 
00338 
00339 void AStar::findPath( Path& path, int x, int y )
00340 {
00341   findPath ( AStar::HexCoord ( _veh->xpos, _veh->ypos ), AStar::HexCoord ( x, y ), path );
00342 }
00343 
00344 
00345 
00346 
00347 void findPath( GameMap* actmap, AStar::Path& path, Vehicle* veh, int x, int y )
00348 {
00349   AStar as ( actmap, veh );
00350   as.findPath ( AStar::HexCoord ( veh->xpos, veh->ypos ), AStar::HexCoord ( x, y ), path );
00351 //   int og = godview;
00352 //   godview = 1;
00353 //   AStar ( actmap, HexCoord ( veh->xpos, veh->ypos ), HexCoord ( x, y ), path, veh );
00354 //   godview = og;
00355 }
00356 
00357 
00358 
00359 
00364 
00365 
00366 bool AStar3D::Node::operator< ( const AStar3D::Node& b ) const
00367 {
00368     // To compare two nodes, we compare the `f' value, which is the
00369     // sum of the g and h values.
00370     if ( hval >= AStar3D::longestPath || b.hval >= AStar3D::longestPath )
00371        return gval < b.gval;
00372     else
00373        return (gval+hval) < (b.gval+b.hval);
00374 
00375 }
00376 /*
00377 bool operator< ( const AStar3D::Node& a, const AStar3D::Node& b )
00378 {
00379     // To compare two nodes, we compare the `f' value, which is the
00380     // sum of the g and h values.
00381     if ( a.hval >= AStar3D::longestPath || b.hval >= AStar3D::longestPath )
00382        return a.gval < b.gval;
00383     else
00384        return (a.gval+a.hval) < (b.gval+b.hval);
00385 }
00386 */
00387 bool operator> ( const AStar3D::Node& a, const AStar3D::Node& b )
00388 {
00389     if ( a.hval >= AStar3D::longestPath || b.hval >= AStar3D::longestPath )
00390        return a.gval > b.gval;
00391     else
00392        return (a.gval+a.hval) > (b.gval+b.hval);
00393 }
00394 
00395 
00396 bool operator == ( const AStar3D::Node& a, const AStar3D::Node& b )
00397 {
00398     // Two nodes are equal if their components are equal
00399     return (a.h == b.h) && (a.gval == b.gval ) && (a.hval == b.hval );
00400 }
00401 
00402 
00403 
00404 
00405 bool AStar3D::Container::update ( const Node& node )
00406 {
00407    iterator i = find ( node.h );
00408    if ( i != Parent::end() )
00409       if (i->gval > node.gval || (i->gval == node.gval && i->hasAttacked && !node.hasAttacked)) {
00410          Parent::erase ( i );
00411          add ( node );
00412          return true;
00413       }
00414    return false;
00415 }
00416 
00417 AStar3D::Container::iterator AStar3D::Container::find ( const MapCoordinate3D& pos )
00418 {
00419    for ( iterator i = begin(); i != end(); i++ )
00420       if ( i->h == pos )
00421          return i;
00422    return end();
00423 }
00424 
00425 
00426 
00427 
00428 
00429 AStar3D :: AStar3D ( GameMap* actmap_, Vehicle* veh_, bool markTemps_, int maxDistance )
00430          : operationLimiter ( NULL )
00431 {
00432    markTemps = markTemps_;
00433    tempsMarked = NULL;
00434    _path = NULL;
00435    veh = veh_;
00436    actmap = actmap_;
00437 
00438    MAXIMUM_PATH_LENGTH = maxDistance;
00439    if ( MAXIMUM_PATH_LENGTH > longestPath )
00440       MAXIMUM_PATH_LENGTH =  int(2* longestPath);
00441 
00442 /*
00443    if ( !veh->maxMovement() ) {
00444       // fatalError ( "AStar3D :: AStar3D  -  trying to move a immobile unit");
00445       int foo = veh->maxMovement()*2;
00446    }
00447 */
00448 
00449    if ( veh->getPosition().getNumericalHeight() >= 0 )
00450       for ( int i = 0; i < 8; i++ )
00451           if ( veh->maxMovement() )
00452              vehicleSpeedFactor[i] = float(veh->typ->movement[i]) / veh->maxMovement();
00453           else
00454              vehicleSpeedFactor[i] = 0.00001;
00455 
00456    else
00457       for ( int i = 0; i < 8; i++ )
00458           vehicleSpeedFactor[i] = float(veh->typ->movement[i]);
00459 
00460    maxVehicleSpeedFactor = 0;
00461    for ( int i = 0; i < 8; ++i )
00462       maxVehicleSpeedFactor = max( maxVehicleSpeedFactor, vehicleSpeedFactor[i] );
00463    
00464    int cnt = actmap->xsize*actmap->ysize*9;
00465    posDirs = new HexDirection[cnt];
00466    posHHops = new int[cnt];
00467    fieldAccess = new int[cnt];
00468 
00469    for ( int i = 0; i < cnt; i++ ) {
00470       posDirs[i] = DirNone;
00471       posHHops[i] = -20;
00472       fieldAccess[i] = 0;
00473    }
00474 
00475    if ( (veh->typ->height & ( chtieffliegend | chfliegend | chhochfliegend )) && actmap->weather.windSpeed ) {
00476       wind = new WindMovement ( veh );
00477    } else
00478       wind = NULL;
00479 
00480 }
00481 
00482 
00483 AStar3D :: ~AStar3D ( )
00484 {
00485    if( tempsMarked )
00486       tempsMarked->cleartemps ( 3 );
00487 
00488    if ( wind ) {
00489       delete wind;
00490       wind = NULL;
00491    }
00492 
00493    delete[] posDirs;
00494    delete[] posHHops;
00495    delete[] fieldAccess;
00496 }
00497 
00498 AStar3D::DistanceType AStar3D::dist( const MapCoordinate3D& a, const MapCoordinate3D& b )
00499 {
00500    int heightDiff;
00501    if ( b.getNumericalHeight() >= 0 && a.getNumericalHeight() >= 0 )
00502       heightDiff = abs ( b.getNumericalHeight() - a.getNumericalHeight() ) * minmalq;
00503    else
00504       heightDiff = 0;
00505 
00506    if ( b.valid() ) {
00507       if  ( wind && ((b.getBitmappedHeight() | a.getBitmappedHeight()) & ( chtieffliegend | chfliegend | chhochfliegend )))
00508          return windbeeline(a, b, wind ) + heightDiff;
00509       else
00510          return beeline ( a, b ) + heightDiff;
00511    } else
00512       return longestPath;
00513 }
00514 
00515 AStar3D::DistanceType AStar3D::dist ( const MapCoordinate3D& a, const vector<MapCoordinate3D>& b )
00516 {
00517    DistanceType d = longestPath;
00518    for ( vector<MapCoordinate3D>::const_iterator i = b.begin(); i != b.end(); i++ ) {
00519       DistanceType e = dist(a,*i);
00520       if ( maxVehicleSpeedFactor )
00521          e /= maxVehicleSpeedFactor;
00522       if ( d > e )
00523          d = e;
00524    }
00525    return d;
00526 }
00527 
00528 
00529 AStar3D::DistanceType AStar3D::getMoveCost ( const MapCoordinate3D& start, const MapCoordinate3D& dest, const Vehicle* vehicle, bool& canStop, bool& hasAttacked )
00530 {
00531     // since we are operating at different levels of height and the unit has different
00532     // speeds at different levels of height, we must not optimize for distance, but for
00533     // travel time.
00534 
00535     int fa = fieldAccessible ( actmap->getField ( dest ), vehicle, dest.getBitmappedHeight(), &hasAttacked );
00536 
00537     canStop = fa >= 2;
00538 
00539     if ( !fa )
00540        return longestPath;
00541 
00542     int movecost = calcMoveMalus ( start, dest, vehicle, wind, &hasAttacked ).first;
00543 
00544     if ( start.getNumericalHeight() >= 0 )
00545        if ( movecost > veh->typ->movement[start.getNumericalHeight()]  )
00546           return longestPath;
00547 
00548 
00549     if ( start.getNumericalHeight() < 0 )
00550        return movecost;
00551     else
00552        if ( !vehicleSpeedFactor[start.getNumericalHeight()] )
00553           return longestPath;
00554        else
00555           return movecost / vehicleSpeedFactor[start.getNumericalHeight()];
00556 }
00557 
00558 
00559 
00560 // greater(Node) is an STL thing to create a 'comparison' object out of
00561 // the greater-than operator, and call it comp.
00562 
00563 // I'm using a priority queue implemented as a heap.  STL has some nice
00564 // heap manipulation functions.  (Look at the source to `priority_queue'
00565 // for details.)  I didn't use priority_queue because later on, I need
00566 // to traverse the entire data structure to update certain elements; the
00567 // abstraction layer on priority_queue wouldn't let me do that.
00568 
00569 
00570 void AStar3D :: nodeVisited ( const Node& N2, HexDirection direc, Container& open, int prevHeight, int heightChangeDist )
00571 {
00572    if ( N2.gval <= MAXIMUM_PATH_LENGTH && N2.gval < longestPath ) {
00573       if ( getPosDir(N2.h) == DirNone ) {
00574          open.add ( N2 );
00575          getPosDir(N2.h) = ReverseDirection(direc);
00576          getPosHHop(N2.h) = 10 + prevHeight + 1000 * heightChangeDist;
00577       } else {
00578          if ( open.update ( N2 ) ) {
00579             getPosDir(N2.h) = ReverseDirection(direc);
00580             getPosHHop(N2.h) = 10 + prevHeight + 1000 * heightChangeDist;
00581          }
00582       }
00583    }
00584 }
00585 
00586 
00587 const int* getDirectionOrder ( int x, int y, int x2, int y2 )
00588 {
00589     typedef const int Directions[sidenum];
00590     static const Directions  directions[3][3]  = {{{5, 0, 4, 1, 3, 2 }, {0, 1, 5, 2, 4, 3 }, {1, 0, 2, 5, 3, 4 }},
00591                                                    {{5, 4, 0, 3, 1, 2 }, {0, 1, 2, 3, 4, 5 }, {1, 2, 0, 3, 5, 4 }},
00592                                                    {{4, 3, 5, 2, 0, 1 }, {3, 4, 2, 5, 1, 0 }, {2, 3, 1, 4, 0, 5 }}};
00593     int a,b;
00594 
00595     int dx = (2 * x2 + (y2 & 1)) - (2 * x + (y & 1));
00596     int dy = y2 - y;
00597 
00598     if (dx < 0)
00599        a = 0;
00600     else
00601        if (dx == 0)
00602           a = 1;
00603        else
00604           a = 2;
00605 
00606     if (dy < 0)
00607        b = 0;
00608     else
00609        if (dy == 0)
00610           b = 1;
00611        else
00612           b = 2;
00613 
00614     return (const int*)(&directions[b][a]);
00615 }
00616 
00617 const AStar3D::DistanceType AStar3D::longestPath = 1e9;
00618 
00619 void AStar3D::findPath( const MapCoordinate3D& A, const vector<MapCoordinate3D>& B, Path& path )
00620 {
00621     _path = &path;
00622 
00623     Node N;
00624     Container open;
00625 
00626     /* this should be checked outside by giving the pathfinder the right movement
00627     if ( !veh->canMove() )
00628        return;
00629     */
00630 
00631     if ( actmap->getField(A)->unitHere(veh) ) {
00632        // insert the original node
00633        N.h = A;
00634     } else {
00635        N.h.setnum(A.x, A.y, -1 );
00636     }
00637     N.hasAttacked = veh->attacked;
00638     N.gval = 0;
00639     N.hval = dist(A,B);
00640     open.add(N);
00641 
00642     // Remember which nodes we visited, so that we can clear the mark array
00643     // at the end.
00644 
00645     bool found = false;
00646     MapCoordinate3D endpos;
00647 
00648     // While there are still nodes to visit, visit them!
00649     while( !open.empty() ) {
00650         N = open.getFirst();
00651        
00652         visited.add( N );
00653         // If we're at the goal, then exit
00654         for ( vector<MapCoordinate3D>::const_iterator i = B.begin(); i != B.end(); i++ )
00655            if( N.h == *i ) {
00656               MapField* fld = actmap->getField(N.h);
00657               if ( N.h.getNumericalHeight() == -1 || !(fld->building || (fld->vehicle && fld->vehicle != veh ))) {
00658                  found = true;
00659                  endpos = N.h;
00660                  break;
00661               }
00662 
00663            }
00664         if ( found )
00665            break;
00666 
00667 
00668         if ( N.h.getNumericalHeight() == -1 ) {
00669            // the unit is inside a container
00670 
00671           if ( !operationLimiter || operationLimiter->allowLeavingContainer() ) {
00672              for ( int dir = 0; dir < 6; dir++ ) {
00673                 MapCoordinate3D pos = getNeighbouringFieldCoordinate ( N.h, dir );
00674                 if ( actmap->getField(pos)) {
00675                    int h = actmap->getField(N.h)->getContainer()->vehicleUnloadable(veh->typ);
00676                    for ( int i = 0; i < 8; i++ )
00677                       if ( h & (1<<i)) {
00678                          Node N2;
00679                          N2.h.setnum ( pos.x, pos.y, i );
00680                          N2.hasAttacked = N.hasAttacked;
00681                          const ContainerBaseType::TransportationIO* tio = actmap->getField(N.h)->getContainer()->vehicleUnloadSystem( veh->typ, 1<<i);
00682                          if ( tio ) {
00683                             if ( tio->disableAttack )
00684                                N2.hasAttacked = true;
00685 
00686                             DistanceType k = getMoveCost( N.h, N2.h, veh, N2.canStop, N2.hasAttacked );
00687                             if ( k > veh->typ->movement[N2.h.getNumericalHeight()]  )
00688                                if ( k < longestPath )
00689                                   k = longestPath;
00690                                   /*
00691                                if ( k < MAXIMUM_PATH_LENGTH )
00692                                   k = MAXIMUM_PATH_LENGTH;
00693                                   */
00694 
00695                             if ( k >= longestPath || N.gval >= longestPath )
00696                                N2.gval = longestPath;
00697                             else
00698                                N2.gval = N.gval + k;
00699 
00700                             N2.hval = dist(N2.h,B);
00701 
00702                             if ( N2.canStop && actmap->getField(N2.h)->getContainer() && actmap->getField(N2.h)->vehicle != veh) {
00703                                  // there's an container on the field that can be entered. This means, the unit can't stop 'over' the container...
00704                                  N2.canStop = false;
00705                                  nodeVisited ( N2, HexDirection(dir), open, N.h.getNumericalHeight(), maxmalq );
00706 
00707                                  // ... only inside it
00708                                  N2.canStop = true;
00709                                  N2.enterHeight = N2.h.getNumericalHeight() ;
00710                                  N2.h.setnum ( N2.h.x, N2.h.y, -1 );
00711                                  // N2.hasAttacked = true;
00712                                  nodeVisited ( N2, HexDirection(dir), open, N.h.getNumericalHeight(), maxmalq );
00713                             } else
00714                                  nodeVisited ( N2, HexDirection(dir), open, N.h.getNumericalHeight(), maxmalq );
00715                          }
00716 
00717                       }
00718                 }
00719              }
00720           }
00721 
00722           if ( !operationLimiter || operationLimiter->allowDocking() ) {
00723              int dock = actmap->getField(N.h)->getContainer()->vehicleDocking(veh, true );
00724              for ( int dir = 0; dir < 6; dir++ ) {
00725                 if ( dock ) {
00726                    for ( int dir = 0; dir < 6; dir++ ) {
00727                       MapCoordinate3D pos = getNeighbouringFieldCoordinate ( N.h, dir );
00728                       MapField* fld = actmap->getField( pos );
00729                       if ( fld && fld->getContainer() && ( fld->getContainer() != actmap->getField(N.h)->getContainer() ))
00730                          if ( fld->getContainer()->vehicleDocking(veh, false ) & dock )
00731                             if ( fld->getContainer()->getOwner() == actmap->getField(N.h)->getContainer()->getOwner() 
00732                                  && veh->getMap()->getPlayer(veh).diplomacy.isAllied( fld->getContainer() ))
00733                                if ( !fld->building || (fld->bdt & getTerrainBitType(cbbuildingentry) ).any()) {
00734                                   Node N2 = N;
00735                                   N2.h.setnum ( pos.x, pos.y, -1);
00736                                   N2.canStop = true;
00737                                   N2.gval = N.gval + 10;
00738                                   N2.hval = dist ( N2.h, B );
00739                                   nodeVisited ( N2, HexDirection(dir), open );
00740                                }
00741                    }
00742                 }
00743             }
00744           }
00745 
00746 
00747         } else {
00748            // the unit is not inside a container
00749 
00750            const int* directions;
00751            if ( B.begin()->valid() ) {
00752               directions = getDirectionOrder ( N.h.x, N.h.y, B.begin()->x, B.begin()->y );
00753            } else {
00754               static const int d[6] = {0,1,2,3,4,5};
00755               directions = d;
00756            }
00757 
00758            if ( !operationLimiter || operationLimiter->allowMovement() )
00759               for( int dci = 0; dci < 6; dci++ ) {
00760 
00761                   HexDirection dir = HexDirection(directions[dci]);
00762                   MapCoordinate3D hn = getNeighbouringFieldCoordinate ( N.h, dir );
00763 
00764                   // If it's off the end of the map, then don't keep scanning
00765                   if( hn.x < 0 || hn.y < 0 || hn.x >= actmap->xsize || hn.y >= actmap->ysize || !fieldAccessible ( actmap->getField ( hn ), veh, hn.getBitmappedHeight() ))
00766                       continue;
00767 
00768                   // cursor.gotoxy ( hn.m, hn.n );
00769 
00770                   Node N2;
00771                   N2.hasAttacked = N.hasAttacked;
00772                   DistanceType k = getMoveCost( N.h, hn, veh, N2.canStop, N2.hasAttacked );
00773 
00774                   if ( k <= 0 )
00775                      k = 1;
00776                   N2.h = hn;
00777 
00778                   if ( k >= longestPath )
00779                      N2.gval = longestPath;
00780                   else
00781                      N2.gval = N.gval + k;
00782 
00783                   N2.hval = dist( N2.h,B);
00784 
00785                   if ( N2.canStop && actmap->getField(N2.h)->getContainer() && actmap->getField(N2.h)->vehicle != veh) {
00786                      // there's an container on the field that can be entered. This means, the unit can't stop 'over' the container...
00787                      if ( !veh->typ->hasFunction( ContainerBaseType::OnlyMoveToAndFromTransports  ) ) {
00788                         N2.canStop = false;
00789                         nodeVisited ( N2, dir, open );
00790                      }
00791 
00792                      // ... only inside it
00793                      N2.canStop = true;
00794                      N2.enterHeight = N2.h.getNumericalHeight() ;
00795                      N2.h.setnum ( N2.h.x, N2.h.y, -1 );
00796                      // N2.hasAttacked = true;
00797                      nodeVisited ( N2, dir, open, N.h.getNumericalHeight(), maxmalq );
00798                   } else
00799                      if ( !veh->typ->hasFunction( ContainerBaseType::OnlyMoveToAndFromTransports  ) )
00800                         nodeVisited ( N2, dir, open );
00801               }
00802 
00803            // and now change the units' height. That's only possible on fields where the unit can stop it's movement
00804 
00805 
00806               if ( (!operationLimiter || operationLimiter->allowHeightChange()) && !(veh->typ->hasFunction( ContainerBaseType::OnlyMoveToAndFromTransports  )) )
00807               if ( (fieldAccessible ( actmap->getField(N.h), veh, N.h.getBitmappedHeight() ) == 2 ) || actmap->getgameparameter( cgp_movefrominvalidfields) )
00808                  for ( int heightDelta = -1; heightDelta <= 1; heightDelta += 2 ) {
00809                     const VehicleType::HeightChangeMethod* hcm = veh->getHeightChange( heightDelta, N.h.getBitmappedHeight());
00810                     if ( hcm ) {
00811                        for ( int dir = 0; (dir < 6 && hcm->dist) || (dir < 1 && !hcm->dist); dir++ ) {
00812                           MapCoordinate3D newpos = N.h;
00813                           bool access = true;
00814                           for ( int step = 0; step <= hcm->dist; step++ ) {
00815                              MapField* fld = actmap->getField(newpos);
00816                              if ( !fld ) {
00817                                 access = false;
00818                                 break;
00819                              }
00820 
00821                              if (  !fieldAccessible ( fld, veh, N.h.getBitmappedHeight()) && (actmap->getgameparameter( cgp_movefrominvalidfields)==0 || step>0))
00822                                 access = false;
00823 
00824                              if ( !fieldAccessible( fld, veh, 1 << (N.h.getNumericalHeight() + hcm->heightDelta)) )
00825                                 access = false;
00826 
00827                              if ( fld && fld->building )
00828                                 access = false;
00829 
00830                              if ( step < hcm->dist )
00831                                 getnextfield ( newpos.x, newpos.y, dir );
00832                              else
00833                                 if ( fld && (fld->building || (fld->vehicle && fld->vehicle != veh)))
00834                                    access = false;
00835                           }
00836 
00837                           MapField* fld = actmap->getField( newpos );
00838                           if ( fld && access ) {
00839                              Node N2;
00840                              N2.h.setnum ( newpos.x, newpos.y, N.h.getNumericalHeight() + hcm->heightDelta );
00841                              if ( fieldAccessible( fld, veh, N2.h.getBitmappedHeight() ) == 2 ) {
00842 
00843                                 N2.canStop = true;
00844                                 N2.hasAttacked= N.hasAttacked;
00845                                 N2.gval = N.gval + getMoveCost( N.h, N2.h, veh, N2.canStop, N2.hasAttacked );
00846 
00847                                 if ( actmap->getField(N2.h)->getContainer() && actmap->getField(N2.h)->vehicle != veh ) {
00848                                    N2.enterHeight = N2.h.getNumericalHeight() ;
00849                                    N2.h.setnum ( N2.h.x, N2.h.y, -1 );
00850                                 }
00851 
00852                                 N2.hval = dist(N2.h,B);
00853                                 nodeVisited ( N2, HexDirection(dir), open, N.h.getNumericalHeight() , hcm->dist * maxmalq );
00854                              }
00855                           }
00856                        }
00857                     }
00858                  }
00859 
00860 
00861         }
00862     }
00863 
00864     if( found && N.gval <= MAXIMUM_PATH_LENGTH && N.gval <= longestPath ) {
00865         // We have found a path, so let's copy it into `path'
00866 
00867         MapCoordinate3D h = endpos;
00868 
00869         path.insert ( path.begin(), PathPoint ( h, int(ceil(N.gval)), N.enterHeight, N.hasAttacked ) );
00870         while( !(h == A) )
00871         {
00872             // tfield* fld = actmap->getField ( h );
00873             HexDirection dir = HexDirection ( getPosDir(h) );
00874 
00875             int prevHeight = getPosHHop(h);
00876             if ( prevHeight == -20 )
00877                fatalError ( "AStar3D : Unknown Position ");
00878             int heightChangeDist = prevHeight / 1000;
00879             prevHeight -= 10 + heightChangeDist * 1000;
00880 
00881             if ( prevHeight > -10  ) {
00882                for ( int i = 0; i < heightChangeDist; i += maxmalq )
00883                   getnextfield ( h.x, h.y, dir );
00884 
00885                h.setnum ( h.x, h.y, prevHeight );
00886             } else
00887                 getnextfield ( h.x, h.y, dir );
00888 
00889             const Node* n = fieldVisited ( h );
00890             path.insert ( path.begin(), PathPoint(h, int(n->gval), n->enterHeight, n->hasAttacked) );
00891         }
00892     }
00893     else
00894     {
00895         // No path
00896     }
00897 }
00898 
00899 void AStar3D::findPath( Path& path, const MapCoordinate3D& dest )
00900 {
00901   vector<MapCoordinate3D> d;
00902   d.push_back ( dest );
00903   findPath ( veh->getPosition3D() , d, path );
00904 }
00905 
00906 void AStar3D::findPath( Path& path, const vector<MapCoordinate3D>& dest )
00907 {
00908   findPath ( veh->getPosition3D(), dest, path );
00909 }
00910 
00911 
00912 void AStar3D::findAllAccessibleFields ( vector<MapCoordinate3D>* path )
00913 {
00914    if ( markTemps )
00915       actmap->cleartemps ( 3 );
00916 
00917    Path dummy;
00918    findPath ( dummy, MapCoordinate3D(actmap->xsize, actmap->ysize, veh->height) );  //this field does not exist...
00919    for ( Container::iterator i = visited.begin(); i != visited.end(); ++i ) {
00920       int& fa = getFieldAccess( i->h );
00921       fa |= i->h.getBitmappedHeight();
00922       if ( markTemps )
00923          actmap->getField ( i->h )->a.temp  |= i->h.getBitmappedHeight();
00924       
00925       if ( path )
00926          path->push_back( i->h );
00927    }
00928    
00929    if ( markTemps )
00930       tempsMarked = actmap;
00931 }
00932 
00933 
00934 
00935 const AStar3D::Node* AStar3D::fieldVisited ( const MapCoordinate3D& pos )
00936 {
00937    Container::iterator i = visited.find( pos );
00938    if ( i != visited.end() )
00939        return &(*i);
00940 
00941    return NULL;
00942 }
00943 
00944 
00945 int& AStar3D::getFieldAccess ( int x, int y )
00946 {
00947    return fieldAccess[x + y * actmap->xsize];
00948 }
00949 
00950 int& AStar3D::getFieldAccess ( const MapCoordinate& mc )
00951 {
00952    return fieldAccess[mc.x + mc.y * actmap->xsize];
00953 }
00954 
00955              
00956 void AStar3D::PathPoint::write( tnstream& stream ) const
00957 {
00958    stream.writeInt(1);
00959    MapCoordinate::write( stream );
00960    stream.writeInt( dist );
00961    stream.writeInt( enterHeight );
00962    stream.writeInt( hasAttacked );
00963 }
00964 
00965 void AStar3D::PathPoint::read( tnstream& stream )
00966 {
00967    stream.readInt(); // version  
00968    MapCoordinate::read ( stream );
00969    dist = stream.readInt();
00970    enterHeight = stream.readInt(),
00971    hasAttacked = stream.readInt();
00972 }
00973 
00974 
00975 AStar3D::PathPoint AStar3D::PathPoint::newFromStream( tnstream& stream )
00976 {
00977    PathPoint pp;
00978    pp.read(stream);
00979    return pp;  
00980 }
00981 

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