/** * Applies a foundation to a slope. * * @pre Foundation and slope must be valid combined. * @param f The #Foundation. * @param s The #Slope to modify. * @return Increment to the tile Z coordinate. */ uint ApplyFoundationToSlope(Foundation f, Slope *s) { if (!IsFoundation(f)) return 0; if (IsLeveledFoundation(f)) { uint dz = TILE_HEIGHT + (IsSteepSlope(*s) ? TILE_HEIGHT : 0); *s = SLOPE_FLAT; return dz; } if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) { *s = HalftileSlope(*s, GetHalftileFoundationCorner(f)); return 0; } if (IsSpecialRailFoundation(f)) { *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f))); return 0; } uint dz = IsSteepSlope(*s) ? TILE_HEIGHT : 0; Corner highest_corner = GetHighestSlopeCorner(*s); switch (f) { case FOUNDATION_INCLINED_X: *s = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? SLOPE_SW : SLOPE_NE); break; case FOUNDATION_INCLINED_Y: *s = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? SLOPE_SE : SLOPE_NW); break; case FOUNDATION_STEEP_LOWER: *s = SlopeWithOneCornerRaised(highest_corner); break; case FOUNDATION_STEEP_BOTH: *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner); break; default: NOT_REACHED(); } return dz; }
/** * 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) { /* Steep slopes behave the same as slopes with one corner raised. */ if (IsSteepSlope(slope)) { slope = SlopeWithOneCornerRaised(GetHighestSlopeCorner(slope)); } /* 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(); } }