Add roadstop GRF properties to set bridge heights and disallowed pillars

pull/374/head
Jonathan G Rennison 2 years ago
parent 1a64d2a97e
commit 2cbbae16da

@ -2450,6 +2450,7 @@ STR_CONFIG_SETTING_ALLOW_GRF_STATIONS_UNDER_BRIDGES_HELPTEXT :If enabled, New
STR_CONFIG_SETTING_ALLOW_ROAD_STATIONS_UNDER_BRIDGES :Allow road/tram stops under bridges: {STRING2}
STR_CONFIG_SETTING_ALLOW_ROAD_STATIONS_UNDER_BRIDGES_HELPTEXT :Allow road/tram stops under bridges. Drive through stops require 1 height level of clearance, drive in bays require 2 height levels of clearance.
STR_CONFIG_SETTING_ALLOW_ROAD_STATIONS_UNDER_BRIDGES_HELPTEXT_EXTRA :{STRING}{}{}NewGRF road/tram stops may override this setting and allow or disallow custom stops under bridges, and set custom height clearance requirements.
STR_CONFIG_SETTING_ALLOW_DOCKS_UNDER_BRIDGES :Allow docks under bridges: {STRING2}
STR_CONFIG_SETTING_ALLOW_DOCKS_UNDER_BRIDGES_HELPTEXT :Allow docks under bridges. Docks require 2 height levels of clearance.{}This may result in graphical issues.

@ -5065,6 +5065,26 @@ static ChangeInfoResult RoadStopChangeInfo(uint id, int numinfo, int prop, const
rs->flags = (uint8)buf->ReadDWord(); // Future-proofing, size this as 4 bytes, but we only need one byte's worth of flags at present
break;
case A0RPI_ROADSTOP_MIN_BRIDGE_HEIGHT:
if (MappedPropertyLengthMismatch(buf, 6, mapping_entry)) break;
FALLTHROUGH;
case 0x13: // Minimum height for a bridge above
SetBit(rs->internal_flags, RSIF_BRIDGE_HEIGHTS_SET);
for (uint i = 0; i < 6; i++) {
rs->bridge_height[i] = buf->ReadByte();
}
break;
case A0RPI_ROADSTOP_DISALLOWED_BRIDGE_PILLARS:
if (MappedPropertyLengthMismatch(buf, 6, mapping_entry)) break;
FALLTHROUGH;
case 0x14: // Disallowed bridge pillars
SetBit(rs->internal_flags, RSIF_BRIDGE_DISALLOWED_PILLARS_SET);
for (uint i = 0; i < 6; i++) {
rs->bridge_disallowed_pillars[i] = buf->ReadByte();
}
break;
default:
ret = CIR_UNKNOWN;
break;

@ -101,6 +101,8 @@ extern const GRFPropertyMapDefinition _grf_action0_remappable_properties[] = {
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_ANIMATION_TRIGGERS, "roadstop_animation_triggers"),
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_CALLBACK_MASK, "roadstop_callback_mask"),
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_GENERAL_FLAGS, "roadstop_general_flags"),
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_MIN_BRIDGE_HEIGHT, "roadstop_min_bridge_height"),
GRFPropertyMapDefinition(GSF_ROADSTOPS, A0RPI_ROADSTOP_DISALLOWED_BRIDGE_PILLARS, "roadstop_disallowed_bridge_pillars"),
GRFPropertyMapDefinition(),
};

@ -50,6 +50,8 @@ enum Action0RemapPropertyIds {
A0RPI_ROADSTOP_ANIMATION_TRIGGERS,
A0RPI_ROADSTOP_CALLBACK_MASK,
A0RPI_ROADSTOP_GENERAL_FLAGS,
A0RPI_ROADSTOP_MIN_BRIDGE_HEIGHT,
A0RPI_ROADSTOP_DISALLOWED_BRIDGE_PILLARS,
};

@ -67,6 +67,11 @@ enum RoadStopSpecFlags {
RSF_CB141_RANDOM_BITS, ///< Callback 141 needs random bits.
};
enum RoadStopSpecIntlFlags {
RSIF_BRIDGE_HEIGHTS_SET, ///< byte bridge_height[6] is set.
RSIF_BRIDGE_DISALLOWED_PILLARS_SET, ///< byte bridge_disallowed_pillars[6] is set.
};
/** Scope resolver for road stops. */
struct RoadStopScopeResolver : public ScopeResolver {
TileIndex tile; ///< %Tile of the station.
@ -131,11 +136,15 @@ struct RoadStopSpec {
RoadStopDrawMode draw_mode = ROADSTOP_DRAW_MODE_ROAD | ROADSTOP_DRAW_MODE_OVERLAY;
uint8 callback_mask = 0;
uint8 flags = 0;
uint8 internal_flags = 0; ///< Bitmask of internal spec flags (RoadStopSpecIntlFlags)
CargoTypes cargo_triggers = 0; ///< Bitmask of cargo types which cause trigger re-randomizing
AnimationInfo animation;
byte bridge_height[6]; ///< Minimum height for a bridge above, 0 for none
byte bridge_disallowed_pillars[6]; ///< Disallowed pillar flags for a bridge above
static const RoadStopSpec *Get(uint16 index);
};

@ -1788,6 +1788,19 @@ static bool SpriteZoomMinSettingGUI(SettingOnGuiCtrlData &data)
}
}
static bool AllowRoadStopsUnderBridgesSettingGUI(SettingOnGuiCtrlData &data)
{
switch (data.type) {
case SOGCT_DESCRIPTION_TEXT:
SetDParam(0, data.text);
data.text = STR_CONFIG_SETTING_ALLOW_ROAD_STATIONS_UNDER_BRIDGES_HELPTEXT_EXTRA;
return true;
default:
return false;
}
}
/* End - GUI callbacks */
/**

@ -946,18 +946,28 @@ CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec *statsp
GetBridgeType(southern_bridge_end), GetTunnelBridgeTransportType(southern_bridge_end));
}
CommandCost IsRoadStopBridgeAboveOK(TileIndex tile, bool drive_through, DiagDirection entrance,
CommandCost IsRoadStopBridgeAboveOK(TileIndex tile, const RoadStopSpec *spec, bool drive_through, DiagDirection entrance,
TileIndex northern_bridge_end, TileIndex southern_bridge_end, int bridge_height,
BridgeType bridge_type, TransportType bridge_transport_type)
{
if (!_settings_game.construction.allow_road_stops_under_bridges) return CommandCost(INVALID_STRING_ID);
if (spec && HasBit(spec->internal_flags, RSIF_BRIDGE_HEIGHTS_SET)) {
int height = spec->bridge_height[drive_through ? (GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET + DiagDirToAxis(entrance)) : entrance];
if (height == 0) return CommandCost(INVALID_STRING_ID);
if (GetTileMaxZ(tile) + height > bridge_height) {
return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION);
}
} else {
if (!_settings_game.construction.allow_road_stops_under_bridges) return CommandCost(INVALID_STRING_ID);
if (GetTileMaxZ(tile) + (drive_through ? 1 : 2) > bridge_height) {
return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION);
if (GetTileMaxZ(tile) + (drive_through ? 1 : 2) > bridge_height) {
return CommandCost(STR_ERROR_BRIDGE_TOO_LOW_FOR_STATION);
}
}
BridgePiecePillarFlags disallowed_pillar_flags = (BridgePiecePillarFlags) 0;
if (drive_through) {
if (spec && HasBit(spec->internal_flags, RSIF_BRIDGE_DISALLOWED_PILLARS_SET)) {
disallowed_pillar_flags = (BridgePiecePillarFlags) spec->bridge_disallowed_pillars[drive_through ? (GFX_TRUCK_BUS_DRIVETHROUGH_OFFSET + DiagDirToAxis(entrance)) : entrance];
} else if (drive_through) {
disallowed_pillar_flags = (BridgePiecePillarFlags) (DiagDirToAxis(entrance) == AXIS_X ? 0x50 : 0xA0);
} else {
SetBit(disallowed_pillar_flags, 4 + entrance);
@ -1066,6 +1076,7 @@ static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag fl
/**
* Checks if a road stop can be built at the given tile.
* @param tile_area Area to check.
* @param spec Road stop spec.
* @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.
@ -1076,20 +1087,21 @@ static CommandCost CheckFlatLandRailStation(TileArea tile_area, DoCommandFlag fl
* @param require_road Is existing road required.
* @return The cost in case of success, or an error code if it failed.
*/
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 CheckFlatLandRoadStop(TileArea tile_area, const RoadStopSpec *spec, 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;
for (TileIndex cur_tile : tile_area) {
CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through, !_settings_game.construction.allow_road_stops_under_bridges);
bool allow_under_bridge = _settings_game.construction.allow_road_stops_under_bridges || (spec != nullptr && HasBit(spec->internal_flags, RSIF_BRIDGE_HEIGHTS_SET));
CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z, !is_drive_through, !allow_under_bridge);
if (ret.Failed()) return ret;
cost.AddCost(ret);
if (_settings_game.construction.allow_road_stops_under_bridges && IsBridgeAbove(cur_tile)) {
if (allow_under_bridge && IsBridgeAbove(cur_tile)) {
TileIndex southern_bridge_end = GetSouthernBridgeEnd(cur_tile);
TileIndex northern_bridge_end = GetNorthernBridgeEnd(cur_tile);
CommandCost bridge_ret = IsRoadStopBridgeAboveOK(cur_tile, is_drive_through, (DiagDirection) FindFirstBit(invalid_dirs),
CommandCost bridge_ret = IsRoadStopBridgeAboveOK(cur_tile, spec, is_drive_through, (DiagDirection) FindFirstBit(invalid_dirs),
northern_bridge_end, southern_bridge_end, GetBridgeHeight(southern_bridge_end),
GetBridgeType(southern_bridge_end), GetTunnelBridgeTransportType(southern_bridge_end));
if (bridge_ret.Failed()) return bridge_ret;
@ -2114,7 +2126,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 ? STATION_TRUCK : STATION_BUS, axis, &est, rt, false);
ret = CheckFlatLandRoadStop(roadstop_area, roadstopspec, 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);

@ -1433,7 +1433,7 @@ class NIHRoadStop : public NIHelper {
output.print(buffer);
seprintf(buffer, lastof(buffer), " spec: stop type: %X, draw mode: %X, cargo triggers: " OTTD_PRINTFHEX64, spec->stop_type, spec->draw_mode, spec->cargo_triggers);
output.print(buffer);
seprintf(buffer, lastof(buffer), " spec: callback mask: %X, flags: %X", spec->callback_mask, spec->flags);
seprintf(buffer, lastof(buffer), " spec: callback mask: %X, flags: %X, intl flags: %X", spec->callback_mask, spec->flags, spec->internal_flags);
output.print(buffer);
seprintf(buffer, lastof(buffer), " animation: frames: %u, status: %u, speed: %u, triggers: 0x%X", spec->animation.frames, spec->animation.status, spec->animation.speed, spec->animation.triggers);
output.print(buffer);

@ -82,6 +82,7 @@ static int64 LinkGraphDistModeXrefChillPP(int64 val);
static bool LinkGraphDistributionSettingGUI(SettingOnGuiCtrlData &data);
static bool OrderTownGrowthRate(SettingOnGuiCtrlData &data);
static bool SpriteZoomMinSettingGUI(SettingOnGuiCtrlData &data);
static bool AllowRoadStopsUnderBridgesSettingGUI(SettingOnGuiCtrlData &data);
/* End - GUI callbacks */
@ -2044,6 +2045,7 @@ cat = SC_ADVANCED
str = STR_CONFIG_SETTING_ALLOW_ROAD_STATIONS_UNDER_BRIDGES
strhelp = STR_CONFIG_SETTING_ALLOW_ROAD_STATIONS_UNDER_BRIDGES_HELPTEXT
patxname = ""allow_stations_under_bridges.construction.allow_road_stops_under_bridges""
guiproc = AllowRoadStopsUnderBridgesSettingGUI
[SDT_BOOL]
var = construction.allow_docks_under_bridges

@ -49,6 +49,7 @@
#include "newgrf_station.h"
#include "station_func.h"
#include "tracerestrict.h"
#include "newgrf_roadstop.h"
#include "table/strings.h"
#include "table/bridge_land.h"
@ -69,7 +70,7 @@ extern const RoadBits _invalid_tileh_slopes_road[2][15];
extern CommandCost IsRailStationBridgeAboveOk(TileIndex tile, const StationSpec *statspec, byte layout, TileIndex northern_bridge_end, TileIndex southern_bridge_end, int bridge_height,
BridgeType bridge_type, TransportType bridge_transport_type);
extern CommandCost IsRoadStopBridgeAboveOK(TileIndex tile, bool drive_through, DiagDirection entrance,
extern CommandCost IsRoadStopBridgeAboveOK(TileIndex tile, const RoadStopSpec *spec, bool drive_through, DiagDirection entrance,
TileIndex northern_bridge_end, TileIndex southern_bridge_end, int bridge_height,
BridgeType bridge_type, TransportType bridge_transport_type);
@ -551,7 +552,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
case STATION_BUS:
case STATION_TRUCK:
case STATION_ROADWAYPOINT: {
CommandCost ret = IsRoadStopBridgeAboveOK(tile, IsDriveThroughStopTile(tile), GetRoadStopDir(tile),
CommandCost ret = IsRoadStopBridgeAboveOK(tile, GetRoadStopSpec(tile), IsDriveThroughStopTile(tile), GetRoadStopDir(tile),
tile_start, tile_end, z_start + 1, bridge_type, transport_type);
if (ret.Failed()) {
if (ret.GetErrorMessage() != INVALID_STRING_ID) return ret;
@ -675,7 +676,7 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
case STATION_BUS:
case STATION_TRUCK:
case STATION_ROADWAYPOINT: {
CommandCost ret = IsRoadStopBridgeAboveOK(tile, IsDriveThroughStopTile(tile), GetRoadStopDir(tile),
CommandCost ret = IsRoadStopBridgeAboveOK(tile, GetRoadStopSpec(tile), IsDriveThroughStopTile(tile), GetRoadStopDir(tile),
tile_start, tile_end, z_start + 1, bridge_type, transport_type);
if (ret.Failed()) {
if (ret.GetErrorMessage() != INVALID_STRING_ID) return ret;

@ -380,8 +380,8 @@ CommandCost CmdBuildRoadWaypoint(TileIndex start_tile, DoCommandFlag flags, uint
/* 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);
extern CommandCost CheckFlatLandRoadStop(TileArea tile_area, const RoadStopSpec *spec, 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, spec, flags, 5 << axis, true, STATION_ROADWAYPOINT, axis, &est, INVALID_ROADTYPE, true);
if (ret.Failed()) return ret;
cost.AddCost(ret);

Loading…
Cancel
Save