File diff r26113:052b5113bfa8 → r26114:91e053fa2e46
src/road_cmd.cpp
Show inline comments
 
@@ -606,14 +606,13 @@ static CommandCost CheckRoadSlope(Slope 
 
 * Build a piece of road.
 
 * @param flags operation to perform
 
 * @param tile tile where to build road
 
 * @param p1 bit 0..3 road pieces to build (RoadBits)
 
 *           bit 4..9 road type
 
 *           bit 11..12 disallowed directions to toggle
 
 * @param p2 the town that is building the road (0 if not applicable)
 
 * @param text unused
 
 * @param pieces road pieces to build (RoadBits)
 
 * @param rt road type
 
 * @param toggle_drd disallowed directions to toggle
 
 * @param town_id the town that is building the road (0 if not applicable)
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdBuildRoad(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdBuildRoad(DoCommandFlag flags, TileIndex tile, RoadBits pieces, RoadType rt, DisallowedRoadDirections toggle_drd, TownID town_id)
 
{
 
	CompanyID company = _current_company;
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
@@ -623,10 +622,10 @@ CommandCost CmdBuildRoad(DoCommandFlag f
 

	
 
	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
 
	 * if a non-company is building the road */
 
	if ((Company::IsValidID(company) && p2 != 0) || (company == OWNER_TOWN && !Town::IsValidID(p2)) || (company == OWNER_DEITY && p2 != 0)) return CMD_ERROR;
 
	if ((Company::IsValidID(company) && town_id != 0) || (company == OWNER_TOWN && !Town::IsValidID(town_id)) || (company == OWNER_DEITY && town_id != 0)) return CMD_ERROR;
 
	if (company != OWNER_TOWN) {
 
		const Town *town = CalcClosestTownFromTile(tile);
 
		p2 = (town != nullptr) ? town->index : INVALID_TOWN;
 
		town_id = (town != nullptr) ? town->index : INVALID_TOWN;
 

	
 
		if (company == OWNER_DEITY) {
 
			company = OWNER_TOWN;
 
@@ -638,16 +637,10 @@ CommandCost CmdBuildRoad(DoCommandFlag f
 
		}
 
	}
 

	
 
	RoadBits pieces = Extract<RoadBits, 0, 4>(p1);
 

	
 
	/* do not allow building 'zero' road bits, code wouldn't handle it */
 
	if (pieces == ROAD_NONE) return CMD_ERROR;
 

	
 
	RoadType rt = Extract<RoadType, 4, 6>(p1);
 
	if (pieces == ROAD_NONE || !IsEnumValid(pieces) || !IsEnumValid(toggle_drd)) return CMD_ERROR;
 
	if (!ValParamRoadType(rt)) return CMD_ERROR;
 

	
 
	DisallowedRoadDirections toggle_drd = Extract<DisallowedRoadDirections, 11, 2>(p1);
 

	
 
	Slope tileh = GetTileSlope(tile);
 
	RoadTramType rtt = GetRoadTramType(rt);
 

	
 
@@ -785,7 +778,7 @@ CommandCost CmdBuildRoad(DoCommandFlag f
 

	
 
				/* Always add road to the roadtypes (can't draw without it) */
 
				bool reserved = HasBit(GetRailReservationTrackBits(tile), railtrack);
 
				MakeRoadCrossing(tile, company, company, GetTileOwner(tile), roaddir, GetRailType(tile), rtt == RTT_ROAD ? rt : INVALID_ROADTYPE, (rtt == RTT_TRAM) ? rt : INVALID_ROADTYPE, p2);
 
				MakeRoadCrossing(tile, company, company, GetTileOwner(tile), roaddir, GetRailType(tile), rtt == RTT_ROAD ? rt : INVALID_ROADTYPE, (rtt == RTT_TRAM) ? rt : INVALID_ROADTYPE, town_id);
 
				SetCrossingReservation(tile, reserved);
 
				UpdateLevelCrossing(tile, false);
 
				MarkTileDirtyByTile(tile);
 
@@ -870,7 +863,7 @@ do_clear:;
 
				if (HasPowerOnRoad(rt, existing_rt)) {
 
					rt = existing_rt;
 
				} else if (HasPowerOnRoad(existing_rt, rt)) {
 
					CommandCost ret = Command<CMD_CONVERT_ROAD>::Do(flags, tile, tile, rt, {});
 
					CommandCost ret = Command<CMD_CONVERT_ROAD>::Do(flags, tile, tile, rt);
 
					if (ret.Failed()) return ret;
 
					cost.AddCost(ret);
 
				} else {
 
@@ -895,7 +888,7 @@ do_clear:;
 
				if (existing == ROAD_NONE || rttype == ROAD_TILE_CROSSING) {
 
					SetRoadType(tile, rtt, rt);
 
					SetRoadOwner(tile, rtt, company);
 
					if (rtt == RTT_ROAD) SetTownIndex(tile, p2);
 
					if (rtt == RTT_ROAD) SetTownIndex(tile, town_id);
 
				}
 
				if (rttype != ROAD_TILE_CROSSING) SetRoadBits(tile, existing | pieces, rtt);
 
				break;
 
@@ -927,7 +920,7 @@ do_clear:;
 
			}
 

	
 
			default:
 
				MakeRoadNormal(tile, pieces, (rtt == RTT_ROAD) ? rt : INVALID_ROADTYPE, (rtt == RTT_TRAM) ? rt : INVALID_ROADTYPE, p2, company, company);
 
				MakeRoadNormal(tile, pieces, (rtt == RTT_ROAD) ? rt : INVALID_ROADTYPE, (rtt == RTT_TRAM) ? rt : INVALID_ROADTYPE, town_id, company, company);
 
				break;
 
		}
 

	
 
@@ -971,49 +964,40 @@ static bool CanConnectToRoad(TileIndex t
 
 * Build a long piece of road.
 
 * @param flags operation to perform
 
 * @param start_tile start tile of drag (the building cost will appear over this tile)
 
 * @param p1 end tile of drag
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1). Only used if bit 6 is set or if we are building a single tile
 
 * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2). Only used if bit 6 is set or if we are building a single tile
 
 * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4)
 
 * - p2 = (bit 3..8) - road type
 
 * - p2 = (bit 10) - set road direction
 
 * - p2 = (bit 11) - defines two different behaviors for this command:
 
 *      - 0 = Build up to an obstacle. Do not build the first and last roadbits unless they can be connected to something, or if we are building a single tile
 
 *      - 1 = Fail if an obstacle is found. Always take into account bit 0 and 1. This behavior is used for scripts
 
 * @param text unused
 
 * @param end_tile end tile of drag
 
 * @param rt road type
 
 * @param axis direction
 
 * @param drd set road direction
 
 * @param start_half start tile starts in the 2nd half of tile (p2 & 1). Only used if \c is_ai is set or if we are building a single tile
 
 * @param end_half end tile starts in the 2nd half of tile (p2 & 2). Only used if \c is_ai is set or if we are building a single tile
 
 * @param is_ai defines two different behaviors for this command:
 
 *      - false = Build up to an obstacle. Do not build the first and last roadbits unless they can be connected to something, or if we are building a single tile
 
 *      - true = Fail if an obstacle is found. Always take into account start_half and end_half. This behavior is used for scripts
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdBuildLongRoad(DoCommandFlag flags, TileIndex start_tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdBuildLongRoad(DoCommandFlag flags, TileIndex start_tile, TileIndex end_tile, RoadType rt, Axis axis, DisallowedRoadDirections drd, bool start_half, bool end_half, bool is_ai)
 
{
 
	DisallowedRoadDirections drd = DRD_NORTHBOUND;
 
	if (end_tile >= MapSize()) return CMD_ERROR;
 

	
 
	if (p1 >= MapSize()) return CMD_ERROR;
 
	TileIndex end_tile = p1;
 
	if (!ValParamRoadType(rt) || !IsEnumValid(axis) || !IsEnumValid(drd)) return CMD_ERROR;
 

	
 
	RoadType rt = Extract<RoadType, 3, 6>(p2);
 
	if (!ValParamRoadType(rt)) return CMD_ERROR;
 

	
 
	Axis axis = Extract<Axis, 2, 1>(p2);
 
	/* Only drag in X or Y direction dictated by the direction variable */
 
	if (axis == AXIS_X && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis
 
	if (axis == AXIS_Y && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis
 

	
 
	DiagDirection dir = AxisToDiagDir(axis);
 

	
 
	/* Swap direction, also the half-tile drag var (bit 0 and 1) */
 
	if (start_tile > end_tile || (start_tile == end_tile && HasBit(p2, 0))) {
 
	/* Swap direction, also the half-tile drag vars. */
 
	if (start_tile > end_tile || (start_tile == end_tile && start_half)) {
 
		dir = ReverseDiagDir(dir);
 
		p2 ^= 3;
 
		drd = DRD_SOUTHBOUND;
 
		std::swap(start_half, end_half);
 
		if (drd == DRD_NORTHBOUND || drd == DRD_SOUTHBOUND) drd ^= DRD_BOTH;
 
	}
 

	
 
	/* On the X-axis, we have to swap the initial bits, so they
 
	 * will be interpreted correctly in the GTTS. Furthermore
 
	 * when you just 'click' on one tile to build them. */
 
	if ((axis == AXIS_Y) == (start_tile == end_tile && HasBit(p2, 0) == HasBit(p2, 1))) drd ^= DRD_BOTH;
 
	/* No disallowed direction bits have to be toggled */
 
	if (!HasBit(p2, 10)) drd = DRD_NONE;
 
	if ((drd == DRD_NORTHBOUND || drd == DRD_SOUTHBOUND) && (axis == AXIS_Y) == (start_tile == end_tile && start_half == end_half)) drd ^= DRD_BOTH;
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	CommandCost last_error = CMD_ERROR;
 
@@ -1021,7 +1005,6 @@ CommandCost CmdBuildLongRoad(DoCommandFl
 
	bool had_bridge = false;
 
	bool had_tunnel = false;
 
	bool had_success = false;
 
	bool is_ai = HasBit(p2, 11);
 

	
 
	/* Start tile is the first tile clicked by the user. */
 
	for (;;) {
 
@@ -1037,11 +1020,11 @@ CommandCost CmdBuildLongRoad(DoCommandFl
 
			}
 
		} else {
 
			/* Road parts only have to be built at the start tile or at the end tile. */
 
			if (tile == end_tile && !HasBit(p2, 1)) bits &= DiagDirToRoadBits(ReverseDiagDir(dir));
 
			if (tile == start_tile && HasBit(p2, 0)) bits &= DiagDirToRoadBits(dir);
 
			if (tile == end_tile && !end_half) bits &= DiagDirToRoadBits(ReverseDiagDir(dir));
 
			if (tile == start_tile && start_half) bits &= DiagDirToRoadBits(dir);
 
		}
 

	
 
		CommandCost ret = Command<CMD_BUILD_ROAD>::Do(flags, tile, drd << 11 | rt << 4 | bits, 0, {});
 
		CommandCost ret = Command<CMD_BUILD_ROAD>::Do(flags, tile, bits, rt, drd, 0);
 
		if (ret.Failed()) {
 
			last_error = ret;
 
			if (last_error.GetErrorMessage() != STR_ERROR_ALREADY_BUILT) {
 
@@ -1080,36 +1063,28 @@ CommandCost CmdBuildLongRoad(DoCommandFl
 
 * Remove a long piece of road.
 
 * @param flags operation to perform
 
 * @param start_tile start tile of drag
 
 * @param p1 end tile of drag
 
 * @param p2 various bitstuffed elements
 
 * - p2 = (bit 0) - start tile starts in the 2nd half of tile (p2 & 1)
 
 * - p2 = (bit 1) - end tile starts in the 2nd half of tile (p2 & 2)
 
 * - p2 = (bit 2) - direction: 0 = along x-axis, 1 = along y-axis (p2 & 4)
 
 * - p2 = (bit 3 - 8) - road type
 
 * @param text unused
 
 * @param end_tile end tile of drag
 
 * @param rt road type
 
 * @param axis direction
 
 * @param start_half start tile starts in the 2nd half of tile
 
 * @param end_half end tile starts in the 2nd half of tile (p2 & 2)
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdRemoveLongRoad(DoCommandFlag flags, TileIndex start_tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdRemoveLongRoad(DoCommandFlag flags, TileIndex start_tile, TileIndex end_tile, RoadType rt, Axis axis, bool start_half, bool end_half)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 

	
 
	if (p1 >= MapSize()) return CMD_ERROR;
 
	if (end_tile >= MapSize()) return CMD_ERROR;
 
	if (!ValParamRoadType(rt) || !IsEnumValid(axis)) return CMD_ERROR;
 

	
 
	TileIndex end_tile = p1;
 
	RoadType rt = Extract<RoadType, 3, 6>(p2);
 
	if (!ValParamRoadType(rt)) return CMD_ERROR;
 

	
 
	Axis axis = Extract<Axis, 2, 1>(p2);
 
	/* Only drag in X or Y direction dictated by the direction variable */
 
	if (axis == AXIS_X && TileY(start_tile) != TileY(end_tile)) return CMD_ERROR; // x-axis
 
	if (axis == AXIS_Y && TileX(start_tile) != TileX(end_tile)) return CMD_ERROR; // y-axis
 

	
 
	/* Swap start and ending tile, also the half-tile drag var (bit 0 and 1) */
 
	if (start_tile > end_tile || (start_tile == end_tile && HasBit(p2, 0))) {
 
		TileIndex t = start_tile;
 
		start_tile = end_tile;
 
		end_tile = t;
 
		p2 ^= IsInsideMM(p2 & 3, 1, 3) ? 3 : 0;
 
	/* Swap start and ending tile, also the half-tile drag vars. */
 
	if (start_tile > end_tile || (start_tile == end_tile && start_half)) {
 
		std::swap(start_tile, end_tile);
 
		std::swap(start_half, end_half);
 
	}
 

	
 
	Money money_available = GetAvailableMoneyForCommand();
 
@@ -1121,8 +1096,8 @@ CommandCost CmdRemoveLongRoad(DoCommandF
 
	for (;;) {
 
		RoadBits bits = AxisToRoadBits(axis);
 

	
 
		if (tile == end_tile && !HasBit(p2, 1)) bits &= ROAD_NW | ROAD_NE;
 
		if (tile == start_tile && HasBit(p2, 0)) bits &= ROAD_SE | ROAD_SW;
 
		if (tile == end_tile && !end_half) bits &= ROAD_NW | ROAD_NE;
 
		if (tile == start_tile && start_half) bits &= ROAD_SE | ROAD_SW;
 

	
 
		/* try to remove the halves. */
 
		if (bits != 0) {
 
@@ -1132,7 +1107,7 @@ CommandCost CmdRemoveLongRoad(DoCommandF
 
				if (flags & DC_EXEC) {
 
					money_spent += ret.GetCost();
 
					if (money_spent > 0 && money_spent > money_available) {
 
						_additional_cash_required = Command<CMD_REMOVE_LONG_ROAD>::Do(flags & ~DC_EXEC, start_tile, end_tile, p2, {}).GetCost();
 
						_additional_cash_required = Command<CMD_REMOVE_LONG_ROAD>::Do(flags & ~DC_EXEC, start_tile, end_tile, rt, axis, start_half, end_half).GetCost();
 
						return cost;
 
					}
 
					RemoveRoad(tile, flags, bits, rtt, true, false);
 
@@ -2342,17 +2317,12 @@ static void ConvertRoadTypeOwner(TileInd
 
 *
 
 * @param flags operation to perform
 
 * @param tile end tile of road conversion drag
 
 * @param p1 start tile of drag
 
 * @param p2 various bitstuffed elements:
 
 * - p2 = (bit  0..5) new roadtype to convert to.
 
 * @param text unused
 
 * @param area_start start tile of drag
 
 * @param to_type new roadtype to convert to.
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdConvertRoad(DoCommandFlag flags, TileIndex tile, uint32 p1, uint32 p2, const std::string &text)
 
CommandCost CmdConvertRoad(DoCommandFlag flags, TileIndex tile, TileIndex area_start, RoadType to_type)
 
{
 
	RoadType to_type = Extract<RoadType, 0, 6>(p2);
 

	
 
	TileIndex area_start = p1;
 
	TileIndex area_end = tile;
 

	
 
	if (!ValParamRoadType(to_type)) return CMD_ERROR;