179 next_trackdir = best_next_node.GetTrackdir(); |
179 next_trackdir = best_next_node.GetTrackdir(); |
180 } |
180 } |
181 return next_trackdir; |
181 return next_trackdir; |
182 } |
182 } |
183 |
183 |
184 static bool stCheckReverseTrain(Vehicle* v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2) |
184 static bool stCheckReverseTrain(Vehicle* v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty) |
185 { |
185 { |
186 Tpf pf1; |
186 Tpf pf1; |
187 bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2); |
187 bool result1 = pf1.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty); |
188 |
188 |
189 #if DEBUG_YAPF_CACHE |
189 #if DEBUG_YAPF_CACHE |
190 Tpf pf2; |
190 Tpf pf2; |
191 pf2.DisableCache(true); |
191 pf2.DisableCache(true); |
192 bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2); |
192 bool result2 = pf2.CheckReverseTrain(v, t1, td1, t2, td2, reverse_penalty); |
193 if (result1 != result2) { |
193 if (result1 != result2) { |
194 DEBUG(yapf, 0, "CACHE ERROR: CheckReverseTrain() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F"); |
194 DEBUG(yapf, 0, "CACHE ERROR: CheckReverseTrain() = [%s, %s]", result1 ? "T" : "F", result2 ? "T" : "F"); |
195 } |
195 } |
196 #endif |
196 #endif |
197 |
197 |
198 return result1; |
198 return result1; |
199 } |
199 } |
200 |
200 |
201 FORCEINLINE bool CheckReverseTrain(Vehicle* v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2) |
201 FORCEINLINE bool CheckReverseTrain(Vehicle* v, TileIndex t1, Trackdir td1, TileIndex t2, Trackdir td2, int reverse_penalty) |
202 { |
202 { |
203 // create pathfinder instance |
203 // create pathfinder instance |
204 // set origin and destination nodes |
204 // set origin and destination nodes |
205 Yapf().SetOrigin(t1, td1, t2, td2, 1, false); |
205 Yapf().SetOrigin(t1, td1, t2, td2, reverse_penalty, false); |
206 Yapf().SetDestination(v); |
206 Yapf().SetDestination(v); |
207 |
207 |
208 // find the best path |
208 // find the best path |
209 bool bFound = Yapf().FindPath(v); |
209 bool bFound = Yapf().FindPath(v); |
210 |
210 |
263 return td_ret; |
263 return td_ret; |
264 } |
264 } |
265 |
265 |
266 bool YapfCheckReverseTrain(Vehicle* v) |
266 bool YapfCheckReverseTrain(Vehicle* v) |
267 { |
267 { |
268 // tile where the engine is |
268 /* last wagon */ |
269 TileIndex tile = v->tile; |
|
270 // tile where we have last wagon |
|
271 Vehicle* last_veh = GetLastVehicleInChain(v); |
269 Vehicle* last_veh = GetLastVehicleInChain(v); |
272 // if we are in tunnel then give up |
270 |
273 if (v->u.rail.track == 0x40 || last_veh->u.rail.track == 0x40) return false; |
|
274 // get trackdirs of both ends |
271 // get trackdirs of both ends |
275 Trackdir td = GetVehicleTrackdir(v); |
272 Trackdir td = GetVehicleTrackdir(v); |
276 Trackdir td_rev = ReverseTrackdir(GetVehicleTrackdir(last_veh)); |
273 Trackdir td_rev = ReverseTrackdir(GetVehicleTrackdir(last_veh)); |
277 |
274 |
278 |
275 /* tiles where front and back are */ |
279 typedef bool (*PfnCheckReverseTrain)(Vehicle*, TileIndex, Trackdir, TileIndex, Trackdir); |
276 TileIndex tile = v->tile; |
|
277 TileIndex tile_rev = last_veh->tile; |
|
278 |
|
279 int reverse_penalty = 0; |
|
280 |
|
281 if (v->u.rail.track == TRACK_BIT_WORMHOLE) { |
|
282 /* front in tunnel / on bridge */ |
|
283 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile); |
|
284 |
|
285 if (TrackdirToExitdir(td) == dir_into_wormhole) tile = GetOtherTunnelBridgeEnd(tile); |
|
286 /* Now 'tile' is the tunnel entry/bridge ramp the train will reach when driving forward */ |
|
287 |
|
288 /* Current position of the train in the wormhole */ |
|
289 TileIndex cur_tile = TileVirtXY(v->x_pos, v->y_pos); |
|
290 |
|
291 /* Add distance to drive in the wormhole as penalty for the forward path, i.e. bonus for the reverse path |
|
292 * Note: Negative penalties are ok for the start tile. */ |
|
293 reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH; |
|
294 } |
|
295 |
|
296 if (last_veh->u.rail.track == TRACK_BIT_WORMHOLE) { |
|
297 /* back in tunnel / on bridge */ |
|
298 DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev); |
|
299 |
|
300 if (TrackdirToExitdir(td_rev) == dir_into_wormhole) tile_rev = GetOtherTunnelBridgeEnd(tile_rev); |
|
301 /* Now 'tile_rev' is the tunnel entry/bridge ramp the train will reach when reversing */ |
|
302 |
|
303 /* Current position of the last wagon in the wormhole */ |
|
304 TileIndex cur_tile = TileVirtXY(last_veh->x_pos, last_veh->y_pos); |
|
305 |
|
306 /* Add distance to drive in the wormhole as penalty for the revere path. */ |
|
307 reverse_penalty += DistanceManhattan(cur_tile, tile_rev) * YAPF_TILE_LENGTH; |
|
308 } |
|
309 |
|
310 typedef bool (*PfnCheckReverseTrain)(Vehicle*, TileIndex, Trackdir, TileIndex, Trackdir, int); |
280 PfnCheckReverseTrain pfnCheckReverseTrain = CYapfRail1::stCheckReverseTrain; |
311 PfnCheckReverseTrain pfnCheckReverseTrain = CYapfRail1::stCheckReverseTrain; |
281 |
312 |
282 // check if non-default YAPF type needed |
313 // check if non-default YAPF type needed |
283 if (_patches.forbid_90_deg) { |
314 if (_patches.forbid_90_deg) { |
284 pfnCheckReverseTrain = &CYapfRail2::stCheckReverseTrain; // Trackdir, forbid 90-deg |
315 pfnCheckReverseTrain = &CYapfRail2::stCheckReverseTrain; // Trackdir, forbid 90-deg |
285 } |
316 } |
286 |
317 |
287 bool reverse = pfnCheckReverseTrain(v, tile, td, last_veh->tile, td_rev); |
318 /* slightly hackish: If the pathfinders finds a path, the cost of the first node is tested to distinguish between forward- and reverse-path. */ |
|
319 if (reverse_penalty == 0) reverse_penalty = 1; |
|
320 |
|
321 bool reverse = pfnCheckReverseTrain(v, tile, td, tile_rev, td_rev, reverse_penalty); |
288 |
322 |
289 return reverse; |
323 return reverse; |
290 } |
324 } |
291 |
325 |
292 bool YapfFindNearestRailDepotTwoWay(Vehicle *v, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed) |
326 bool YapfFindNearestRailDepotTwoWay(Vehicle *v, int max_distance, int reverse_penalty, TileIndex* depot_tile, bool* reversed) |