mirror of https://github.com/OpenTTD/OpenTTD
(svn r2635) Fix: [ntp/misc] Improve the old pathfinder. Changed it to A* instead of Dijkstra.
- Benchmark shows that NTP is now around 10x faster than NPF. - Made IsTunnelTile macro to determine if a tile is a tunnel. - Added some useful debugging functions for making tiles red / getting accurate timestamps. - Remove old depot finding algorithm. - Disable warning for signed/unsigned comparisons.release/0.4.5
parent
29f6ada06a
commit
3e97dda275
2
debug.c
2
debug.c
|
@ -15,6 +15,7 @@ int _debug_net_level;
|
||||||
int _debug_spritecache_level;
|
int _debug_spritecache_level;
|
||||||
int _debug_oldloader_level;
|
int _debug_oldloader_level;
|
||||||
int _debug_pbs_level;
|
int _debug_pbs_level;
|
||||||
|
int _debug_ntp_level;
|
||||||
#ifdef GPMI
|
#ifdef GPMI
|
||||||
int _debug_gpmi_level;
|
int _debug_gpmi_level;
|
||||||
#endif /* GPMI */
|
#endif /* GPMI */
|
||||||
|
@ -49,6 +50,7 @@ typedef struct DebugLevel {
|
||||||
DEBUG_LEVEL(spritecache),
|
DEBUG_LEVEL(spritecache),
|
||||||
DEBUG_LEVEL(oldloader),
|
DEBUG_LEVEL(oldloader),
|
||||||
DEBUG_LEVEL(pbs),
|
DEBUG_LEVEL(pbs),
|
||||||
|
DEBUG_LEVEL(ntp),
|
||||||
#ifdef GPMI
|
#ifdef GPMI
|
||||||
DEBUG_LEVEL(gpmi),
|
DEBUG_LEVEL(gpmi),
|
||||||
#endif
|
#endif
|
||||||
|
|
1
debug.h
1
debug.h
|
@ -15,6 +15,7 @@
|
||||||
extern int _debug_spritecache_level;
|
extern int _debug_spritecache_level;
|
||||||
extern int _debug_oldloader_level;
|
extern int _debug_oldloader_level;
|
||||||
extern int _debug_pbs_level;
|
extern int _debug_pbs_level;
|
||||||
|
extern int _debug_ntp_level;
|
||||||
#ifdef GPMI
|
#ifdef GPMI
|
||||||
extern int _debug_gpmi_level;
|
extern int _debug_gpmi_level;
|
||||||
#endif /* GPMI */
|
#endif /* GPMI */
|
||||||
|
|
|
@ -128,8 +128,8 @@ uint InteractiveRandomRange(uint max);
|
||||||
|
|
||||||
|
|
||||||
// Used for profiling
|
// Used for profiling
|
||||||
#define TIC() { extern uint32 rdtsc(void); uint32 _xxx_ = rdtsc();
|
#define TIC() { extern uint32 rdtsc(void); uint32 _xxx_ = rdtsc(); static float __avg__;
|
||||||
#define TOC(s) _xxx_ = rdtsc() - _xxx_; printf("%s: %d\n", s, _xxx_); }
|
#define TOC(s) _xxx_ = rdtsc() - _xxx_; __avg__=__avg__*0.99+_xxx_*0.01; printf("%s: %8d %f\n", s, _xxx_,__avg__); }
|
||||||
|
|
||||||
|
|
||||||
void SetDate(uint date);
|
void SetDate(uint date);
|
||||||
|
|
416
pathfind.c
416
pathfind.c
|
@ -45,7 +45,6 @@ static bool TPFSetTileBit(TrackPathFinder *tpf, TileIndex tile, int dir)
|
||||||
/* allocate a link. if out of links, handle this by returning
|
/* allocate a link. if out of links, handle this by returning
|
||||||
* that a tile was already visisted. */
|
* that a tile was already visisted. */
|
||||||
if (tpf->num_links_left == 0) {
|
if (tpf->num_links_left == 0) {
|
||||||
DEBUG(misc, 4) ("[NTP] no links left\n");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tpf->num_links_left--;
|
tpf->num_links_left--;
|
||||||
|
@ -84,7 +83,6 @@ static bool TPFSetTileBit(TrackPathFinder *tpf, TileIndex tile, int dir)
|
||||||
/* get here if we need to add a new link to link,
|
/* get here if we need to add a new link to link,
|
||||||
* first, allocate a new link, in the same way as before */
|
* first, allocate a new link, in the same way as before */
|
||||||
if (tpf->num_links_left == 0) {
|
if (tpf->num_links_left == 0) {
|
||||||
DEBUG(misc, 4)("[NTP] no links left\n");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tpf->num_links_left--;
|
tpf->num_links_left--;
|
||||||
|
@ -125,11 +123,6 @@ static const byte _otherdir_mask[4] = {
|
||||||
0x2A,
|
0x2A,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef DEBUG_TILE_PUSH
|
|
||||||
extern void dbg_push_tile(TileIndex tile, int track);
|
|
||||||
extern void dbg_pop_tile();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void TPFMode2(TrackPathFinder *tpf, TileIndex tile, int direction)
|
static void TPFMode2(TrackPathFinder *tpf, TileIndex tile, int direction)
|
||||||
{
|
{
|
||||||
uint bits;
|
uint bits;
|
||||||
|
@ -198,15 +191,9 @@ static void TPFMode2(TrackPathFinder *tpf, TileIndex tile, int direction)
|
||||||
continue_here:;
|
continue_here:;
|
||||||
tpf->the_dir = HASBIT(_otherdir_mask[direction],i) ? (i+8) : i;
|
tpf->the_dir = HASBIT(_otherdir_mask[direction],i) ? (i+8) : i;
|
||||||
|
|
||||||
#ifdef DEBUG_TILE_PUSH
|
|
||||||
dbg_push_tile(tile, tpf->the_dir);
|
|
||||||
#endif
|
|
||||||
if (!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, NULL)) {
|
if (!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, NULL)) {
|
||||||
TPFMode2(tpf, tile, _tpf_new_direction[tpf->the_dir]);
|
TPFMode2(tpf, tile, _tpf_new_direction[tpf->the_dir]);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_TILE_PUSH
|
|
||||||
dbg_pop_tile();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
tpf->rd = rd;
|
tpf->rd = rd;
|
||||||
} while (++i, bits>>=1);
|
} while (++i, bits>>=1);
|
||||||
|
@ -327,16 +314,10 @@ static void TPFMode1(TrackPathFinder *tpf, TileIndex tile, int direction)
|
||||||
tpf->the_dir = (_otherdir_mask[direction] & (byte)(1 << i)) ? (i+8) : i;
|
tpf->the_dir = (_otherdir_mask[direction] & (byte)(1 << i)) ? (i+8) : i;
|
||||||
rd = tpf->rd;
|
rd = tpf->rd;
|
||||||
|
|
||||||
#ifdef DEBUG_TILE_PUSH
|
|
||||||
dbg_push_tile(tile, tpf->the_dir);
|
|
||||||
#endif
|
|
||||||
if (TPFSetTileBit(tpf, tile, tpf->the_dir) &&
|
if (TPFSetTileBit(tpf, tile, tpf->the_dir) &&
|
||||||
!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, &tpf->rd.pft_var6) ) {
|
!tpf->enum_proc(tile, tpf->userdata, tpf->the_dir, tpf->rd.cur_length, &tpf->rd.pft_var6) ) {
|
||||||
TPFMode1(tpf, tile, _tpf_new_direction[tpf->the_dir]);
|
TPFMode1(tpf, tile, _tpf_new_direction[tpf->the_dir]);
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_TILE_PUSH
|
|
||||||
dbg_pop_tile();
|
|
||||||
#endif
|
|
||||||
tpf->rd = rd;
|
tpf->rd = rd;
|
||||||
} while (bits != 0);
|
} while (bits != 0);
|
||||||
}
|
}
|
||||||
|
@ -422,7 +403,8 @@ void FollowTrack(TileIndex tile, uint16 flags, byte direction, TPFEnumProc *enum
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TileIndex tile;
|
TileIndex tile;
|
||||||
uint16 cur_length;
|
uint16 cur_length; // This is the current length to this tile.
|
||||||
|
uint16 priority; // This is the current length + estimated length to the goal.
|
||||||
byte track;
|
byte track;
|
||||||
byte depth;
|
byte depth;
|
||||||
byte state;
|
byte state;
|
||||||
|
@ -445,8 +427,9 @@ typedef struct HashLink {
|
||||||
} HashLink;
|
} HashLink;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TPFEnumProc *enum_proc;
|
NTPEnumProc *enum_proc;
|
||||||
void *userdata;
|
void *userdata;
|
||||||
|
TileIndex dest;
|
||||||
|
|
||||||
byte tracktype;
|
byte tracktype;
|
||||||
uint maxlength;
|
uint maxlength;
|
||||||
|
@ -457,7 +440,7 @@ typedef struct {
|
||||||
uint nstack;
|
uint nstack;
|
||||||
StackedItem stack[256]; // priority queue of stacked items
|
StackedItem stack[256]; // priority queue of stacked items
|
||||||
|
|
||||||
uint16 hash_head[0x400]; // hash heads. 0 means unused. 0xFFC0 = length, 0x3F = type
|
uint16 hash_head[0x400]; // hash heads. 0 means unused. 0xFFFC = length, 0x3 = dir
|
||||||
TileIndex hash_tile[0x400]; // tiles. or links.
|
TileIndex hash_tile[0x400]; // tiles. or links.
|
||||||
|
|
||||||
HashLink links[0x400]; // hash links
|
HashLink links[0x400]; // hash links
|
||||||
|
@ -475,7 +458,7 @@ static inline void HeapifyUp(NewTrackPathFinder *tpf)
|
||||||
StackedItem si;
|
StackedItem si;
|
||||||
int i = ++tpf->nstack;
|
int i = ++tpf->nstack;
|
||||||
|
|
||||||
while (i != 1 && ARR(i).cur_length < ARR(i>>1).cur_length) {
|
while (i != 1 && ARR(i).priority < ARR(i>>1).priority) {
|
||||||
// the child element is larger than the parent item.
|
// the child element is larger than the parent item.
|
||||||
// swap the child item and the parent item.
|
// swap the child item and the parent item.
|
||||||
si = ARR(i); ARR(i) = ARR(i>>1); ARR(i>>1) = si;
|
si = ARR(i); ARR(i) = ARR(i>>1); ARR(i>>1) = si;
|
||||||
|
@ -500,11 +483,11 @@ static inline void HeapifyDown(NewTrackPathFinder *tpf)
|
||||||
|
|
||||||
while ((j=i*2) <= n) {
|
while ((j=i*2) <= n) {
|
||||||
// figure out which is smaller of the children.
|
// figure out which is smaller of the children.
|
||||||
if (j != n && ARR(j).cur_length > ARR(j+1).cur_length)
|
if (j != n && ARR(j).priority > ARR(j+1).priority)
|
||||||
j++; // right item is smaller
|
j++; // right item is smaller
|
||||||
|
|
||||||
assert(i <= n && j <= n);
|
assert(i <= n && j <= n);
|
||||||
if (ARR(i).cur_length <= ARR(j).cur_length)
|
if (ARR(i).priority <= ARR(j).priority)
|
||||||
break; // base elem smaller than smallest, done!
|
break; // base elem smaller than smallest, done!
|
||||||
|
|
||||||
// swap parent with the child
|
// swap parent with the child
|
||||||
|
@ -544,8 +527,11 @@ static bool NtpVisit(NewTrackPathFinder *tpf, TileIndex tile, uint dir, uint len
|
||||||
// two tiles with the same hash, need to make a link
|
// two tiles with the same hash, need to make a link
|
||||||
// allocate a link. if out of links, handle this by returning
|
// allocate a link. if out of links, handle this by returning
|
||||||
// that a tile was already visisted.
|
// that a tile was already visisted.
|
||||||
if (tpf->num_links_left == 0)
|
if (tpf->num_links_left == 0) {
|
||||||
|
DEBUG(ntp, 1) ("[NTP] no links left");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
tpf->num_links_left--;
|
tpf->num_links_left--;
|
||||||
link = tpf->new_link++;
|
link = tpf->new_link++;
|
||||||
|
|
||||||
|
@ -575,8 +561,10 @@ static bool NtpVisit(NewTrackPathFinder *tpf, TileIndex tile, uint dir, uint len
|
||||||
|
|
||||||
/* get here if we need to add a new link to link,
|
/* get here if we need to add a new link to link,
|
||||||
* first, allocate a new link, in the same way as before */
|
* first, allocate a new link, in the same way as before */
|
||||||
if (tpf->num_links_left == 0)
|
if (tpf->num_links_left == 0) {
|
||||||
return false;
|
DEBUG(ntp, 1) ("[NTP] no links left");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
tpf->num_links_left--;
|
tpf->num_links_left--;
|
||||||
new_link = tpf->new_link++;
|
new_link = tpf->new_link++;
|
||||||
|
|
||||||
|
@ -638,155 +626,239 @@ static const uint16 _is_upwards_slope[15] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define DIAG_FACTOR 3
|
||||||
|
#define STR_FACTOR 2
|
||||||
|
|
||||||
|
|
||||||
|
static uint DistanceMoo(TileIndex t0, TileIndex t1)
|
||||||
|
{
|
||||||
|
const uint dx = abs(TileX(t0) - TileX(t1));
|
||||||
|
const uint dy = abs(TileY(t0) - TileY(t1));
|
||||||
|
|
||||||
|
const uint straightTracks = 2 * min(dx, dy); /* The number of straight (not full length) tracks */
|
||||||
|
/* OPTIMISATION:
|
||||||
|
* Original: diagTracks = max(dx, dy) - min(dx,dy);
|
||||||
|
* Proof:
|
||||||
|
* (dx-dy) - straightTracks == (min + max) - straightTracks = min + // max - 2 * min = max - min */
|
||||||
|
const uint diagTracks = dx + dy - straightTracks; /* The number of diagonal (full tile length) tracks. */
|
||||||
|
|
||||||
|
return diagTracks*DIAG_FACTOR + straightTracks*STR_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These has to be small cause the max length of a track
|
||||||
|
// is currently limited to 16384
|
||||||
|
|
||||||
|
static const byte _length_of_track[16] = {
|
||||||
|
DIAG_FACTOR,DIAG_FACTOR,STR_FACTOR,STR_FACTOR,STR_FACTOR,STR_FACTOR,0,0,
|
||||||
|
DIAG_FACTOR,DIAG_FACTOR,STR_FACTOR,STR_FACTOR,STR_FACTOR,STR_FACTOR,0,0
|
||||||
|
};
|
||||||
|
|
||||||
// new more optimized pathfinder for trains...
|
// new more optimized pathfinder for trains...
|
||||||
|
// Tile is the tile the train is at.
|
||||||
|
// direction is the tile the train is moving towards.
|
||||||
|
|
||||||
static void NTPEnum(NewTrackPathFinder *tpf, TileIndex tile, uint direction)
|
static void NTPEnum(NewTrackPathFinder *tpf, TileIndex tile, uint direction)
|
||||||
{
|
{
|
||||||
uint bits, tile_org;
|
uint bits, tile_org, track;
|
||||||
int i;
|
|
||||||
StackedItem si;
|
StackedItem si;
|
||||||
FindLengthOfTunnelResult flotr;
|
FindLengthOfTunnelResult flotr;
|
||||||
|
int estimation;
|
||||||
|
|
||||||
si.cur_length = 0;
|
// Need to have a special case for the start.
|
||||||
|
// We shouldn't call the callback for the current tile.
|
||||||
|
si.cur_length = 1; // Need to start at 1 cause 0 is a reserved value.
|
||||||
si.depth = 0;
|
si.depth = 0;
|
||||||
si.state = 0;
|
si.state = 0;
|
||||||
|
goto start_at;
|
||||||
restart:
|
|
||||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && (_m[tile].m5 & 0xF0) == 0) {
|
|
||||||
/* This is a tunnel tile */
|
|
||||||
if ( (uint)(_m[tile].m5 & 3) != (direction ^ 2)) { /* ^ 2 is reversing the direction */
|
|
||||||
/* We are not just driving out of the tunnel */
|
|
||||||
if ( (uint)(_m[tile].m5 & 3) != direction || ((_m[tile].m5>>1)&6) != tpf->tracktype)
|
|
||||||
/* We are not driving into the tunnel, or it
|
|
||||||
* is an invalid tunnel */
|
|
||||||
goto stop_search;
|
|
||||||
flotr = FindLengthOfTunnel(tile, direction);
|
|
||||||
si.cur_length += flotr.length;
|
|
||||||
tile = flotr.tile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// remember the start tile so we know if we're in an inf loop.
|
|
||||||
tile_org = tile;
|
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
int track;
|
// Get the next item to search from from the priority queue
|
||||||
|
do {
|
||||||
|
if (tpf->nstack == 0)
|
||||||
|
return; // nothing left? then we're done!
|
||||||
|
si = tpf->stack[0];
|
||||||
|
tile = si.tile;
|
||||||
|
|
||||||
tile += TileOffsByDir(direction);
|
HeapifyDown(tpf);
|
||||||
|
// Make sure we havn't already visited this tile.
|
||||||
|
} while (!NtpCheck(tpf, tile, _tpf_prev_direction[si.track], si.cur_length));
|
||||||
|
|
||||||
// too long search length? bail out.
|
// Add the length of this track.
|
||||||
if (++si.cur_length >= tpf->maxlength) {
|
si.cur_length += _length_of_track[si.track];
|
||||||
DEBUG(misc,4) ("[NTP] cur_length too big\n");
|
|
||||||
goto stop_search;
|
callback_and_continue:
|
||||||
|
if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
|
||||||
|
return;
|
||||||
|
|
||||||
|
direction = _tpf_new_direction[si.track];
|
||||||
|
|
||||||
|
start_at:
|
||||||
|
// If the tile is the entry tile of a tunnel, and we're not going out of the tunnel,
|
||||||
|
// need to find the exit of the tunnel.
|
||||||
|
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||||
|
if ((_m[tile].m5 & 0xF0) == 0 &&
|
||||||
|
(uint)(_m[tile].m5 & 3) != (direction ^ 2)) {
|
||||||
|
/* This is a tunnel tile */
|
||||||
|
/* We are not just driving out of the tunnel */
|
||||||
|
if ( (uint)(_m[tile].m5 & 3) != direction || ((_m[tile].m5>>1)&6) != tpf->tracktype)
|
||||||
|
/* We are not driving into the tunnel, or it
|
||||||
|
* is an invalid tunnel */
|
||||||
|
continue;
|
||||||
|
flotr = FindLengthOfTunnel(tile, direction);
|
||||||
|
si.cur_length += flotr.length * DIAG_FACTOR;
|
||||||
|
tile = flotr.tile;
|
||||||
|
// tile now points to the exit tile of the tunnel
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not a regular rail tile?
|
// This is a special loop used to go through
|
||||||
// Then we can't use the code below, but revert to more general code.
|
// a rail net and find the first intersection
|
||||||
if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) {
|
tile_org = tile;
|
||||||
bits = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _tpfmode1_and[direction];
|
for(;;) {
|
||||||
bits = (bits | (bits >> 8)) & 0x3F;
|
tile += TileOffsByDir(direction);
|
||||||
if (bits == 0) goto stop_search;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// regular rail tile, determine the tracks that are actually reachable.
|
// too long search length? bail out.
|
||||||
bits = _m[tile].m5 & _bits_mask[direction];
|
if (si.cur_length >= tpf->maxlength) {
|
||||||
if (bits == 0) goto stop_search; // no tracks there? stop searching.
|
DEBUG(ntp,1) ("[NTP] cur_length too big");
|
||||||
|
bits = 0;
|
||||||
// intersection? then we need to branch the search space,
|
break;
|
||||||
// can't handle that from here.
|
|
||||||
if (KILL_FIRST_BIT(bits) != 0) break;
|
|
||||||
|
|
||||||
track = _new_track[FIND_FIRST_BIT(bits)][direction];
|
|
||||||
|
|
||||||
// Check if this rail is an upwards slope. If it is, then add a penalty.
|
|
||||||
// Small optimization here.. if (track&7)>1 then it can't be a slope so we avoid calling GetTileSlope
|
|
||||||
if ((track & 7) <= 1 && (_is_upwards_slope[GetTileSlope(tile, NULL)] & (1 << track)) ) {
|
|
||||||
// upwards slope. add some penalty.
|
|
||||||
si.cur_length += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// railway tile with signals..?
|
|
||||||
if (HasSignals(tile)) {
|
|
||||||
byte m3;
|
|
||||||
|
|
||||||
m3 = _m[tile].m3;
|
|
||||||
if (!(m3 & SignalAlongTrackdir(track))) {
|
|
||||||
// if one way signal not pointing towards us, stop going in this direction.
|
|
||||||
if (m3 & SignalAgainstTrackdir(track))
|
|
||||||
goto stop_search;
|
|
||||||
} else if (_m[tile].m2 & SignalAlongTrackdir(track)) {
|
|
||||||
// green signal in our direction. either one way or two way.
|
|
||||||
si.state |= 1;
|
|
||||||
} else {
|
|
||||||
// reached a red signal.
|
|
||||||
if (m3 & SignalAgainstTrackdir(track)) {
|
|
||||||
// two way red signal. unless we passed another green signal on the way,
|
|
||||||
// stop going in this direction.
|
|
||||||
// this is to prevent us from going into a full platform.
|
|
||||||
if (!(si.state&1))
|
|
||||||
goto stop_search;
|
|
||||||
}
|
|
||||||
// add some penalty since this path has a red signal on it.
|
|
||||||
// only add this penalty max 2 times.
|
|
||||||
if ((si.state & 6) != 4) {
|
|
||||||
si.cur_length += 10;
|
|
||||||
si.state += 2; // remember that we added penalty.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tpf->enum_proc(tile, tpf->userdata, track, si.cur_length, &si.state))
|
// Not a regular rail tile?
|
||||||
goto stop_search; // we should stop searching in this direction
|
// Then we can't use the code below, but revert to more general code.
|
||||||
|
if (!IsTileType(tile, MP_RAILWAY) || !IsPlainRailTile(tile)) {
|
||||||
|
// We found a tile which is not a normal railway tile.
|
||||||
|
// Determine which tracks that exist on this tile.
|
||||||
|
bits = GetTileTrackStatus(tile, TRANSPORT_RAIL) & _tpfmode1_and[direction];
|
||||||
|
bits = (bits | (bits >> 8)) & 0x3F;
|
||||||
|
|
||||||
|
// Check that the tile contains exactly one track
|
||||||
|
if (bits == 0 || KILL_FIRST_BIT(bits) != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
///////////////////
|
||||||
|
// If we reach here, the tile has exactly one track.
|
||||||
|
// tile - index to a tile that is not rail tile, but still straight (with optional signals)
|
||||||
|
// bits - bitmask of which track that exist on the tile (exactly one bit is set)
|
||||||
|
// direction - which direction are we moving in?
|
||||||
|
///////////////////
|
||||||
|
si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
|
||||||
|
si.cur_length += _length_of_track[si.track];
|
||||||
|
goto callback_and_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Regular rail tile, determine which tracks exist.
|
||||||
|
bits = _m[tile].m5 & 0x3F;
|
||||||
|
if (bits == 0)
|
||||||
|
break; // None at all?
|
||||||
|
|
||||||
|
// Make sure that the tile contains exactly ONE track
|
||||||
|
if (KILL_FIRST_BIT(bits) != 0) {
|
||||||
|
// It contained many tracks,
|
||||||
|
// but first, mask out the tracks that are not reachable
|
||||||
|
bits &= _bits_mask[direction];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
track = _new_track[FIND_FIRST_BIT(bits)][direction];
|
||||||
|
si.cur_length += _length_of_track[track];
|
||||||
|
|
||||||
|
// Check if this rail is an upwards slope. If it is, then add a penalty.
|
||||||
|
// Small optimization here.. if (track&7)>1 then it can't be a slope so we avoid calling GetTileSlope
|
||||||
|
if ((track & 7) <= 1 && (_is_upwards_slope[GetTileSlope(tile, NULL)] & (1 << track)) ) {
|
||||||
|
// upwards slope. add some penalty.
|
||||||
|
si.cur_length += 4*DIAG_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// railway tile with signals..?
|
||||||
|
if (HasSignals(tile)) {
|
||||||
|
byte m3;
|
||||||
|
|
||||||
|
m3 = _m[tile].m3;
|
||||||
|
if (!(m3 & SignalAlongTrackdir(track))) {
|
||||||
|
// if one way signal not pointing towards us, stop going in this direction.
|
||||||
|
if (m3 & SignalAgainstTrackdir(track)) {
|
||||||
|
bits = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (_m[tile].m2 & SignalAlongTrackdir(track)) {
|
||||||
|
// green signal in our direction. either one way or two way.
|
||||||
|
si.state |= 3;
|
||||||
|
} else {
|
||||||
|
// reached a red signal.
|
||||||
|
if (m3 & SignalAgainstTrackdir(track)) {
|
||||||
|
// two way red signal. unless we passed another green signal on the way,
|
||||||
|
// stop going in this direction.
|
||||||
|
// this is to prevent us from going into a full platform.
|
||||||
|
if (!(si.state&1)) {
|
||||||
|
bits = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(si.state & 2)) {
|
||||||
|
// Is this the first signal we see? And it's red... add penalty
|
||||||
|
si.cur_length += 10*DIAG_FACTOR;
|
||||||
|
si.state += 2; // remember that we added penalty.
|
||||||
|
// Because we added a penalty, we can't just continue as usual.
|
||||||
|
// Need to get out and let A* do it's job with
|
||||||
|
// possibly finding an even shorter path.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tpf->enum_proc(tile, tpf->userdata, si.first_track, si.cur_length))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// continue with the next track
|
||||||
|
direction = _tpf_new_direction[track];
|
||||||
|
assert(direction != 0xFF);
|
||||||
|
|
||||||
|
// safety check if we're running around chasing our tail... (infinite loop)
|
||||||
|
if (tile == tile_org) {
|
||||||
|
bits = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// continue with the next track
|
// There are no tracks to choose between.
|
||||||
direction = _tpf_new_direction[track];
|
// Stop searching in this direction
|
||||||
assert(direction != 0xFF);
|
if (bits == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
// check if we're running around chasing our tail... (infinite loop)
|
////////////////
|
||||||
if (tile == tile_org)
|
// We got multiple tracks to choose between (intersection).
|
||||||
goto stop_search;
|
// Branch the search space into several branches.
|
||||||
}
|
////////////////
|
||||||
|
|
||||||
// if only one possible track to choose from, just continue
|
// Check if we've already visited this intersection.
|
||||||
if (KILL_FIRST_BIT(bits) == 0) {
|
// If we've already visited it with a better length, then
|
||||||
i = _new_track[FIND_FIRST_BIT(bits)][direction];
|
// there's no point in visiting it again.
|
||||||
// call the callback to check if we've reached the destination
|
if (!NtpVisit(tpf, tile, direction, si.cur_length))
|
||||||
if (tpf->enum_proc(tile, tpf->userdata, i, si.cur_length, &si.state))
|
continue;
|
||||||
goto stop_search; // we should stop searching in this direction.
|
|
||||||
|
|
||||||
// we should continue searching. determine new direction.
|
|
||||||
direction = _tpf_new_direction[i];
|
|
||||||
goto restart; // use tail recursion optimization.
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////
|
|
||||||
// We got multiple tracks to choose between (intersection).
|
|
||||||
// Branch the search space into several branches.
|
|
||||||
// Push each alternative on the stack.
|
|
||||||
////////////////
|
|
||||||
|
|
||||||
// Increase recursion depth counter, and
|
|
||||||
// Check so the depth is not too big.. to prevent enourmous slowdown.
|
|
||||||
if (si.depth >= _patches.pf_maxdepth) {
|
|
||||||
DEBUG(misc, 4) ("[NTP] depth too big\n");
|
|
||||||
goto stop_search;
|
|
||||||
}
|
|
||||||
si.depth++;
|
|
||||||
|
|
||||||
// Check if we've already visited this intersection.
|
|
||||||
// If we've already visited it with a better length, then
|
|
||||||
// there's no point in visiting it again.
|
|
||||||
if (NtpVisit(tpf, tile, direction, si.cur_length)) {
|
|
||||||
// Push all possible alternatives that we can reach from here
|
// Push all possible alternatives that we can reach from here
|
||||||
// onto the priority heap.
|
// onto the priority heap.
|
||||||
|
// 'bits' contains the tracks that we can choose between.
|
||||||
|
|
||||||
|
// First compute the estimated distance to the target.
|
||||||
|
// This is used to implement A*
|
||||||
|
estimation = 0;
|
||||||
|
if (tpf->dest != 0)
|
||||||
|
estimation = DistanceMoo(tile, tpf->dest);
|
||||||
|
|
||||||
|
si.depth++;
|
||||||
si.tile = tile;
|
si.tile = tile;
|
||||||
do {
|
do {
|
||||||
si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
|
si.track = _new_track[FIND_FIRST_BIT(bits)][direction];
|
||||||
|
si.priority = si.cur_length + estimation;
|
||||||
|
|
||||||
// out of stack items, bail out?
|
// out of stack items, bail out?
|
||||||
if (tpf->nstack >= lengthof(tpf->stack)) {
|
if (tpf->nstack >= lengthof(tpf->stack)) {
|
||||||
DEBUG(misc, 4) ("[NTP] out of stack\n");
|
DEBUG(ntp, 1) ("[NTP] out of stack");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
tpf->stack[tpf->nstack] = si;
|
tpf->stack[tpf->nstack] = si;
|
||||||
HeapifyUp(tpf);
|
HeapifyUp(tpf);
|
||||||
} while ((bits = KILL_FIRST_BIT(bits)) != 0);
|
} while ((bits = KILL_FIRST_BIT(bits)) != 0);
|
||||||
|
@ -795,54 +867,36 @@ restart:
|
||||||
// so the code outside knows which path is better.
|
// so the code outside knows which path is better.
|
||||||
// also randomize the order in which we search through them.
|
// also randomize the order in which we search through them.
|
||||||
if (si.depth == 1) {
|
if (si.depth == 1) {
|
||||||
uint32 r = Random();
|
assert(tpf->nstack == 1 || tpf->nstack == 2 || tpf->nstack == 3);
|
||||||
assert(tpf->nstack == 2 || tpf->nstack == 3);
|
if (tpf->nstack != 1) {
|
||||||
if (r&1) swap_byte(&tpf->stack[0].track, &tpf->stack[1].track);
|
uint32 r = Random();
|
||||||
if (tpf->nstack != 2) {
|
if (r&1) swap_byte(&tpf->stack[0].track, &tpf->stack[1].track);
|
||||||
byte t = tpf->stack[2].track;
|
if (tpf->nstack != 2) {
|
||||||
if (r&2) swap_byte(&tpf->stack[0].track, &t);
|
byte t = tpf->stack[2].track;
|
||||||
if (r&4) swap_byte(&tpf->stack[1].track, &t);
|
if (r&2) swap_byte(&tpf->stack[0].track, &t);
|
||||||
tpf->stack[2].first_track = tpf->stack[2].track = t;
|
if (r&4) swap_byte(&tpf->stack[1].track, &t);
|
||||||
|
tpf->stack[2].first_track = tpf->stack[2].track = t;
|
||||||
|
}
|
||||||
|
tpf->stack[0].first_track = tpf->stack[0].track;
|
||||||
|
tpf->stack[1].first_track = tpf->stack[1].track;
|
||||||
}
|
}
|
||||||
tpf->stack[0].first_track = tpf->stack[0].track;
|
|
||||||
tpf->stack[1].first_track = tpf->stack[1].track;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Continue with the next from the queue...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
stop_search:
|
|
||||||
// Now continue searching from the intersection that has the lowest
|
|
||||||
// cost.
|
|
||||||
// Pop the lowest cost item from the priority heap.
|
|
||||||
do {
|
|
||||||
if (tpf->nstack == 0)
|
|
||||||
return; // nothing left? then we're done!
|
|
||||||
si = tpf->stack[0];
|
|
||||||
tile = si.tile;
|
|
||||||
HeapifyDown(tpf);
|
|
||||||
|
|
||||||
// First check if we've already visited the tile we're just about to continue at.
|
|
||||||
// If we've already visited it, no point in continuing from there.
|
|
||||||
// Then call the callback.
|
|
||||||
} while (
|
|
||||||
!NtpCheck(tpf, tile, _tpf_prev_direction[si.track], si.cur_length) || // already have better path to that tile?
|
|
||||||
tpf->enum_proc(tile, tpf->userdata, si.track, si.cur_length, &si.state)
|
|
||||||
);
|
|
||||||
|
|
||||||
direction = _tpf_new_direction[si.track];
|
|
||||||
goto restart;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// new pathfinder for trains. better and faster.
|
// new pathfinder for trains. better and faster.
|
||||||
void NewTrainPathfind(TileIndex tile, byte direction, TPFEnumProc *enum_proc, void *data, byte *cache)
|
void NewTrainPathfind(TileIndex tile, TileIndex dest, byte direction, NTPEnumProc *enum_proc, void *data)
|
||||||
{
|
{
|
||||||
NewTrackPathFinder tpf;
|
NewTrackPathFinder tpf;
|
||||||
|
|
||||||
|
tpf.dest = dest;
|
||||||
tpf.userdata = data;
|
tpf.userdata = data;
|
||||||
tpf.enum_proc = enum_proc;
|
tpf.enum_proc = enum_proc;
|
||||||
tpf.tracktype = 0;
|
tpf.tracktype = 0;
|
||||||
tpf.maxlength = _patches.pf_maxlength;
|
tpf.maxlength = min(_patches.pf_maxlength * 3, 10000);
|
||||||
tpf.nstack = 0;
|
tpf.nstack = 0;
|
||||||
tpf.new_link = tpf.links;
|
tpf.new_link = tpf.links;
|
||||||
tpf.num_links_left = lengthof(tpf.links);
|
tpf.num_links_left = lengthof(tpf.links);
|
||||||
|
|
|
@ -8,6 +8,7 @@ typedef struct TrackPathFinder TrackPathFinder;
|
||||||
typedef bool TPFEnumProc(TileIndex tile, void *data, int track, uint length, byte *state);
|
typedef bool TPFEnumProc(TileIndex tile, void *data, int track, uint length, byte *state);
|
||||||
typedef void TPFAfterProc(TrackPathFinder *tpf);
|
typedef void TPFAfterProc(TrackPathFinder *tpf);
|
||||||
|
|
||||||
|
typedef bool NTPEnumProc(TileIndex tile, void *data, int track, uint length);
|
||||||
|
|
||||||
#define PATHFIND_GET_LINK_OFFS(tpf, link) ((byte*)(link) - (byte*)tpf->links)
|
#define PATHFIND_GET_LINK_OFFS(tpf, link) ((byte*)(link) - (byte*)tpf->links)
|
||||||
#define PATHFIND_GET_LINK_PTR(tpf, link_offs) (TrackPathFinderLink*)((byte*)tpf->links + (link_offs))
|
#define PATHFIND_GET_LINK_PTR(tpf, link_offs) (TrackPathFinderLink*)((byte*)tpf->links + (link_offs))
|
||||||
|
@ -63,6 +64,6 @@ typedef struct {
|
||||||
} FindLengthOfTunnelResult;
|
} FindLengthOfTunnelResult;
|
||||||
FindLengthOfTunnelResult FindLengthOfTunnel(TileIndex tile, int direction);
|
FindLengthOfTunnelResult FindLengthOfTunnel(TileIndex tile, int direction);
|
||||||
|
|
||||||
void NewTrainPathfind(TileIndex tile, byte direction, TPFEnumProc *enum_proc, void *data, byte *cache);
|
void NewTrainPathfind(TileIndex tile, TileIndex dest, byte direction, NTPEnumProc *enum_proc, void *data);
|
||||||
|
|
||||||
#endif /* PATHFIND_H */
|
#endif /* PATHFIND_H */
|
||||||
|
|
|
@ -872,7 +872,6 @@ const SettingDesc patch_settings[] = {
|
||||||
{"snow_line_height", SDT_UINT8, (void*)7, &_patches.snow_line_height, NULL},
|
{"snow_line_height", SDT_UINT8, (void*)7, &_patches.snow_line_height, NULL},
|
||||||
|
|
||||||
{"bribe", SDT_BOOL, (void*)true, &_patches.bribe, NULL},
|
{"bribe", SDT_BOOL, (void*)true, &_patches.bribe, NULL},
|
||||||
{"new_depot_finding", SDT_BOOL, (void*)false, &_patches.new_depot_finding, NULL},
|
|
||||||
|
|
||||||
{"nonuniform_stations", SDT_BOOL, (void*)true, &_patches.nonuniform_stations, NULL},
|
{"nonuniform_stations", SDT_BOOL, (void*)true, &_patches.nonuniform_stations, NULL},
|
||||||
{"always_small_airport",SDT_BOOL, (void*)false, &_patches.always_small_airport, NULL},
|
{"always_small_airport",SDT_BOOL, (void*)false, &_patches.always_small_airport, NULL},
|
||||||
|
|
|
@ -679,7 +679,6 @@ static const PatchEntry _patches_vehicles[] = {
|
||||||
{PE_BOOL, 0, STR_CONFIG_PATCHES_MAMMOTHTRAINS, "mammoth_trains", &_patches.mammoth_trains, 0, 0, 0, NULL},
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_MAMMOTHTRAINS, "mammoth_trains", &_patches.mammoth_trains, 0, 0, 0, NULL},
|
||||||
{PE_BOOL, 0, STR_CONFIG_PATCHES_GOTODEPOT, "goto_depot", &_patches.gotodepot, 0, 0, 0, NULL},
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_GOTODEPOT, "goto_depot", &_patches.gotodepot, 0, 0, 0, NULL},
|
||||||
{PE_BOOL, 0, STR_CONFIG_PATCHES_ROADVEH_QUEUE, "roadveh_queue", &_patches.roadveh_queue, 0, 0, 0, NULL},
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_ROADVEH_QUEUE, "roadveh_queue", &_patches.roadveh_queue, 0, 0, 0, NULL},
|
||||||
{PE_BOOL, 0, STR_CONFIG_PATCHES_NEW_DEPOT_FINDING,"depot_finding", &_patches.new_depot_finding, 0, 0, 0, NULL},
|
|
||||||
{PE_BOOL, 0, STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL, "new_pathfinding_all", &_patches.new_pathfinding_all, 0, 0, 0, NULL},
|
{PE_BOOL, 0, STR_CONFIG_PATCHES_NEW_PATHFINDING_ALL, "new_pathfinding_all", &_patches.new_pathfinding_all, 0, 0, 0, NULL},
|
||||||
|
|
||||||
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_WARN_INCOME_LESS, "train_income_warn", &_patches.train_income_warn, 0, 0, 0, NULL},
|
{PE_BOOL, PF_PLAYERBASED, STR_CONFIG_PATCHES_WARN_INCOME_LESS, "train_income_warn", &_patches.train_income_warn, 0, 0, 0, NULL},
|
||||||
|
|
2
stdafx.h
2
stdafx.h
|
@ -9,7 +9,7 @@
|
||||||
#pragma warning(disable: 4244) // conversion
|
#pragma warning(disable: 4244) // conversion
|
||||||
#pragma warning(disable: 4245) // conversion
|
#pragma warning(disable: 4245) // conversion
|
||||||
#pragma warning(disable: 4305) // 'initializing' : truncation from 'const int ' to 'char '
|
#pragma warning(disable: 4305) // 'initializing' : truncation from 'const int ' to 'char '
|
||||||
//#pragma warning(disable: 4018) // warning C4018: '==' : signed/unsigned mismatch
|
#pragma warning(disable: 4018) // warning C4018: '==' : signed/unsigned mismatch
|
||||||
#pragma warning(disable: 4201) // nameless union
|
#pragma warning(disable: 4201) // nameless union
|
||||||
#pragma warning(disable: 4514) // removed unref inline
|
#pragma warning(disable: 4514) // removed unref inline
|
||||||
#pragma warning(disable: 4127) // constant conditional expression
|
#pragma warning(disable: 4127) // constant conditional expression
|
||||||
|
|
7
tile.h
7
tile.h
|
@ -15,7 +15,7 @@ typedef enum TileTypes {
|
||||||
MP_VOID, // invisible tiles at the SW and SE border
|
MP_VOID, // invisible tiles at the SW and SE border
|
||||||
MP_INDUSTRY,
|
MP_INDUSTRY,
|
||||||
MP_TUNNELBRIDGE,
|
MP_TUNNELBRIDGE,
|
||||||
MP_UNMOVABLE
|
MP_UNMOVABLE,
|
||||||
} TileType;
|
} TileType;
|
||||||
|
|
||||||
/* Direction as commonly used in v->direction, 8 way. */
|
/* Direction as commonly used in v->direction, 8 way. */
|
||||||
|
@ -95,6 +95,11 @@ static inline bool IsTileType(TileIndex tile, TileType type)
|
||||||
return GetTileType(tile) == type;
|
return GetTileType(tile) == type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool IsTunnelTile(TileIndex tile)
|
||||||
|
{
|
||||||
|
return IsTileType(tile, MP_TUNNELBRIDGE) && (_m[tile].m5 & 0xF0) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static inline Owner GetTileOwner(TileIndex tile)
|
static inline Owner GetTileOwner(TileIndex tile)
|
||||||
{
|
{
|
||||||
assert(tile < MapSize());
|
assert(tile < MapSize());
|
||||||
|
|
75
train_cmd.c
75
train_cmd.c
|
@ -666,11 +666,6 @@ int32 CmdBuildRailVehicle(int x, int y, uint32 flags, uint32 p1, uint32 p2)
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsTunnelTile(TileIndex tile)
|
|
||||||
{
|
|
||||||
return IsTileType(tile, MP_TUNNELBRIDGE) && (_m[tile].m5 & 0x80) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Check if all the wagons of the given train are in a depot, returns the
|
/* Check if all the wagons of the given train are in a depot, returns the
|
||||||
* number of cars (including loco) then. If not, sets the error message to
|
* number of cars (including loco) then. If not, sets the error message to
|
||||||
|
@ -1307,9 +1302,7 @@ TileIndex GetVehicleTileOutOfTunnel(const Vehicle *v, bool reverse)
|
||||||
return v->tile;
|
return v->tile;
|
||||||
|
|
||||||
for (tile = v->tile;; tile += delta) {
|
for (tile = v->tile;; tile += delta) {
|
||||||
if (IsTileType(tile, MP_TUNNELBRIDGE) &&
|
if (IsTunnelTile(tile) && (_m[tile].m5 & 0x3) != (direction) && GetTileZ(tile) == v->z_pos)
|
||||||
(_m[tile].m5 & 0xF3) != (direction) &&
|
|
||||||
GetTileZ(tile) == v->z_pos)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return tile;
|
return tile;
|
||||||
|
@ -1569,26 +1562,17 @@ typedef struct TrainFindDepotData {
|
||||||
bool reverse;
|
bool reverse;
|
||||||
} TrainFindDepotData;
|
} TrainFindDepotData;
|
||||||
|
|
||||||
static bool TrainFindDepotEnumProc(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length, byte *state)
|
static bool NtpCallbFindDepot(TileIndex tile, TrainFindDepotData *tfdd, int track, uint length)
|
||||||
{
|
{
|
||||||
if (IsTileType(tile, MP_RAILWAY) && IsTileOwner(tile, tfdd->owner)) {
|
if (IsTileType(tile, MP_RAILWAY) && IsTileOwner(tile, tfdd->owner)) {
|
||||||
if ((_m[tile].m5 & ~0x3) == 0xC0) {
|
if ((_m[tile].m5 & ~0x3) == 0xC0) {
|
||||||
if (length < tfdd->best_length) {
|
tfdd->best_length = length;
|
||||||
tfdd->best_length = length;
|
tfdd->tile = tile;
|
||||||
tfdd->tile = tile;
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the train doesn't run against a oneway signal
|
|
||||||
if ((_m[tile].m5 & 0xC0) == 0x40) {
|
|
||||||
if (!(_m[tile].m3 & SignalAlongTrackdir(track)) && _m[tile].m3 & SignalAgainstTrackdir(track))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop searching if we've found a destination that is closer already.
|
return false;
|
||||||
return length >= tfdd->best_length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns the tile of a depot to goto to. The given vehicle must not be
|
// returns the tile of a depot to goto to. The given vehicle must not be
|
||||||
|
@ -1632,21 +1616,17 @@ static TrainFindDepotData FindClosestTrainDepot(Vehicle *v)
|
||||||
if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE))
|
if (NPFGetFlag(&ftd.node, NPF_FLAG_REVERSE))
|
||||||
tfdd.reverse = true;
|
tfdd.reverse = true;
|
||||||
}
|
}
|
||||||
} else if (!_patches.new_depot_finding) {
|
|
||||||
// search in all directions
|
|
||||||
for(i=0; i!=4; i++)
|
|
||||||
NewTrainPathfind(tile, i, (TPFEnumProc*)TrainFindDepotEnumProc, &tfdd, NULL);
|
|
||||||
} else {
|
} else {
|
||||||
// search in the forward direction first.
|
// search in the forward direction first.
|
||||||
i = v->direction >> 1;
|
i = v->direction >> 1;
|
||||||
if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { i = (i - 1) & 3; }
|
if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { i = (i - 1) & 3; }
|
||||||
NewTrainPathfind(tile, i, (TPFEnumProc*)TrainFindDepotEnumProc, &tfdd, NULL);
|
NewTrainPathfind(tile, 0, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
|
||||||
if (tfdd.best_length == (uint)-1){
|
if (tfdd.best_length == (uint)-1){
|
||||||
tfdd.reverse = true;
|
tfdd.reverse = true;
|
||||||
// search in backwards direction
|
// search in backwards direction
|
||||||
i = (v->direction^4) >> 1;
|
i = (v->direction^4) >> 1;
|
||||||
if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { i = (i - 1) & 3; }
|
if (!(v->direction & 1) && v->u.rail.track != _state_dir_table[i]) { i = (i - 1) & 3; }
|
||||||
NewTrainPathfind(tile, i, (TPFEnumProc*)TrainFindDepotEnumProc, &tfdd, NULL);
|
NewTrainPathfind(tile, 0, i, (NTPEnumProc*)NtpCallbFindDepot, &tfdd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1887,7 +1867,7 @@ typedef struct TrainTrackFollowerData {
|
||||||
byte best_track;
|
byte best_track;
|
||||||
} TrainTrackFollowerData;
|
} TrainTrackFollowerData;
|
||||||
|
|
||||||
static bool TrainTrackFollower(TileIndex tile, TrainTrackFollowerData *ttfd, int track, uint length, byte *state)
|
static bool NtpCallbFindStation(TileIndex tile, TrainTrackFollowerData *ttfd, int track, uint length)
|
||||||
{
|
{
|
||||||
// heading for nowhere?
|
// heading for nowhere?
|
||||||
if (ttfd->dest_coords == 0)
|
if (ttfd->dest_coords == 0)
|
||||||
|
@ -1900,24 +1880,16 @@ static bool TrainTrackFollower(TileIndex tile, TrainTrackFollowerData *ttfd, int
|
||||||
* because in that case the dest_coords are just an
|
* because in that case the dest_coords are just an
|
||||||
* approximation of where the station is */
|
* approximation of where the station is */
|
||||||
// found station
|
// found station
|
||||||
ttfd->best_bird_dist = 0;
|
ttfd->best_track = track;
|
||||||
if (length < ttfd->best_track_dist) {
|
|
||||||
ttfd->best_track_dist = length;
|
|
||||||
ttfd->best_track = state[1];
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
uint dist;
|
uint dist;
|
||||||
|
|
||||||
// we've actually found the destination already. no point searching in directions longer than this.
|
// didn't find station, keep track of the best path so far.
|
||||||
if (ttfd->best_track_dist != (uint)-1)
|
|
||||||
return length >= ttfd->best_track_dist;
|
|
||||||
|
|
||||||
// didn't find station
|
|
||||||
dist = DistanceManhattan(tile, ttfd->dest_coords);
|
dist = DistanceManhattan(tile, ttfd->dest_coords);
|
||||||
if (dist < ttfd->best_bird_dist) {
|
if (dist < ttfd->best_bird_dist) {
|
||||||
ttfd->best_bird_dist = dist;
|
ttfd->best_bird_dist = dist;
|
||||||
ttfd->best_track = state[1];
|
ttfd->best_track = track;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2046,7 +2018,8 @@ static byte ChooseTrainTrack(Vehicle *v, TileIndex tile, int enterdir, TrackdirB
|
||||||
fd.best_track_dist = (uint)-1;
|
fd.best_track_dist = (uint)-1;
|
||||||
fd.best_track = 0xFF;
|
fd.best_track = 0xFF;
|
||||||
|
|
||||||
NewTrainPathfind(tile - TileOffsByDir(enterdir), enterdir, (TPFEnumProc*)TrainTrackFollower, &fd, NULL);
|
NewTrainPathfind(tile - TileOffsByDir(enterdir), v->dest_tile,
|
||||||
|
enterdir, (NTPEnumProc*)NtpCallbFindStation, &fd);
|
||||||
|
|
||||||
if (fd.best_track == 0xff) {
|
if (fd.best_track == 0xff) {
|
||||||
// blaha
|
// blaha
|
||||||
|
@ -2118,7 +2091,7 @@ static bool CheckReverseTrain(Vehicle *v)
|
||||||
fd.best_bird_dist = (uint)-1;
|
fd.best_bird_dist = (uint)-1;
|
||||||
fd.best_track_dist = (uint)-1;
|
fd.best_track_dist = (uint)-1;
|
||||||
|
|
||||||
NewTrainPathfind(v->tile, reverse ^ i, (TPFEnumProc*)TrainTrackFollower, &fd, NULL);
|
NewTrainPathfind(v->tile, v->dest_tile, reverse ^ i, (NTPEnumProc*)NtpCallbFindStation, &fd);
|
||||||
|
|
||||||
if (best_track != -1) {
|
if (best_track != -1) {
|
||||||
if (best_bird_dist != 0) {
|
if (best_bird_dist != 0) {
|
||||||
|
@ -2861,18 +2834,15 @@ green_light:
|
||||||
/* in tunnel */
|
/* in tunnel */
|
||||||
GetNewVehiclePos(v, &gp);
|
GetNewVehiclePos(v, &gp);
|
||||||
|
|
||||||
if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) &&
|
// Check if to exit the tunnel...
|
||||||
!(_m[gp.new_tile].m5 & 0xF0)) {
|
if (!IsTunnelTile(gp.new_tile) ||
|
||||||
r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
|
!(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y)&0x4) ) {
|
||||||
if (r & 0x4) goto common;
|
v->x_pos = gp.x;
|
||||||
|
v->y_pos = gp.y;
|
||||||
|
VehiclePositionChanged(v);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
v->x_pos = gp.x;
|
|
||||||
v->y_pos = gp.y;
|
|
||||||
VehiclePositionChanged(v);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
common:;
|
|
||||||
|
|
||||||
/* update image of train, as well as delta XY */
|
/* update image of train, as well as delta XY */
|
||||||
newdir = GetNewVehicleDirection(v, gp.x, gp.y);
|
newdir = GetNewVehicleDirection(v, gp.x, gp.y);
|
||||||
|
@ -3125,8 +3095,7 @@ static bool TrainCheckIfLineEnds(Vehicle *v)
|
||||||
tile = v->tile;
|
tile = v->tile;
|
||||||
|
|
||||||
// tunnel entrance?
|
// tunnel entrance?
|
||||||
if (IsTileType(tile, MP_TUNNELBRIDGE) &&
|
if (IsTunnelTile(tile) && (byte)((_m[tile].m5 & 3)*2+1) == v->direction)
|
||||||
(_m[tile].m5 & 0xF0) == 0 && (byte)((_m[tile].m5 & 3)*2+1) == v->direction)
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// depot?
|
// depot?
|
||||||
|
|
|
@ -130,7 +130,6 @@ typedef struct Patches {
|
||||||
byte errmsg_duration; // duration of error message
|
byte errmsg_duration; // duration of error message
|
||||||
byte snow_line_height; // a number 0-15 that configured snow line height
|
byte snow_line_height; // a number 0-15 that configured snow line height
|
||||||
bool bribe; // enable bribing the local authority
|
bool bribe; // enable bribing the local authority
|
||||||
bool new_depot_finding; // use new algorithm to find a depot.
|
|
||||||
bool nonuniform_stations;// allow nonuniform train stations
|
bool nonuniform_stations;// allow nonuniform train stations
|
||||||
bool always_small_airport; // always allow small airports
|
bool always_small_airport; // always allow small airports
|
||||||
bool realistic_acceleration; // realistic acceleration for trains
|
bool realistic_acceleration; // realistic acceleration for trains
|
||||||
|
|
70
viewport.c
70
viewport.c
|
@ -540,60 +540,42 @@ void *AddStringToDraw(int x, int y, StringID string, uint32 params_1, uint32 par
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Debugging code */
|
|
||||||
|
|
||||||
#ifdef DEBUG_TILE_PUSH
|
#ifdef DEBUG_HILIGHT_MARKED_TILES
|
||||||
static uint _num_push;
|
|
||||||
static TileIndex _pushed_tile[200];
|
|
||||||
static int _pushed_track[200];
|
|
||||||
|
|
||||||
static TileIndex _stored_tile[200];
|
static void DrawHighlighedTile(const TileInfo *ti)
|
||||||
static int _stored_track[200];
|
|
||||||
static uint _num_stored;
|
|
||||||
|
|
||||||
void dbg_store_path(void)
|
|
||||||
{
|
{
|
||||||
memcpy(_stored_tile, _pushed_tile, sizeof(_stored_tile));
|
if (_m[ti->tile].extra & 0x80) {
|
||||||
memcpy(_stored_track, _pushed_track, sizeof(_stored_tile));
|
DrawSelectionSprite(PALETTE_TILE_RED_PULSATING | (SPR_SELECT_TILE + _tileh_to_sprite[ti->tileh]), ti);
|
||||||
_num_stored = _num_push;
|
}
|
||||||
MarkWholeScreenDirty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbg_push_tile(TileIndex tile, int track)
|
int _debug_marked_tiles, _debug_red_tiles;
|
||||||
{
|
|
||||||
_pushed_tile[_num_push] = tile;
|
// Helper functions that allow you mark a tile as red.
|
||||||
_pushed_track[_num_push++] = track;
|
void DebugMarkTile(TileIndex tile) {
|
||||||
dbg_store_path();
|
_debug_marked_tiles++;
|
||||||
|
if (_m[tile].extra & 0x80)
|
||||||
|
return;
|
||||||
|
_debug_red_tiles++;
|
||||||
|
MarkTileDirtyByTile(tile);
|
||||||
|
_m[tile].extra = (_m[tile].extra & ~0xE0) | 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
void dbg_pop_tile(void)
|
void DebugClearMarkedTiles()
|
||||||
{
|
{
|
||||||
assert(_num_push > 0)
|
uint size = MapSize(), i;
|
||||||
_num_push--;
|
for(i=0; i!=size; i++) {
|
||||||
}
|
if (_m[i].extra & 0x80) {
|
||||||
|
_m[i].extra &= ~0x80;
|
||||||
static const uint16 _dbg_track_sprite[] = {
|
MarkTileDirtyByTile(i);
|
||||||
0x3F4,
|
|
||||||
0x3F3,
|
|
||||||
0x3F5,
|
|
||||||
0x3F6,
|
|
||||||
0x3F8,
|
|
||||||
0x3F7,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int dbg_draw_pushed(const TileInfo *ti)
|
|
||||||
{
|
|
||||||
uint i;
|
|
||||||
|
|
||||||
if (ti->tile == 0) return 0;
|
|
||||||
for (i = 0; i != _num_stored; i++) {
|
|
||||||
if (_stored_tile[i] == ti->tile) {
|
|
||||||
DrawGroundSpriteAt(_dbg_track_sprite[_stored_track[i]&7], ti->x, ti->y, ti->z);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
_debug_red_tiles = 0;
|
||||||
|
_debug_red_tiles = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void DrawSelectionSprite(uint32 image, const TileInfo *ti)
|
static void DrawSelectionSprite(uint32 image, const TileInfo *ti)
|
||||||
|
@ -641,8 +623,8 @@ static void DrawTileSelection(const TileInfo *ti)
|
||||||
{
|
{
|
||||||
uint32 image;
|
uint32 image;
|
||||||
|
|
||||||
#ifdef DEBUG_TILE_PUSH
|
#ifdef DEBUG_HILIGHT_MARKED_TILES
|
||||||
dbg_draw_pushed(ti);
|
DrawHighlighedTile(ti);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Draw a red error square?
|
// Draw a red error square?
|
||||||
|
|
43
win32.c
43
win32.c
|
@ -181,6 +181,34 @@ static void ClientSizeChanged(int w, int h)
|
||||||
|
|
||||||
extern void DoExitSave(void);
|
extern void DoExitSave(void);
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
// Keep this function here..
|
||||||
|
// It allows you to redraw the screen from within the MSVC debugger
|
||||||
|
int RedrawScreenDebug()
|
||||||
|
{
|
||||||
|
HDC dc,dc2;
|
||||||
|
static int _fooctr;
|
||||||
|
HBITMAP old_bmp;
|
||||||
|
HPALETTE old_palette;
|
||||||
|
|
||||||
|
_screen.dst_ptr = _wnd.buffer_bits;
|
||||||
|
UpdateWindows();
|
||||||
|
|
||||||
|
dc = GetDC(_wnd.main_wnd);
|
||||||
|
dc2 = CreateCompatibleDC(dc);
|
||||||
|
|
||||||
|
old_bmp = SelectObject(dc2, _wnd.dib_sect);
|
||||||
|
old_palette = SelectPalette(dc, _wnd.gdi_palette, FALSE);
|
||||||
|
BitBlt(dc, 0, 0, _wnd.width, _wnd.height, dc2, 0, 0, SRCCOPY);
|
||||||
|
SelectPalette(dc, old_palette, TRUE);
|
||||||
|
SelectObject(dc2, old_bmp);
|
||||||
|
DeleteDC(dc2);
|
||||||
|
ReleaseDC(_wnd.main_wnd, dc);
|
||||||
|
|
||||||
|
return _fooctr++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
switch (msg) {
|
switch (msg) {
|
||||||
|
@ -2267,3 +2295,18 @@ void CSleep(int milliseconds)
|
||||||
{
|
{
|
||||||
Sleep(milliseconds);
|
Sleep(milliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Utility function to get the current timestamp in milliseconds
|
||||||
|
// Useful for profiling
|
||||||
|
int64 GetTS()
|
||||||
|
{
|
||||||
|
static double freq;
|
||||||
|
__int64 value;
|
||||||
|
if (!freq) {
|
||||||
|
QueryPerformanceFrequency((LARGE_INTEGER*)&value);
|
||||||
|
freq = (double)1000000 / value;
|
||||||
|
}
|
||||||
|
QueryPerformanceCounter((LARGE_INTEGER*)&value);
|
||||||
|
return (__int64)(value * freq);
|
||||||
|
}
|
Loading…
Reference in New Issue