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

astar2.cpp

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

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