From a4a66ec1aa2a7772ed174b8dcc1905e9bc5dd02d Mon Sep 17 00:00:00 2001 From: terkhen Date: Wed, 24 Feb 2010 21:55:03 +0000 Subject: [PATCH] (svn r19231) -Feature: Allow overbuilding of road stops. --- bin/ai/compat_0.7.nut | 16 +++++ bin/ai/compat_1.0.nut | 19 +++++- bin/ai/regression/regression.txt | 16 ++--- src/ai/api/ai_changelog.hpp | 4 ++ src/lang/english.txt | 1 + src/station_cmd.cpp | 114 +++++++++++++++++++++---------- 6 files changed, 125 insertions(+), 45 deletions(-) diff --git a/bin/ai/compat_0.7.nut b/bin/ai/compat_0.7.nut index 3e4b4fa68e..db56fdaee1 100644 --- a/bin/ai/compat_0.7.nut +++ b/bin/ai/compat_0.7.nut @@ -258,3 +258,19 @@ class AIWaypointList extends _AIWaypointList { ::_AIWaypointList.constructor(AIWaypoint.WAYPOINT_RAIL); } } + +AIRoad._BuildRoadStation <- AIRoad.BuildRoadStation; +AIRoad.BuildRoadStation <- function(tile, front, road_veh_type, station_id) +{ + if (AIRoad.IsRoadStationTile(tile)) return false; + + return AIRoad._BuildRoadStation(tile, front, road_veh_type, station_id); +} + +AIRoad._BuildDriveThroughRoadStation <- AIRoad.BuildDriveThroughRoadStation; +AIRoad.BuildDriveThroughRoadStation <- function(tile, front, road_veh_type, station_id) +{ + if (AIRoad.IsRoadStationTile(tile)) return false; + + return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id); +} diff --git a/bin/ai/compat_1.0.nut b/bin/ai/compat_1.0.nut index f14520c1ef..77ae2525aa 100644 --- a/bin/ai/compat_1.0.nut +++ b/bin/ai/compat_1.0.nut @@ -7,5 +7,20 @@ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . */ -/* Enable when adding the first compatability code: - * AILog.Info("1.0 API compatability in effect"); */ +AILog.Info("1.0 API compatability in effect."); + +AIRoad._BuildRoadStation <- AIRoad.BuildRoadStation; +AIRoad.BuildRoadStation <- function(tile, front, road_veh_type, station_id) +{ + if (AIRoad.IsRoadStationTile(tile)) return false; + + return AIRoad._BuildRoadStation(tile, front, road_veh_type, station_id); +} + +AIRoad._BuildDriveThroughRoadStation <- AIRoad.BuildDriveThroughRoadStation; +AIRoad.BuildDriveThroughRoadStation <- function(tile, front, road_veh_type, station_id) +{ + if (AIRoad.IsRoadStationTile(tile)) return false; + + return AIRoad._BuildDriveThroughRoadStation(tile, front, road_veh_type, station_id); +} diff --git a/bin/ai/regression/regression.txt b/bin/ai/regression/regression.txt index be69ce3889..aa45f1151d 100644 --- a/bin/ai/regression/regression.txt +++ b/bin/ai/regression/regression.txt @@ -7259,7 +7259,7 @@ BuildRoadStation(): false BuildRoadStation(): false BuildRoadStation(): true - BuildRoadStation(): false + BuildRoadStation(): true IsStationTile(): true IsStationTile(): false HasRoadType(Road): true @@ -8452,11 +8452,11 @@ 14 => 1 12 => 1 Age ListDump: + 14 => 1 + 13 => 1 + 12 => 1 17 => 0 16 => 0 - 14 => 0 - 13 => 0 - 12 => 0 MaxAge ListDump: 16 => 10980 14 => 10980 @@ -8465,10 +8465,10 @@ 12 => 5490 AgeLeft ListDump: 16 => 10980 - 14 => 10980 + 14 => 10979 17 => 7320 - 13 => 5490 - 12 => 5490 + 13 => 5489 + 12 => 5489 CurrentSpeed ListDump: 12 => 21 17 => 0 @@ -8486,7 +8486,7 @@ 16 => 0 14 => 0 13 => 0 - 12 => 0 + 12 => -1 ProfitLastYear ListDump: 17 => 0 16 => 0 diff --git a/src/ai/api/ai_changelog.hpp b/src/ai/api/ai_changelog.hpp index d554b44180..16b9505b77 100644 --- a/src/ai/api/ai_changelog.hpp +++ b/src/ai/api/ai_changelog.hpp @@ -18,6 +18,10 @@ * * 1.1.0 is not yet released. The following changes are not set in stone yet. * + * Other changes: + * \li AIRoad::BuildRoadStation now allows overbuilding + * \li AIRoad::BuildDriveThroughRoadStation now allows overbuilding + * * \b 1.0.0 * * 1.0.0 is not yet released. The following changes are not set in stone yet. diff --git a/src/lang/english.txt b/src/lang/english.txt index 2da50d2e45..643b518c05 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3425,6 +3425,7 @@ STR_ERROR_CAN_T_REMOVE_BUS_STATION :{WHITE}Can't re STR_ERROR_CAN_T_REMOVE_TRUCK_STATION :{WHITE}Can't remove lorry station... STR_ERROR_CAN_T_REMOVE_PASSENGER_TRAM_STATION :{WHITE}Can't remove passenger tram station... STR_ERROR_CAN_T_REMOVE_CARGO_TRAM_STATION :{WHITE}Can't remove freight tram station... +STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST :{WHITE}Must remove road stop first STR_ERROR_MUST_DEMOLISH_RAILROAD :{WHITE}Must demolish railway station first STR_ERROR_MUST_DEMOLISH_BUS_STATION_FIRST :{WHITE}Must demolish bus station first diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index 6a2216d7a4..c30f4108ba 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -804,11 +804,13 @@ 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 axis Axis of a drive-through road stop. + * @param station StationID to be queried and returned if available. * @param rts Road types to build. Bits already built at the tile will be removed. * @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, Axis axis, RoadTypes &rts) +static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags, uint invalid_dirs, bool is_drive_through, bool is_truck_stop, Axis axis, StationID *station, RoadTypes &rts) { CommandCost cost(EXPENSES_CONSTRUCTION); int allowed_z = -1; @@ -818,43 +820,64 @@ static CommandCost CheckFlatLandRoadStop(TileArea tile_area, DoCommandFlag flags if (ret.Failed()) return ret; cost.AddCost(ret); - bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile); - /* Road bits in the wrong direction. */ - if (build_over_road && (GetAllRoadBits(cur_tile) & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION); - - RoadTypes cur_rts = IsNormalRoadTile(cur_tile) ? GetRoadTypes(cur_tile) : ROADTYPES_NONE; - uint num_roadbits = 0; - if (build_over_road) { - /* There is a road, check if we can build road+tram stop over it. */ - if (HasBit(cur_rts, ROADTYPE_ROAD)) { - Owner road_owner = GetRoadOwner(cur_tile, ROADTYPE_ROAD); - if (road_owner == OWNER_TOWN) { - if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD); - } else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE && !CheckOwnership(road_owner)) { - return CMD_ERROR; + /* If station is set, then we have special handling to allow building on top of already existing stations. + * 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 != NULL && IsTileType(cur_tile, MP_STATION)) { + if (!IsRoadStop(cur_tile)) { + return ClearTile_Station(cur_tile, DC_AUTO); // Get error message. + } else { + if (is_truck_stop != IsTruckStop(cur_tile) || + is_drive_through != IsDriveThroughStopTile(cur_tile) || + HasBit(rts, ROADTYPE_TRAM) != HasBit(GetRoadTypes(cur_tile), ROADTYPE_TRAM)) { + return ClearTile_Station(cur_tile, DC_AUTO); // Get error message. } - num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_ROAD)); - } - - /* There is a tram, check if we can build road+tram stop over it. */ - if (HasBit(cur_rts, ROADTYPE_TRAM)) { - Owner tram_owner = GetRoadOwner(cur_tile, ROADTYPE_TRAM); - if (!_settings_game.construction.road_stop_on_competitor_road && tram_owner != OWNER_NONE && !CheckOwnership(tram_owner)) { - return CMD_ERROR; + StationID st = GetStationIndex(cur_tile); + if (*station == INVALID_STATION) { + *station = st; + } else if (*station != st) { + return_cmd_error(STR_ERROR_ADJOINS_MORE_THAN_ONE_EXISTING); } - num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_TRAM)); } - - /* Do not remove roadtypes! */ - rts |= cur_rts; } else { - ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); - if (ret.Failed()) return ret; - cost.AddCost(ret); - } + bool build_over_road = is_drive_through && IsNormalRoadTile(cur_tile); + /* Road bits in the wrong direction. */ + if (build_over_road && (GetAllRoadBits(cur_tile) & (axis == AXIS_X ? ROAD_Y : ROAD_X)) != 0) return_cmd_error(STR_ERROR_DRIVE_THROUGH_DIRECTION); - uint roadbits_to_build = CountBits(rts) * 2 - num_roadbits; - cost.AddCost(_price[PR_BUILD_ROAD] * roadbits_to_build); + RoadTypes cur_rts = IsNormalRoadTile(cur_tile) ? GetRoadTypes(cur_tile) : ROADTYPES_NONE; + uint num_roadbits = 0; + if (build_over_road) { + /* There is a road, check if we can build road+tram stop over it. */ + if (HasBit(cur_rts, ROADTYPE_ROAD)) { + Owner road_owner = GetRoadOwner(cur_tile, ROADTYPE_ROAD); + if (road_owner == OWNER_TOWN) { + if (!_settings_game.construction.road_stop_on_town_road) return_cmd_error(STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD); + } else if (!_settings_game.construction.road_stop_on_competitor_road && road_owner != OWNER_NONE && !CheckOwnership(road_owner)) { + return CMD_ERROR; + } + num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_ROAD)); + } + + /* There is a tram, check if we can build road+tram stop over it. */ + if (HasBit(cur_rts, ROADTYPE_TRAM)) { + Owner tram_owner = GetRoadOwner(cur_tile, ROADTYPE_TRAM); + if (!_settings_game.construction.road_stop_on_competitor_road && tram_owner != OWNER_NONE && !CheckOwnership(tram_owner)) { + return CMD_ERROR; + } + num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_TRAM)); + } + + /* Do not remove roadtypes! */ + rts |= cur_rts; + } else { + ret = DoCommand(cur_tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); + if (ret.Failed()) return ret; + cost.AddCost(ret); + } + + uint roadbits_to_build = CountBits(rts) * 2 - num_roadbits; + cost.AddCost(_price[PR_BUILD_ROAD] * roadbits_to_build); + } } return cost; @@ -1595,6 +1618,22 @@ static RoadStop **FindRoadStopSpot(bool truck_station, Station *st) } } +static CommandCost RemoveRoadStop(TileIndex tile, DoCommandFlag flags); + +/** + * Find a nearby station that joins this road stop. + * @param existing_stop an existing road stop we build over + * @param station_to_join the station to join to + * @param adjacent whether adjacent stations are allowed + * @param ta the area of the newly build station + * @param st 'return' pointer for the found station + * @return command cost with the error or 'okay' + */ +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); +} + /** Build a bus or truck stop. * @param tile Northernmost tile of the stop. * @param flags Operation to perform. @@ -1651,12 +1690,13 @@ 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]); - CommandCost ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << ddir : 1 << ddir, is_drive_through, DiagDirToAxis(ddir), rts); + StationID est = INVALID_STATION; + CommandCost ret = CheckFlatLandRoadStop(roadstop_area, flags, is_drive_through ? 5 << ddir : 1 << ddir, is_drive_through, type, DiagDirToAxis(ddir), &est, rts); if (ret.Failed()) return ret; cost.AddCost(ret); Station *st = NULL; - ret = FindJoiningStation(INVALID_STATION, station_to_join, HasBit(p2, 5), roadstop_area, &st); + ret = FindJoiningRoadStop(est, station_to_join, HasBit(p2, 5), roadstop_area, &st); if (ret.Failed()) return ret; /* Find a deleted station close to us */ @@ -1690,6 +1730,10 @@ CommandCost CmdBuildRoadStop(TileIndex tile, DoCommandFlag flags, uint32 p1, uin if (flags & DC_EXEC) { /* Check every tile in the area. */ TILE_AREA_LOOP(cur_tile, roadstop_area) { + if (IsTileType(cur_tile, MP_STATION) && IsRoadStop(cur_tile)) { + RemoveRoadStop(cur_tile, flags); + } + RoadStop *road_stop = new RoadStop(cur_tile); /* Insert into linked list of RoadStops. */ RoadStop **currstop = FindRoadStopSpot(type, st);