diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp index 9e9c7a2f71..aa96ac04e2 100644 --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -519,6 +519,7 @@ struct BuildRailToolbarWindow : Window { ~BuildRailToolbarWindow() { if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) SetViewportCatchmentStation(nullptr, true); + if (this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT)) SetViewportCatchmentWaypoint(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -903,6 +904,7 @@ struct BuildRailToolbarWindow : Window { void OnPlaceObjectAbort() override { if (this->IsWidgetLowered(WID_RAT_BUILD_STATION)) SetViewportCatchmentStation(nullptr, true); + if (this->IsWidgetLowered(WID_RAT_BUILD_WAYPOINT)) SetViewportCatchmentWaypoint(nullptr, true); this->RaiseButtons(); this->DisableWidget(WID_RAT_REMOVE); @@ -2467,6 +2469,11 @@ struct BuildRailWaypointWindow : PickerWindowBase { } } } + + void OnRealtimeTick(uint delta_ms) override + { + CheckRedrawWaypointCoverage(this, false); + } }; /** Nested widget definition for the build NewGRF rail waypoint window */ diff --git a/src/road_gui.cpp b/src/road_gui.cpp index 677d2024a0..3f05a050f1 100644 --- a/src/road_gui.cpp +++ b/src/road_gui.cpp @@ -379,6 +379,7 @@ struct BuildRoadToolbarWindow : Window { ~BuildRoadToolbarWindow() { if (_game_mode == GM_NORMAL && (this->IsWidgetLowered(WID_ROT_BUS_STATION) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION))) SetViewportCatchmentStation(nullptr, true); + if (_game_mode == GM_NORMAL && this->IsWidgetLowered(WID_ROT_BUILD_WAYPOINT)) SetViewportCatchmentWaypoint(nullptr, true); if (_settings_client.gui.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0, false); } @@ -690,6 +691,7 @@ struct BuildRoadToolbarWindow : Window { void OnPlaceObjectAbort() override { if (_game_mode != GM_EDITOR && (this->IsWidgetLowered(WID_ROT_BUS_STATION) || this->IsWidgetLowered(WID_ROT_TRUCK_STATION))) SetViewportCatchmentStation(nullptr, true); + if (_game_mode != GM_EDITOR && this->IsWidgetLowered(WID_ROT_BUILD_WAYPOINT)) SetViewportCatchmentWaypoint(nullptr, true); this->RaiseButtons(); this->SetWidgetDisabledState(WID_ROT_REMOVE, true); @@ -2003,6 +2005,11 @@ struct BuildRoadWaypointWindow : PickerWindowBase { } } } + + void OnRealtimeTick(uint delta_ms) override + { + CheckRedrawWaypointCoverage(this, true); + } }; /** Nested widget definition for the build NewGRF road waypoint window */ diff --git a/src/station_gui.cpp b/src/station_gui.cpp index b82f15300d..4e3b531ccb 100644 --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -56,6 +56,29 @@ enum StationRatingTooltipMode { SRTM_DETAILED, }; +template +struct IsSpecializedStationRightType { + IsSpecializedStationRightType() {} + + IsSpecializedStationRightType(const CommandContainer &cmd) {} + + bool operator()(const T*) const { return true; } +}; + +template <> +struct IsSpecializedStationRightType { + bool road_waypoint_search; + + IsSpecializedStationRightType(bool is_road) : road_waypoint_search(is_road) {} + + IsSpecializedStationRightType(const CommandContainer &cmd) + { + this->road_waypoint_search = (cmd.cmd & CMD_ID_MASK) == CMD_BUILD_ROAD_WAYPOINT; + } + + bool operator()(const Waypoint* wp) const { return HasBit(wp->waypoint_flags, WPF_ROAD) == this->road_waypoint_search; } +}; + /** * Calculates and draws the accepted or supplied cargo around the selected tile(s) * @param left x position where the string is to be drawn @@ -97,11 +120,12 @@ int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageTyp * Find stations adjacent to the current tile highlight area, so that existing coverage * area can be drawn. */ -static void FindStationsAroundSelection() +template +void FindStationsAroundSelection(IsSpecializedStationRightType is_right_type) { /* With distant join we don't know which station will be selected, so don't show any */ if (_ctrl_pressed) { - SetViewportCatchmentStation(nullptr, true); + SetViewportCatchmentSpecializedStation(nullptr, true); return; } @@ -115,13 +139,13 @@ static void FindStationsAroundSelection() int max_c = 1; TileArea ta(TileXY(std::max(0, x - max_c), std::max(0, y - max_c)), TileXY(std::min(MapMaxX(), x + location.w + max_c), std::min(MapMaxY(), y + location.h + max_c))); - Station *adjacent = nullptr; + T *adjacent = nullptr; /* Direct loop instead of ForAllStationsAroundTiles as we are not interested in catchment area */ for (TileIndex tile : ta) { if (IsTileType(tile, MP_STATION) && GetTileOwner(tile) == _local_company) { - Station *st = Station::GetByTile(tile); - if (st == nullptr) continue; + T *st = T::GetByTile(tile); + if (st == nullptr || !is_right_type(st)) continue; if (adjacent != nullptr && st != adjacent) { /* Multiple nearby, distant join is required. */ adjacent = nullptr; @@ -130,7 +154,8 @@ static void FindStationsAroundSelection() adjacent = st; } } - SetViewportCatchmentStation(adjacent, true); + + SetViewportCatchmentSpecializedStation(adjacent, true); } /** @@ -152,7 +177,25 @@ void CheckRedrawStationCoverage(Window *w) w->SetDirty(); if (_settings_client.gui.station_show_coverage && _thd.drawstyle == HT_RECT) { - FindStationsAroundSelection(); + FindStationsAroundSelection(IsSpecializedStationRightType()); + } + } +} + +void CheckRedrawWaypointCoverage(Window *w, bool is_road) +{ + /* Test if ctrl state changed */ + static bool _last_ctrl_pressed; + if (_ctrl_pressed != _last_ctrl_pressed) { + _thd.dirty = 0xff; + _last_ctrl_pressed = _ctrl_pressed; + } + + if (_thd.dirty & 1) { + _thd.dirty &= ~1; + + if (_thd.drawstyle == HT_RECT) { + FindStationsAroundSelection(IsSpecializedStationRightType(is_road)); } } } @@ -2344,10 +2387,12 @@ struct TileAndStation { static std::vector _deleted_stations_nearby; static std::vector _stations_nearby_list; -static bool _station_nearby_road_waypoint_search; -static bool IsNearbyStationRightType(const Station *st) { return true; } -static bool IsNearbyStationRightType(const Waypoint *wp) { return HasBit(wp->waypoint_flags, WPF_ROAD) == _station_nearby_road_waypoint_search; } +template +struct AddNearbyStationData { + TileArea ctx; + IsSpecializedStationRightType is_right_type; +}; /** * Add station on this tile to _stations_nearby_list if it's fully within the @@ -2359,7 +2404,8 @@ static bool IsNearbyStationRightType(const Waypoint *wp) { return HasBit(wp->way template static bool AddNearbyStation(TileIndex tile, void *user_data) { - TileArea *ctx = (TileArea *)user_data; + AddNearbyStationData *data = (AddNearbyStationData *)user_data; + TileArea *ctx = &(data->ctx); /* First check if there were deleted stations here */ for (uint i = 0; i < _deleted_stations_nearby.size(); i++) { @@ -2380,7 +2426,7 @@ static bool AddNearbyStation(TileIndex tile, void *user_data) if (!T::IsValidID(sid)) return false; T *st = T::Get(sid); - if (st->owner != _local_company || !IsNearbyStationRightType(st) || std::find(_stations_nearby_list.begin(), _stations_nearby_list.end(), sid) != _stations_nearby_list.end()) return false; + if (st->owner != _local_company || !data->is_right_type(st) || std::find(_stations_nearby_list.begin(), _stations_nearby_list.end(), sid) != _stations_nearby_list.end()) return false; if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) { _stations_nearby_list.push_back(sid); @@ -2399,9 +2445,10 @@ static bool AddNearbyStation(TileIndex tile, void *user_data) * @tparam T the type of station to look for */ template -static const T *FindStationsNearby(TileArea ta, bool distant_join) +static const T *FindStationsNearby(TileArea ta, bool distant_join, IsSpecializedStationRightType is_right_type) { - TileArea ctx = ta; + AddNearbyStationData data { ta, is_right_type }; + TileArea &ctx = data.ctx; _stations_nearby_list.clear(); _deleted_stations_nearby.clear(); @@ -2413,7 +2460,7 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join) /* Look for deleted stations */ for (const BaseStation *st : BaseStation::Iterate()) { - if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company && IsNearbyStationRightType(T::From(st))) { + if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company && is_right_type(T::From(st))) { /* Include only within station spread (yes, it is strictly less than) */ if (std::max(DistanceMax(ta.tile, st->xy), DistanceMax(TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) { _deleted_stations_nearby.push_back({st->xy, st->index}); @@ -2421,7 +2468,7 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join) /* Add the station when it's within where we're going to build */ if (IsInsideBS(TileX(st->xy), TileX(ctx.tile), ctx.w) && IsInsideBS(TileY(st->xy), TileY(ctx.tile), ctx.h)) { - AddNearbyStation(st->xy, &ctx); + AddNearbyStation(st->xy, &data); } } } @@ -2434,7 +2481,7 @@ static const T *FindStationsNearby(TileArea ta, bool distant_join) uint max_dist = distant_join ? _settings_game.station.station_spread - std::min(ta.w, ta.h) : 1; TileIndex tile = TileAddByDir(ctx.tile, DIR_N); - CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation, &ctx); + CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation, &data); return nullptr; } @@ -2568,26 +2615,25 @@ struct SelectStationWindow : Window { void OnInvalidateData(int data = 0, bool gui_scope = true) override { if (!gui_scope) return; - if (T::EXPECTED_FACIL == FACIL_WAYPOINT) _station_nearby_road_waypoint_search = (this->select_station_cmd.cmd & CMD_ID_MASK) == CMD_BUILD_ROAD_WAYPOINT; - FindStationsNearby(this->area, true); + FindStationsNearby(this->area, true, IsSpecializedStationRightType(this->select_station_cmd)); this->vscroll->SetCount((uint)_stations_nearby_list.size() + 1); this->SetDirty(); } void OnMouseOver(Point pt, int widget) override { - if (widget != WID_JS_PANEL || T::EXPECTED_FACIL == FACIL_WAYPOINT) { - SetViewportCatchmentStation(nullptr, true); + if (widget != WID_JS_PANEL) { + SetViewportCatchmentSpecializedStation(nullptr, true); return; } /* Show coverage area of station under cursor */ uint st_index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_JS_PANEL, WidgetDimensions::scaled.framerect.top); if (st_index == 0 || st_index > _stations_nearby_list.size()) { - SetViewportCatchmentStation(nullptr, true); + SetViewportCatchmentSpecializedStation(nullptr, true); } else { st_index--; - SetViewportCatchmentStation(Station::Get(_stations_nearby_list[st_index]), true); + SetViewportCatchmentSpecializedStation(T::Get(_stations_nearby_list[st_index]), true); } } }; @@ -2631,8 +2677,7 @@ static bool StationJoinerNeeded(const CommandContainer &cmd, TileArea ta) /* Test for adjacent station or station below selection. * If adjacent-stations is disabled and we are building next to a station, do not show the selection window. * but join the other station immediately. */ - if (T::EXPECTED_FACIL == FACIL_WAYPOINT) _station_nearby_road_waypoint_search = (cmd.cmd & CMD_ID_MASK) == CMD_BUILD_ROAD_WAYPOINT; - const T *st = FindStationsNearby(ta, false); + const T *st = FindStationsNearby(ta, false, IsSpecializedStationRightType(cmd)); return st == nullptr && (_settings_game.station.adjacent_stations || _stations_nearby_list.size() == 0); } diff --git a/src/station_gui.h b/src/station_gui.h index 345c99279c..cf0d1263fc 100644 --- a/src/station_gui.h +++ b/src/station_gui.h @@ -27,6 +27,7 @@ enum StationCoverageType { int DrawStationCoverageAreaText(int left, int right, int top, StationCoverageType sct, int rad, bool supplies); void CheckRedrawStationCoverage(Window *w); +void CheckRedrawWaypointCoverage(Window *w, bool is_road); void ShowSelectStationIfNeeded(const CommandContainer &cmd, TileArea ta); void ShowSelectWaypointIfNeeded(const CommandContainer &cmd, TileArea ta); diff --git a/src/viewport.cpp b/src/viewport.cpp index b03bca9af7..b5ace3deb5 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -1478,8 +1478,9 @@ enum TileHighlightType { THT_LIGHT_BLUE, }; -const Station *_viewport_highlight_station; ///< Currently selected station for coverage area highlight -const Town *_viewport_highlight_town; ///< Currently selected town for coverage area highlight +const Station *_viewport_highlight_station; ///< Currently selected station for coverage area highlight +const Waypoint *_viewport_highlight_waypoint; ///< Currently selected waypoint for coverage area highlight +const Town *_viewport_highlight_town; ///< Currently selected town for coverage area highlight const TraceRestrictProgram *_viewport_highlight_tracerestrict_program; ///< Currently selected tracerestrict program for highlight /** @@ -1493,6 +1494,9 @@ static TileHighlightType GetTileHighlightType(TileIndex t) if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_station->index) return THT_LIGHT_BLUE; if (_viewport_highlight_station->TileIsInCatchment(t)) return THT_BLUE; } + if (_viewport_highlight_waypoint != nullptr) { + if (IsTileType(t, MP_STATION) && GetStationIndex(t) == _viewport_highlight_waypoint->index) return THT_LIGHT_BLUE; + } if (_viewport_highlight_town != nullptr) { if (IsTileType(t, MP_HOUSE)) { @@ -6514,6 +6518,12 @@ static void MarkCatchmentTilesDirty() } } } + if (_viewport_highlight_waypoint != nullptr) { + if (!_viewport_highlight_waypoint->IsInUse()) { + _viewport_highlight_waypoint = nullptr; + } + MarkWholeNonMapViewportsDirty(); + } } bool CurrentlySnappingRailPlacement() @@ -6566,6 +6576,7 @@ void ResetRailPlacementSnapping() static void SetWindowDirtyForViewportCatchment() { if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index); + if (_viewport_highlight_waypoint != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint->index); if (_viewport_highlight_town != nullptr) SetWindowDirty(WC_TOWN_VIEW, _viewport_highlight_town->index); if (_viewport_highlight_tracerestrict_program != nullptr) InvalidateWindowClassesData(WC_TRACE_RESTRICT); } @@ -6574,6 +6585,7 @@ static void ClearViewportCatchment() { MarkCatchmentTilesDirty(); _viewport_highlight_station = nullptr; + _viewport_highlight_waypoint = nullptr; _viewport_highlight_town = nullptr; _viewport_highlight_tracerestrict_program = nullptr; } @@ -6598,6 +6610,26 @@ void SetViewportCatchmentStation(const Station *st, bool sel) if (_viewport_highlight_station != nullptr) SetWindowDirty(WC_STATION_VIEW, _viewport_highlight_station->index); } +/** + * Select or deselect waypoint for coverage area highlight. + * Selecting a waypoint will deselect a town. + * @param *wp Waypoint in question + * @param sel Select or deselect given waypoint + */ +void SetViewportCatchmentWaypoint(const Waypoint *wp, bool sel) +{ + SetWindowDirtyForViewportCatchment(); + if (sel && _viewport_highlight_waypoint != wp) { + ClearViewportCatchment(); + _viewport_highlight_waypoint = wp; + MarkCatchmentTilesDirty(); + } else if (!sel && _viewport_highlight_waypoint == wp) { + MarkCatchmentTilesDirty(); + _viewport_highlight_waypoint = nullptr; + } + if (_viewport_highlight_waypoint != nullptr) SetWindowDirty(WC_WAYPOINT_VIEW, _viewport_highlight_waypoint->index); +} + /** * Select or deselect town for coverage area highlight. * Selecting a town will deselect a station. diff --git a/src/viewport_func.h b/src/viewport_func.h index ebcc75b558..46db27af34 100644 --- a/src/viewport_func.h +++ b/src/viewport_func.h @@ -141,12 +141,29 @@ void ViewportMapBuildTunnelCache(); void DrawTileSelectionRect(const TileInfo *ti, PaletteID pal); void DrawSelectionSprite(SpriteID image, PaletteID pal, const TileInfo *ti, int z_offset, FoundationPart foundation_part, int extra_offs_x = 0, int extra_offs_y = 0, const SubSprite *sub = nullptr); +struct Waypoint; struct Town; struct TraceRestrictProgram; void SetViewportCatchmentStation(const Station *st, bool sel); +void SetViewportCatchmentWaypoint(const Waypoint *wp, bool sel); void SetViewportCatchmentTown(const Town *t, bool sel); void SetViewportCatchmentTraceRestrictProgram(const TraceRestrictProgram *prog, bool sel); +template +void SetViewportCatchmentSpecializedStation(const T *st, bool sel); + +template<> +inline void SetViewportCatchmentSpecializedStation(const Station *st, bool sel) +{ + SetViewportCatchmentStation(st, sel); +} + +template<> +inline void SetViewportCatchmentSpecializedStation(const Waypoint *st, bool sel) +{ + SetViewportCatchmentWaypoint(st, sel); +} + void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height, ViewportMarkDirtyFlags flags = VMDF_NONE); void MarkBridgeDirty(TileIndex tile, ViewportMarkDirtyFlags flags = VMDF_NONE); void MarkBridgeOrTunnelDirty(TileIndex tile, ViewportMarkDirtyFlags flags = VMDF_NONE);