(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.
authorpeter1138
Wed, 04 Jul 2007 17:21:28 +0000
changeset 7659 5456fc83a700
parent 7658 742319a52186
child 7660 cbf9a5a3c704
(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
src/rail_gui.cpp
--- a/src/rail_cmd.cpp	Wed Jul 04 13:30:33 2007 +0000
+++ b/src/rail_cmd.cpp	Wed Jul 04 17:21:28 2007 +0000
@@ -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;
 
-		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 @@
  * - 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	Wed Jul 04 13:30:33 2007 +0000
+++ b/src/rail_gui.cpp	Wed Jul 04 17:21:28 2007 +0000
@@ -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