Changeset - r14642:03d1a1f40787
[Not reviewed]
master
0 6 0
terkhen - 15 years ago 2010-02-24 21:55:03
terkhen@openttd.org
(svn r19231) -Feature: Allow overbuilding of road stops.
6 files changed with 124 insertions and 44 deletions:
0 comments (0 inline, 0 general)
bin/ai/compat_0.7.nut
Show inline comments
 
@@ -249,12 +249,28 @@ AIEngine.GetPlaneType <- function(engine
 
{
 
	if (!AIEngine.IsBuildable(engine_id)) return -1;
 
	return AIEngine._GetPlaneType(engine_id);
 
}
 

	
 
_AIWaypointList <- AIWaypointList;
 
class AIWaypointList extends _AIWaypointList {
 
	constructor()
 
	{
 
		::_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);
 
}
bin/ai/compat_1.0.nut
Show inline comments
 
/* $Id$ */
 

	
 
/*
 
 * This file is part of OpenTTD.
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * 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 <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/* 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);
 
}
bin/ai/regression/regression.txt
Show inline comments
 
@@ -7250,25 +7250,25 @@
 
    IsBuildable():                 false
 
    DepotList
 
      Count():                     1
 
      Depot distance from (0,0) ListDump:
 
        33411 => 261
 
    RemoveRoadDepot():             true
 
    RemoveRoadDepot():             false
 
  Station
 
    IsRoadTile():                  false
 
    BuildRoadStation():            false
 
    BuildRoadStation():            false
 
    BuildRoadStation():            true
 
    BuildRoadStation():            false
 
    BuildRoadStation():            true
 
    IsStationTile():               true
 
    IsStationTile():               false
 
    HasRoadType(Road):             true
 
    HasRoadType(Tram):             false
 
    IsRoadTile():                  false
 
    GetDriveThroughBackTile():     -1
 
    GetRoadStationFrontTile():     33412
 
    IsRoadStationTile():           true
 
    IsDriveThroughRoadStationTile: false
 
    RemoveRoadStation():           true
 
    RemoveRoadStation():           false
 
  Station Types
 
@@ -8443,59 +8443,59 @@
 
    14 => 219
 
    16 => 204
 
    13 => 153
 
    12 => 153
 
    17 => 9
 
  UnitNumber ListDump:
 
    13 => 2
 
    17 => 1
 
    16 => 1
 
    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
 
    17 => 7320
 
    13 => 5490
 
    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
 
    16 => 0
 
    14 => 0
 
    13 => 0
 
  RunningCost ListDump:
 
    14 => 2756
 
    17 => 2296
 
    16 => 2296
 
    13 => 421
 
    12 => 421
 
  ProfitThisYear ListDump:
 
    17 => 0
 
    16 => 0
 
    14 => 0
 
    13 => 0
 
    12 => 0
 
    12 => -1
 
  ProfitLastYear ListDump:
 
    17 => 0
 
    16 => 0
 
    14 => 0
 
    13 => 0
 
    12 => 0
 
  CurrentValue ListDump:
 
    14 => 30761
 
    16 => 30468
 
    17 => 22265
 
    13 => 5947
 
    12 => 5947
src/ai/api/ai_changelog.hpp
Show inline comments
 
@@ -9,24 +9,28 @@
 

	
 
/** @file ai_changelog.hpp Lists all changes / additions to the API.
 
 *
 
 * Only new / renamed / deleted api functions will be listed here. A list of
 
 * bug fixes can be found in the normal changelog. Note that removed API
 
 * functions may still be available if you return an older API version
 
 * in GetAPIVersion() in info.nut.
 
 *
 
 * \b 1.1.0
 
 *
 
 * 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.
 
 *
 
 * API additions:
 
 * \li AIBaseStation
 
 * \li AIEngine::IsBuildable
 
 * \li AIEventCompanyAskMerger
 
 * \li AIIndustry::GetLastMonthTransportedPercentage
 
 * \li AIInfo::AICONFIG_INGAME
 
 * \li AIMarine::GetBuildCost
 
 * \li AIOrder::AIOF_GOTO_NEAREST_DEPOT
src/lang/english.txt
Show inline comments
 
@@ -3416,24 +3416,25 @@ STR_ERROR_TOO_CLOSE_TO_ANOTHER_DOCK     
 
STR_ERROR_TOO_CLOSE_TO_ANOTHER_AIRPORT                          :{WHITE}Too close to another airport
 
STR_ERROR_CAN_T_RENAME_STATION                                  :{WHITE}Can't rename station...
 
STR_ERROR_DRIVE_THROUGH_ON_TOWN_ROAD                            :{WHITE}... this is a town owned road
 
STR_ERROR_DRIVE_THROUGH_DIRECTION                               :{WHITE}... road facing in the wrong direction
 

	
 
# Station destruction related errors
 
STR_ERROR_CAN_T_REMOVE_PART_OF_STATION                          :{WHITE}Can't remove part of station...
 
STR_ERROR_MUST_REMOVE_RAILWAY_STATION_FIRST                     :{WHITE}Must remove railway station first
 
STR_ERROR_CAN_T_REMOVE_BUS_STATION                              :{WHITE}Can't remove bus station...
 
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
 
STR_ERROR_MUST_DEMOLISH_TRUCK_STATION_FIRST                     :{WHITE}Must demolish lorry station first
 
STR_ERROR_MUST_DEMOLISH_PASSENGER_TRAM_STATION_FIRST            :{WHITE}Must demolish passenger tram station first
 
STR_ERROR_MUST_DEMOLISH_CARGO_TRAM_STATION_FIRST                :{WHITE}Must demolish freight tram station first
 
STR_ERROR_MUST_DEMOLISH_DOCK_FIRST                              :{WHITE}Must demolish dock first
 
STR_ERROR_MUST_DEMOLISH_AIRPORT_FIRST                           :{WHITE}Must demolish airport first
 

	
 
# Waypoint related errors
 
STR_ERROR_WAYPOINT_ADJOINS_MORE_THAN_ONE_EXISTING               :{WHITE}Adjoins more than one existing waypoint
 
STR_ERROR_TOO_CLOSE_TO_ANOTHER_WAYPOINT                         :{WHITE}Too close to another waypoint
src/station_cmd.cpp
Show inline comments
 
@@ -795,75 +795,98 @@ static CommandCost CheckFlatLandRailStat
 
			cost.AddCost(ret);
 
		}
 
	}
 

	
 
	return cost;
 
}
 

	
 
/** Checks if a road stop can be built at the given tile.
 
 * @param tile_area Area to check.
 
 * @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;
 

	
 
	TILE_AREA_LOOP(cur_tile, tile_area) {
 
		CommandCost ret = CheckBuildableTile(cur_tile, invalid_dirs, allowed_z);
 
		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));
 
				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);
 
				}
 
			}
 

	
 
			/* 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;
 
		} else {
 
			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;
 
					}
 
					num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_ROAD));
 
				}
 
				num_roadbits += CountBits(GetRoadBits(cur_tile, ROADTYPE_TRAM));
 

	
 
				/* 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);
 
			}
 

	
 
			/* 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);
 
		}
 

	
 
		uint roadbits_to_build = CountBits(rts) * 2 - num_roadbits;
 
		cost.AddCost(_price[PR_BUILD_ROAD] * roadbits_to_build);
 
	}
 

	
 
	return cost;
 
}
 

	
 
/**
 
 * Check whether we can expand the rail part of the given station.
 
 * @param st the station to expand
 
 * @param new_ta the current (and if all is fine new) tile area of the rail part of the station
 
 * @param axis the axis of the newly build rail
 
 * @return true if we are allowed to extend
 
 */
 
@@ -1586,24 +1609,40 @@ static RoadStop **FindRoadStopSpot(bool 
 

	
 
	if (*primary_stop == NULL) {
 
		/* we have no roadstop of the type yet, so write a "primary stop" */
 
		return primary_stop;
 
	} else {
 
		/* there are stops already, so append to the end of the list */
 
		RoadStop *stop = *primary_stop;
 
		while (stop->next != NULL) stop = stop->next;
 
		return &stop->next;
 
	}
 
}
 

	
 
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<Station, STR_ERROR_MUST_REMOVE_ROAD_STOP_FIRST>(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.
 
 * @param p1 bit 0..7: Width of the road stop.
 
 *           bit 8..15: Lenght of the road stop.
 
 * @param p2 bit 0: 0 For bus stops, 1 for truck stops.
 
 *           bit 1: 0 For normal stops, 1 for drive-through.
 
 *           bit 2..3: The roadtypes.
 
 *           bit 5: Allow stations directly adjacent to other stations.
 
 *           bit 6..7: Entrance direction (DiagDirection).
 
 *           bit 16..31: Station ID to join (NEW_STATION if build new one).
 
 * @param text Unused.
 
@@ -1642,30 +1681,31 @@ CommandCost CmdBuildRoadStop(TileIndex t
 

	
 
	DiagDirection ddir = (DiagDirection)GB(p2, 6, 2);
 

	
 
	/* Safeguard the parameters. */
 
	if (!IsValidDiagDirection(ddir)) return CMD_ERROR;
 
	/* If it is a drive-through stop, check for valid axis. */
 
	if (is_drive_through && !IsValidAxis((Axis)ddir)) return CMD_ERROR;
 

	
 
	if (!CheckIfAuthorityAllowsNewStation(tile, flags)) return CMD_ERROR;
 

	
 
	/* 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 */
 
	if (st == NULL && reuse) st = GetClosestDeletedStation(tile);
 

	
 
	/* Check if this number of road stops can be allocated. */
 
	if (!RoadStop::CanAllocateItem(roadstop_area.w * roadstop_area.h)) return_cmd_error(type ? STR_ERROR_TOO_MANY_TRUCK_STOPS : STR_ERROR_TOO_MANY_BUS_STOPS);
 

	
 
	if (st != NULL) {
 
		if (st->owner != _current_company) {
 
			return_cmd_error(STR_ERROR_TOO_CLOSE_TO_ANOTHER_STATION);
 
		}
 
@@ -1681,24 +1721,28 @@ CommandCost CmdBuildRoadStop(TileIndex t
 
			st->town = ClosestTownFromTile(tile, UINT_MAX);
 
			st->string_id = GenerateStationName(st, tile, STATIONNAMING_ROAD);
 

	
 
			if (Company::IsValidID(_current_company)) {
 
				SetBit(st->town->have_ratings, _current_company);
 
			}
 
		}
 
	}
 

	
 
	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);
 
			*currstop = road_stop;
 

	
 
			if (type) {
 
				st->truck_station.Add(cur_tile);
 
			} else {
 
				st->bus_station.Add(cur_tile);
 
			}
 

	
 
			/* Initialize an empty station. */
0 comments (0 inline, 0 general)