diff options
author | smatz <smatz@openttd.org> | 2008-01-09 23:00:59 +0000 |
---|---|---|
committer | smatz <smatz@openttd.org> | 2008-01-09 23:00:59 +0000 |
commit | f44a9a5d5b468496fe92473e3bbd6a556efabf12 (patch) | |
tree | 3de62d8fa49bd51c2036af4c35d3e035e59db6ea /src/rail_cmd.cpp | |
parent | 6c954cad5f73f20fad3804d16f1852c7b52d3ad7 (diff) | |
download | openttd-f44a9a5d5b468496fe92473e3bbd6a556efabf12.tar.xz |
(svn r11802) -Fix [FS#716]: do not crash trains when leaving depot to a very long track
-Codechange: use dedicated pathfinder for signal updating, resulting in better performance and possible future improvements
Diffstat (limited to 'src/rail_cmd.cpp')
-rw-r--r-- | src/rail_cmd.cpp | 226 |
1 files changed, 3 insertions, 223 deletions
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index b86616ba5..78e8766a8 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -42,6 +42,7 @@ #include "window_func.h" #include "vehicle_func.h" #include "sound_func.h" +#include "signal_func.h" const byte _track_sloped_sprites[14] = { @@ -84,7 +85,7 @@ const byte _track_sloped_sprites[14] = { */ -static void *EnsureNoTrainOnTrackProc(Vehicle *v, void *data) +void *EnsureNoTrainOnTrackProc(Vehicle *v, void *data) { TrackBits rail_bits = *(TrackBits *)data; @@ -740,7 +741,7 @@ CommandCost CmdBuildTrainDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p d->town_index = ClosestTownFromTile(tile, (uint)-1)->index; - UpdateSignalsOnSegment(tile, dir); + UpdateSignalsOnSegment(tile, INVALID_DIAGDIR); YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir))); d_auto_delete.Detach(); } @@ -1846,227 +1847,6 @@ void DrawDefaultWaypointSprite(int x, int y, RailType railtype) DrawTileSequence(x, y, dts->ground_sprite + offset, dts->seq, 0); } -struct SetSignalsData { - int cur; - int cur_stack; - bool stop; - bool has_presignal; - - /* presignal info */ - int presignal_exits; - int presignal_exits_free; - - /* these are used to keep track of the signals that change. */ - TrackdirByte bit[NUM_SSD_ENTRY]; - TileIndex tile[NUM_SSD_ENTRY]; - - /* these are used to keep track of the stack that modifies presignals recursively */ - TileIndex next_tile[NUM_SSD_STACK]; - DiagDirectionByte next_dir[NUM_SSD_STACK]; - -}; - -static bool SetSignalsEnumProc(TileIndex tile, void* data, Trackdir trackdir, uint length, byte* state) -{ - SetSignalsData* ssd = (SetSignalsData*)data; - Track track = TrackdirToTrack(trackdir); - - if (!IsTileType(tile, MP_RAILWAY)) return false; - - /* the tile has signals? */ - if (HasSignalOnTrack(tile, track)) { - if (HasSignalOnTrackdir(tile, ReverseTrackdir(trackdir))) { - /* yes, add the signal to the list of signals */ - if (ssd->cur != NUM_SSD_ENTRY) { - ssd->tile[ssd->cur] = tile; // remember the tile index - ssd->bit[ssd->cur] = trackdir; // and the controlling bit number - ssd->cur++; - } - - /* remember if this block has a presignal. */ - ssd->has_presignal |= IsPresignalEntry(tile, track); - } - - if (HasSignalOnTrackdir(tile, trackdir) && IsPresignalExit(tile, track)) { - /* this is an exit signal that points out from the segment */ - ssd->presignal_exits++; - if (GetSignalStateByTrackdir(tile, trackdir) != SIGNAL_STATE_RED) - ssd->presignal_exits_free++; - } - - return true; - } else if (IsTileDepotType(tile, TRANSPORT_RAIL)) { - return true; // don't look further if the tile is a depot - } - - return false; -} - -static void *SignalVehicleCheckProc(Vehicle *v, void *data) -{ - uint track = *(uint*)data; - - if (v->type != VEH_TRAIN) return NULL; - - /* Are we on the same piece of track? */ - if (track & v->u.rail.track * 0x101) return v; - - return NULL; -} - -/* Special check for SetSignalsAfterProc, to see if there is a vehicle on this tile */ -static bool SignalVehicleCheck(TileIndex tile, uint track) -{ - if (IsTileType(tile, MP_TUNNELBRIDGE)) { - /* Locate vehicles in tunnels or on bridges */ - return GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL; - } else { - return VehicleFromPos(tile, &track, &SignalVehicleCheckProc) != NULL; - } -} - -static void SetSignalsAfterProc(TrackPathFinder *tpf) -{ - SetSignalsData *ssd = (SetSignalsData*)tpf->userdata; - const TrackPathFinderLink* link; - uint offs; - uint i; - - ssd->stop = false; - - /* Go through all the PF tiles */ - for (i = 0; i < lengthof(tpf->hash_head); i++) { - /* Empty hash item */ - if (tpf->hash_head[i] == 0) continue; - - /* If 0x8000 is not set, there is only 1 item */ - if (!(tpf->hash_head[i] & 0x8000)) { - /* Check if there is a vehicle on this tile */ - if (SignalVehicleCheck(tpf->hash_tile[i], tpf->hash_head[i])) { - ssd->stop = true; - return; - } - } else { - /* There are multiple items, where hash_tile points to the first item in the list */ - offs = tpf->hash_tile[i]; - do { - /* Find the next item */ - link = PATHFIND_GET_LINK_PTR(tpf, offs); - /* Check if there is a vehicle on this tile */ - if (SignalVehicleCheck(link->tile, link->flags)) { - ssd->stop = true; - return; - } - /* Goto the next item */ - } while ((offs = link->next) != 0xFFFF); - } - } -} - -static void ChangeSignalStates(SetSignalsData *ssd) -{ - int i; - - /* thinking about presignals... - * the presignal is green if, - * if no train is in the segment AND - * there is at least one green exit signal OR - * there are no exit signals in the segment */ - - /* then mark the signals in the segment accordingly */ - for (i = 0; i != ssd->cur; i++) { - TileIndex tile = ssd->tile[i]; - byte bit = SignalAgainstTrackdir(ssd->bit[i]); - uint signals = GetSignalStates(tile); - Track track = TrackdirToTrack(ssd->bit[i]); - - /* presignals don't turn green if there is at least one presignal exit and none are free */ - if (IsPresignalEntry(tile, track)) { - int ex = ssd->presignal_exits, exfree = ssd->presignal_exits_free; - - /* subtract for dual combo signals so they don't count themselves */ - if (IsPresignalExit(tile, track) && HasSignalOnTrackdir(tile, ssd->bit[i])) { - ex--; - if (GetSignalStateByTrackdir(tile, ssd->bit[i]) != SIGNAL_STATE_RED) exfree--; - } - - /* if we have exits and none are free, make red. */ - if (ex && !exfree) goto make_red; - } - - /* check if the signal is unaffected. */ - if (ssd->stop) { -make_red: - /* turn red */ - if ((bit & signals) == 0) continue; - } else { - /* turn green */ - if ((bit & signals) != 0) continue; - } - - /* Update signals on the other side of this exit-combo signal; it changed. */ - if (IsPresignalExit(tile, track)) { - if (ssd->cur_stack != NUM_SSD_STACK) { - ssd->next_tile[ssd->cur_stack] = tile; - ssd->next_dir[ssd->cur_stack] = TrackdirToExitdir(ssd->bit[i]); - ssd->cur_stack++; - } else { - DEBUG(misc, 0, "NUM_SSD_STACK too small"); /// @todo WTF is this??? - } - } - - /* it changed, so toggle it */ - SetSignalStates(tile, signals ^ bit); - MarkTileDirtyByTile(tile); - } -} - - -bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection direction) -{ - SetSignalsData ssd; - int result = -1; - - ssd.cur_stack = 0; - - for (;;) { - /* go through one segment and update all signals pointing into that segment. */ - ssd.cur = ssd.presignal_exits = ssd.presignal_exits_free = 0; - ssd.has_presignal = false; - - FollowTrack(tile, 0xC000 | TRANSPORT_RAIL, 0, direction, SetSignalsEnumProc, SetSignalsAfterProc, &ssd); - ChangeSignalStates(&ssd); - - /* remember the result only for the first iteration. */ - if (result < 0) { - /* stay in depot while segment is occupied or while all presignal exits are blocked */ - result = ssd.stop || (ssd.presignal_exits > 0 && ssd.presignal_exits_free == 0); - } - - /* if any exit signals were changed, we need to keep going to modify the stuff behind those. */ - if (ssd.cur_stack == 0) break; - - /* one or more exit signals were changed, so we need to update another segment too. */ - tile = ssd.next_tile[--ssd.cur_stack]; - direction = ssd.next_dir[ssd.cur_stack]; - } - - return result != 0; -} - -void SetSignalsOnBothDir(TileIndex tile, byte track) -{ - static const DiagDirection _search_dir_1[] = { - DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_NE, DIAGDIR_SE, DIAGDIR_SW, DIAGDIR_SE - }; - static const DiagDirection _search_dir_2[] = { - DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NW, DIAGDIR_SW, DIAGDIR_NW, DIAGDIR_NE - }; - - UpdateSignalsOnSegment(tile, _search_dir_1[track]); - UpdateSignalsOnSegment(tile, _search_dir_2[track]); -} - static uint GetSlopeZ_Track(TileIndex tile, uint x, uint y) { uint z; |