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