diff --git a/src/citymania/cm_highlight.cpp b/src/citymania/cm_highlight.cpp index cf075287ab..b2e377803c 100644 --- a/src/citymania/cm_highlight.cpp +++ b/src/citymania/cm_highlight.cpp @@ -188,9 +188,6 @@ struct TileZoning { static TileZoning *_mz = nullptr; static IndustryType _industry_forbidden_tiles = INVALID_INDUSTRYTYPE; -extern const Station *_station_to_join; -extern const Station *_highlight_station_to_join; -extern TileArea _highlight_join_area; extern bool _fn_mod; std::set, std::greater>> _town_cache; @@ -1775,8 +1772,6 @@ static void SetStationSelectionHighlight(const TileInfo *ti, TileHighlight &th) bool draw_selection = ((_thd.drawstyle & HT_DRAG_MASK) == HT_RECT && _thd.outersize.x > 0); const Station *highlight_station = _viewport_highlight_station; - if (_highlight_station_to_join) highlight_station = _highlight_station_to_join; - if (draw_selection) { // const SpriteID pal[] = {SPR_PALETTE_ZONING_RED, SPR_PALETTE_ZONING_YELLOW, SPR_PALETTE_ZONING_LIGHT_BLUE, SPR_PALETTE_ZONING_GREEN}; // auto color = pal[(int)_station_building_status]; @@ -1819,20 +1814,6 @@ static void SetStationSelectionHighlight(const TileInfo *ti, TileHighlight &th) const SpriteID pal2[] = {PAL_NONE, CM_PALETTE_TINT_WHITE, CM_PALETTE_TINT_BLUE}; th.ground_pal = th.structure_pal = pal2[b.second]; } - - if (_highlight_join_area.tile != INVALID_TILE) { - auto b = CalcTileBorders(ti->tile, [](TileIndex t) { - return _highlight_join_area.Contains(t) ? 1 : 0; - }); - th.add_border(b.first, CM_SPR_PALETTE_ZONING_LIGHT_BLUE); - if (b.second) { - switch (th.ground_pal) { - case CM_PALETTE_TINT_WHITE: th.ground_pal = th.structure_pal = CM_PALETTE_TINT_CYAN_WHITE; break; - case CM_PALETTE_TINT_BLUE: break; - default: th.ground_pal = th.structure_pal = CM_PALETTE_TINT_CYAN; break; - } - } - } } void CalcCBAcceptanceBorders(TileHighlight &th, TileIndex tile, SpriteID border_pal, SpriteID ground_pal) { diff --git a/src/citymania/cm_station_gui.cpp b/src/citymania/cm_station_gui.cpp index 1a3b92e9be..bf627a45b8 100644 --- a/src/citymania/cm_station_gui.cpp +++ b/src/citymania/cm_station_gui.cpp @@ -37,10 +37,12 @@ #include "generated/cm_gen_commands.hpp" #include +#include #include #include #include #include +#include bool _remove_button_clicked; // replace vanilla static vars @@ -83,13 +85,20 @@ extern byte _selected_airport_layout; ///< selected airport layout numb namespace citymania { -const Station *_highlight_station_to_join = nullptr; -TileArea _highlight_join_area; - bool UseImprovedStationJoin() { return _settings_client.gui.cm_use_improved_station_join && _settings_game.station.distant_join_stations && _settings_game.station.adjacent_stations; } +namespace StationAction { + struct Create {}; + struct Join { StationID station; }; + struct Picker {}; + + using Mode = std::variant; +}; + +StationAction::Mode _station_action = StationAction::Create{}; + static const int MAX_TILE_EXTENT_LEFT = ZOOM_LVL_BASE * TILE_PIXELS; ///< Maximum left extent of tile relative to north corner. static const int MAX_TILE_EXTENT_RIGHT = ZOOM_LVL_BASE * TILE_PIXELS; ///< Maximum right extent of tile relative to north corner. static const int MAX_TILE_EXTENT_TOP = ZOOM_LVL_BASE * MAX_BUILDING_PIXELS; ///< Maximum top extent of tile relative to north corner (not considering bridges). @@ -599,8 +608,8 @@ bool IsHighlightCoverageStation(const Station *station) { void OnStationRemoved(const Station *station) { // if (_last_built_station == station) _last_built_station = nullptr; - if (StationBuildTool::station_to_join == station->index) { - StationBuildTool::station_to_join = INVALID_STATION; + if (auto mode = std::get_if(&_station_action); mode && mode->station == station->index) { + _station_action = StationAction::Create{}; UpdateActiveTool(); } if (_selected_station == station->index) { @@ -753,15 +762,25 @@ void RemoveAction::OnStationRemoved(const Station *) {} ToolGUIInfo PlacementAction::PrepareGUIInfo(std::optional ohl, up cmd, StationCoverageType sct, uint rad) { if (!cmd || !ohl.has_value()) return {}; ohl.value().UpdateTiles(); + auto palette = CM_PALETTE_TINT_WHITE; + auto area = ohl.value().GetArea(); auto cost = cmd->test(); + if (std::holds_alternative(_station_action)) { + palette = CM_PALETTE_TINT_YELLOW; + } else { + palette = cost.Succeeded() ? CM_PALETTE_TINT_WHITE : CM_PALETTE_TINT_RED_DEEP; + } bool show_coverage = _settings_client.gui.station_show_coverage; + Station *to_join = nullptr; + if (auto mode = std::get_if(&_station_action)) + to_join = Station::GetIfValid(mode->station); auto hlmap = PrepareHighilightMap( - UseImprovedStationJoin() ? Station::GetIfValid(StationBuildTool::station_to_join) : nullptr, + to_join, ohl.value(), - cost.Succeeded() ? CM_PALETTE_TINT_WHITE : CM_PALETTE_TINT_RED_DEEP, + palette, true, show_coverage, rad @@ -771,14 +790,13 @@ ToolGUIInfo PlacementAction::PrepareGUIInfo(std::optional ohl, BuildInfoOverlayData data; - if (StationBuildTool::station_to_join != INVALID_STATION) { - SetDParam(0, StationBuildTool::station_to_join); + if (auto mode = std::get_if(&_station_action)) { + SetDParam(0, mode->station); data.emplace_back(0, PAL_NONE, GetString(CM_STR_BULID_INFO_OVERLAY_JOIN_STATION)); } else { data.emplace_back(0, PAL_NONE, GetString(CM_STR_BULID_INFO_OVERLAY_NEW_STATION)); } - auto area = ohl.value().GetArea(); if (area.has_value()) { // Add supplied cargo information // TODO can we use rad_area since we already have it? @@ -881,6 +899,57 @@ ToolGUIInfo PlacementAction::PrepareGUIInfo(std::optional ohl, template void SizedPlacementAction::Update(Point, TileIndex tile) { this->cur_tile = tile; + if (UseImprovedStationJoin()) return; + + _station_action = StationAction::Create{}; + + auto area = this->GetArea(); + if (!area.has_value()) return; + auto cmdptr = this->handler.GetCommand(tile, INVALID_STATION); + auto cmd = dynamic_cast(cmdptr.get()); + if (cmd == nullptr) return; + + if (!_settings_game.station.distant_join_stations && _fn_mod) return; + + area->Expand(1); + area->ClampToMap(); + StationID to_join = INVALID_STATION; + bool ambigous_join = false; + for (auto tile : area.value()) { + if (IsTileType(tile, MP_STATION) && GetTileOwner(tile) == _local_company) { + Station *st = Station::GetByTile(tile); + if (st == nullptr || st->index == to_join) continue; + if (to_join != INVALID_STATION) { + to_join = INVALID_STATION; + if (_settings_game.station.distant_join_stations) + ambigous_join = true; + break; + } + to_join = st->index; + // TODO check for command to return multiple? but also check each to + // see if they can be built + // if (this->GetCommand(true, st->index)->test().Succeeded()) { + // if (this->station_to_join != INVALID_STATION) { + // this->station_to_join = INVALID_STATION; + // this->palette = CM_PALETTE_TINT_YELLOW; + // break; + // } else this->station_to_join = st->index; + // } + } + } + + if (!_settings_game.station.distant_join_stations) return; + + if (ambigous_join) _station_action = StationAction::Picker{}; + else if (to_join != INVALID_STATION) _station_action = StationAction::Join{to_join}; + else _station_action = StationAction::Create{}; + + // cmd->station_to_join = NEW_STATION; + // cmd->adjacent = true; + + // if (StationBuildTool::station_to_join == INVALID_STATION && !cmd->test().Succeeded()) { + // StationBuildTool::ambigous_join = false; + // } } template @@ -967,12 +1036,11 @@ template void StationSelectAction::HandleMouseRelease() { // TODO station sign click if (!IsValidTile(this->cur_tile)) return; - this->selected_station = INVALID_STATION; + _station_action = StationAction::Create{}; if (IsTileType(this->cur_tile, MP_STATION)) { auto st = Station::GetByTile(this->cur_tile); - if (st) this->selected_station = st->index; + if (st) _station_action = StationAction::Join{st->index}; } - this->handler.SelectStationToJoin(this->selected_station); } template @@ -993,13 +1061,11 @@ ToolGUIInfo StationSelectAction::GetGUIInfo() { template void StationSelectAction::OnStationRemoved(const Station *station) { - if (this->selected_station == station->index) this->selected_station = INVALID_STATION; + // if (this->selected_station == station->index) this->selected_station = INVALID_STATION; } // --- StationBuildTool --- -StationID StationBuildTool::station_to_join = INVALID_STATION; - TileArea GetCommandArea(const up &cmd) { if (auto rail_cmd = dynamic_cast(cmd.get())) { auto w = rail_cmd->numtracks; @@ -1014,6 +1080,7 @@ TileArea GetCommandArea(const up &cmd) { return {dock_cmd->tile, tile_to}; } else if (auto airport_cmd = dynamic_cast(cmd.get())) { const AirportSpec *as = AirportSpec::Get(airport_cmd->airport_type); + if (as == nullptr) return {}; return {airport_cmd->tile, as->size_x, as->size_y}; } NOT_REACHED(); @@ -1026,8 +1093,8 @@ StationBuildTool::StationBuildTool() { template bool StationBuildTool::ExecuteBuildCommand(Thandler *handler, Tcallback callback, Targ arg) { - if (UseImprovedStationJoin()) { - auto cmd = handler->GetCommand(arg, StationBuildTool::station_to_join); + if (auto mode = std::get_if(&_station_action)) { + auto cmd = handler->GetCommand(arg, mode->station); return cmd ? cmd->post(callback) : false; } @@ -1073,6 +1140,14 @@ bool RailStationBuildTool::RemoveHandler::Execute(TileArea area) { return cmd->post(&CcPlaySound_CONSTRUCTION_RAIL); } +std::optional RailStationBuildTool::SizedPlacementHandler::GetArea(TileIndex tile) const { + if (!IsValidTile(tile)) return std::nullopt; + auto w = _settings_client.gui.station_numtracks; + auto h = _settings_client.gui.station_platlength; + if (_railstation.orientation == AXIS_X) std::swap(w, h); + return TileArea{tile, w, h}; +} + up RailStationBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, StationID to_join) { // TODO mostly same as DragNDropPlacement auto cmd = make_up( @@ -1084,7 +1159,7 @@ up RailStationBuildTool::SizedPlacementHandler::GetCommand(TileIndex ti _railstation.station_class, _railstation.station_type, to_join, - true + _fn_mod ); cmd->with_error(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION); return cmd; @@ -1109,7 +1184,7 @@ up RailStationBuildTool::DragNDropPlacementHandler::GetCommand(TileArea _railstation.station_class, _railstation.station_type, to_join, - true + _fn_mod ); cmd->with_error(STR_ERROR_CAN_T_BUILD_RAILROAD_STATION); return cmd; @@ -1217,7 +1292,7 @@ up RoadStopBuildTool::DragNDropPlacementHandler::GetCommand(TileArea ar _roadstop_gui_settings.roadstop_class, _roadstop_gui_settings.roadstop_type, to_join, - true + _fn_mod ); return res; @@ -1313,14 +1388,23 @@ bool DockBuildTool::RemoveHandler::Execute(TileArea area) { } // SizedPlacementHandler + +std::optional DockBuildTool::SizedPlacementHandler::GetArea(TileIndex tile) const { + if (!IsValidTile(tile)) return std::nullopt; + DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile)); + TileIndex tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile, ReverseDiagDir(dir)) : tile); + return TileArea{tile, tile_to}; +} + up DockBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, StationID to_join) { return make_up( tile, to_join, - true + _fn_mod ); } + bool DockBuildTool::SizedPlacementHandler::Execute(TileIndex tile) { return this->tool.ExecuteBuildCommand(this, &CcBuildDocks, tile); } @@ -1387,15 +1471,25 @@ bool AirportBuildTool::RemoveHandler::Execute(TileArea area) { } // SizedPlacementHandler + +std::optional AirportBuildTool::SizedPlacementHandler::GetArea(TileIndex tile) const { + if (!IsValidTile(tile)) return std::nullopt; + auto as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + if (as == nullptr) return std::nullopt; + return TileArea{tile, as->size_x, as->size_y}; +} + up AirportBuildTool::SizedPlacementHandler::GetCommand(TileIndex tile, StationID to_join) { - byte airport_type = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index)->GetIndex(); + auto as = AirportClass::Get(_selected_airport_class)->GetSpec(_selected_airport_index); + if (as == nullptr) return nullptr; + byte airport_type = as->GetIndex(); byte layout = _selected_airport_layout; auto cmd = make_up( tile, airport_type, layout, to_join, - true + _fn_mod ); cmd->with_error(STR_ERROR_CAN_T_BUILD_AIRPORT_HERE); return cmd; diff --git a/src/citymania/cm_station_gui.hpp b/src/citymania/cm_station_gui.hpp index 7da44401a5..f57cef7e54 100644 --- a/src/citymania/cm_station_gui.hpp +++ b/src/citymania/cm_station_gui.hpp @@ -95,7 +95,6 @@ public: class StationSelectHandler { public: virtual ~StationSelectHandler() = default; - virtual void SelectStationToJoin(StationID station_id) = 0; }; template concept ImplementsStationSelectHandler = std::derived_from; @@ -105,7 +104,6 @@ class StationSelectAction : public Action { private: Handler handler; TileIndex cur_tile = INVALID_TILE; - StationID selected_station = INVALID_STATION; public: StationSelectAction(const Handler &handler) : handler{handler} {} ~StationSelectAction() override = default; @@ -131,6 +129,7 @@ public: virtual bool Execute(TileIndex tile) = 0; virtual std::optional GetObjectHighlight(TileIndex tile) = 0; virtual std::pair GetCatchmentParams() = 0; + virtual std::optional GetArea(TileIndex tile) const = 0; }; template concept ImplementsSizedPlacementHandler = std::derived_from; @@ -144,7 +143,7 @@ public: SizedPlacementAction(const Handler &handler) : handler{handler} {} ~SizedPlacementAction() override = default; void Update(Point pt, TileIndex tile) override; - std::optional GetArea() const override { return std::nullopt; }; + std::optional GetArea() const override { return this->handler.GetArea(this->cur_tile); } bool HandleMousePress() override; void HandleMouseRelease() override; ToolGUIInfo GetGUIInfo() override; @@ -182,19 +181,18 @@ public: class StationBuildTool : public Tool { public: - static StationID station_to_join; + // static StationID station_to_join; + // static bool ambigous_join; class StationSelectHandler : public citymania::StationSelectHandler { public: StationBuildTool &tool; StationSelectHandler(StationBuildTool &tool) : tool(tool) {} ~StationSelectHandler() {} - void SelectStationToJoin(StationID station_id) override { this->tool.SelectStationToJoin(station_id); }; }; StationBuildTool(); ~StationBuildTool() override = default; - void SelectStationToJoin(StationID station_id) { StationBuildTool::station_to_join = station_id; }; ToolGUIInfo GetGUIInfo() override { if (!this->action) return {}; return this->action->GetGUIInfo(); @@ -228,6 +226,7 @@ private: bool Execute(TileIndex tile) override; std::optional GetObjectHighlight(TileIndex tile) override; std::pair GetCatchmentParams() override { return {this->tool.GetCatchmentParams()}; }; + std::optional GetArea(TileIndex tile) const override; }; class DragNDropPlacementHandler: public citymania::DragNDropPlacementHandler { @@ -314,6 +313,7 @@ private: bool Execute(TileIndex tile) override; std::optional GetObjectHighlight(TileIndex tile) override; std::pair GetCatchmentParams() override { return {SCT_ALL, CA_DOCK}; }; + std::optional GetArea(TileIndex tile) const override; }; public: @@ -348,6 +348,7 @@ private: bool Execute(TileIndex tile) override; std::optional GetObjectHighlight(TileIndex tile) override; std::pair GetCatchmentParams() override; + std::optional GetArea(TileIndex tile) const override; }; public: diff --git a/src/viewport.cpp b/src/viewport.cpp index b24a885abb..60bbcdabd3 100644 --- a/src/viewport.cpp +++ b/src/viewport.cpp @@ -3237,8 +3237,8 @@ static void CheckOverflow(int &test, int &other, int max, int mult) test = max; } -// static const uint X_DIRS = (1 << DIR_NE) | (1 << DIR_SW); -// static const uint Y_DIRS = (1 << DIR_SE) | (1 << DIR_NW); +static const uint X_DIRS = (1 << DIR_NE) | (1 << DIR_SW); +static const uint Y_DIRS = (1 << DIR_SE) | (1 << DIR_NW); static const uint HORZ_DIRS = (1 << DIR_W) | (1 << DIR_E); // static const uint VERT_DIRS = (1 << DIR_N) | (1 << DIR_S);