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
00121 static const byte _ship_search_directions[6][4] = {
00122 { 0, 9, 2, 9 },
00123 { 9, 1, 9, 3 },
00124 { 9, 0, 3, 9 },
00125 { 1, 9, 9, 2 },
00126 { 3, 2, 9, 9 },
00127 { 9, 9, 1, 0 },
00128 };
00129
00130 static const byte _pick_shiptrack_table[6] = {1, 3, 2, 2, 0, 0};
00131
00132 static uint FindShipTrack(const Ship *v, TileIndex tile, DiagDirection dir, TrackBits bits, TileIndex skiptile, Track *track)
00133 {
00134 TrackPathFinder pfs;
00135 uint best_bird_dist = 0;
00136 uint best_length = 0;
00137 byte ship_dir = v->direction & 3;
00138
00139 pfs.dest_coords = v->dest_tile;
00140 pfs.skiptile = skiptile;
00141
00142 Track best_track = INVALID_TRACK;
00143
00144 do {
00145 Track i = RemoveFirstTrack(&bits);
00146
00147 pfs.best_bird_dist = UINT_MAX;
00148 pfs.best_length = UINT_MAX;
00149
00150 OPFShipFollowTrack(tile, (DiagDirection)_ship_search_directions[i][dir], &pfs);
00151
00152 if (best_track != INVALID_TRACK) {
00153 if (pfs.best_bird_dist != 0) {
00154
00155 if (pfs.best_bird_dist > best_bird_dist) goto bad;
00156 if (pfs.best_bird_dist < best_bird_dist) goto good;
00157 } else {
00158 if (pfs.best_length > best_length) goto bad;
00159 if (pfs.best_length < best_length) goto good;
00160 }
00161
00162
00163
00164 uint r = GB(Random(), 0, 8);
00165 if (_pick_shiptrack_table[i] == ship_dir) r += 80;
00166 if (_pick_shiptrack_table[best_track] == ship_dir) r -= 80;
00167 if (r <= 127) goto bad;
00168 }
00169 good:;
00170 best_track = i;
00171 best_bird_dist = pfs.best_bird_dist;
00172 best_length = pfs.best_length;
00173 bad:;
00174
00175 } while (bits != 0);
00176
00177 *track = best_track;
00178 return best_bird_dist;
00179 }
00180
00184 Track OPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
00185 {
00186 assert(IsValidDiagDirection(enterdir));
00187
00188 TileIndex tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir));
00189 Track track;
00190
00191
00192 TrackBits b = TrackStatusToTrackBits(GetTileTrackStatus(tile2, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(ReverseDiagDir(enterdir)) & v->state;
00193
00194 uint distr = UINT_MAX;
00195 if (b != 0) {
00196 distr = FindShipTrack(v, tile2, ReverseDiagDir(enterdir), b, tile, &track);
00197 if (distr != UINT_MAX) distr++;
00198 }
00199
00200
00201 uint dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track);
00202
00203 if (dist <= distr) return track;
00204 return INVALID_TRACK;
00205 }