(svn r1571) Feature: Visually enhanced autorail placing
authordominik
Wed, 19 Jan 2005 20:55:23 +0000
changeset 1070 bef634a62323
parent 1069 922f5c7be173
child 1071 f6da855a4c2e
(svn r1571) Feature: Visually enhanced autorail placing
When using the autorail tool, the rail pieces which are going to be build are highlighted.
If a piece is shown in red, this indicates that the slope/rail combination is impossible. It does not tell you if the rail line construction might not be possible because of other obstacles, e.g. houses or water.
data/autorail.grf
data/openttd.grf
main_gui.c
rail_gui.c
spritecache.c
table/autorail.h
table/sprites.h
viewport.c
viewport.h
Binary file data/autorail.grf has changed
Binary file data/openttd.grf has changed
--- a/main_gui.c	Wed Jan 19 20:22:10 2005 +0000
+++ b/main_gui.c	Wed Jan 19 20:55:23 2005 +0000
@@ -111,7 +111,19 @@
 	}
 }
 
-// this code is shared for the majority of the pushbuttons
+/**
+ * This code is shared for the majority of the pushbuttons.
+ * Handles e.g. the pressing of a button (to build things), playing of click sound and sets certain parameters
+ *
+ * @param w Window which called the function
+ * @param widget ID of the widget (=button) that called this function
+ * @param cursor How should the cursor image change? E.g. cursor with depot image in it
+ * @param mode Tile highlighting mode, e.g. drawing a rectangle or a dot on the ground
+ * @param placeproc Procedure which will be called when someone clicks on the map
+ 
+ * @return true if the button is clicked, false if it's unclicked
+ */
+
 bool HandlePlacePushButton(Window *w, int widget, uint32 cursor, int mode, PlaceProc *placeproc)
 {
 	uint32 mask = 1 << widget;
--- a/rail_gui.c	Wed Jan 19 20:22:10 2005 +0000
+++ b/rail_gui.c	Wed Jan 19 20:55:23 2005 +0000
@@ -232,7 +232,7 @@
 
 static void BuildRailClick_AutoRail(Window *w)
 {
-	HandlePlacePushButton(w, 8, _cur_railtype + SPR_OPENTTD_BASE + 4, 1, PlaceRail_AutoRail);
+	HandlePlacePushButton(w, 8, _cur_railtype + SPR_CURSOR_AUTORAIL, VHM_RAIL, PlaceRail_AutoRail);
 }
 
 static void BuildRailClick_Demolish(Window *w)
@@ -266,7 +266,7 @@
 
 static void BuildRailClick_AutoSignals(Window *w)
 {
-	HandlePlacePushButton(w, 13, ANIMCURSOR_BUILDSIGNALS , 1, PlaceRail_AutoSignals);
+	HandlePlacePushButton(w, 13, ANIMCURSOR_BUILDSIGNALS, VHM_RECT, PlaceRail_AutoSignals);
 }
 
 static void BuildRailClick_Bridge(Window *w)
@@ -320,6 +320,10 @@
 	);
 }
 
+/* This code was used for ludde's special autorail autocomplete.
+ * It analyzes the adjecent tiles and bases it's decision which
+ * rail piece to place on this.
+
 typedef struct {
 	byte bit, a,b, mouse;
 } BestFitStruct;
@@ -432,7 +436,9 @@
 
 	return best;
 }
+*/
 
+// This function is more or less a hack because DoRailroadTrack() would otherwise screw up
 static void SwapSelection()
 {
 	TileHighlightData *thd = &_thd;
@@ -442,6 +448,8 @@
 	thd->selend = pt;
 }
 
+/* see above, residue from ludde's special autorail autocomplete
+
 static bool Check2x1AutoRail(int mode)
 {
 	TileHighlightData *thd = &_thd;
@@ -474,46 +482,61 @@
 
 	return false;
 }
-
+*/
 
 static void HandleAutodirPlacement()
 {
 	TileHighlightData *thd = &_thd;
 	int bit;
-
-	if (thd->drawstyle == HT_RECT) {
-		int dx = thd->selstart.x - (thd->selend.x&~0xF);
-		int dy = thd->selstart.y - (thd->selend.y&~0xF);
+	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
-			bit = GetBestFit1x1(thd->selend.x, thd->selend.y);
-			if (bit == -1) return;
-			GenericPlaceRail(TILE_FROM_XY(thd->selend.x, thd->selend.y), bit);
-		} else if (dx == 0) {
-			if (dy == -16) {
-				if (Check2x1AutoRail(0)) return;
-			} else if (dy == 16) {
-				if (Check2x1AutoRail(1)) return;
+	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);
 			}
-			// same x coordinate
-			DoRailroadTrack(VPM_FIX_X);
-		} else {
-			// same y coordinate
-			// check it's it -16 or 16, then we must check if it should be normal tiles or special tiles.
-			if (dx == -16) {
-				if (Check2x1AutoRail(2)) return;
-			} else if (dx == 16) {
-				if (Check2x1AutoRail(3)) return;
+		} else if (thd->drawstyle == (HT_LINE | HT_DIR_VR)) {
+			if(dx == 0) {
+				DoRailroadTrack(0);
+			} else {
+				SwapSelection();
+				DoRailroadTrack(3);
+				SwapSelection();
 			}
-			DoRailroadTrack(VPM_FIX_Y);
 		}
-	} else {
-		DoRailroadTrack(thd->drawstyle & 1 ? 0 : 3);
 	}
 }
 
-static void HandleAutoSignalPlacement()
+static void HandleAutoSignalPlacement(void)
 {
 	TileHighlightData *thd = &_thd;
 	int mode = 0;
@@ -525,7 +548,7 @@
 	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 (!(thd->drawstyle & 0xE)) { // X,Y direction
 			if (dx == 0)
 				mode = VPM_FIX_X;
 			else if (dy == 0)
@@ -533,16 +556,18 @@
 
 			trackstat = 0xC0;
 		}	else { // W-E or N-S direction
-			mode = thd->drawstyle & 1 ? 0 : 3;
+			if ((thd->drawstyle & 0xF) == 2 || (thd->drawstyle & 0xF) == 5)
+				mode = 0;
+			else
+				mode = 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;
+				trackstat = (thd->drawstyle & 1) ? 8 : 4;
 		}
-
-		/* _patches.drag_signals_density is given as a parameter such that each user in a network
-		 * game can specify his/her own signal density */
+		// _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 ? 8 : 0)) | (trackstat << 8) | (_patches.drag_signals_density << 24),
 		CcPlaySound1E,
--- a/spritecache.c	Wed Jan 19 20:22:10 2005 +0000
+++ b/spritecache.c	Wed Jan 19 20:55:23 2005 +0000
@@ -883,6 +883,9 @@
 
 		LoadGrfIndexed("trkfoundw.grf", _slopes_spriteindexes[_opt.landscape], i++);
 
+		load_index = SPR_AUTORAIL_BASE;
+		load_index += LoadGrfFile("autorail.grf", load_index, i++);
+
 		load_index = SPR_CANALS_BASE;
 		load_index += LoadGrfFile("canalsw.grf", load_index, i++);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/table/autorail.h	Wed Jan 19 20:55:23 2005 +0000
@@ -0,0 +1,70 @@
+/* Rail selection types (directions):
+ / \    / \    / \    / \   / \   / \
+/  /\  /\  \  /===\  /   \ /|  \ /  |\
+\/  /  \  \/  \   /  \===/ \|  / \  |/
+ \ /    \ /    \ /    \ /   \ /   \ /
+  0      1      2      3     4     5
+*/
+
+// mark invalid tiles red
+#define RED(c) c | PALETTE_SEL_TILE_RED
+
+// table maps each of the six rail directions and tileh combinations to a sprite
+// invalid entries are required to make sure that this array can be quickly accessed
+const int AutorailTilehSprite[31][6] = {
+// type   0        1        2        3        4        5
+	{       0,       8,      16,      25,      34,      42 }, // tileh = 0
+	{       5,      13, RED(22), RED(31),      35,      42 }, // tileh = 1
+	{       5,      10,      16,      26, RED(38), RED(46) }, // tileh = 2
+	{       5,       9, RED(23),      26,      35, RED(46) }, // tileh = 3
+	{       2,      10, RED(19), RED(28),      34,      43 }, // tileh = 4
+	{       1,       9,      17,      26,      35,      43 }, // tileh = 5
+	{       1,      10, RED(20),      26, RED(38),      43 }, // tileh = 6
+	{       1,       9,      17,      26,      35,      43 }, // tileh = 7
+	{       2,      13,      17,      25, RED(40), RED(48) }, // tileh = 8
+	{       1,      13,      17, RED(32),      35, RED(48) }, // tileh = 9
+	{       2,       9,      17,      26,      35,      43 }, // tileh = 10
+	{       1,       9,      17,      26,      35,      43 }, // tileh = 11
+	{       2,       9,      17, RED(29), RED(40),      43 }, // tileh = 12
+	{       1,       9,      17,      26,      35,      43 }, // tileh = 13
+	{       1,       9,      17,      26,      35,      43 }, // tileh = 14
+	{       0,       1,       2,       3,       4,       5 }, // invalid (15)
+	{       0,       1,       2,       3,       4,       5 }, // invalid (16)
+	{       0,       1,       2,       3,       4,       5 }, // invalid (17)
+	{       0,       1,       2,       3,       4,       5 }, // invalid (18)
+	{       0,       1,       2,       3,       4,       5 }, // invalid (19)
+	{       0,       1,       2,       3,       4,       5 }, // invalid (20)
+	{       0,       1,       2,       3,       4,       5 }, // invalid (21)
+	{       0,       1,       2,       3,       4,       5 }, // invalid (22)
+	{  RED(6), RED(11), RED(17), RED(27), RED(39), RED(47) }, // tileh = 23
+	{       0,       1,       2,       3,       4,       5 }, // invalid (24)
+	{       0,       1,       2,       3,       4,       5 }, // invalid (25)
+	{       0,       1,       2,       3,       4,       5 }, // invalid (26)
+	{  RED(7), RED(15), RED(24), RED(33), RED(36), RED(44) }, // tileh = 27
+	{       0,       1,       2,       3,       4,       5 }, // invalid (28)
+	{  RED(3), RED(14), RED(18), RED(26), RED(41), RED(49) }, // tileh = 29
+	{  RED(4), RED(12), RED(21), RED(30), RED(37), RED(45) }, // tileh = 30
+};
+#undef RED
+
+
+// maps each pixel of a tile (16x16) to a selection type
+// (0,0) is the top corner, (16,16) the bottom corner
+const int AutorailPiece[16][16] = {
+	{ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5 },
+	{ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5 },
+	{ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5 },
+	{ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5 },
+	{ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5 },
+	{ 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 5, 5, 5, 5, 5, 5 },
+	{ 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1 },
+	{ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1 },
+	{ 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 },
+	{ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1 },
+	{ 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3 },
+	{ 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3 },
+	{ 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3 },
+	{ 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3 },
+	{ 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3 },
+	{ 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3 }
+};
--- a/table/sprites.h	Wed Jan 19 20:22:10 2005 +0000
+++ b/table/sprites.h	Wed Jan 19 20:55:23 2005 +0000
@@ -44,7 +44,8 @@
 	/* Extra graphic spritenumbers */
 	SPR_CANALS_BASE		= 5126,
 	SPR_SLOPES_BASE		= SPR_CANALS_BASE + 70,
-	SPR_OPENTTD_BASE	= SPR_SLOPES_BASE + 74,		//5270
+	SPR_AUTORAIL_BASE		= SPR_SLOPES_BASE + 78,
+	SPR_OPENTTD_BASE	= SPR_AUTORAIL_BASE + 55, // can be lowered once autorail.grf is finalized
 
 	SPR_BLOT = SPR_OPENTTD_BASE + 32, // colored circle (mainly used as vehicle profit marker and for sever compatibility)
 
--- a/viewport.c	Wed Jan 19 20:22:10 2005 +0000
+++ b/viewport.c	Wed Jan 19 20:55:23 2005 +0000
@@ -595,11 +595,7 @@
 
 static void DrawSelectionSprite(uint32 image, const TileInfo *ti)
 {
-	if (_added_tile_sprite) {
-		DrawGroundSpriteAt(image, ti->x, ti->y, ti->z + 7);
-	} else {
-		AddSortableSpriteToDraw(image, ti->x, ti->y, 0x10, 0x10, 1, ti->z + 7);
-	}
+	AddSortableSpriteToDraw(image, ti->x, ti->y, 0x10, 0x10, 1, ti->z + 7);
 }
 
 static bool IsPartOfAutoLine(int px, int py)
@@ -610,10 +606,12 @@
 	py -= thd->selstart.y;
 
 	switch(thd->drawstyle) {
-	case HT_LINE | 0: return px == py || px == py + 16;
-	case HT_LINE | 1: return px == py || px == py - 16;
-	case HT_LINE | 2: return px == -py || px == -py + 16;
-	case HT_LINE | 3: return px == -py || px == -py - 16;
+	case HT_LINE | HT_DIR_X:  return py == 0; // x direction
+	case HT_LINE | HT_DIR_Y:  return px == 0; // y direction
+	case HT_LINE | HT_DIR_HU: return px == -py || px == -py - 16; // horizontal upper
+	case HT_LINE | HT_DIR_HL: return px == -py || px == -py + 16; // horizontal lower
+	case HT_LINE | HT_DIR_VL: return px == py || px == py + 16; // vertival left
+	case HT_LINE | HT_DIR_VR: return px == py || px == py - 16; // vertical right
 	default:
 		NOT_REACHED();
 	}
@@ -622,6 +620,18 @@
 	return 0;
 }
 
+// [direction][side]
+static const int AutorailType[6][2] = {
+	{ HT_DIR_X,  HT_DIR_X },
+	{ HT_DIR_Y,  HT_DIR_Y },
+	{ HT_DIR_HU, HT_DIR_HL },
+	{ HT_DIR_HL, HT_DIR_HU },
+	{ HT_DIR_VL, HT_DIR_VR },
+	{ HT_DIR_VR, HT_DIR_VL }
+};
+
+#include "table/autorail.h"
+
 static void DrawTileSelection(const TileInfo *ti)
 {
 	uint32 image;
@@ -657,13 +667,32 @@
 				}
 			}
 			DrawGroundSpriteAt(_cur_dpi->zoom != 2 ? 0x306 : 0xFEE,ti->x, ti->y, z);
-		} else {
-			if (IsPartOfAutoLine(ti->x, ti->y)) {
-				image = 0x2F0 + _tileh_to_sprite[ti->tileh];
+
+		} else if (thd->drawstyle & HT_RAIL /*&& thd->place_mode == VHM_RAIL*/) { // autorail highlight piece under cursor
+			int type = thd->drawstyle & 0xF;
+			assert(type<=5);
+			image = SPR_AUTORAIL_BASE + AutorailTilehSprite[ ti->tileh ][ AutorailType[type][0] ];
+
+			if (thd->make_square_red) image |= 0x3048000;
+			DrawSelectionSprite(image, ti);
+
+		} else if (IsPartOfAutoLine(ti->x, ti->y)) { // autorail highlighting long line
+				int dir = thd->drawstyle & ~0xF0;
+				uint start = TILE_FROM_XY(thd->selstart.x, thd->selstart.y);
+				int diffx, diffy;
+				int side;
+
+				diffx = myabs(TileX(start)-TileX(ti->tile));
+				diffy = myabs(TileY(start)-TileY(ti->tile));
+				
+				side = myabs( diffx-diffy );
+				if(dir<2) side = 0;
+
+				image = SPR_AUTORAIL_BASE + AutorailTilehSprite[ ti->tileh ][ AutorailType[dir][side] ];
+
 				if (thd->make_square_red) image |= 0x3048000;
 				DrawSelectionSprite(image, ti);
-			}
-		}
+			} 
 		return;
 	}
 
@@ -1715,7 +1744,7 @@
 	if (pt.x == -1)
 		return;
 
-	if (_thd.place_mode == 2) {
+	if (_thd.place_mode == VHM_POINT) {
 		pt.x += 8;
 		pt.y += 8;
 	}
@@ -1810,7 +1839,15 @@
 	thd->new_outersize.y = sy * 16;
 }
 
+/* returns the best autorail highlight type from map coordinates */
+static byte GetAutorailHT(int x, int y)
+{
+	int i;
+	i = AutorailPiece[x&0xF][y&0xF];
+	return HT_RAIL | i;
+}
 
+// called regular to update tile highlighting in all cases
 void UpdateTileSelection()
 {
 	TileHighlightData *thd = _thd_ptr;
@@ -1819,7 +1856,7 @@
 
 	thd->new_drawstyle = 0;
 
-	if (thd->place_mode == 3) {
+	if (thd->place_mode == VHM_SPECIAL) {
 		x1 = thd->selend.x;
 		y1 = thd->selend.y;
 		if (x1 != -1) {
@@ -1836,23 +1873,29 @@
 			thd->new_size.y = y2 - y1 + 16;
 			thd->new_drawstyle = thd->next_drawstyle;
 		}
-	} else if (thd->place_mode != 0) {
+	} else if (thd->place_mode != VHM_NONE) {
 		pt = GetTileBelowCursor();
 		x1 = pt.x;
 		y1 = pt.y;
 		if (x1 != -1) {
-			if (thd->place_mode == 1) {
-				thd->new_drawstyle = HT_RECT;
-			} else {
-				thd->new_drawstyle = HT_POINT;
-				x1 += 8;
-				y1 += 8;
+			switch (thd->place_mode) {
+				case VHM_RECT:
+					thd->new_drawstyle = HT_RECT;
+					break;
+				case VHM_POINT:
+					thd->new_drawstyle = HT_POINT;
+					x1 += 8;
+					y1 += 8;
+					break;
+				case VHM_RAIL:
+					thd->new_drawstyle = GetAutorailHT(pt.x, pt.y); // draw one highlighted tile
 			}
 			thd->new_pos.x = x1 & ~0xF;
 			thd->new_pos.y = y1 & ~0xF;
 		}
 	}
 
+	// redraw selection
 	if (thd->drawstyle != thd->new_drawstyle ||
 			thd->pos.x != thd->new_pos.x || thd->pos.y != thd->new_pos.y ||
 			thd->size.x != thd->new_size.x || thd->size.y != thd->new_size.y) {
@@ -1871,21 +1914,24 @@
 	}
 }
 
+// highlighting tiles while only going over them with the mouse
 void VpStartPlaceSizing(uint tile, int user)
 {
 	TileHighlightData *thd;
-
 	thd = _thd_ptr;
 	thd->userdata = user;
 	thd->selend.x = TileX(tile) * 16;
 	thd->selstart.x = TileX(tile) * 16;
 	thd->selend.y = TileY(tile) * 16;
 	thd->selstart.y = TileY(tile) * 16;
-	if (thd->place_mode == 1) {
-		thd->place_mode = 3;
+	if (thd->place_mode == VHM_RECT) {
+		thd->place_mode = VHM_SPECIAL;
 		thd->next_drawstyle = HT_RECT;
+	} else if (thd->place_mode == VHM_RAIL) { // autorail one piece
+		thd->place_mode = VHM_SPECIAL;
+		thd->next_drawstyle = thd->drawstyle;
 	} else {
-		thd->place_mode = 3;
+		thd->place_mode = VHM_SPECIAL;
 		thd->next_drawstyle = HT_POINT;
 	}
 	_special_mouse_mode = WSM_SIZING;
@@ -1912,51 +1958,114 @@
 	_special_mouse_mode = WSM_PRESIZE;
 }
 
-static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y)
+/* returns information about the 2x1 piece to be build. 
+ * The lower bits (0-3) are the track type. */
+static byte Check2x1AutoRail(int mode)
+{
+	TileHighlightData *thd = &_thd;
+	int fxpy = _tile_fract_coords.x + _tile_fract_coords.y;
+	int sxpy = (thd->selend.x & 0xF) + (thd->selend.y & 0xF);
+	int fxmy = _tile_fract_coords.x - _tile_fract_coords.y;
+	int sxmy = (thd->selend.x & 0xF) - (thd->selend.y & 0xF);
+
+	switch(mode) {
+	case 0: // end piece is lower right
+		if (fxpy >= 20 && sxpy <= 12) { /*SwapSelection(); DoRailroadTrack(0); */return 3; }
+		if (fxmy < -3 && sxmy > 3) {/* DoRailroadTrack(0); */return 5; }
+		return 1;
+		break;
+
+	case 1:
+		if (fxmy > 3 && sxmy < -3) { /*SwapSelection(); DoRailroadTrack(0); */return 4; }
+		if (fxpy <= 12 && sxpy >= 20) { /*DoRailroadTrack(0); */return 2; }
+		return 1;
+		break;
+
+	case 2:
+		if (fxmy > 3 && sxmy < -3) { /*DoRailroadTrack(3);*/ return 4; }
+		if (fxpy >= 20 && sxpy <= 12) { /*SwapSelection(); DoRailroadTrack(0); */return 3; }
+		return 0;
+		break;
+
+	case 3:
+		if (fxmy < -3 && sxmy > 3) { /*SwapSelection(); DoRailroadTrack(3);*/ return 5; }
+		if (fxpy <= 12 && sxpy >= 20) { /*DoRailroadTrack(0); */return 2; }
+		return 0;
+		break;
+	}
+
+	return 0; // avoids compiler warnings
+}
+
+
+// while dragging
+static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y, int method)
 {
 	int d;
-	bool b;
+	byte b=6;
 	uint w,h;
 
-	w =	myabs((x & ~0xF) - thd->selstart.x) + 16;
-	h = myabs((y & ~0xF) - thd->selstart.y) + 16;
+	int dx = thd->selstart.x - (thd->selend.x&~0xF);
+	int dy = thd->selstart.y - (thd->selend.y&~0xF);
+	w = myabs(dx) + 16;
+	h = myabs(dy) + 16;
 
-	// vertical and horizontal lines are really simple
-	if (w == 16 || h == 16) {
-		b = HT_RECT;
-	} else if (w * 2 < h) { // see if we're closer to rect?
+	if (TILE_FROM_XY(thd->selstart.x, thd->selstart.y) == TILE_FROM_XY(x,y)) { // check if we're only within one tile
+			if(method == VPM_RAILDIRS)
+				b = GetAutorailHT(x, y);
+			else // rect for autosignals on one tile
+				b = HT_RECT;
+	} else if (h == 16) { // Is this in X direction?
+		if (dx==16) // 2x1 special handling
+			b = (Check2x1AutoRail(3)) | HT_LINE;
+		else if (dx==-16)
+			b = (Check2x1AutoRail(2)) | HT_LINE;
+		else 
+			b = HT_LINE | HT_DIR_X;
+		y = thd->selstart.y;
+	} else if (w == 16) { // Or Y direction?
+		if (dy==16) // 2x1 special handling
+			b = (Check2x1AutoRail(1)) | HT_LINE;
+		else if (dy==-16) // 2x1 other direction
+			b = (Check2x1AutoRail(0)) | HT_LINE;
+		else 
+			b = HT_LINE | HT_DIR_Y;
 		x = thd->selstart.x;
-		b = HT_RECT;
-	} else if (w > h * 2) {
+	} else if (w > h * 2) { // still count as x dir?
+			b = HT_LINE | HT_DIR_X;
 		y = thd->selstart.y;
-		b = HT_RECT;
-	} else {
+	} else if (h > w * 2) { // still count as y dir?
+			b = HT_LINE | HT_DIR_Y;
+		x = thd->selstart.x;
+	} else { // complicated direction
 		d = w - h;
+		thd->selend.x = thd->selend.x&~0xF;
+		thd->selend.y = thd->selend.y&~0xF;
 
 		// four cases.
 		if (x > thd->selstart.x) {
 			if (y > thd->selstart.y) {
 				// south
-				if (d ==0) b = (x & 0xF) > (y & 0xF) ? HT_LINE | 0 : HT_LINE | 1;
-				else if (d >= 0) { x = thd->selstart.x + h; b = HT_LINE | 0; } // return px == py || px == py + 16;
-				else { y = thd->selstart.y + w; b = HT_LINE | 1; } // return px == py || px == py - 16;
+				if (d ==0) b = (x & 0xF) > (y & 0xF) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
+				else if (d >= 0) { x = thd->selstart.x + h; b = HT_LINE | HT_DIR_VL; } // return px == py || px == py + 16;
+				else { y = thd->selstart.y + w; b = HT_LINE | HT_DIR_VR; } // return px == py || px == py - 16;
 			} else {
 				// west
-				if (d ==0) b = (x & 0xF) + (y & 0xF) >= 0x10 ? HT_LINE | 2 : HT_LINE | 3;
-				else if (d >= 0) { x = thd->selstart.x + h; b = HT_LINE | 2; }
-				else { y = thd->selstart.y - w; b = HT_LINE | 3; }
+				if (d ==0) b = (x & 0xF) + (y & 0xF) >= 0x10 ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
+				else if (d >= 0) { x = thd->selstart.x + h; b = HT_LINE | HT_DIR_HL; }
+				else { y = thd->selstart.y - w; b = HT_LINE | HT_DIR_HU; }
 			}
 		} else {
 			if (y > thd->selstart.y) {
 				// east
-				if (d ==0) b = (x & 0xF) + (y & 0xF) >= 0x10 ? HT_LINE | 2 : HT_LINE | 3;
-				else if (d >= 0) { x = thd->selstart.x - h; b = HT_LINE | 3; } // return px == -py || px == -py - 16;
-				else { y = thd->selstart.y + w; b = HT_LINE | 2; } // return px == -py || px == -py + 16;
+				if (d ==0) b = (x & 0xF) + (y & 0xF) >= 0x10 ? HT_LINE | HT_DIR_HL : HT_LINE | HT_DIR_HU;
+				else if (d >= 0) { x = thd->selstart.x - h; b = HT_LINE | HT_DIR_HU; } // return px == -py || px == -py - 16;
+				else { y = thd->selstart.y + w; b = HT_LINE | HT_DIR_HL; } // return px == -py || px == -py + 16;
 			} else {
 				// north
-				if (d ==0) b = (x & 0xF) > (y & 0xF) ? HT_LINE | 0 : HT_LINE | 1;
-				else if (d >= 0) { x = thd->selstart.x - h; b = HT_LINE | 1; } // return px == py || px == py - 16;
-				else { y = thd->selstart.y - w; b = HT_LINE | 0; } //return px == py || px == py + 16;
+				if (d ==0) b = (x & 0xF) > (y & 0xF) ? HT_LINE | HT_DIR_VL : HT_LINE | HT_DIR_VR;
+				else if (d >= 0) { x = thd->selstart.x - h; b = HT_LINE | HT_DIR_VR; } // return px == py || px == py - 16;
+				else { y = thd->selstart.y - w; b = HT_LINE | HT_DIR_VL; } //return px == py || px == py + 16;
 			}
 		}
 	}
@@ -1965,11 +2074,11 @@
 	thd->next_drawstyle = b;
 }
 
+// while dragging
 void VpSelectTilesWithMethod(int x, int y, int method)
 {
 	TileHighlightData *thd = _thd_ptr;
 	int sx,sy;
-
 	if (x == -1) {
 		thd->selend.x = -1;
 		return;
@@ -1977,14 +2086,14 @@
 
 	// allow drag in any rail direction
 	if (method == VPM_RAILDIRS || method == VPM_SIGNALDIRS) {
-		CalcRaildirsDrawstyle(thd, x, y);
+		thd->selend.x = x;
+		thd->selend.y = y;
+		CalcRaildirsDrawstyle(thd, x, y, method);
 		return;
 	}
 
 	if (_thd.next_drawstyle == HT_POINT) { x += 8; y += 8; }
 
-	//thd->next_drawstyle = HT_RECT;
-
 	sx = thd->selstart.x;
 	sy = thd->selstart.y;
 
@@ -2017,6 +2126,7 @@
 	thd->selend.y = y;
 }
 
+// while dragging 
 bool VpHandlePlaceSizingDrag()
 {
 	Window *w;
@@ -2027,13 +2137,14 @@
 
 	e.place.userdata = _thd.userdata;
 
+	// stop drag mode if the window has been closed
 	w = FindWindowById(_thd.window_class,_thd.window_number);
 	if (w == NULL) {
 		ResetObjectToPlace();
 		return false;
 	}
 
-	// while dragging...
+	// while dragging execute the drag procedure of the corresponding window (mostly VpSelectTilesWithMethod() )
 	if (_left_button_down) {
 		e.event = WE_PLACE_DRAG;
 		e.place.pt = GetTileBelowCursor();
@@ -2044,8 +2155,16 @@
 	// mouse button released..
 	// keep the selected tool, but reset it to the original mode.
 	_special_mouse_mode = WSM_NONE;
-	_thd.place_mode = (_thd.next_drawstyle == HT_RECT || _thd.next_drawstyle & HT_LINE) ? 1 : 2;
-
+	if (_thd.next_drawstyle == HT_RECT) 
+		_thd.place_mode = VHM_RECT;
+	else if ((e.place.userdata & 0xF) == VPM_SIGNALDIRS) // some might call this a hack... -- Dominik
+		_thd.place_mode = VHM_RECT;
+	else if (_thd.next_drawstyle & HT_LINE)
+		_thd.place_mode = VHM_RAIL;
+	else if (_thd.next_drawstyle & HT_RAIL)
+		_thd.place_mode = VHM_RAIL;
+	else
+		_thd.place_mode = VHM_POINT;
 	SetTileSelectSize(1, 1);
 
 	// and call the mouseup event.
@@ -2070,6 +2189,7 @@
 	TileHighlightData *thd = _thd_ptr;
 	Window *w;
 
+	// undo clicking on button
 	if (thd->place_mode != 0) {
 		thd->place_mode = 0;
 		w = FindWindowById(thd->window_class, thd->window_number);
@@ -2081,7 +2201,7 @@
 
 	thd->make_square_red = false;
 
-	if (mode == 4) {
+	if (mode == VHM_DRAG) { // mode 4 is for dragdropping trains in the depot window
 		mode = 0;
 		_special_mouse_mode = WSM_DRAGDROP;
 	} else {
@@ -2092,7 +2212,7 @@
 	thd->window_class = window_class;
 	thd->window_number = window_num;
 
-	if (mode == 3)
+	if (mode == VHM_SPECIAL) // special tools, like tunnels or docks start with presizing mode
 		VpStartPreSizing();
 
 	if ( (int)icon < 0)
--- a/viewport.h	Wed Jan 19 20:22:10 2005 +0000
+++ b/viewport.h	Wed Jan 19 20:55:23 2005 +0000
@@ -54,16 +54,39 @@
 	VPM_RAILDIRS = 3,
 	VPM_X_AND_Y = 4,
 	VPM_X_AND_Y_LIMITED = 5,
-	VPM_SIGNALDIRS = 6,
+	VPM_SIGNALDIRS = 6
+};
+
+// viewport highlight mode (for highlighting tiles below cursor)
+enum {
+	VHM_NONE = 0,    // default
+	VHM_RECT = 1,    // rectangle (stations, depots, ...)
+	VHM_POINT = 2,   // point (lower land, raise land, level land, ...)
+	VHM_SPECIAL = 3, // special mode used for highlighting while dragging (and for tunnels/docks)
+	VHM_DRAG = 4,    // dragging items in the depot windows
+	VHM_RAIL = 5,    // rail pieces
 };
 
 void VpSelectTilesWithMethod(int x, int y, int method);
 
+// highlighting draw styles
 enum {
 	HT_NONE = 0,
 	HT_RECT = 0x80,
 	HT_POINT = 0x40,
-	HT_LINE = 0x20,
+	HT_LINE = 0x20, /* used for autorail highlighting (longer streches)
+									 * (uses lower bits to indicate direction) */
+	HT_RAIL = 0x10, /* autorail (one piece)
+									 * (uses lower bits to indicate direction) */
+
+	/* lower bits (used with HT_LINE and HT_RAIL): 
+	 * (see ASCII art in autorail.h for a visual interpretation) */
+	HT_DIR_X = 0,  // X direction
+	HT_DIR_Y = 1,  // Y direction
+	HT_DIR_HU = 2, // horizontal upper
+	HT_DIR_HL = 3, // horizontal lower
+	HT_DIR_VL = 4, // vertical left
+	HT_DIR_VR = 5, // vertical right
 };
 
 typedef struct TileHighlightData {
@@ -81,9 +104,9 @@
 	byte dirty;
 	byte sizelimit;
 
-	byte drawstyle;
-	byte new_drawstyle;
-	byte next_drawstyle;
+	byte drawstyle;      // lower bits 0-3 are reserved for detailed highlight information information
+	byte new_drawstyle;  // only used in UpdateTileSelection() to as a buffer to compare if there was a change between old and new
+	byte next_drawstyle; // queued, but not yet drawn style
 
 	byte place_mode;
 	bool make_square_red;