10 #ifndef YAPF_COSTRAIL_HPP
11 #define YAPF_COSTRAIL_HPP
13 #include "../../pbs.h"
15 template <
class Types>
18 typedef typename Types::Tpf
Tpf;
19 typedef typename Types::TrackFollower TrackFollower;
20 typedef typename Types::NodeList::Titem
Node;
21 typedef typename Node::Key
Key;
22 typedef typename Node::CachedData CachedData;
60 bool m_stopped_on_first_two_way_signal;
63 static const int s_max_segment_cost = 10000;
68 int p0 =
Yapf().PfGetSettings().rail_look_ahead_signal_p0;
69 int p1 =
Yapf().PfGetSettings().rail_look_ahead_signal_p1;
70 int p2 =
Yapf().PfGetSettings().rail_look_ahead_signal_p2;
71 int *pen = m_sig_look_ahead_costs.
GrowSizeNC(
Yapf().PfGetSettings().rail_look_ahead_max_signals);
72 for (uint i = 0; i <
Yapf().PfGetSettings().rail_look_ahead_max_signals; i++) {
73 pen[i] = p0 + i * (p1 + i * p2);
80 return *
static_cast<Tpf *
>(
this);
88 return Yapf().PfGetSettings().rail_slope_penalty;
96 if (TrackFollower::Allow90degTurns()
99 cost +=
Yapf().PfGetSettings().rail_curve90_penalty;
102 cost +=
Yapf().PfGetSettings().rail_curve45_penalty;
112 if (t1 && t2)
return Yapf().PfGetSettings().rail_doubleslip_penalty;
128 cost +=
Yapf().PfGetSettings().rail_crossing_penalty;
146 for (; skipped >= 0; skipped--, tile += diff) {
155 if (n.m_num_signals_passed >= m_sig_look_ahead_costs.
Size() / 2)
return 0;
156 if (!IsPbsSignal(n.m_last_signal_type))
return 0;
159 return Yapf().PfGetSettings().rail_pbs_station_penalty * (skipped + 1);
161 int cost =
Yapf().PfGetSettings().rail_pbs_cross_penalty;
163 return cost * (skipped + 1);
178 n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
180 if (has_signal_along) {
184 n.m_last_signal_type = sig_type;
187 int look_ahead_cost = (n.m_num_signals_passed < m_sig_look_ahead_costs.
Size()) ? m_sig_look_ahead_costs.
Data()[n.m_num_signals_passed] : 0;
190 n.flags_u.flags_s.m_last_signal_was_red =
false;
192 if (look_ahead_cost < 0) {
194 cost -= look_ahead_cost;
199 if (!IsPbsSignal(sig_type) &&
Yapf().TreatFirstRedTwoWaySignalAsEOL() && n.flags_u.flags_s.m_choice_seen && has_signal_against && n.m_num_signals_passed == 0) {
201 Yapf().PruneIntermediateNodeBranch();
202 n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
203 Yapf().m_stopped_on_first_two_way_signal =
true;
206 n.m_last_red_signal_type = sig_type;
207 n.flags_u.flags_s.m_last_signal_was_red =
true;
210 if (!IsPbsSignal(sig_type) && look_ahead_cost > 0) {
212 cost += look_ahead_cost;
216 if (n.m_num_signals_passed == 0) {
219 case SIGTYPE_EXIT: cost +=
Yapf().PfGetSettings().rail_firstred_exit_penalty;
break;
227 n.m_num_signals_passed++;
228 n.m_segment->m_last_signal_tile = tile;
229 n.m_segment->m_last_signal_td = trackdir;
232 if (has_signal_against && IsPbsSignal(GetSignalType(tile,
TrackdirToTrack(trackdir)))) {
233 cost += n.m_num_signals_passed <
Yapf().PfGetSettings().rail_look_ahead_max_signals ?
Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0;
240 inline int PlatformLengthPenalty(
int platform_length)
244 assert(v !=
nullptr);
248 if (missing_platform_length < 0) {
250 cost +=
Yapf().PfGetSettings().rail_longer_platform_penalty +
Yapf().PfGetSettings().rail_longer_platform_per_tile_penalty * -missing_platform_length;
251 }
else if (missing_platform_length > 0) {
253 cost +=
Yapf().PfGetSettings().rail_shorter_platform_penalty +
Yapf().PfGetSettings().rail_shorter_platform_per_tile_penalty * missing_platform_length;
259 inline void SetMaxCost(
int max_cost)
271 assert(!n.flags_u.flags_s.m_targed_seen);
272 assert(tf->m_new_tile == n.m_key.m_tile);
273 assert((
HasTrackdir(tf->m_new_td_bits, n.m_key.m_td)));
278 bool has_parent = (n.m_parent !=
nullptr);
281 CachedData &segment = *n.m_segment;
282 bool is_cached_segment = (segment.m_cost >= 0);
284 int parent_cost = has_parent ? n.m_parent->m_cost : 0;
305 int transition_cost = 0;
313 int segment_entry_cost = 0;
314 int segment_cost = 0;
319 TILE cur(n.m_key.m_tile, n.m_key.m_td);
322 TILE prev = !has_parent ?
TILE() :
TILE(n.m_parent->GetLastTile(), n.m_parent->GetLastTrackdir());
324 EndSegmentReasonBits end_segment_reason = ESRB_NONE;
326 TrackFollower tf_local(v,
Yapf().GetCompatibleRailTypes(), &
Yapf().m_perf_ts_cost);
330 assert(!is_cached_segment);
337 transition_cost =
Yapf().CurveCost(prev.td, cur.td);
342 if (segment_cost == 0) {
344 segment_entry_cost = transition_cost;
348 if (is_cached_segment) {
350 segment_cost = segment.m_cost;
352 end_segment_reason = segment.m_end_segment_reason;
358 n.flags_u.flags_s.m_last_signal_was_red = is_red;
360 n.m_last_red_signal_type = GetSignalType(segment.m_last_signal_tile,
TrackdirToTrack(segment.m_last_signal_td));
364 cur =
TILE(n.GetLastTile(), n.GetLastTrackdir());
369 segment_cost += transition_cost;
375 segment_cost +=
Yapf().OneTileCost(cur.tile, cur.td);
381 segment_cost +=
Yapf().SlopeCost(cur.tile, cur.td);
384 segment_cost +=
Yapf().SignalCost(n, cur.tile, cur.td);
387 segment_cost +=
Yapf().ReservationCost(n, cur.tile, cur.td, tf->m_tiles_skipped);
389 end_segment_reason = segment.m_end_segment_reason;
392 if (cur.tile == prev.tile) {
395 segment_cost +=
Yapf().PfGetSettings().rail_depot_reverse_penalty;
399 end_segment_reason |= ESRB_DEPOT;
413 while (ft.
Follow(t, td)) {
416 if (t == cur.tile || --max_tiles == 0) {
439 extra_cost +=
Yapf().PfGetSettings().rail_lastred_penalty;
443 end_segment_reason |= ESRB_WAYPOINT;
445 }
else if (tf->m_is_station) {
447 uint platform_length = tf->m_tiles_skipped + 1;
450 segment_cost +=
Yapf().PfGetSettings().rail_station_penalty * platform_length;
452 end_segment_reason |= ESRB_STATION;
454 }
else if (TrackFollower::DoTrackMasking() && cur.tile_type ==
MP_RAILWAY) {
457 end_segment_reason |= ESRB_SAFE_TILE;
463 if (n.m_num_signals_passed < m_sig_look_ahead_costs.
Size())
466 int max_speed = tf->GetSpeedLimit(&min_speed);
468 if (max_speed < max_veh_speed) {
469 extra_cost +=
YAPF_TILE_LENGTH * (max_veh_speed - max_speed) * (4 + tf->m_tiles_skipped) / max_veh_speed;
471 if (min_speed > max_veh_speed) {
479 end_segment_reason |= ESRB_PATH_TOO_LONG;
484 tf_local.Init(v,
Yapf().GetCompatibleRailTypes(), &
Yapf().m_perf_ts_cost);
486 if (!tf_local.Follow(cur.tile, cur.td)) {
487 assert(tf_local.m_err != TrackFollower::EC_NONE);
489 if (tf_local.m_err == TrackFollower::EC_RAIL_ROAD_TYPE) {
490 end_segment_reason |= ESRB_RAIL_TYPE;
492 end_segment_reason |= ESRB_DEAD_END;
496 end_segment_reason |= ESRB_SAFE_TILE;
504 end_segment_reason |= ESRB_CHOICE_FOLLOWS;
514 end_segment_reason |= ESRB_SAFE_TILE;
517 end_segment_reason |= ESRB_SAFE_TILE | ESRB_DEAD_END;
518 extra_cost +=
Yapf().PfGetSettings().rail_lastred_exit_penalty;
523 if (next.rail_type != cur.rail_type) {
525 end_segment_reason |= ESRB_RAIL_TYPE;
530 if (next.tile == n.m_key.m_tile && next.td == n.m_key.m_td) {
531 end_segment_reason |= ESRB_INFINITE_LOOP;
535 if (segment_cost > s_max_segment_cost) {
539 end_segment_reason |= ESRB_SEGMENT_TOO_LONG;
545 if (end_segment_reason != ESRB_NONE) {
556 if (end_segment_reason & ESRB_PATH_TOO_LONG)
return false;
558 bool target_seen =
false;
559 if ((end_segment_reason & ESRB_POSSIBLE_TARGET) != ESRB_NONE) {
561 if (
Yapf().PfDetectDestination(cur.tile, cur.td)) {
568 if (!is_cached_segment) {
570 segment.m_cost = segment_cost;
571 segment.m_end_segment_reason = end_segment_reason & ESRB_CACHED_MASK;
573 n.SetLastTileTrackdir(cur.tile, cur.td);
577 if (!target_seen && (end_segment_reason & ESRB_ABORT_PF_MASK) != ESRB_NONE) {
584 n.flags_u.flags_s.m_targed_seen =
true;
586 if (n.flags_u.flags_s.m_last_signal_was_red) {
589 extra_cost +=
Yapf().PfGetSettings().rail_lastred_exit_penalty;
590 }
else if (!IsPbsSignal(n.m_last_red_signal_type)) {
592 extra_cost +=
Yapf().PfGetSettings().rail_lastred_penalty;
597 if ((end_segment_reason & ESRB_STATION) != ESRB_NONE) {
599 assert(st !=
nullptr);
602 extra_cost -=
Yapf().PfGetSettings().rail_station_penalty * platform_length;
604 extra_cost += PlatformLengthPenalty(platform_length);
609 n.m_cost = parent_cost + segment_entry_cost + segment_cost + extra_cost;
614 inline bool CanUseGlobalCache(
Node &n)
const
616 return !m_disable_cache
617 && (n.m_parent !=
nullptr)
618 && (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.
Size());
621 inline void ConnectNodeToCachedData(
Node &n, CachedData &ci)
624 if (n.m_segment->m_cost < 0) {
625 n.m_segment->m_last_tile = n.m_key.m_tile;
626 n.m_segment->m_last_td = n.m_key.m_td;
630 void DisableCache(
bool disable)
632 m_disable_cache = disable;