diff --git a/docs/landscape.html b/docs/landscape.html
index f9856b1de1..2e3d82313b 100644
--- a/docs/landscape.html
+++ b/docs/landscape.html
@@ -1032,7 +1032,7 @@
-
m6 bits 6..3: the station type (rail, airport, truck, bus, oilrig, dock, buoy, waypoint)
+ m6 bits 6..3: the station type (rail, airport, truck, bus, oilrig, dock, buoy, waypoint, road waypoint)
m6 bit 2: pbs reservation state for railway stations/waypoints
m7 bits 4..0: owner of road (road stops)
diff --git a/src/command.cpp b/src/command.cpp
index fcfff1a10f..f3274b4b4c 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -67,6 +67,7 @@ CommandProc CmdBuildTunnel;
CommandProc CmdBuildTrainDepot;
CommandProcEx CmdBuildRailWaypoint;
+CommandProc CmdBuildRoadWaypoint;
CommandProc CmdRenameWaypoint;
CommandProc CmdSetWaypointLabelHidden;
CommandProc CmdRemoveFromRailWaypoint;
@@ -316,6 +317,7 @@ static const Command _command_proc_table[] = {
DEF_CMD(CmdRemoveFromRailStation, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_FROM_RAIL_STATION
DEF_CMD(CmdConvertRail, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_CONVERT_RAIL
DEF_CMD(CmdBuildRailWaypoint, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_RAIL_WAYPOINT
+ DEF_CMD(CmdBuildRoadWaypoint, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_BUILD_ROAD_WAYPOINT
DEF_CMD(CmdRenameWaypoint, 0, CMDT_OTHER_MANAGEMENT ), // CMD_RENAME_WAYPOINT
DEF_CMD(CmdSetWaypointLabelHidden, 0, CMDT_OTHER_MANAGEMENT ), // CMD_SET_WAYPOINT_LABEL_HIDDEN
DEF_CMD(CmdRemoveFromRailWaypoint, 0, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_REMOVE_FROM_RAIL_WAYPOINT
diff --git a/src/command_type.h b/src/command_type.h
index f02980a101..9409520ef5 100644
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -251,6 +251,7 @@ enum Commands {
CMD_CONVERT_RAIL, ///< convert a rail type
CMD_BUILD_RAIL_WAYPOINT, ///< build a waypoint
+ CMD_BUILD_ROAD_WAYPOINT, ///< build a road waypoint
CMD_RENAME_WAYPOINT, ///< rename a waypoint
CMD_SET_WAYPOINT_LABEL_HIDDEN, ///< set whether waypoint label is hidden
CMD_REMOVE_FROM_RAIL_WAYPOINT, ///< remove a (rectangle of) tiles from a rail waypoint
diff --git a/src/lang/english.txt b/src/lang/english.txt
index fbc68a61f9..102f4aae6d 100644
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -3549,6 +3549,8 @@ STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOROAD :{BLACK}Build ro
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_AUTOTRAM :{BLACK}Build tramway section using the Autotram mode. Ctrl toggles build/remove for tramway construction. Shift toggles building/showing cost estimate
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT :{BLACK}Build road vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT :{BLACK}Build tram vehicle depot (for buying and servicing vehicles). Shift toggles building/showing cost estimate
+STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD_TO_WAYPOINT :{BLACK}Convert road to waypoint. Ctrl enables joining waypoints. Shift toggles building/showing cost estimate
+STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM_TO_WAYPOINT :{BLACK}Convert tram to waypoint. Ctrl enables joining waypoints. Shift toggles building/showing cost estimate
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION :{BLACK}Build bus station. Ctrl enables joining stations. Shift toggles building/showing cost estimate
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION :{BLACK}Build passenger tram station. Ctrl enables joining stations. Shift toggles building/showing cost estimate
STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY :{BLACK}Build lorry loading bay. Ctrl enables joining stations. Shift toggles building/showing cost estimate
@@ -6142,11 +6144,14 @@ STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING :{WHITE}Adjoins
STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT :{WHITE}Too close to another waypoint
STR_ERROR_CAN_T_BUILD_TRAIN_WAYPOINT :{WHITE}Can't build train waypoint here...
+STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT :{WHITE}Can't build road waypoint here...
STR_ERROR_CAN_T_POSITION_BUOY_HERE :{WHITE}Can't place buoy here...
STR_ERROR_CAN_T_CHANGE_WAYPOINT_NAME :{WHITE}Can't change waypoint name...
STR_ERROR_CAN_T_REMOVE_TRAIN_WAYPOINT :{WHITE}Can't remove train waypoint here...
+STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT :{WHITE}Can't remove road waypoint here...
STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST :{WHITE}Must remove rail waypoint first
+STR_ERROR_MUST_REMOVE_ROADWAYPOINT_FIRST :{WHITE}Must remove road waypoint first
STR_ERROR_BUOY_IN_THE_WAY :{WHITE}... buoy in the way
STR_ERROR_BUOY_IS_IN_USE :{WHITE}... buoy is in use by another company!
diff --git a/src/order_cmd.cpp b/src/order_cmd.cpp
index a16114514a..23ae7e2e57 100644
--- a/src/order_cmd.cpp
+++ b/src/order_cmd.cpp
@@ -1090,6 +1090,14 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s
break;
}
+ case VEH_ROAD: {
+ if (!(wp->facilities & FACIL_BUS_STOP) || !(wp->facilities & FACIL_TRUCK_STOP)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
+
+ CommandCost ret = CheckInfraUsageAllowed(v->type, wp->owner);
+ if (ret.Failed()) return ret;
+ break;
+ }
+
case VEH_SHIP:
if (!(wp->facilities & FACIL_DOCK)) return_cmd_error(STR_ERROR_CAN_T_ADD_ORDER);
if (wp->owner != OWNER_NONE) {
@@ -1101,9 +1109,9 @@ CommandCost CmdInsertOrderIntl(DoCommandFlag flags, Vehicle *v, VehicleOrderID s
/* Order flags can be any of the following for waypoints:
* [non-stop]
- * non-stop orders (if any) are only valid for trains */
- if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && v->type != VEH_TRAIN) return CMD_ERROR;
- if (_settings_game.order.nonstop_only && !(new_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) && v->type == VEH_TRAIN) return CMD_ERROR;
+ * non-stop orders (if any) are only valid for trains/RVs */
+ if (new_order.GetNonStopType() != ONSF_STOP_EVERYWHERE && !v->IsGroundVehicle()) return CMD_ERROR;
+ if (_settings_game.order.nonstop_only && !(new_order.GetNonStopType() & ONSF_NO_STOP_AT_INTERMEDIATE_STATIONS) && v->IsGroundVehicle()) return CMD_ERROR;
break;
}
diff --git a/src/order_gui.cpp b/src/order_gui.cpp
index ff4d02b82a..c14e7f0100 100644
--- a/src/order_gui.cpp
+++ b/src/order_gui.cpp
@@ -1130,6 +1130,15 @@ static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
return order;
}
+ /* check road waypoint */
+ if (IsRoadWaypointTile(tile) &&
+ v->type == VEH_ROAD &&
+ IsInfraTileUsageAllowed(VEH_ROAD, v->owner, tile)) {
+ order.MakeGoToWaypoint(GetStationIndex(tile));
+ if (_settings_client.gui.new_nonstop != _ctrl_pressed || _settings_game.order.nonstop_only) order.SetNonStopType(ONSF_NO_STOP_AT_ANY_STATION);
+ return order;
+ }
+
/* check buoy (no ownership) */
if (IsBuoyTile(tile) && v->type == VEH_SHIP) {
order.MakeGoToWaypoint(GetStationIndex(tile));
diff --git a/src/pathfinder/follow_track.hpp b/src/pathfinder/follow_track.hpp
index 61698f1c2a..dd42553bc5 100644
--- a/src/pathfinder/follow_track.hpp
+++ b/src/pathfinder/follow_track.hpp
@@ -228,7 +228,7 @@ protected:
/* special handling for stations */
if (IsRailTT() && HasStationTileRail(m_new_tile)) {
m_is_station = true;
- } else if (IsRoadTT() && IsRoadStopTile(m_new_tile)) {
+ } else if (IsRoadTT() && IsStationRoadStopTile(m_new_tile)) {
m_is_station = true;
}
}
diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp
index 2999a962cf..70c44a7a05 100644
--- a/src/pathfinder/npf/npf.cpp
+++ b/src/pathfinder/npf/npf.cpp
@@ -341,6 +341,7 @@ static int32 NPFRoadPathCost(AyStar *as, AyStarNode *current, OpenListNode *pare
case MP_STATION: {
cost = NPF_TILE_LENGTH;
+ if (IsRoadWaypoint(tile)) break;
const RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
if (IsDriveThroughStopTile(tile)) {
/* Increase the cost for drive-through road stops */
@@ -1131,7 +1132,7 @@ static void NPFFillWithOrderData(NPFFindStationOrTileData *fstd, const Vehicle *
if (v->type == VEH_TRAIN) {
fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_RAIL : STATION_WAYPOINT;
} else if (v->type == VEH_ROAD) {
- fstd->station_type = RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK;
+ fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? (RoadVehicle::From(v)->IsBus() ? STATION_BUS : STATION_TRUCK) : STATION_ROADWAYPOINT;
} else if (v->type == VEH_SHIP) {
fstd->station_type = v->current_order.IsType(OT_GOTO_STATION) ? STATION_DOCK : STATION_BUOY;
}
diff --git a/src/pathfinder/yapf/yapf_road.cpp b/src/pathfinder/yapf/yapf_road.cpp
index 8777a80583..38b1694586 100644
--- a/src/pathfinder/yapf/yapf_road.cpp
+++ b/src/pathfinder/yapf/yapf_road.cpp
@@ -92,6 +92,8 @@ protected:
break;
case MP_STATION: {
+ if (IsRoadWaypoint(tile)) break;
+
const RoadStop *rs = RoadStop::GetByTile(tile, GetRoadStopType(tile));
if (IsDriveThroughStopTile(tile)) {
/* Increase the cost for drive-through road stops */
@@ -270,7 +272,7 @@ protected:
TileIndex m_destTile;
TrackdirBits m_destTrackdirs;
StationID m_dest_station;
- bool m_bus;
+ StationType m_station_type;
bool m_non_artic;
public:
@@ -278,8 +280,14 @@ public:
{
if (v->current_order.IsType(OT_GOTO_STATION)) {
m_dest_station = v->current_order.GetDestination();
- m_bus = v->IsBus();
- m_destTile = CalcClosestStationTile(m_dest_station, v->tile, m_bus ? STATION_BUS : STATION_TRUCK);
+ m_station_type = v->IsBus() ? STATION_BUS : STATION_TRUCK;
+ m_destTile = CalcClosestStationTile(m_dest_station, v->tile, m_station_type);
+ m_non_artic = !v->HasArticulatedPart();
+ m_destTrackdirs = INVALID_TRACKDIR_BIT;
+ } else if (v->current_order.IsType(OT_GOTO_WAYPOINT)) {
+ m_dest_station = v->current_order.GetDestination();
+ m_station_type = STATION_ROADWAYPOINT;
+ m_destTile = CalcClosestStationTile(m_dest_station, v->tile, m_station_type);
m_non_artic = !v->HasArticulatedPart();
m_destTrackdirs = INVALID_TRACKDIR_BIT;
} else {
@@ -313,7 +321,7 @@ public:
if (m_dest_station != INVALID_STATION) {
return IsTileType(tile, MP_STATION) &&
GetStationIndex(tile) == m_dest_station &&
- (m_bus ? IsBusStop(tile) : IsTruckStop(tile)) &&
+ (m_station_type == GetStationType(tile)) &&
(m_non_artic || IsDriveThroughStopTile(tile));
}
diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp
index fdb349aa96..d7b7bdffa6 100644
--- a/src/road_cmd.cpp
+++ b/src/road_cmd.cpp
@@ -1967,7 +1967,7 @@ void DrawRoadCatenary(const TileInfo *ti)
tram = road = (GetCrossingRailAxis(ti->tile) == AXIS_Y ? ROAD_X : ROAD_Y);
}
} else if (IsTileType(ti->tile, MP_STATION)) {
- if (IsRoadStop(ti->tile)) {
+ if (IsAnyRoadStop(ti->tile)) {
if (IsDriveThroughStopTile(ti->tile)) {
Axis axis = GetRoadStopDir(ti->tile) == DIAGDIR_NE ? AXIS_X : AXIS_Y;
tram = road = (axis == AXIS_X ? ROAD_X : ROAD_Y);
@@ -2976,7 +2976,7 @@ CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
TileType tt = GetTileType(tile);
switch (tt) {
case MP_STATION:
- if (!IsRoadStop(tile)) continue;
+ if (!IsAnyRoadStop(tile)) continue;
break;
case MP_ROAD:
if (IsLevelCrossing(tile) && RoadNoLevelCrossing(to_type)) {
@@ -3036,7 +3036,7 @@ CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
}
uint num_pieces;
- if (IsRoadDepotTile(tile) || IsRoadStopTile(tile)) {
+ if (IsRoadDepotTile(tile) || IsAnyRoadStopTile(tile)) {
num_pieces = HasTileRoadType(tile, rtt) ? 2 : 0;
} else {
num_pieces = CountBits(GetAnyRoadBits(tile, rtt));
@@ -3047,7 +3047,7 @@ CommandCost CmdConvertRoad(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
if (flags & DC_EXEC) { // we can safely convert, too
/* Update the company infrastructure counters. */
- if (!IsRoadStopTile(tile) && owner == _current_company) {
+ if (!IsAnyRoadStopTile(tile) && owner == _current_company) {
ConvertRoadTypeOwner(tile, num_pieces, owner, from_type, to_type);
} else {
UpdateCompanyRoadInfrastructure(from_type, owner, -(int)num_pieces);
diff --git a/src/road_gui.cpp b/src/road_gui.cpp
index 9359e9aa8f..242ddcb975 100644
--- a/src/road_gui.cpp
+++ b/src/road_gui.cpp
@@ -32,6 +32,7 @@
#include "core/geometry_func.hpp"
#include "date_func.h"
#include "station_map.h"
+#include "waypoint_func.h"
#include "widgets/road_widget.h"
#include "table/strings.h"
@@ -197,6 +198,29 @@ static void PlaceRoadStop(TileIndex start_tile, TileIndex end_tile, uint32 p2, u
ShowSelectStationIfNeeded(cmdcont, ta);
}
+/**
+ * Place a road waypoint.
+ * @param tile Position to start dragging a waypoint.
+ */
+static void PlaceRoad_Waypoint(TileIndex tile)
+{
+ if (_remove_button_clicked) {
+ VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_REMOVE_ROAD_WAYPOINT);
+ return;
+ }
+
+ Axis axis = GetAxisForNewRoadWaypoint(tile);
+ if (IsValidAxis(axis)) {
+ /* Valid tile for waypoints */
+ VpStartPlaceSizing(tile, axis == AXIS_X ? VPM_X_LIMITED : VPM_Y_LIMITED, DDSP_BUILD_ROAD_WAYPOINT);
+ VpSetPlaceSizingLimit(_settings_game.station.station_spread);
+ } else {
+ /* Tile where we can't build rail waypoints. This is always going to fail,
+ * but provides the user with a proper error message. */
+ DoCommandP(tile, 1 | 1 << 8, INVALID_STATION << 16, CMD_BUILD_ROAD_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT));
+ }
+}
+
/**
* Callback for placing a bus station.
* @param tile Position to place the station.
@@ -309,6 +333,7 @@ struct BuildRoadToolbarWindow : Window {
bool can_build = CanBuildVehicleInfrastructure(VEH_ROAD, rtt);
this->SetWidgetsDisabledState(!can_build,
WID_ROT_DEPOT,
+ WID_ROT_BUILD_WAYPOINT,
WID_ROT_BUS_STATION,
WID_ROT_TRUCK_STATION,
WIDGET_LIST_END);
@@ -322,10 +347,12 @@ struct BuildRoadToolbarWindow : Window {
if (!can_build) {
/* Show in the tooltip why this button is disabled. */
this->GetWidget(WID_ROT_DEPOT)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
+ this->GetWidget(WID_ROT_BUILD_WAYPOINT)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
this->GetWidget(WID_ROT_BUS_STATION)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
this->GetWidget(WID_ROT_TRUCK_STATION)->SetToolTip(STR_TOOLBAR_DISABLED_NO_VEHICLE_AVAILABLE);
} else {
this->GetWidget(WID_ROT_DEPOT)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT : STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT);
+ this->GetWidget(WID_ROT_BUILD_WAYPOINT)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD_TO_WAYPOINT : STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM_TO_WAYPOINT);
this->GetWidget(WID_ROT_BUS_STATION)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION : STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION);
this->GetWidget(WID_ROT_TRUCK_STATION)->SetToolTip(rtt == RTT_ROAD ? STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRUCK_LOADING_BAY : STR_ROAD_TOOLBAR_TOOLTIP_BUILD_CARGO_TRAM_STATION);
}
@@ -405,6 +432,7 @@ struct BuildRoadToolbarWindow : Window {
case WID_ROT_BUS_STATION:
case WID_ROT_TRUCK_STATION:
+ case WID_ROT_BUILD_WAYPOINT:
if (RoadTypeIsRoad(this->roadtype)) this->DisableWidget(WID_ROT_ONE_WAY);
this->SetWidgetDisabledState(WID_ROT_REMOVE, !this->IsWidgetLowered(clicked_widget));
break;
@@ -465,6 +493,12 @@ struct BuildRoadToolbarWindow : Window {
}
break;
+ case WID_ROT_BUILD_WAYPOINT:
+ if (HandlePlacePushButton(this, WID_ROT_BUILD_WAYPOINT, SPR_CURSOR_WAYPOINT, HT_RECT)) {
+ this->last_started_action = widget;
+ }
+ break;
+
case WID_ROT_BUS_STATION:
if (HandlePlacePushButton(this, WID_ROT_BUS_STATION, SPR_CURSOR_BUS_STATION, HT_RECT)) {
ShowRVStationPicker(this, ROADSTOP_BUS);
@@ -554,6 +588,10 @@ struct BuildRoadToolbarWindow : Window {
CMD_BUILD_ROAD_DEPOT | CMD_MSG(this->rti->strings.err_depot), CcRoadDepot);
break;
+ case WID_ROT_BUILD_WAYPOINT:
+ PlaceRoad_Waypoint(tile);
+ break;
+
case WID_ROT_BUS_STATION:
PlaceRoad_BusStation(tile);
break;
@@ -675,6 +713,22 @@ struct BuildRoadToolbarWindow : Window {
CMD_BUILD_LONG_ROAD | CMD_MSG(this->rti->strings.err_build_road), CcPlaySound_CONSTRUCTION_OTHER);
break;
+ case DDSP_BUILD_ROAD_WAYPOINT:
+ case DDSP_REMOVE_ROAD_WAYPOINT:
+ if (this->IsWidgetLowered(WID_ROT_BUILD_WAYPOINT)) {
+ TileArea ta(start_tile, end_tile);
+ if (_remove_button_clicked) {
+ DoCommandP(ta.tile, ta.w | ta.h << 8, (1 << 2), CMD_REMOVE_ROAD_STOP | CMD_MSG(STR_ERROR_CAN_T_REMOVE_ROAD_WAYPOINT), CcPlaySound_CONSTRUCTION_OTHER);
+ } else {
+ uint32 p1 = ta.w | ta.h << 8 | _ctrl_pressed << 16 | (select_method == VPM_X_LIMITED ? AXIS_X : AXIS_Y) << 17;
+ uint32 p2 = INVALID_STATION << 16;
+
+ CommandContainer cmdcont = NewCommandContainerBasic(ta.tile, p1, p2, CMD_BUILD_ROAD_WAYPOINT | CMD_MSG(STR_ERROR_CAN_T_BUILD_ROAD_WAYPOINT), CcPlaySound_CONSTRUCTION_OTHER);
+ ShowSelectWaypointIfNeeded(cmdcont, ta);
+ }
+ }
+ break;
+
case DDSP_BUILD_BUSSTOP:
case DDSP_REMOVE_BUSSTOP:
if (this->IsWidgetLowered(WID_ROT_BUS_STATION)) {
@@ -812,6 +866,8 @@ static const NWidgetPart _nested_build_road_widgets[] = {
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_ROAD_VEHICLE_DEPOT),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_WAYPOINT),
+ SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_ROAD_TO_WAYPOINT),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_BUS_STATION),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION),
@@ -855,6 +911,8 @@ static const NWidgetPart _nested_build_tramway_widgets[] = {
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_DYNAMITE, STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_DEPOT),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_ROAD_DEPOT, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_TRAM_VEHICLE_DEPOT),
+ NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUILD_WAYPOINT),
+ SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_WAYPOINT, STR_ROAD_TOOLBAR_TOOLTIP_CONVERT_TRAM_TO_WAYPOINT),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_BUS_STATION),
SetFill(0, 1), SetMinimalSize(22, 22), SetDataTip(SPR_IMG_BUS_STATION, STR_ROAD_TOOLBAR_TOOLTIP_BUILD_PASSENGER_TRAM_STATION),
NWidget(WWT_IMGBTN, COLOUR_DARK_GREEN, WID_ROT_TRUCK_STATION),
@@ -1314,7 +1372,7 @@ static void SetDefaultRoadGui()
std::array tram_count = {};
for (TileIndex t = 0; t < MapSize(); t++) {
if (MayHaveRoad(t)) {
- if (IsTileType(t, MP_STATION) && !IsRoadStop(t)) continue;
+ if (IsTileType(t, MP_STATION) && !IsAnyRoadStop(t)) continue;
RoadType road_type = GetRoadTypeRoad(t);
if (road_type != INVALID_ROADTYPE) road_count[road_type]++;
RoadType tram_type = GetRoadTypeTram(t);
diff --git a/src/road_map.cpp b/src/road_map.cpp
index d5417e46f4..c1b784af98 100644
--- a/src/road_map.cpp
+++ b/src/road_map.cpp
@@ -44,7 +44,7 @@ RoadBits GetAnyRoadBits(TileIndex tile, RoadTramType rtt, bool straight_tunnel_b
}
case MP_STATION:
- if (!IsRoadStopTile(tile)) return ROAD_NONE;
+ if (!IsAnyRoadStopTile(tile)) return ROAD_NONE;
if (IsDriveThroughStopTile(tile)) return (GetRoadStopDir(tile) == DIAGDIR_NE) ? ROAD_X : ROAD_Y;
return DiagDirToRoadBits(GetRoadStopDir(tile));
diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp
index 711784d5b0..59efd300d7 100644
--- a/src/roadveh_cmd.cpp
+++ b/src/roadveh_cmd.cpp
@@ -1804,7 +1804,7 @@ again:
v->tile != tile) {
/* So, keep 'our' state */
dir = (Trackdir)v->state;
- } else if (IsRoadStop(v->tile)) {
+ } else if (IsStationRoadStop(v->tile)) {
/* We're not continuing our drive through road stop, so leave. */
RoadStop::GetByTile(v->tile, GetRoadStopType(v->tile))->Leave(v);
}
diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp
index db1761db1b..8913e5cfcc 100644
--- a/src/saveload/afterload.cpp
+++ b/src/saveload/afterload.cpp
@@ -1234,7 +1234,7 @@ bool AfterLoadGame()
break;
case MP_STATION:
- if (IsRoadStop(t)) SB(_me[t].m7, 6, 2, 1);
+ if (IsStationRoadStop(t)) SB(_me[t].m7, 6, 2, 1);
break;
case MP_TUNNELBRIDGE:
@@ -1288,7 +1288,7 @@ bool AfterLoadGame()
break;
case MP_STATION:
- if (!IsRoadStop(t)) break;
+ if (!IsStationRoadStop(t)) break;
if (fix_roadtypes) SB(_me[t].m7, 6, 2, (RoadTypes)GB(_m[t].m3, 0, 3));
SB(_me[t].m7, 0, 5, HasBit(_me[t].m6, 2) ? OWNER_TOWN : GetTileOwner(t));
@@ -1445,7 +1445,7 @@ bool AfterLoadGame()
has_road = true;
break;
case MP_STATION:
- has_road = IsRoadStop(t);
+ has_road = IsAnyRoadStop(t);
break;
case MP_TUNNELBRIDGE:
has_road = GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD;
@@ -1499,7 +1499,7 @@ bool AfterLoadGame()
has_road = true;
break;
case MP_STATION:
- has_road = IsRoadStop(t);
+ has_road = IsAnyRoadStop(t);
break;
case MP_TUNNELBRIDGE:
has_road = GetTunnelBridgeTransportType(t) == TRANSPORT_ROAD;
diff --git a/src/saveload/company_sl.cpp b/src/saveload/company_sl.cpp
index 93234d7c44..1a3ca65d72 100644
--- a/src/saveload/company_sl.cpp
+++ b/src/saveload/company_sl.cpp
@@ -160,7 +160,8 @@ void AfterLoadCompanyStats()
break;
case STATION_BUS:
- case STATION_TRUCK: {
+ case STATION_TRUCK:
+ case STATION_ROADWAYPOINT: {
/* Iterate all present road types as each can have a different owner. */
for (RoadTramType rtt : _roadtramtypes) {
RoadType rt = GetRoadType(tile, rtt);
diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp
index 33b1e1bce4..9936e4bd69 100644
--- a/src/saveload/extended_ver_sl.cpp
+++ b/src/saveload/extended_ver_sl.cpp
@@ -166,6 +166,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_ST_INDUSTRY_CARGO_MODE, XSCF_IGNORABLE_UNKNOWN, 1, 1, "st_industry_cargo_mode", nullptr, nullptr, nullptr },
{ XSLFI_TL_SPEED_LIMIT, XSCF_IGNORABLE_UNKNOWN, 1, 1, "tl_speed_limit", nullptr, nullptr, nullptr },
{ XSLFI_WAYPOINT_FLAGS, XSCF_NULL, 1, 1, "waypoint_flags", nullptr, nullptr, nullptr },
+ { XSLFI_ROAD_WAYPOINTS, XSCF_NULL, 1, 1, "road_waypoints", nullptr, nullptr, nullptr },
{ XSLFI_MORE_STATION_TYPES, XSCF_NULL, 1, 1, "more_station_types", nullptr, nullptr, nullptr },
{ XSLFI_SCRIPT_INT64, XSCF_NULL, 1, 1, "script_int64", nullptr, nullptr, nullptr },
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h
index ad0cfe05cf..001539950b 100644
--- a/src/saveload/extended_ver_sl.h
+++ b/src/saveload/extended_ver_sl.h
@@ -120,6 +120,7 @@ enum SlXvFeatureIndex {
XSLFI_ST_INDUSTRY_CARGO_MODE, ///< Station industry cargo mode setting
XSLFI_TL_SPEED_LIMIT, ///< Through load maximum speed setting
XSLFI_WAYPOINT_FLAGS, ///< Waypoint flags
+ XSLFI_ROAD_WAYPOINTS, ///< Road waypoints
XSLFI_MORE_STATION_TYPES, ///< More station types (field widening)
XSLFI_SCRIPT_INT64, ///< See: SLV_SCRIPT_INT64
diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp
index 81be8b1e28..7c1ed34f89 100644
--- a/src/saveload/station_sl.cpp
+++ b/src/saveload/station_sl.cpp
@@ -462,6 +462,9 @@ static const SaveLoad _waypoint_desc[] = {
SLE_CONDVAR(Waypoint, train_station.w, SLE_FILE_U8 | SLE_VAR_U16, SLV_124, SL_MAX_VERSION),
SLE_CONDVAR(Waypoint, train_station.h, SLE_FILE_U8 | SLE_VAR_U16, SLV_124, SL_MAX_VERSION),
SLE_CONDVAR_X(Waypoint, waypoint_flags, SLE_UINT16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_WAYPOINT_FLAGS)),
+ SLE_CONDVAR_X(Waypoint, road_waypoint_area.tile, SLE_UINT32, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS)),
+ SLE_CONDVAR_X(Waypoint, road_waypoint_area.w, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS)),
+ SLE_CONDVAR_X(Waypoint, road_waypoint_area.h, SLE_FILE_U8 | SLE_VAR_U16, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_ROAD_WAYPOINTS)),
};
/**
diff --git a/src/screenshot.cpp b/src/screenshot.cpp
index 874400add7..f3f2b526e2 100644
--- a/src/screenshot.cpp
+++ b/src/screenshot.cpp
@@ -1135,6 +1135,8 @@ static byte GetTopographyValue(TileIndex tile)
return MKCOLOUR(PC_WATER);
case STATION_WAYPOINT:
return MKCOLOUR(PC_GREY);
+ case STATION_ROADWAYPOINT:
+ return MKCOLOUR(PC_GREY);
default: NOT_REACHED();
}
}
@@ -1228,6 +1230,8 @@ static byte GetIndustryValue(TileIndex tile)
return MKCOLOUR(PC_BLACK);
case STATION_WAYPOINT:
return MKCOLOUR(PC_GREY);
+ case STATION_ROADWAYPOINT:
+ return MKCOLOUR(PC_GREY);
default: NOT_REACHED();
}
}
diff --git a/src/script/api/script_road.cpp b/src/script/api/script_road.cpp
index afad3a3012..8d769e1ea8 100644
--- a/src/script/api/script_road.cpp
+++ b/src/script/api/script_road.cpp
@@ -50,7 +50,7 @@
if (!::IsValidTile(tile)) return false;
if (!IsRoadTypeAvailable(GetCurrentRoadType())) return false;
- return ::IsRoadStopTile(tile) && HasBit(::GetPresentRoadTypes(tile), (::RoadType)GetCurrentRoadType());
+ return ::IsStationRoadStopTile(tile) && HasBit(::GetPresentRoadTypes(tile), (::RoadType)GetCurrentRoadType());
}
/* static */ bool ScriptRoad::IsDriveThroughRoadStationTile(TileIndex tile)
@@ -624,7 +624,7 @@ static bool NeighbourHasReachableRoad(::RoadType rt, TileIndex start_tile, DiagD
EnforcePrecondition(false, ScriptObject::GetCompany() != OWNER_DEITY);
EnforcePrecondition(false, ::IsValidTile(tile));
EnforcePrecondition(false, IsTileType(tile, MP_STATION));
- EnforcePrecondition(false, IsRoadStop(tile));
+ EnforcePrecondition(false, IsStationRoadStop(tile));
return ScriptObject::DoCommand(tile, 1 | 1 << 8, GetRoadStopType(tile), CMD_REMOVE_ROAD_STOP);
}
diff --git a/src/station.cpp b/src/station.cpp
index a99bf26bb6..d996e18db7 100644
--- a/src/station.cpp
+++ b/src/station.cpp
@@ -314,13 +314,15 @@ static uint GetTileCatchmentRadius(TileIndex tile, const Station *st)
default: NOT_REACHED();
case STATION_BUOY:
- case STATION_WAYPOINT: return CA_NONE;
+ case STATION_WAYPOINT:
+ case STATION_ROADWAYPOINT: return CA_NONE;
}
} else {
switch (GetStationType(tile)) {
default: return CA_UNMODIFIED + inc;
case STATION_BUOY:
- case STATION_WAYPOINT: return CA_NONE;
+ case STATION_WAYPOINT:
+ case STATION_ROADWAYPOINT: return CA_NONE;
}
}
}
diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
index f0a8dda687..31fea176da 100644
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -98,8 +98,8 @@ bool IsHangar(TileIndex t)
* @param st to 'return' the found station
* @return Succeeded command (if zero or one station found) or failed command (for two or more stations found).
*/
-template
-CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st)
+template
+CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID company, T **st, F filter)
{
ta.Expand(1);
@@ -107,7 +107,7 @@ CommandCost GetStationAround(TileArea ta, StationID closest_station, CompanyID c
for (TileIndex tile_cur : ta) {
if (IsTileType(tile_cur, MP_STATION)) {
StationID t = GetStationIndex(tile_cur);
- if (!T::IsValidID(t) || Station::Get(t)->owner != company) continue;
+ if (!T::IsValidID(t) || T::Get(t)->owner != company || !filter(T::Get(t))) continue;
if (closest_station == INVALID_STATION) {
closest_station = t;
} else if (closest_station != t) {
@@ -1068,13 +1068,14 @@ static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag fl
* @param flags Operation to perform.
* @param invalid_dirs Prohibited directions (set of DiagDirections).
* @param is_drive_through True if trying to build a drive-through station.
- * @param is_truck_stop True when building a truck stop, false otherwise.
+ * @param station_type Station type (bus, truck or road waypoint).
* @param axis Axis of a drive-through road stop.
* @param station StationID to be queried and returned if available.
* @param rt Road type to build.
+ * @param require_road Is existing road required.
* @return The cost in case of success, or an error code if it failed.
*/
-static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadType rt)
+CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, StationType station_type, Axis axis, StationID *station, RoadType rt, bool require_road)
{
CommandCost cost(EXPENSES_CONSTRUCTION);
int allowed_z = -1;
@@ -1097,10 +1098,10 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags
* Station points to INVALID_STATION if we can build on any station.
* Or it points to a station if we're only allowed to build on exactly that station. */
if (station != nullptr && IsTileType(cur_tile, MP_STATION)) {
- if (!IsRoadStop(cur_tile)) {
+ if (!IsAnyRoadStop(cur_tile)) {
return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
} else {
- if (is_truck_stop != IsTruckStop(cur_tile) ||
+ if (station_type != GetStationType(cur_tile) ||
is_drive_through != IsDriveThroughStopTile(cur_tile)) {
return ClearTile_Station(cur_tile, DC_AUTO); // Get error message.
}
@@ -1147,10 +1148,10 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags
}
uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_ROAD));
- if (RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
+ if (rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt) && !HasPowerOnRoad(rt, road_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
cost.AddCost(RoadBuildCost(road_rt) * (2 - num_pieces));
- } else if (RoadTypeIsRoad(rt)) {
+ } else if (rt != INVALID_ROADTYPE && RoadTypeIsRoad(rt)) {
cost.AddCost(RoadBuildCost(rt) * 2);
}
@@ -1168,12 +1169,14 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags
}
uint num_pieces = CountBits(GetRoadBits(cur_tile, RTT_TRAM));
- if (RoadTypeIsTram(rt) && !HasPowerOnRoad(rt, tram_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
+ if (rt != INVALID_ROADTYPE && RoadTypeIsTram(rt) && !HasPowerOnRoad(rt, tram_rt)) return_cmd_error(STR_ERROR_NO_SUITABLE_ROAD);
cost.AddCost(RoadBuildCost(tram_rt) * (2 - num_pieces));
- } else if (RoadTypeIsTram(rt)) {
+ } else if (rt != INVALID_ROADTYPE && RoadTypeIsTram(rt)) {
cost.AddCost(RoadBuildCost(rt) * 2);
}
+ } else if (require_road) {
+ return_cmd_error(STR_ERROR_THERE_IS_NO_ROAD);
} else {
ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
if (ret.Failed()) return ret;
@@ -1316,8 +1319,8 @@ void GetStationLayout(byte *layout, uint numtracks, uint plat_len, const Station
* @param error_message the error message when building a station on top of others
* @return command cost with the error or 'okay'
*/
-template
-CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st, StringID error_message)
+template
+CommandCost FindJoiningBaseStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, T **st, StringID error_message, F filter)
{
assert(*st == nullptr);
bool check_surrounding = true;
@@ -1331,7 +1334,8 @@ CommandCost FindJoiningBaseStation(StationID existing_station, StationID station
} else {
/* Extend the current station, and don't check whether it will
* be near any other stations. */
- *st = T::GetIfValid(existing_station);
+ T *candidate = T::GetIfValid(existing_station);
+ if (candidate != nullptr && filter(candidate)) *st = candidate;
check_surrounding = (*st == nullptr);
}
} else {
@@ -1343,7 +1347,7 @@ CommandCost FindJoiningBaseStation(StationID existing_station, StationID station
if (check_surrounding) {
/* Make sure there is no more than one other station around us that is owned by us. */
- CommandCost ret = GetStationAround(ta, existing_station, _current_company, st);
+ CommandCost ret = GetStationAround(ta, existing_station, _current_company, st, filter);
if (ret.Failed()) return ret;
}
@@ -1365,7 +1369,7 @@ CommandCost FindJoiningBaseStation(StationID existing_station, StationID station
*/
static CommandCost FindJoiningStation(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Station **st, StringID error_message = STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST)
{
- return FindJoiningBaseStation(existing_station, station_to_join, adjacent, ta, st, error_message);
+ return FindJoiningBaseStation(existing_station, station_to_join, adjacent, ta, st, error_message, [](Station *st) -> bool { return true; });
}
/**
@@ -1377,9 +1381,11 @@ static CommandCost FindJoiningStation(StationID existing_station, StationID stat
* @param wp 'return' pointer for the found waypoint
* @return command cost with the error or 'okay'
*/
-CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp)
+CommandCost FindJoiningWaypoint(StationID existing_waypoint, StationID waypoint_to_join, bool adjacent, TileArea ta, Waypoint **wp, bool is_road)
{
- return FindJoiningBaseStation(existing_waypoint, waypoint_to_join, adjacent, ta, wp, STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST);
+ return FindJoiningBaseStation(existing_waypoint, waypoint_to_join, adjacent, ta, wp,
+ is_road ? STR_ERROR_MUST_REMOVE_ROADWAYPOINT_FIRST : STR_ERROR_MUST_REMOVE_RAILWAYPOINT_FIRST,
+ [is_road](Waypoint *wp) -> bool { return HasBit(wp->waypoint_flags, WPF_ROAD) == is_road; });
}
/**
@@ -1736,6 +1742,16 @@ static void MakeShipStationAreaSmaller(Station *st)
UpdateStationDockingTiles(st);
}
+static bool TileBelongsToRoadWaypointStation(BaseStation *st, TileIndex tile)
+{
+ return IsRoadWaypointTile(tile) && GetStationIndex(tile) == st->index;
+}
+
+void MakeRoadWaypointStationAreaSmaller(BaseStation *st, TileArea &road_waypoint_area)
+{
+ road_waypoint_area = MakeStationAreaSmaller(st, road_waypoint_area, TileBelongsToRoadWaypointStation);
+}
+
/**
* Remove a number of tiles from any rail station within the area.
* @param ta the area to clear station tile from.
@@ -2004,7 +2020,7 @@ static RoadStop **FindRoadStopSpot(bool truck_station, Station *st)
}
}
-static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags);
+CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags);
/**
* Find a nearby station that joins this road stop.
@@ -2017,7 +2033,7 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags);
*/
static CommandCost FindJoiningRoadStop(StationID existing_stop, StationID station_to_join, bool adjacent, TileArea ta, Station **st)
{
- return FindJoiningBaseStation(existing_stop, station_to_join, adjacent, ta, st, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST);
+ return FindJoiningBaseStation(existing_stop, station_to_join, adjacent, ta, st, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST, [](Station *st) -> bool { return true; });
}
/**
@@ -2082,7 +2098,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
/* Total road stop cost. */
CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[type ? PR_BUILD_STATION_TRUCK : PR_BUILD_STATION_BUS]);
StationID est = INVALID_STATION;
- ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type, axis, &est, rt);
+ ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << axis : 1 << ddir, is_drive_through, type ? STATION_TRUCK : STATION_BUS, axis, &est, rt, false);
if (ret.Failed()) return ret;
cost.AddCost(ret);
@@ -2106,7 +2122,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
Owner tram_owner = tram_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_TRAM) : _current_company;
DisallowedRoadDirections drd = IsNormalRoadTile(cur_tile) ? GetDisallowedRoadDirections(cur_tile) : DRD_NONE;
- if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) {
+ if (IsTileType(cur_tile, MP_STATION) && IsAnyRoadStop(cur_tile)) {
RemoveRoadStop(cur_tile, flags);
}
@@ -2141,7 +2157,7 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
UpdateCompanyRoadInfrastructure(road_rt, road_owner, ROAD_STOP_TRACKBIT_FACTOR);
UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, ROAD_STOP_TRACKBIT_FACTOR);
- MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, rs_type, road_rt, tram_rt, axis);
+ MakeDriveThroughRoadStop(cur_tile, st->owner, road_owner, tram_owner, st->index, (rs_type == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), road_rt, tram_rt, axis);
SetDriveThroughStopDisallowedRoadDirections(cur_tile, drd);
road_stop->MakeDriveThrough();
} else {
@@ -2154,10 +2170,10 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin
Company::Get(st->owner)->infrastructure.station++;
MarkTileDirtyByTile(cur_tile);
+ UpdateRoadCachedOneWayStatesAroundTile(cur_tile);
}
ZoningMarkDirtyStationCoverageArea(st);
NotifyRoadLayoutChanged(true);
- UpdateRoadCachedOneWayStatesAroundTile(tile);
if (st != nullptr) {
st->AfterStationTileSetChange(true, type ? STATION_TRUCK: STATION_BUS);
@@ -2181,6 +2197,52 @@ static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
return nullptr;
}
+CommandCost RemoveRoadWaypointStop(TileIndex tile, DoCommandFlag flags)
+{
+ Waypoint *wp = Waypoint::GetByTile(tile);
+
+ if (_current_company != OWNER_WATER) {
+ CommandCost ret = CheckOwnership(wp->owner);
+ if (ret.Failed()) return ret;
+ }
+
+ /* don't do the check for drive-through road stops when company bankrupts */
+ if (!(flags & DC_BANKRUPT)) {
+ CommandCost ret = EnsureNoVehicleOnGround(tile);
+ if (ret.Failed()) return ret;
+ }
+
+ if (flags & DC_EXEC) {
+ /* Update company infrastructure counts. */
+ for (RoadTramType rtt : _roadtramtypes) {
+ RoadType rt = GetRoadType(tile, rtt);
+ UpdateCompanyRoadInfrastructure(rt, GetRoadOwner(tile, rtt), -static_cast(ROAD_STOP_TRACKBIT_FACTOR));
+ }
+
+ Company::Get(wp->owner)->infrastructure.station--;
+ DirtyCompanyInfrastructureWindows(wp->owner);
+
+ DoClearSquare(tile);
+
+ wp->rect.AfterRemoveTile(wp, tile);
+
+ MakeRoadWaypointStationAreaSmaller(wp, wp->road_waypoint_area);
+
+ UpdateStationSignCoord(wp);
+
+ /* if we deleted the whole waypoint, delete the road facility. */
+ if (wp->road_waypoint_area.tile == INVALID_TILE) {
+ wp->facilities &= ~(FACIL_BUS_STOP | FACIL_TRUCK_STOP);
+ SetWindowWidgetDirty(WC_STATION_VIEW, wp->index, WID_SV_ROADVEHS);
+ wp->UpdateVirtCoord();
+ DeleteStationIfEmpty(wp);
+ }
+
+ NotifyRoadLayoutChanged(false);
+ }
+
+ return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_CLEAR_STATION_TRUCK]);
+}
/**
* Remove a bus station/truck stop
@@ -2188,8 +2250,12 @@ static Vehicle *ClearRoadStopStatusEnum(Vehicle *v, void *)
* @param flags operation to perform
* @return cost or failure of operation
*/
-static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
+CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
{
+ if (IsRoadWaypoint(tile)) {
+ return RemoveRoadWaypointStop(tile, flags);
+ }
+
Station *st = Station::GetByTile(tile);
if (_current_company != OWNER_WATER) {
@@ -2289,6 +2355,7 @@ static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags)
* bit 8..15: Height of the removal area.
* @param p2 bit 0: 0 For bus stops, 1 for truck stops.
* @param p2 bit 1: 0 to keep roads of all drive-through stops, 1 to remove them.
+ * @param p2 bit 2: 0 for bus/truck stops, 1 for road waypoints.
* @param text Unused.
* @return The cost of this operation or an error.
*/
@@ -2296,7 +2363,7 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
{
uint8 width = (uint8)GB(p1, 0, 8);
uint8 height = (uint8)GB(p1, 8, 8);
- bool keep_drive_through_roads = !HasBit(p2, 1);
+ bool keep_drive_through_roads = !HasBit(p2, 1) || HasBit(p2, 2);
/* Check for incorrect width / height. */
if (width == 0 || height == 0) return CMD_ERROR;
@@ -2312,8 +2379,13 @@ CommandCost CmdRemoveRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, ui
bool had_success = false;
for (TileIndex cur_tile : roadstop_area) {
- /* Make sure the specified tile is a road stop of the correct type */
- if (!IsTileType(cur_tile, MP_STATION) || !IsRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue;
+ if (HasBit(p2, 2)) {
+ /* Make sure the specified tile is a road waypoint */
+ if (!IsTileType(cur_tile, MP_STATION) || !IsRoadWaypoint(cur_tile)) continue;
+ } else {
+ /* Make sure the specified tile is a road stop of the correct type */
+ if (!IsTileType(cur_tile, MP_STATION) || !IsStationRoadStop(cur_tile) || (uint32)GetRoadStopType(cur_tile) != GB(p2, 0, 1)) continue;
+ }
/* Save information on to-be-restored roads before the stop is removed. */
RoadBits road_bits = ROAD_NONE;
@@ -3336,7 +3408,7 @@ draw_default_foundation:
if (HasStationRail(ti->tile) && HasRailCatenaryDrawn(GetRailType(ti->tile))) DrawRailCatenary(ti);
- if (IsRoadStop(ti->tile)) {
+ if (IsAnyRoadStop(ti->tile)) {
RoadType road_rt = GetRoadTypeRoad(ti->tile);
RoadType tram_rt = GetRoadTypeTram(ti->tile);
const RoadTypeInfo* road_rti = road_rt == INVALID_ROADTYPE ? nullptr : GetRoadTypeInfo(road_rt);
@@ -3441,7 +3513,7 @@ static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
{
td->owner[0] = GetTileOwner(tile);
- if (IsRoadStopTile(tile)) {
+ if (IsAnyRoadStopTile(tile)) {
RoadType road_rt = GetRoadTypeRoad(tile);
RoadType tram_rt = GetRoadTypeTram(tile);
Owner road_owner = INVALID_OWNER;
@@ -3535,6 +3607,7 @@ static void GetTileDesc_Station(TileIndex tile, TileDesc *td)
case STATION_DOCK: str = STR_LAI_STATION_DESCRIPTION_SHIP_DOCK; break;
case STATION_BUOY: str = STR_LAI_STATION_DESCRIPTION_BUOY; break;
case STATION_WAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break;
+ case STATION_ROADWAYPOINT: str = STR_LAI_STATION_DESCRIPTION_WAYPOINT; break;
}
td->str = str;
}
@@ -3564,7 +3637,7 @@ static TrackStatus GetTileTrackStatus_Station(TileIndex tile, TransportType mode
break;
case TRANSPORT_ROAD:
- if (IsRoadStop(tile)) {
+ if (IsAnyRoadStop(tile)) {
RoadTramType rtt = (RoadTramType)sub_mode;
if (!HasTileRoadType(tile, rtt)) break;
@@ -3733,7 +3806,7 @@ static VehicleEnterTileStatus VehicleEnter_Station(Vehicle *v, TileIndex tile, i
} else if (v->type == VEH_ROAD) {
RoadVehicle *rv = RoadVehicle::From(v);
if (rv->state < RVSB_IN_ROAD_STOP && !IsReversingRoadTrackdir((Trackdir)rv->state) && rv->frame == 0) {
- if (IsRoadStop(tile) && rv->IsFrontEngine()) {
+ if (IsStationRoadStop(tile) && rv->IsFrontEngine()) {
/* Attempt to allocate a parking bay in a road stop */
return RoadStop::GetByTile(tile, GetRoadStopType(tile))->Enter(rv) ? VETSB_CONTINUE : VETSB_CANNOT_ENTER;
}
@@ -4712,7 +4785,7 @@ void DeleteOilRig(TileIndex tile)
static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_owner)
{
- if (IsRoadStopTile(tile)) {
+ if (IsAnyRoadStopTile(tile)) {
for (RoadTramType rtt : _roadtramtypes) {
/* Update all roadtypes, no matter if they are present */
if (GetRoadOwner(tile, rtt) == old_owner) {
@@ -4749,6 +4822,7 @@ static void ChangeTileOwner_Station(TileIndex tile, Owner old_owner, Owner new_o
case STATION_BUS:
case STATION_TRUCK:
+ case STATION_ROADWAYPOINT:
/* Road stops were already handled above. */
break;
@@ -4839,6 +4913,7 @@ CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
default: break;
case STATION_RAIL: return_cmd_error(STR_ERROR_MUST_DEMOLISH_RAILROAD);
case STATION_WAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
+ case STATION_ROADWAYPOINT: return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
case STATION_AIRPORT: return_cmd_error(STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST);
case STATION_TRUCK: return_cmd_error(HasTileRoadType(tile, RTT_TRAM) ? STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST);
case STATION_BUS: return_cmd_error(HasTileRoadType(tile, RTT_TRAM) ? STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST : STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST);
@@ -4866,6 +4941,11 @@ CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags)
return RemoveRoadStopAndUpdateRoadCachedOneWayState(tile, flags);
case STATION_BUOY: return RemoveBuoy(tile, flags);
case STATION_DOCK: return RemoveDock(tile, flags);
+ case STATION_ROADWAYPOINT:
+ if (IsDriveThroughStopTile(tile) && !CanRemoveRoadWithStop(tile, flags)) {
+ return_cmd_error(STR_ERROR_BUILDING_MUST_BE_DEMOLISHED);
+ }
+ return RemoveRoadStopAndUpdateRoadCachedOneWayState(tile, flags);
default: break;
}
@@ -4892,7 +4972,8 @@ static CommandCost TerraformTile_Station(TileIndex tile, DoCommandFlag flags, in
return CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_FOUNDATION]);
case STATION_TRUCK:
- case STATION_BUS: {
+ case STATION_BUS:
+ case STATION_ROADWAYPOINT: {
DiagDirection direction = GetRoadStopDir(tile);
if (!AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, direction)) break;
if (IsDriveThroughStopTile(tile)) {
diff --git a/src/station_gui.cpp b/src/station_gui.cpp
index 541cdb0984..8b1c90fdb3 100644
--- a/src/station_gui.cpp
+++ b/src/station_gui.cpp
@@ -2326,6 +2326,10 @@ 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; }
/**
* Add station on this tile to _stations_nearby_list if it's fully within the
@@ -2358,7 +2362,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 || std::find(_stations_nearby_list.begin(), _stations_nearby_list.end(), sid) != _stations_nearby_list.end()) return false;
+ 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->rect.BeforeAddRect(ctx->tile, ctx->w, ctx->h, StationRect::ADD_TEST).Succeeded()) {
_stations_nearby_list.push_back(sid);
@@ -2391,7 +2395,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) {
+ if (T::IsExpected(st) && !st->IsInUse() && st->owner == _local_company && IsNearbyStationRightType(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});
@@ -2546,6 +2550,7 @@ 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);
this->vscroll->SetCount((uint)_stations_nearby_list.size() + 1);
this->SetDirty();
@@ -2608,6 +2613,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);
return st == nullptr && (_settings_game.station.adjacent_stations || _stations_nearby_list.size() == 0);
}
diff --git a/src/station_map.h b/src/station_map.h
index e53db5fd5d..98ef3236e3 100644
--- a/src/station_map.h
+++ b/src/station_map.h
@@ -193,13 +193,34 @@ static inline bool IsBusStop(TileIndex t)
return GetStationType(t) == STATION_BUS;
}
+/**
+ * Is the station at \a t a road waypoint?
+ * @param t Tile to check
+ * @pre IsTileType(t, MP_STATION)
+ * @return \c true if station is a road waypoint, \c false otherwise
+ */
+static inline bool IsRoadWaypoint(TileIndex t)
+{
+ return GetStationType(t) == STATION_ROADWAYPOINT;
+}
+
+/**
+ * Is this tile a station tile and a road waypoint?
+ * @param t the tile to get the information from
+ * @return true if and only if the tile is a road waypoint
+ */
+static inline bool IsRoadWaypointTile(TileIndex t)
+{
+ return IsTileType(t, MP_STATION) && IsRoadWaypoint(t);
+}
+
/**
* Is the station at \a t a road station?
* @param t Tile to check
* @pre IsTileType(t, MP_STATION)
- * @return \c true if station at the tile is a bus top or a truck stop, \c false otherwise
+ * @return \c true if station at the tile is a bus stop, truck stop \c false otherwise
*/
-static inline bool IsRoadStop(TileIndex t)
+static inline bool IsStationRoadStop(TileIndex t)
{
assert_tile(IsTileType(t, MP_STATION), t);
return IsTruckStop(t) || IsBusStop(t);
@@ -210,9 +231,31 @@ static inline bool IsRoadStop(TileIndex t)
* @param t Tile to check
* @return \c true if the tile is a station tile and a road stop
*/
-static inline bool IsRoadStopTile(TileIndex t)
+static inline bool IsStationRoadStopTile(TileIndex t)
+{
+ return IsTileType(t, MP_STATION) && IsStationRoadStop(t);
+}
+
+/**
+ * Is the station at \a t a road station?
+ * @param t Tile to check
+ * @pre IsTileType(t, MP_STATION)
+ * @return \c true if station at the tile is a bus stop, truck stop or road waypoint, \c false otherwise
+ */
+static inline bool IsAnyRoadStop(TileIndex t)
+{
+ assert_tile(IsTileType(t, MP_STATION), t);
+ return IsTruckStop(t) || IsBusStop(t) || IsRoadWaypoint(t);
+}
+
+/**
+ * Is tile \a t a road stop station?
+ * @param t Tile to check
+ * @return \c true if the tile is a station tile and a road stop
+ */
+static inline bool IsAnyRoadStopTile(TileIndex t)
{
- return IsTileType(t, MP_STATION) && IsRoadStop(t);
+ return IsTileType(t, MP_STATION) && IsAnyRoadStop(t);
}
/**
@@ -222,7 +265,7 @@ static inline bool IsRoadStopTile(TileIndex t)
*/
static inline bool IsStandardRoadStopTile(TileIndex t)
{
- return IsRoadStopTile(t) && GetStationGfx(t) < GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET;
+ return IsAnyRoadStopTile(t) && GetStationGfx(t) < GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET;
}
/**
@@ -232,7 +275,7 @@ static inline bool IsStandardRoadStopTile(TileIndex t)
*/
static inline bool IsDriveThroughStopTile(TileIndex t)
{
- return IsRoadStopTile(t) && GetStationGfx(t) >= GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET;
+ return IsAnyRoadStopTile(t) && GetStationGfx(t) >= GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET;
}
/**
@@ -274,13 +317,13 @@ static inline StationGfx GetAirportGfx(TileIndex t)
/**
* Gets the direction the road stop entrance points towards.
* @param t the tile of the road stop
- * @pre IsRoadStopTile(t)
+ * @pre IsAnyRoadStopTile(t)
* @return the direction of the entrance
*/
static inline DiagDirection GetRoadStopDir(TileIndex t)
{
StationGfx gfx = GetStationGfx(t);
- assert_tile(IsRoadStopTile(t), t);
+ assert_tile(IsAnyRoadStopTile(t), t);
if (gfx < GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET) {
return (DiagDirection)(gfx);
} else {
@@ -630,9 +673,9 @@ static inline void MakeRoadStop(TileIndex t, Owner o, StationID sid, RoadStopTyp
* @param tram_rt the tram roadtype on this tile
* @param a the direction of the roadstop
*/
-static inline void MakeDriveThroughRoadStop(TileIndex t, Owner station, Owner road, Owner tram, StationID sid, RoadStopType rst, RoadType road_rt, RoadType tram_rt, Axis a)
+static inline void MakeDriveThroughRoadStop(TileIndex t, Owner station, Owner road, Owner tram, StationID sid, StationType rst, RoadType road_rt, RoadType tram_rt, Axis a)
{
- MakeStation(t, station, sid, (rst == ROADSTOP_BUS ? STATION_BUS : STATION_TRUCK), GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET + a);
+ MakeStation(t, station, sid, rst, GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET + a);
SetRoadTypes(t, road_rt, tram_rt);
SetRoadOwner(t, RTT_ROAD, road);
SetRoadOwner(t, RTT_TRAM, tram);
diff --git a/src/station_type.h b/src/station_type.h
index 2753e3adbb..84309897ca 100644
--- a/src/station_type.h
+++ b/src/station_type.h
@@ -41,6 +41,7 @@ enum StationType {
STATION_DOCK,
STATION_BUOY,
STATION_WAYPOINT,
+ STATION_ROADWAYPOINT,
};
/** Types of RoadStops */
diff --git a/src/table/newgrf_debug_data.h b/src/table/newgrf_debug_data.h
index 05d11d3dfe..9a1003567d 100644
--- a/src/table/newgrf_debug_data.h
+++ b/src/table/newgrf_debug_data.h
@@ -16,6 +16,7 @@
#include "../ship.h"
#include "../aircraft.h"
#include "../object_map.h"
+#include "../waypoint_base.h"
#include "../string_func_extra.h"
/* Helper for filling property tables */
@@ -1269,6 +1270,27 @@ class NIHStationStruct : public NIHelper {
seprintf(buffer, lastof(buffer), " Docking tiles: %X, %u x %u", st->docking_station.tile, st->docking_station.w, st->docking_station.h);
output.print(buffer);
}
+ const Waypoint *wp = Waypoint::GetIfValid(index);
+ if (wp) {
+ output.register_next_line_click_flag_toggle(1);
+ seprintf(buffer, lastof(buffer), " [%c] flags: 0x%X", output.flags & 1 ? '-' : '+', wp->waypoint_flags);
+ output.print(buffer);
+ if (output.flags & 1) {
+ auto print = [&](const char *name) {
+ seprintf(buffer, lastof(buffer), " %s", name);
+ output.print(buffer);
+ };
+ auto check_flag = [&](WaypointFlags flag, const char *name) {
+ if (HasBit(wp->waypoint_flags, flag)) print(name);
+ };
+ check_flag(WPF_HIDE_LABEL, "WPF_HIDE_LABEL");
+ check_flag(WPF_ROAD, "WPF_ROAD");
+ }
+
+ seprintf(buffer, lastof(buffer), " road_waypoint_area: tile: %X (%u x %u), width: %u, height: %u",
+ wp->road_waypoint_area.tile, TileX(wp->road_waypoint_area.tile), TileY(wp->road_waypoint_area.tile), wp->road_waypoint_area.w, wp->road_waypoint_area.h);
+ output.print(buffer);
+ }
}
};
diff --git a/src/table/station_land.h b/src/table/station_land.h
index 53a69e1e21..8b98505ee5 100644
--- a/src/table/station_land.h
+++ b/src/table/station_land.h
@@ -955,6 +955,15 @@ static const DrawTileSprites _station_display_datas_bus[] = {
TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0171)
};
+static const DrawTileSprites _station_display_datas_road_waypoint[] = {
+ TILE_SPRITE_LINE(SPR_BUS_STOP_NE_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_71)
+ TILE_SPRITE_LINE(SPR_BUS_STOP_SE_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_72)
+ TILE_SPRITE_LINE(SPR_BUS_STOP_SW_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_73)
+ TILE_SPRITE_LINE(SPR_BUS_STOP_NW_GROUND | (1U << PALETTE_MODIFIER_COLOUR), _station_display_datas_74)
+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_X, _station_display_datas_0170)
+ TILE_SPRITE_LINE(SPR_ROAD_PAVED_STRAIGHT_Y, _station_display_datas_0171)
+};
+
static const DrawTileSprites _station_display_datas_oilrig[] = {
TILE_SPRITE_LINE(SPR_FLAT_WATER_TILE, _station_display_nothing)
};
@@ -999,4 +1008,5 @@ static const DrawTileSprites * const _station_display_datas[] = {
_station_display_datas_dock,
_station_display_datas_buoy,
_station_display_datas_waypoint,
+ _station_display_datas_road_waypoint,
};
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index 79356008df..4975431738 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -1301,7 +1301,7 @@ static bool CanRoadContinueIntoNextTile(const Town *t, const TileIndex tile, con
/* If the next tile is a station, allow if it's a road station facing the proper direction. Otherwise return false. */
if (IsTileType(next_tile, MP_STATION)) {
/* If the next tile is a road station, allow if it can be entered by the new tunnel/bridge, otherwise disallow. */
- return IsRoadStop(next_tile) && (GetRoadStopDir(next_tile) == ReverseDiagDir(road_dir) || (IsDriveThroughStopTile(next_tile) && GetRoadStopDir(next_tile) == road_dir));
+ return IsAnyRoadStop(next_tile) && (GetRoadStopDir(next_tile) == ReverseDiagDir(road_dir) || (IsDriveThroughStopTile(next_tile) && GetRoadStopDir(next_tile) == road_dir));
}
/* If the next tile is a road depot, allow if it's facing the right way. */
diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp
index 02dea527ec..59502a7d63 100644
--- a/src/tunnelbridge_cmd.cpp
+++ b/src/tunnelbridge_cmd.cpp
@@ -549,7 +549,8 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
}
case STATION_BUS:
- case STATION_TRUCK: {
+ case STATION_TRUCK:
+ case STATION_ROADWAYPOINT: {
CommandCost ret = IsRoadStopBridgeAboveOK(tile, IsDriveThroughStopTile(tile), GetRoadStopDir(tile),
tile_start, tile_end, z_start + 1, bridge_type, transport_type);
if (ret.Failed()) {
@@ -672,7 +673,8 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
}
case STATION_BUS:
- case STATION_TRUCK: {
+ case STATION_TRUCK:
+ case STATION_ROADWAYPOINT: {
CommandCost ret = IsRoadStopBridgeAboveOK(tile, IsDriveThroughStopTile(tile), GetRoadStopDir(tile),
tile_start, tile_end, z_start + 1, bridge_type, transport_type);
if (ret.Failed()) {
diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp
index 716a8fc1a2..e9d017f385 100644
--- a/src/vehicle_gui.cpp
+++ b/src/vehicle_gui.cpp
@@ -2470,6 +2470,7 @@ public:
/* check rail waypoint or buoy (no ownership) */
if ((IsRailWaypointTile(tile) && this->vli.vtype == VEH_TRAIN && IsInfraTileUsageAllowed(VEH_TRAIN, this->vli.company, tile))
+ || (IsRoadWaypointTile(tile) && this->vli.vtype == VEH_ROAD && IsInfraTileUsageAllowed(VEH_ROAD, this->vli.company, tile))
|| (IsBuoyTile(tile) && this->vli.vtype == VEH_SHIP)) {
if (this->vli.type != VL_STATION_LIST) return;
if (!(Station::Get(this->vli.index)->facilities & FACIL_WAYPOINT)) return;
@@ -2480,7 +2481,7 @@ public:
if (IsTileType(tile, MP_STATION)) {
if (this->vli.type != VL_STATION_LIST) return;
- if (Station::Get(this->vli.index)->facilities & FACIL_WAYPOINT) return;
+ if (BaseStation::Get(this->vli.index)->facilities & FACIL_WAYPOINT) return;
StationID st_index = GetStationIndex(tile);
const Station *st = Station::Get(st_index);
@@ -3754,7 +3755,7 @@ public:
break;
case OT_GOTO_WAYPOINT: {
- assert(v->type == VEH_TRAIN || v->type == VEH_SHIP);
+ assert(v->type == VEH_TRAIN || v->type == VEH_ROAD || v->type == VEH_SHIP);
SetDParam(0, v->current_order.GetDestination());
str = HasBit(v->vehicle_flags, VF_PATHFINDER_LOST) ? STR_VEHICLE_STATUS_CANNOT_REACH_WAYPOINT_VEL : STR_VEHICLE_STATUS_HEADING_FOR_WAYPOINT_VEL;
SetDParam(1, v->GetDisplaySpeed());
diff --git a/src/viewport_type.h b/src/viewport_type.h
index f4494a0951..f84a73f757 100644
--- a/src/viewport_type.h
+++ b/src/viewport_type.h
@@ -194,8 +194,10 @@ enum ViewportDragDropSelectionProcess {
DDSP_PLACE_ROAD_X_DIR, ///< Road placement (X axis)
DDSP_PLACE_ROAD_Y_DIR, ///< Road placement (Y axis)
DDSP_PLACE_AUTOROAD, ///< Road placement (auto)
+ DDSP_BUILD_ROAD_WAYPOINT, ///< Road stop placement (waypoint)
DDSP_BUILD_BUSSTOP, ///< Road stop placement (buses)
DDSP_BUILD_TRUCKSTOP, ///< Road stop placement (trucks)
+ DDSP_REMOVE_ROAD_WAYPOINT, ///< Road stop removal (waypoint)
DDSP_REMOVE_BUSSTOP, ///< Road stop removal (buses)
DDSP_REMOVE_TRUCKSTOP, ///< Road stop removal (trucks)
DDSP_CONVERT_ROAD, ///< Road conversion
diff --git a/src/waypoint.cpp b/src/waypoint.cpp
index eb9ef17ac6..68992808c3 100644
--- a/src/waypoint.cpp
+++ b/src/waypoint.cpp
@@ -41,6 +41,10 @@ void Waypoint::GetTileArea(TileArea *ta, StationType type) const
*ta = this->train_station;
return;
+ case STATION_ROADWAYPOINT:
+ *ta = this->road_waypoint_area;
+ return;
+
case STATION_BUOY:
ta->tile = this->xy;
ta->w = 1;
diff --git a/src/waypoint_base.h b/src/waypoint_base.h
index 649f1ed856..07e057a5a5 100644
--- a/src/waypoint_base.h
+++ b/src/waypoint_base.h
@@ -17,6 +17,7 @@
*/
enum WaypointFlags {
WPF_HIDE_LABEL = 0, ///< Hide waypoint label
+ WPF_ROAD = 1, ///< This is a road waypoint
};
/** Representation of a waypoint. */
@@ -24,6 +25,8 @@ struct Waypoint FINAL : SpecializedStation {
uint16 town_cn; ///< The N-1th waypoint for this town (consecutive number)
uint16 waypoint_flags; ///< Waypoint flags, see WaypointFlags
+ TileArea road_waypoint_area; ///< Tile area the road waypoint part covers
+
/**
* Create a waypoint at the given tile.
* @param tile The location of the waypoint.
diff --git a/src/waypoint_cmd.cpp b/src/waypoint_cmd.cpp
index 40c4e49a91..6d665eb4df 100644
--- a/src/waypoint_cmd.cpp
+++ b/src/waypoint_cmd.cpp
@@ -68,13 +68,13 @@ void Waypoint::MoveSign(TileIndex new_xy)
* @param cid previous owner of the waypoint
* @return the deleted nearby waypoint
*/
-static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile, StringID str, CompanyID cid)
+static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile, StringID str, CompanyID cid, bool is_road)
{
Waypoint *best = nullptr;
uint thres = 8;
for (Waypoint *wp : Waypoint::Iterate()) {
- if (!wp->IsInUse() && wp->string_id == str && wp->owner == cid) {
+ if (!wp->IsInUse() && wp->string_id == str && wp->owner == cid && HasBit(wp->waypoint_flags, WPF_ROAD) == is_road) {
uint cur_dist = DistanceManhattan(tile, wp->xy);
if (cur_dist < thres) {
@@ -109,6 +109,29 @@ Axis GetAxisForNewWaypoint(TileIndex tile)
}
}
+/**
+ * Get the axis for a new road waypoint. This means that if it is a valid
+ * tile to build a waypoint on it returns a valid Axis, otherwise an
+ * invalid one.
+ * @param tile the tile to look at.
+ * @return the axis for the to-be-build waypoint.
+ */
+Axis GetAxisForNewRoadWaypoint(TileIndex tile)
+{
+ /* The axis for rail waypoints is easy. */
+ if (IsRoadWaypointTile(tile)) return DiagDirToAxis(GetRoadStopDir(tile));
+
+ /* Non-plain road type, no valid axis for waypoints. */
+ if (!IsNormalRoadTile(tile)) return INVALID_AXIS;
+
+ RoadBits bits = GetAllRoadBits(tile);
+
+ if ((bits & ROAD_Y) == 0) return AXIS_X;
+ if ((bits & ROAD_X) == 0) return AXIS_Y;
+
+ return INVALID_AXIS;
+}
+
extern CommandCost ClearTile_Station(TileIndex tile, DoCommandFlag flags);
/**
@@ -152,7 +175,7 @@ static CommandCost IsValidTileForWaypoint(TileIndex tile, Axis axis, StationID *
}
extern void GetStationLayout(byte *layout, uint numtracks, uint plat_len, const StationSpec *statspec);
-extern CommandCost FindJoiningWaypoint(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Waypoint **wp);
+extern CommandCost FindJoiningWaypoint(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Waypoint **wp, bool is_road);
extern CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta, Axis axis);
extern CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec *statspec, byte layout);
@@ -232,15 +255,16 @@ CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint
Waypoint *wp = nullptr;
TileArea new_location(start_tile, width, height);
- CommandCost ret = FindJoiningWaypoint(est, station_to_join, adjacent, new_location, &wp);
+ CommandCost ret = FindJoiningWaypoint(est, station_to_join, adjacent, new_location, &wp, false);
if (ret.Failed()) return ret;
/* 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 == nullptr && reuse) wp = FindDeletedWaypointCloseTo(center_tile, STR_SV_STNAME_WAYPOINT, _current_company);
+ if (wp == nullptr && reuse) wp = FindDeletedWaypointCloseTo(center_tile, STR_SV_STNAME_WAYPOINT, _current_company, false);
if (wp != nullptr) {
/* Reuse an existing waypoint. */
+ if (HasBit(wp->waypoint_flags, WPF_ROAD)) return CMD_ERROR;
if (wp->owner != _current_company) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT);
/* check if we want to expand an already existing waypoint? */
@@ -301,6 +325,134 @@ CommandCost CmdBuildRailWaypoint(TileIndex start_tile, DoCommandFlag flags, uint
return CommandCost(EXPENSES_CONSTRUCTION, count * _price[PR_BUILD_WAYPOINT_RAIL]);
}
+/**
+ * Convert existing road to waypoint. Eg build a waypoint station over
+ * piece of road
+ * @param start_tile northern most tile where waypoint will be built
+ * @param flags Operation to perform.
+ * @param p1 bit 0..7: Width of the road stop.
+ * bit 8..15: Length of the road stop.
+ * bit 16: Allow stations directly adjacent to other stations.
+ * bit 17: #Axis of the road.
+ * @param p2 bit 16..31: Station ID to join (NEW_STATION if build new one).
+ * @param text Unused.
+ * @return The cost of this operation or an error.
+ */
+CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ StationID station_to_join = GB(p2, 16, 16);
+ byte width = GB(p1, 0, 8);
+ byte height = GB(p1, 8, 8);
+ bool adjacent = HasBit(p1, 16);
+ Axis axis = Extract(p1);
+
+ /* The number of parts to build */
+ byte count = axis == AXIS_X ? height : width;
+
+ if ((axis == AXIS_X ? width : height) != 1) return CMD_ERROR;
+ if (count == 0 || count > _settings_game.station.station_spread) 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;
+
+ /* Check if the first tile and the last tile are valid */
+ if (!IsValidTile(start_tile) || TileAddWrap(start_tile, width - 1, height - 1) == INVALID_TILE) return CMD_ERROR;
+
+ TileArea roadstop_area(start_tile, width, height);
+ /* Total road stop cost. */
+ CommandCost cost(EXPENSES_CONSTRUCTION, roadstop_area.w * roadstop_area.h * _price[PR_BUILD_STATION_TRUCK]);
+ StationID est = INVALID_STATION;
+ extern CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, StationType station_type, Axis axis, StationID *station, RoadType rt, bool require_road);
+ CommandCost ret = CheckFlatLandRoadStop(roadstop_area, flags, 5 << axis, true, STATION_ROADWAYPOINT, axis, &est, INVALID_ROADTYPE, true);
+ if (ret.Failed()) return ret;
+ cost.AddCost(ret);
+
+ Waypoint *wp = nullptr;
+ ret = FindJoiningWaypoint(est, station_to_join, adjacent, roadstop_area, &wp, true);
+ if (ret.Failed()) return ret;
+
+ /* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
+ TileIndex center_tile = start_tile + (count / 2) * TileOffsByDiagDir(AxisToDiagDir(OtherAxis(axis)));;
+ if (wp == nullptr && reuse) wp = FindDeletedWaypointCloseTo(center_tile, STR_SV_STNAME_WAYPOINT, _current_company, true);
+
+ if (wp != nullptr) {
+ /* Reuse an existing waypoint. */
+ if (!HasBit(wp->waypoint_flags, WPF_ROAD)) return CMD_ERROR;
+ if (wp->owner != _current_company) return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT);
+
+ CommandCost ret = wp->rect.BeforeAddRect(start_tile, width, height, StationRect::ADD_TEST);
+ if (ret.Failed()) return ret;
+ } else {
+ /* allocate and initialize new waypoint */
+ if (!Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
+ }
+
+ if (flags & DC_EXEC) {
+ if (wp == nullptr) {
+ wp = new Waypoint(start_tile);
+ SetBit(wp->waypoint_flags, WPF_ROAD);
+ } else if (!wp->IsInUse()) {
+ /* Move existing (recently deleted) waypoint to the new location */
+ wp->xy = start_tile;
+ }
+ wp->owner = _current_company;
+
+ wp->rect.BeforeAddRect(start_tile, width, height, StationRect::ADD_TRY);
+
+ wp->delete_ctr = 0;
+ wp->facilities |= FACIL_BUS_STOP | FACIL_TRUCK_STOP;
+ wp->build_date = _date;
+ wp->string_id = STR_SV_STNAME_WAYPOINT;
+
+ if (wp->town == nullptr) MakeDefaultName(wp);
+
+ wp->UpdateVirtCoord();
+
+ /* Check every tile in the area. */
+ for (TileIndex cur_tile : roadstop_area) {
+ /* Get existing road types and owners before any tile clearing */
+ RoadType road_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_ROAD) : INVALID_ROADTYPE;
+ RoadType tram_rt = MayHaveRoad(cur_tile) ? GetRoadType(cur_tile, RTT_TRAM) : INVALID_ROADTYPE;
+ Owner road_owner = road_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_ROAD) : _current_company;
+ Owner tram_owner = tram_rt != INVALID_ROADTYPE ? GetRoadOwner(cur_tile, RTT_TRAM) : _current_company;
+ DisallowedRoadDirections drd = IsNormalRoadTile(cur_tile) ? GetDisallowedRoadDirections(cur_tile) : DRD_NONE;
+
+ extern CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags);
+ if (IsTileType(cur_tile, MP_STATION) && IsAnyRoadStop(cur_tile)) {
+ RemoveRoadStop(cur_tile, flags);
+ }
+
+ wp->road_waypoint_area.Add(cur_tile);
+
+ wp->rect.BeforeAddTile(cur_tile, StationRect::ADD_TRY);
+
+ /* Update company infrastructure counts. If the current tile is a normal road tile, remove the old
+ * bits first. */
+ if (IsNormalRoadTile(cur_tile)) {
+ UpdateCompanyRoadInfrastructure(road_rt, road_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_ROAD)));
+ UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, -(int)CountBits(GetRoadBits(cur_tile, RTT_TRAM)));
+ }
+
+ UpdateCompanyRoadInfrastructure(road_rt, road_owner, ROAD_STOP_TRACKBIT_FACTOR);
+ UpdateCompanyRoadInfrastructure(tram_rt, tram_owner, ROAD_STOP_TRACKBIT_FACTOR);
+
+ MakeDriveThroughRoadStop(cur_tile, wp->owner, road_owner, tram_owner, wp->index, STATION_ROADWAYPOINT, road_rt, tram_rt, axis);
+ SetDriveThroughStopDisallowedRoadDirections(cur_tile, drd);
+
+ Company::Get(wp->owner)->infrastructure.station++;
+
+ MarkTileDirtyByTile(cur_tile);
+ UpdateRoadCachedOneWayStatesAroundTile(cur_tile);
+ }
+ NotifyRoadLayoutChanged(true);
+ DirtyCompanyInfrastructureWindows(wp->owner);
+ }
+ return cost;
+}
+
/**
* Build a buoy.
* @param tile tile where to place the buoy
@@ -317,7 +469,7 @@ CommandCost CmdBuildBuoy(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32
if (!IsTileFlat(tile)) return_cmd_error(STR_ERROR_SITE_UNSUITABLE);
/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
- Waypoint *wp = FindDeletedWaypointCloseTo(tile, STR_SV_STNAME_BUOY, OWNER_NONE);
+ Waypoint *wp = FindDeletedWaypointCloseTo(tile, STR_SV_STNAME_BUOY, OWNER_NONE, false);
if (wp == nullptr && !Waypoint::CanAllocateItem()) return_cmd_error(STR_ERROR_TOO_MANY_STATIONS_LOADING);
CommandCost cost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_WAYPOINT_BUOY]);
diff --git a/src/waypoint_func.h b/src/waypoint_func.h
index 2906fa6369..ba816957da 100644
--- a/src/waypoint_func.h
+++ b/src/waypoint_func.h
@@ -17,6 +17,7 @@
CommandCost RemoveBuoy(TileIndex tile, DoCommandFlag flags);
Axis GetAxisForNewWaypoint(TileIndex tile);
+Axis GetAxisForNewRoadWaypoint(TileIndex tile);
void ShowWaypointWindow(const Waypoint *wp);
void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype);
diff --git a/src/waypoint_gui.cpp b/src/waypoint_gui.cpp
index 44a75a9a27..c417843222 100644
--- a/src/waypoint_gui.cpp
+++ b/src/waypoint_gui.cpp
@@ -45,7 +45,24 @@ private:
if (!this->wp->IsInUse()) return this->wp->xy;
TileArea ta;
- this->wp->GetTileArea(&ta, this->vt == VEH_TRAIN ? STATION_WAYPOINT : STATION_BUOY);
+ StationType type;
+ switch (this->vt) {
+ case VEH_TRAIN:
+ type = STATION_WAYPOINT;
+ break;
+
+ case VEH_ROAD:
+ type = STATION_ROADWAYPOINT;
+ break;
+
+ case VEH_SHIP:
+ type = STATION_BUOY;
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+ this->wp->GetTileArea(&ta, type);
return ta.GetCenterTile();
}
@@ -58,15 +75,24 @@ public:
WaypointWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc)
{
this->wp = Waypoint::Get(window_number);
- this->vt = (wp->string_id == STR_SV_STNAME_WAYPOINT) ? VEH_TRAIN : VEH_SHIP;
+ if (wp->string_id == STR_SV_STNAME_WAYPOINT) {
+ this->vt = HasBit(this->wp->waypoint_flags, WPF_ROAD) ? VEH_ROAD : VEH_TRAIN;
+ } else {
+ this->vt = VEH_SHIP;
+ }
this->CreateNestedTree();
if (this->vt == VEH_TRAIN) {
this->GetWidget(WID_W_SHOW_VEHICLES)->SetDataTip(STR_TRAIN, STR_STATION_VIEW_SCHEDULED_TRAINS_TOOLTIP);
+ }
+ if (this->vt == VEH_ROAD) {
+ this->GetWidget(WID_W_SHOW_VEHICLES)->SetDataTip(STR_LORRY, STR_STATION_VIEW_SCHEDULED_ROAD_VEHICLES_TOOLTIP);
+ }
+ if (this->vt != VEH_SHIP) {
this->GetWidget(WID_W_CENTER_VIEW)->tool_tip = STR_WAYPOINT_VIEW_CENTER_TOOLTIP;
this->GetWidget(WID_W_RENAME)->tool_tip = STR_WAYPOINT_VIEW_CHANGE_WAYPOINT_NAME;
}
- this->show_hide_label = (this->vt == VEH_TRAIN && _settings_client.gui.allow_hiding_waypoint_labels);
+ this->show_hide_label = (this->vt != VEH_SHIP && _settings_client.gui.allow_hiding_waypoint_labels);
this->GetWidget(WID_W_TOGGLE_HIDDEN_SEL)->SetDisplayedPlane(this->show_hide_label ? 0 : SZSP_NONE);
this->FinishInitNested(window_number);
@@ -135,7 +161,7 @@ public:
this->SetWidgetLoweredState(WID_W_TOGGLE_HIDDEN, HasBit(this->wp->waypoint_flags, WPF_HIDE_LABEL));
- bool show_hide_label = (this->vt == VEH_TRAIN && _settings_client.gui.allow_hiding_waypoint_labels);
+ bool show_hide_label = (this->vt != VEH_SHIP && _settings_client.gui.allow_hiding_waypoint_labels);
if (show_hide_label != this->show_hide_label) {
this->show_hide_label = show_hide_label;
this->GetWidget(WID_W_TOGGLE_HIDDEN_SEL)->SetDisplayedPlane(this->show_hide_label ? 0 : SZSP_NONE);
diff --git a/src/widgets/road_widget.h b/src/widgets/road_widget.h
index 3d49e9ae9d..5d9ea034af 100644
--- a/src/widgets/road_widget.h
+++ b/src/widgets/road_widget.h
@@ -19,6 +19,7 @@ enum RoadToolbarWidgets {
WID_ROT_AUTOROAD, ///< Autorail.
WID_ROT_DEMOLISH, ///< Demolish.
WID_ROT_DEPOT, ///< Build depot.
+ WID_ROT_BUILD_WAYPOINT, ///< Build waypoint.
WID_ROT_BUS_STATION, ///< Build bus station.
WID_ROT_TRUCK_STATION, ///< Build truck station.
WID_ROT_ONE_WAY, ///< Build one-way road.