diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 5bee6bc806..dd40ca869b 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -415,6 +415,68 @@ static void HandleAutoSignalPlacement() } +// FIXME duplicate from road_gui.cpp +static DiagDirection TileFractCoordsToDiagDir() { + bool diag = (_tile_fract_coords.x + _tile_fract_coords.y) < 16; + if (_tile_fract_coords.x < _tile_fract_coords.y) { + return diag ? DIAGDIR_NE : DIAGDIR_SE; + } + return diag ? DIAGDIR_NW : DIAGDIR_SW; +} + +// FIXME duplicate from road_gui.cpp +static DiagDirection RoadBitsToDiagDir(RoadBits bits) { + if (bits < ROAD_SE) { + return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW; + } + return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE; +} + + +RoadBits FindRailsToConnect(TileIndex tile) { + RoadBits directed = ROAD_NONE; + RoadBits passing = ROAD_NONE; + DiagDirection ddir; + for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + TileIndex cur_tile = TileAddByDiagDir(tile, ddir); + if (!IsTileType(cur_tile, MP_RAILWAY)) continue; + if (!IsPlainRail(cur_tile)) continue; + passing |= DiagDirToRoadBits(ddir); + if (GetTrackBits(cur_tile) & DiagdirReachesTracks(ddir)) { + directed |= DiagDirToRoadBits(ddir); + } + } + // Prioritize track bits that head in this direction + if (directed != ROAD_NONE) { + return directed; + } + return passing; +} + +/* + * Selects orientation for rail object (depot) + */ +static DiagDirection AutodetectRailObjectDirection(TileIndex tile) { + RoadBits bits = FindRailsToConnect(tile); + // FIXME after this point repeats road autodetection + if (HasExactlyOneBit(bits)) + return RoadBitsToDiagDir(bits); + if (bits == ROAD_NONE) + bits = ROAD_ALL; + RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir()); + if (HasExactlyOneBit(frac_bits & bits)) + return RoadBitsToDiagDir(frac_bits & bits); + frac_bits |= MirrorRoadBits(frac_bits); + if (HasExactlyOneBit(frac_bits & bits)) + return RoadBitsToDiagDir(frac_bits & bits); + for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + if (DiagDirToRoadBits(ddir) & bits) + return ddir; + } + NOT_REACHED(); +} + + /** Rail toolbar management class. */ struct BuildRailToolbarWindow : Window { RailType railtype; ///< Rail type to build. @@ -625,6 +687,7 @@ struct BuildRailToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { + DiagDirection ddir; switch (this->last_user_action) { case WID_RAT_BUILD_NS: VpStartPlaceSizing(tile, VPM_FIX_VERTICAL | VPM_RAILDIRS, DDSP_PLACE_RAIL); @@ -652,7 +715,11 @@ struct BuildRailToolbarWindow : Window { break; case WID_RAT_BUILD_DEPOT: - DoCommandP(tile, _cur_railtype, _build_depot_direction, + ddir = _build_depot_direction; + if (ddir == DIAGDIR_NW + 1) { + ddir = AutodetectRailObjectDirection(tile); + } + DoCommandP(tile, _cur_railtype, ddir, CMD_BUILD_TRAIN_DEPOT | CMD_MSG(STR_ERROR_CAN_T_BUILD_TRAIN_DEPOT), CcRailDepot); break; @@ -1713,6 +1780,7 @@ struct BuildRailDepotWindow : public PickerWindowBase { case WID_BRAD_DEPOT_SE: case WID_BRAD_DEPOT_SW: case WID_BRAD_DEPOT_NW: + case WID_BRAD_DEPOT_AUTO: this->RaiseWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); _build_depot_direction = (DiagDirection)(widget - WID_BRAD_DEPOT_NE); this->LowerWidget(_build_depot_direction + WID_BRAD_DEPOT_NE); @@ -1731,23 +1799,24 @@ static const NWidgetPart _nested_build_depot_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_SPACER), SetMinimalSize(0, 3), - NWidget(NWID_HORIZONTAL_LTR), + NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), - EndContainer(), - EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NW), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SW), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_NE), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BRAD_DEPOT_SE), SetMinimalSize(66, 50), SetFill(0, 0), SetDataTip(0x0, STR_BUILD_DEPOT_TRAIN_ORIENTATION_TOOLTIP), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BRAD_DEPOT_AUTO), SetMinimalSize(134, 12), + SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 3), @@ -1865,7 +1934,7 @@ static void ShowBuildWaypointPicker(Window *parent) */ void InitializeRailGui() { - _build_depot_direction = DIAGDIR_NW; + _build_depot_direction = (DiagDirection)(DIAGDIR_NW + 1); } /** diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 6b9d5add03..8c44923e0b 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -11,7 +11,9 @@ #include "stdafx.h" #include "gui.h" +#include "cmd_helper.h" #include "window_gui.h" +#include "station_func.h" #include "station_gui.h" #include "terraform_gui.h" #include "viewport_func.h" @@ -208,6 +210,103 @@ void CcRoadStop(const CommandCost &result, TileIndex tile, uint32 p1, uint32 p2) } } + +static RoadBits FindRoadsToConnect(TileIndex tile) { + RoadBits bits = ROAD_NONE; + DiagDirection ddir; + // Prioritize roadbits that head in this direction + for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + TileIndex cur_tile = TileAddByDiagDir(tile, ddir); + if (GetAnyRoadBits(cur_tile, ROADTYPE_ROAD, true) & + DiagDirToRoadBits(ReverseDiagDir(ddir))) { + bits |= DiagDirToRoadBits(ddir); + } + } + if (bits != ROAD_NONE) { + return bits; + } + // Try to connect to any road passing by + for (ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + TileIndex cur_tile = TileAddByDiagDir(tile, ddir); + if (HasTileRoadType(cur_tile, ROADTYPE_ROAD) && (GetTileType(cur_tile) == MP_ROAD) && + (GetRoadTileType(cur_tile) == ROAD_TILE_NORMAL)) { + bits |= DiagDirToRoadBits(ddir); + } + } + return bits; +} + +static DiagDirection RoadBitsToDiagDir(RoadBits bits) { + if (bits < ROAD_SE) { + return bits == ROAD_NW ? DIAGDIR_NW : DIAGDIR_SW; + } + return bits == ROAD_SE ? DIAGDIR_SE : DIAGDIR_NE; +} + +static DiagDirection TileFractCoordsToDiagDir() { + bool diag = (_tile_fract_coords.x + _tile_fract_coords.y) < 16; + if (_tile_fract_coords.x < _tile_fract_coords.y) { + return diag ? DIAGDIR_NE : DIAGDIR_SE; + } + return diag ? DIAGDIR_NW : DIAGDIR_SW; +} +/* + * Selects orientation for road object (depot, terminal station) + */ +static DiagDirection AutodetectRoadObjectDirection(TileIndex tile) { + RoadBits bits = FindRoadsToConnect(tile); + if (HasExactlyOneBit(bits)) + return RoadBitsToDiagDir(bits); + if (bits == ROAD_NONE) + bits = ROAD_ALL; + RoadBits frac_bits = DiagDirToRoadBits(TileFractCoordsToDiagDir()); + if (HasExactlyOneBit(frac_bits & bits)) + return RoadBitsToDiagDir(frac_bits & bits); + frac_bits |= MirrorRoadBits(frac_bits); + if (HasExactlyOneBit(frac_bits & bits)) + return RoadBitsToDiagDir(frac_bits & bits); + for (DiagDirection ddir = DIAGDIR_BEGIN; ddir < DIAGDIR_END; ddir++) { + if (DiagDirToRoadBits(ddir) & bits) + return ddir; + } + NOT_REACHED(); +} + + +static bool CheckDriveThroughRoadStopDirection(TileArea area, RoadBits r) { + TILE_AREA_LOOP(tile, area) { + if (!HasTileRoadType(tile, ROADTYPE_ROAD)) continue; + if (GetTileType(tile) != MP_ROAD) continue; + if (GetRoadTileType(tile) != ROAD_TILE_NORMAL) continue; + if (GetRoadBits(tile, ROADTYPE_ROAD) & ~r) return false; + } + return true; +} + + +/* + * Automaticaly selects direction to use for road stop. + * @param area road stop area + * @return selected direction + */ +static DiagDirection AutodetectDriveThroughRoadStopDirection(TileArea area) { + bool se_suits, ne_suits; + + // Check which direction is available + // If both are not use SE, building will fail anyway + se_suits = CheckDriveThroughRoadStopDirection(area, ROAD_Y); + ne_suits = CheckDriveThroughRoadStopDirection(area, ROAD_X); + if (!ne_suits) return DIAGDIR_SE; + if (!se_suits) return DIAGDIR_NE; + + // Build station along the longer direction + if (area.w > area.h) return DIAGDIR_NE; + if (area.w < area.h) return DIAGDIR_SE; + + return AutodetectRoadObjectDirection(area.tile); +} + + /** * Place a new road stop. * @param start_tile First tile of the area. @@ -222,14 +321,21 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, u { uint8 ddir = _road_station_picker_orientation; SB(p2, 16, 16, INVALID_STATION); // no station to join + TileArea ta(start_tile, end_tile); if (ddir >= DIAGDIR_END) { - SetBit(p2, 1); // It's a drive-through stop. - ddir -= DIAGDIR_END; // Adjust picker result to actual direction. + if (ddir < DIAGDIR_END + 2) { + SetBit(p2, 1); // It's a drive-through stop. + ddir -= DIAGDIR_END; // Adjust picker result to actual direction. + } else if (ddir == DIAGDIR_END + 2) { + ddir = AutodetectRoadObjectDirection(start_tile); + } else if (ddir == DIAGDIR_END + 3) { + SetBit(p2, 1); // It's a drive-through stop. + ddir = AutodetectDriveThroughRoadStopDirection(ta); + } } p2 |= ddir << 6; // Set the DiagDirecion into p2 bits 6 and 7. - TileArea ta(start_tile, end_tile); CommandContainer cmdcont = { ta.tile, ta.w | ta.h << 8, p2, cmd, CcRoadStop, "" }; ShowSelectStationIfNeeded(cmdcont, ta); } @@ -497,6 +603,7 @@ struct BuildRoadToolbarWindow : Window { virtual void OnPlaceObject(Point pt, TileIndex tile) { + DiagDirection ddir; _remove_button_clicked = this->IsWidgetLowered(WID_ROT_REMOVE); _one_way_button_clicked = this->IsWidgetLowered(WID_ROT_ONE_WAY); switch (this->last_started_action) { @@ -529,7 +636,11 @@ struct BuildRoadToolbarWindow : Window { break; case WID_ROT_DEPOT: - DoCommandP(tile, _cur_roadtype << 2 | _road_depot_orientation, 0, + ddir = _road_depot_orientation; + if (ddir == DIAGDIR_NW + 1) { + ddir = AutodetectRoadObjectDirection(tile); + } + DoCommandP(tile, _cur_roadtype << 2 | ddir, 0, CMD_BUILD_ROAD_DEPOT | CMD_MSG(_road_type_infos[_cur_roadtype].err_depot), CcRoadDepot); break; @@ -903,7 +1014,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase { this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); if ( _cur_roadtype == ROADTYPE_TRAM) { this->GetWidget(WID_BROD_CAPTION)->widget_data = STR_BUILD_DEPOT_TRAM_ORIENTATION_CAPTION; - for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_NW; i++) this->GetWidget(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP; + for (int i = WID_BROD_DEPOT_NE; i <= WID_BROD_DEPOT_AUTO; i++) this->GetWidget(i)->tool_tip = STR_BUILD_DEPOT_TRAM_ORIENTATION_SELECT_TOOLTIP; } this->FinishInitNested(TRANSPORT_ROAD); @@ -923,6 +1034,7 @@ struct BuildRoadDepotWindow : public PickerWindowBase { case WID_BROD_DEPOT_NE: case WID_BROD_DEPOT_SW: case WID_BROD_DEPOT_SE: + case WID_BROD_DEPOT_AUTO: this->RaiseWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); _road_depot_orientation = (DiagDirection)(widget - WID_BROD_DEPOT_NE); this->LowerWidget(_road_depot_orientation + WID_BROD_DEPOT_NE); @@ -943,25 +1055,38 @@ static const NWidgetPart _nested_build_road_depot_widgets[] = { EndContainer(), NWidget(WWT_PANEL, COLOUR_DARK_GREEN), NWidget(NWID_SPACER), SetMinimalSize(0, 3), - NWidget(NWID_HORIZONTAL_LTR), + NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), SetFill(0, 0), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), - EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NW), SetMinimalSize(66, 50), + SetFill(0, 0), + SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(2, 0), - NWidget(NWID_VERTICAL), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), - EndContainer(), - NWidget(NWID_SPACER), SetMinimalSize(0, 2), - NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetMinimalSize(66, 50), SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), - EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_NE), SetMinimalSize(66, 50), + SetFill(0, 0), + SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), SetFill(0, 0), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SW), SetMinimalSize(66, 50), + SetFill(0, 0), + SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + EndContainer(), + NWidget(WWT_PANEL, COLOUR_GREY, WID_BROD_DEPOT_SE), SetMinimalSize(66, 50), + SetFill(0, 0), + SetDataTip(0x0, STR_BUILD_DEPOT_ROAD_ORIENTATION_SELECT_TOOLTIP), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROD_DEPOT_AUTO), SetMinimalSize(134, 12), + SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP), + NWidget(NWID_SPACER), SetMinimalSize(3, 0), SetFill(1, 0), + EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 3), EndContainer(), }; @@ -1054,6 +1179,8 @@ struct BuildRoadStationWindow : public PickerWindowBase { case WID_BROS_STATION_NW: case WID_BROS_STATION_X: case WID_BROS_STATION_Y: + case WID_BROS_STATION_AUTO: + case WID_BROS_STATION_XY_AUTO: this->RaiseWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); _road_station_picker_orientation = (DiagDirection)(widget - WID_BROS_STATION_NE); this->LowerWidget(_road_station_picker_orientation + WID_BROS_STATION_NE); @@ -1105,6 +1232,15 @@ static const NWidgetPart _nested_rv_station_picker_widgets[] = { NWidget(WWT_PANEL, COLOUR_GREY, WID_BROS_STATION_Y), SetMinimalSize(66, 50), EndContainer(), NWidget(NWID_SPACER), SetFill(1, 0), EndContainer(), + NWidget(NWID_SPACER), SetMinimalSize(0, 2), + NWidget(NWID_HORIZONTAL), SetPIP(0, 2, 0), + NWidget(NWID_SPACER), SetFill(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_STATION_AUTO), SetMinimalSize(134, 12), + SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP), + NWidget(WWT_TEXTBTN, COLOUR_GREY, WID_BROS_STATION_XY_AUTO), SetMinimalSize(66, 12), + SetDataTip(STR_STATION_BUILD_ORIENTATION_AUTO, STR_STATION_BUILD_ORIENTATION_AUTO_TOOLTIP), + NWidget(NWID_SPACER), SetFill(1, 0), + EndContainer(), NWidget(NWID_SPACER), SetMinimalSize(0, 1), NWidget(NWID_HORIZONTAL), SetPIP(2, 0, 2), NWidget(WWT_LABEL, COLOUR_DARK_GREEN, WID_BROS_INFO), SetMinimalSize(140, 14), SetDataTip(STR_STATION_BUILD_COVERAGE_AREA_TITLE, STR_NULL), @@ -1136,6 +1272,6 @@ static void ShowRVStationPicker(Window *parent, RoadStopType rs) void InitializeRoadGui() { - _road_depot_orientation = DIAGDIR_NW; - _road_station_picker_orientation = DIAGDIR_NW; + _road_depot_orientation = (DiagDirection)(DIAGDIR_NW + 1); + _road_station_picker_orientation = (DiagDirection)(DIAGDIR_END + 3); }