/**
 *
 *  rct2: 0x006D17C6
 */
static sint32 window_track_place_get_base_z(sint32 x, sint32 y)
{
    rct_tile_element *tileElement;
    sint32 z;

    tileElement = map_get_surface_element_at(x >> 5, y >> 5);
    z = tileElement->base_height * 8;

    // Increase Z above slope
    if (tileElement->properties.surface.slope & TILE_ELEMENT_SLOPE_ALL_CORNERS_UP) {
        z += 16;

        // Increase Z above double slope
        if (tileElement->properties.surface.slope & TILE_ELEMENT_SLOPE_DOUBLE_HEIGHT)
            z += 16;
    }

    // Increase Z above water
    if (map_get_water_height(tileElement) > 0)
        z = Math::Max(z, map_get_water_height(tileElement) << 4);

    return z + place_virtual_track(_trackDesign, PTD_OPERATION_GET_PLACE_Z, true, 0, x, y, z);
}
Beispiel #2
0
static void cheat_set_grass_length(sint32 length)
{
    sint32 x, y;
    rct_tile_element *tileElement;

    for (y = 0; y < MAXIMUM_MAP_SIZE_TECHNICAL; y++) {
        for (x = 0; x < MAXIMUM_MAP_SIZE_TECHNICAL; x++) {
            tileElement = map_get_surface_element_at(x, y);
            if (!(tileElement->properties.surface.ownership & OWNERSHIP_OWNED))
                continue;

            if (tile_element_get_terrain(tileElement) != TERRAIN_GRASS)
                continue;

            if (map_get_water_height(tileElement) > 0)
                continue;

            tileElement->properties.surface.grass_length = length;
        }
    }

    gfx_invalidate_screen();
}
Beispiel #3
0
/**
 * Raises the corners based on the height offset of neighbour tiles.
 * This does not change the base height, unless all corners have been raised.
 * @returns 0 if no edits were made, 1 otherwise
 */
sint32 tile_smooth(sint32 x, sint32 y)
{
    rct_map_element *const surfaceElement = map_get_surface_element_at(x, y);

    // +-----+-----+-----+
    // | NW  |  N  | NE  |
    // |  2  |  1  |  0  |
    // +-----+-----+-----+
    // |  W  |  _  |  E  |
    // |  4  |     |  3  |
    // +-----+-----+-----+
    // | SW  |  S  | SE  |
    // |  7  |  6  |  5  |
    // +-----+-----+-----+
    union
    {
        sint32 baseheight[8];
        struct { sint32 NE, N, NW, E, W, SE, S, SW; };
    } neighbourHeightOffset = { 0 };

    // Find the neighbour base heights
    for (sint32 index = 0, y_offset = -1; y_offset <= 1; y_offset++)
    {
        for (sint32 x_offset = -1; x_offset <= 1; x_offset++)
        {
            // Skip self
            if (y_offset == 0 && x_offset == 0)
                continue;

            // Get neighbour height. If the element is not valid (outside of map) assume the same height
            rct_map_element *neighbour_element = map_get_surface_element_at(x + x_offset, y + y_offset);
            neighbourHeightOffset.baseheight[index] = neighbour_element ? neighbour_element->base_height : surfaceElement->base_height;

            // Make the height relative to the current surface element
            neighbourHeightOffset.baseheight[index] -= surfaceElement->base_height;

            index++;
        }
    }

    // Count number from the three tiles that is currently higher
    sint8 thresholdNW = clamp(neighbourHeightOffset.W, 0, 1) + clamp(neighbourHeightOffset.NW, 0, 1) + clamp(neighbourHeightOffset.N, 0, 1);
    sint8 thresholdNE = clamp(neighbourHeightOffset.N, 0, 1) + clamp(neighbourHeightOffset.NE, 0, 1) + clamp(neighbourHeightOffset.E, 0, 1);
    sint8 thresholdSE = clamp(neighbourHeightOffset.E, 0, 1) + clamp(neighbourHeightOffset.SE, 0, 1) + clamp(neighbourHeightOffset.S, 0, 1);
    sint8 thresholdSW = clamp(neighbourHeightOffset.S, 0, 1) + clamp(neighbourHeightOffset.SW, 0, 1) + clamp(neighbourHeightOffset.W, 0, 1);

    uint8 slope = 0;
    slope |= (thresholdNW >= 1) ? (1 << 1) : 0;
    slope |= (thresholdNE >= 1) ? (1 << 2) : 0;
    slope |= (thresholdSE >= 1) ? (1 << 3) : 0;
    slope |= (thresholdSW >= 1) ? (1 << 0) : 0;

    // Set diagonal when three corners have been raised, and the middle one can be raised one more
    if ((slope == 0b0111 && neighbourHeightOffset.NW >= 4) || (slope == 0b1011 && neighbourHeightOffset.SW >= 4) ||
        (slope == 0b1101 && neighbourHeightOffset.SE >= 4) || (slope == 0b1110 && neighbourHeightOffset.NE >= 4))
    {
        slope |= 1 << 4;
    }

    // Check if the calculated slope is the same already
    uint8 currentSlope = surfaceElement->properties.surface.slope & 0x1F;
    if (currentSlope == slope)
    {
        return 0;
    }

    // Remove old slope value
    surfaceElement->properties.surface.slope &= ~0x1F;
    if ((slope & 0xF) == 0xF)
    {
        // All corners are raised, raise the entire tile instead.
        surfaceElement->base_height = (surfaceElement->clearance_height += 2);
        uint8 waterHeight = map_get_water_height(surfaceElement) * 2;
        if (waterHeight <= surfaceElement->base_height)
        {
            surfaceElement->properties.surface.terrain &= ~MAP_ELEMENT_WATER_HEIGHT_MASK;
        }
    }
    else
    {
        // Apply the slope to this tile
        surfaceElement->properties.surface.slope |= slope;

        // Set correct clearance height
        if (slope & 0x10)
            surfaceElement->clearance_height = surfaceElement->base_height + 4;
        else if (slope & 0x0F)
            surfaceElement->clearance_height = surfaceElement->base_height + 2;
    }

    return 1;
}
Beispiel #4
0
/**
 *
 *  rct2: 0x0068B3FB
 */
static void sub_68B3FB(sint32 x, sint32 y)
{
    rct_drawpixelinfo *dpi = unk_140E9A8;

    gLeftTunnelCount = 0;
    gRightTunnelCount = 0;
    gLeftTunnels[0] = (tunnel_entry){0xFF, 0xFF};
    gRightTunnels[0] = (tunnel_entry){0xFF, 0xFF};

    gVerticalTunnelHeight = 0xFF;

#ifndef NO_RCT2
    RCT2_GLOBAL(0x009DE56A, uint16) = x;
    RCT2_GLOBAL(0x009DE56E, uint16) = y;
#endif
    gPaintMapPosition.x = x;
    gPaintMapPosition.y = y;

    rct_map_element* map_element = map_get_first_element_at(x >> 5, y >> 5);
    uint8 rotation = get_current_rotation();

    /* Check if the first (lowest) map_element is below the clip
     * height. */
    if ((gCurrentViewportFlags & VIEWPORT_FLAG_PAINT_CLIP_TO_HEIGHT) && (map_element->base_height > gClipHeight)) {
        blank_tiles_paint(x, y);
        return;
    }

    sint32 dx = 0;
    switch (rotation) {
    case 0:
        dx = x + y;
        break;
    case 1:
        x += 32;
        dx = y - x;
        break;
    case 2:
        x += 32;
        y += 32;
        dx = -(x + y);
        break;
    case 3:
        y += 32;
        dx = x - y;
        break;
    }
    dx >>= 1;
    // Display little yellow arrow when building footpaths?
    if ((gMapSelectFlags & MAP_SELECT_FLAG_ENABLE_ARROW) &&
        gPaintMapPosition.x == gMapSelectArrowPosition.x &&
        gPaintMapPosition.y == gMapSelectArrowPosition.y
    ) {
        uint8 arrowRotation =
            (rotation
            + (gMapSelectArrowDirection & 3)) & 3;

        uint32 imageId =
            arrowRotation +
            (gMapSelectArrowDirection & 0xFC) +
            0x20900C27;
        sint32 arrowZ = gMapSelectArrowPosition.z;

        gUnk9DE568 = x;
        gUnk9DE56C = y;
        gPaintInteractionType = VIEWPORT_INTERACTION_ITEM_NONE;

        sub_98197C(imageId, 0, 0, 32, 32, 0xFF, arrowZ, 0, 0, arrowZ + 18, rotation);
    }
    sint32 bx = dx + 52;

    if (bx <= dpi->y)
        return;

    const rct_map_element* element = map_element;//push map_element

    sint16 max_height = 0;
    do{
        max_height = max(max_height, element->clearance_height);
    } while (!map_element_is_last_for_tile(element++));

    element--;

    if (map_element_get_type(element) == MAP_ELEMENT_TYPE_SURFACE &&
        (map_get_water_height(element) > 0))
    {
        max_height = map_get_water_height(element) * 2;
    }

    max_height *= 8;

    dx -= max_height + 32;

    element = map_element;//pop map_element
    dx -= dpi->height;
    if (dx >= dpi->y)
        return;

    gUnk9DE568 = x;
    gUnk9DE56C = y;
    gDidPassSurface = false;
    do {
        // Only paint map_elements below the clip height.
        if ((gCurrentViewportFlags & VIEWPORT_FLAG_PAINT_CLIP_TO_HEIGHT) && (map_element->base_height > gClipHeight)) break;

        sint32 direction = map_element_get_direction_with_offset(map_element, rotation);
        sint32 height = map_element->base_height * 8;

        rct_xy16 dword_9DE574 = gPaintMapPosition;
        g_currently_drawn_item = map_element;
        // Setup the painting of for example: the underground, signs, rides, scenery, etc.
        switch (map_element_get_type(map_element))
        {
        case MAP_ELEMENT_TYPE_SURFACE:
            surface_paint(direction, height, map_element);
            break;
        case MAP_ELEMENT_TYPE_PATH:
            path_paint(direction, height, map_element);
            break;
        case MAP_ELEMENT_TYPE_TRACK:
            track_paint(direction, height, map_element);
            break;
        case MAP_ELEMENT_TYPE_SCENERY:
            scenery_paint(direction, height, map_element);
            break;
        case MAP_ELEMENT_TYPE_ENTRANCE:
            entrance_paint(direction, height, map_element);
            break;
        case MAP_ELEMENT_TYPE_WALL:
            fence_paint(direction, height, map_element);
            break;
        case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE:
            scenery_multiple_paint(direction, height, map_element);
            break;
        case MAP_ELEMENT_TYPE_BANNER:
            banner_paint(direction, height, map_element);
            break;
        // A corrupt element inserted by OpenRCT2 itself, which skips the drawing of the next element only.
        case MAP_ELEMENT_TYPE_CORRUPT:
            if (map_element_is_last_for_tile(map_element))
                return;
            map_element++;
            break;
        default:
            // An undefined map element is most likely a corrupt element inserted by 8 cars' MOM feature to skip drawing of all elements after it.
            return;
        }
        gPaintMapPosition = dword_9DE574;
    } while (!map_element_is_last_for_tile(map_element++));

    if (!gShowSupportSegmentHeights) {
        return;
    }

    if (map_element_get_type(map_element - 1) == MAP_ELEMENT_TYPE_SURFACE) {
        return;
    }

    static const sint32 segmentPositions[][3] = {
        {0, 6, 2},
        {5, 4, 8},
        {1, 7, 3},
    };

    for (sint32 sy = 0; sy < 3; sy++) {
        for (sint32 sx = 0; sx < 3; sx++) {
            uint16 segmentHeight = gSupportSegments[segmentPositions[sy][sx]].height;
            sint32 imageColourFlats = 0b101111 << 19 | IMAGE_TYPE_TRANSPARENT;
            if (segmentHeight == 0xFFFF) {
                segmentHeight = gSupport.height;
                // white: 0b101101
                imageColourFlats = 0b111011 << 19 | IMAGE_TYPE_TRANSPARENT;
            }

            // Only draw supports below the clipping height.
            if ((gCurrentViewportFlags & VIEWPORT_FLAG_PAINT_CLIP_TO_HEIGHT) && (segmentHeight > gClipHeight)) continue;

            sint32 xOffset = sy * 10;
            sint32 yOffset = -22 + sx * 10;
            paint_struct * ps = sub_98197C(5504 | imageColourFlats, xOffset, yOffset, 10, 10, 1, segmentHeight, xOffset + 1, yOffset + 16, segmentHeight, get_current_rotation());
            if (ps != NULL) {
                ps->flags &= PAINT_STRUCT_FLAG_IS_MASKED;
                ps->colour_image_id = COLOUR_BORDEAUX_RED;
            }

        }
    }
}
Beispiel #5
0
/**
 * Randomly places a selection of preset trees on the map. Picks the right tree for the terrain it is placing it on.
 */
static void mapgen_place_trees()
{
    sint32 numGrassTreeIds = 0, numDesertTreeIds = 0, numSnowTreeIds = 0;
    sint32 *grassTreeIds = (sint32*)malloc(countof(GrassTrees) * sizeof(sint32));
    sint32 *desertTreeIds = (sint32*)malloc(countof(DesertTrees) * sizeof(sint32));
    sint32 *snowTreeIds = (sint32*)malloc(countof(SnowTrees) * sizeof(sint32));

    for (sint32 i = 0; i < object_entry_group_counts[OBJECT_TYPE_SMALL_SCENERY]; i++) {
        rct_scenery_entry *sceneryEntry = get_small_scenery_entry(i);
        rct_object_entry_extended *entry = &object_entry_groups[OBJECT_TYPE_SMALL_SCENERY].entries[i];

        if (sceneryEntry == (rct_scenery_entry*)-1 || sceneryEntry == NULL)
            continue;

        sint32 j;
        for (j = 0; j < countof(GrassTrees); j++)
            if (strncmp(GrassTrees[j], entry->name, 8) == 0)
                break;
        if (j != countof(GrassTrees)) {
            grassTreeIds[numGrassTreeIds++] = i;
            continue;
        }

        for (j = 0; j < countof(DesertTrees); j++)
            if (strncmp(DesertTrees[j], entry->name, 8) == 0)
                break;
        if (j != countof(DesertTrees)) {
            desertTreeIds[numDesertTreeIds++] = i;
            continue;
        }

        for (j = 0; j < countof(SnowTrees); j++)
            if (strncmp(SnowTrees[j], entry->name, 8) == 0)
                break;
        if (j != countof(SnowTrees)) {
            snowTreeIds[numSnowTreeIds++] = i;
            continue;
        }
    }

    sint32 availablePositionsCount = 0;
    struct { sint32 x; sint32 y; } tmp, *pos, *availablePositions;
    availablePositions = malloc(MAXIMUM_MAP_SIZE_TECHNICAL * MAXIMUM_MAP_SIZE_TECHNICAL * sizeof(tmp));

    // Create list of available tiles
    for (sint32 y = 1; y < gMapSize - 1; y++) {
        for (sint32 x = 1; x < gMapSize - 1; x++) {
            rct_map_element *mapElement = map_get_surface_element_at(x, y);

            // Exclude water tiles
            if (map_get_water_height(mapElement) > 0)
                continue;

            pos = &availablePositions[availablePositionsCount++];
            pos->x = x;
            pos->y = y;
        }
    }

    // Shuffle list
    for (sint32 i = 0; i < availablePositionsCount; i++) {
        sint32 rindex = util_rand() % availablePositionsCount;
        if (rindex == i)
            continue;

        tmp = availablePositions[i];
        availablePositions[i] = availablePositions[rindex];
        availablePositions[rindex] = tmp;
    }

    // Place trees
    float treeToLandRatio = (10 + (util_rand() % 30)) / 100.0f;
    sint32 numTrees = max(4, (sint32)(availablePositionsCount * treeToLandRatio));

    for (sint32 i = 0; i < numTrees; i++) {
        pos = &availablePositions[i];

        sint32 type = -1;
        rct_map_element *mapElement = map_get_surface_element_at(pos->x, pos->y);
        switch (map_element_get_terrain(mapElement)) {
        case TERRAIN_GRASS:
        case TERRAIN_DIRT:
        case TERRAIN_GRASS_CLUMPS:
            if (numGrassTreeIds == 0)
                break;

            type = grassTreeIds[util_rand() % numGrassTreeIds];
            break;

        case TERRAIN_SAND:
        case TERRAIN_SAND_DARK:
        case TERRAIN_SAND_LIGHT:
            if (numDesertTreeIds == 0)
                break;

            if (util_rand() % 4 == 0)
                type = desertTreeIds[util_rand() % numDesertTreeIds];
            break;

        case TERRAIN_ICE:
            if (numSnowTreeIds == 0)
                break;

            type = snowTreeIds[util_rand() % numSnowTreeIds];
            break;
        }

        if (type != -1)
            mapgen_place_tree(type, pos->x, pos->y);
    }

    free(availablePositions);
    free(grassTreeIds);
    free(desertTreeIds);
    free(snowTreeIds);
}