/** * 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; } }
/** * 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(); } }