204 } |
204 } |
205 |
205 |
206 return PBSTileInfo(tile, trackdir, false); |
206 return PBSTileInfo(tile, trackdir, false); |
207 } |
207 } |
208 |
208 |
209 /** Callback for VehicleFromPos to find a train on a specific track. */ |
209 /** |
|
210 * Helper struct for finding the best matching vehicle on a specific track. |
|
211 */ |
|
212 struct FindTrainOnTrackInfo { |
|
213 PBSTileInfo res; ///< Information about the track. |
|
214 Vehicle *best; ///< The currently "best" vehicle we have found. |
|
215 |
|
216 /** Init the best location to NULL always! */ |
|
217 FindTrainOnTrackInfo() : best(NULL) {} |
|
218 }; |
|
219 |
|
220 /** Callback for Has/FindVehicleOnPos to find a train on a specific track. */ |
210 static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data) |
221 static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data) |
211 { |
222 { |
212 PBSTileInfo info = *(PBSTileInfo *)data; |
223 FindTrainOnTrackInfo *info = (FindTrainOnTrackInfo *)data; |
213 |
224 |
214 if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) && HasBit((TrackBits)v->u.rail.track, TrackdirToTrack(info.trackdir))) return v; |
225 if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) && HasBit((TrackBits)v->u.rail.track, TrackdirToTrack(info->res.trackdir))) { |
|
226 v = v->First(); |
|
227 |
|
228 /* ALWAYS return the lowest ID (anti-desync!) */ |
|
229 if (info->best == NULL || v->index < info->best->index) info->best = v; |
|
230 return v; |
|
231 } |
215 |
232 |
216 return NULL; |
233 return NULL; |
217 } |
234 } |
218 |
235 |
219 /** |
236 /** |
221 * |
238 * |
222 * @param v the vehicle |
239 * @param v the vehicle |
223 * @param train_on_res Is set to a train we might encounter |
240 * @param train_on_res Is set to a train we might encounter |
224 * @returns The last tile of the reservation or the current train tile if no reservation present. |
241 * @returns The last tile of the reservation or the current train tile if no reservation present. |
225 */ |
242 */ |
226 PBSTileInfo FollowTrainReservation(const Vehicle *v, Vehicle **train_on_res) |
243 PBSTileInfo FollowTrainReservation(const Vehicle *v, bool *train_on_res) |
227 { |
244 { |
228 assert(v->type == VEH_TRAIN); |
245 assert(v->type == VEH_TRAIN); |
229 |
246 |
230 TileIndex tile = v->tile; |
247 TileIndex tile = v->tile; |
231 Trackdir trackdir = GetVehicleTrackdir(v); |
248 Trackdir trackdir = GetVehicleTrackdir(v); |
232 |
249 |
233 if (IsRailDepotTile(tile) && !GetRailDepotReservation(tile)) return PBSTileInfo(tile, trackdir, false); |
250 if (IsRailDepotTile(tile) && !GetRailDepotReservation(tile)) return PBSTileInfo(tile, trackdir, false); |
234 |
251 |
235 PBSTileInfo res = FollowReservation(v->owner, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes, tile, trackdir); |
252 FindTrainOnTrackInfo ftoti; |
236 res.okay = IsSafeWaitingPosition(v, res.tile, res.trackdir, true, _settings_game.pf.forbid_90_deg); |
253 ftoti.res = FollowReservation(v->owner, GetRailTypeInfo(v->u.rail.railtype)->compatible_railtypes, tile, trackdir); |
237 if (train_on_res != NULL) *train_on_res = VehicleFromPos(res.tile, &res, FindTrainOnTrackEnum); |
254 ftoti.res.okay = IsSafeWaitingPosition(v, ftoti.res.tile, ftoti.res.trackdir, true, _settings_game.pf.forbid_90_deg); |
238 return res; |
255 if (train_on_res != NULL) *train_on_res = HasVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum); |
|
256 return ftoti.res; |
239 } |
257 } |
240 |
258 |
241 /** |
259 /** |
242 * Find the train which has reserved a specific path. |
260 * Find the train which has reserved a specific path. |
243 * |
261 * |
254 |
272 |
255 /* Follow the path from tile to both ends, one of the end tiles should |
273 /* Follow the path from tile to both ends, one of the end tiles should |
256 * have a train on it. We need FollowReservation to ignore one-way signals |
274 * have a train on it. We need FollowReservation to ignore one-way signals |
257 * here, as one of the two search directions will be the "wrong" way. */ |
275 * here, as one of the two search directions will be the "wrong" way. */ |
258 for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) { |
276 for (int i = 0; i < 2; ++i, trackdir = ReverseTrackdir(trackdir)) { |
259 PBSTileInfo dest = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true); |
277 FindTrainOnTrackInfo ftoti; |
260 |
278 ftoti.res = FollowReservation(GetTileOwner(tile), rts, tile, trackdir, true); |
261 Vehicle *v = VehicleFromPos(dest.tile, &dest, FindTrainOnTrackEnum); |
279 |
262 if (v != NULL) return v->First(); |
280 FindVehicleOnPos(ftoti.res.tile, &ftoti, FindTrainOnTrackEnum); |
|
281 if (ftoti.best != NULL) return ftoti.best; |
263 |
282 |
264 /* Special case for stations: check the whole platform for a vehicle. */ |
283 /* Special case for stations: check the whole platform for a vehicle. */ |
265 if (IsRailwayStationTile(dest.tile)) { |
284 if (IsRailwayStationTile(ftoti.res.tile)) { |
266 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(dest.trackdir))); |
285 TileIndexDiff diff = TileOffsByDiagDir(TrackdirToExitdir(ReverseTrackdir(ftoti.res.trackdir))); |
267 for (TileIndex st_tile = dest.tile + diff; IsCompatibleTrainStationTile(st_tile, dest.tile); st_tile += diff) { |
286 for (TileIndex st_tile = ftoti.res.tile + diff; IsCompatibleTrainStationTile(st_tile, ftoti.res.tile); st_tile += diff) { |
268 v = VehicleFromPos(st_tile, &dest, FindTrainOnTrackEnum); |
287 FindVehicleOnPos(st_tile, &ftoti, FindTrainOnTrackEnum); |
269 if (v != NULL) return v->First(); |
288 if (ftoti.best != NULL) return ftoti.best; |
270 } |
289 } |
271 } |
290 } |
272 |
291 |
273 /* Special case for bridges/tunnels: check the other end as well. */ |
292 /* Special case for bridges/tunnels: check the other end as well. */ |
274 if (IsTileType(dest.tile, MP_TUNNELBRIDGE)) { |
293 if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) { |
275 v = VehicleFromPos(GetOtherTunnelBridgeEnd(dest.tile), &dest, FindTrainOnTrackEnum); |
294 FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum); |
276 if (v != NULL) return v->First(); |
295 if (ftoti.best != NULL) return ftoti.best; |
277 } |
296 } |
278 } |
297 } |
279 |
298 |
280 return NULL; |
299 return NULL; |
281 } |
300 } |