* Free the reserved path in front of a vehicle. * @param v %Train owning the reserved path. */
| 2417 | * @param v %Train owning the reserved path. |
| 2418 | */ |
| 2419 | void FreeTrainTrackReservation(const Train *v) |
| 2420 | { |
| 2421 | assert(v->IsFrontEngine()); |
| 2422 | |
| 2423 | TileIndex tile = v->tile; |
| 2424 | Trackdir td = v->GetVehicleTrackdir(); |
| 2425 | bool free_tile = !(IsRailStationTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE)); |
| 2426 | StationID station_id = IsRailStationTile(v->tile) ? GetStationIndex(v->tile) : StationID::Invalid(); |
| 2427 | |
| 2428 | /* Can't be holding a reservation if we enter a depot. */ |
| 2429 | if (IsRailDepotTile(tile) && TrackdirToExitdir(td) != GetRailDepotDirection(tile)) return; |
| 2430 | if (v->track == TRACK_BIT_DEPOT) { |
| 2431 | /* Front engine is in a depot. We enter if some part is not in the depot. */ |
| 2432 | for (const Train *u = v; u != nullptr; u = u->Next()) { |
| 2433 | if (u->track != TRACK_BIT_DEPOT || u->tile != v->tile) return; |
| 2434 | } |
| 2435 | } |
| 2436 | /* Don't free reservation if it's not ours. */ |
| 2437 | if (TracksOverlap(GetReservedTrackbits(tile) | TrackToTrackBits(TrackdirToTrack(td)))) return; |
| 2438 | |
| 2439 | CFollowTrackRail ft(v, GetAllCompatibleRailTypes(v->railtypes)); |
| 2440 | while (ft.Follow(tile, td)) { |
| 2441 | tile = ft.new_tile; |
| 2442 | TrackdirBits bits = ft.new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(tile)); |
| 2443 | td = RemoveFirstTrackdir(&bits); |
| 2444 | assert(bits == TRACKDIR_BIT_NONE); |
| 2445 | |
| 2446 | if (!IsValidTrackdir(td)) break; |
| 2447 | |
| 2448 | if (IsTileType(tile, MP_RAILWAY)) { |
| 2449 | if (HasSignalOnTrackdir(tile, td) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(td)))) { |
| 2450 | /* Conventional signal along trackdir: remove reservation and stop. */ |
| 2451 | UnreserveRailTrack(tile, TrackdirToTrack(td)); |
| 2452 | break; |
| 2453 | } |
| 2454 | if (HasPbsSignalOnTrackdir(tile, td)) { |
| 2455 | if (GetSignalStateByTrackdir(tile, td) == SIGNAL_STATE_RED) { |
| 2456 | /* Red PBS signal? Can't be our reservation, would be green then. */ |
| 2457 | break; |
| 2458 | } else { |
| 2459 | /* Turn the signal back to red. */ |
| 2460 | SetSignalStateByTrackdir(tile, td, SIGNAL_STATE_RED); |
| 2461 | MarkTileDirtyByTile(tile); |
| 2462 | } |
| 2463 | } else if (HasPbsSignalOnTrackdir(tile, ReverseTrackdir(td))) { |
| 2464 | /* Reservation passes an opposing path signal. Mark signal for update to re-establish the proper default state. */ |
| 2465 | AddSideToSignalBuffer(tile, TrackdirToExitdir(ReverseTrackdir(td)), v->owner); |
| 2466 | } else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) { |
| 2467 | break; |
| 2468 | } |
| 2469 | } |
| 2470 | |
| 2471 | /* Don't free first station/bridge/tunnel if we are on it. */ |
| 2472 | if (free_tile || (!(ft.is_station && GetStationIndex(ft.new_tile) == station_id) && !ft.is_tunnel && !ft.is_bridge)) ClearPathReservation(v, tile, td); |
| 2473 | |
| 2474 | free_tile = true; |
| 2475 | } |
| 2476 |
no test coverage detected