예제 #1
0
/**
 * Lookup function for building road parts when building on slopes is disabled.
 * @param slope The slope of the tile to examine.
 * @param existing The existing road parts.
 * @param start The part that should be build first.
 * @param end The part that will be build second.
 * @return 0 when the build parts do not connect, 1 when they do connect once
 *         they are build or 2 when building the first part automatically
 *         builds the second part.
 */
static int32 LookupWithoutBuildOnSlopes(::Slope slope, const Array *existing, int32 start, int32 end)
{
	switch (slope) {
		/* Flat slopes can always be build. */
		case SLOPE_FLAT:
			return 1;

		/* Only 4 of the slopes can be build upon. Testing the existing bits is
		 * necessary because these bits can be something else when the settings
		 * in the game have been changed.
		 */
		case SLOPE_NE: case SLOPE_SW:
			return (CheckAutoExpandedRoadBits(existing, start, end) && (start == 1 || end == 1)) ? (existing->size == 0 ? 2 : 1) : 0;
		case SLOPE_SE: case SLOPE_NW:
			return (CheckAutoExpandedRoadBits(existing, start, end) && (start != 1 && end != 1)) ? (existing->size == 0 ? 2 : 1) : 0;

		/* Any other tile cannot be built on. */
		default:
			return 0;
	}
}
예제 #2
0
/**
 * Lookup function for building road parts when building on slopes is enabled.
 * @param slope The slope of the tile to examine.
 * @param existing The existing neighbours.
 * @param start The part that should be build first.
 * @param end The part that will be build second.
 * @return 0 when the build parts do not connect, 1 when they do connect once
 *         they are build or 2 when building the first part automatically
 *         builds the second part.
 */
static int32 LookupWithBuildOnSlopes(::Slope slope, Array *existing, int32 start, int32 end)
{
	if (::IsSteepSlope(slope)) {
		switch (slope) {
			/* On steep slopes one can only build straight roads that will be
			 * automatically expanded to a straight road. Just check that the existing
			 * road parts are in the same direction. */
			case SLOPE_STEEP_S:
			case SLOPE_STEEP_W:
			case SLOPE_STEEP_N:
			case SLOPE_STEEP_E:
				return CheckAutoExpandedRoadBits(existing, start, end) ? (existing->size == 0 ? 2 : 1) : 0;

			/* All other slopes are invalid slopes!. */
			default:
				return -1;
		}
	}

	/* The slope is not steep. Furthermore lots of slopes are generally the
	 * same but are only rotated. So to reduce the amount of lookup work that
	 * needs to be done the data is made uniform. This means rotating the
	 * existing parts and updating the slope. */
	static const ::Slope base_slopes[] = {
		SLOPE_FLAT, SLOPE_W,   SLOPE_W,   SLOPE_SW,
		SLOPE_W,    SLOPE_EW,  SLOPE_SW,  SLOPE_WSE,
		SLOPE_W,    SLOPE_SW,  SLOPE_EW,  SLOPE_WSE,
		SLOPE_SW,   SLOPE_WSE, SLOPE_WSE};
	static const byte base_rotates[] = {0, 0, 1, 0, 2, 0, 1, 0, 3, 3, 2, 3, 2, 2, 1};

	if (slope >= (::Slope)lengthof(base_slopes)) {
		/* This slope is an invalid slope, so ignore it. */
		return -1;
	}
	byte base_rotate = base_rotates[slope];
	slope = base_slopes[slope];

	/* Some slopes don't need rotating, so return early when we know we do
	 * not need to rotate. */
	switch (slope) {
		case SLOPE_FLAT:
			/* Flat slopes can always be build. */
			return 1;

		case SLOPE_EW:
		case SLOPE_WSE:
			/* A slope similar to a SLOPE_EW or SLOPE_WSE will always cause
			 * foundations which makes them accessible from all sides. */
			return 1;

		case SLOPE_W:
		case SLOPE_SW:
			/* A slope for which we need perform some calculations. */
			break;

		default:
			/* An invalid slope. */
			return -1;
	}

	/* Now perform the actual rotation. */
	for (int j = 0; j < base_rotate; j++) {
		for (int i = 0; i < existing->size; i++) {
			existing->array[i] = RotateNeighbour(existing->array[i]);
		}
		start = RotateNeighbour(start);
		end   = RotateNeighbour(end);
	}

	/* Create roadbits out of the data for easier handling. */
	RoadBits start_roadbits    = NeighbourToRoadBits(start);
	RoadBits new_roadbits      = start_roadbits | NeighbourToRoadBits(end);
	RoadBits existing_roadbits = ROAD_NONE;
	for (int i = 0; i < existing->size; i++) {
		existing_roadbits |= NeighbourToRoadBits(existing->array[i]);
	}

	switch (slope) {
		case SLOPE_W:
			/* A slope similar to a SLOPE_W. */
			switch (new_roadbits) {
				case ROAD_N:
				case ROAD_E:
				case ROAD_S:
					/* Cannot build anything with a turn from the low side. */
					return 0;

				case ROAD_X:
				case ROAD_Y:
					/* A 'sloped' tile is going to be build. */
					if ((existing_roadbits | new_roadbits) != new_roadbits) {
						/* There is already a foundation on the tile, or at least
						 * another slope that is not compatible with the new one. */
						return 0;
					}
					/* If the start is in the low part, it is automatically
					 * building the second part too. */
					return ((start_roadbits & ROAD_E) && !(existing_roadbits & ROAD_W)) ? 2 : 1;

				default:
					/* Roadbits causing a foundation are going to be build.
					 * When the existing roadbits are slopes (the lower bits
					 * are used), this cannot be done. */
					if ((existing_roadbits | new_roadbits) == new_roadbits) return 1;
					return (existing_roadbits & ROAD_E) ? 0 : 1;
			}

		case SLOPE_SW:
			/* A slope similar to a SLOPE_SW. */
			switch (new_roadbits) {
				case ROAD_N:
				case ROAD_E:
					/* Cannot build anything with a turn from the low side. */
					return 0;

				case ROAD_X:
					/* A 'sloped' tile is going to be build. */
					if ((existing_roadbits | new_roadbits) != new_roadbits) {
						/* There is already a foundation on the tile, or at least
						 * another slope that is not compatible with the new one. */
						return 0;
					}
					/* If the start is in the low part, it is automatically
					 * building the second part too. */
					return ((start_roadbits & ROAD_NE) && !(existing_roadbits & ROAD_SW)) ? 2 : 1;

				default:
					/* Roadbits causing a foundation are going to be build.
					 * When the existing roadbits are slopes (the lower bits
					 * are used), this cannot be done. */
					return (existing_roadbits & ROAD_NE) ? 0 : 1;
			}

		default:
			NOT_REACHED();
	}
}