/** main follower routine. Fills all members and return true on success. * Otherwise returns false if track can't be followed. */ inline bool Follow(TileIndex old_tile, Trackdir old_td) { m_old_tile = old_tile; m_old_td = old_td; m_err = EC_NONE; assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), IsRoadTT() && m_veh != NULL ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)) & TrackdirToTrackdirBits(m_old_td)) != 0) || (IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR)); // Disable the assertion for single tram bits m_exitdir = TrackdirToExitdir(m_old_td); if (ForcedReverse()) return true; if (!CanExitOldTile()) return false; FollowTileExit(); if (!QueryNewTileTrackStatus()) return TryReverse(); if (!CanEnterNewTile()) return false; m_new_td_bits &= DiagdirReachesTrackdirs(m_exitdir); if (m_new_td_bits == TRACKDIR_BIT_NONE) { m_err = EC_NO_WAY; return false; } if (!Allow90degTurns()) { m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td); if (m_new_td_bits == TRACKDIR_BIT_NONE) { m_err = EC_90DEG; return false; } } return true; }
static Trackdir ChooseShipTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found) { /* handle special case - when next tile is destination tile */ if (tile == v->dest_tile) { /* convert tracks to trackdirs */ TrackdirBits trackdirs = (TrackdirBits)(tracks | ((int)tracks << 8)); /* limit to trackdirs reachable from enterdir */ trackdirs &= DiagdirReachesTrackdirs(enterdir); /* use vehicle's current direction if that's possible, otherwise use first usable one. */ Trackdir veh_dir = v->GetVehicleTrackdir(); return ((trackdirs & TrackdirToTrackdirBits(veh_dir)) != 0) ? veh_dir : (Trackdir)FindFirstBit2x64(trackdirs); } /* move back to the old tile/trackdir (where ship is coming from) */ TileIndex src_tile = TILE_ADD(tile, TileOffsByDiagDir(ReverseDiagDir(enterdir))); Trackdir trackdir = v->GetVehicleTrackdir(); assert(IsValidTrackdir(trackdir)); /* convert origin trackdir to TrackdirBits */ TrackdirBits trackdirs = TrackdirToTrackdirBits(trackdir); /* get available trackdirs on the destination tile */ TrackdirBits dest_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_WATER, 0)); /* create pathfinder instance */ Tpf pf; /* set origin and destination nodes */ pf.SetOrigin(src_tile, trackdirs); pf.SetDestination(v->dest_tile, dest_trackdirs); /* find best path */ path_found = pf.FindPath(v); Trackdir next_trackdir = INVALID_TRACKDIR; // this would mean "path not found" Node *pNode = pf.GetBestNode(); if (pNode != NULL) { /* walk through the path back to the origin */ Node *pPrevNode = NULL; while (pNode->m_parent != NULL) { pPrevNode = pNode; pNode = pNode->m_parent; } /* return trackdir from the best next node (direct child of origin) */ Node& best_next_node = *pPrevNode; assert(best_next_node.GetTile() == tile); next_trackdir = best_next_node.GetTrackdir(); } return next_trackdir; }
/** * main follower routine. Fills all members and return true on success. * Otherwise returns false if track can't be followed. */ inline bool Follow(TileIndex old_tile, Trackdir old_td) { m_old_tile = old_tile; m_old_td = old_td; m_err = EC_NONE; assert( ((TrackStatusToTrackdirBits( GetTileTrackStatus(m_old_tile, TT(), (IsRoadTT() && m_veh != NULL) ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0) ) & TrackdirToTrackdirBits(m_old_td)) != 0) || (IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR) // Disable the assertion for single tram bits ); m_exitdir = TrackdirToExitdir(m_old_td); if (ForcedReverse()) return true; if (!CanExitOldTile()) return false; FollowTileExit(); if (!QueryNewTileTrackStatus()) return TryReverse(); m_new_td_bits &= DiagdirReachesTrackdirs(m_exitdir); if (m_new_td_bits == TRACKDIR_BIT_NONE || !CanEnterNewTile()) { /* In case we can't enter the next tile, but are * a normal road vehicle, then we can actually * try to reverse as this is the end of the road. * Trams can only turn on the appropriate bits in * which case reaching this would mean a dead end * near a building and in that case there would * a "false" QueryNewTileTrackStatus result and * as such reversing is already tried. The fact * that function failed can have to do with a * missing road bit, or inability to connect the * different bits due to slopes. */ if (IsRoadTT() && !IsTram() && TryReverse()) return true; /* CanEnterNewTile already set a reason. * Do NOT overwrite it (important for example for EC_RAIL_TYPE). * Only set a reason if CanEnterNewTile was not called */ if (m_new_td_bits == TRACKDIR_BIT_NONE) m_err = EC_NO_WAY; return false; } if (!Allow90degTurns()) { m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td); if (m_new_td_bits == TRACKDIR_BIT_NONE) { m_err = EC_90DEG; return false; } } return true; }
inline Trackdir ChooseRoadTrack(const RoadVehicle *v, TileIndex tile, DiagDirection enterdir, bool &path_found) { /* Handle special case - when next tile is destination tile. * However, when going to a station the (initial) destination * tile might not be a station, but a junction, in which case * this method forces the vehicle to jump in circles. */ if (tile == v->dest_tile && !v->current_order.IsType(OT_GOTO_STATION)) { /* choose diagonal trackdir reachable from enterdir */ return DiagDirToDiagTrackdir(enterdir); } /* our source tile will be the next vehicle tile (should be the given one) */ TileIndex src_tile = tile; /* get available trackdirs on the start tile */ TrackdirBits src_trackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)); /* select reachable trackdirs only */ src_trackdirs &= DiagdirReachesTrackdirs(enterdir); /* set origin and destination nodes */ Yapf().SetOrigin(src_tile, src_trackdirs); Yapf().SetDestination(v); /* find the best path */ path_found = Yapf().FindPath(v); /* if path not found - return INVALID_TRACKDIR */ Trackdir next_trackdir = INVALID_TRACKDIR; Node *pNode = Yapf().GetBestNode(); if (pNode != NULL) { /* path was found or at least suggested * walk through the path back to its origin */ while (pNode->m_parent != NULL) { pNode = pNode->m_parent; } /* return trackdir from the best origin node (one of start nodes) */ Node& best_next_node = *pNode; assert(best_next_node.GetTile() == tile); next_trackdir = best_next_node.GetTrackdir(); } return next_trackdir; }