diff --git a/data/autorail.grf b/data/autorail.grf new file mode 100644 index 0000000000..cd6fd293c2 Binary files /dev/null and b/data/autorail.grf differ diff --git a/data/openttd.grf b/data/openttd.grf index d67107ea98..6145941abb 100644 Binary files a/data/openttd.grf and b/data/openttd.grf differ diff --git a/main_gui.c b/main_gui.c index 7fb3f0df45..b0428f6903 100644 --- a/main_gui.c +++ b/main_gui.c @@ -111,7 +111,19 @@ void HandleOnEditText(WindowEvent *e) { } } -// 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; diff --git a/rail_gui.c b/rail_gui.c index 40034cb1af..2acd535830 100644 --- a/rail_gui.c +++ b/rail_gui.c @@ -232,7 +232,7 @@ static void BuildRailClick_NW(Window *w) 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_Station(Window *w) 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 @@ static void DoRailroadTrack(int mode) ); } +/* 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 @@ static int GetBestFit1x1(int x, int y) 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 @@ static void SwapSelection() thd->selend = pt; } +/* see above, residue from ludde's special autorail autocomplete + static bool Check2x1AutoRail(int mode) { TileHighlightData *thd = &_thd; @@ -474,46 +482,61 @@ static bool Check2x1AutoRail(int mode) return false; } - +*/ static void HandleAutodirPlacement() { TileHighlightData *thd = &_thd; int bit; + int dx = thd->selstart.x - (thd->selend.x&~0xF); + int dy = thd->selstart.y - (thd->selend.y&~0xF); - if (thd->drawstyle == HT_RECT) { - 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; - } - // same x coordinate - DoRailroadTrack(VPM_FIX_X); + 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 { - // 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; - } - DoRailroadTrack(VPM_FIX_Y); + 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(); + } } - } else { - DoRailroadTrack(thd->drawstyle & 1 ? 0 : 3); } } -static void HandleAutoSignalPlacement() +static void HandleAutoSignalPlacement(void) { TileHighlightData *thd = &_thd; int mode = 0; @@ -525,7 +548,7 @@ static void HandleAutoSignalPlacement() 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 @@ static void HandleAutoSignalPlacement() 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, diff --git a/spritecache.c b/spritecache.c index fae4238ead..c7f32b4f3a 100644 --- a/spritecache.c +++ b/spritecache.c @@ -883,6 +883,9 @@ static void LoadSpriteTables() 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++); diff --git a/table/autorail.h b/table/autorail.h new file mode 100644 index 0000000000..f219f1c7d8 --- /dev/null +++ b/table/autorail.h @@ -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 } +}; diff --git a/table/sprites.h b/table/sprites.h index d17d2b4b7e..88929b4d7e 100644 --- a/table/sprites.h +++ b/table/sprites.h @@ -44,7 +44,8 @@ enum Sprites { /* 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) diff --git a/viewport.c b/viewport.c index 005379ef12..f1f99067bf 100644 --- a/viewport.c +++ b/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) diff --git a/viewport.h b/viewport.h index 85652efa81..beba02b400 100644 --- a/viewport.h +++ b/viewport.h @@ -54,16 +54,39 @@ enum { 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 @@ typedef struct TileHighlightData { 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;