12 #ifndef YAPF_COSTRAIL_HPP 
   13 #define YAPF_COSTRAIL_HPP 
   15 #include "../../pbs.h" 
   17 template <
class Types>
 
   20   typedef typename Types::Tpf 
Tpf;              
 
   21   typedef typename Types::TrackFollower TrackFollower;
 
   22   typedef typename Types::NodeList::Titem 
Node; 
 
   23   typedef typename Node::Key 
Key;               
 
   24   typedef typename Node::CachedData CachedData;
 
   55       tile_type = src.tile_type;
 
   56       rail_type = src.rail_type;
 
   70   bool          m_stopped_on_first_two_way_signal;
 
   73   static const int s_max_segment_cost = 10000;
 
   78     int p0 = 
Yapf().PfGetSettings().rail_look_ahead_signal_p0;
 
   79     int p1 = 
Yapf().PfGetSettings().rail_look_ahead_signal_p1;
 
   80     int p2 = 
Yapf().PfGetSettings().rail_look_ahead_signal_p2;
 
   81     int *pen = m_sig_look_ahead_costs.
GrowSizeNC(
Yapf().PfGetSettings().rail_look_ahead_max_signals);
 
   82     for (uint i = 0; i < 
Yapf().PfGetSettings().rail_look_ahead_max_signals; i++) {
 
   83       pen[i] = p0 + i * (p1 + i * p2);
 
   90     return *
static_cast<Tpf *
>(
this);
 
   98     return Yapf().PfGetSettings().rail_slope_penalty;
 
  106     if (TrackFollower::Allow90degTurns()
 
  109       cost += 
Yapf().PfGetSettings().rail_curve90_penalty;
 
  112       cost += 
Yapf().PfGetSettings().rail_curve45_penalty;
 
  122       if (t1 && t2) 
return Yapf().PfGetSettings().rail_doubleslip_penalty;
 
  138             cost += 
Yapf().PfGetSettings().rail_crossing_penalty;
 
  156     for (; skipped >= 0; skipped--, tile += diff) {
 
  165     if (n.m_num_signals_passed >= m_sig_look_ahead_costs.
Size() / 2) 
return 0;
 
  166     if (!IsPbsSignal(n.m_last_signal_type)) 
return 0;
 
  169       return Yapf().PfGetSettings().rail_pbs_station_penalty * (skipped + 1);
 
  171       int cost = 
Yapf().PfGetSettings().rail_pbs_cross_penalty;
 
  173       return cost * (skipped + 1);
 
  188         n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
 
  190         if (has_signal_along) {
 
  194           n.m_last_signal_type = sig_type;
 
  197           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;
 
  200             n.flags_u.flags_s.m_last_signal_was_red = 
false;
 
  202             if (look_ahead_cost < 0) {
 
  204               cost -= look_ahead_cost;
 
  209             if (!IsPbsSignal(sig_type) && 
Yapf().TreatFirstRedTwoWaySignalAsEOL() && n.flags_u.flags_s.m_choice_seen && has_signal_against && n.m_num_signals_passed == 0) {
 
  211               Yapf().PruneIntermediateNodeBranch();
 
  212               n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
 
  213               Yapf().m_stopped_on_first_two_way_signal = 
true;
 
  216             n.m_last_red_signal_type = sig_type;
 
  217             n.flags_u.flags_s.m_last_signal_was_red = 
true;
 
  220             if (!IsPbsSignal(sig_type) && look_ahead_cost > 0) {
 
  222               cost += look_ahead_cost;
 
  226             if (n.m_num_signals_passed == 0) {
 
  229                 case SIGTYPE_EXIT:   cost += 
Yapf().PfGetSettings().rail_firstred_exit_penalty; 
break; 
 
  237           n.m_num_signals_passed++;
 
  238           n.m_segment->m_last_signal_tile = tile;
 
  239           n.m_segment->m_last_signal_td = trackdir;
 
  242         if (has_signal_against && IsPbsSignal(GetSignalType(tile, 
TrackdirToTrack(trackdir)))) {
 
  243           cost += n.m_num_signals_passed < 
Yapf().PfGetSettings().rail_look_ahead_max_signals ? 
Yapf().PfGetSettings().rail_pbs_signal_back_penalty : 0;
 
  250   inline int PlatformLengthPenalty(
int platform_length)
 
  258     if (missing_platform_length < 0) {
 
  260       cost += 
Yapf().PfGetSettings().rail_longer_platform_penalty + 
Yapf().PfGetSettings().rail_longer_platform_per_tile_penalty * -missing_platform_length;
 
  261     } 
else if (missing_platform_length > 0) {
 
  263       cost += 
Yapf().PfGetSettings().rail_shorter_platform_penalty + 
Yapf().PfGetSettings().rail_shorter_platform_per_tile_penalty * missing_platform_length;
 
  269   inline void SetMaxCost(
int max_cost)
 
  281     assert(!n.flags_u.flags_s.m_targed_seen);
 
  282     assert(tf->m_new_tile == n.m_key.m_tile);
 
  288     bool has_parent = (n.m_parent != NULL);
 
  291     CachedData &segment = *n.m_segment;
 
  292     bool is_cached_segment = (segment.m_cost >= 0);
 
  294     int parent_cost = has_parent ? n.m_parent->m_cost : 0;
 
  315     int transition_cost = 0;
 
  323     int segment_entry_cost = 0;
 
  324     int segment_cost = 0;
 
  329     TILE cur(n.m_key.m_tile, n.m_key.m_td);
 
  332     TILE prev = !has_parent ? 
TILE() : TILE(n.m_parent->GetLastTile(), n.m_parent->GetLastTrackdir());
 
  334     EndSegmentReasonBits end_segment_reason = ESRB_NONE;
 
  336     TrackFollower tf_local(v, 
Yapf().GetCompatibleRailTypes(), &
Yapf().m_perf_ts_cost);
 
  340       assert(!is_cached_segment);
 
  347       transition_cost = 
Yapf().CurveCost(prev.td, cur.td);
 
  352       if (segment_cost == 0) {
 
  354         segment_entry_cost = transition_cost;
 
  358         if (is_cached_segment) {
 
  360           segment_cost = segment.m_cost;
 
  362           end_segment_reason = segment.m_end_segment_reason;
 
  368             n.flags_u.flags_s.m_last_signal_was_red = is_red;
 
  370               n.m_last_red_signal_type = GetSignalType(segment.m_last_signal_tile, 
TrackdirToTrack(segment.m_last_signal_td));
 
  374           cur = TILE(n.GetLastTile(), n.GetLastTrackdir());
 
  379         segment_cost += transition_cost;
 
  385       segment_cost += 
Yapf().OneTileCost(cur.tile, cur.td);
 
  391       segment_cost += 
Yapf().SlopeCost(cur.tile, cur.td);
 
  394       segment_cost += 
Yapf().SignalCost(n, cur.tile, cur.td);
 
  397       segment_cost += 
Yapf().ReservationCost(n, cur.tile, cur.td, tf->m_tiles_skipped);
 
  399       end_segment_reason = segment.m_end_segment_reason;
 
  402       if (cur.tile == prev.tile) {
 
  405         segment_cost += 
Yapf().PfGetSettings().rail_depot_reverse_penalty;
 
  407         end_segment_reason |= ESRB_DEPOT;
 
  419           while (ft.
Follow(t, td)) {
 
  440             extra_cost += 
Yapf().PfGetSettings().rail_lastred_penalty;
 
  444         end_segment_reason |= ESRB_WAYPOINT;
 
  446       } 
else if (tf->m_is_station) {
 
  448         uint platform_length = tf->m_tiles_skipped + 1;
 
  451         segment_cost += 
Yapf().PfGetSettings().rail_station_penalty * platform_length;
 
  453         end_segment_reason |= ESRB_STATION;
 
  455       } 
else if (TrackFollower::DoTrackMasking() && cur.tile_type == 
MP_RAILWAY) {
 
  458           end_segment_reason |= ESRB_SAFE_TILE;
 
  464       if (n.m_num_signals_passed < m_sig_look_ahead_costs.
Size())
 
  467         int max_speed = tf->GetSpeedLimit(&min_speed);
 
  469         if (max_speed < max_veh_speed) {
 
  470           extra_cost += 
YAPF_TILE_LENGTH * (max_veh_speed - max_speed) * (4 + tf->m_tiles_skipped) / max_veh_speed;
 
  472         if (min_speed > max_veh_speed) {
 
  480         end_segment_reason |= ESRB_PATH_TOO_LONG;
 
  485       tf_local.Init(v, 
Yapf().GetCompatibleRailTypes(), &
Yapf().m_perf_ts_cost);
 
  487       if (!tf_local.Follow(cur.tile, cur.td)) {
 
  488         assert(tf_local.m_err != TrackFollower::EC_NONE);
 
  490         if (tf_local.m_err == TrackFollower::EC_RAIL_TYPE) {
 
  491           end_segment_reason |= ESRB_RAIL_TYPE;
 
  493           end_segment_reason |= ESRB_DEAD_END;
 
  497           end_segment_reason |= ESRB_SAFE_TILE;
 
  505         end_segment_reason |= ESRB_CHOICE_FOLLOWS;
 
  515           end_segment_reason |= ESRB_SAFE_TILE;
 
  518           end_segment_reason |= ESRB_SAFE_TILE | ESRB_DEAD_END;
 
  519           extra_cost += 
Yapf().PfGetSettings().rail_lastred_exit_penalty;
 
  524       if (next.rail_type != cur.rail_type) {
 
  526         end_segment_reason |= ESRB_RAIL_TYPE;
 
  531       if (next.tile == n.m_key.m_tile && next.td == n.m_key.m_td) {
 
  532         end_segment_reason |= ESRB_INFINITE_LOOP;
 
  536       if (segment_cost > s_max_segment_cost) {
 
  540           end_segment_reason |= ESRB_SEGMENT_TOO_LONG;
 
  546       if (end_segment_reason != ESRB_NONE) {
 
  556     bool target_seen = 
false;
 
  557     if ((end_segment_reason & ESRB_POSSIBLE_TARGET) != ESRB_NONE) {
 
  559       if (
Yapf().PfDetectDestination(cur.tile, cur.td)) {
 
  566     if (!is_cached_segment) {
 
  568       segment.m_cost = segment_cost;
 
  569       segment.m_end_segment_reason = end_segment_reason & ESRB_CACHED_MASK;
 
  571       n.SetLastTileTrackdir(cur.tile, cur.td);
 
  575     if (!target_seen && (end_segment_reason & ESRB_ABORT_PF_MASK) != ESRB_NONE) {
 
  582       n.flags_u.flags_s.m_targed_seen = 
true;
 
  584       if (n.flags_u.flags_s.m_last_signal_was_red) {
 
  587           extra_cost += 
Yapf().PfGetSettings().rail_lastred_exit_penalty;
 
  588         } 
else if (!IsPbsSignal(n.m_last_red_signal_type)) {
 
  590           extra_cost += 
Yapf().PfGetSettings().rail_lastred_penalty;
 
  595       if ((end_segment_reason & ESRB_STATION) != ESRB_NONE) {
 
  600         extra_cost -= 
Yapf().PfGetSettings().rail_station_penalty * platform_length;
 
  602         extra_cost += PlatformLengthPenalty(platform_length);
 
  607     n.m_cost = parent_cost + segment_entry_cost + segment_cost + extra_cost;
 
  612   inline bool CanUseGlobalCache(
Node &n)
 const 
  614     return !m_disable_cache
 
  615       && (n.m_parent != NULL)
 
  616       && (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.
Size());
 
  619   inline void ConnectNodeToCachedData(
Node &n, CachedData &ci)
 
  622     if (n.m_segment->m_cost < 0) {
 
  623       n.m_segment->m_last_tile = n.m_key.m_tile;
 
  624       n.m_segment->m_last_td = n.m_key.m_td;
 
  628   void DisableCache(
bool disable)
 
  630     m_disable_cache = disable;