00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../../stdafx.h"
00013 #include "../../tunnelbridge_map.h"
00014 #include "../../tunnelbridge.h"
00015 #include "../../ship.h"
00016 #include "../../core/random_func.hpp"
00017
00018 struct RememberData {
00019 uint16 cur_length;
00020 byte depth;
00021 Track last_choosen_track;
00022 };
00023
00024 struct TrackPathFinder {
00025 TileIndex skiptile;
00026 TileIndex dest_coords;
00027 uint best_bird_dist;
00028 uint best_length;
00029 RememberData rd;
00030 TrackdirByte the_dir;
00031 };
00032
00033 static bool ShipTrackFollower(TileIndex tile, TrackPathFinder *pfs, uint length)
00034 {
00035
00036 if (tile == pfs->dest_coords) {
00037 pfs->best_bird_dist = 0;
00038
00039 pfs->best_length = minu(pfs->best_length, length);
00040 return true;
00041 }
00042
00043
00044 if (tile != pfs->skiptile) {
00045 pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile));
00046 }
00047
00048 return false;
00049 }
00050
00051 static void TPFModeShip(TrackPathFinder *tpf, TileIndex tile, DiagDirection direction)
00052 {
00053 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00054
00055 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) return;
00056
00057 DiagDirection dir = GetTunnelBridgeDirection(tile);
00058
00059 if (dir == direction) {
00060 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
00061
00062 tpf->rd.cur_length += GetTunnelBridgeLength(tile, endtile) + 1;
00063
00064 tile = endtile;
00065 } else {
00066
00067 if (ReverseDiagDir(dir) != direction) return;
00068 }
00069 }
00070
00071
00072
00073
00074 tile = TILE_MASK(tile + TileOffsByDiagDir(direction));
00075
00076 if (++tpf->rd.cur_length > 50) return;
00077
00078 TrackBits bits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(direction);
00079 if (bits == TRACK_BIT_NONE) return;
00080
00081 assert(TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY());
00082
00083 bool only_one_track = true;
00084 do {
00085 Track track = RemoveFirstTrack(&bits);
00086 if (bits != TRACK_BIT_NONE) only_one_track = false;
00087 RememberData rd = tpf->rd;
00088
00089
00090 if (!only_one_track && track != tpf->rd.last_choosen_track) {
00091 if (++tpf->rd.depth > 4) {
00092 tpf->rd = rd;
00093 return;
00094 }
00095 tpf->rd.last_choosen_track = track;
00096 }
00097
00098 tpf->the_dir = TrackEnterdirToTrackdir(track, direction);
00099
00100 if (!ShipTrackFollower(tile, tpf, tpf->rd.cur_length)) {
00101 TPFModeShip(tpf, tile, TrackdirToExitdir(tpf->the_dir));
00102 }
00103
00104 tpf->rd = rd;
00105 } while (bits != TRACK_BIT_NONE);
00106 }
00107
00108 static void OPFShipFollowTrack(TileIndex tile, DiagDirection direction, TrackPathFinder *tpf)
00109 {
00110 assert(IsValidDiagDirection(direction));
00111
00112
00113 tpf->rd.cur_length = 0;
00114 tpf->rd.depth = 0;
00115 tpf->rd.last_choosen_track = INVALID_TRACK;
00116
00117 ShipTrackFollower(tile, tpf, 0);
00118 TPFModeShip(tpf, tile, direction);
00119 }
00120
00122 static const DiagDirection _ship_search_directions[6][4] = {
00123 { DIAGDIR_NE, INVALID_DIAGDIR, DIAGDIR_SW, INVALID_DIAGDIR },
00124 { INVALID_DIAGDIR, DIAGDIR_SE, INVALID_DIAGDIR, DIAGDIR_NW },
00125 { INVALID_DIAGDIR, DIAGDIR_NE, DIAGDIR_NW, INVALID_DIAGDIR },
00126 { DIAGDIR_SE, INVALID_DIAGDIR, INVALID_DIAGDIR, DIAGDIR_SW },
00127 { DIAGDIR_NW, DIAGDIR_SW, INVALID_DIAGDIR, INVALID_DIAGDIR },
00128 { INVALID_DIAGDIR, INVALID_DIAGDIR, DIAGDIR_SE, DIAGDIR_NE },
00129 };
00130
00132 static const byte _pick_shiptrack_table[6] = {DIR_NE, DIR_SE, DIR_E, DIR_E, DIR_N, DIR_N};
00133
00134 static uint FindShipTrack(const Ship *v, TileIndex tile, DiagDirection dir, TrackBits bits, TileIndex skiptile, Track *track)
00135 {
00136 TrackPathFinder pfs;
00137 uint best_bird_dist = 0;
00138 uint best_length = 0;
00139 byte ship_dir = v->direction & 3;
00140
00141 pfs.dest_coords = v->dest_tile;
00142 pfs.skiptile = skiptile;
00143
00144 Track best_track = INVALID_TRACK;
00145
00146 do {
00147 Track i = RemoveFirstTrack(&bits);
00148
00149 pfs.best_bird_dist = UINT_MAX;
00150 pfs.best_length = UINT_MAX;
00151
00152 OPFShipFollowTrack(tile, _ship_search_directions[i][dir], &pfs);
00153
00154 if (best_track != INVALID_TRACK) {
00155 if (pfs.best_bird_dist != 0) {
00156
00157 if (pfs.best_bird_dist > best_bird_dist) goto bad;
00158 if (pfs.best_bird_dist < best_bird_dist) goto good;
00159 } else {
00160 if (pfs.best_length > best_length) goto bad;
00161 if (pfs.best_length < best_length) goto good;
00162 }
00163
00164
00165
00166 uint r = GB(Random(), 0, 8);
00167 if (_pick_shiptrack_table[i] == ship_dir) r += 80;
00168 if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80;
00169 if (r <= 127) goto bad;
00170 }
00171 good:;
00172 best_track = i;
00173 best_bird_dist = pfs.best_bird_dist;
00174 best_length = pfs.best_length;
00175 bad:;
00176
00177 } while (bits != 0);
00178
00179 *track = best_track;
00180 return best_bird_dist;
00181 }
00182
00188 Track OPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks, bool &path_found)
00189 {
00190 assert(IsValidDiagDirection(enterdir));
00191
00192 TileIndex tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir));
00193 Track track;
00194
00195
00196 TrackBits b = TrackStatusToTrackBits(GetTileTrackStatus(tile2, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(ReverseDiagDir(enterdir)) & v->state;
00197
00198 uint distr = UINT_MAX;
00199 if (b != 0) {
00200 distr = FindShipTrack(v, tile2, ReverseDiagDir(enterdir), b, tile, &track);
00201 if (distr != UINT_MAX) distr++;
00202 }
00203
00204
00205 uint dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track);
00206
00207
00208
00209
00210
00211
00212 path_found = (dist == 0 || distr == 1 || (!(v->vehicle_flags & VF_PATHFINDER_LOST) && min(dist, distr) < DistanceManhattan(tile, v->dest_tile)));
00213 if (dist <= distr) return track;
00214 return INVALID_TRACK;
00215 }