* Move a vehicle chain one movement stop forwards. * @param v First vehicle to move. * @param nomove Stop moving this and all following vehicles. * @param reverse Set to false to not execute the vehicle reversing. This does not change any other logic. * @return True if the vehicle could be moved forward, false otherwise. */
| 3287 | * @return True if the vehicle could be moved forward, false otherwise. |
| 3288 | */ |
| 3289 | bool TrainController(Train *v, Vehicle *nomove, bool reverse) |
| 3290 | { |
| 3291 | Train *first = v->First(); |
| 3292 | Train *prev; |
| 3293 | bool direction_changed = false; // has direction of any part changed? |
| 3294 | |
| 3295 | /* For every vehicle after and including the given vehicle */ |
| 3296 | for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) { |
| 3297 | DiagDirection enterdir = DIAGDIR_BEGIN; |
| 3298 | bool update_signals_crossing = false; // will we update signals or crossing state? |
| 3299 | |
| 3300 | GetNewVehiclePosResult gp = GetNewVehiclePos(v); |
| 3301 | if (v->track != TRACK_BIT_WORMHOLE) { |
| 3302 | /* Not inside tunnel */ |
| 3303 | if (gp.old_tile == gp.new_tile) { |
| 3304 | /* Staying in the old tile */ |
| 3305 | if (v->track == TRACK_BIT_DEPOT) { |
| 3306 | /* Inside depot */ |
| 3307 | gp.x = v->x_pos; |
| 3308 | gp.y = v->y_pos; |
| 3309 | } else { |
| 3310 | /* Not inside depot */ |
| 3311 | |
| 3312 | /* Reverse when we are at the end of the track already, do not move to the new position */ |
| 3313 | if (v->IsFrontEngine() && !TrainCheckIfLineEnds(v, reverse)) return false; |
| 3314 | |
| 3315 | auto vets = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y); |
| 3316 | if (vets.Test(VehicleEnterTileState::CannotEnter)) { |
| 3317 | goto invalid_rail; |
| 3318 | } |
| 3319 | if (vets.Test(VehicleEnterTileState::EnteredStation)) { |
| 3320 | /* The new position is the end of the platform */ |
| 3321 | TrainEnterStation(v, GetStationIndex(gp.new_tile)); |
| 3322 | } |
| 3323 | } |
| 3324 | } else { |
| 3325 | /* A new tile is about to be entered. */ |
| 3326 | |
| 3327 | /* Determine what direction we're entering the new tile from */ |
| 3328 | enterdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile); |
| 3329 | assert(IsValidDiagDirection(enterdir)); |
| 3330 | |
| 3331 | /* Get the status of the tracks in the new tile and mask |
| 3332 | * away the bits that aren't reachable. */ |
| 3333 | TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir)); |
| 3334 | TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(enterdir); |
| 3335 | |
| 3336 | TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs; |
| 3337 | TrackBits red_signals = TrackdirBitsToTrackBits(TrackStatusToRedSignals(ts) & reachable_trackdirs); |
| 3338 | |
| 3339 | TrackBits bits = TrackdirBitsToTrackBits(trackdirbits); |
| 3340 | if (Rail90DegTurnDisallowed(GetTileRailType(gp.old_tile), GetTileRailType(gp.new_tile)) && prev == nullptr) { |
| 3341 | /* We allow wagons to make 90 deg turns, because forbid_90_deg |
| 3342 | * can be switched on halfway a turn */ |
| 3343 | bits &= ~TrackCrossesTracks(FindFirstTrack(v->track)); |
| 3344 | } |
| 3345 | |
| 3346 | if (bits == TRACK_BIT_NONE) goto invalid_rail; |
no test coverage detected