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
00021
00022
00023
00024
00025
00026
00027 bool AStar::Node::operator< ( const AStar::Node& a ) const
00028 {
00029
00030
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
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
00057
00058
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
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
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
00116
00117
00118
00119
00120
00121
00122
00123
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
00135
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
00155 N.h = A;
00156 N.gval = 0;
00157 N.hval = dist(A,B);
00158 open.push_back(N);
00159 }
00160
00161
00162
00163
00164
00165
00166 while( !open.empty() )
00167 {
00168 get_first( open, N );
00169 visited.push_back( N );
00170
00171 if( N.h == B )
00172 break;
00173
00174
00175
00176
00177
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
00188 for( int dci = 0; dci < 6; dci++ )
00189 {
00190 #if 0
00191 {
00192
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
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
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
00220 if( gamemap->getField (hn.m,hn.n)->temp3 == DirNone ) {
00221
00222
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
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
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
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
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
00272
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
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 );
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
00352
00353
00354
00355 }
00356
00357
00358
00359
00364
00365
00366 bool AStar3D::Node::operator< ( const AStar3D::Node& b ) const
00367 {
00368
00369
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
00378
00379
00380
00381
00382
00383
00384
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
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
00444
00445
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
00532
00533
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
00561
00562
00563
00564
00565
00566
00567
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
00627
00628
00629
00630
00631 if ( actmap->getField(A)->unitHere(veh) ) {
00632
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
00643
00644
00645 bool found = false;
00646 MapCoordinate3D endpos;
00647
00648
00649 while( !open.empty() ) {
00650 N = open.getFirst();
00651
00652 visited.add( N );
00653
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
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
00692
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
00704 N2.canStop = false;
00705 nodeVisited ( N2, HexDirection(dir), open, N.h.getNumericalHeight(), maxmalq );
00706
00707
00708 N2.canStop = true;
00709 N2.enterHeight = N2.h.getNumericalHeight() ;
00710 N2.h.setnum ( N2.h.x, N2.h.y, -1 );
00711
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
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
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
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
00787 if ( !veh->typ->hasFunction( ContainerBaseType::OnlyMoveToAndFromTransports ) ) {
00788 N2.canStop = false;
00789 nodeVisited ( N2, dir, open );
00790 }
00791
00792
00793 N2.canStop = true;
00794 N2.enterHeight = N2.h.getNumericalHeight() ;
00795 N2.h.setnum ( N2.h.x, N2.h.y, -1 );
00796
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
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
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
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
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) );
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();
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