/** Directions to search towards given track bits and the ship's enter direction. */ static const DiagDirection _ship_search_directions[6][4] = { { DIAGDIR_NE, INVALID_DIAGDIR, DIAGDIR_SW, INVALID_DIAGDIR }, { INVALID_DIAGDIR, DIAGDIR_SE, INVALID_DIAGDIR, DIAGDIR_NW }, { INVALID_DIAGDIR, DIAGDIR_NE, DIAGDIR_NW, INVALID_DIAGDIR }, { DIAGDIR_SE, INVALID_DIAGDIR, INVALID_DIAGDIR, DIAGDIR_SW }, { DIAGDIR_NW, DIAGDIR_SW, INVALID_DIAGDIR, INVALID_DIAGDIR }, { INVALID_DIAGDIR, INVALID_DIAGDIR, DIAGDIR_SE, DIAGDIR_NE }, }; /** Track to "direction (& 3)" mapping. */ static const byte _pick_shiptrack_table[6] = {DIR_NE, DIR_SE, DIR_E, DIR_E, DIR_N, DIR_N}; static uint FindShipTrack(const Ship *v, TileIndex tile, DiagDirection dir, TrackBits bits, TileIndex skiptile, Track *track) { TrackPathFinder pfs; uint best_bird_dist = 0; uint best_length = 0; byte ship_dir = v->direction & 3; pfs.dest_coords = v->dest_tile; pfs.skiptile = skiptile; Track best_track = INVALID_TRACK; assert(bits != TRACK_BIT_NONE); do { Track i = RemoveFirstTrack(&bits); pfs.best_bird_dist = UINT_MAX; pfs.best_length = UINT_MAX; OPFShipFollowTrack(tile, _ship_search_directions[i][dir], &pfs); if (best_track != INVALID_TRACK) { if (pfs.best_bird_dist != 0) { /* neither reached the destination, pick the one with the smallest bird dist */ if (pfs.best_bird_dist > best_bird_dist) goto bad; if (pfs.best_bird_dist < best_bird_dist) goto good; } else { if (pfs.best_length > best_length) goto bad; if (pfs.best_length < best_length) goto good; } TileIndex tile_i = TileAddByDiagDir(tile, TrackdirToExitdir(TrackEnterdirToTrackdir(i, dir))); TileIndex tile_best_track = TileAddByDiagDir(tile, TrackdirToExitdir(TrackEnterdirToTrackdir(best_track, dir))); if (IsValidTile(tile_i) && IsValidTile(tile_best_track)) { uint distancempm_i = DistanceMaxPlusManhattan(pfs.dest_coords, tile_i); uint distancempm_best_track = DistanceMaxPlusManhattan(pfs.dest_coords, tile_best_track); uint distancem_i = DistanceManhattan(pfs.dest_coords, tile_i); uint distancem_best_track = DistanceManhattan(pfs.dest_coords, tile_best_track); uint distances_i = DistanceSquare(pfs.dest_coords, tile_i); uint distances_best_track = DistanceSquare(pfs.dest_coords, tile_best_track); assert((distancempm_i < distancempm_best_track) == (distances_i < distances_best_track)); assert((distancempm_i == distancempm_best_track) == (distances_i == distances_best_track)); assert((distancempm_i > distancempm_best_track) == (distances_i > distances_best_track)); if (distancempm_i > distancempm_best_track) goto bad; if (distancempm_i < distancempm_best_track) goto good; if (distances_i > distances_best_track) goto bad; if (distances_i < distances_best_track) goto good; if (distancem_i > distancem_best_track) goto bad; if (distancem_i < distancem_best_track) goto good; } /* if we reach this position, there's two paths of equal value so far. * pick one randomly. */ uint r = GB(Random(), 0, 8); if (_pick_shiptrack_table[i] == ship_dir) r += 80; if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80; if (r <= 127) goto bad; } good:; best_track = i; best_bird_dist = pfs.best_bird_dist; best_length = pfs.best_length; bad:; } while (bits != TRACK_BIT_NONE); *track = best_track; return best_bird_dist; }