KUDr@3900: /* $Id$ */ KUDr@3900: rubidium@10455: /** @file yapf_costrail.hpp Cost determination for rails. */ celestar@6447: KUDr@3900: #ifndef YAPF_COSTRAIL_HPP KUDr@3900: #define YAPF_COSTRAIL_HPP KUDr@3900: KUDr@3900: KUDr@3900: template KUDr@3900: class CYapfCostRailT KUDr@3900: : public CYapfCostBase KUDr@3900: , public CostRailSettings KUDr@3900: { KUDr@3900: public: KUDr@3914: typedef typename Types::Tpf Tpf; ///< the pathfinder class (derived from THIS class) KUDr@3900: typedef typename Types::TrackFollower TrackFollower; KUDr@3900: typedef typename Types::NodeList::Titem Node; ///< this will be our node type KUDr@3914: typedef typename Node::Key Key; ///< key to hash tables KUDr@3900: typedef typename Node::CachedData CachedData; KUDr@3900: KUDr@3900: protected: glx@9629: glx@9629: /* Structure used inside PfCalcCost() to keep basic tile information. */ glx@9629: struct TILE { glx@9629: TileIndex tile; glx@9629: Trackdir td; glx@9629: TileType tile_type; glx@9629: RailType rail_type; glx@9629: glx@9629: TILE() glx@9629: { glx@9629: tile = INVALID_TILE; glx@9629: td = INVALID_TRACKDIR; glx@9629: tile_type = MP_VOID; glx@9629: rail_type = INVALID_RAILTYPE; glx@9629: } glx@9629: glx@9629: TILE(TileIndex tile, Trackdir td) glx@9629: { glx@9629: this->tile = tile; glx@9629: this->td = td; glx@9629: this->tile_type = GetTileType(tile); glx@9629: this->rail_type = GetTileRailType(tile); glx@9629: } glx@9629: glx@9629: TILE(const TILE &src) glx@9629: { glx@9629: tile = src.tile; glx@9629: td = src.td; glx@9629: tile_type = src.tile_type; glx@9629: rail_type = src.rail_type; glx@9629: } glx@9629: }; glx@9629: glx@9629: protected: KUDr@3900: int m_max_cost; KUDr@3900: CBlobT m_sig_look_ahead_costs; rubidium@9631: bool m_disable_cache; glx@9629: KUDr@5675: public: KUDr@5675: bool m_stopped_on_first_two_way_signal; KUDr@5675: protected: KUDr@3900: KUDr@3900: static const int s_max_segment_cost = 10000; KUDr@3900: KUDr@5675: CYapfCostRailT() KUDr@5675: : m_max_cost(0) rubidium@9631: , m_disable_cache(false) KUDr@5675: , m_stopped_on_first_two_way_signal(false) KUDr@3900: { KUDr@3900: // pre-compute look-ahead penalties into array KUDr@3900: int p0 = Yapf().PfGetSettings().rail_look_ahead_signal_p0; KUDr@3900: int p1 = Yapf().PfGetSettings().rail_look_ahead_signal_p1; KUDr@3900: int p2 = Yapf().PfGetSettings().rail_look_ahead_signal_p2; KUDr@3900: int *pen = m_sig_look_ahead_costs.GrowSizeNC(Yapf().PfGetSettings().rail_look_ahead_max_signals); KUDr@3900: for (uint i = 0; i < Yapf().PfGetSettings().rail_look_ahead_max_signals; i++) KUDr@3900: pen[i] = p0 + i * (p1 + i * p2); KUDr@3900: } KUDr@3900: KUDr@3914: /// to access inherited path finder KUDr@3900: Tpf& Yapf() {return *static_cast(this);} KUDr@3900: KUDr@3900: public: KUDr@3900: FORCEINLINE int SlopeCost(TileIndex tile, Trackdir td) KUDr@3900: { KUDr@3900: CPerfStart perf_cost(Yapf().m_perf_slope_cost); KUDr@3900: if (!stSlopeCost(tile, td)) return 0; KUDr@3900: return Yapf().PfGetSettings().rail_slope_penalty; KUDr@3900: } KUDr@3900: KUDr@3900: FORCEINLINE int CurveCost(Trackdir td1, Trackdir td2) KUDr@3900: { rubidium@9631: assert(IsValidTrackdir(td1)); rubidium@9631: assert(IsValidTrackdir(td2)); KUDr@3900: int cost = 0; KUDr@3900: if (TrackFollower::Allow90degTurns() KUDr@3900: && ((TrackdirToTrackdirBits(td2) & (TrackdirBits)TrackdirCrossesTrackdirs(td1)) != 0)) { KUDr@3900: // 90-deg curve penalty KUDr@3900: cost += Yapf().PfGetSettings().rail_curve90_penalty; KUDr@3900: } else if (td2 != NextTrackdir(td1)) { KUDr@3900: // 45-deg curve penalty KUDr@3900: cost += Yapf().PfGetSettings().rail_curve45_penalty; KUDr@3900: } KUDr@3900: return cost; KUDr@3900: } KUDr@3900: glx@9629: /** Return one tile cost (base cost + level crossing penalty). */ glx@9629: FORCEINLINE int OneTileCost(TileIndex& tile, Trackdir trackdir) KUDr@3900: { KUDr@3900: int cost = 0; KUDr@3900: // set base cost KUDr@3900: if (IsDiagonalTrackdir(trackdir)) { KUDr@3900: cost += YAPF_TILE_LENGTH; KUDr@3900: switch (GetTileType(tile)) { rubidium@9694: case MP_ROAD: KUDr@3900: /* Increase the cost for level crossings */ KUDr@3900: if (IsLevelCrossing(tile)) KUDr@3900: cost += Yapf().PfGetSettings().rail_crossing_penalty; KUDr@3900: break; KUDr@3900: KUDr@3900: default: KUDr@3900: break; KUDr@3900: } KUDr@3900: } else { KUDr@3900: // non-diagonal trackdir KUDr@3900: cost = YAPF_TILE_CORNER_LENGTH; KUDr@3900: } KUDr@3900: return cost; KUDr@3900: } KUDr@3900: KUDr@3900: int SignalCost(Node& n, TileIndex tile, Trackdir trackdir) KUDr@3900: { KUDr@3900: int cost = 0; KUDr@3900: // if there is one-way signal in the opposite direction, then it is not our way KUDr@3900: CPerfStart perf_cost(Yapf().m_perf_other_cost); KUDr@3900: if (IsTileType(tile, MP_RAILWAY)) { KUDr@3900: bool has_signal_against = HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir)); KUDr@3900: bool has_signal_along = HasSignalOnTrackdir(tile, trackdir); KUDr@3900: if (has_signal_against && !has_signal_along) { KUDr@3900: // one-way signal in opposite direction glx@9629: n.m_segment->m_end_segment_reason |= ESRB_DEAD_END; KUDr@3900: } else if (has_signal_along) { KUDr@3900: SignalState sig_state = GetSignalStateByTrackdir(tile, trackdir); KUDr@5095: // cache the look-ahead polynomial constant only if we didn't pass more signals than the look-ahead limit is KUDr@5095: 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; KUDr@3900: if (sig_state != SIGNAL_STATE_RED) { KUDr@3900: // green signal KUDr@3900: n.flags_u.flags_s.m_last_signal_was_red = false; KUDr@5095: // negative look-ahead red-signal penalties would cause problems later, so use them as positive penalties for green signal KUDr@5095: if (look_ahead_cost < 0) { KUDr@5095: // add its negation to the cost KUDr@5095: cost -= look_ahead_cost; KUDr@5095: } KUDr@3900: } else { KUDr@3900: // we have a red signal in our direction KUDr@3900: // was it first signal which is two-way? KUDr@3979: if (Yapf().TreatFirstRedTwoWaySignalAsEOL() && n.flags_u.flags_s.m_choice_seen && has_signal_against && n.m_num_signals_passed == 0) { KUDr@3900: // yes, the first signal is two-way red signal => DEAD END glx@9629: n.m_segment->m_end_segment_reason |= ESRB_DEAD_END; KUDr@5675: Yapf().m_stopped_on_first_two_way_signal = true; KUDr@3900: return -1; KUDr@3900: } rubidium@9625: SignalType sig_type = GetSignalType(tile, TrackdirToTrack(trackdir)); KUDr@3900: n.m_last_red_signal_type = sig_type; KUDr@3900: n.flags_u.flags_s.m_last_signal_was_red = true; KUDr@3900: KUDr@3900: // look-ahead signal penalty KUDr@5095: if (look_ahead_cost > 0) { KUDr@5095: // add the look ahead penalty only if it is positive KUDr@5095: cost += look_ahead_cost; KUDr@3900: } KUDr@3900: KUDr@3900: // special signal penalties KUDr@3900: if (n.m_num_signals_passed == 0) { KUDr@3900: switch (sig_type) { KUDr@3900: case SIGTYPE_COMBO: KUDr@3900: case SIGTYPE_EXIT: cost += Yapf().PfGetSettings().rail_firstred_exit_penalty; break; // first signal is red pre-signal-exit KUDr@3900: case SIGTYPE_NORMAL: KUDr@3900: case SIGTYPE_ENTRY: cost += Yapf().PfGetSettings().rail_firstred_penalty; break; KUDr@3900: }; KUDr@3900: } KUDr@3900: } KUDr@3900: n.m_num_signals_passed++; KUDr@3900: n.m_segment->m_last_signal_tile = tile; KUDr@3900: n.m_segment->m_last_signal_td = trackdir; KUDr@3900: } KUDr@3900: } KUDr@3900: return cost; KUDr@3900: } KUDr@3900: KUDr@3931: FORCEINLINE int PlatformLengthPenalty(int platform_length) KUDr@3931: { KUDr@3931: int cost = 0; glx@10829: const Vehicle *v = Yapf().GetVehicle(); KUDr@3931: assert(v != NULL); rubidium@6585: assert(v->type == VEH_TRAIN); KUDr@3931: assert(v->u.rail.cached_total_length != 0); KUDr@3931: int needed_platform_length = (v->u.rail.cached_total_length + TILE_SIZE - 1) / TILE_SIZE; KUDr@3931: if (platform_length > needed_platform_length) { KUDr@3931: // apply penalty for longer platform than needed KUDr@3932: cost += Yapf().PfGetSettings().rail_longer_platform_penalty; KUDr@3932: } else if (needed_platform_length > platform_length) { KUDr@3931: // apply penalty for shorter platform than needed KUDr@3932: cost += Yapf().PfGetSettings().rail_shorter_platform_penalty; KUDr@3931: } KUDr@3931: return cost; KUDr@3931: } KUDr@3931: KUDr@3900: public: KUDr@3900: FORCEINLINE void SetMaxCost(int max_cost) {m_max_cost = max_cost;} KUDr@3900: glx@9629: glx@9629: KUDr@3914: /** Called by YAPF to calculate the cost from the origin to the given node. rubidium@4549: * Calculates only the cost of given node, adds it to the parent node cost rubidium@4549: * and stores the result into Node::m_cost member */ glx@9629: FORCEINLINE bool PfCalcCost(Node &n, const TrackFollower *tf) KUDr@3900: { KUDr@3900: assert(!n.flags_u.flags_s.m_targed_seen); glx@9629: assert(tf->m_new_tile == n.m_key.m_tile); glx@9629: assert((TrackdirToTrackdirBits(n.m_key.m_td) & tf->m_new_td_bits) != TRACKDIR_BIT_NONE); glx@9629: KUDr@3900: CPerfStart perf_cost(Yapf().m_perf_cost); glx@9629: glx@9629: /* Does the node have some parent node? */ glx@9629: bool has_parent = (n.m_parent != NULL); glx@9629: glx@9629: /* Do we already have a cached segment? */ glx@9629: CachedData &segment = *n.m_segment; glx@9629: bool is_cached_segment = (segment.m_cost >= 0); glx@9629: glx@9629: int parent_cost = has_parent ? n.m_parent->m_cost : 0; glx@9629: glx@9629: /* Each node cost contains 2 or 3 main components: glx@9629: * 1. Transition cost - cost of the move from previous node (tile): glx@9629: * - curve cost (or zero for straight move) glx@9629: * 2. Tile cost: glx@9629: * - base tile cost glx@9629: * - YAPF_TILE_LENGTH for diagonal tiles glx@9629: * - YAPF_TILE_CORNER_LENGTH for non-diagonal tiles glx@9629: * - tile penalties glx@9629: * - tile slope penalty (upward slopes) glx@9629: * - red signal penalty glx@9629: * - level crossing penalty glx@9629: * - speed-limit penalty (bridges) glx@9629: * - station platform penalty glx@9629: * - penalty for reversing in the depot glx@9629: * - etc. glx@9629: * 3. Extra cost (applies to the last node only) glx@9629: * - last red signal penalty glx@9629: * - penalty for too long or too short platform on the destination station glx@9629: */ glx@9629: int transition_cost = 0; glx@9629: int extra_cost = 0; glx@9629: glx@9629: /* Segment: one or more tiles connected by contiguous tracks of the same type. glx@9629: * Each segment cost includes 'Tile cost' for all its tiles (including the first glx@9629: * and last), and the 'Transition cost' between its tiles. The first transition glx@9629: * cost of segment entry (move from the 'parent' node) is not included! glx@9629: */ glx@9629: int segment_entry_cost = 0; KUDr@3900: int segment_cost = 0; glx@9629: glx@10829: const Vehicle *v = Yapf().GetVehicle(); KUDr@3900: KUDr@3900: // start at n.m_key.m_tile / n.m_key.m_td and walk to the end of segment glx@9629: TILE cur(n.m_key.m_tile, n.m_key.m_td); KUDr@3900: glx@9629: // the previous tile will be needed for transition cost calculations rubidium@9631: TILE prev = !has_parent ? TILE() : TILE(n.m_parent->GetLastTile(), n.m_parent->GetLastTrackdir()); KUDr@3900: glx@9629: EndSegmentReasonBits end_segment_reason = ESRB_NONE; KUDr@3900: glx@9629: TrackFollower tf_local(v, &Yapf().m_perf_ts_cost); KUDr@3900: glx@9629: if (!has_parent) { glx@9629: /* We will jump to the middle of the cost calculator assuming that segment cache is not used. */ glx@9629: assert(!is_cached_segment); glx@9629: /* Skip the first transition cost calculation. */ glx@9629: goto no_entry_cost; KUDr@6458: } KUDr@6458: glx@9629: for (;;) { glx@9629: /* Transition cost (cost of the move from previous tile) */ glx@9629: transition_cost = Yapf().CurveCost(prev.td, cur.td); glx@9629: glx@9629: /* First transition cost counts against segment entry cost, other transitions glx@9629: * inside segment will come to segment cost (and will be cached) */ glx@9629: if (segment_cost == 0) { glx@9629: /* We just entered the loop. First transition cost goes to segment entry cost)*/ glx@9629: segment_entry_cost = transition_cost; glx@9629: transition_cost = 0; glx@9629: glx@9629: /* It is the right time now to look if we can reuse the cached segment cost. */ glx@9629: if (is_cached_segment) { glx@9629: /* Yes, we already know the segment cost. */ glx@9629: segment_cost = segment.m_cost; glx@9629: /* We know also the reason why the segment ends. */ glx@9629: end_segment_reason = segment.m_end_segment_reason; rubidium@9631: /* We will need also some information about the last signal (if it was red). */ rubidium@9631: if (segment.m_last_signal_tile != INVALID_TILE) { rubidium@9631: assert(HasSignalOnTrackdir(segment.m_last_signal_tile, segment.m_last_signal_td)); rubidium@9631: SignalState sig_state = GetSignalStateByTrackdir(segment.m_last_signal_tile, segment.m_last_signal_td); rubidium@9631: bool is_red = (sig_state == SIGNAL_STATE_RED); rubidium@9631: n.flags_u.flags_s.m_last_signal_was_red = is_red; rubidium@9631: if (is_red) { rubidium@9631: n.m_last_red_signal_type = GetSignalType(segment.m_last_signal_tile, TrackdirToTrack(segment.m_last_signal_td)); rubidium@9631: } rubidium@9631: } glx@9629: /* No further calculation needed. */ glx@9629: cur = TILE(n.GetLastTile(), n.GetLastTrackdir()); glx@9629: break; glx@9629: } glx@9629: } else { glx@9629: /* Other than first transition cost count as the regular segment cost. */ glx@9629: segment_cost += transition_cost; KUDr@3900: } KUDr@3900: glx@9629: no_entry_cost: // jump here at the beginning if the node has no parent (it is the first node) KUDr@3900: glx@9629: /* All other tile costs will be calculated here. */ glx@9629: segment_cost += Yapf().OneTileCost(cur.tile, cur.td); glx@9629: glx@9629: /* If we skipped some tunnel/bridge/station tiles, add their base cost */ glx@9629: segment_cost += YAPF_TILE_LENGTH * tf->m_tiles_skipped; glx@9629: glx@9629: /* Slope cost. */ glx@9629: segment_cost += Yapf().SlopeCost(cur.tile, cur.td); glx@9629: glx@9629: /* Signal cost (routine can modify segment data). */ glx@9629: segment_cost += Yapf().SignalCost(n, cur.tile, cur.td); glx@9629: end_segment_reason = segment.m_end_segment_reason; glx@9629: glx@9629: /* Tests for 'potential target' reasons to close the segment. */ glx@9629: if (cur.tile == prev.tile) { glx@9629: /* Penalty for reversing in a depot. */ glx@9629: assert(IsRailDepot(cur.tile)); glx@9629: segment_cost += Yapf().PfGetSettings().rail_depot_reverse_penalty; glx@9629: /* We will end in this pass (depot is possible target) */ glx@9629: end_segment_reason |= ESRB_DEPOT; glx@9629: glx@9629: } else if (tf->m_is_station) { glx@9629: /* Station penalties. */ glx@9629: uint platform_length = tf->m_tiles_skipped + 1; glx@9629: /* We don't know yet if the station is our target or not. Act like glx@9629: * if it is pass-through station (not our destination). */ glx@9629: segment_cost += Yapf().PfGetSettings().rail_station_penalty * platform_length; glx@9629: /* We will end in this pass (station is possible target) */ glx@9629: end_segment_reason |= ESRB_STATION; glx@9629: glx@9629: } else if (cur.tile_type == MP_RAILWAY && IsRailWaypoint(cur.tile)) { glx@9629: /* Waypoint is also a good reason to finish. */ glx@9629: end_segment_reason |= ESRB_WAYPOINT; KUDr@3900: } KUDr@3900: glx@9629: /* Apply min/max speed penalties only when inside the look-ahead radius. Otherwise glx@9629: * it would cause desync in MP. */ glx@9629: if (n.m_num_signals_passed < m_sig_look_ahead_costs.Size()) glx@9629: { glx@9629: int min_speed = 0; glx@9629: int max_speed = tf->GetSpeedLimit(&min_speed); glx@9629: if (max_speed < v->max_speed) glx@9629: extra_cost += YAPF_TILE_LENGTH * (v->max_speed - max_speed) * (4 + tf->m_tiles_skipped) / v->max_speed; glx@9629: if (min_speed > v->max_speed) glx@9629: extra_cost += YAPF_TILE_LENGTH * (min_speed - v->max_speed); KUDr@3900: } KUDr@3900: glx@9629: /* Finish if we already exceeded the maximum path cost (i.e. when glx@9629: * searching for the nearest depot). */ glx@9629: if (m_max_cost > 0 && (parent_cost + segment_entry_cost + segment_cost) > m_max_cost) { glx@9629: end_segment_reason |= ESRB_PATH_TOO_LONG; KUDr@3900: } KUDr@3900: glx@9629: /* Move to the next tile/trackdir. */ glx@9629: tf = &tf_local; glx@9629: tf_local.Init(v, &Yapf().m_perf_ts_cost); glx@9629: glx@9629: if (!tf_local.Follow(cur.tile, cur.td)) { truelight@9641: assert(tf_local.m_err != TrackFollower::EC_NONE); glx@9629: /* Can't move to the next tile (EOL?). */ truelight@9641: if (tf_local.m_err == TrackFollower::EC_RAIL_TYPE) { truelight@9641: end_segment_reason |= ESRB_RAIL_TYPE; truelight@9641: } else { truelight@9641: end_segment_reason |= ESRB_DEAD_END; truelight@9641: } KUDr@3900: break; KUDr@3900: } KUDr@3900: glx@9629: /* Check if the next tile is not a choice. */ rubidium@9722: if (KillFirstBit(tf_local.m_new_td_bits) != TRACKDIR_BIT_NONE) { glx@9629: /* More than one segment will follow. Close this one. */ glx@9629: end_segment_reason |= ESRB_CHOICE_FOLLOWS; KUDr@3900: break; KUDr@3900: } KUDr@3900: glx@9629: /* Gather the next tile/trackdir/tile_type/rail_type. */ glx@9629: TILE next(tf_local.m_new_tile, (Trackdir)FindFirstBit2x64(tf_local.m_new_td_bits)); KUDr@3931: glx@9629: /* Check the next tile for the rail type. */ glx@9629: if (next.rail_type != cur.rail_type) { glx@9629: /* Segment must consist from the same rail_type tiles. */ glx@9629: end_segment_reason |= ESRB_RAIL_TYPE; glx@9629: break; glx@9629: } glx@9629: glx@9629: /* Avoid infinite looping. */ glx@9629: if (next.tile == n.m_key.m_tile && next.td == n.m_key.m_td) { glx@9629: end_segment_reason |= ESRB_INFINITE_LOOP; glx@9629: break; glx@9629: } glx@9629: glx@9629: if (segment_cost > s_max_segment_cost) { glx@9629: /* Potentially in the infinite loop (or only very long segment?). We should glx@9629: * not force it to finish prematurely unless we are on a regular tile. */ glx@9629: if (IsTileType(tf->m_new_tile, MP_RAILWAY)) { glx@9629: end_segment_reason |= ESRB_SEGMENT_TOO_LONG; glx@9629: break; KUDr@3931: } KUDr@3931: } KUDr@3900: glx@9629: /* Any other reason bit set? */ glx@9629: if (end_segment_reason != ESRB_NONE) { glx@9629: break; KUDr@3900: } KUDr@3900: glx@9629: /* For the next loop set new prev and cur tile info. */ glx@9629: prev = cur; glx@9629: cur = next; KUDr@3900: glx@9629: } // for (;;) glx@9629: glx@9629: bool target_seen = false; glx@9629: if ((end_segment_reason & ESRB_POSSIBLE_TARGET) != ESRB_NONE) { glx@9629: /* Depot, station or waypoint. */ glx@9629: if (Yapf().PfDetectDestination(cur.tile, cur.td)) { glx@9629: /* Destination found. */ glx@9629: target_seen = true; KUDr@3900: } KUDr@3900: } KUDr@3900: glx@9629: /* Update the segment if needed. */ glx@9629: if (!is_cached_segment) { glx@9629: /* Write back the segment information so it can be reused the next time. */ glx@9629: segment.m_cost = segment_cost; glx@9629: segment.m_end_segment_reason = end_segment_reason & ESRB_CACHED_MASK; glx@9629: /* Save end of segment back to the node. */ glx@9629: n.SetLastTileTrackdir(cur.tile, cur.td); KUDr@3900: } KUDr@3900: glx@9629: /* Do we have an excuse why not to continue pathfinding in this direction? */ glx@9629: if (!target_seen && (end_segment_reason & ESRB_ABORT_PF_MASK) != ESRB_NONE) { glx@9629: /* Reason to not continue. Stop this PF branch. */ glx@9629: return false; glx@9629: } glx@9629: glx@9629: /* Special costs for the case we have reached our target. */ KUDr@3900: if (target_seen) { KUDr@3900: n.flags_u.flags_s.m_targed_seen = true; glx@9629: /* Last-red and last-red-exit penalties. */ KUDr@3900: if (n.flags_u.flags_s.m_last_signal_was_red) { KUDr@3900: if (n.m_last_red_signal_type == SIGTYPE_EXIT) { KUDr@3900: // last signal was red pre-signal-exit KUDr@3900: extra_cost += Yapf().PfGetSettings().rail_lastred_exit_penalty; KUDr@3900: } else { KUDr@3900: // last signal was red, but not exit KUDr@3900: extra_cost += Yapf().PfGetSettings().rail_lastred_penalty; KUDr@3900: } KUDr@3900: } glx@9629: glx@9629: /* Station platform-length penalty. */ glx@9629: if ((end_segment_reason & ESRB_STATION) != ESRB_NONE) { glx@9629: Station *st = GetStationByTile(n.GetLastTile()); glx@9629: assert(st != NULL); glx@9629: uint platform_length = st->GetPlatformLength(n.GetLastTile(), ReverseDiagDir(TrackdirToExitdir(n.GetLastTrackdir()))); glx@9629: /* Reduce the extra cost caused by passing-station penalty (each station receives it in the segment cost). */ glx@9629: extra_cost -= Yapf().PfGetSettings().rail_station_penalty * platform_length; glx@9629: /* Add penalty for the inappropriate platform length. */ glx@9629: extra_cost += PlatformLengthPenalty(platform_length); glx@9629: } KUDr@3900: } KUDr@3900: KUDr@3900: // total node cost glx@9629: n.m_cost = parent_cost + segment_entry_cost + segment_cost + extra_cost; KUDr@3900: glx@9629: return true; KUDr@3900: } KUDr@3900: KUDr@3900: FORCEINLINE bool CanUseGlobalCache(Node& n) const KUDr@3900: { rubidium@9631: return !m_disable_cache rubidium@9631: && (n.m_parent != NULL) KUDr@3900: && (n.m_parent->m_num_signals_passed >= m_sig_look_ahead_costs.Size()); KUDr@3900: } KUDr@3900: KUDr@3900: FORCEINLINE void ConnectNodeToCachedData(Node& n, CachedData& ci) KUDr@3900: { KUDr@3900: n.m_segment = &ci; KUDr@3900: if (n.m_segment->m_cost < 0) { KUDr@3900: n.m_segment->m_last_tile = n.m_key.m_tile; KUDr@3900: n.m_segment->m_last_td = n.m_key.m_td; KUDr@3900: } KUDr@3900: } KUDr@3900: rubidium@9631: void DisableCache(bool disable) rubidium@9631: { rubidium@9631: m_disable_cache = disable; rubidium@9631: } KUDr@3900: }; KUDr@3900: KUDr@3900: KUDr@3900: KUDr@3900: #endif /* YAPF_COSTRAIL_HPP */