forked from mirror/OpenTTD
(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.
This commit is contained in:
242
viewport.c
242
viewport.c
@@ -595,11 +595,7 @@ static int dbg_draw_pushed(const TileInfo *ti)
|
||||
|
||||
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 @@ static bool IsPartOfAutoLine(int px, int py)
|
||||
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 @@ static bool IsPartOfAutoLine(int px, int py)
|
||||
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 @@ static void DrawTileSelection(const TileInfo *ti)
|
||||
}
|
||||
}
|
||||
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 @@ void PlaceObject()
|
||||
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 @@ void SetTileSelectBigSize(int ox, int oy, int sx, int sy) {
|
||||
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 @@ void UpdateTileSelection()
|
||||
|
||||
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 @@ void UpdateTileSelection()
|
||||
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 @@ void UpdateTileSelection()
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ void VpStartPreSizing()
|
||||
_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?
|
||||
x = thd->selstart.x;
|
||||
b = HT_RECT;
|
||||
} else if (w > h * 2) {
|
||||
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;
|
||||
b = HT_RECT;
|
||||
} else {
|
||||
} 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;
|
||||
} else if (w > h * 2) { // still count as x dir?
|
||||
b = HT_LINE | HT_DIR_X;
|
||||
y = thd->selstart.y;
|
||||
} 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 @@ static void CalcRaildirsDrawstyle(TileHighlightData *thd, int x, int y)
|
||||
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 @@ void VpSelectTilesWithMethod(int x, int y, int method)
|
||||
|
||||
// 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 @@ void VpSelectTilesWithMethod(int x, int y, int method)
|
||||
thd->selend.y = y;
|
||||
}
|
||||
|
||||
// while dragging
|
||||
bool VpHandlePlaceSizingDrag()
|
||||
{
|
||||
Window *w;
|
||||
@@ -2027,13 +2137,14 @@ bool VpHandlePlaceSizingDrag()
|
||||
|
||||
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 @@ bool VpHandlePlaceSizingDrag()
|
||||
// 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 @@ void SetObjectToPlace(int icon, byte mode, WindowClass window_class, WindowNumbe
|
||||
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 @@ void SetObjectToPlace(int icon, byte mode, WindowClass window_class, WindowNumbe
|
||||
|
||||
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 @@ void SetObjectToPlace(int icon, byte mode, WindowClass window_class, WindowNumbe
|
||||
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)
|
||||
|
Reference in New Issue
Block a user