Example #1
0
	inline int CurveCost(Trackdir td1, Trackdir td2)
	{
		assert(IsValidTrackdir(td1));
		assert(IsValidTrackdir(td2));
		int cost = 0;
		if (TrackFollower::Allow90degTurns()
				&& ((TrackdirToTrackdirBits(td2) & (TrackdirBits)TrackdirCrossesTrackdirs(td1)) != 0)) {
			/* 90-deg curve penalty */
			cost += Yapf().PfGetSettings().rail_curve90_penalty;
		} else if (td2 != NextTrackdir(td1)) {
			/* 45-deg curve penalty */
			cost += Yapf().PfGetSettings().rail_curve45_penalty;
		}
		return cost;
	}
Example #2
0
	/** Called by YAPF to calculate the cost from the origin to the given node.
	 *  Calculates only the cost of given node, adds it to the parent node cost
	 *  and stores the result into Node::m_cost member */
	FORCEINLINE bool PfCalcCost(Node& n, const TrackFollower *tf)
	{
		/* base tile cost depending on distance */
		int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH;
		/* additional penalty for curves */
		if (n.m_parent != NULL && n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
			/* new trackdir does not match the next one when going straight */
			c += YAPF_TILE_LENGTH;
		}

		c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;

		/* apply it */
		n.m_cost = n.m_parent->m_cost + c;
		return true;
	}
Example #3
0
static int32 NPFWaterPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
{
	/* TileIndex tile = current->tile; */
	int32 cost = 0;
	Trackdir trackdir = current->direction;

	cost = _trackdir_length[trackdir]; // Should be different for diagonal tracks

	if (IsBuoyTile(current->tile) && IsDiagonalTrackdir(trackdir))
		cost += _settings_game.pf.npf.npf_buoy_penalty; // A small penalty for going over buoys

	if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
		cost += _settings_game.pf.npf.npf_water_curve_penalty;

	/* @todo More penalties? */

	return cost;
}
Example #4
0
	/**
	 * Called by YAPF to calculate the cost from the origin to the given node.
	 *  Calculates only the cost of given node, adds it to the parent node cost
	 *  and stores the result into Node::m_cost member
	 */
	inline bool PfCalcCost(Node& n, const TrackFollower *tf)
	{
		/* base tile cost depending on distance */
		int c = IsDiagonalTrackdir(n.GetTrackdir()) ? YAPF_TILE_LENGTH : YAPF_TILE_CORNER_LENGTH;
		/* additional penalty for curves */
		if (n.GetTrackdir() != NextTrackdir(n.m_parent->GetTrackdir())) {
			/* new trackdir does not match the next one when going straight */
			c += YAPF_TILE_LENGTH;
		}

		/* Skipped tile cost for aqueducts. */
		c += YAPF_TILE_LENGTH * tf->m_tiles_skipped;

		/* Ocean/canal speed penalty. */
		const ShipVehicleInfo *svi = ShipVehInfo(Yapf().GetVehicle()->engine_type);
		byte speed_frac = (GetEffectiveWaterClass(n.GetTile()) == WATER_CLASS_SEA) ? svi->ocean_speed_frac : svi->canal_speed_frac;
		if (speed_frac > 0) c += YAPF_TILE_LENGTH * (1 + tf->m_tiles_skipped) * speed_frac / (256 - speed_frac);

		/* apply it */
		n.m_cost = n.m_parent->m_cost + c;
		return true;
	}
Example #5
0
/* Determine the cost of this node, for railway tracks */
static int32 NPFRailPathCost(AyStar *as, AyStarNode *current, OpenListNode *parent)
{
	TileIndex tile = current->tile;
	Trackdir trackdir = current->direction;
	int32 cost = 0;
	/* HACK: We create a OpenListNode manually, so we can call EndNodeCheck */
	OpenListNode new_node;

	/* Determine base length */
	switch (GetTileType(tile)) {
		case MP_TUNNELBRIDGE:
			cost = IsTunnel(tile) ? NPFTunnelCost(current) : NPFBridgeCost(current);
			break;

		case MP_RAILWAY:
			cost = _trackdir_length[trackdir]; // Should be different for diagonal tracks
			break;

		case MP_ROAD: // Railway crossing
			cost = NPF_TILE_LENGTH;
			break;

		case MP_STATION:
			/* We give a station tile a penalty. Logically we would only want to give
			 * station tiles that are not our destination this penalty. This would
			 * discourage trains to drive through busy stations. But, we can just
			 * give any station tile a penalty, because every possible route will get
			 * this penalty exactly once, on its end tile (if it's a station) and it
			 * will therefore not make a difference. */
			cost = NPF_TILE_LENGTH + _settings_game.pf.npf.npf_rail_station_penalty;

			if (IsRailWaypoint(tile)) {
				NPFFindStationOrTileData *fstd = (NPFFindStationOrTileData*)as->user_target;
				if (fstd->v->current_order.IsType(OT_GOTO_WAYPOINT) && GetStationIndex(tile) == fstd->v->current_order.GetDestination()) {
					/* This waypoint is our destination; maybe this isn't an unreserved
					 * one, so check that and if so see that as the last signal being
					 * red. This way waypoints near stations should work better. */
					const Train *train = Train::From(fstd->v);
					CFollowTrackRail ft(train);
					TileIndex t = tile;
					Trackdir td = trackdir;
					while (ft.Follow(t, td)) {
						assert(t != ft.m_new_tile);
						t = ft.m_new_tile;
						if (KillFirstBit(ft.m_new_td_bits) != TRACKDIR_BIT_NONE) {
							/* We encountered a junction; it's going to be too complex to
							 * handle this perfectly, so just bail out. There is no simple
							 * free path, so try the other possibilities. */
							td = INVALID_TRACKDIR;
							break;
						}
						td = RemoveFirstTrackdir(&ft.m_new_td_bits);
						/* If this is a safe waiting position we're done searching for it */
						if (IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg)) break;
					}
					if (td == INVALID_TRACKDIR ||
							!IsSafeWaitingPosition(train, t, td, true, _settings_game.pf.forbid_90_deg) ||
							!IsWaitingPositionFree(train, t, td, _settings_game.pf.forbid_90_deg)) {
						cost += _settings_game.pf.npf.npf_rail_lastred_penalty;
					}
				}
			}
			break;

		default:
			break;
	}

	/* Determine extra costs */

	/* Check for signals */
	if (IsTileType(tile, MP_RAILWAY)) {
		if (HasSignalOnTrackdir(tile, trackdir)) {
			SignalType sigtype = GetSignalType(tile, TrackdirToTrack(trackdir));
			/* Ordinary track with signals */
			if (GetSignalStateByTrackdir(tile, trackdir) == SIGNAL_STATE_RED) {
				/* Signal facing us is red */
				if (!NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) {
					/* Penalize the first signal we
					 * encounter, if it is red */

					/* Is this a presignal exit or combo? */
					if (!IsPbsSignal(sigtype)) {
						if (sigtype == SIGTYPE_EXIT || sigtype == SIGTYPE_COMBO) {
							/* Penalise exit and combo signals differently (heavier) */
							cost += _settings_game.pf.npf.npf_rail_firstred_exit_penalty;
						} else {
							cost += _settings_game.pf.npf.npf_rail_firstred_penalty;
						}
					}
				}
				/* Record the state of this signal */
				NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, true);
			} else {
				/* Record the state of this signal */
				NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_RED, false);
			}
			if (NPFGetFlag(current, NPF_FLAG_SEEN_SIGNAL)) {
				if (NPFGetFlag(current, NPF_FLAG_2ND_SIGNAL)) {
					NPFSetFlag(current, NPF_FLAG_3RD_SIGNAL, true);
				} else {
					NPFSetFlag(current, NPF_FLAG_2ND_SIGNAL, true);
				}
			} else {
				NPFSetFlag(current, NPF_FLAG_SEEN_SIGNAL, true);
			}
			NPFSetFlag(current, NPF_FLAG_LAST_SIGNAL_BLOCK, !IsPbsSignal(sigtype));
		}

		if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(trackdir)) && !NPFGetFlag(current, NPF_FLAG_3RD_SIGNAL)) {
			cost += _settings_game.pf.npf.npf_rail_pbs_signal_back_penalty;
		}
	}

	/* Penalise the tile if it is a target tile and the last signal was
	 * red */
	/* HACK: We create a new_node here so we can call EndNodeCheck. Ugly as hell
	 * of course... */
	new_node.path.node = *current;
	if (as->EndNodeCheck(as, &new_node) == AYSTAR_FOUND_END_NODE && NPFGetFlag(current, NPF_FLAG_LAST_SIGNAL_RED))
		cost += _settings_game.pf.npf.npf_rail_lastred_penalty;

	/* Check for slope */
	cost += NPFSlopeCost(current);

	/* Check for turns */
	if (current->direction != NextTrackdir((Trackdir)parent->path.node.direction))
		cost += _settings_game.pf.npf.npf_rail_curve_penalty;
	/* TODO, with realistic acceleration, also the amount of straight track between
	 *      curves should be taken into account, as this affects the speed limit. */

	/* Check for reverse in depot */
	if (IsRailDepotTile(tile) && as->EndNodeCheck(as, &new_node) != AYSTAR_FOUND_END_NODE) {
		/* Penalise any depot tile that is not the last tile in the path. This
		 * _should_ penalise every occurence of reversing in a depot (and only
		 * that) */
		cost += _settings_game.pf.npf.npf_rail_depot_reverse_penalty;
	}

	/* Check for occupied track */
	cost += NPFReservedTrackCost(current);

	NPFMarkTile(tile);
	DEBUG(npf, 4, "Calculating G for: (%d, %d). Result: %d", TileX(current->tile), TileY(current->tile), cost);
	return cost;
}