00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../../stdafx.h"
00013 #include "../../debug.h"
00014 #include "../../tunnelbridge_map.h"
00015 #include "../../tunnelbridge.h"
00016 #include "../../ship.h"
00017 #include "../../core/random_func.hpp"
00018 #include "opf_ship.h"
00019
00020 struct RememberData {
00021 uint16 cur_length;
00022 byte depth;
00023 Track last_choosen_track;
00024 };
00025
00026 struct TrackPathFinder {
00027 TileIndex skiptile;
00028 TileIndex dest_coords;
00029 uint best_bird_dist;
00030 uint best_length;
00031 RememberData rd;
00032 TrackdirByte the_dir;
00033 };
00034
00035 static bool ShipTrackFollower(TileIndex tile, TrackPathFinder *pfs, uint length)
00036 {
00037
00038 if (tile == pfs->dest_coords) {
00039 pfs->best_bird_dist = 0;
00040
00041 pfs->best_length = minu(pfs->best_length, length);
00042 return true;
00043 }
00044
00045
00046 if (tile != pfs->skiptile) {
00047 pfs->best_bird_dist = minu(pfs->best_bird_dist, DistanceMaxPlusManhattan(pfs->dest_coords, tile));
00048 }
00049
00050 return false;
00051 }
00052
00053 static void TPFModeShip(TrackPathFinder *tpf, TileIndex tile, DiagDirection direction)
00054 {
00055 if (IsTileType(tile, MP_TUNNELBRIDGE)) {
00056
00057 if (GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) return;
00058
00059 DiagDirection dir = GetTunnelBridgeDirection(tile);
00060
00061 if (dir == direction) {
00062 TileIndex endtile = GetOtherTunnelBridgeEnd(tile);
00063
00064 tpf->rd.cur_length += GetTunnelBridgeLength(tile, endtile) + 1;
00065
00066 tile = endtile;
00067 } else {
00068
00069 if (ReverseDiagDir(dir) != direction) return;
00070 }
00071 }
00072
00073
00074
00075
00076 tile = TILE_MASK(tile + TileOffsByDiagDir(direction));
00077
00078 if (++tpf->rd.cur_length > 50) return;
00079
00080 TrackBits bits = TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(direction);
00081 if (bits == TRACK_BIT_NONE) return;
00082
00083 assert(TileX(tile) != MapMaxX() && TileY(tile) != MapMaxY());
00084
00085 bool only_one_track = true;
00086 do {
00087 Track track = RemoveFirstTrack(&bits);
00088 if (bits != TRACK_BIT_NONE) only_one_track = false;
00089 RememberData rd = tpf->rd;
00090
00091
00092 if (!only_one_track && track != tpf->rd.last_choosen_track) {
00093 if (++tpf->rd.depth > 4) {
00094 tpf->rd = rd;
00095 return;
00096 }
00097 tpf->rd.last_choosen_track = track;
00098 }
00099
00100 tpf->the_dir = TrackEnterdirToTrackdir(track, direction);
00101
00102 if (!ShipTrackFollower(tile, tpf, tpf->rd.cur_length)) {
00103 TPFModeShip(tpf, tile, TrackdirToExitdir(tpf->the_dir));
00104 }
00105
00106 tpf->rd = rd;
00107 } while (bits != TRACK_BIT_NONE);
00108 }
00109
00110 static void OPFShipFollowTrack(TileIndex tile, DiagDirection direction, TrackPathFinder *tpf)
00111 {
00112 assert(IsValidDiagDirection(direction));
00113
00114
00115 tpf->rd.cur_length = 0;
00116 tpf->rd.depth = 0;
00117 tpf->rd.last_choosen_track = INVALID_TRACK;
00118
00119 ShipTrackFollower(tile, tpf, 0);
00120 TPFModeShip(tpf, tile, direction);
00121 }
00122
00123 static const byte _ship_search_directions[6][4] = {
00124 { 0, 9, 2, 9 },
00125 { 9, 1, 9, 3 },
00126 { 9, 0, 3, 9 },
00127 { 1, 9, 9, 2 },
00128 { 3, 2, 9, 9 },
00129 { 9, 9, 1, 0 },
00130 };
00131
00132 static const byte _pick_shiptrack_table[6] = {1, 3, 2, 2, 0, 0};
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, (DiagDirection)_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
00186 Track OPFShipChooseTrack(const Ship *v, TileIndex tile, DiagDirection enterdir, TrackBits tracks)
00187 {
00188 assert(IsValidDiagDirection(enterdir));
00189
00190 TileIndex tile2 = TILE_ADD(tile, -TileOffsByDiagDir(enterdir));
00191 Track track;
00192
00193
00194 TrackBits b = TrackStatusToTrackBits(GetTileTrackStatus(tile2, TRANSPORT_WATER, 0)) & DiagdirReachesTracks(ReverseDiagDir(enterdir)) & v->state;
00195
00196 uint distr = UINT_MAX;
00197 if (b != 0) {
00198 distr = FindShipTrack(v, tile2, ReverseDiagDir(enterdir), b, tile, &track);
00199 if (distr != UINT_MAX) distr++;
00200 }
00201
00202
00203 uint dist = FindShipTrack(v, tile, enterdir, tracks, 0, &track);
00204
00205 if (dist <= distr) return track;
00206 return INVALID_TRACK;
00207 }