00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../../stdafx.h"
00013 #include "../../ship.h"
00014
00015 #include "yapf.hpp"
00016 #include "yapf_node_ship.hpp"
00017
00019 template <class Types>
00020 class CYapfFollowShipT
00021 {
00022 public:
00023 typedef typename Types::Tpf Tpf;
00024 typedef typename Types::TrackFollower TrackFollower;
00025 typedef typename Types::NodeList::Titem Node;
00026 typedef typename Node::Key Key;
00027
00028 protected:
00030 inline Tpf& Yapf()
00031 {
00032 return *static_cast<Tpf*>(this);
00033 }
00034
00035 public:
00041 inline void PfFollowNode(Node& old_node)
00042 {
00043 TrackFollower F(Yapf().GetVehicle());
00044 if (F.Follow(old_node.m_key.m_tile, old_node.m_key.m_td)) {
00045 Yapf().AddMultipleNodes(&old_node, F);
00046 }
00047 }
00048
00050 inline char TransportTypeChar() const
00051 {
00052 return 'w';
00053 }
00054
00055 static Trackdir ChooseShipTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found)
00056 {
00057
00058 if (tile == v->dest_tile) {
00059
00060 TrackdirBits trackdirs = (TrackdirBits)(tracks | ((int)tracks << 8));
00061
00062 trackdirs &= DiagdirReachesTrackdirs(enterdir);
00063
00064
00065 Trackdir veh_dir = v->GetVehicleTrackdir();
00066 return ((trackdirs & TrackdirToTrackdirBits(veh_dir)) != 0) ? veh_dir : (Trackdir)FindFirstBit2x64(trackdirs);
00067 }
00068
00069
00070 TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir)));
00071 Trackdir trackdir = v->GetVehicleTrackdir();
00072 assert(IsValidTrackdir(trackdir));
00073
00074
00075 TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir);
00076
00077 TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
00078
00079
00080 Tpf pf;
00081
00082 pf.SetOrigin(src_tile, trackdirs);
00083 pf.SetDestination(v->dest_tile, dest_trackdirs);
00084
00085 path_found = pf.FindPath(v);
00086
00087 Trackdir next_trackdir = INVALID_TRACKDIR;
00088
00089 Node *pNode = pf.GetBestNode();
00090 if (pNode != NULL) {
00091
00092 Node *pPrevNode = NULL;
00093 while (pNode->m_parent != NULL) {
00094 pPrevNode = pNode;
00095 pNode = pNode->m_parent;
00096 }
00097
00098 Node& best_next_node = *pPrevNode;
00099 assert(best_next_node.GetTile() == tile);
00100 next_trackdir = best_next_node.GetTrackdir();
00101 }
00102 return next_trackdir;
00103 }
00104
00114 static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2)
00115 {
00116
00117 TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0));
00118
00119
00120 Tpf pf;
00121
00122 pf.SetOrigin(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2));
00123 pf.SetDestination(v->dest_tile, dest_trackdirs);
00124
00125 if (!pf.FindPath(v)) return false;
00126
00127 Node *pNode = pf.GetBestNode();
00128 if (pNode == NULL) return false;
00129
00130
00131
00132 while (pNode->m_parent != NULL) {
00133 pNode = pNode->m_parent;
00134 }
00135
00136 Trackdir best_trackdir = pNode->GetTrackdir();
00137 assert(best_trackdir == td1 || best_trackdir == td2);
00138 return best_trackdir == td2;
00139 }
00140 };
00141
00143 template <class Types>
00144 class CYapfCostShipT
00145 {
00146 public:
00147 typedef typename Types::Tpf Tpf;
00148 typedef typename Types::TrackFollower TrackFollower;
00149 typedef typename Types::NodeList::Titem Node;
00150 typedef typename Node::Key Key;
00151
00152 protected:
00154 Tpf& Yapf()
00155 {
00156 return *static_cast<Tpf*>(this);
00157 }
00158
00159 public:
00165 inline bool PfCalcCost(Node& n, const TrackFollower *tf)
00166 {
00167
00168 int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH;
00169
00170 if (n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
00171
00172 c += YAPF_TILE_LENGTH;
00173 }
00174
00175
00176 c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;
00177
00178
00179 const ShipVehicleInfo *svi = ShipVehInfo(Yapf().GetVehicle()->engine_type);
00180 byte speed_frac = (GetEffectiveWaterClass(n.GetTile()) == WATER_CLASS_SEA) ? svi->ocean_speed_frac : svi->canal_speed_frac;
00181 if (speed_frac > 0) c += YAPF_TILE_LENGTH * (1 + tf->m_tiles_skipped) * speed_frac / (256 - speed_frac);
00182
00183
00184 n.m_cost = n.m_parent->m_cost + c;
00185 return true;
00186 }
00187 };
00188
00193 template <class Tpf_, class Ttrack_follower, class Tnode_list>
00194 struct CYapfShip_TypesT
00195 {
00197 typedef CYapfShip_TypesT<Tpf_, Ttrack_follower, Tnode_list> Types;
00198
00200 typedef Tpf_ Tpf;
00202 typedef Ttrack_follower TrackFollower;
00204 typedef Tnode_list NodeList;
00205 typedef Ship VehicleType;
00207 typedef CYapfBaseT<Types> PfBase;
00208 typedef CYapfFollowShipT<Types> PfFollow;
00209 typedef CYapfOriginTileT<Types> PfOrigin;
00210 typedef CYapfDestinationTileT<Types> PfDestination;
00211 typedef CYapfSegmentCostCacheNoneT<Types> PfCache;
00212 typedef CYapfCostShipT<Types> PfCost;
00213 };
00214
00215
00216 struct CYapfShip1 : CYapfT<CYapfShip_TypesT<CYapfShip1, CFollowTrackWater , CShipNodeListTrackDir> > {};
00217
00218 struct CYapfShip2 : CYapfT<CYapfShip_TypesT<CYapfShip2, CFollowTrackWater , CShipNodeListExitDir > > {};
00219
00220 struct CYapfShip3 : CYapfT<CYapfShip_TypesT<CYapfShip3, CFollowTrackWaterNo90, CShipNodeListTrackDir> > {};
00221
00223 Track YapfShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found)
00224 {
00225
00226 typedef Trackdir (*PfnChooseShipTrack)(const Ship*, TileIndex, DiagDirection, TrackBits, bool &path_found);
00227 PfnChooseShipTrack pfnChooseShipTrack = CYapfShip2::ChooseShipTrack;
00228
00229
00230 if (_settings_game.pf.forbid_90_deg) {
00231 pfnChooseShipTrack = &CYapfShip3::ChooseShipTrack;
00232 } else if (_settings_game.pf.yapf.disable_node_optimization) {
00233 pfnChooseShipTrack = &CYapfShip1::ChooseShipTrack;
00234 }
00235
00236 Trackdir td_ret = pfnChooseShipTrack(v, tile, enterdir, tracks, path_found);
00237 return (td_ret != INVALID_TRACKDIR) ? TrackdirToTrack(td_ret) : INVALID_TRACK;
00238 }
00239
00240 bool YapfShipCheckReverse(const Ship *v)
00241 {
00242 Trackdir td = v->GetVehicleTrackdir();
00243 Trackdir td_rev = ReverseTrackdir(td);
00244 TileIndex tile = v->tile;
00245
00246 typedef bool (*PfnCheckReverseShip)(const Ship*, TileIndex, Trackdir, Trackdir);
00247 PfnCheckReverseShip pfnCheckReverseShip = CYapfShip2::CheckShipReverse;
00248
00249
00250 if (_settings_game.pf.forbid_90_deg) {
00251 pfnCheckReverseShip = &CYapfShip3::CheckShipReverse;
00252 } else if (_settings_game.pf.yapf.disable_node_optimization) {
00253 pfnCheckReverseShip = &CYapfShip1::CheckShipReverse;
00254 }
00255
00256 bool reverse = pfnCheckReverseShip(v, tile, td, td_rev);
00257
00258 return reverse;
00259 }