yapf_ship.cpp

Go to the documentation of this file.
00001 /* $Id: yapf_ship.cpp 18374 2009-12-02 10:47:18Z rubidium $ */
00002 
00003 /*
00004  * This file is part of OpenTTD.
00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
00008  */
00009 
00012 #include "../../stdafx.h"
00013 #include "../../ship.h"
00014 
00015 #include "yapf.hpp"
00016 
00018 template <class Types>
00019 class CYapfFollowShipT
00020 {
00021 public:
00022   typedef typename Types::Tpf Tpf;                     
00023   typedef typename Types::TrackFollower TrackFollower;
00024   typedef typename Types::NodeList::Titem Node;        
00025   typedef typename Node::Key Key;                      
00026 
00027 protected:
00029   FORCEINLINE Tpf& Yapf()
00030   {
00031     return *static_cast<Tpf*>(this);
00032   }
00033 
00034 public:
00038   inline void PfFollowNode(Node& old_node)
00039   {
00040     TrackFollower F(Yapf().GetVehicle());
00041     if (F.Follow(old_node.m_key.m_tile, old_node.m_key.m_td)) {
00042       Yapf().AddMultipleNodes(&old_node, F);
00043     }
00044   }
00045 
00047   FORCEINLINE char TransportTypeChar() const
00048   {
00049     return 'w';
00050   }
00051 
00052   static Trackdir ChooseShipTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
00053   {
00054     /* handle special case - when next tile is destination tile */
00055     if (tile == v->dest_tile) {
00056       /* convert tracks to trackdirs */
00057       TrackdirBits trackdirs = (TrackdirBits)(tracks | ((int)tracks << 8));
00058       /* choose any trackdir reachable from enterdir */
00059       trackdirs &= DiagdirReachesTrackdirs(enterdir);
00060       return (Trackdir)FindFirstBit2x64(trackdirs);
00061     }
00062 
00063     /* move back to the old tile/trackdir (where ship is coming from) */
00064     TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir)));
00065     Trackdir trackdir = v->GetVehicleTrackdir();
00066     assert(IsValidTrackdir(trackdir));
00067 
00068     /* convert origin trackdir to TrackdirBits */
00069     TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
00070     /* get available trackdirs on the destination tile */
00071     TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
00072 
00073     /* create pathfinder instance */
00074     Tpf pf;
00075     /* set origin and destination nodes */
00076     pf.SetOrigin(src_tile, trackdirs);
00077     pf.SetDestination(v->dest_tile, dest_trackdirs);
00078     /* find best path */
00079     pf.FindPath(v);
00080 
00081     Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found"
00082 
00083     Node *pNode = pf.GetBestNode();
00084     if (pNode != NULL) {
00085       /* walk through the path back to the origin */
00086       Node *pPrevNode = NULL;
00087       while (pNode->m_parent != NULL) {
00088         pPrevNode = pNode;
00089         pNode = pNode->m_parent;
00090       }
00091       /* return trackdir from the best next node (direct child of origin) */
00092       Node& best_next_node = *pPrevNode;
00093       assert(best_next_node.GetTile() == tile);
00094       next_trackdir = best_next_node.GetTrackdir();
00095     }
00096     return next_trackdir;
00097   }
00098 };
00099 
00101 template <class Types>
00102 class CYapfCostShipT
00103 {
00104 public:
00105   typedef typename Types::Tpf Tpf;              
00106   typedef typename Types::TrackFollower TrackFollower;
00107   typedef typename Types::NodeList::Titem Node; 
00108   typedef typename Node::Key Key;               
00109 
00110 protected:
00112   Tpf& Yapf()
00113   {
00114     return *static_cast<Tpf*>(this);
00115   }
00116 
00117 public:
00121   FORCEINLINE bool PfCalcCost(Node& n, const TrackFollower *tf)
00122   {
00123     /* base tile cost depending on distance */
00124     int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH;
00125     /* additional penalty for curves */
00126     if (n.m_parent != NULL && n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
00127       /* new trackdir does not match the next one when going straight */
00128       c += YAPF_TILE_LENGTH;
00129     }
00130 
00131     c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
00132 
00133     /* apply it */
00134     n.m_cost = n.m_parent->m_cost + c;
00135     return true;
00136   }
00137 };
00138 
00142 template <class Tpf_, class Ttrack_follower, class Tnode_list>
00143 struct CYapfShip_TypesT
00144 {
00146   typedef CYapfShip_TypesT<Tpf_, Ttrack_follower, Tnode_list>  Types;
00147 
00149   typedef Tpf_                              Tpf;
00151   typedef Ttrack_follower                   TrackFollower;
00153   typedef Tnode_list                        NodeList;
00154   typedef Ship                              VehicleType;
00156   typedef CYapfBaseT<Types>                 PfBase;        // base pathfinder class
00157   typedef CYapfFollowShipT<Types>           PfFollow;      // node follower
00158   typedef CYapfOriginTileT<Types>           PfOrigin;      // origin provider
00159   typedef CYapfDestinationTileT<Types>      PfDestination; // destination/distance provider
00160   typedef CYapfSegmentCostCacheNoneT<Types> PfCache;       // segment cost cache provider
00161   typedef CYapfCostShipT<Types>             PfCost;        // cost provider
00162 };
00163 
00164 /* YAPF type 1 - uses TileIndex/Trackdir as Node key, allows 90-deg turns */
00165 struct CYapfShip1 : CYapfT<CYapfShip_TypesT<CYapfShip1, CFollowTrackWater    , CShipNodeListTrackDir> > {};
00166 /* YAPF type 2 - uses TileIndex/DiagDirection as Node key, allows 90-deg turns */
00167 struct CYapfShip2 : CYapfT<CYapfShip_TypesT<CYapfShip2, CFollowTrackWater    , CShipNodeListExitDir > > {};
00168 /* YAPF type 3 - uses TileIndex/Trackdir as Node key, forbids 90-deg turns */
00169 struct CYapfShip3 : CYapfT<CYapfShip_TypesT<CYapfShip3, CFollowTrackWaterNo90, CShipNodeListTrackDir> > {};
00170 
00172 Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
00173 {
00174   /* default is YAPF type 2 */
00175   typedef Trackdir (*PfnChooseShipTrack)(const Ship*, TileIndex, DiagDirection, TrackBits);
00176   PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack; // default: ExitDir, allow 90-deg
00177 
00178   /* check if non-default YAPF type needed */
00179   if (_settings_game.pf.forbid_90_deg) {
00180     pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack; // Trackdir, forbid 90-deg
00181   } else if (_settings_game.pf.yapf.disable_node_optimization) {
00182     pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack; // Trackdir, allow 90-deg
00183   }
00184 
00185   Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks);
00186   return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : INVALID_TRACK;
00187 }

Generated on Thu Feb 4 17:20:27 2010 for OpenTTD by  doxygen 1.5.6