src/town_cmd.cpp
changeset 8451 a3ae65b58eec
parent 8359 6efdb08cedb8
child 8461 126aeb3ebd1d
equal deleted inserted replaced
8450:73371bb82922 8451:a3ae65b58eec
   671  * @param dir target direction
   671  * @param dir target direction
   672  * @param dist_multi distance multiplyer
   672  * @param dist_multi distance multiplyer
   673  * @return true if one of the neighboring tiles at the
   673  * @return true if one of the neighboring tiles at the
   674  *  given distance is a road tile else false
   674  *  given distance is a road tile else false
   675  */
   675  */
   676 static bool IsNeighborRoadTile(TileIndex tile, DiagDirection dir, uint dist_multi)
   676 static bool IsNeighborRoadTile(TileIndex tile, const DiagDirection dir, uint dist_multi)
   677 {
   677 {
   678 	static TileIndexDiff tid_lt[3]; // lookup table for the used diff values
   678 	/* Lookup table for the used diff values */
   679 	tid_lt[0] = TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT));
   679 	const TileIndexDiff tid_lt[3] = {
   680 	tid_lt[1] = TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT));
   680 		TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT)),
   681 	tid_lt[2] = TileOffsByDiagDir(ReverseDiagDir(dir));
   681 		TileOffsByDiagDir(ChangeDiagDir(dir, DIAGDIRDIFF_90LEFT)),
       
   682 		TileOffsByDiagDir(ReverseDiagDir(dir)),
       
   683 	};
   682 
   684 
   683 	/* We add 1 to the distance because we want to get 1 for
   685 	/* We add 1 to the distance because we want to get 1 for
   684 	 * the min distance multiplyer and not 0.
   686 	 * the min distance multiplyer and not 0.
   685 	 * Therefore we start at 4. The 4 is used because
   687 	 * Therefore we start at 4. The 4 is used because
   686 	 * there are 4 tiles per distance step to check.
   688 	 * there are 4 tiles per distance step to check. */
   687 	 */
       
   688 	dist_multi = (dist_multi + 1) * 4;
   689 	dist_multi = (dist_multi + 1) * 4;
   689 	for (uint pos = 4; pos < dist_multi; pos++) {
   690 	for (uint pos = 4; pos < dist_multi; pos++) {
   690 		TileIndexDiff cur = 0;
   691 		TileIndexDiff cur = 0;
   691 		/* For each even value of pos add the right TileIndexDiff
   692 		/* For each even value of pos add the right TileIndexDiff
   692 		 * for each uneven value the left TileIndexDiff
   693 		 * for each uneven value the left TileIndexDiff
   693 		 * for each with 2nd bit set (2,3,6,7,..) add the reversed TileIndexDiff
   694 		 * for each with 2nd bit set (2,3,6,7,..) add the reversed TileIndexDiff */
   694 		 */
       
   695 		cur += tid_lt[(pos & 1) ? 0 : 1];
   695 		cur += tid_lt[(pos & 1) ? 0 : 1];
   696 		if (pos & 2) cur += tid_lt[2];
   696 		if (pos & 2) cur += tid_lt[2];
   697 
   697 
   698 		cur = (uint)(pos / 4) * cur; // Multiply for the fitting distance
   698 		cur = (uint)(pos / 4) * cur; // Multiply for the fitting distance
   699 		if (GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true;
   699 		if (GetTownRoadBits(TILE_ADD(tile, cur)) & DiagDirToRoadBits((pos & 2) ? dir : ReverseDiagDir(dir))) return true;
   708  * @param dir The direction in which we want to extend the town
   708  * @param dir The direction in which we want to extend the town
   709  * @return true if it is allowed else false
   709  * @return true if it is allowed else false
   710  */
   710  */
   711 static bool IsRoadAllowedHere(TileIndex tile, DiagDirection dir)
   711 static bool IsRoadAllowedHere(TileIndex tile, DiagDirection dir)
   712 {
   712 {
   713 	if (TileX(tile) < 2 || TileY(tile) < 2 || MapMaxX() <= TileX(tile) || MapMaxY() <= TileY(tile)) return false;
   713 	if (TileX(tile) < 2 || TileX(tile) >= MapMaxX() || TileY(tile) < 2 || TileY(tile) >= MapMaxY()) return false;
   714 
   714 
   715 	Slope cur_slope, desired_slope;
   715 	Slope cur_slope, desired_slope;
   716 
       
   717 	/* If this assertion fails, it might be because the world contains
       
   718 	 *  land at the edges. This is not ok. */
       
   719 	TILE_ASSERT(tile);
       
   720 
   716 
   721 	for (;;) {
   717 	for (;;) {
   722 		/* Check if there already is a road at this point? */
   718 		/* Check if there already is a road at this point? */
   723 		if (GetTownRoadBits(tile) == ROAD_NONE) {
   719 		if (GetTownRoadBits(tile) == ROAD_NONE) {
   724 			/* No, try to build one in the direction.
   720 			/* No, try if we are able to build a road piece there.
   725 			 * if that fails clear the land, and if that fails exit.
   721 			 * If that fails clear the land, and if that fails exit.
   726 			 * This is to make sure that we can build a road here later. */
   722 			 * This is to make sure that we can build a road here later. */
   727 			if (CmdFailed(DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_X : ROAD_Y), 0, DC_AUTO, CMD_BUILD_ROAD)) &&
   723 			if (CmdFailed(DoCommand(tile, ((dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? ROAD_X : ROAD_Y), 0, DC_AUTO, CMD_BUILD_ROAD)) &&
   728 					CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
   724 					CmdFailed(DoCommand(tile, 0, 0, DC_AUTO, CMD_LANDSCAPE_CLEAR)))
   729 				return false;
   725 				return false;
   730 		}
   726 		}
   734 no_slope:
   730 no_slope:
   735 			/* Tile has no slope */
   731 			/* Tile has no slope */
   736 			switch (_patches.town_layout) {
   732 			switch (_patches.town_layout) {
   737 				default: NOT_REACHED();
   733 				default: NOT_REACHED();
   738 
   734 
   739 				case TL_ORIGINAL: /* Disallow the road if any neighboring tile has a road (distance: 1) */
   735 				case TL_ORIGINAL: // Disallow the road if any neighboring tile has a road (distance: 1)
   740 					return !IsNeighborRoadTile(tile, dir, 1);
   736 					return !IsNeighborRoadTile(tile, dir, 1);
   741 
   737 
   742 				case TL_BETTER_ROADS: /* Disallow the road if any neighboring tile has a road (distance: 1 and 2). */
   738 				case TL_BETTER_ROADS: // Disallow the road if any neighboring tile has a road (distance: 1 and 2).
   743 					return !IsNeighborRoadTile(tile, dir, 2);
   739 					return !IsNeighborRoadTile(tile, dir, 2);
   744 			}
   740 			}
   745 		}
   741 		}
   746 
   742 
   747 		/* If the tile is not a slope in the right direction, then
   743 		/* If the tile is not a slope in the right direction, then
   749 		desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NW : SLOPE_NE;
   745 		desired_slope = (dir == DIAGDIR_NW || dir == DIAGDIR_SE) ? SLOPE_NW : SLOPE_NE;
   750 		if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) {
   746 		if (desired_slope != cur_slope && ComplementSlope(desired_slope) != cur_slope) {
   751 			if (Chance16(1, 8)) {
   747 			if (Chance16(1, 8)) {
   752 				CommandCost res = CMD_ERROR;
   748 				CommandCost res = CMD_ERROR;
   753 				if (!_generating_world && Chance16(1, 10)) {
   749 				if (!_generating_world && Chance16(1, 10)) {
   754 					/* Note: Do not replace " ^ 0xF" with ComplementSlope(). The slope might be steep. */
   750 					/* Note: Do not replace "^ SLOPE_ELEVATED" with ComplementSlope(). The slope might be steep. */
   755 					res = DoCommand(tile, Chance16(1, 16) ? cur_slope : cur_slope ^ 0xF, 0,
   751 					res = DoCommand(tile, Chance16(1, 16) ? cur_slope : cur_slope ^ SLOPE_ELEVATED, 0,
   756 							DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
   752 							DC_EXEC | DC_AUTO | DC_NO_WATER, CMD_TERRAFORM_LAND);
   757 				}
   753 				}
   758 				if (CmdFailed(res) && Chance16(1, 3)) {
   754 				if (CmdFailed(res) && Chance16(1, 3)) {
   759 					/* We can consider building on the slope, though. */
   755 					/* We can consider building on the slope, though. */
   760 					goto no_slope;
   756 					goto no_slope;
   788 	if (IsTileType(tile, MP_HOUSE)) return;
   784 	if (IsTileType(tile, MP_HOUSE)) return;
   789 	tileh = GetTileSlope(tile, NULL);
   785 	tileh = GetTileSlope(tile, NULL);
   790 	if (tileh == SLOPE_FLAT) return;
   786 	if (tileh == SLOPE_FLAT) return;
   791 
   787 
   792 	/* First try up, then down */
   788 	/* First try up, then down */
   793 	if (!TerraformTownTile(tile, ~tileh & 0xF, 1)) {
   789 	if (!TerraformTownTile(tile, ~tileh & SLOPE_ELEVATED, 1)) {
   794 		TerraformTownTile(tile, tileh & 0xF, 0);
   790 		TerraformTownTile(tile, tileh & SLOPE_ELEVATED, 0);
   795 	}
   791 	}
   796 }
   792 }
   797 
   793 
   798 /**
   794 /**
   799  * Generate the RoadBits of a grid tile
   795  * Generate the RoadBits of a grid tile
   912  * @param t The current town
   908  * @param t The current town
   913  * @param tile The current tile
   909  * @param tile The current tile
   914  * @param bridge_dir The valid direction in which to grow a bridge
   910  * @param bridge_dir The valid direction in which to grow a bridge
   915  * @return true if a bridge has been build else false
   911  * @return true if a bridge has been build else false
   916  */
   912  */
   917 static bool GrowTownWithBridge(const Town *t, TileIndex tile, DiagDirection bridge_dir)
   913 static bool GrowTownWithBridge(const Town *t, const TileIndex tile, const DiagDirection bridge_dir)
   918 {
   914 {
   919 	assert(bridge_dir < DIAGDIR_END);
   915 	assert(bridge_dir < DIAGDIR_END);
   920 
   916 
   921 	const Slope slope = GetTileSlope(tile, NULL);
   917 	const Slope slope = GetTileSlope(tile, NULL);
   922 	if (slope == SLOPE_FLAT) return false; // no slope, no bridge
   918 	if (slope == SLOPE_FLAT) return false; // no slope, no bridge
   923 
   919 
   924 	/* Make sure the direction is compatible with the slope.
   920 	/* Make sure the direction is compatible with the slope.
   925 	 * If any of the following bits match, the slope is forbidden for
   921 	 * Well we check if the slope has an up bit set in the
   926 	 *  that diagdir. This means 5 non-steep slopes, and 3 steep-slopes
   922 	 * reverse direction. */
   927 	 *  per diagdir.
   923 	if (HASBITS(slope, InclinedSlope(bridge_dir))) return false;
   928 	 * 0 -> 0b1100
       
   929 	 * 1 -> 0b0110
       
   930 	 * 2 -> 0b0011
       
   931 	 * 3 -> 0b1001
       
   932 	 * 0xCC is 0b11001100, so we just shift it right with
       
   933 	 * the direction to get the forbidden slope mask. */
       
   934 	if (HASBITS(slope & 0x0F, 0xCC >> bridge_dir)) return false;
       
   935 
   924 
   936 	/* Assure that the bridge is connectable to the start side */
   925 	/* Assure that the bridge is connectable to the start side */
   937 	if (!(GetTownRoadBits(TileAddByDiagDir(tile, ReverseDiagDir(bridge_dir))) & DiagDirToRoadBits(bridge_dir))) return false;
   926 	if (!(GetTownRoadBits(TileAddByDiagDir(tile, ReverseDiagDir(bridge_dir))) & DiagDirToRoadBits(bridge_dir))) return false;
   938 
   927 
   939 	/* We are in the right direction */
   928 	/* We are in the right direction */
   940 	uint8 bridge_length = 0;     // This value stores the length of the possible bridge
   929 	uint8 bridge_length = 0;      // This value stores the length of the possible bridge
   941 	TileIndex bridge_tile = tile; // Used to store the other waterside
   930 	TileIndex bridge_tile = tile; // Used to store the other waterside
   942 
   931 
   943 	int delta = TileOffsByDiagDir(bridge_dir);
   932 	const int delta = TileOffsByDiagDir(bridge_dir);
   944 
       
   945 	do {
   933 	do {
   946 		if (bridge_length++ >= 11) {
   934 		if (bridge_length++ >= 11) {
   947 			/* Max 11 tile long bridges */
   935 			/* Max 11 tile long bridges */
   948 			return false;
   936 			return false;
   949 		}
   937 		}
   950 		bridge_tile += delta;
   938 		bridge_tile += delta;
   951 	} while (TileX(bridge_tile) != 0 && TileY(bridge_tile) != 0 && IsWaterTile(bridge_tile) && TileX(bridge_tile) != 0);
   939 	} while (TileX(bridge_tile) != 0 && TileY(bridge_tile) != 0 && IsWaterTile(bridge_tile));
   952 
   940 
   953 	/* no water tiles in between? */
   941 	/* no water tiles in between? */
   954 	if (bridge_length == 1) return false;
   942 	if (bridge_length == 1) return false;
   955 
   943 
   956 	for (uint8 times = 0; times <= 22; times++) {
   944 	for (uint8 times = 0; times <= 22; times++) {