changeset 7163:1bf2973edcd6 draft

(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.
author peter1138 <peter1138@openttd.org>
date Wed, 04 Jul 2007 17:21:28 +0000
parents e548e286a5b6
children ec8a38941fe5
files src/rail_cmd.cpp src/rail_gui.cpp
diffstat 2 files changed, 98 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -738,6 +738,64 @@
 	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 @@
  * - 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 @@
 	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 @@
 
 	/* 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 @@
 		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 @@
 	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 @@
 			}
 		}
 
-		if (tile == end_tile) break;
+		if (autofill) {
+			if (!CheckSignalAutoFill(tile, trackdir, signal_ctr, remove)) break;
+
+			/* Prevent possible loops */
+			if (tile == start_tile && trackdir == start_trackdir) break;
+		} else {
+			if (tile == end_tile) break;
 
-		tile += ToTileIndexDiff(_trackdelta[trackdir]);
-		signal_ctr++;
+			tile += ToTileIndexDiff(_trackdelta[trackdir]);
+			signal_ctr++;
 
-		/* toggle railbit for the non-diagonal tracks (|, -- tracks) */
-		if (!IsDiagonalTrackdir(trackdir)) ToggleBitT(trackdir, 0);
+			/* 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 @@
  * - 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 @@
  * - 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
  */
--- a/src/rail_gui.cpp
+++ b/src/rail_gui.cpp
@@ -373,8 +373,10 @@
 		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