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
00020
00021
00022
00023
00024
00025
00026
00027 bool operator < ( const AStar::Node& a, const AStar::Node& b )
00028 {
00029
00030
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
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 _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
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 ( 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 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
00156 N.h = A;
00157 N.gval = 0;
00158 N.hval = dist(A,B);
00159 open.push_back(N);
00160 }
00161
00162
00163
00164
00165
00166
00167 while( !open.empty() )
00168 {
00169 get_first( open, N );
00170 visited.push_back( N );
00171
00172 if( N.h == B )
00173 break;
00174
00175
00176
00177
00178
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
00189 for( int dci = 0; dci < 6; dci++ )
00190 {
00191 #if 0
00192 {
00193
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
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
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
00221 if( getfield (hn.m,hn.n)->temp3 == DirNone ) {
00222
00223
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
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
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
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
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
00273
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
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 );
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
00353
00354
00355
00356 }
00357
00358
00359
00360
00365
00366
00367 bool AStar3D::Node::operator< ( const AStar3D::Node& b ) const
00368 {
00369
00370
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
00379
00380
00381
00382
00383
00384
00385
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
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
00445
00446
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
00527
00528
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
00556
00557
00558
00559
00560
00561
00562
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
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
00638
00639
00640 bool found = false;
00641 MapCoordinate3D endpos;
00642
00643
00644 while( !open.empty() ) {
00645 N = open.getFirst();
00646
00647 visited.add( N );
00648
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
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
00687
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
00699 N2.canStop = false;
00700 nodeVisited ( N2, HexDirection(dir), open, N.h.getNumericalHeight(), maxmalq );
00701
00702
00703 N2.canStop = true;
00704 N2.enterHeight = N2.h.getNumericalHeight() ;
00705 N2.h.setnum ( N2.h.x, N2.h.y, -1 );
00706
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
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
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
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
00782 if ( !veh->typ->hasFunction( ContainerBaseType::OnlyMoveToAndFromTransports ) ) {
00783 N2.canStop = false;
00784 nodeVisited ( N2, dir, open );
00785 }
00786
00787
00788 N2.canStop = true;
00789 N2.enterHeight = N2.h.getNumericalHeight() ;
00790 N2.h.setnum ( N2.h.x, N2.h.y, -1 );
00791
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
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
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
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
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) );
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 }