diff --git a/src/lang/english.txt b/src/lang/english.txt --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1586,7 +1586,9 @@ STR_RAILROAD_TRACK_WITH_PBS_NOENTRYSIGNA STR_MUST_REMOVE_RAILWAY_STATION_FIRST :{WHITE}Must remove railway station first STR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Must remove rail waypoint first STR_CREATE_SPLITTED_STATION :{YELLOW}Build a separate station +STR_CREATE_SPLITTED_WAYPOINT :{YELLOW}Build a separate waypoint STR_SELECT_STATION_TO_JOIN :{BLACK}Join station +STR_SELECT_WAYPOINT_TO_JOIN :{BLACK}Join waypoint @@ -1819,6 +1821,7 @@ STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_S STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST :{WHITE}Must demolish freight tram station first STR_STATION_LIST_CAPTION :{WHITE}{COMPANY} - {COMMA} Station{P "" s} STR_STATION_LIST_STATION :{YELLOW}{STATION} {STATIONFEATURES} +STR_STATION_LIST_WAYPOINT :{YELLOW}{WAYPOINT} STR_STATION_LIST_NONE :{YELLOW}- None - STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK :{WHITE}Too close to another dock STR_ERROR_MUST_DEMOLISH_DOCK_FIRST :{WHITE}Must demolish dock first diff --git a/src/rail_gui.cpp b/src/rail_gui.cpp --- a/src/rail_gui.cpp +++ b/src/rail_gui.cpp @@ -776,7 +776,7 @@ struct BuildRailToolbarWindow : Window { uint32 p2 = STAT_CLASS_WAYP | _cur_waypoint_type << 8 | INVALID_STATION << 16; CommandContainer cmdcont = { ta.tile, p1, p2, CMD_BUILD_RAIL_WAYPOINT | CMD_MSG(STR_CANT_BUILD_TRAIN_WAYPOINT), CcPlaySound1E, "" }; - DoCommandP(&cmdcont); + ShowSelectWaypointIfNeeded(cmdcont, ta); } } break; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -828,7 +828,7 @@ void GetStationLayout(byte *layout, int /** * Find a nearby station that joins this station. - * @param T the class to find a station for + * @tparam T the class to find a station for * @param error_message the error message when building a station on top of others * @param existing_station an existing station we build over * @param station_to_join the station to join to @@ -867,6 +867,9 @@ CommandCost FindJoiningBaseStation(Stati if (!GetStationAround(ta, existing_station, st)) return CMD_ERROR; } + /* Distant join */ + if (*st == NULL && station_to_join != INVALID_STATION) *st = T::GetIfValid(station_to_join); + return CommandCost();; } @@ -881,12 +884,7 @@ CommandCost FindJoiningBaseStation(Stati */ CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st) { - CommandCost cost = FindJoiningBaseStation(existing_station, station_to_join, adjacent, ta, st); - - /* Distant join */ - if (*st == NULL && station_to_join != INVALID_STATION) *st = Station::GetIfValid(station_to_join); - - return cost; + return FindJoiningBaseStation(existing_station, station_to_join, adjacent, ta, st); } /** @@ -1184,7 +1182,7 @@ restart: * @param affected_stations the stations affected * @param flags the command flags * @param removal_cost the cost for removing the tile - * @param T the type of station to remove + * @tparam T the type of station to remove * @return the number of cleared tiles or an error */ template @@ -1337,7 +1335,7 @@ CommandCost CmdRemoveFromRailWaypoint(Ti * Remove a rail road station/waypoint * @param st The station/waypoint to remove the rail part from * @param flags operation to perform - * @param T the type of station to remove + * @tparam T the type of station to remove * @return cost or failure of operation */ template diff --git a/src/station_gui.cpp b/src/station_gui.cpp --- a/src/station_gui.cpp +++ b/src/station_gui.cpp @@ -20,6 +20,7 @@ #include "widgets/dropdown_func.h" #include "newgrf_cargo.h" #include "station_base.h" +#include "waypoint_base.h" #include "tilehighlight_func.h" #include "core/smallmap_type.hpp" #include "company_base.h" @@ -1081,7 +1082,9 @@ static SmallVector _statio * station spread. * @param tile Tile just being checked * @param user_data Pointer to TileArea context + * @tparam T the type of station to look for */ +template static bool AddNearbyStation(TileIndex tile, void *user_data) { TileArea *ctx = (TileArea *)user_data; @@ -1102,9 +1105,9 @@ static bool AddNearbyStation(TileIndex t StationID sid = GetStationIndex(tile); /* This station is (likely) a waypoint */ - if (!Station::IsValidID(sid)) return false; + if (!T::IsValidID(sid)) return false; - Station *st = Station::Get(sid); + T *st = T::Get(sid); if (st->owner != _local_company || _stations_nearby_list.Contains(sid)) return false; if (st->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST)) { @@ -1123,8 +1126,10 @@ static bool AddNearbyStation(TileIndex t * @param h Height of the to-be-built station * @param distant_join Search for adjacent stations (false) or stations fully * within station spread + * @tparam T the type of station to look for **/ -static const Station *FindStationsNearby(TileArea ta, bool distant_join) +template +static const T *FindStationsNearby(TileArea ta, bool distant_join) { TileArea ctx = ta; @@ -1133,13 +1138,13 @@ static const Station *FindStationsNearby /* Check the inside, to return, if we sit on another station */ TILE_LOOP(t, ta.w, ta.h, ta.tile) { - if (t < MapSize() && IsTileType(t, MP_STATION) && Station::IsValidID(GetStationIndex(t))) return Station::GetByTile(t); + if (t < MapSize() && IsTileType(t, MP_STATION) && T::IsValidID(GetStationIndex(t))) return T::GetByTile(t); } /* Look for deleted stations */ const BaseStation *st; FOR_ALL_BASE_STATIONS(st) { - if (Station::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) { + if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company) { /* Include only within station spread (yes, it is strictly less than) */ if (max(DistanceMax(ta.tile, st->xy), DistanceMax(TILE_ADDXY(ta.tile, ta.w - 1, ta.h - 1), st->xy)) < _settings_game.station.station_spread) { TileAndStation *ts = _deleted_stations_nearby.Append(); @@ -1149,7 +1154,7 @@ static const Station *FindStationsNearby /* 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, &ctx); } } } @@ -1162,7 +1167,7 @@ static const Station *FindStationsNearby uint max_dist = distant_join ? _settings_game.station.station_spread - min(ta.w, ta.h) : 1; TileIndex tile = TILE_ADD(ctx.tile, TileOffsByDir(DIR_N)); - CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation, &ctx); + CircularTileSearch(&tile, max_dist, ta.w, ta.h, AddNearbyStation, &ctx); return NULL; } @@ -1198,6 +1203,11 @@ static const NWidgetPart _nested_select_ EndContainer(), }; +/** + * Window for selecting stations/waypoints to (distant) join to. + * @tparam T The type of station to join with + */ +template struct SelectStationWindow : Window { CommandContainer select_station_cmd; ///< Command to build new station TileArea area; ///< Location of new station @@ -1210,8 +1220,9 @@ struct SelectStationWindow : Window { this->vscroll.cap = 6; this->resize.step_height = 10; - FindStationsNearby(this->area, true); + FindStationsNearby(this->area, true); + this->widget[JSW_WIDGET_CAPTION].data = T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_SELECT_WAYPOINT_TO_JOIN : STR_SELECT_STATION_TO_JOIN; this->FindWindowPlacementAndResize(desc); } @@ -1223,7 +1234,7 @@ struct SelectStationWindow : Window { uint y = 17; if (this->vscroll.pos == 0) { - DrawString(3, this->widget[JSW_PANEL].right - 2, y, STR_CREATE_SPLITTED_STATION); + DrawString(3, this->widget[JSW_PANEL].right - 2, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_CREATE_SPLITTED_WAYPOINT : STR_CREATE_SPLITTED_STATION); y += 10; } @@ -1231,10 +1242,10 @@ struct SelectStationWindow : Window { /* Don't draw anything if it extends past the end of the window. */ if (i - this->vscroll.pos >= this->vscroll.cap) break; - const Station *st = Station::Get(_stations_nearby_list[i - 1]); + const T *st = T::Get(_stations_nearby_list[i - 1]); SetDParam(0, st->index); SetDParam(1, st->facilities); - DrawString(3, this->widget[JSW_PANEL].right - 2, y, STR_STATION_LIST_STATION); + DrawString(3, this->widget[JSW_PANEL].right - 2, y, T::EXPECTED_FACIL == FACIL_WAYPOINT ? STR_STATION_LIST_WAYPOINT : STR_STATION_LIST_STATION); } } @@ -1274,7 +1285,7 @@ struct SelectStationWindow : Window { virtual void OnInvalidateData(int data) { - FindStationsNearby(this->area, true); + FindStationsNearby(this->area, true); this->SetDirty(); } }; @@ -1292,8 +1303,10 @@ static const WindowDesc _select_station_ * @param cmd Command to build the station. * @param w Width of the to-be-built station * @param h Height of the to-be-built station + * @tparam T the type of station * @return whether we need to show the station selection window. */ +template static bool StationJoinerNeeded(CommandContainer cmd, TileArea ta) { /* Only show selection if distant join is enabled in the settings */ @@ -1319,23 +1332,44 @@ static bool StationJoinerNeeded(CommandC /* 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 immediatelly. */ - const Station *st = FindStationsNearby(ta, false); + const T *st = FindStationsNearby(ta, false); return st == NULL && (_settings_game.station.adjacent_stations || _stations_nearby_list.Length() == 0); } /** * Show the station selection window when needed. If not, build the station. * @param cmd Command to build the station. - * @param w Width of the to-be-built station - * @param h Height of the to-be-built station + * @param ta Area to build the station in + * @tparam the class to find stations for */ -void ShowSelectStationIfNeeded(CommandContainer cmd, TileArea ta) +template +void ShowSelectBaseStationIfNeeded(CommandContainer cmd, TileArea ta) { - if (StationJoinerNeeded(cmd, ta)) { + if (StationJoinerNeeded(cmd, ta)) { if (!_settings_client.gui.persistent_buildingtools) ResetObjectToPlace(); if (BringWindowToFrontById(WC_SELECT_STATION, 0)) return; - new SelectStationWindow(&_select_station_desc, cmd, ta); + new SelectStationWindow(&_select_station_desc, cmd, ta); } else { DoCommandP(&cmd); } } + +/** + * Show the station selection window when needed. If not, build the station. + * @param cmd Command to build the station. + * @param ta Area to build the station in + */ +void ShowSelectStationIfNeeded(CommandContainer cmd, TileArea ta) +{ + ShowSelectBaseStationIfNeeded(cmd, ta); +} + +/** + * Show the waypoint selection window when needed. If not, build the waypoint. + * @param cmd Command to build the waypoint. + * @param ta Area to build the waypoint in + */ +void ShowSelectWaypointIfNeeded(CommandContainer cmd, TileArea ta) +{ + ShowSelectBaseStationIfNeeded(cmd, ta); +} diff --git a/src/station_gui.h b/src/station_gui.h --- a/src/station_gui.h +++ b/src/station_gui.h @@ -38,5 +38,6 @@ int DrawStationCoverageAreaText(int left void CheckRedrawStationCoverage(const Window *w); void ShowSelectStationIfNeeded(CommandContainer cmd, TileArea ta); +void ShowSelectWaypointIfNeeded(CommandContainer cmd, TileArea ta); #endif /* STATION_GUI_H */ diff --git a/src/waypoint_cmd.cpp b/src/waypoint_cmd.cpp --- a/src/waypoint_cmd.cpp +++ b/src/waypoint_cmd.cpp @@ -225,8 +225,11 @@ CommandCost CmdBuildRailWaypoint(TileInd if ((axis == AXIS_X ? width : height) != 1) return CMD_ERROR; if (count == 0 || count > _settings_game.station.station_spread) return CMD_ERROR; - /* Temporary */ - if (station_to_join != INVALID_STATION) return CMD_ERROR; + bool reuse = (station_to_join != NEW_STATION); + if (!reuse) station_to_join = INVALID_STATION; + bool distant_join = (station_to_join != INVALID_STATION); + + if (distant_join && (!_settings_game.station.distant_join_stations || !Waypoint::IsValidID(station_to_join))) return CMD_ERROR; /* Make sure the area below consists of clear tiles. (OR tiles belonging to a certain rail station) */ StationID est = INVALID_STATION; @@ -246,7 +249,7 @@ CommandCost CmdBuildRailWaypoint(TileInd /* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */ TileIndex center_tile = start_tile + (count / 2) * offset; - if (wp == NULL) wp = FindDeletedWaypointCloseTo(center_tile, STR_SV_STNAME_WAYPOINT); + if (wp == NULL && reuse) wp = FindDeletedWaypointCloseTo(center_tile, STR_SV_STNAME_WAYPOINT); if (wp != NULL) { /* Reuse an existing station. */