(svn r1731) - Fix: [ 1106930 ] BugFix: placing signals with 2x1 drags workaround is completely rewritten. Also features checks for hacked/modified clients. Thanks a lot Hackykid!
authordarkvater
Sun, 30 Jan 2005 15:57:38 +0000
changeset 1227 3552f20fcfcb
parent 1226 cbcaba80c31c
child 1228 d3fdda5f80f5
(svn r1731) - Fix: [ 1106930 ] BugFix: placing signals with 2x1 drags workaround is completely rewritten. Also features checks for hacked/modified clients. Thanks a lot Hackykid!
command.c
command.h
rail_cmd.c
rail_gui.c
--- a/command.c	Sun Jan 30 14:52:04 2005 +0000
+++ b/command.c	Sun Jan 30 15:57:38 2005 +0000
@@ -22,8 +22,8 @@
 DEF_COMMAND(CmdRemoveFromRailroadStation);
 DEF_COMMAND(CmdConvertRail);
 
-DEF_COMMAND(CmdBuildSignals);
-DEF_COMMAND(CmdRemoveSignals);
+DEF_COMMAND(CmdBuildSingleSignal);
+DEF_COMMAND(CmdRemoveSingleSignal);
 
 DEF_COMMAND(CmdTerraformLand);
 
@@ -163,7 +163,8 @@
 
 DEF_COMMAND(CmdStartScenario);
 
-DEF_COMMAND(CmdBuildManySignals);
+DEF_COMMAND(CmdBuildSignalTrack);
+DEF_COMMAND(CmdRemoveSignalTrack);
 
 DEF_COMMAND(CmdReplaceVehicle);
 
@@ -177,8 +178,8 @@
 	CmdBuildBridge,								/* 5  */
 	CmdBuildRailroadStation,			/* 6  */
 	CmdBuildTrainDepot,						/* 7  */
-	CmdBuildSignals,							/* 8  */
-	CmdRemoveSignals,							/* 9  */
+	CmdBuildSingleSignal,					/* 8  */
+	CmdRemoveSingleSignal,				/* 9  */
 	CmdTerraformLand,							/* 10 */
 	CmdPurchaseLandArea,					/* 11 */
 	CmdSellLandArea,							/* 12 */
@@ -302,12 +303,14 @@
 	CmdRestoreOrderIndex,					/* 107 */
 	CmdBuildLock,									/* 108 */
 	CmdStartScenario,							/* 109 */
-	CmdBuildManySignals,					/* 110 */
-	//CmdDestroyIndustry,						/* 109 */
-	CmdDestroyCompanyHQ,					/* 111 */
-	CmdGiveMoney,									/* 112 */
-	CmdChangePatchSetting,				/* 113 */
-	CmdReplaceVehicle,							/* 114 */
+	CmdBuildSignalTrack,					/* 110 */
+	CmdRemoveSignalTrack,					/* 111 */
+	CmdDestroyCompanyHQ,					/* 112 */
+	CmdGiveMoney,									/* 113 */
+	CmdChangePatchSetting,				/* 114 */
+	CmdReplaceVehicle,						/* 115 */
+
+	//CmdDestroyIndustry,					/* 109 */
 };
 
 /* This function range-checks a cmd, and checks if the cmd is not NULL */
--- a/command.h	Sun Jan 30 14:52:04 2005 +0000
+++ b/command.h	Sun Jan 30 15:57:38 2005 +0000
@@ -141,14 +141,15 @@
 	CMD_BUILD_LOCK = 108,
 
 	CMD_START_SCENARIO = 109,
-	CMD_BUILD_MANY_SIGNALS = 110,
+	CMD_BUILD_SIGNAL_TRACK  = 110,
+	CMD_REMOVE_SIGNAL_TRACK = 111,
 
+	CMD_DESTROY_COMPANY_HQ = 112,
+	CMD_GIVE_MONEY = 113,
+	CMD_CHANGE_PATCH_SETTING = 114,
+
+	CMD_REPLACE_VEHICLE = 115,
 	//CMD_DESTROY_INDUSTRY = 109,
-	CMD_DESTROY_COMPANY_HQ = 111,
-	CMD_GIVE_MONEY = 112,
-	CMD_CHANGE_PATCH_SETTING = 113,
-
-	CMD_REPLACE_VEHICLE = 114,
 };
 
 enum {
--- a/rail_cmd.c	Sun Jan 30 14:52:04 2005 +0000
+++ b/rail_cmd.c	Sun Jan 30 15:57:38 2005 +0000
@@ -512,64 +512,99 @@
 static const struct {
 	int8 xinc[16];
 	int8 yinc[16];
-	byte initial[16];
 } _railbit = {{
-//  0   1   2    3   4   5
-	 16,  0,-16,   0, 16,  0,    0,  0,
-	-16,  0,  0,  16,  0,-16,    0,  0,
+//  0   1   2   3   4   5
+	-16,  0,-16,  0, 16,  0,    0,  0,
+	 16,  0,  0, 16,  0,-16,    0,  0,
 },{
-	0,   16,  0,  16,  0, 16,    0,  0,
-	0,  -16, -16,  0,-16,  0,    0,  0,
-},{
-	5,     1,   0,   4, // normal
-	2,     1, 8|0,   3, // x > sx
-	8|2, 8|1,   0, 8|3, // y > sy
-	8|5, 8|1, 8|0, 8|4, // x > sx && y > sy
+	  0, 16,  0, 16,  0, 16,    0,  0,
+	  0,-16,-16,  0,-16,  0,    0,  0,
 }};
 
+static int32 ValidateAutoDrag(int *railbit, int x, int y, int ex, int ey)
+{
+	int dx, dy, trdx, trdy;
 
-/* Build either NE or NW sequence of tracks.
- * p1 0:15  - end pt X
- * p1 16:31 - end pt y
- *
- * p2 0:3   - rail type
- * p2 4:7   - rail direction
+	if (*railbit > 5) return CMD_ERROR; // only 6 possible track-combinations
+
+	// calculate delta x,y from start to end tile
+	dx = ex - x;
+	dy = ey - y;
+
+	// calculate delta x,y for the first direction
+	trdx = _railbit.xinc[*railbit];
+	trdy = _railbit.yinc[*railbit];
+
+	if (*railbit & 0x6) {
+		trdx += _railbit.xinc[*railbit ^ 1];
+		trdy += _railbit.yinc[*railbit ^ 1];
+	}
+
+	// validate the direction
+	while (((trdx <= 0) && (dx > 0)) || ((trdx >= 0) && (dx < 0)) ||
+	       ((trdy <= 0) && (dy > 0)) || ((trdy >= 0) && (dy < 0))) {
+		if (*railbit < 8) { // first direction is invalid, try the other
+			SETBIT(*railbit, 3);
+			trdx = -trdx;
+			trdy = -trdy;
+		} else // other direction is invalid too, invalid drag
+			return CMD_ERROR;
+	}
+
+	// (for diagonal tracks, this is already made sure of by above test), but:
+	// for non-diagonal tracks, check if the start and end tile are on 1 line
+	if (*railbit & 0x6) {
+		trdx = _railbit.xinc[*railbit];
+		trdy = _railbit.yinc[*railbit];
+		if ((abs(dx) != abs(dy)) && (abs(dx) + abs(trdy) != abs(dy) + abs(trdx)))
+			return CMD_ERROR;
+	}
+
+	return 0;
+}
+
+/* Build a stretch of railroad tracks.
+ * x,y= start tile
+ * p1 = end tile
+ * p2 = (bit 0-3)		- railroad type normal/maglev
+ * p2 = (bit 4-6)		- track-orientation, valid values: 0-5
+ * p2 = (bit 7)			- 0 = build, 1 = remove tracks
  */
-
+static int32 CmdRailTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+{
+	int ex, ey;
+	int32 ret, total_cost = 0;
+	int railbit = (p2 >> 4) & 7;
+	byte mode = HASBIT(p2, 7);
 
-int32 CmdBuildRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2)
-{
-	int sx, sy;
-	int32 ret, total_cost = 0;
-	int railbit;
+	/* unpack end point */
+	ex = TileX(p1) * 16;
+	ey = TileY(p1) * 16;
 
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
 	if (flags & DC_EXEC)
 		SndPlayTileFx(SND_20_SPLAT_2, TILE_FROM_XY(x,y));
 
-	/* unpack end point */
-	sx = (p1 & 0xFFFF) & ~0xF;
-	sy = (p1 >> 16) & ~0xF;
-
-	railbit = _railbit.initial[(p2 >> 4) + (x > sx ? 4 : 0) + (y > sy ? 8 : 0)];
+	if (ValidateAutoDrag(&railbit, x, y, ex, ey) == CMD_ERROR)
+		return CMD_ERROR;
 
 	for(;;) {
-		ret = DoCommand(x, y, p2&0xF, railbit&7, flags, CMD_BUILD_SINGLE_RAIL);
+		ret = DoCommand(x, y, p2&0x3, railbit&7, flags, (mode == 0) ? CMD_BUILD_SINGLE_RAIL : CMD_REMOVE_SINGLE_RAIL);
 
 		if (ret == CMD_ERROR) {
-			if (_error_message != STR_1007_ALREADY_BUILT)
+			if ((_error_message != STR_1007_ALREADY_BUILT) && (mode == 0))
 				break;
 		} else
 			total_cost += ret;
 
-		if (x == sx && y == sy)
+		if (x == ex && y == ey)
 			break;
 
 		x += _railbit.xinc[railbit];
 		y += _railbit.yinc[railbit];
 
-		// toggle railbit for the diagonal tiles
+		// toggle railbit for the non-diagonal tracks
 		if (railbit & 0x6) railbit ^= 1;
 	}
 
@@ -579,48 +614,14 @@
 	return total_cost;
 }
 
-
-/* Remove either NE or NW sequence of tracks.
- * p1 0:15  - start pt X
- * p1 16:31 - start pt y
- *
- * p2 0:3   - rail type
- * p2 4:7   - rail direction
- */
-
+int32 CmdBuildRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+{
+	return CmdRailTrackHelper(x, y, flags, p1, p2);
+}
 
 int32 CmdRemoveRailroadTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 {
-	int sx, sy;
-	int32 ret, total_cost = 0;
-	int railbit;
-
-	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
-
-	if (flags & DC_EXEC)
-		SndPlayTileFx(SND_20_SPLAT_2, TILE_FROM_XY(x,y));
-
-	/* unpack start point */
-	sx = (p1 & 0xFFFF) & ~0xF;
-	sy = (p1 >> 16) & ~0xF;
-
-	railbit = _railbit.initial[(p2 >> 4) + (x > sx ? 4 : 0) + (y > sy ? 8 : 0)];
-
-	for(;;) {
-		ret = DoCommand(x, y, p2&0xF, railbit&7, flags, CMD_REMOVE_SINGLE_RAIL);
-		if (ret != CMD_ERROR) total_cost += ret;
-		if (x == sx && y == sy)
-			break;
-		x += _railbit.xinc[railbit];
-		y += _railbit.yinc[railbit];
-		// toggle railbit for the diagonal tiles
-		if (railbit & 0x6) railbit ^= 1;
-	}
-
-	if (total_cost == 0)
-		return CMD_ERROR;
-
-	return total_cost;
+	return CmdRailTrackHelper(x, y, flags, p1, SETBIT(p2, 7));
 }
 
 /* Build a train depot
@@ -870,7 +871,7 @@
  *               depending on context
  * p2 = used for CmdBuildManySignals() to copy style of first signal
  */
-int32 CmdBuildSignals(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+int32 CmdBuildSingleSignal(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 {
 	TileIndex tile = TILE_FROM_XY(x, y);
 	bool semaphore;
@@ -992,68 +993,45 @@
 }
 
 /*	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
-		p2 = (byte 24-31)	- user defined signals_density
+ * x,y = start tile
+ * p1  = end tile
+ * p2  = (bit 0)			- 0 = build, 1 = remove signals
+ * p2  = (bit 3)			- 0 = signals, 1 = semaphores
+ * p2  = (bit 4-6)		- track-orientation, valid values: 0-5
+ * p2  = (bit 24-31)	- user defined signals_density
  */
-int32 CmdBuildManySignals(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+static int32 CmdSignalTrackHelper(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 {
-	int ex, ey, railbit;
+	int ex, ey;
+	int railbit = (p2 >> 4) & 7;
 	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;
+	int mode = p2 & 0x1;
 	// 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) ? (p2 >> 24) : (p2 >> 24) * 2;
-	byte signals = (p2 >> 8)&0xFF;
-	mode = p2 & 0x1;  // build/remove signals
+	byte signal_density = (railbit & 0x6) ? (p2 >> 24) * 2: (p2 >> 24);
+	byte signals;
 
 	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
 
-	/* unpack end tile */
+	// unpack end tile
 	ex = TileX(p1) * 16;
 	ey = TileY(p1) * 16;
 
-	railbit = _railbit.initial[((p2 >> 4)&0xF) + (x > ex ? 4 : 0) + (y > ey ? 8 : 0)];
+	if (ValidateAutoDrag(&railbit, x, y, ex, ey) == CMD_ERROR)
+		return CMD_ERROR;
 
 	// 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;
-			}
-		}
+		signals = _map3_lo[tile] & _signals_table_both[railbit];
+		if (signals == 0) signals = _signals_table_both[railbit];
 
 		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;
-		}
+		signals = _signals_table_both[railbit];
 	}
 
 	/* signal_density_ctr	- amount of tiles already processed
@@ -1089,19 +1067,25 @@
 		y += _railbit.yinc[railbit];
 		signal_ctr++;
 
-		// toggle railbit for the diagonal tiles (|, -- tracks)
+		// toggle railbit for the non-diagonal tracks (|, -- tracks)
 		if (railbit & 0x6) railbit ^= 1;
 	}
 
 	return (error) ? CMD_ERROR : total_cost;
 }
 
+/* Stub for the unified Signal builder/remover */
+int32 CmdBuildSignalTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+{
+	return CmdSignalTrackHelper(x, y, flags, p1, p2);
+}
+
 /* Remove signals
  * p1 bits 0..2 = track
  * p2 = unused
  */
 
-int32 CmdRemoveSignals(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+int32 CmdRemoveSingleSignal(int x, int y, uint32 flags, uint32 p1, uint32 p2)
 {
 	TileInfo ti;
 	uint tile;
@@ -1159,6 +1143,12 @@
 	return _price.remove_signals;
 }
 
+/* Stub for the unified Signal builder/remover */
+int32 CmdRemoveSignalTrack(int x, int y, uint32 flags, uint32 p1, uint32 p2)
+{
+	return CmdSignalTrackHelper(x, y, flags, p1, SETBIT(p2, 1));
+}
+
 typedef int32 DoConvertRailProc(uint tile, uint totype, bool exec);
 
 static int32 DoConvertRail(uint tile, uint totype, bool exec)
--- a/rail_gui.c	Sun Jan 30 14:52:04 2005 +0000
+++ b/rail_gui.c	Sun Jan 30 15:57:38 2005 +0000
@@ -309,117 +309,45 @@
 	ShowTerraformToolbar();
 }
 
-
 static void DoRailroadTrack(int mode)
 {
-	DoCommandP(TILE_FROM_XY(_thd.selstart.x, _thd.selstart.y), PACK_POINT(_thd.selend.x, _thd.selend.y), (mode << 4) | _cur_railtype, NULL,
+	DoCommandP(TILE_FROM_XY(_thd.selstart.x, _thd.selstart.y), TILE_FROM_XY(_thd.selend.x, _thd.selend.y), _cur_railtype | (mode << 4), NULL,
 		_remove_button_clicked ?
 		CMD_REMOVE_RAILROAD_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1012_CAN_T_REMOVE_RAILROAD_TRACK) :
-		CMD_BUILD_RAILROAD_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK)
+		CMD_BUILD_RAILROAD_TRACK  | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1011_CAN_T_BUILD_RAILROAD_TRACK)
 	);
 }
 
-
-// This function is more or less a hack because DoRailroadTrack() would otherwise screw up
-static void SwapSelection(void)
-{
-	TileHighlightData *thd = &_thd;
-	Point pt = thd->selstart;
-	thd->selstart.x = thd->selend.x & ~0xF;
-	thd->selstart.y = thd->selend.y & ~0xF;
-	thd->selend = pt;
-}
-
-
 static void HandleAutodirPlacement(void)
 {
 	TileHighlightData *thd = &_thd;
-	int bit;
-	int dx = thd->selstart.x - (thd->selend.x&~0xF);
-	int dy = thd->selstart.y - (thd->selend.y&~0xF);
+	int trackstat = thd->drawstyle & 0xF; // 0..5
 
 	if (thd->drawstyle & HT_RAIL) { // one tile case
-		bit = thd->drawstyle & 0xF;
-		GenericPlaceRail(TILE_FROM_XY(thd->selend.x, thd->selend.y), bit);
-	} else if ( !(thd->drawstyle & 0xE) ) { // x/y dir
-		if (dx == 0) { // Y dir
-			DoRailroadTrack(1);
-		} else {
-			DoRailroadTrack(2);
-		}
-	} else if (myabs(dx)+myabs(dy) >= 32) { // long line (more than 2 tiles)
-		if(thd->drawstyle == (HT_LINE | HT_DIR_HU))
-			DoRailroadTrack(0);
-		if(thd->drawstyle == (HT_LINE | HT_DIR_HL))
-			DoRailroadTrack(3);
-		if(thd->drawstyle == (HT_LINE | HT_DIR_VL))
-			DoRailroadTrack(3);
-		if(thd->drawstyle == (HT_LINE | HT_DIR_VR))
-			DoRailroadTrack(0);
-	} else { // 2x1 pieces line
-		if(thd->drawstyle == (HT_LINE | HT_DIR_HU)) {
-			DoRailroadTrack(0);
-		} else if (thd->drawstyle == (HT_LINE | HT_DIR_HL)) {
-			SwapSelection();
-			DoRailroadTrack(0);
-			SwapSelection();
-		} else if (thd->drawstyle == (HT_LINE | HT_DIR_VL)) {
-			if(dx == 0) {
-				SwapSelection();
-				DoRailroadTrack(0);
-				SwapSelection();
-			} else {
-				DoRailroadTrack(3);
-			}
-		} else if (thd->drawstyle == (HT_LINE | HT_DIR_VR)) {
-			if(dx == 0) {
-				DoRailroadTrack(0);
-			} else {
-				SwapSelection();
-				DoRailroadTrack(3);
-				SwapSelection();
-			}
-		}
+		GenericPlaceRail(TILE_FROM_XY(thd->selend.x, thd->selend.y), trackstat);
+		return;
 	}
+
+	DoRailroadTrack(trackstat);
 }
 
 static void HandleAutoSignalPlacement(void)
 {
 	TileHighlightData *thd = &_thd;
-	int mode = 0;
-	uint trackstat = 0;
-
-	int dx = thd->selstart.x - (thd->selend.x&~0xF);
-	int dy = thd->selstart.y - (thd->selend.y&~0xF);
+	byte trackstat = thd->drawstyle & 0xF; // 0..5
 
 	if (thd->drawstyle == HT_RECT) { // one tile case
 		GenericPlaceSignals(TILE_FROM_XY(thd->selend.x, thd->selend.y));
 		return;
 	}
 
-	if (!(thd->drawstyle & 0xE)) { // X/Y direction
-		mode = (dx == 0) ? VPM_FIX_X : VPM_FIX_Y;
-		trackstat = 0xC0;
-	} else if (myabs(dx) + myabs(dy) >= 32) { // long line (more than 2 tiles)
-		mode = ((thd->drawstyle & 0xF) == HT_DIR_HU || (thd->drawstyle & 0xF) == HT_DIR_VR) ? 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) ? 8 : 4;
-
-	} else { // 2x1 pieces line
-		GenericPlaceSignals(TILE_FROM_XY(thd->selstart.x, thd->selstart.y));
-		return;
-	}
-
 	// _patches.drag_signals_density is given as a parameter such that each user in a network
 	// game can specify his/her own signal density
 	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) | (trackstat << 8) | (_patches.drag_signals_density << 24),
+	(_ctrl_pressed ? 1 << 3 : 0) | (trackstat << 4) | (_patches.drag_signals_density << 24),
 	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) ) );
+	(_remove_button_clicked ?	CMD_REMOVE_SIGNAL_TRACK | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1013_CAN_T_REMOVE_SIGNALS_FROM) :
+	                          CMD_BUILD_SIGNAL_TRACK  | CMD_AUTO | CMD_NO_WATER | CMD_MSG(STR_1010_CAN_T_BUILD_SIGNALS_HERE) ) );
 }
 
 static OnButtonClick * const _build_railroad_button_proc[] = {
@@ -527,9 +455,8 @@
 				DoCommandP(end_tile, start_tile, _cur_railtype, CcPlaySound10, CMD_LEVEL_LAND | CMD_AUTO);
 			} else if (e->place.userdata == VPM_X_AND_Y_LIMITED) {
 				HandleStationPlacement(start_tile, end_tile);
-			} else {
-				DoRailroadTrack(e->place.userdata);
-			}
+			} else
+				DoRailroadTrack(e->place.userdata & 1);
 		}
 		break;