(svn r59) -Feature: Added Autosignals, just like Autorail. Can copy signal style, convert signal<->semaphore, etc. Big thanks to betatesters Dribbel and Testman57 (Darkvater)
authordarkvater
Sun, 15 Aug 2004 20:23:42 +0000
changeset 58 b9fdcc9b5c90
parent 57 8e7283026637
child 59 fb1a20aefeae
(svn r59) -Feature: Added Autosignals, just like Autorail. Can copy signal style, convert signal<->semaphore, etc. Big thanks to betatesters Dribbel and Testman57 (Darkvater)
command.c
command.h
lang/english.txt
rail_cmd.c
rail_gui.c
settings.c
settings_gui.c
variables.h
viewport.c
viewport.h
--- a/command.c	Sun Aug 15 16:19:54 2004 +0000
+++ b/command.c	Sun Aug 15 20:23:42 2004 +0000
@@ -160,6 +160,8 @@
 
 DEF_COMMAND(CmdStartScenario);
 
+DEF_COMMAND(CmdBuildManySignals);
+
 /* The master command table */
 static CommandProc * const _command_proc_table[] = {
 	CmdBuildRailroadTrack,			/* 0 */
@@ -294,8 +296,8 @@
 	CmdRefitRailVehicle,		/* 106 */
 	CmdRestoreOrderIndex,		/* 107 */
 	CmdBuildLock,						/* 108 */
-	CmdStartScenario				/* 109 */
-	
+	CmdStartScenario,				/* 109 */
+	CmdBuildManySignals,		/* 110 */
 	//CmdDestroyIndustry,			/* 109 */
 };
 
--- a/command.h	Sun Aug 15 16:19:54 2004 +0000
+++ b/command.h	Sun Aug 15 20:23:42 2004 +0000
@@ -142,6 +142,7 @@
 	CMD_BUILD_LOCK = 108,
 	
 	CMD_START_SCENARIO = 109,
+	CMD_BUILD_MANY_SIGNALS = 110,
 
 	//CMD_DESTROY_INDUSTRY = 109,
 };
--- a/lang/english.txt	Sun Aug 15 16:19:54 2004 +0000
+++ b/lang/english.txt	Sun Aug 15 20:23:42 2004 +0000
@@ -999,6 +999,7 @@
 STR_CONFIG_PATCHES_COLORED_NEWS_DATE	:{LTBLUE}Coloured news appears in: {ORANGE}{STRING}
 STR_CONFIG_PATCHES_STARTING_DATE		:{LTBLUE}Starting date: {ORANGE}{STRING}
 STR_CONFIG_PATCHES_SMOOTH_ECONOMY		:{LTBLUE}Enable smooth economy (more, smaller changes)
+STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY		:{LTBLUE}When dragging place signals every: {ORANGE}{STRING} tile(s)
 
 STR_CONFIG_PATCHES_GUI					:{BLACK}Interface
 STR_CONFIG_PATCHES_CONSTRUCTION			:{BLACK}Construction
--- a/rail_cmd.c	Sun Aug 15 16:19:54 2004 +0000
+++ b/rail_cmd.c	Sun Aug 15 20:23:42 2004 +0000
@@ -521,8 +521,8 @@
 
 
 /* Build either NE or NW sequence of tracks.
- * p1 0:15  - start pt X
- * p1 16:31 - start pt y
+ * p1 0:15  - end pt X
+ * p1 16:31 - end pt y
  *
  * p2 0:3   - rail type
  * p2 4:7   - rail direction
@@ -538,7 +538,7 @@
 	if (flags & DC_EXEC)
 		SndPlayTileFx(0x1E, TILE_FROM_XY(x,y));
 	
-	/* unpack start point */
+	/* unpack end point */
 	sx = (p1 & 0xFFFF) & ~0xF;
 	sy = (p1 >> 16) & ~0xF;
 
@@ -837,7 +837,11 @@
 }
 
 
-/* build signals, p1 = track */
+/*	build signals, alternate between double/single, signal/semaphore, pre/exit/combo -signals
+		p1 = (lower 3 bytes)	- track-orientation
+		p1 = (byte 4)					- semaphores/signals
+		p2 = used for CmdBuildManySignals() to copy style first signal
+ */
 int32 CmdBuildSignals(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 {
 	uint tile;
@@ -845,8 +849,7 @@
 	int32 cost;
 	int track = p1 & 0x7;
 	
-	assert(track >= 0 && track < 6);
-	assert(p2 == 0);
+	assert(track >= 0 && track < 6); // only 6 possible track-combinations
 	
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
@@ -855,12 +858,12 @@
 	if (!EnsureNoVehicle(tile))
 		return CMD_ERROR;
 
-	_error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK;
-	
 	// must be railway, and not a depot, and it must have a track in the suggested position.
 	if (!IS_TILETYPE(tile, MP_RAILWAY) || (m5=_map5[tile], m5&0x80) || !HASBIT(m5, track))
 		return CMD_ERROR;
 
+	_error_message = STR_1005_NO_SUITABLE_RAILROAD_TRACK;
+
 	// check rail combination
 	{
 		byte m = m5 & RAIL_BIT_MASK;
@@ -873,40 +876,54 @@
 	if (!CheckTileOwnership(tile))
 		return CMD_ERROR;
 
-	// If it had signals previously it's no cost to build.
+	// If it had signals previously it is free to change orientation/pre-exit-combo signals
 	cost = 0;
 	if (!(m5 & RAIL_TYPE_SIGNALS)) {
 		cost = _price.build_signals;
+	// if converting signals<->semaphores, charge the player for it
+	} else if (p2 && ((HASBIT(p1, 3) && !HASBIT(_map3_hi[tile], 2)) || (!HASBIT(p1, 3) && HASBIT(_map3_hi[tile], 2)) ) ) {
+		cost += _price.build_signals + _price.remove_signals;
 	}
 
 	if (flags & DC_EXEC) {
 		
 
-		if (!(m5 & RAIL_TYPE_SIGNALS)) {
+		if (!(m5 & RAIL_TYPE_SIGNALS)) {		// if there are no signals yet present on the track
 			_map5[tile] |= RAIL_TYPE_SIGNALS; // change into signals
 			_map2[tile] |= 0xF0;              // all signals are on
 			_map3_lo[tile] &= ~0xF0;          // no signals built by default
 			_map3_hi[tile] = (p1 & 8) ? 4 : 0;// initial presignal state, semaphores depend on ctrl key
-			goto ignore_presig;
+			if (!p2)
+				goto ignore_presig;
 		}
 
-		if (!(p1 & 8)) {
-			byte a,b,c,d;
-ignore_presig:
-			a = _signals_table[track];      // signal for this track in one direction
-			b = _signals_table[track + 8];  // signal for this track in the other direction
-			c = a | b;
-			d = _map3_lo[tile] & c;					// mask of built signals. it only affects &0xF0
+		if (!p2) { // not called from CmdBuildManySignals
+			if (!HASBIT(p1, 3)) { // not CTRL pressed
+				byte a,b,c,d;
+	ignore_presig:
+				a = _signals_table[track];      // signal for this track in one direction
+				b = _signals_table[track + 8];  // signal for this track in the other direction
+				c = a | b;
+				d = _map3_lo[tile] & c;					// mask of built signals. it only affects &0xF0
 
-			// Alternate between a|b, b, a
-			if ( d != 0 && d != a) {
-				c = (d==c)?b:a;
+				// Alternate between a|b, b, a
+				if ( d != 0 && d != a) {
+					c = (d==c)?b:a;
+				}
+
+				_map3_lo[tile] = (_map3_lo[tile]&~(a|b)) | c;
+			} else // CTRL pressed
+				_map3_hi[tile] = (_map3_hi[tile] & ~3) | ((_map3_hi[tile] + 1) & 3);
+		} else {
+			/* If CmdBuildManySignals is called with copying signals, just copy the style of the first signal
+			* given as parameter by CmdBuildManySignals */
+			switch (track) {
+			case 2: case 4: _map3_lo[tile] = (p2&0xC0) | _map3_lo[tile]&~0xC0; break;
+			case 3: case 5: _map3_lo[tile] = (p2&0x30) | _map3_lo[tile]&~0x30; break;
+			default : _map3_lo[tile] = (p2&0xF0) | _map3_lo[tile]&0xF;
 			}
-
-			_map3_lo[tile] = (_map3_lo[tile]&~(a|b)) | c;
-		} else {
-			// toggle between the signal types. Using low 2 bits of map3_hi.
-			_map3_hi[tile] = (_map3_hi[tile] & ~3) | ((_map3_hi[tile] + 1) & 3);
+			// convert between signal<->semaphores when dragging
+			HASBIT(p1, 3) ? SETBIT(_map3_hi[tile], 2) : CLRBIT(_map3_hi[tile], 2);
 		}
 		
 		MarkTileDirtyByTile(tile);
@@ -916,6 +933,108 @@
 	return cost;
 }
 
+/*	Build many signals by dragging: AutoSignals
+		x,y= start tile
+		p1 = end tile
+		p2 = (byte 0)		- 0 = build, 1 = remove signals
+		p2 = (byte 3)		- 0 = signals, 1 = semaphores
+		p2 = (byte 7-4)	- track-orientation
+		p2 = (byte 8-)	- track style
+ */
+int32 CmdBuildManySignals(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+{
+	int ex, ey, railbit;
+	bool error = true;
+	TileIndex tile = TILE_FROM_XY(x, y);
+	int32 ret, total_cost, signal_ctr;
+	byte m5, semaphores = (HASBIT(p2, 3)) ? 8 : 0;
+	int mode = (p2 >> 4)&0xF;
+	// for vertical/horizontal tracks, double the given signals density
+	// since the original amount will be too dense (shorter tracks)
+	byte signal_density = (mode == 1 || mode == 2) ? _patches.drag_signals_density : _patches.drag_signals_density * 2;
+	byte signals = p2 >> 8;
+	mode = p2 & 0x1;  // build/remove signals
+
+	/* unpack end tile */
+	ex = GET_TILE_X(p1)*16;
+	ey = GET_TILE_Y(p1)*16;
+
+	railbit = _railbit.initial[((p2 >> 4)&0xF) + (x > ex ? 4 : 0) + (y > ey ? 8 : 0)];
+
+	// copy the signal-style of the first rail-piece if existing
+	m5 = _map5[tile];
+	if (!(m5 & RAIL_TYPE_SPECIAL) && (m5 & RAIL_BIT_MASK) && (m5 & RAIL_TYPE_SIGNALS)) {
+		if (m5 & 0x3) // X,Y direction tracks
+			signals = _map3_lo[tile]&0xC0;
+		else {
+			/* W-E or N-S direction, only copy the side which was chosen, leave
+			 * the other side alone */
+			switch (signals) {
+				case 0x20: case 8: /* east corner (N-S), south corner (W-E) */
+					if (_map3_lo[tile]&0x30) 
+						signals = _map3_lo[tile]&0x30;
+					else
+						signals = 0x30 | _map3_lo[tile]&0xC0;
+					break;
+				case 0x10: case 4: /* west corner (N-S), north corner (W-E) */
+					if (_map3_lo[tile]&0xC0) 
+						signals = _map3_lo[tile]&0xC0;
+					else
+						signals = 0xC0 | _map3_lo[tile]&0x30;
+					break;
+			}
+		}
+
+		semaphores = (_map3_hi[tile] & ~3) ? 8 : 0; // copy signal/semaphores style (independent of CTRL)
+	} else { // no signals exist, drag a two-way signal stretch
+		switch (signals) {
+			case 0x20: case 8: /* east corner (N-S), south corner (W-E) */
+				signals = 0x30; break;
+			case 0x10: case 4: /* west corner (N-S), north corner (W-E) */
+				signals = 0xC0;
+		}
+	}
+
+	/* signal_density_ctr	- amount of tiles already processed
+	 * signals_density		- patch setting to put signal on every Nth tile (double space on |, -- tracks)
+	 **********
+	 * railbit		- direction of autorail
+	 * semaphores	- semaphores or signals
+	 * signals		- is there a signal/semaphore on the first tile, copy its style (two-way/single-way) 
+									and convert all others to semaphore/signal
+	 * mode				- 1 remove signals, 0 build signals */
+	signal_ctr = total_cost = 0;
+	for(;;) {
+		// only build/remove signals with the specified density
+		if ((signal_ctr %	signal_density) == 0 ) {
+			ret = DoCommand(x, y, (railbit & 7) | semaphores, signals, flags, (mode == 1) ? CMD_REMOVE_SIGNALS : CMD_BUILD_SIGNALS);
+
+			/* Abort placement for any other error then NOT_SUITEABLE_TRACK
+			 * This includes vehicles on track, competitor's tracks, etc. */
+			if (ret == CMD_ERROR) {
+				if (_error_message != STR_1005_NO_SUITABLE_RAILROAD_TRACK && mode != 1) {
+					return CMD_ERROR;
+				}
+			} else {
+				error = false;
+				total_cost += ret;
+			}
+		}
+
+		if (ex == x && ey == y) // reached end of drag
+			break;
+
+		x += _railbit.xinc[railbit];
+		y += _railbit.yinc[railbit];	
+		signal_ctr++;
+		
+		// toggle railbit for the diagonal tiles (|, -- tracks)
+		if (railbit & 0x6) railbit ^= 1;
+	}
+
+	return (error) ? CMD_ERROR : total_cost;
+}
+
 /* Remove signals
  * p1 = unused
  * p2 = unused
@@ -952,6 +1071,7 @@
 		byte bits = _map5[tile];
 		_map5[tile] &= ~RAIL_TYPE_SIGNALS;
 		_map2[tile] &= ~0xF0;
+		CLRBIT(_map3_hi[tile], 2); // remove any possible semaphores
 		
 		/* TTDBUG: this code contains a bug, if a tile contains 2 signals
 		 * on separate tracks, it won't work properly for the 2nd track */		
--- a/rail_gui.c	Sun Aug 15 16:19:54 2004 +0000
+++ b/rail_gui.c	Sun Aug 15 20:23:42 2004 +0000
@@ -140,7 +140,7 @@
 	}
 }
 
-static void PlaceRail_Signals(uint tile)
+static void GenericPlaceSignals(uint tile)
 {
 	uint trackstat;
 	int i;
@@ -199,6 +199,11 @@
 	VpStartPlaceSizing(tile, VPM_X_AND_Y | (1<<4));
 }
 
+static void PlaceRail_AutoSignals(uint tile)
+{
+	VpStartPlaceSizing(tile, VPM_SIGNALDIRS);
+}
+
 static void BuildRailClick_AutoRail(Window *w)
 {
 	HandlePlacePushButton(w, 3, _cur_railtype + SPR_OPENTTD_BASE + 4, 1, PlaceRail_AutoRail);
@@ -255,9 +260,9 @@
 	if (HandlePlacePushButton(w, 12, 0x514, 1, PlaceRail_Station)) ShowStationBuilder();	
 }
 
-static void BuildRailClick_Signals(Window *w)
+static void BuildRailClick_AutoSignals(Window *w)
 {
-	HandlePlacePushButton(w, 13, ANIMCURSOR_BUILDSIGNALS, 1, PlaceRail_Signals);
+	HandlePlacePushButton(w, 13, ANIMCURSOR_BUILDSIGNALS , 1, PlaceRail_AutoSignals);
 }
 
 static void BuildRailClick_Bridge(Window *w)
@@ -508,6 +513,42 @@
 	}
 }
 
+static void HandleAutoSignalPlacement()
+{
+	TileHighlightData *thd = &_thd;
+	int mode;
+	uint trackstat = 0;
+
+	int dx = thd->selstart.x - (thd->selend.x&~0xF);
+	int dy = thd->selstart.y - (thd->selend.y&~0xF);
+	
+	if (dx == 0 && dy == 0 ) // 1x1 tile signals
+		GenericPlaceSignals(TILE_FROM_XY(thd->selend.x, thd->selend.y));
+	else { // signals have been dragged
+		if (thd->drawstyle == HT_RECT) { // X,Y direction
+			if (dx == 0) 
+				mode = VPM_FIX_X;
+			else if (dy == 0)
+				mode = VPM_FIX_Y;
+
+			trackstat = 0xC0;
+		}	else { // W-E or N-S direction
+			mode = thd->drawstyle & 1 ? 0 : 3;
+
+			if (dx == dy || abs(dx - dy) == 16) // North<->South track |
+				trackstat = (thd->drawstyle & 1) ? 0x20 : 0x10;
+			else if (dx == -dy || abs(dx + dy) == 16) // East<->West track --
+				trackstat = (thd->drawstyle & 1) ? 4 : 8;
+		}
+
+		DoCommandP(TILE_FROM_XY(thd->selstart.x, thd->selstart.y), TILE_FROM_XY(thd->selend.x, thd->selend.y), 
+		(mode << 4) | (_remove_button_clicked + (_ctrl_pressed ? 8 : 0)) | (trackstat << 8), 
+		CcPlaySound1E, 
+		(_remove_button_clicked ?	CMD_BUILD_MANY_SIGNALS | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM) :
+															CMD_BUILD_MANY_SIGNALS | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE) ) );									
+	}	
+}
+
 static OnButtonClick * const _build_railroad_button_proc[] = {
 	BuildRailClick_AutoRail,
 	BuildRailClick_N,
@@ -519,7 +560,7 @@
 	BuildRailClick_Raise,
 	BuildRailClick_Depot,
 	BuildRailClick_Station,
-	BuildRailClick_Signals,
+	BuildRailClick_AutoSignals,
 	BuildRailClick_Bridge,
 	BuildRailClick_Tunnel,
 	BuildRailClick_Remove,
@@ -603,6 +644,8 @@
 				if (_ctrl_pressed) _remove_button_clicked = true;
 				HandleAutodirPlacement();
 				_remove_button_clicked = old;
+			} else if (e->place.userdata == VPM_SIGNALDIRS) {
+				HandleAutoSignalPlacement();
 			} else if (e->place.userdata == VPM_X_AND_Y) {
 				DoCommandP(end_tile, start_tile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
 			} else if (e->place.userdata == (VPM_X_AND_Y | (1<<4))) {
--- a/settings.c	Sun Aug 15 16:19:54 2004 +0000
+++ b/settings.c	Sun Aug 15 20:23:42 2004 +0000
@@ -873,6 +873,8 @@
 	{"wait_oneway_signal", SDT_UINT8, (void*)15, (void*)offsetof(Patches, wait_oneway_signal)},
 	{"wait_twoway_signal", SDT_UINT8, (void*)41, (void*)offsetof(Patches, wait_twoway_signal)},
 
+	{"drag_signals_density", SDT_UINT8, (void*)4, (void*)offsetof(Patches, drag_signals_density)},
+
 	{NULL}
 };
 
--- a/settings_gui.c	Sun Aug 15 16:19:54 2004 +0000
+++ b/settings_gui.c	Sun Aug 15 20:23:42 2004 +0000
@@ -700,6 +700,7 @@
 	{PE_BOOL, 0, STR_CONFIG_PATCHES_SIGNALSIDE, &_patches.signal_side},
 	{PE_BOOL, 0, STR_CONFIG_PATCHES_BUILD_IN_PAUSE, &_patches.build_in_pause},
 	{PE_BOOL, 0, STR_CONFIG_PATCHES_SMALL_AIRPORTS, &_patches.always_small_airport},
+	{PE_UINT8,0, STR_CONFIG_PATCHES_DRAG_SIGNALS_DENSITY, &_patches.drag_signals_density, 1, 20, 1},
 
 };
 
--- a/variables.h	Sun Aug 15 16:19:54 2004 +0000
+++ b/variables.h	Sun Aug 15 20:23:42 2004 +0000
@@ -152,6 +152,7 @@
 	byte wait_oneway_signal;	//waitingtime in days before a oneway signal
 	byte wait_twoway_signal;	//waitingtime in days before a twoway signal
 
+	byte drag_signals_density; // many signals density
 } Patches;
 
 VARDEF Patches _patches;
--- a/viewport.c	Sun Aug 15 16:19:54 2004 +0000
+++ b/viewport.c	Sun Aug 15 20:23:42 2004 +0000
@@ -1910,7 +1910,7 @@
 	}
 
 	// allow drag in any rail direction
-	if (method == VPM_RAILDIRS) {
+	if (method == VPM_RAILDIRS || method == VPM_SIGNALDIRS) {
 		CalcRaildirsDrawstyle(thd, x, y);
 		return;
 	}
--- a/viewport.h	Sun Aug 15 16:19:54 2004 +0000
+++ b/viewport.h	Sun Aug 15 20:23:42 2004 +0000
@@ -53,6 +53,7 @@
 	VPM_RAILDIRS = 3,
 	VPM_X_AND_Y = 4,
 	VPM_X_AND_Y_LIMITED = 5,
+	VPM_SIGNALDIRS = 6,
 };
 
 void VpSelectTilesWithMethod(int x, int y, int method);