From efef78f786844fcb898c784fb26751f547afd78a Mon Sep 17 00:00:00 2001 From: peter1138 Date: Wed, 4 Jul 2007 17:21:28 +0000 Subject: [PATCH] (svn r10437) -Feature: Automatic signal completion, enabled by pressing ctrl when dragging signals. Signals will continue following track until an existing signal, junction or station are reached. This currently replaces the existing use of ctrl-drag for changing existing signal type. --- src/rail_cmd.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++---- src/rail_gui.cpp | 4 +- 2 files changed, 98 insertions(+), 8 deletions(-) diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index 0ccaa19967..61c6cea011 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -738,6 +738,64 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 return cost; } +static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal_ctr, bool remove) +{ + tile = AddTileIndexDiffCWrap(tile, _trackdelta[trackdir]); + if (tile == INVALID_TILE) return false; + + /* Check for track bits on the new tile */ + uint32 ts = GetTileTrackStatus(tile, TRANSPORT_RAIL, 0); + TrackdirBits trackdirbits = (TrackdirBits)(ts & TRACKDIR_BIT_MASK); + + if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false; + trackdirbits &= TrackdirReachesTrackdirs(trackdir); + + /* No track bits, must stop */ + if (trackdirbits == TRACKDIR_BIT_NONE) return false; + + /* Get the first track dir */ + trackdir = RemoveFirstTrackdir(&trackdirbits); + + /* Any left? It's a junction so we stop */ + if (trackdirbits != TRACKDIR_BIT_NONE) return false; + + switch (GetTileType(tile)) { + case MP_RAILWAY: + if (IsRailDepot(tile)) return false; + if (!remove && HasSignalOnTrack(tile, TrackdirToTrack(trackdir))) return false; + signal_ctr++; + if (IsDiagonalTrackdir(trackdir)) { + signal_ctr++; + /* Ensure signal_ctr even so X and Y pieces get signals */ + CLRBIT(signal_ctr, 0); + } + return true; + + case MP_STREET: + if (!IsLevelCrossing(tile)) return false; + signal_ctr += 2; + return true; + + case MP_TUNNELBRIDGE: { + TileIndex orig_tile = tile; + /* Skip to end of tunnel or bridge */ + if (IsBridge(tile)) { + if (GetBridgeTransportType(tile) != TRANSPORT_RAIL) return false; + if (GetBridgeRampDirection(tile) != TrackdirToExitdir(trackdir)) return false; + tile = GetOtherBridgeEnd(tile); + } else { + if (GetTunnelTransportType(tile) != TRANSPORT_RAIL) return false; + if (GetTunnelDirection(tile) != TrackdirToExitdir(trackdir)) return false; + tile = GetOtherTunnelEnd(tile); + } + signal_ctr += 2 + DistanceMax(orig_tile, tile) * 2; + return true; + } + + default: return false; + } +} + /** Build many signals by dragging; AutoSignals * @param tile start tile of drag * @param flags operation to perform @@ -747,6 +805,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint32 * - p2 = (bit 3) - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle) * - p2 = (bit 4) - 0 = signals, 1 = semaphores * - p2 = (bit 5) - 0 = build, 1 = remove signals + * - p2 = (bit 6) - 0 = selected stretch, 1 = auto fill * - p2 = (bit 24-31) - user defined signals_density */ static CommandCost CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) @@ -756,11 +815,13 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, byte signals; bool error = true; TileIndex end_tile; + TileIndex start_tile = tile; Track track = (Track)GB(p2, 0, 3); bool mode = HASBIT(p2, 3); bool semaphores = HASBIT(p2, 4); bool remove = HASBIT(p2, 5); + bool autofill = HASBIT(p2, 6); Trackdir trackdir = TrackToTrackdir(track); byte signal_density = GB(p2, 24, 8); @@ -774,11 +835,15 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, /* for vertical/horizontal tracks, double the given signals density * since the original amount will be too dense (shorter tracks) */ - if (!IsDiagonalTrack(track)) signal_density *= 2; + signal_density *= 2; if (CmdFailed(ValidateAutoDrag(&trackdir, tile, end_tile))) return CMD_ERROR; track = TrackdirToTrack(trackdir); /* trackdir might have changed, keep track in sync */ + Trackdir start_trackdir = trackdir; + + /* Autofill must start on a valid track to be able to avoid loops */ + if (autofill && !HasTrack(tile, track)) return CMD_ERROR; /* copy the signal-style of the first rail-piece if existing */ if (HasSignals(tile)) { @@ -791,6 +856,10 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, signals = SignalOnTrack(track); } + byte signal_dir = 0; + if (signals & SignalAlongTrackdir(trackdir)) SETBIT(signal_dir, 0); + if (signals & SignalAgainstTrackdir(trackdir)) SETBIT(signal_dir, 1); + /* signal_ctr - amount of tiles already processed * signals_density - patch setting to put signal on every Nth tile (double space on |, -- tracks) ********** @@ -802,10 +871,16 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, signal_ctr = 0; for (;;) { /* only build/remove signals with the specified density */ - if (signal_ctr % signal_density == 0) { + if ((remove && autofill) || signal_ctr % signal_density == 0) { uint32 p1 = GB(TrackdirToTrack(trackdir), 0, 3); SB(p1, 3, 1, mode); SB(p1, 4, 1, semaphores); + + /* Pick the correct orientation for the track direction */ + signals = 0; + if (HASBIT(signal_dir, 0)) signals |= SignalAlongTrackdir(trackdir); + if (HASBIT(signal_dir, 1)) signals |= SignalAgainstTrackdir(trackdir); + ret = DoCommand(tile, p1, signals, flags, remove ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS); /* Be user-friendly and try placing signals as much as possible */ @@ -815,13 +890,24 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, } } - if (tile == end_tile) break; + if (autofill) { + if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break; - tile += ToTileIndexDiff(_trackdelta[trackdir]); - signal_ctr++; + /* Prevent possible loops */ + if (tile == start_tile && trackdir == start_trackdir) break; + } else { + if (tile == end_tile) break; - /* toggle railbit for the non-diagonal tracks (|, -- tracks) */ - if (!IsDiagonalTrackdir(trackdir)) ToggleBitT(trackdir, 0); + tile += ToTileIndexDiff(_trackdelta[trackdir]); + signal_ctr++; + + /* toggle railbit for the non-diagonal tracks (|, -- tracks) */ + if (IsDiagonalTrackdir(trackdir)) { + signal_ctr++; + } else { + ToggleBitT(trackdir, 0); + } + } } return error ? CMD_ERROR : total_cost; @@ -837,6 +923,7 @@ static CommandCost CmdSignalTrackHelper(TileIndex tile, uint32 flags, uint32 p1, * - p2 = (bit 3) - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle) * - p2 = (bit 4) - 0 = signals, 1 = semaphores * - p2 = (bit 5) - 0 = build, 1 = remove signals + * - p2 = (bit 6) - 0 = selected stretch, 1 = auto fill * - p2 = (bit 24-31) - user defined signals_density * @see CmdSignalTrackHelper */ @@ -900,6 +987,7 @@ CommandCost CmdRemoveSingleSignal(TileIndex tile, uint32 flags, uint32 p1, uint3 * - p2 = (bit 3) - 1 = override signal/semaphore, or pre/exit/combo signal (CTRL-toggle) * - p2 = (bit 4) - 0 = signals, 1 = semaphores * - p2 = (bit 5) - 0 = build, 1 = remove signals + * - p2 = (bit 6) - 0 = selected stretch, 1 = auto fill * - p2 = (bit 24-31) - user defined signals_density * @see CmdSignalTrackHelper */ diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index b2e2ec49aa..cecebf246f 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -373,8 +373,10 @@ static void HandleAutoSignalPlacement() return; } - SB(p2, 3, 1, _ctrl_pressed); + /* XXX Steal ctrl for autosignal function, until we get some GUI */ + SB(p2, 3, 1, 0); SB(p2, 4, 1, _cur_year < _patches.semaphore_build_before); + SB(p2, 6, 1, _ctrl_pressed); SB(p2, 24, 8, _patches.drag_signals_density); /* _patches.drag_signals_density is given as a parameter such that each user