Пример #1
0
	/** 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;
	}
Пример #2
0
/**
 * Returns the driveable Trackdirs on a tile.
 *
 * One-way-roads are taken into account. Signals are not tested.
 *
 * @param dst_tile The tile of interest.
 * @param src_trackdir The direction the vehicle is currently moving.
 * @param type The transporttype of the vehicle.
 * @param subtype For TRANSPORT_ROAD the compatible RoadTypes of the vehicle.
 * @return The Trackdirs the vehicle can continue moving on.
 */
static TrackdirBits GetDriveableTrackdirBits(TileIndex dst_tile, Trackdir src_trackdir, TransportType type, uint subtype)
{
	TrackdirBits trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(dst_tile, type, subtype));

	if (trackdirbits == 0 && type == TRANSPORT_ROAD && HasBit(subtype, ROADTYPE_TRAM)) {
		/* GetTileTrackStatus() returns 0 for single tram bits.
		 * As we cannot change it there (easily) without breaking something, change it here */
		switch (GetSingleTramBit(dst_tile)) {
			case DIAGDIR_NE:
			case DIAGDIR_SW:
				trackdirbits = TRACKDIR_BIT_X_NE | TRACKDIR_BIT_X_SW;
				break;

			case DIAGDIR_NW:
			case DIAGDIR_SE:
				trackdirbits = TRACKDIR_BIT_Y_NW | TRACKDIR_BIT_Y_SE;
				break;

			default: break;
		}
	}

	DEBUG(npf, 4, "Next node: (%d, %d) [%d], possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), dst_tile, trackdirbits);

	/* Select only trackdirs we can reach from our current trackdir */
	trackdirbits &= TrackdirReachesTrackdirs(src_trackdir);

	/* Filter out trackdirs that would make 90 deg turns for trains */
	if (_settings_game.pf.forbid_90_deg && (type == TRANSPORT_RAIL || type == TRANSPORT_WATER)) trackdirbits &= ~TrackdirCrossesTrackdirs(src_trackdir);

	DEBUG(npf, 6, "After filtering: (%d, %d), possible trackdirs: 0x%X", TileX(dst_tile), TileY(dst_tile), trackdirbits);

	return trackdirbits;
}
Пример #3
0
	/**
	 * Check whether a ship should reverse to reach its destination.
	 * Called when leaving depot.
	 * @param v Ship
	 * @param tile Current position
	 * @param td1 Forward direction
	 * @param td2 Reverse direction
	 * @return true if the reverse direction is better
	 */
	static bool CheckShipReverse(const Ship *v, TileIndex tile, Trackdir td1, Trackdir td2)
	{
		/* 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(tile, TrackdirToTrackdirBits(td1) | TrackdirToTrackdirBits(td2));
		pf.SetDestination(v->dest_tile, dest_trackdirs);
		/* find best path */
		if (!pf.FindPath(v)) return false;

		Node *pNode = pf.GetBestNode();
		if (pNode == NULL) return false;

		/* path was found
		 * walk through the path back to the origin */
		while (pNode->m_parent != NULL) {
			pNode = pNode->m_parent;
		}

		Trackdir best_trackdir = pNode->GetTrackdir();
		assert(best_trackdir == td1 || best_trackdir == td2);
		return best_trackdir == td2;
	}
Пример #4
0
	void SetDestination(const Train *v)
	{
		switch (v->current_order.GetType()) {
			case OT_GOTO_WAYPOINT:
				if (!Waypoint::Get(v->current_order.GetDestination())->IsSingleTile()) {
					/* In case of 'complex' waypoints we need to do a look
					 * ahead. This look ahead messes a bit about, which
					 * means that it 'corrupts' the cache. To prevent this
					 * we disable caching when we're looking for a complex
					 * waypoint. */
					Yapf().DisableCache(true);
				}
				/* FALL THROUGH */
			case OT_GOTO_STATION:
				m_destTile = CalcClosestStationTile(v->current_order.GetDestination(), v->tile, v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT);
				m_dest_station_id = v->current_order.GetDestination();
				m_destTrackdirs = INVALID_TRACKDIR_BIT;
				break;

			default:
				m_destTile = v->dest_tile;
				m_dest_station_id = INVALID_STATION;
				m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_RAIL, 0));
				break;
		}
		CYapfDestinationRailBase::SetDestination(v);
	}
Пример #5
0
 /** Return true if the valid origin (tile/trackdir) was set from the current vehicle position. */
 inline bool SetOriginFromVehiclePos(const RoadVehicle *v)
 {
     /* set origin (tile, trackdir) */
     TileIndex src_tile = v->tile;
     Trackdir src_td = v->GetVehicleTrackdir();
     if ((TrackStatusToTrackdirBits(GetTileTrackStatus(src_tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(src_td)) == 0) {
         /* sometimes the roadveh is not on the road (it resides on non-existing track)
          * how should we handle that situation? */
         return false;
     }
     Yapf().SetOrigin(src_tile, TrackdirToTrackdirBits(src_td));
     return true;
 }
Пример #6
0
 void SetDestination(const RoadVehicle *v)
 {
     if (v->current_order.IsType(OT_GOTO_STATION)) {
         m_dest_station  = v->current_order.GetDestination();
         m_bus           = v->IsBus();
         m_destTile      = CalcClosestStationTile(m_dest_station, v->tile, m_bus ? STATION_BUS : STATION_TRUCK);
         m_non_artic     = !v->HasArticulatedPart();
         m_destTrackdirs = INVALID_TRACKDIR_BIT;
     } else {
         m_dest_station  = INVALID_STATION;
         m_destTile      = v->dest_tile;
         m_destTrackdirs = TrackStatusToTrackdirBits(GetTileTrackStatus(v->dest_tile, TRANSPORT_ROAD, v->compatible_roadtypes));
     }
 }
Пример #7
0
	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;
	}
Пример #8
0
	/**
	 * 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;
	}
Пример #9
0
FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_distance)
{
	TileIndex tile = v->tile;
	Trackdir trackdir = v->GetVehicleTrackdir();
	if (!HasTrackdir(TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)), trackdir)) {
		return FindDepotData();
	}

	/* default is YAPF type 2 */
	typedef FindDepotData (*PfnFindNearestDepot)(const RoadVehicle*, TileIndex, Trackdir, int);
	PfnFindNearestDepot pfnFindNearestDepot = &CYapfRoadAnyDepot2::stFindNearestDepot;

	/* check if non-default YAPF type should be used */
	if (_settings_game.pf.yapf.disable_node_optimization) {
		pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot; // Trackdir
	}

	return pfnFindNearestDepot(v, tile, trackdir, max_distance);
}
Пример #10
0
    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;
    }
Пример #11
0
FindDepotData YapfRoadVehicleFindNearestDepot(const RoadVehicle *v, int max_distance)
{
    TileIndex tile = v->tile;
    Trackdir trackdir = v->GetVehicleTrackdir();
    if ((TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_ROAD, v->compatible_roadtypes)) & TrackdirToTrackdirBits(trackdir)) == 0) {
        return FindDepotData();
    }

    /* default is YAPF type 2 */
    typedef bool (*PfnFindNearestDepot)(const RoadVehicle*, TileIndex, Trackdir, int, TileIndex*);
    PfnFindNearestDepot pfnFindNearestDepot = &CYapfRoadAnyDepot2::stFindNearestDepot;

    /* check if non-default YAPF type should be used */
    if (_settings_game.pf.yapf.disable_node_optimization) {
        pfnFindNearestDepot = &CYapfRoadAnyDepot1::stFindNearestDepot; // Trackdir, allow 90-deg
    }

    FindDepotData fdd;
    bool ret = pfnFindNearestDepot(v, tile, trackdir, max_distance, &fdd.tile);
    fdd.best_length = ret ? max_distance / 2 : UINT_MAX; // some fake distance or NOT_FOUND
    return fdd;
}