Changeset - r9341:c8e34c3b896e
[Not reviewed]
master
0 6 0
frosch - 16 years ago 2008-05-24 19:36:20
frosch@openttd.org
(svn r13233) -Fix: Replace some (incorrect) evaluations of TileOwner by RoadOwner.
-Fix: Before evaluating RoadOwner, check if the roadtype is present.
-Fix: Some places assumed that MP_ROAD means normal street.
6 files changed with 34 insertions and 28 deletions:
0 comments (0 inline, 0 general)
src/ai/default/default.cpp
Show inline comments
 
@@ -3670,197 +3670,197 @@ return_to_loop:;
 

	
 
static void AiStateRemoveStation(Player *p)
 
{
 
	// Remove stations that aren't in use by any vehicle
 
	const Order *ord;
 
	const Station *st;
 
	TileIndex tile;
 

	
 
	// Go to this state when we're done.
 
	_players_ai[p->index].state = AIS_1;
 

	
 
	// Get a list of all stations that are in use by a vehicle
 
	byte *in_use = MallocT<byte>(GetMaxStationIndex() + 1);
 
	memset(in_use, 0, GetMaxStationIndex() + 1);
 
	FOR_ALL_ORDERS(ord) {
 
		if (ord->IsType(OT_GOTO_STATION)) in_use[ord->GetDestination()] = 1;
 
	}
 

	
 
	// Go through all stations and delete those that aren't in use
 
	FOR_ALL_STATIONS(st) {
 
		if (st->owner == _current_player && !in_use[st->index] &&
 
				( (st->bus_stops != NULL && (tile = st->bus_stops->xy) != 0) ||
 
					(st->truck_stops != NULL && (tile = st->truck_stops->xy)) != 0 ||
 
					(tile = st->train_tile) != 0 ||
 
					(tile = st->dock_tile) != 0 ||
 
					(tile = st->airport_tile) != 0)) {
 
			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
		}
 
	}
 

	
 
	free(in_use);
 
}
 

	
 
static void AiRemovePlayerRailOrRoad(Player *p, TileIndex tile)
 
{
 
	TrackBits rails;
 

	
 
	if (IsTileType(tile, MP_RAILWAY)) {
 
		if (!IsTileOwner(tile, _current_player)) return;
 

	
 
		if (IsPlainRailTile(tile)) {
 
is_rail_crossing:;
 
			rails = GetRailTrackStatus(tile);
 

	
 
			if (rails == TRACK_BIT_HORZ || rails == TRACK_BIT_VERT) return;
 

	
 
			if (rails & TRACK_BIT_3WAY_NE) {
 
pos_0:
 
				if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(1, 0))) & TRACK_BIT_3WAY_SW) == 0) {
 
					_players_ai[p->index].cur_dir_a = DIAGDIR_NE;
 
					_players_ai[p->index].cur_tile_a = tile;
 
					_players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE;
 
					return;
 
				}
 
			}
 

	
 
			if (rails & TRACK_BIT_3WAY_SE) {
 
pos_1:
 
				if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(0, 1))) & TRACK_BIT_3WAY_NW) == 0) {
 
					_players_ai[p->index].cur_dir_a = DIAGDIR_SE;
 
					_players_ai[p->index].cur_tile_a = tile;
 
					_players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE;
 
					return;
 
				}
 
			}
 

	
 
			if (rails & TRACK_BIT_3WAY_SW) {
 
pos_2:
 
				if ((GetRailTrackStatus(TILE_MASK(tile + TileDiffXY(1, 0))) & TRACK_BIT_3WAY_NE) == 0) {
 
					_players_ai[p->index].cur_dir_a = DIAGDIR_SW;
 
					_players_ai[p->index].cur_tile_a = tile;
 
					_players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE;
 
					return;
 
				}
 
			}
 

	
 
			if (rails & TRACK_BIT_3WAY_NW) {
 
pos_3:
 
				if ((GetRailTrackStatus(TILE_MASK(tile - TileDiffXY(0, 1))) & TRACK_BIT_3WAY_SE) == 0) {
 
					_players_ai[p->index].cur_dir_a = DIAGDIR_NW;
 
					_players_ai[p->index].cur_tile_a = tile;
 
					_players_ai[p->index].state = AIS_REMOVE_SINGLE_RAIL_TILE;
 
					return;
 
				}
 
			}
 
		} else {
 
			static const byte _depot_bits[] = {0x19, 0x16, 0x25, 0x2A};
 

	
 
			DiagDirection dir = GetRailDepotDirection(tile);
 

	
 
			if (GetRailTrackStatus(tile + TileOffsByDiagDir(dir)) & _depot_bits[dir])
 
				return;
 

	
 
			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
		}
 
	} else if (IsTileType(tile, MP_ROAD)) {
 
		if (!IsTileOwner(tile, _current_player)) return;
 

	
 
		if (IsLevelCrossing(tile)) goto is_rail_crossing;
 

	
 
		if (IsRoadDepot(tile)) {
 
			if (!IsTileOwner(tile, _current_player)) return;
 

	
 
			DiagDirection dir;
 
			TileIndex t;
 

	
 
			// Check if there are any stations around.
 
			t = tile + TileDiffXY(-1, 0);
 
			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
 

	
 
			t = tile + TileDiffXY(1, 0);
 
			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
 

	
 
			t = tile + TileDiffXY(0, -1);
 
			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
 

	
 
			t = tile + TileDiffXY(0, 1);
 
			if (IsTileType(t, MP_STATION) && IsTileOwner(t, _current_player)) return;
 

	
 
			dir = GetRoadDepotDirection(tile);
 

	
 
			DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
			DoCommand(
 
				TILE_MASK(tile + TileOffsByDiagDir(dir)),
 
				DiagDirToRoadBits(ReverseDiagDir(dir)),
 
				0,
 
				DC_EXEC,
 
				CMD_REMOVE_ROAD);
 
		}
 
	} else if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 
		if (!IsTileOwner(tile, _current_player) ||
 
				!IsBridge(tile) ||
 
				GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) {
 
			return;
 
		}
 

	
 
		rails = TRACK_BIT_NONE;
 

	
 
		switch (GetTunnelBridgeDirection(tile)) {
 
			default:
 
			case DIAGDIR_NE: goto pos_2;
 
			case DIAGDIR_SE: goto pos_3;
 
			case DIAGDIR_SW: goto pos_0;
 
			case DIAGDIR_NW: goto pos_1;
 
		}
 
	}
 
}
 

	
 
static void AiStateRemoveTrack(Player *p)
 
{
 
	/* Was 1000 for standard 8x8 maps. */
 
	int num = MapSizeX() * 4;
 

	
 
	do {
 
		TileIndex tile = ++_players_ai[p->index].state_counter;
 

	
 
		// Iterated all tiles?
 
		if (tile >= MapSize()) {
 
			_players_ai[p->index].state = AIS_REMOVE_STATION;
 
			return;
 
		}
 

	
 
		// Remove player stuff in that tile
 
		AiRemovePlayerRailOrRoad(p, tile);
 
		if (_players_ai[p->index].state != AIS_REMOVE_TRACK) return;
 
	} while (--num);
 
}
 

	
 
static void AiStateRemoveSingleRailTile(Player *p)
 
{
 
	// Remove until we can't remove more.
 
	if (!AiRemoveTileAndGoForward(p)) _players_ai[p->index].state = AIS_REMOVE_TRACK;
 
}
 

	
 
static AiStateAction * const _ai_actions[] = {
 
	AiCase0,
 
	AiCase1,
 
	AiStateVehLoop,
 
	AiStateCheckReplaceVehicle,
 
	AiStateDoReplaceVehicle,
 
	AiStateWantNewRoute,
 

	
 
	AiStateBuildDefaultRailBlocks,
 
	AiStateBuildRail,
 
	AiStateBuildRailVeh,
 
	AiStateDeleteRailBlocks,
 

	
 
	AiStateBuildDefaultRoadBlocks,
 
	AiStateBuildRoad,
 
	AiStateBuildRoadVehicles,
 
	AiStateDeleteRoadBlocks,
 

	
 
	AiStateAirportStuff,
 
	AiStateBuildDefaultAirportBlocks,
 
	AiStateBuildAircraftVehicles,
 

	
 
	AiStateCheckShipStuff,
 
	AiStateBuildDefaultShipBlocks,
 
	AiStateDoShipStuff,
src/road_cmd.cpp
Show inline comments
 
@@ -80,240 +80,235 @@ static const uint32 VALID_LEVEL_CROSSING
 
#undef M
 

	
 
/* Invalid RoadBits on slopes  */
 
static const RoadBits _invalid_tileh_slopes_road[2][15] = {
 
	/* The inverse of the mixable RoadBits on a leveled slope */
 
	{
 
		ROAD_NONE,         // SLOPE_FLAT
 
		ROAD_NE | ROAD_SE, // SLOPE_W
 
		ROAD_NE | ROAD_NW, // SLOPE_S
 

	
 
		ROAD_NE,           // SLOPE_SW
 
		ROAD_NW | ROAD_SW, // SLOPE_E
 
		ROAD_NONE,         // SLOPE_EW
 

	
 
		ROAD_NW,           // SLOPE_SE
 
		ROAD_NONE,         // SLOPE_WSE
 
		ROAD_SE | ROAD_SW, // SLOPE_N
 

	
 
		ROAD_SE,           // SLOPE_NW
 
		ROAD_NONE,         // SLOPE_NS
 
		ROAD_NONE,         // SLOPE_ENW
 

	
 
		ROAD_SW,           // SLOPE_NE
 
		ROAD_NONE,         // SLOPE_SEN
 
		ROAD_NONE          // SLOPE_NWS
 
	},
 
	/* The inverse of the allowed straight roads on a slope
 
	 * (with and without a foundation). */
 
	{
 
		ROAD_NONE, // SLOPE_FLAT
 
		ROAD_NONE, // SLOPE_W    Foundation
 
		ROAD_NONE, // SLOPE_S    Foundation
 

	
 
		ROAD_Y,    // SLOPE_SW
 
		ROAD_NONE, // SLOPE_E    Foundation
 
		ROAD_ALL,  // SLOPE_EW
 

	
 
		ROAD_X,    // SLOPE_SE
 
		ROAD_ALL,  // SLOPE_WSE
 
		ROAD_NONE, // SLOPE_N    Foundation
 

	
 
		ROAD_X,    // SLOPE_NW
 
		ROAD_ALL,  // SLOPE_NS
 
		ROAD_ALL,  // SLOPE_ENW
 

	
 
		ROAD_Y,    // SLOPE_NE
 
		ROAD_ALL,  // SLOPE_SEN
 
		ROAD_ALL   // SLOPE_NW
 
	}
 
};
 

	
 
Foundation GetRoadFoundation(Slope tileh, RoadBits bits);
 

	
 
bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, Owner owner, bool *edge_road, RoadType rt)
 
{
 
	*edge_road = true;
 

	
 
	if (_game_mode == GM_EDITOR || remove == ROAD_NONE) return true;
 

	
 
	/* Water can always flood and towns can always remove "normal" road pieces.
 
	 * Towns are not be allowed to remove non "normal" road pieces, like tram
 
	 * tracks as that would result in trams that cannot turn. */
 
	if (_current_player == OWNER_WATER ||
 
			(rt == ROADTYPE_ROAD && !IsValidPlayer(_current_player))) return true;
 

	
 
	/* Only do the special processing if the road is owned
 
	 * by a town */
 
	if (owner != OWNER_TOWN) return (owner == OWNER_NONE) || CheckOwnership(owner);
 

	
 
	if (_cheats.magic_bulldozer.value) return true;
 

	
 
	/* Get a bitmask of which neighbouring roads has a tile */
 
	RoadBits n = ROAD_NONE;
 
	RoadBits present = GetAnyRoadBits(tile, rt);
 
	if (present & ROAD_NE && GetAnyRoadBits(TILE_ADDXY(tile, -1,  0), rt) & ROAD_SW) n |= ROAD_NE;
 
	if (present & ROAD_SE && GetAnyRoadBits(TILE_ADDXY(tile,  0,  1), rt) & ROAD_NW) n |= ROAD_SE;
 
	if (present & ROAD_SW && GetAnyRoadBits(TILE_ADDXY(tile,  1,  0), rt) & ROAD_NE) n |= ROAD_SW;
 
	if (present & ROAD_NW && GetAnyRoadBits(TILE_ADDXY(tile,  0, -1), rt) & ROAD_SE) n |= ROAD_NW;
 

	
 
	/* If 0 or 1 bits are set in n, or if no bits that match the bits to remove,
 
	 * then allow it */
 
	if (KillFirstBit(n) != ROAD_NONE && (n & remove) != ROAD_NONE) {
 
		*edge_road = false;
 
		/* you can remove all kind of roads with extra dynamite */
 
		if (_patches.extra_dynamite) return true;
 

	
 
		const Town *t = ClosestTownFromTile(tile, (uint)-1);
 

	
 
		SetDParam(0, t->index);
 
		_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
 
		return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
static bool CheckAllowRemoveRoad(TileIndex tile, RoadBits remove, bool *edge_road, RoadType rt)
 
{
 
	return CheckAllowRemoveRoad(tile, remove, GetRoadOwner(tile, rt), edge_road, rt);
 
}
 

	
 

	
 
/** Delete a piece of road.
 
 * @param tile tile where to remove road from
 
 * @param flags operation to perform
 
 * @param pieces roadbits to remove
 
 * @param rt roadtype to remove
 
 * @param crossing_check should we check if there is a tram track when we are removing road from crossing?
 
 */
 
static CommandCost RemoveRoad(TileIndex tile, uint32 flags, RoadBits pieces, RoadType rt, bool crossing_check, bool town_check = true)
 
{
 
	/* cost for removing inner/edge -roads */
 
	static const uint16 road_remove_cost[2] = {50, 18};
 

	
 
	/* true if the roadpiece was always removeable,
 
	 * false if it was a center piece. Affects town ratings drop */
 
	bool edge_road;
 

	
 
	RoadTypes rts = GetRoadTypes(tile);
 
	/* The tile doesn't have the given road type */
 
	if (!HasBit(rts, rt)) return CMD_ERROR;
 

	
 
	Town *t = NULL;
 
	switch (GetTileType(tile)) {
 
		case MP_ROAD:
 
			if (_game_mode != GM_EDITOR && GetRoadOwner(tile, rt) == OWNER_TOWN) t = GetTownByTile(tile);
 
			if (_game_mode != GM_EDITOR && IsRoadOwner(tile, rt, OWNER_TOWN)) t = GetTownByTile(tile);
 
			if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 
			break;
 

	
 
		case MP_STATION:
 
			if (!IsDriveThroughStopTile(tile)) return CMD_ERROR;
 
			if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 
			break;
 

	
 
		case MP_TUNNELBRIDGE:
 
			if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
 
			if (GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL) return CMD_ERROR;
 
			break;
 

	
 
		default:
 
			return CMD_ERROR;
 
	}
 

	
 
	RoadTypes rts = GetRoadTypes(tile);
 
	/* The tile doesn't have the given road type */
 
	if (!HasBit(rts, rt)) return CMD_ERROR;
 

	
 
	if (!CheckAllowRemoveRoad(tile, pieces, &edge_road, rt)) return CMD_ERROR;
 
	if (!CheckAllowRemoveRoad(tile, pieces, GetRoadOwner(tile, rt), &edge_road, rt)) return CMD_ERROR;
 

	
 
	/* check if you're allowed to remove the street owned by a town
 
	 * removal allowance depends on difficulty setting */
 
	if (town_check && !CheckforTownRating(flags, t, ROAD_REMOVE)) return CMD_ERROR;
 

	
 
	if (!IsTileType(tile, MP_ROAD)) {
 
		/* If it's the last roadtype, just clear the whole tile */
 
		if (rts == RoadTypeToRoadTypes(rt)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 

	
 
		CommandCost cost(EXPENSES_CONSTRUCTION);
 
		if (IsTileType(tile, MP_TUNNELBRIDGE)) {
 
			TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
 
			/* Pay for *every* tile of the bridge or tunnel */
 
			cost.AddCost((GetTunnelBridgeLength(other_end, tile) + 2) * _price.remove_road);
 
			if (flags & DC_EXEC) {
 
				SetRoadTypes(other_end, GetRoadTypes(other_end) & ~RoadTypeToRoadTypes(rt));
 
				SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt));
 

	
 
				/* Mark tiles diry that have been repaved */
 
				MarkTileDirtyByTile(tile);
 
				MarkTileDirtyByTile(other_end);
 
				if (IsBridge(tile)) {
 
					TileIndexDiff delta = TileOffsByDiagDir(GetTunnelBridgeDirection(tile));
 

	
 
					for (TileIndex t = tile + delta; t != other_end; t += delta) MarkTileDirtyByTile(t);
 
				}
 
			}
 
		} else {
 
			cost.AddCost(_price.remove_road);
 
			if (flags & DC_EXEC) {
 
				SetRoadTypes(tile, GetRoadTypes(tile) & ~RoadTypeToRoadTypes(rt));
 
				MarkTileDirtyByTile(tile);
 
			}
 
		}
 
		return cost;
 
	}
 

	
 
	switch (GetRoadTileType(tile)) {
 
		case ROAD_TILE_NORMAL: {
 
			const Slope tileh = GetTileSlope(tile, NULL);
 
			RoadBits present = GetRoadBits(tile, rt);
 
			const RoadBits other = GetOtherRoadBits(tile, rt);
 
			const Foundation f = GetRoadFoundation(tileh, present);
 

	
 
			if (HasRoadWorks(tile) && _current_player != OWNER_WATER) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
 

	
 
			/* Autocomplete to a straight road
 
			 * @li on steep slopes
 
			 * @li if the bits of the other roadtypes result in another foundation
 
			 * @li if build on slopes is disabled */
 
			if (IsSteepSlope(tileh) || (IsStraightRoad(other) &&
 
					(other & _invalid_tileh_slopes_road[0][tileh & SLOPE_ELEVATED]) != ROAD_NONE) ||
 
					(tileh != SLOPE_FLAT && !_patches.build_on_slopes)) {
 
				pieces |= MirrorRoadBits(pieces);
 
			}
 

	
 
			/* limit the bits to delete to the existing bits. */
 
			pieces &= present;
 
			if (pieces == ROAD_NONE) return CMD_ERROR;
 

	
 
			/* Now set present what it will be after the remove */
 
			present ^= pieces;
 

	
 
			/* Check for invalid RoadBit combinations on slopes */
 
			if (tileh != SLOPE_FLAT && present != ROAD_NONE &&
 
					(present & _invalid_tileh_slopes_road[0][tileh & SLOPE_ELEVATED]) == present) {
 
				return CMD_ERROR;
 
			}
 

	
 
			if (town_check) ChangeTownRating(t, -road_remove_cost[(byte)edge_road], RATING_ROAD_MINIMUM);
 
			if (flags & DC_EXEC) {
 
				if (HasRoadWorks(tile)) {
 
					/* flooding tile with road works, don't forget to remove the effect vehicle too */
 
					assert(_current_player == OWNER_WATER);
 
					Vehicle *v;
 
					FOR_ALL_VEHICLES(v) {
 
						if (v->type == VEH_EFFECT && TileVirtXY(v->x_pos, v->y_pos) == tile) {
 
							delete v;
 
						}
 
					}
 
				}
 
				if (present == ROAD_NONE) {
 
					RoadTypes rts = GetRoadTypes(tile) & ComplementRoadTypes(RoadTypeToRoadTypes(rt));
 
					if (rts == ROADTYPES_NONE) {
 
						/* Includes MarkTileDirtyByTile() */
 
						DoClearSquare(tile);
 
					} else {
 
						SetRoadBits(tile, ROAD_NONE, rt);
 
						SetRoadTypes(tile, rts);
 
						MarkTileDirtyByTile(tile);
 
					}
 
				} else {
 
					/* When bits are removed, you *always* end up with something that
 
					 * is not a complete straight road tile. However, trams do not have
 
					 * onewayness, so they cannot remove it either. */
 
					if (rt != ROADTYPE_TRAM) SetDisallowedRoadDirections(tile, DRD_NONE);
 
@@ -408,193 +403,193 @@ static CommandCost CheckRoadSlope(Slope 
 
		 * roads are allowed here. */
 
		existing |= other;
 

	
 
		if ((existing == ROAD_NONE || existing == *pieces) && IsStraightRoad(*pieces)) {
 
			return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
		}
 
		return CMD_ERROR;
 
	}
 

	
 
	/* Save the merge of all bits of the current type */
 
	RoadBits type_bits = existing | *pieces;
 

	
 
	/* Roads on slopes */
 
	if (_patches.build_on_slopes && (_invalid_tileh_slopes_road[0][tileh] & (other | type_bits)) == ROAD_NONE) {
 

	
 
		/* If we add leveling we've got to pay for it */
 
		if ((other | existing) == ROAD_NONE) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 

	
 
		return CommandCost();
 
	}
 

	
 
	/* Autocomplete uphill roads */
 
	*pieces |= MirrorRoadBits(*pieces);
 
	type_bits = existing | *pieces;
 

	
 
	/* Uphill roads */
 
	if (IsStraightRoad(type_bits) && (other == type_bits || other == ROAD_NONE) &&
 
			(_invalid_tileh_slopes_road[1][tileh] & (other | type_bits)) == ROAD_NONE) {
 

	
 
		/* Slopes with foundation ? */
 
		if (IsSlopeWithOneCornerRaised(tileh)) {
 

	
 
			/* Prevent build on slopes if it isn't allowed */
 
			if (_patches.build_on_slopes) {
 

	
 
				/* If we add foundation we've got to pay for it */
 
				if ((other | existing) == ROAD_NONE) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 

	
 
				return CommandCost();
 
			}
 
		} else {
 
			if (CountBits(existing) == 1) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
			return CommandCost();
 
		}
 
	}
 
	return CMD_ERROR;
 
}
 

	
 
/** Build a piece of road.
 
 * @param tile tile where to build road
 
 * @param flags operation to perform
 
 * @param p1 bit 0..3 road pieces to build (RoadBits)
 
 *           bit 4..5 road type
 
 *           bit 6..7 disallowed directions to toggle
 
 * @param p2 the town that is building the road (0 if not applicable)
 
 */
 
CommandCost CmdBuildRoad(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 

	
 
	RoadBits existing = ROAD_NONE;
 
	RoadBits other_bits = ROAD_NONE;
 

	
 
	/* Road pieces are max 4 bitset values (NE, NW, SE, SW) and town can only be non-zero
 
	 * if a non-player is building the road */
 
	if ((IsValidPlayer(_current_player) && p2 != 0) || (_current_player == OWNER_TOWN && !IsValidTownID(p2))) return CMD_ERROR;
 

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

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

	
 
	RoadType rt = (RoadType)GB(p1, 4, 2);
 
	if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR;
 

	
 
	DisallowedRoadDirections toggle_drd = (DisallowedRoadDirections)GB(p1, 6, 2);
 

	
 
	Slope tileh = GetTileSlope(tile, NULL);
 

	
 
	switch (GetTileType(tile)) {
 
		case MP_ROAD:
 
			switch (GetRoadTileType(tile)) {
 
				case ROAD_TILE_NORMAL: {
 
					if (HasRoadWorks(tile)) return_cmd_error(STR_ROAD_WORKS_IN_PROGRESS);
 

	
 
					other_bits = GetOtherRoadBits(tile, rt);
 
					if (!HasTileRoadType(tile, rt)) break;
 

	
 
					existing = GetRoadBits(tile, rt);
 
					bool crossing = !IsStraightRoad(existing | pieces);
 
					if (rt != ROADTYPE_TRAM && (GetDisallowedRoadDirections(tile) != DRD_NONE || toggle_drd != DRD_NONE) && crossing) {
 
						/* Junctions cannot be one-way */
 
						return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION);
 
					}
 
					if ((existing & pieces) == pieces) {
 
						/* We only want to set the (dis)allowed road directions */
 
						if (toggle_drd != DRD_NONE && rt != ROADTYPE_TRAM && GetRoadOwner(tile, ROADTYPE_ROAD) == _current_player) {
 
						if (toggle_drd != DRD_NONE && rt != ROADTYPE_TRAM && IsRoadOwner(tile, ROADTYPE_ROAD, _current_player)) {
 
							if (crossing) return_cmd_error(STR_ERR_ONEWAY_ROADS_CAN_T_HAVE_JUNCTION);
 

	
 
							if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 

	
 
							/* Ignore half built tiles */
 
							if (flags & DC_EXEC && rt != ROADTYPE_TRAM && IsStraightRoad(existing)) {
 
								SetDisallowedRoadDirections(tile, GetDisallowedRoadDirections(tile) ^ toggle_drd);
 
								MarkTileDirtyByTile(tile);
 
							}
 
							return CommandCost();
 
						}
 
						return_cmd_error(STR_1007_ALREADY_BUILT);
 
					}
 
				} break;
 

	
 
				case ROAD_TILE_CROSSING:
 
					if (HasTileRoadType(tile, rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
 
					other_bits = GetCrossingRoadBits(tile);
 
					if (pieces & ComplementRoadBits(other_bits)) goto do_clear;
 
					break;
 

	
 
				default:
 
				case ROAD_TILE_DEPOT:
 
					goto do_clear;
 
			}
 
			break;
 

	
 
		case MP_RAILWAY: {
 
			if (IsSteepSlope(tileh)) {
 
				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 
			}
 

	
 
			/* Level crossings may only be built on these slopes */
 
			if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) {
 
				return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 
			}
 

	
 
			if (GetRailTileType(tile) != RAIL_TILE_NORMAL) goto do_clear;
 

	
 
			Axis roaddir;
 
			switch (GetTrackBits(tile)) {
 
				case TRACK_BIT_X:
 
					if (pieces & ROAD_X) goto do_clear;
 
					roaddir = AXIS_Y;
 
					break;
 

	
 
				case TRACK_BIT_Y:
 
					if (pieces & ROAD_Y) goto do_clear;
 
					roaddir = AXIS_X;
 
					break;
 

	
 
				default: goto do_clear;
 
			}
 

	
 
			if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 

	
 
			if (flags & DC_EXEC) {
 
				YapfNotifyTrackLayoutChange(tile, FindFirstTrack(GetTrackBits(tile)));
 
				/* Always add road to the roadtypes (can't draw without it) */
 
				MakeRoadCrossing(tile, _current_player, _current_player, _current_player, GetTileOwner(tile), roaddir, GetRailType(tile), RoadTypeToRoadTypes(rt) | ROADTYPES_ROAD, p2);
 
				UpdateLevelCrossing(tile, false);
 
				MarkTileDirtyByTile(tile);
 
			}
 
			return CommandCost(EXPENSES_CONSTRUCTION, _price.build_road * (rt == ROADTYPE_ROAD ? 2 : 4));
 
		}
 

	
 
		case MP_STATION:
 
			if (!IsDriveThroughStopTile(tile)) return CMD_ERROR;
 
			if (HasTileRoadType(tile, rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
 
			break;
 

	
 
		case MP_TUNNELBRIDGE:
 
			if (GetTunnelBridgeTransportType(tile) != TRANSPORT_ROAD) return CMD_ERROR;
 
			if (HasTileRoadType(tile, rt)) return_cmd_error(STR_1007_ALREADY_BUILT);
 
			/* Don't allow adding roadtype to the bridge/tunnel when vehicles are already driving on it */
 
			if (GetVehicleTunnelBridge(tile, GetOtherTunnelBridgeEnd(tile)) != NULL) return CMD_ERROR;
 
			break;
 

	
 
		default: {
 
do_clear:;
 
			CommandCost ret = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
			if (CmdFailed(ret)) return ret;
 
			cost.AddCost(ret);
 
		} break;
 
	}
 

	
 
	if (other_bits != pieces) {
 
		/* Check the foundation/slopes when adding road/tram bits */
 
		CommandCost ret = CheckRoadSlope(tileh, &pieces, existing, other_bits);
 
		/* Return an error if we need to build a foundation (ret != 0) but the
 
		 * current patch-setting is turned off (or stupid AI@work) */
 
		if (CmdFailed(ret) || (ret.GetCost() != 0 && !_patches.build_on_slopes)) {
 
			return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 
		}
 
		cost.AddCost(ret);
 
	}
 
@@ -801,193 +796,193 @@ CommandCost CmdRemoveLongRoad(TileIndex 
 
	for (;;) {
 
		RoadBits bits = HasBit(p2, 2) ? ROAD_Y : ROAD_X;
 

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

	
 
		/* try to remove the halves. */
 
		if (bits != 0) {
 
			CommandCost ret = RemoveRoad(tile, flags & ~DC_EXEC, bits, rt, true);
 
			if (CmdSucceeded(ret)) {
 
				if (flags & DC_EXEC) {
 
					money -= ret.GetCost();
 
					if (money < 0) {
 
						_additional_cash_required = DoCommand(end_tile, start_tile, p2, flags & ~DC_EXEC, CMD_REMOVE_LONG_ROAD).GetCost();
 
						return cost;
 
					}
 
					RemoveRoad(tile, flags, bits, rt, true, false);
 
				}
 
				cost.AddCost(ret);
 
			}
 
		}
 

	
 
		if (tile == end_tile) break;
 

	
 
		tile += HasBit(p2, 2) ? TileDiffXY(0, 1) : TileDiffXY(1, 0);
 
	}
 

	
 
	return (cost.GetCost() == 0) ? CMD_ERROR : cost;
 
}
 

	
 
/** Build a road depot.
 
 * @param tile tile where to build the depot
 
 * @param flags operation to perform
 
 * @param p1 bit 0..1 entrance direction (DiagDirection)
 
 *           bit 2..3 road type
 
 * @param p2 unused
 
 *
 
 * @todo When checking for the tile slope,
 
 * distingush between "Flat land required" and "land sloped in wrong direction"
 
 */
 
CommandCost CmdBuildRoadDepot(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	DiagDirection dir = Extract<DiagDirection, 0>(p1);
 
	RoadType rt = (RoadType)GB(p1, 2, 2);
 

	
 
	if (!IsValidRoadType(rt) || !ValParamRoadType(rt)) return CMD_ERROR;
 

	
 
	Slope tileh = GetTileSlope(tile, NULL);
 
	if (tileh != SLOPE_FLAT && (
 
				!_patches.build_on_slopes ||
 
				IsSteepSlope(tileh) ||
 
				!CanBuildDepotByTileh(dir, tileh)
 
			)) {
 
		return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
 
	}
 

	
 
	CommandCost cost = DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
	if (CmdFailed(cost)) return CMD_ERROR;
 

	
 
	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);
 

	
 
	if (!Depot::CanAllocateItem()) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		Depot *dep = new Depot(tile);
 
		dep->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
 

	
 
		MakeRoadDepot(tile, _current_player, dir, rt);
 
		MarkTileDirtyByTile(tile);
 
	}
 
	return cost.AddCost(_price.build_road_depot);
 
}
 

	
 
static CommandCost RemoveRoadDepot(TileIndex tile, uint32 flags)
 
{
 
	if (!CheckTileOwnership(tile) && _current_player != OWNER_WATER) return CMD_ERROR;
 

	
 
	if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		DoClearSquare(tile);
 
		delete GetDepotByTile(tile);
 
	}
 

	
 
	return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_road_depot);
 
}
 

	
 
static CommandCost ClearTile_Road(TileIndex tile, byte flags)
 
{
 
	switch (GetRoadTileType(tile)) {
 
		case ROAD_TILE_NORMAL: {
 
			RoadBits b = GetAllRoadBits(tile);
 

	
 
			/* Clear the road if only one piece is on the tile OR the AI tries
 
			 * to clear town road OR we are not using the DC_AUTO flag */
 
			if ((CountBits(b) == 1 && GetRoadBits(tile, ROADTYPE_TRAM) == ROAD_NONE) ||
 
			    ((flags & DC_AI_BUILDING) && IsTileOwner(tile, OWNER_TOWN)) ||
 
			    ((flags & DC_AI_BUILDING) && GetOtherRoadBits(tile, ROADTYPE_ROAD) == ROAD_NONE && IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)) ||
 
			    !(flags & DC_AUTO)
 
				) {
 
				RoadTypes rts = GetRoadTypes(tile);
 
				CommandCost ret(EXPENSES_CONSTRUCTION);
 
				for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
 
					if (HasBit(rts, rt)) {
 
						CommandCost tmp_ret = RemoveRoad(tile, flags, GetRoadBits(tile, rt), rt, true);
 
						if (CmdFailed(tmp_ret)) return tmp_ret;
 
						ret.AddCost(tmp_ret);
 
					}
 
				}
 
				return ret;
 
			}
 
			return_cmd_error(STR_1801_MUST_REMOVE_ROAD_FIRST);
 
		}
 

	
 
		case ROAD_TILE_CROSSING: {
 
			RoadTypes rts = GetRoadTypes(tile);
 
			CommandCost ret(EXPENSES_CONSTRUCTION);
 

	
 
			if (flags & DC_AUTO) return_cmd_error(STR_1801_MUST_REMOVE_ROAD_FIRST);
 

	
 
			/* Must iterate over the roadtypes in a reverse manner because
 
			 * tram tracks must be removed before the road bits. */
 
			RoadType rt = ROADTYPE_HWAY;
 
			do {
 
				if (HasBit(rts, rt)) {
 
					CommandCost tmp_ret = RemoveRoad(tile, flags, GetCrossingRoadBits(tile), rt, false);
 
					if (CmdFailed(tmp_ret)) return tmp_ret;
 
					ret.AddCost(tmp_ret);
 
				}
 
			} while (rt-- != ROADTYPE_ROAD);
 

	
 
			if (flags & DC_EXEC) {
 
				DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
			}
 
			return ret;
 
		}
 

	
 
		default:
 
		case ROAD_TILE_DEPOT:
 
			if (flags & DC_AUTO) {
 
				return_cmd_error(STR_2004_BUILDING_MUST_BE_DEMOLISHED);
 
			}
 
			return RemoveRoadDepot(tile, flags);
 
	}
 
}
 

	
 

	
 
struct DrawRoadTileStruct {
 
	uint16 image;
 
	byte subcoord_x;
 
	byte subcoord_y;
 
};
 

	
 
#include "table/road_land.h"
 

	
 
/**
 
 * Get the foundationtype of a RoadBits Slope combination
 
 *
 
 * @param tileh The Slope part
 
 * @param bits The RoadBits part
 
 * @return The resulting Foundation
 
 */
 
Foundation GetRoadFoundation(Slope tileh, RoadBits bits)
 
{
 
	/* Flat land and land without a road doesn't require a foundation */
 
	if (tileh == SLOPE_FLAT || bits == ROAD_NONE) return FOUNDATION_NONE;
 

	
 
	if (!IsSteepSlope(tileh)) {
 
		/* Leveled RoadBits on a slope */
 
		if ((_invalid_tileh_slopes_road[0][tileh] & bits) == ROAD_NONE) return FOUNDATION_LEVELED;
 

	
 
		/* Straight roads without foundation on a slope */
 
		if (!IsSlopeWithOneCornerRaised(tileh) &&
 
				(_invalid_tileh_slopes_road[1][tileh] & bits) == ROAD_NONE)
 
			return FOUNDATION_NONE;
 
	}
 

	
 
	/* Roads on steep Slopes or on Slopes with one corner raised */
 
	return (bits == ROAD_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y);
 
}
 

	
 
const byte _road_sloped_sprites[14] = {
 
	0,  0,  2,  0,
 
	0,  1,  0,  0,
 
	3,  0,  0,  0,
 
	0,  0
 
};
 

	
 
/**
 
 * Whether to draw unpaved roads regardless of the town zone.
 
 * By default, OpenTTD always draws roads as unpaved if they are on a desert
 
 * tile or above the snowline. Newgrf files, however, can set a bit that allows
 
 * paved roads to be built on desert tiles as they would be on grassy tiles.
 
 *
 
@@ -1456,172 +1451,170 @@ static void GetTileDesc_Road(TileIndex t
 
			RoadTypes rts = GetRoadTypes(tile);
 
			rail_owner = GetTileOwner(tile);
 
			if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
 
			if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
 
			break;
 
		}
 

	
 
		case ROAD_TILE_DEPOT:
 
			td->str = STR_1817_ROAD_VEHICLE_DEPOT;
 
			road_owner = GetTileOwner(tile); // Tile has only one owner, roadtype does not matter
 
			break;
 

	
 
		default: {
 
			RoadTypes rts = GetRoadTypes(tile);
 
			td->str = (HasBit(rts, ROADTYPE_ROAD) ? _road_tile_strings[GetRoadside(tile)] : STR_TRAMWAY);
 
			if (HasBit(rts, ROADTYPE_ROAD)) road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
 
			if (HasBit(rts, ROADTYPE_TRAM)) tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
 
			break;
 
		}
 
	}
 

	
 
	/* Now we have to discover, if the tile has only one owner or many:
 
	 *   - Find a first_owner of the tile. (Currently road or tram must be present, but this will break when the third type becomes available)
 
	 *   - Compare the found owner with the other owners, and test if they differ.
 
	 * Note: If road exists it will be the first_owner.
 
	 */
 
	Owner first_owner = (road_owner == INVALID_OWNER ? tram_owner : road_owner);
 
	bool mixed_owners = (tram_owner != INVALID_OWNER && tram_owner != first_owner) || (rail_owner != INVALID_OWNER && rail_owner != first_owner);
 

	
 
	if (mixed_owners) {
 
		/* Multiple owners */
 
		td->owner_type[0] = (rail_owner == INVALID_OWNER ? STR_NULL : STR_RAIL_OWNER);
 
		td->owner[0] = rail_owner;
 
		td->owner_type[1] = (road_owner == INVALID_OWNER ? STR_NULL : STR_ROAD_OWNER);
 
		td->owner[1] = road_owner;
 
		td->owner_type[2] = (tram_owner == INVALID_OWNER ? STR_NULL : STR_TRAM_OWNER);
 
		td->owner[2] = tram_owner;
 
	} else {
 
		/* One to rule them all */
 
		td->owner[0] = first_owner;
 
	}
 
}
 

	
 
/**
 
 * Given the direction the road depot is pointing, this is the direction the
 
 * vehicle should be travelling in in order to enter the depot.
 
 */
 
static const byte _roadveh_enter_depot_dir[4] = {
 
	TRACKDIR_X_SW, TRACKDIR_Y_NW, TRACKDIR_X_NE, TRACKDIR_Y_SE
 
};
 

	
 
static VehicleEnterTileStatus VehicleEnter_Road(Vehicle *v, TileIndex tile, int x, int y)
 
{
 
	switch (GetRoadTileType(tile)) {
 
		case ROAD_TILE_CROSSING:
 
			if (v->type == VEH_TRAIN) {
 
				/* it should be barred */
 
				assert(IsCrossingBarred(tile));
 
			}
 
			break;
 

	
 
		case ROAD_TILE_DEPOT:
 
			if (v->type == VEH_ROAD &&
 
					v->u.road.frame == 11 &&
 
					_roadveh_enter_depot_dir[GetRoadDepotDirection(tile)] == v->u.road.state) {
 
				v->u.road.state = RVSB_IN_DEPOT;
 
				v->vehstatus |= VS_HIDDEN;
 
				v->direction = ReverseDir(v->direction);
 
				if (v->Next() == NULL) VehicleEnterDepot(v);
 
				v->tile = tile;
 

	
 
				InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
 
				return VETSB_ENTERED_WORMHOLE;
 
			}
 
			break;
 

	
 
		default: break;
 
	}
 
	return VETSB_CONTINUE;
 
}
 

	
 

	
 
static void ChangeTileOwner_Road(TileIndex tile, PlayerID old_player, PlayerID new_player)
 
{
 
	if (IsRoadDepot(tile)) {
 
		if (GetTileOwner(tile) == old_player) {
 
			if (new_player == PLAYER_SPECTATOR) {
 
				DoCommand(tile, 0, 0, DC_EXEC | DC_BANKRUPT, CMD_LANDSCAPE_CLEAR);
 
			} else {
 
				SetTileOwner(tile, new_player);
 
			}
 
		}
 
		return;
 
	}
 

	
 
	for (RoadType rt = ROADTYPE_ROAD; rt < ROADTYPE_END; rt++) {
 
		/* ROADTYPE_ROAD denotes the tile owner, so update it too */
 
		if (rt != ROADTYPE_ROAD && !HasTileRoadType(tile, rt)) continue;
 

	
 
		/* Update all roadtypes, no matter if they are present */
 
		if (GetRoadOwner(tile, rt) == old_player) {
 
			SetRoadOwner(tile, rt, new_player == PLAYER_SPECTATOR ? OWNER_NONE : new_player);
 
		}
 
	}
 

	
 
	if (IsLevelCrossing(tile)) {
 
		if (GetTileOwner(tile) == old_player) {
 
			if (new_player == PLAYER_SPECTATOR) {
 
				DoCommand(tile, 0, GetCrossingRailTrack(tile), DC_EXEC | DC_BANKRUPT, CMD_REMOVE_SINGLE_RAIL);
 
			} else {
 
				SetTileOwner(tile, new_player);
 
			}
 
		}
 
	}
 
}
 

	
 
static CommandCost TerraformTile_Road(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
 
{
 
	if (_patches.build_on_slopes && AutoslopeEnabled()) {
 
		switch (GetRoadTileType(tile)) {
 
			case ROAD_TILE_CROSSING:
 
				if (!IsSteepSlope(tileh_new) && (GetTileMaxZ(tile) == z_new + GetSlopeMaxZ(tileh_new)) && HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
				break;
 

	
 
			case ROAD_TILE_DEPOT:
 
				if (AutoslopeCheckForEntranceEdge(tile, z_new, tileh_new, GetRoadDepotDirection(tile))) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
				break;
 

	
 
			case ROAD_TILE_NORMAL: {
 
				RoadBits bits = GetAllRoadBits(tile);
 
				RoadBits bits_copy = bits;
 
				/* Check if the slope-road_bits combination is valid at all, i.e. it is save to call GetRoadFoundation(). */
 
				if (!CmdFailed(CheckRoadSlope(tileh_new, &bits_copy, ROAD_NONE, ROAD_NONE))) {
 
					/* CheckRoadSlope() sometimes changes the road_bits, if it does not agree with them. */
 
					if (bits == bits_copy) {
 
						uint z_old;
 
						Slope tileh_old = GetTileSlope(tile, &z_old);
 

	
 
						/* Get the slope on top of the foundation */
 
						z_old += ApplyFoundationToSlope(GetRoadFoundation(tileh_old, bits), &tileh_old);
 
						z_new += ApplyFoundationToSlope(GetRoadFoundation(tileh_new, bits), &tileh_new);
 

	
 
						/* The surface slope must not be changed */
 
						if ((z_old == z_new) && (tileh_old == tileh_new)) return CommandCost(EXPENSES_CONSTRUCTION, _price.terraform);
 
					}
 
				}
 
				break;
 
			}
 

	
 
			default: NOT_REACHED();
 
		}
 
	}
 

	
 
	return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
 
}
 

	
 

	
 
extern const TileTypeProcs _tile_type_road_procs = {
 
	DrawTile_Road,           /* draw_tile_proc */
 
	GetSlopeZ_Road,          /* get_slope_z_proc */
 
	ClearTile_Road,          /* clear_tile_proc */
 
	GetAcceptedCargo_Road,   /* get_accepted_cargo_proc */
 
	GetTileDesc_Road,        /* get_tile_desc_proc */
 
	GetTileTrackStatus_Road, /* get_tile_track_status_proc */
 
	ClickTile_Road,          /* click_tile_proc */
 
	AnimateTile_Road,        /* animate_tile_proc */
 
	TileLoop_Road,           /* tile_loop_clear */
 
	ChangeTileOwner_Road,    /* change_tile_owner_clear */
 
	NULL,                    /* get_produced_cargo_proc */
 
	VehicleEnter_Road,       /* vehicle_enter_tile_proc */
 
	GetFoundation_Road,      /* get_foundation_proc */
 
	TerraformTile_Road,      /* terraform_tile_proc */
 
};
src/road_map.h
Show inline comments
 
@@ -94,192 +94,198 @@ static inline void SetRoadBits(TileIndex
 
{
 
	assert(IsNormalRoad(t)); // XXX incomplete
 
	switch (rt) {
 
		default: NOT_REACHED();
 
		case ROADTYPE_ROAD: SB(_m[t].m4, 0, 4, r); break;
 
		case ROADTYPE_TRAM: SB(_m[t].m4, 4, 4, r); break;
 
		case ROADTYPE_HWAY: SB(_m[t].m6, 2, 4, r); break;
 
	}
 
}
 

	
 
static inline RoadTypes GetRoadTypes(TileIndex t)
 
{
 
	if (IsTileType(t, MP_ROAD)) {
 
		return (RoadTypes)GB(_me[t].m7, 5, 3);
 
	} else {
 
		return (RoadTypes)GB(_m[t].m3, 0, 3);
 
	}
 
}
 

	
 
static inline void SetRoadTypes(TileIndex t, RoadTypes rt)
 
{
 
	if (IsTileType(t, MP_ROAD)) {
 
		SB(_me[t].m7, 5, 3, rt);
 
	} else {
 
		assert(IsTileType(t, MP_STATION) || IsTileType(t, MP_TUNNELBRIDGE));
 
		SB(_m[t].m3, 0, 2, rt);
 
	}
 
}
 

	
 
static inline bool HasTileRoadType(TileIndex t, RoadType rt)
 
{
 
	return HasBit(GetRoadTypes(t), rt);
 
}
 

	
 
static inline Owner GetRoadOwner(TileIndex t, RoadType rt)
 
{
 
	if (!IsTileType(t, MP_ROAD)) return GetTileOwner(t);
 

	
 
	switch (GetRoadTileType(t)) {
 
		default: NOT_REACHED();
 
		case ROAD_TILE_NORMAL:
 
			switch (rt) {
 
				default: NOT_REACHED();
 
				case ROADTYPE_ROAD: return (Owner)GB( _m[t].m1, 0, 5);
 
				case ROADTYPE_TRAM: {
 
					/* Trams don't need OWNER_TOWN, and remapping OWNER_NONE
 
					 * to OWNER_TOWN makes it use one bit less */
 
					Owner o = (Owner)GB( _m[t].m5, 0, 4);
 
					return o == OWNER_TOWN ? OWNER_NONE : o;
 
				}
 
				case ROADTYPE_HWAY: return (Owner)GB(_me[t].m7, 0, 5);
 
			}
 
		case ROAD_TILE_CROSSING:
 
			switch (rt) {
 
				default: NOT_REACHED();
 
				case ROADTYPE_ROAD: return (Owner)GB( _m[t].m4, 0, 5);
 
				case ROADTYPE_TRAM: {
 
					/* Trams don't need OWNER_TOWN, and remapping OWNER_NONE
 
					 * to OWNER_TOWN makes it use one bit less */
 
					Owner o = (Owner)GB( _m[t].m5, 0, 4);
 
					return o == OWNER_TOWN ? OWNER_NONE : o;
 
				}
 
				case ROADTYPE_HWAY: return (Owner)GB(_me[t].m7, 0, 5);
 
			}
 
		case ROAD_TILE_DEPOT: return GetTileOwner(t);
 
	}
 
}
 

	
 
static inline void SetRoadOwner(TileIndex t, RoadType rt, Owner o)
 
{
 
	if (!IsTileType(t, MP_ROAD)) return SetTileOwner(t, o);
 

	
 
	switch (GetRoadTileType(t)) {
 
		default: NOT_REACHED();
 
		case ROAD_TILE_NORMAL:
 
			switch (rt) {
 
				default: NOT_REACHED();
 
				case ROADTYPE_ROAD: SB( _m[t].m1, 0, 5, o); break;
 
				case ROADTYPE_TRAM: SB( _m[t].m5, 0, 4, o == OWNER_NONE ? OWNER_TOWN : o); break;
 
				case ROADTYPE_HWAY: SB(_me[t].m7, 0, 5, o); break;
 
			}
 
			break;
 
		case ROAD_TILE_CROSSING:
 
			switch (rt) {
 
				default: NOT_REACHED();
 
				case ROADTYPE_ROAD: SB( _m[t].m4, 0, 5, o); break;
 
				/* Trams don't need OWNER_TOWN, and remapping OWNER_NONE
 
				 * to OWNER_TOWN makes it use one bit less */
 
				case ROADTYPE_TRAM: SB( _m[t].m5, 0, 4, o == OWNER_NONE ? OWNER_TOWN : o); break;
 
				case ROADTYPE_HWAY: SB(_me[t].m7, 0, 5, o); break;
 
			}
 
			break;
 
		case ROAD_TILE_DEPOT: return SetTileOwner(t, o);
 
	}
 
}
 

	
 
static inline bool IsRoadOwner(TileIndex t, RoadType rt, Owner o)
 
{
 
	assert(HasTileRoadType(t, rt));
 
	return (GetRoadOwner(t, rt) == o);
 
}
 

	
 
/** Which directions are disallowed ? */
 
enum DisallowedRoadDirections {
 
	DRD_NONE,       ///< None of the directions are disallowed
 
	DRD_SOUTHBOUND, ///< All southbound traffic is disallowed
 
	DRD_NORTHBOUND, ///< All northbound traffic is disallowed
 
	DRD_BOTH,       ///< All directions are disallowed
 
	DRD_END
 
};
 
DECLARE_ENUM_AS_BIT_SET(DisallowedRoadDirections);
 

	
 
/**
 
 * Gets the disallowed directions
 
 * @param t the tile to get the directions from
 
 * @return the disallowed directions
 
 */
 
static inline DisallowedRoadDirections GetDisallowedRoadDirections(TileIndex t)
 
{
 
	assert(IsNormalRoad(t));
 
	return (DisallowedRoadDirections)GB(_m[t].m5, 4, 2);
 
}
 

	
 
/**
 
 * Sets the disallowed directions
 
 * @param t   the tile to set the directions for
 
 * @param drd the disallowed directions
 
 */
 
static inline void SetDisallowedRoadDirections(TileIndex t, DisallowedRoadDirections drd)
 
{
 
	assert(IsNormalRoad(t));
 
	assert(drd < DRD_END);
 
	SB(_m[t].m5, 4, 2, drd);
 
}
 

	
 
static inline Axis GetCrossingRoadAxis(TileIndex t)
 
{
 
	assert(IsLevelCrossing(t));
 
	return (Axis)GB(_m[t].m4, 6, 1);
 
}
 

	
 
static inline Axis GetCrossingRailAxis(TileIndex t)
 
{
 
	assert(IsLevelCrossing(t));
 
	return OtherAxis((Axis)GetCrossingRoadAxis(t));
 
}
 

	
 
static inline RoadBits GetCrossingRoadBits(TileIndex tile)
 
{
 
	return GetCrossingRoadAxis(tile) == AXIS_X ? ROAD_X : ROAD_Y;
 
}
 

	
 
static inline Track GetCrossingRailTrack(TileIndex tile)
 
{
 
	return AxisToTrack(GetCrossingRailAxis(tile));
 
}
 

	
 
static inline TrackBits GetCrossingRailBits(TileIndex tile)
 
{
 
	return AxisToTrackBits(GetCrossingRailAxis(tile));
 
}
 

	
 
static inline bool IsCrossingBarred(TileIndex t)
 
{
 
	assert(IsLevelCrossing(t));
 
	return HasBit(_m[t].m4, 5);
 
}
 

	
 
static inline void SetCrossingBarred(TileIndex t, bool barred)
 
{
 
	assert(IsLevelCrossing(t));
 
	SB(_m[t].m4, 5, 1, barred);
 
}
 

	
 
static inline void UnbarCrossing(TileIndex t)
 
{
 
	SetCrossingBarred(t, false);
 
}
 

	
 
static inline void BarCrossing(TileIndex t)
 
{
 
	SetCrossingBarred(t, true);
 
}
 

	
 
#define IsOnDesert IsOnSnow
 
static inline bool IsOnSnow(TileIndex t)
 
{
 
	return HasBit(_m[t].m3, 7);
 
}
 

	
 
#define ToggleDesert ToggleSnow
 
static inline void ToggleSnow(TileIndex t)
 
{
 
	ToggleBit(_m[t].m3, 7);
 
}
 

	
 

	
 
enum Roadside {
src/smallmap_gui.cpp
Show inline comments
 
@@ -397,192 +397,196 @@ static inline uint32 GetSmallMapIndustri
 
		}
 
	}
 

	
 
	return ApplyMask(MKCOLOR(0x54545454), &_smallmap_vehicles_andor[t]);
 
}
 

	
 
/**
 
 * Return the color a tile would be displayed with in the small map in mode "Routes".
 
 *
 
 * @param tile The tile of which we would like to get the color.
 
 * @return The color of tile  in the small map in mode "Routes"
 
 */
 
static inline uint32 GetSmallMapRoutesPixels(TileIndex tile)
 
{
 
	TileType t = GetEffectiveTileType(tile);
 
	uint32 bits;
 

	
 
	if (t == MP_STATION) {
 
		switch (GetStationType(tile)) {
 
			case STATION_RAIL:    bits = MKCOLOR(0x56565656); break;
 
			case STATION_AIRPORT: bits = MKCOLOR(0xB8B8B8B8); break;
 
			case STATION_TRUCK:   bits = MKCOLOR(0xC2C2C2C2); break;
 
			case STATION_BUS:     bits = MKCOLOR(0xBFBFBFBF); break;
 
			case STATION_DOCK:    bits = MKCOLOR(0x98989898); break;
 
			default:              bits = MKCOLOR(0xFFFFFFFF); break;
 
		}
 
	} else {
 
		/* ground color */
 
		bits = ApplyMask(MKCOLOR(0x54545454), &_smallmap_contours_andor[t]);
 
	}
 
	return bits;
 
}
 

	
 

	
 
static const uint32 _vegetation_clear_bits[] = {
 
	MKCOLOR(0x54545454), ///< full grass
 
	MKCOLOR(0x52525252), ///< rough land
 
	MKCOLOR(0x0A0A0A0A), ///< rocks
 
	MKCOLOR(0x25252525), ///< fields
 
	MKCOLOR(0x98989898), ///< snow
 
	MKCOLOR(0xC2C2C2C2), ///< desert
 
	MKCOLOR(0x54545454), ///< unused
 
	MKCOLOR(0x54545454), ///< unused
 
};
 

	
 
static inline uint32 GetSmallMapVegetationPixels(TileIndex tile)
 
{
 
	TileType t = GetEffectiveTileType(tile);
 
	uint32 bits;
 

	
 
	switch (t) {
 
		case MP_CLEAR:
 
			if (IsClearGround(tile, CLEAR_GRASS) && GetClearDensity(tile) < 3) {
 
				bits = MKCOLOR(0x37373737);
 
			} else {
 
				bits = _vegetation_clear_bits[GetClearGround(tile)];
 
			}
 
			break;
 

	
 
		case MP_INDUSTRY:
 
			bits = GetIndustrySpec(GetIndustryByTile(tile)->type)->check_proc == CHECK_FOREST ? MKCOLOR(0xD0D0D0D0) : MKCOLOR(0xB5B5B5B5);
 
			break;
 

	
 
		case MP_TREES:
 
			if (GetTreeGround(tile) == TREE_GROUND_SNOW_DESERT) {
 
				bits = (_opt.landscape == LT_ARCTIC) ? MKCOLOR(0x98575798) : MKCOLOR(0xC25757C2);
 
			} else {
 
				bits = MKCOLOR(0x54575754);
 
			}
 
			break;
 

	
 
		default:
 
			bits = ApplyMask(MKCOLOR(0x54545454), &_smallmap_vehicles_andor[t]);
 
			break;
 
	}
 

	
 
	return bits;
 
}
 

	
 

	
 
static uint32 _owner_colors[OWNER_END + 1];
 

	
 
/**
 
 * Return the color a tile would be displayed with in the small map in mode "Owner".
 
 *
 
 * @param tile The tile of which we would like to get the color.
 
 * @return The color of tile in the small map in mode "Owner"
 
 */
 
static inline uint32 GetSmallMapOwnerPixels(TileIndex tile)
 
{
 
	Owner o;
 

	
 
	switch (GetTileType(tile)) {
 
		case MP_INDUSTRY: o = OWNER_END;          break;
 
		case MP_HOUSE:    o = OWNER_TOWN;         break;
 
		default:          o = GetTileOwner(tile); break;
 
		/* FIXME: For MP_ROAD there are multiple owners.
 
		 * GetTileOwner returns the rail owner (level crossing) resp. the owner of ROADTYPE_ROAD (normal road),
 
		 * even if there are no ROADTYPE_ROAD bits on the tile.
 
		 */
 
	}
 

	
 
	return _owner_colors[o];
 
}
 

	
 

	
 
static const uint32 _smallmap_mask_left[3] = {
 
	MKCOLOR(0xFF000000),
 
	MKCOLOR(0xFFFF0000),
 
	MKCOLOR(0xFFFFFF00),
 
};
 

	
 
static const uint32 _smallmap_mask_right[] = {
 
	MKCOLOR(0x000000FF),
 
	MKCOLOR(0x0000FFFF),
 
	MKCOLOR(0x00FFFFFF),
 
};
 

	
 
/* each tile has 4 x pixels and 1 y pixel */
 

	
 
static GetSmallMapPixels *_smallmap_draw_procs[] = {
 
	GetSmallMapContoursPixels,
 
	GetSmallMapVehiclesPixels,
 
	GetSmallMapIndustriesPixels,
 
	GetSmallMapRoutesPixels,
 
	GetSmallMapVegetationPixels,
 
	GetSmallMapOwnerPixels,
 
};
 

	
 
static const byte _vehicle_type_colors[6] = {
 
	184, 191, 152, 15, 215, 184
 
};
 

	
 

	
 
static void DrawVertMapIndicator(int x, int y, int x2, int y2)
 
{
 
	GfxFillRect(x, y,      x2, y + 3, 69);
 
	GfxFillRect(x, y2 - 3, x2, y2,    69);
 
}
 

	
 
static void DrawHorizMapIndicator(int x, int y, int x2, int y2)
 
{
 
	GfxFillRect(x,      y, x + 3, y2, 69);
 
	GfxFillRect(x2 - 3, y, x2,    y2, 69);
 
}
 

	
 
enum SmallMapWindowWidgets {
 
	SM_WIDGET_MAP = 4,
 
	SM_WIDGET_CONTOUR,
 
	SM_WIDGET_VEHICLES,
 
	SM_WIDGET_INDUSTRIES,
 
	SM_WIDGET_ROUTES,
 
	SM_WIDGET_VEGETATION,
 
	SM_WIDGET_OWNERS,
 
	SM_WIDGET_CENTERMAP,
 
	SM_WIDGET_TOGGLETOWNNAME,
 
	SM_WIDGET_LEGEND,
 
	SM_WIDGET_BUTTONSPANEL,
 
	SM_WIDGET_BOTTOMPANEL,
 
	SM_WIDGET_ENABLEINDUSTRIES,
 
	SM_WIDGET_DISABLEINDUSTRIES,
 
	SM_WIDGET_RESIZEBOX,
 
};
 

	
 
class SmallMapWindow : public Window
 
{
 
	enum SmallMapType {
 
		SMT_CONTOUR,
 
		SMT_VEHICLES,
 
		SMT_INDUSTRY,
 
		SMT_OWNER = 5,
 
	};
 

	
 
	enum {
 
		BASE_NB_PER_COLUMN = 6,
 
	};
 

	
 
	int32 scroll_x;
 
	int32 scroll_y;
 
	int32 subscroll;
 

	
 
public:
 
	/**
 
	 * Draws the small map.
 
	 *
 
	 * Basically, the small map is draw column of pixels by column of pixels. The pixels
 
	 * are drawn directly into the screen buffer. The final map is drawn in multiple passes.
 
	 * The passes are:
 
	 * <ol><li>The colors of tiles in the different modes.</li>
 
	 * <li>Town names (optional)</li></ol>
 
	 *
 
	 * @param dpi pointer to pixel to write onto
 
	 * @param w pointer to Window struct
 
	 * @param type type of map requested (vegetation, owners, routes, etc)
 
	 * @param show_towns true if the town names should be displayed, false if not.
 
	 */
src/station_cmd.cpp
Show inline comments
 
@@ -1207,219 +1207,222 @@ CommandCost CmdRemoveFromRailroadStation
 
static CommandCost RemoveRailroadStation(Station *st, TileIndex tile, uint32 flags)
 
{
 
	/* if there is flooding and non-uniform stations are enabled, remove platforms tile by tile */
 
	if (_current_player == OWNER_WATER && _patches.nonuniform_stations) {
 
		return DoCommand(tile, 0, 0, DC_EXEC, CMD_REMOVE_FROM_RAILROAD_STATION);
 
	}
 

	
 
	/* Current player owns the station? */
 
	if (_current_player != OWNER_WATER && !CheckOwnership(st->owner)) return CMD_ERROR;
 

	
 
	/* determine width and height of platforms */
 
	tile = st->train_tile;
 
	int w = st->trainst_w;
 
	int h = st->trainst_h;
 

	
 
	assert(w != 0 && h != 0);
 

	
 
	CommandCost cost(EXPENSES_CONSTRUCTION);
 
	/* clear all areas of the station */
 
	do {
 
		int w_bak = w;
 
		do {
 
			/* for nonuniform stations, only remove tiles that are actually train station tiles */
 
			if (st->TileBelongsToRailStation(tile)) {
 
				if (!EnsureNoVehicleOnGround(tile))
 
					return CMD_ERROR;
 
				cost.AddCost(_price.remove_rail_station);
 
				if (flags & DC_EXEC) {
 
					/* read variables before the station tile is removed */
 
					Track track = GetRailStationTrack(tile);
 
					Owner owner = GetTileOwner(tile); // _current_player can be OWNER_WATER
 
					DoClearSquare(tile);
 
					AddTrackToSignalBuffer(tile, track, owner);
 
					YapfNotifyTrackLayoutChange(tile, track);
 
				}
 
			}
 
			tile += TileDiffXY(1, 0);
 
		} while (--w);
 
		w = w_bak;
 
		tile += TileDiffXY(-w, 1);
 
	} while (--h);
 

	
 
	if (flags & DC_EXEC) {
 
		st->rect.AfterRemoveRect(st, st->train_tile, st->trainst_w, st->trainst_h);
 

	
 
		st->train_tile = 0;
 
		st->trainst_w = st->trainst_h = 0;
 
		st->facilities &= ~FACIL_TRAIN;
 

	
 
		free(st->speclist);
 
		st->num_specs = 0;
 
		st->speclist  = NULL;
 
		st->cached_anim_triggers = 0;
 

	
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
 
		UpdateStationVirtCoordDirty(st);
 
		DeleteStationIfEmpty(st);
 
	}
 

	
 
	return cost;
 
}
 

	
 
/**
 
 * @param truck_station Determines whether a stop is ROADSTOP_BUS or ROADSTOP_TRUCK
 
 * @param st The Station to do the whole procedure for
 
 * @return a pointer to where to link a new RoadStop*
 
 */
 
static RoadStop **FindRoadStopSpot(bool truck_station, Station *st)
 
{
 
	RoadStop **primary_stop = (truck_station) ? &st->truck_stops : &st->bus_stops;
 

	
 
	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;
 
	}
 
}
 

	
 
/** Build a bus or truck stop
 
 * @param tile tile to build the stop at
 
 * @param flags operation to perform
 
 * @param p1 entrance direction (DiagDirection)
 
 * @param p2 bit 0: 0 for Bus stops, 1 for truck stops
 
 *           bit 1: 0 for normal, 1 for drive-through
 
 *           bit 2..4: the roadtypes
 
 *           bit 5: allow stations directly adjacent to other stations.
 
 */
 
CommandCost CmdBuildRoadStop(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	bool type = HasBit(p2, 0);
 
	bool is_drive_through = HasBit(p2, 1);
 
	bool build_over_road  = is_drive_through && IsNormalRoadTile(tile);
 
	bool town_owned_road  = build_over_road && IsTileOwner(tile, OWNER_TOWN);
 
	bool town_owned_road  = false;
 
	RoadTypes rts = (RoadTypes)GB(p2, 2, 3);
 

	
 
	if (!AreValidRoadTypes(rts) || !HasRoadTypesAvail(_current_player, rts)) return CMD_ERROR;
 

	
 
	/* Trams only have drive through stops */
 
	if (!is_drive_through && HasBit(rts, ROADTYPE_TRAM)) return CMD_ERROR;
 

	
 
	/* Saveguard the parameters */
 
	if (!IsValidDiagDirection((DiagDirection)p1)) return CMD_ERROR;
 
	/* If it is a drive-through stop check for valid axis */
 
	if (is_drive_through && !IsValidAxis((Axis)p1)) return CMD_ERROR;
 
	/* Road bits in the wrong direction */
 
	if (build_over_road && (GetAllRoadBits(tile) & ((Axis)p1 == AXIS_X ? ROAD_Y : ROAD_X)) != 0) return_cmd_error(STR_DRIVE_THROUGH_ERROR_DIRECTION);
 

	
 
	if (!(flags & DC_NO_TOWN_RATING) && !CheckIfAuthorityAllows(tile)) return CMD_ERROR;
 

	
 
	/* Not allowed to build over this road */
 
	if (build_over_road) {
 
		if (IsTileOwner(tile, OWNER_TOWN) && !_patches.road_stop_on_town_road) return_cmd_error(STR_DRIVE_THROUGH_ERROR_ON_TOWN_ROAD);
 

	
 
		RoadTypes cur_rts = GetRoadTypes(tile);
 

	
 
		/* there is a road, check if we can build road+tram stop over it */
 
		if (HasBit(cur_rts, ROADTYPE_ROAD)) {
 
			Owner road_owner = GetRoadOwner(tile, ROADTYPE_ROAD);
 
			if (road_owner != OWNER_TOWN && road_owner != OWNER_NONE && !CheckOwnership(road_owner)) return CMD_ERROR;
 
			if (road_owner == OWNER_TOWN) {
 
				town_owned_road = true;
 
				if (!_patches.road_stop_on_town_road) return_cmd_error(STR_DRIVE_THROUGH_ERROR_ON_TOWN_ROAD);
 
			} else {
 
				if (road_owner != OWNER_NONE && !CheckOwnership(road_owner)) return CMD_ERROR;
 
			}
 
		}
 

	
 
		/* there is a tram, check if we can build road+tram stop over it */
 
		if (HasBit(cur_rts, ROADTYPE_TRAM)) {
 
			Owner tram_owner = GetRoadOwner(tile, ROADTYPE_TRAM);
 
			if (tram_owner != OWNER_NONE && !CheckOwnership(tram_owner)) return CMD_ERROR;
 
		}
 

	
 
		/* Don't allow building the roadstop when vehicles are already driving on it */
 
		if (!EnsureNoVehicleOnGround(tile)) return CMD_ERROR;
 

	
 
		/* Do not remove roadtypes! */
 
		rts |= cur_rts;
 
	}
 

	
 
	CommandCost cost = CheckFlatLandBelow(tile, 1, 1, flags, is_drive_through ? 5 << p1 : 1 << p1, NULL, !build_over_road);
 
	if (CmdFailed(cost)) return cost;
 

	
 
	Station *st = NULL;
 

	
 
	if (!_patches.adjacent_stations || !HasBit(p2, 5)) {
 
		st = GetStationAround(tile, 1, 1, INVALID_STATION);
 
		if (st == CHECK_STATIONS_ERR) return CMD_ERROR;
 
	}
 

	
 
	/* Find a station close to us */
 
	if (st == NULL) st = GetClosestStationFromTile(tile);
 

	
 
	/* give us a road stop in the list, and check if something went wrong */
 
	if (!RoadStop::CanAllocateItem()) return_cmd_error(type ? STR_TOO_MANY_TRUCK_STOPS : STR_TOO_MANY_BUS_STOPS);
 

	
 
	if (st != NULL &&
 
			GetNumRoadStopsInStation(st, ROADSTOP_BUS) + GetNumRoadStopsInStation(st, ROADSTOP_TRUCK) >= RoadStop::LIMIT) {
 
		return_cmd_error(type ? STR_TOO_MANY_TRUCK_STOPS : STR_TOO_MANY_BUS_STOPS);
 
	}
 

	
 
	if (st != NULL) {
 
		if (st->owner != _current_player) {
 
			return_cmd_error(STR_3009_TOO_CLOSE_TO_ANOTHER_STATION);
 
		}
 

	
 
		if (!st->rect.BeforeAddTile(tile, StationRect::ADD_TEST)) return CMD_ERROR;
 
	} else {
 
		/* allocate and initialize new station */
 
		if (!Station::CanAllocateItem()) return_cmd_error(STR_3008_TOO_MANY_STATIONS_LOADING);
 

	
 
		if (flags & DC_EXEC) {
 
			st = new Station(tile);
 

	
 
			st->town = ClosestTownFromTile(tile, UINT_MAX);
 
			st->string_id = GenerateStationName(st, tile, STATIONNAMING_ROAD);
 

	
 
			if (IsValidPlayer(_current_player)) {
 
				SetBit(st->town->have_ratings, _current_player);
 
			}
 
			st->sign.width_1 = 0;
 
		}
 
	}
 

	
 
	cost.AddCost((type) ? _price.build_truck_station : _price.build_bus_station);
 

	
 
	if (flags & DC_EXEC) {
 
		RoadStop *road_stop = new RoadStop(tile);
 
		/* Insert into linked list of RoadStops */
 
		RoadStop **currstop = FindRoadStopSpot(type, st);
 
		*currstop = road_stop;
 

	
 
		/*initialize an empty station */
 
		st->AddFacility((type) ? FACIL_TRUCK_STOP : FACIL_BUS_STOP, tile);
 

	
 
		st->rect.BeforeAddTile(tile, StationRect::ADD_TRY);
 

	
 
		RoadStopType rs_type = type ? ROADSTOP_TRUCK : ROADSTOP_BUS;
 
		if (is_drive_through) {
 
			MakeDriveThroughRoadStop(tile, st->owner, st->index, rs_type, rts, (Axis)p1, town_owned_road);
 
		} else {
 
			MakeRoadStop(tile, st->owner, st->index, rs_type, rts, (DiagDirection)p1);
 
		}
 

	
 
		UpdateStationVirtCoordDirty(st);
 
		UpdateStationAcceptance(st, false);
 
		InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
 
		InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
 
	}
 
	return cost;
 
}
 

	
 

	
 
static void *ClearRoadStopStatusEnum(Vehicle *v, void *)
 
{
 
	if (v->type == VEH_ROAD) ClrBit(v->u.road.state, RVS_IN_DT_ROAD_STOP);
 

	
 
	return NULL;
 
}
 

	
 

	
src/town_cmd.cpp
Show inline comments
 
@@ -1119,200 +1119,200 @@ static void GrowTownInTile(TileIndex *ti
 
				break;
 

	
 
			case TL_BETTER_ROADS: /* Use original afterwards! */
 
				GrowTownWithExtraHouse(t1, TileAddByDiagDir(house_tile, target_dir));
 
				/* FALL THROUGH */
 

	
 
			case TL_ORIGINAL:
 
				 /* Allow a house at the edge. 60% chance or
 
				  * always ok if no road allowed. */
 
				rcmd = DiagDirToRoadBits(target_dir);
 
				allow_house = (!IsRoadAllowedHere(t1, house_tile, target_dir) || Chance16(6, 10));
 
				break;
 
		}
 

	
 
		if (allow_house) {
 
			/* Build a house, but not if there already is a house there. */
 
			if (!IsTileType(house_tile, MP_HOUSE)) {
 
				/* Level the land if possible */
 
				if (Chance16(1, 6)) LevelTownLand(house_tile);
 

	
 
				/* And build a house.
 
				 * Set result to -1 if we managed to build it. */
 
				if (BuildTownHouse(t1, house_tile)) {
 
					_grow_town_result = GROWTH_SUCCEED;
 
				}
 
			}
 
			return;
 
		}
 

	
 
		_grow_town_result = GROWTH_SEARCH_STOPPED;
 
	}
 

	
 
	/* Return if a water tile */
 
	if (IsWaterTile(tile)) return;
 

	
 
	/* Make the roads look nicer */
 
	rcmd = CleanUpRoadBits(tile, rcmd);
 
	if (rcmd == ROAD_NONE) return;
 

	
 
	/* Only use the target direction for bridges to ensure they're connected.
 
	 * The target_dir is as computed previously according to town layout, so
 
	 * it will match it perfectly. */
 
	if (GrowTownWithBridge(t1, tile, target_dir)) return;
 

	
 
	GrowTownWithRoad(t1, tile, rcmd);
 
}
 

	
 
/** Returns "growth" if a house was built, or no if the build failed.
 
 * @param t town to inquiry
 
 * @param tile to inquiry
 
 * @return something other than zero(0)if town expansion was possible
 
 */
 
static int GrowTownAtRoad(Town *t, TileIndex tile)
 
{
 
	/* Special case.
 
	 * @see GrowTownInTile Check the else if
 
	 */
 
	DiagDirection target_dir = DIAGDIR_END; // The direction in which we want to extend the town
 

	
 
	TILE_ASSERT(tile);
 

	
 
	/* Number of times to search.
 
	 * Better roads, 2X2 and 3X3 grid grow quite fast so we give
 
	 * them a little handicap. */
 
	switch (t->GetActiveLayout()) {
 
		case TL_BETTER_ROADS:
 
			_grow_town_result = 10 + t->num_houses * 2 / 9;
 
			break;
 

	
 
		case TL_3X3_GRID:
 
		case TL_2X2_GRID:
 
			_grow_town_result = 10 + t->num_houses * 1 / 9;
 
			break;
 

	
 
		default:
 
			_grow_town_result = 10 + t->num_houses * 4 / 9;
 
			break;
 
	}
 

	
 
	do {
 
		RoadBits cur_rb = GetTownRoadBits(tile); // The RoadBits of the current tile
 

	
 
		/* Try to grow the town from this point */
 
		GrowTownInTile(&tile, cur_rb, target_dir, t);
 

	
 
		/* Exclude the source position from the bitmask
 
		 * and return if no more road blocks available */
 
		cur_rb &= ~DiagDirToRoadBits(ReverseDiagDir(target_dir));
 
		if (cur_rb == ROAD_NONE)
 
			return _grow_town_result;
 

	
 
		/* Select a random bit from the blockmask, walk a step
 
		 * and continue the search from there. */
 
		do target_dir = RandomDiagDir(); while (!(cur_rb & DiagDirToRoadBits(target_dir)));
 
		tile = TileAddByDiagDir(tile, target_dir);
 

	
 
		if (IsTileType(tile, MP_ROAD)) {
 
		if (IsTileType(tile, MP_ROAD) && !IsRoadDepot(tile) && HasTileRoadType(tile, ROADTYPE_ROAD)) {
 
			/* Don't allow building over roads of other cities */
 
			if (IsTileOwner(tile, OWNER_TOWN) && GetTownByTile(tile) != t) {
 
			if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN) && GetTownByTile(tile) != t) {
 
				_grow_town_result = GROWTH_SUCCEED;
 
			} else if (IsTileOwner(tile, OWNER_NONE) && _game_mode == GM_EDITOR) {
 
			} else if (IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_NONE) && _game_mode == GM_EDITOR) {
 
				/* If we are in the SE, and this road-piece has no town owner yet, it just found an
 
				 * owner :) (happy happy happy road now) */
 
				SetTileOwner(tile, OWNER_TOWN);
 
				SetRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN);
 
				SetTownIndex(tile, t->index);
 
			}
 
		}
 

	
 
		/* Max number of times is checked. */
 
	} while (--_grow_town_result >= 0);
 

	
 
	return (_grow_town_result == -2);
 
}
 

	
 
/**
 
 * Generate a random road block.
 
 * The probability of a straight road
 
 * is somewhat higher than a curved.
 
 *
 
 * @return A RoadBits value with 2 bits set
 
 */
 
static RoadBits GenRandomRoadBits()
 
{
 
	uint32 r = Random();
 
	uint a = GB(r, 0, 2);
 
	uint b = GB(r, 8, 2);
 
	if (a == b) b ^= 2;
 
	return (RoadBits)((ROAD_NW << a) + (ROAD_NW << b));
 
}
 

	
 
/** Grow the town
 
 * @param t town to grow
 
 * @return true iff a house was built
 
 */
 
static bool GrowTown(Town *t)
 
{
 
	/* Let the town be a ghost town
 
	 * The player wanted it in such a way. Thus there he has it. ;)
 
	 * Never reached in editor mode. */
 
	if (_patches.town_layout == TL_NO_ROADS && _generating_world) {
 
		return false;
 
	}
 

	
 
	static const TileIndexDiffC _town_coord_mod[] = {
 
		{-1,  0},
 
		{ 1,  1},
 
		{ 1, -1},
 
		{-1, -1},
 
		{-1,  0},
 
		{ 0,  2},
 
		{ 2,  0},
 
		{ 0, -2},
 
		{-1, -1},
 
		{-2,  2},
 
		{ 2,  2},
 
		{ 2, -2},
 
		{ 0,  0}
 
	};
 

	
 
	/* Current player is a town */
 
	PlayerID old_player = _current_player;
 
	_current_player = OWNER_TOWN;
 

	
 
	TileIndex tile = t->xy; // The tile we are working with ATM
 

	
 
	/* Find a road that we can base the construction on. */
 
	const TileIndexDiffC *ptr;
 
	for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
 
		if (GetTownRoadBits(tile) != ROAD_NONE) {
 
			int r = GrowTownAtRoad(t, tile);
 
			_current_player = old_player;
 
			return r != 0;
 
		}
 
		tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
 
	}
 

	
 
	/* No road available, try to build a random road block by
 
	 * clearing some land and then building a road there. */
 
	tile = t->xy;
 
	for (ptr = _town_coord_mod; ptr != endof(_town_coord_mod); ++ptr) {
 
		/* Only work with plain land that not already has a house */
 
		if (!IsTileType(tile, MP_HOUSE) && GetTileSlope(tile, NULL) == SLOPE_FLAT) {
 
			if (CmdSucceeded(DoCommand(tile, 0, 0, DC_AUTO | DC_NO_WATER, CMD_LANDSCAPE_CLEAR))) {
 
				DoCommand(tile, GenRandomRoadBits(), t->index, DC_EXEC | DC_AUTO, CMD_BUILD_ROAD);
 
				_current_player = old_player;
 
				return true;
 
			}
 
		}
 
		tile = TILE_ADD(tile, ToTileIndexDiff(*ptr));
 
	}
 

	
 
	_current_player = old_player;
 
	return false;
 
}
 

	
 
void UpdateTownRadius(Town *t)
 
{
 
	static const uint32 _town_squared_town_zone_radius_data[23][5] = {
 
		{  4,  0,  0,  0,  0}, // 0
 
		{ 16,  0,  0,  0,  0},
 
@@ -2345,194 +2345,194 @@ static void UpdateTownGrowRate(Town *t)
 
	uint16 m;
 

	
 
	if (t->fund_buildings_months != 0) {
 
		m = _grow_count_values[0][min(n, 5)];
 
		t->fund_buildings_months--;
 
	} else {
 
		m = _grow_count_values[1][min(n, 5)];
 
		if (n == 0 && !Chance16(1, 12)) return;
 
	}
 

	
 
	if (_opt.landscape == LT_ARCTIC) {
 
		if (TilePixelHeight(t->xy) >= GetSnowLine() && t->act_food == 0 && t->population > 90)
 
			return;
 
	} else if (_opt.landscape == LT_TROPIC) {
 
		if (GetTropicZone(t->xy) == TROPICZONE_DESERT && (t->act_food == 0 || t->act_water == 0) && t->population > 60)
 
			return;
 
	}
 

	
 
	/* Use the normal growth rate values if new buildings have been funded in
 
	 * this town and the growth rate is set to none. */
 
	uint growth_multiplier = _patches.town_growth_rate != 0 ? _patches.town_growth_rate - 1 : 1;
 

	
 
	m >>= growth_multiplier;
 
	if (t->larger_town) m /= 2;
 

	
 
	t->growth_rate = m / (t->num_houses / 50 + 1);
 
	if (m <= t->grow_counter)
 
		t->grow_counter = m;
 

	
 
	SetBit(t->flags12, TOWN_IS_FUNDED);
 
}
 

	
 
static void UpdateTownAmounts(Town *t)
 
{
 
	/* Using +1 here to prevent overflow and division by zero */
 
	t->pct_pass_transported = t->new_act_pass * 256 / (t->new_max_pass + 1);
 

	
 
	t->max_pass = t->new_max_pass; t->new_max_pass = 0;
 
	t->act_pass = t->new_act_pass; t->new_act_pass = 0;
 
	t->act_food = t->new_act_food; t->new_act_food = 0;
 
	t->act_water = t->new_act_water; t->new_act_water = 0;
 

	
 
	/* Using +1 here to prevent overflow and division by zero */
 
	t->pct_mail_transported = t->new_act_mail * 256 / (t->new_max_mail + 1);
 
	t->max_mail = t->new_max_mail; t->new_max_mail = 0;
 
	t->act_mail = t->new_act_mail; t->new_act_mail = 0;
 

	
 
	InvalidateWindow(WC_TOWN_VIEW, t->index);
 
}
 

	
 
static void UpdateTownUnwanted(Town *t)
 
{
 
	const Player *p;
 

	
 
	FOR_ALL_PLAYERS(p) {
 
		if (t->unwanted[p->index] > 0) t->unwanted[p->index]--;
 
	}
 
}
 

	
 
bool CheckIfAuthorityAllows(TileIndex tile)
 
{
 
	if (!IsValidPlayer(_current_player)) return true;
 

	
 
	Town *t = ClosestTownFromTile(tile, _patches.dist_local_authority);
 
	if (t == NULL) return true;
 

	
 
	if (t->ratings[_current_player] > RATING_VERYPOOR) return true;
 

	
 
	_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
 
	SetDParam(0, t->index);
 

	
 
	return false;
 
}
 

	
 

	
 
Town *CalcClosestTownFromTile(TileIndex tile, uint threshold)
 
{
 
	Town *t;
 
	uint best = threshold;
 
	Town *best_town = NULL;
 

	
 
	FOR_ALL_TOWNS(t) {
 
		uint dist = DistanceManhattan(tile, t->xy);
 
		if (dist < best) {
 
			best = dist;
 
			best_town = t;
 
		}
 
	}
 

	
 
	return best_town;
 
}
 

	
 

	
 
Town *ClosestTownFromTile(TileIndex tile, uint threshold)
 
{
 
	if (IsTileType(tile, MP_HOUSE) || (
 
				IsTileType(tile, MP_ROAD) &&
 
				GetRoadOwner(tile, ROADTYPE_ROAD) == OWNER_TOWN
 
				IsTileType(tile, MP_ROAD) && HasTileRoadType(tile, ROADTYPE_ROAD) &&
 
				IsRoadOwner(tile, ROADTYPE_ROAD, OWNER_TOWN)
 
			)) {
 
		return GetTownByTile(tile);
 
	} else {
 
		return CalcClosestTownFromTile(tile, threshold);
 
	}
 
}
 

	
 
static bool _town_rating_test = false;
 
std::map<const Town *, int> _town_test_ratings;
 

	
 
void SetTownRatingTestMode(bool mode)
 
{
 
	static int ref_count = 0;
 
	if (mode) {
 
		if (ref_count == 0) {
 
			_town_test_ratings.clear();
 
		}
 
		ref_count++;
 
	} else {
 
		assert(ref_count > 0);
 
		ref_count--;
 
	}
 
	_town_rating_test = !(ref_count == 0);
 
}
 

	
 
static int GetRating(const Town *t)
 
{
 
	if (_town_rating_test) {
 
		std::map<const Town *, int>::iterator it = _town_test_ratings.find(t);
 
		if (it != _town_test_ratings.end()) {
 
			return (*it).second;
 
		}
 
	}
 
	return t->ratings[_current_player];
 
}
 

	
 
void ChangeTownRating(Town *t, int add, int max)
 
{
 
	/* if magic_bulldozer cheat is active, town doesn't penaltize for removing stuff */
 
	if (t == NULL ||
 
			!IsValidPlayer(_current_player) ||
 
			(_cheats.magic_bulldozer.value && add < 0)) {
 
		return;
 
	}
 

	
 
	SetBit(t->have_ratings, _current_player);
 

	
 
	int rating = GetRating(t);
 
	if (add < 0) {
 
		if (rating > max) {
 
			rating += add;
 
			if (rating < max) rating = max;
 
		}
 
	} else {
 
		if (rating < max) {
 
			rating += add;
 
			if (rating > max) rating = max;
 
		}
 
	}
 
	if (_town_rating_test) {
 
		_town_test_ratings[t] = rating;
 
	} else {
 
		t->ratings[_current_player] = rating;
 
	}
 
}
 

	
 
/* penalty for removing town-owned stuff */
 
static const int _default_rating_settings [3][3] = {
 
	/* ROAD_REMOVE, TUNNELBRIDGE_REMOVE, INDUSTRY_REMOVE */
 
	{  0, 128, 384}, // Permissive
 
	{ 48, 192, 480}, // Neutral
 
	{ 96, 384, 768}, // Hostile
 
};
 

	
 
bool CheckforTownRating(uint32 flags, Town *t, byte type)
 
{
 
	/* if magic_bulldozer cheat is active, town doesn't restrict your destructive actions */
 
	if (t == NULL || !IsValidPlayer(_current_player) || _cheats.magic_bulldozer.value)
 
		return true;
 

	
 
	/* check if you're allowed to remove the street/bridge/tunnel/industry
 
	 * owned by a town no removal if rating is lower than ... depends now on
 
	 * difficulty setting. Minimum town rating selected by difficulty level
 
	 */
 
	int modemod = _default_rating_settings[_opt.diff.town_council_tolerance][type];
 

	
 
	if (GetRating(t) < 16 + modemod && !(flags & DC_NO_TOWN_RATING)) {
 
		SetDParam(0, t->index);
 
		_error_message = STR_2009_LOCAL_AUTHORITY_REFUSES;
 
		return false;
 
	}
 

	
 
	return true;
 
}
 

	
 
void TownsMonthlyLoop()
0 comments (0 inline, 0 general)