diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index 601b403f64..667f7b4eda 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -333,6 +333,7 @@ + diff --git a/src/openrct2/paint/map_element/fence.c b/src/openrct2/paint/map_element/fence.c index 733a3701ea..0e6bc7e5f9 100644 --- a/src/openrct2/paint/map_element/fence.c +++ b/src/openrct2/paint/map_element/fence.c @@ -384,7 +384,3 @@ void fence_paint(uint8 direction, sint32 height, rct_map_element * map_element) sub_98199C(scrolling_text_setup(stringId, scroll, scrollingMode), 0, 0, 1, 1, 13, height + 8, boundsOffset.x, boundsOffset.y, boundsOffset.z, get_current_rotation()); } - -uint8 fence_get_animation_frame(rct_map_element *fenceElement) { - return (fenceElement->properties.fence.animation >> 3) & 0xF; -} diff --git a/src/openrct2/world/fence.cpp b/src/openrct2/world/fence.cpp new file mode 100644 index 0000000000..400239c775 --- /dev/null +++ b/src/openrct2/world/fence.cpp @@ -0,0 +1,717 @@ +#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers +/***************************************************************************** + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * OpenRCT2 is the work of many authors, a full list can be found in contributors.md + * For more information, visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * A full copy of the GNU General Public License can be found in licence.txt + *****************************************************************************/ +#pragma endregion + +#include "../common.h" +#include "../network/network.h" + +extern "C" +{ + #include "map.h" + #include "park.h" + #include "scenery.h" + #include "../cheats.h" + #include "../game.h" + #include "../ride/track.h" + #include "../ride/track_data.h" + #include "../localisation/string_ids.h" +} + +static bool gWallAcrossTrack; + +extern "C" +{ + uint8 fence_get_animation_frame(rct_map_element *fenceElement) { + return (fenceElement->properties.fence.animation >> 3) & 0xF; + } + + rct_map_element *map_get_fence_element_at(sint32 x, sint32 y, sint32 z, sint32 direction) + { + rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) + continue; + if (mapElement->base_height != z) + continue; + if (map_element_get_direction(mapElement) != direction) + continue; + + return mapElement; + } while (!map_element_is_last_for_tile(mapElement++)); + return NULL; + } + + /** + * + * rct2: 0x006E588E + */ + void map_remove_walls_at(sint32 x, sint32 y, sint32 z0, sint32 z1) + { + rct_map_element *mapElement; + + z0 /= 8; + z1 /= 8; + repeat: + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) + continue; + if (z0 >= mapElement->clearance_height) + continue; + if (z1 <= mapElement->base_height) + continue; + + map_element_remove_banner_entry(mapElement); + map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->base_height * 8 + 72); + map_element_remove(mapElement); + goto repeat; + } while (!map_element_is_last_for_tile(mapElement++)); + } + + /** + * + * rct2: 0x006E57E6 + */ + void map_remove_walls_at_z(sint32 x, sint32 y, sint32 z) + { + map_remove_walls_at(x, y, z, z + 48); + } + + /** + * + * rct2: 0x006E5935 + */ + void map_remove_intersecting_walls(sint32 x, sint32 y, sint32 z0, sint32 z1, sint32 direction) + { + rct_map_element *mapElement; + + mapElement = map_get_first_element_at(x >> 5, y >> 5); + do { + if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) + continue; + + if (mapElement->clearance_height <= z0 || mapElement->base_height >= z1) + continue; + + if (direction != (mapElement->type & 3)) + continue; + + map_element_remove_banner_entry(mapElement); + map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->base_height * 8 + 72); + map_element_remove(mapElement); + mapElement--; + } while (!map_element_is_last_for_tile(mapElement++)); + } + + /** + * + * rct2: 0x006E5CBA + */ + static bool map_place_fence_check_obstruction_with_track(rct_scenery_entry *wall, sint32 x, sint32 y, sint32 z0, sint32 z1, sint32 edge, rct_map_element *trackElement) + { + const rct_preview_track *trackBlock; + sint32 z, direction; + + sint32 trackType = trackElement->properties.track.type; + sint32 sequence = trackElement->properties.track.sequence & 0x0F; + direction = (edge - trackElement->type) & 3; + rct_ride *ride = get_ride(trackElement->properties.track.ride_index); + + if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { + if (FlatRideTrackSequenceElementAllowedWallEdges[trackType][sequence] & (1 << direction)) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_TRACK_NO_WALLS)) { + return true; + } + } + } else { + if (TrackSequenceElementAllowedWallEdges[trackType][sequence] & (1 << direction)) { + if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_TRACK_NO_WALLS)) { + return true; + } + } + } + + if (!(wall->wall.flags & WALL_SCENERY_IS_DOOR)) { + return false; + } + + if (!(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_0)) { + return false; + } + + rct_ride_entry *rideEntry = get_ride_entry(ride->subtype); + if (rideEntry->flags & RIDE_ENTRY_FLAG_16) { + return false; + } + + gWallAcrossTrack = true; + if (z0 & 1) { + return false; + } + + if (sequence == 0) { + if (TrackSequenceProperties[trackType][0] & TRACK_SEQUENCE_FLAG_DISALLOW_DOORS) { + return false; + } + + if (TrackDefinitions[trackType].bank_start == 0) { + if (!(TrackCoordinates[trackType].rotation_begin & 4)) { + direction = (trackElement->type & 3) ^ 2; + if (direction == edge) { + trackBlock = &TrackBlocks[trackType][sequence]; + z = TrackCoordinates[trackType].z_begin; + z = trackElement->base_height + ((z - trackBlock->z) * 8); + if (z == z0) { + return true; + } + } + } + } + } + + trackBlock = &TrackBlocks[trackType][sequence + 1]; + if (trackBlock->index != 0xFF) { + return false; + } + + if (TrackDefinitions[trackType].bank_end != 0) { + return false; + } + + direction = TrackCoordinates[trackType].rotation_end; + if (direction & 4) { + return false; + } + + direction = (trackElement->type + direction) & 3; + if (direction != edge) { + return false; + } + + trackBlock = &TrackBlocks[trackType][sequence]; + z = TrackCoordinates[trackType].z_end; + z = trackElement->base_height + ((z - trackBlock->z) * 8); + if (z != z0) { + return false; + } + + return true; + } + + /** + * + * rct2: 0x006E5C1A + */ + static bool map_place_fence_check_obstruction(rct_scenery_entry *wall, sint32 x, sint32 y, sint32 z0, sint32 z1, sint32 edge) + { + sint32 entryType, sequence; + rct_scenery_entry *entry; + rct_large_scenery_tile *tile; + + gWallAcrossTrack = false; + gMapGroundFlags = ELEMENT_IS_ABOVE_GROUND; + if (map_is_location_at_edge(x, y)) { + gGameCommandErrorText = STR_OFF_EDGE_OF_MAP; + return false; + } + + rct_map_element *mapElement = map_get_first_element_at(x / 32, y / 32); + do { + sint32 elementType = map_element_get_type(mapElement); + if (elementType == MAP_ELEMENT_TYPE_SURFACE) continue; + if (z0 >= mapElement->clearance_height) continue; + if (z1 <= mapElement->base_height) continue; + if (elementType == MAP_ELEMENT_TYPE_FENCE) { + sint32 direction = mapElement->type & 3; + if (edge == direction) { + map_obstruction_set_error_text(mapElement); + return false; + } + continue; + } + if ((mapElement->flags & 0x0F) == 0) continue; + + switch (elementType) { + case MAP_ELEMENT_TYPE_ENTRANCE: + map_obstruction_set_error_text(mapElement); + return false; + case MAP_ELEMENT_TYPE_PATH: + if (mapElement->properties.path.edges & (1 << edge)) { + map_obstruction_set_error_text(mapElement); + return false; + } + break; + case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: + entryType = mapElement->properties.scenerymultiple.type & 0x3FF; + sequence = mapElement->properties.scenerymultiple.type >> 10; + entry = get_large_scenery_entry(entryType); + tile = &entry->large_scenery.tiles[sequence]; + { + sint32 direction = ((edge - mapElement->type) & 3) + 8; + if (!(tile->var_7 & (1 << direction))) { + map_obstruction_set_error_text(mapElement); + return false; + } + } + break; + case MAP_ELEMENT_TYPE_SCENERY: + entryType = mapElement->properties.scenery.type; + entry = get_small_scenery_entry(entryType); + if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_ALLOW_WALLS) { + map_obstruction_set_error_text(mapElement); + return false; + } + break; + case MAP_ELEMENT_TYPE_TRACK: + if (!map_place_fence_check_obstruction_with_track(wall, x, y, z0, z1, edge, mapElement)) { + return false; + } + break; + } + } while (!map_element_is_last_for_tile(mapElement++)); + return true; + } + + enum + { + EDGE_SLOPE_ELEVATED = (1 << 0), // 0x01 + EDGE_SLOPE_UPWARDS = (1 << 6), // 0x40 + EDGE_SLOPE_DOWNWARDS = (1 << 7), // 0x80 + + EDGE_SLOPE_UPWARDS_ELEVATED = EDGE_SLOPE_UPWARDS | EDGE_SLOPE_ELEVATED, + EDGE_SLOPE_DOWNWARDS_ELEVATED = EDGE_SLOPE_DOWNWARDS | EDGE_SLOPE_ELEVATED, + }; + + /** rct2: 0x009A3FEC */ + static const uint8 EdgeSlopes[][4] = { + // Top right Bottom right Bottom left Top left + { 0, 0, 0, 0 }, + { 0, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS, 0 }, + { 0, 0, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS }, + { 0, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS }, + { EDGE_SLOPE_DOWNWARDS, 0, 0, EDGE_SLOPE_UPWARDS }, + { EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS }, + { EDGE_SLOPE_DOWNWARDS, 0, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED }, + { EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED }, + { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS, 0, 0 }, + { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS, 0 }, + { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS }, + { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS }, + { EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS, 0, EDGE_SLOPE_UPWARDS }, + { EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS }, + { EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED }, + { EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_UPWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS_ELEVATED }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { 0, 0, 0, 0 }, + { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_UPWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS }, + { 0, 0, 0, 0 }, + { EDGE_SLOPE_UPWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS }, + { EDGE_SLOPE_DOWNWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_UPWARDS_ELEVATED }, + { 0, 0, 0, 0 }, + }; + + /** + * + * rct2: 0x006E519A + */ + void game_command_place_fence(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp){ + rct_xyz16 position = { + *eax & 0xFFFF, + *ecx & 0xFFFF, + *edi & 0xFFFF + }; + + uint8 flags = *ebx & 0xFF; + uint8 fence_type = (*ebx >> 8) & 0xFF; + uint8 primary_colour = (*edx >> 8) & 0xFF; + uint8 secondary_colour = *ebp & 0xFF; + uint8 tertiary_colour = (*ebp >> 8) & 0xFF; + uint8 edge = *edx & 0xFF; + + gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + gCommandPosition.x = position.x + 16; + gCommandPosition.y = position.y + 16; + gCommandPosition.z = position.z; + + if (position.z == 0){ + gCommandPosition.z = map_element_height(position.x, position.y) & 0xFFFF; + } + + if (game_is_paused() && !gCheatsBuildInPauseMode){ + gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && + !(flags & GAME_COMMAND_FLAG_7) && !gCheatsSandboxMode){ + + if (position.z == 0){ + if (!map_is_location_in_park(position.x, position.y)){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + else if (!map_is_location_owned(position.x, position.y, position.z)){ + *ebx = MONEY32_UNDEFINED; + return; + } + } + + uint8 bp = 0; + if (position.z == 0){ + rct_map_element* map_element = map_get_surface_element_at(position.x / 32, position.y / 32); + if (map_element == NULL){ + *ebx = MONEY32_UNDEFINED; + return; + } + position.z = map_element->base_height * 8; + + uint8 slope = map_element->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; + bp = EdgeSlopes[slope][edge & 3]; + if (bp & EDGE_SLOPE_ELEVATED) { + position.z += 16; + bp &= ~(1 << 0); + } + } + + rct_map_element* map_element = map_get_surface_element_at(position.x / 32, position.y / 32); + if (map_element == NULL){ + *ebx = MONEY32_UNDEFINED; + return; + } + + if (map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK){ + uint16 water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; + water_height *= 16; + + if (position.z < water_height){ + gGameCommandErrorText = STR_CANT_BUILD_THIS_UNDERWATER; + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if (position.z / 8 < map_element->base_height){ + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (!(bp & 0xC0)){ + uint8 new_edge = (edge + 2) & 3; + uint8 new_base_height = map_element->base_height; + new_base_height += 2; + if (map_element->properties.surface.slope & (1 << new_edge)){ + if (position.z / 8 < new_base_height){ + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (map_element->properties.surface.slope & (1 << 4)){ + new_edge = (new_edge - 1) & 3; + + if (map_element->properties.surface.slope & (1 << new_edge)){ + new_edge = (new_edge + 2) & 3; + if (map_element->properties.surface.slope & (1 << new_edge)){ + new_base_height += 2; + if (position.z / 8 < new_base_height){ + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + new_base_height -= 2; + } + } + } + } + + new_edge = (edge + 3) & 3; + if (map_element->properties.surface.slope & (1 << new_edge)){ + if (position.z / 8 < new_base_height){ + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + + if (map_element->properties.surface.slope & (1 << 4)){ + new_edge = (new_edge - 1) & 3; + + if (map_element->properties.surface.slope & (1 << new_edge)){ + new_edge = (new_edge + 2) & 3; + if (map_element->properties.surface.slope & (1 << new_edge)){ + new_base_height += 2; + if (position.z / 8 < new_base_height){ + gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; + *ebx = MONEY32_UNDEFINED; + return; + } + } + } + } + } + } + sint32 banner_index = 0xFF; + rct_scenery_entry* fence = get_wall_entry(fence_type); + // Have to check both -1 and NULL, as one can be a invalid object, + // while the other can be invalid index + if ((uintptr_t)fence == (uintptr_t)-1 || fence == NULL) { + *ebx = MONEY32_UNDEFINED; + return; + } + if (fence->wall.scrolling_mode != 0xFF){ + banner_index = create_new_banner(flags); + + if (banner_index == 0xFF){ + *ebx = MONEY32_UNDEFINED; + return; + } + + rct_banner* banner = &gBanners[banner_index]; + if (flags & GAME_COMMAND_FLAG_APPLY){ + banner->flags |= (1 << 3); + banner->type = 0; + banner->x = position.x / 32; + banner->y = position.y / 32; + + sint32 rideIndex = banner_get_closest_ride_index(position.x, position.y, position.z); + if (rideIndex != -1) { + banner->colour = rideIndex & 0xFF; + banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; + } + } + } + + uint8 clearanceHeight = position.z / 8; + if (bp & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) { + if (fence->wall.flags & WALL_SCENERY_CANT_BUILD_ON_SLOPE){ + gGameCommandErrorText = STR_ERR_UNABLE_TO_BUILD_THIS_ON_SLOPE; + *ebx = MONEY32_UNDEFINED; + return; + } + clearanceHeight += 2; + } + clearanceHeight += fence->wall.height; + + if (!(flags & GAME_COMMAND_FLAG_7) && !gCheatsDisableClearanceChecks){ + if (!map_place_fence_check_obstruction(fence, position.x, position.y, position.z / 8, clearanceHeight, edge)) { + *ebx = MONEY32_UNDEFINED; + return; + } + } + + if (!map_check_free_elements_and_reorganise(1)){ + *ebx = MONEY32_UNDEFINED; + return; + } + + if (flags & GAME_COMMAND_FLAG_APPLY){ + if (gGameCommandNestLevel == 1 && !(*ebx & GAME_COMMAND_FLAG_GHOST)) { + rct_xyz16 coord; + coord.x = position.x + 16; + coord.y = position.y + 16; + coord.z = map_element_height(coord.x, coord.y); + network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); + } + + map_element = map_element_insert(position.x / 32, position.y / 32, position.z / 8, 0); + assert(map_element != NULL); + + map_animation_create(MAP_ANIMATION_TYPE_WALL, position.x, position.y, position.z / 8); + + map_element->clearance_height = clearanceHeight; + + map_element->type = bp | edge | MAP_ELEMENT_TYPE_FENCE; + + map_element->properties.fence.colour_1 = primary_colour; + map_element->properties.fence.colour_1 |= (secondary_colour & 7) << 5; + map_element->flags |= (secondary_colour & 0x18) << 2; + + if (gWallAcrossTrack) { + map_element->properties.fence.animation |= (1 << 2); + } + + map_element->properties.fence.type = fence_type; + if (banner_index != 0xFF){ + map_element->properties.fence.banner_index = banner_index; + } + + if (fence->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR){ + map_element->properties.fence.colour_3 = tertiary_colour; + } + + if (flags & (1 << 6)){ + map_element->flags |= MAP_ELEMENT_FLAG_GHOST; + } + + gSceneryMapElement = map_element; + map_invalidate_tile_zoom1(position.x, position.y, map_element->base_height * 8, map_element->base_height * 8 + 72); + } + + if (gParkFlags & PARK_FLAGS_NO_MONEY){ + *ebx = 0; + } + else{ + *ebx = fence->wall.price; + } + } + + money32 map_place_fence( + sint32 type, sint32 x, sint32 y, sint32 z, sint32 edge, sint32 primaryColour, sint32 secondaryColour, sint32 tertiaryColour, sint32 flags + ) { + sint32 eax, ebx, ecx, edx, esi, edi, ebp; + + eax = x; + ebx = flags | (type << 8); + ecx = y; + edx = edge | (primaryColour << 8); + edi = z; + ebp = secondaryColour | (tertiaryColour << 8); + game_command_place_fence(&eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); + return ebx; + } + + + /** + * + * rct2: 0x006E5597 + */ + void game_command_remove_fence(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) + { + sint32 x = *eax; + sint32 y = *ecx; + if (!map_is_location_valid(x, y)) { + *ebx = MONEY32_UNDEFINED; + return; + } + uint8 base_height = (*edx >> 8); + uint8 direction = *edx; + uint8 flags = *ebx & 0xFF; + + gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + if(!(flags & GAME_COMMAND_FLAG_GHOST) && game_is_paused() && !gCheatsBuildInPauseMode){ + gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; + *ebx = MONEY32_UNDEFINED; + return; + } + if(!(flags & GAME_COMMAND_FLAG_GHOST) && !(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(x, y, base_height * 8)){ + *ebx = MONEY32_UNDEFINED; + return; + } + + bool sceneryFound = false; + rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); + do { + if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_FENCE) + continue; + if (map_element->base_height != base_height) + continue; + if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != direction) + continue; + if ((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)) + continue; + + sceneryFound = true; + break; + } while (!map_element_is_last_for_tile(map_element++)); + + if (!(*ebx & GAME_COMMAND_FLAG_APPLY) || (sceneryFound == false)) { + *ebx = 0; + return; + } + + if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) { + rct_xyz16 coord; + coord.x = x + 16; + coord.y = y + 16; + coord.z = map_element_height(coord.x, coord.y); + network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); + } + + map_element_remove_banner_entry(map_element); + map_invalidate_tile_zoom1(x, y, map_element->base_height * 8, (map_element->base_height * 8) + 72); + map_element_remove(map_element); + *ebx = 0; + } + + /** + * + * rct2: 0x006E56B5 + */ + void game_command_set_fence_colour(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) + { + gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; + sint32 x = *eax; + sint32 y = *ecx; + uint8 map_element_direction = *edx; + uint8 base_height = *edx >> 8; + uint8 colour1 = *ebx >> 8; + uint8 colour2 = *ebp; + uint8 colour3 = *ebp >> 8; + uint8 flags = *ebx & 0xFF; + sint32 z = base_height * 8; + + gCommandPosition.x = x + 16; + gCommandPosition.y = y + 16; + gCommandPosition.z = z; + + if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && + !map_is_location_in_park(x, y) && + !gCheatsSandboxMode) { + + *ebx = MONEY32_UNDEFINED; + return; + } + + rct_map_element* map_element = map_get_fence_element_at(x, y, base_height, map_element_direction); + + if (map_element == NULL) { + *ebx = 0; + return; + } + + if ((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)) { + *ebx = 0; + return; + } + + if(flags & GAME_COMMAND_FLAG_APPLY){ + rct_scenery_entry* scenery_entry = get_wall_entry(map_element->properties.fence.type); + map_element->properties.fence.colour_1 &= 0xE0; + map_element->properties.fence.colour_1 |= colour1; + map_element->properties.fence.colour_1 &= 0x1F; + map_element->flags &= 0x9F; + map_element->properties.fence.colour_1 |= (colour2 & 0x7) * 32; + map_element->flags |= (colour2 & 0x18) * 4; + + if(scenery_entry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR){ + map_element->properties.fence.colour_3 = colour3; + } + map_invalidate_tile_zoom1(x, y, z, z + 72); + } + + *ebx = 0; + } +} diff --git a/src/openrct2/world/map.c b/src/openrct2/world/map.c index 6dbbcdaf57..def3c3a25b 100644 --- a/src/openrct2/world/map.c +++ b/src/openrct2/world/map.c @@ -128,13 +128,10 @@ rct_xyz16 gCommandPosition; uint8 gUnk9E2E28; -static bool gWallAcrossTrack; - static void map_update_grass_length(sint32 x, sint32 y, rct_map_element *mapElement); static void map_set_grass_length(sint32 x, sint32 y, rct_map_element *mapElement, sint32 length); static void clear_elements_at(sint32 x, sint32 y); static void translate_3d_to_2d(sint32 rotation, sint32 *x, sint32 *y); -static void map_obstruction_set_error_text(rct_map_element *mapElement); void rotate_map_coordinates(sint16 *x, sint16 *y, sint32 rotation) { @@ -1201,65 +1198,6 @@ void game_command_set_scenery_colour(sint32* eax, sint32* ebx, sint32* ecx, sint *ebx = 0; } -/** - * - * rct2: 0x006E56B5 - */ -void game_command_set_fence_colour(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) -{ - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - sint32 x = *eax; - sint32 y = *ecx; - uint8 map_element_direction = *edx; - uint8 base_height = *edx >> 8; - uint8 colour1 = *ebx >> 8; - uint8 colour2 = *ebp; - uint8 colour3 = *ebp >> 8; - uint8 flags = *ebx & 0xFF; - sint32 z = base_height * 8; - - gCommandPosition.x = x + 16; - gCommandPosition.y = y + 16; - gCommandPosition.z = z; - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && - !map_is_location_in_park(x, y) && - !gCheatsSandboxMode) { - - *ebx = MONEY32_UNDEFINED; - return; - } - - rct_map_element* map_element = map_get_fence_element_at(x, y, base_height, map_element_direction); - - if (map_element == NULL) { - *ebx = 0; - return; - } - - if ((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)) { - *ebx = 0; - return; - } - - if(flags & GAME_COMMAND_FLAG_APPLY){ - rct_scenery_entry* scenery_entry = get_wall_entry(map_element->properties.fence.type); - map_element->properties.fence.colour_1 &= 0xE0; - map_element->properties.fence.colour_1 |= colour1; - map_element->properties.fence.colour_1 &= 0x1F; - map_element->flags &= 0x9F; - map_element->properties.fence.colour_1 |= (colour2 & 0x7) * 32; - map_element->flags |= (colour2 & 0x18) * 4; - - if(scenery_entry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR){ - map_element->properties.fence.colour_3 = colour3; - } - map_invalidate_tile_zoom1(x, y, z, z + 72); - } - - *ebx = 0; -} - /** * * rct2: 0x006B909A @@ -2803,68 +2741,6 @@ void game_command_set_water_height(sint32* eax, sint32* ebx, sint32* ecx, sint32 } } -/** - * - * rct2: 0x006E5597 - */ -void game_command_remove_fence(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) -{ - sint32 x = *eax; - sint32 y = *ecx; - if (!map_is_location_valid(x, y)) { - *ebx = MONEY32_UNDEFINED; - return; - } - uint8 base_height = (*edx >> 8); - uint8 direction = *edx; - uint8 flags = *ebx & 0xFF; - - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - if(!(flags & GAME_COMMAND_FLAG_GHOST) && game_is_paused() && !gCheatsBuildInPauseMode){ - gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - *ebx = MONEY32_UNDEFINED; - return; - } - if(!(flags & GAME_COMMAND_FLAG_GHOST) && !(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && !gCheatsSandboxMode && !map_is_location_owned(x, y, base_height * 8)){ - *ebx = MONEY32_UNDEFINED; - return; - } - - bool sceneryFound = false; - rct_map_element* map_element = map_get_first_element_at(x / 32, y / 32); - do { - if (map_element_get_type(map_element) != MAP_ELEMENT_TYPE_FENCE) - continue; - if (map_element->base_height != base_height) - continue; - if ((map_element->type & MAP_ELEMENT_DIRECTION_MASK) != direction) - continue; - if ((flags & GAME_COMMAND_FLAG_GHOST) && !(map_element->flags & MAP_ELEMENT_FLAG_GHOST)) - continue; - - sceneryFound = true; - break; - } while (!map_element_is_last_for_tile(map_element++)); - - if (!(*ebx & GAME_COMMAND_FLAG_APPLY) || (sceneryFound == false)) { - *ebx = 0; - return; - } - - if (gGameCommandNestLevel == 1 && !(flags & GAME_COMMAND_FLAG_GHOST)) { - rct_xyz16 coord; - coord.x = x + 16; - coord.y = y + 16; - coord.z = map_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } - - map_element_remove_banner_entry(map_element); - map_invalidate_tile_zoom1(x, y, map_element->base_height * 8, (map_element->base_height * 8) + 72); - map_element_remove(map_element); - *ebx = 0; -} - /** * * rct2: 0x006B9E6D @@ -3283,488 +3159,11 @@ void game_command_place_scenery(sint32* eax, sint32* ebx, sint32* ecx, sint32* e } } -static bool map_is_location_at_edge(sint32 x, sint32 y) +bool map_is_location_at_edge(sint32 x, sint32 y) { return x < 32 || y < 32 || x >= ((256 - 1) * 32) || y >= ((256 - 1) * 32); } -/** - * - * rct2: 0x006E5CBA - */ -static bool map_place_fence_check_obstruction_with_track(rct_scenery_entry *wall, sint32 x, sint32 y, sint32 z0, sint32 z1, sint32 edge, rct_map_element *trackElement) -{ - const rct_preview_track *trackBlock; - sint32 z, direction; - - sint32 trackType = trackElement->properties.track.type; - sint32 sequence = trackElement->properties.track.sequence & 0x0F; - direction = (edge - trackElement->type) & 3; - rct_ride *ride = get_ride(trackElement->properties.track.ride_index); - - if (ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_FLAT_RIDE)) { - if (FlatRideTrackSequenceElementAllowedWallEdges[trackType][sequence] & (1 << direction)) { - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_TRACK_NO_WALLS)) { - return true; - } - } - } else { - if (TrackSequenceElementAllowedWallEdges[trackType][sequence] & (1 << direction)) { - if (!ride_type_has_flag(ride->type, RIDE_TYPE_FLAG_TRACK_NO_WALLS)) { - return true; - } - } - } - - if (!(wall->wall.flags & WALL_SCENERY_IS_DOOR)) { - return false; - } - - if (!(RideData4[ride->type].flags & RIDE_TYPE_FLAG4_0)) { - return false; - } - - rct_ride_entry *rideEntry = get_ride_entry(ride->subtype); - if (rideEntry->flags & RIDE_ENTRY_FLAG_16) { - return false; - } - - gWallAcrossTrack = true; - if (z0 & 1) { - return false; - } - - if (sequence == 0) { - if (TrackSequenceProperties[trackType][0] & TRACK_SEQUENCE_FLAG_DISALLOW_DOORS) { - return false; - } - - if (TrackDefinitions[trackType].bank_start == 0) { - if (!(TrackCoordinates[trackType].rotation_begin & 4)) { - direction = (trackElement->type & 3) ^ 2; - if (direction == edge) { - trackBlock = &TrackBlocks[trackType][sequence]; - z = TrackCoordinates[trackType].z_begin; - z = trackElement->base_height + ((z - trackBlock->z) * 8); - if (z == z0) { - return true; - } - } - } - } - } - - trackBlock = &TrackBlocks[trackType][sequence + 1]; - if (trackBlock->index != 0xFF) { - return false; - } - - if (TrackDefinitions[trackType].bank_end != 0) { - return false; - } - - direction = TrackCoordinates[trackType].rotation_end; - if (direction & 4) { - return false; - } - - direction = (trackElement->type + direction) & 3; - if (direction != edge) { - return false; - } - - trackBlock = &TrackBlocks[trackType][sequence]; - z = TrackCoordinates[trackType].z_end; - z = trackElement->base_height + ((z - trackBlock->z) * 8); - if (z != z0) { - return false; - } - - return true; -} - -/** - * - * rct2: 0x006E5C1A - */ -static bool map_place_fence_check_obstruction(rct_scenery_entry *wall, sint32 x, sint32 y, sint32 z0, sint32 z1, sint32 edge) -{ - sint32 entryType, sequence; - rct_scenery_entry *entry; - rct_large_scenery_tile *tile; - - gWallAcrossTrack = false; - gMapGroundFlags = ELEMENT_IS_ABOVE_GROUND; - if (map_is_location_at_edge(x, y)) { - gGameCommandErrorText = STR_OFF_EDGE_OF_MAP; - return false; - } - - rct_map_element *mapElement = map_get_first_element_at(x / 32, y / 32); - do { - sint32 elementType = map_element_get_type(mapElement); - if (elementType == MAP_ELEMENT_TYPE_SURFACE) continue; - if (z0 >= mapElement->clearance_height) continue; - if (z1 <= mapElement->base_height) continue; - if (elementType == MAP_ELEMENT_TYPE_FENCE) { - sint32 direction = mapElement->type & 3; - if (edge == direction) { - map_obstruction_set_error_text(mapElement); - return false; - } - continue; - } - if ((mapElement->flags & 0x0F) == 0) continue; - - switch (elementType) { - case MAP_ELEMENT_TYPE_ENTRANCE: - map_obstruction_set_error_text(mapElement); - return false; - case MAP_ELEMENT_TYPE_PATH: - if (mapElement->properties.path.edges & (1 << edge)) { - map_obstruction_set_error_text(mapElement); - return false; - } - break; - case MAP_ELEMENT_TYPE_SCENERY_MULTIPLE: - entryType = mapElement->properties.scenerymultiple.type & 0x3FF; - sequence = mapElement->properties.scenerymultiple.type >> 10; - entry = get_large_scenery_entry(entryType); - tile = &entry->large_scenery.tiles[sequence]; - - sint32 direction = ((edge - mapElement->type) & 3) + 8; - if (!(tile->var_7 & (1 << direction))) { - map_obstruction_set_error_text(mapElement); - return false; - } - break; - case MAP_ELEMENT_TYPE_SCENERY: - entryType = mapElement->properties.scenery.type; - entry = get_small_scenery_entry(entryType); - if (entry->small_scenery.flags & SMALL_SCENERY_FLAG_ALLOW_WALLS) { - map_obstruction_set_error_text(mapElement); - return false; - } - break; - case MAP_ELEMENT_TYPE_TRACK: - if (!map_place_fence_check_obstruction_with_track(wall, x, y, z0, z1, edge, mapElement)) { - return false; - } - break; - } - } while (!map_element_is_last_for_tile(mapElement++)); - return true; -} - -enum -{ - EDGE_SLOPE_ELEVATED = (1 << 0), // 0x01 - EDGE_SLOPE_UPWARDS = (1 << 6), // 0x40 - EDGE_SLOPE_DOWNWARDS = (1 << 7), // 0x80 - - EDGE_SLOPE_UPWARDS_ELEVATED = EDGE_SLOPE_UPWARDS | EDGE_SLOPE_ELEVATED, - EDGE_SLOPE_DOWNWARDS_ELEVATED = EDGE_SLOPE_DOWNWARDS | EDGE_SLOPE_ELEVATED, -}; - -/** rct2: 0x009A3FEC */ -static const uint8 EdgeSlopes[][4] = { -// Top right Bottom right Bottom left Top left - { 0, 0, 0, 0 }, - { 0, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS, 0 }, - { 0, 0, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS }, - { 0, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS }, - { EDGE_SLOPE_DOWNWARDS, 0, 0, EDGE_SLOPE_UPWARDS }, - { EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS }, - { EDGE_SLOPE_DOWNWARDS, 0, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED }, - { EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED }, - { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS, 0, 0 }, - { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS, 0 }, - { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_DOWNWARDS }, - { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS }, - { EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS, 0, EDGE_SLOPE_UPWARDS }, - { EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS }, - { EDGE_SLOPE_ELEVATED, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_ELEVATED }, - { EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED, EDGE_SLOPE_ELEVATED }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_UPWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS_ELEVATED }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { 0, 0, 0, 0 }, - { EDGE_SLOPE_UPWARDS, EDGE_SLOPE_UPWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS }, - { 0, 0, 0, 0 }, - { EDGE_SLOPE_UPWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS }, - { EDGE_SLOPE_DOWNWARDS_ELEVATED, EDGE_SLOPE_DOWNWARDS, EDGE_SLOPE_UPWARDS, EDGE_SLOPE_UPWARDS_ELEVATED }, - { 0, 0, 0, 0 }, -}; - -/** - * - * rct2: 0x006E519A - */ -void game_command_place_fence(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp){ - rct_xyz16 position = { - .x = *eax & 0xFFFF, - .y = *ecx & 0xFFFF, - .z = *edi & 0xFFFF - }; - - uint8 flags = *ebx & 0xFF; - uint8 fence_type = (*ebx >> 8) & 0xFF; - uint8 primary_colour = (*edx >> 8) & 0xFF; - uint8 secondary_colour = *ebp & 0xFF; - uint8 tertiary_colour = (*ebp >> 8) & 0xFF; - uint8 edge = *edx & 0xFF; - - gCommandExpenditureType = RCT_EXPENDITURE_TYPE_LANDSCAPING; - gCommandPosition.x = position.x + 16; - gCommandPosition.y = position.y + 16; - gCommandPosition.z = position.z; - - if (position.z == 0){ - gCommandPosition.z = map_element_height(position.x, position.y) & 0xFFFF; - } - - if (game_is_paused() && !gCheatsBuildInPauseMode){ - gGameCommandErrorText = STR_CONSTRUCTION_NOT_POSSIBLE_WHILE_GAME_IS_PAUSED; - *ebx = MONEY32_UNDEFINED; - return; - } - - if (!(gScreenFlags & SCREEN_FLAGS_SCENARIO_EDITOR) && - !(flags & GAME_COMMAND_FLAG_7) && !gCheatsSandboxMode){ - - if (position.z == 0){ - if (!map_is_location_in_park(position.x, position.y)){ - *ebx = MONEY32_UNDEFINED; - return; - } - } - else if (!map_is_location_owned(position.x, position.y, position.z)){ - *ebx = MONEY32_UNDEFINED; - return; - } - } - - uint8 bp = 0; - if (position.z == 0){ - rct_map_element* map_element = map_get_surface_element_at(position.x / 32, position.y / 32); - if (map_element == NULL){ - *ebx = MONEY32_UNDEFINED; - return; - } - position.z = map_element->base_height * 8; - - uint8 slope = map_element->properties.surface.slope & MAP_ELEMENT_SLOPE_MASK; - bp = EdgeSlopes[slope][edge & 3]; - if (bp & EDGE_SLOPE_ELEVATED) { - position.z += 16; - bp &= ~(1 << 0); - } - } - - rct_map_element* map_element = map_get_surface_element_at(position.x / 32, position.y / 32); - if (map_element == NULL){ - *ebx = MONEY32_UNDEFINED; - return; - } - - if (map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK){ - uint16 water_height = map_element->properties.surface.terrain & MAP_ELEMENT_WATER_HEIGHT_MASK; - water_height *= 16; - - if (position.z < water_height){ - gGameCommandErrorText = STR_CANT_BUILD_THIS_UNDERWATER; - *ebx = MONEY32_UNDEFINED; - return; - } - } - - if (position.z / 8 < map_element->base_height){ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; - *ebx = MONEY32_UNDEFINED; - return; - } - - if (!(bp & 0xC0)){ - uint8 new_edge = (edge + 2) & 3; - uint8 new_base_height = map_element->base_height; - new_base_height += 2; - if (map_element->properties.surface.slope & (1 << new_edge)){ - if (position.z / 8 < new_base_height){ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; - *ebx = MONEY32_UNDEFINED; - return; - } - - if (map_element->properties.surface.slope & (1 << 4)){ - new_edge = (new_edge - 1) & 3; - - if (map_element->properties.surface.slope & (1 << new_edge)){ - new_edge = (new_edge + 2) & 3; - if (map_element->properties.surface.slope & (1 << new_edge)){ - new_base_height += 2; - if (position.z / 8 < new_base_height){ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; - *ebx = MONEY32_UNDEFINED; - return; - } - new_base_height -= 2; - } - } - } - } - - new_edge = (edge + 3) & 3; - if (map_element->properties.surface.slope & (1 << new_edge)){ - if (position.z / 8 < new_base_height){ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; - *ebx = MONEY32_UNDEFINED; - return; - } - - if (map_element->properties.surface.slope & (1 << 4)){ - new_edge = (new_edge - 1) & 3; - - if (map_element->properties.surface.slope & (1 << new_edge)){ - new_edge = (new_edge + 2) & 3; - if (map_element->properties.surface.slope & (1 << new_edge)){ - new_base_height += 2; - if (position.z / 8 < new_base_height){ - gGameCommandErrorText = STR_CAN_ONLY_BUILD_THIS_ABOVE_GROUND; - *ebx = MONEY32_UNDEFINED; - return; - } - } - } - } - } - } - sint32 banner_index = 0xFF; - rct_scenery_entry* fence = get_wall_entry(fence_type); - // Have to check both -1 and NULL, as one can be a invalid object, - // while the other can be invalid index - if ((uintptr_t)fence == (uintptr_t)-1 || fence == NULL) { - *ebx = MONEY32_UNDEFINED; - return; - } - if (fence->wall.scrolling_mode != 0xFF){ - banner_index = create_new_banner(flags); - - if (banner_index == 0xFF){ - *ebx = MONEY32_UNDEFINED; - return; - } - - rct_banner* banner = &gBanners[banner_index]; - if (flags & GAME_COMMAND_FLAG_APPLY){ - banner->flags |= (1 << 3); - banner->type = 0; - banner->x = position.x / 32; - banner->y = position.y / 32; - - sint32 rideIndex = banner_get_closest_ride_index(position.x, position.y, position.z); - if (rideIndex != -1) { - banner->colour = rideIndex & 0xFF; - banner->flags |= BANNER_FLAG_LINKED_TO_RIDE; - } - } - } - - uint8 clearanceHeight = position.z / 8; - if (bp & (EDGE_SLOPE_UPWARDS | EDGE_SLOPE_DOWNWARDS)) { - if (fence->wall.flags & WALL_SCENERY_CANT_BUILD_ON_SLOPE){ - gGameCommandErrorText = STR_ERR_UNABLE_TO_BUILD_THIS_ON_SLOPE; - *ebx = MONEY32_UNDEFINED; - return; - } - clearanceHeight += 2; - } - clearanceHeight += fence->wall.height; - - if (!(flags & GAME_COMMAND_FLAG_7) && !gCheatsDisableClearanceChecks){ - if (!map_place_fence_check_obstruction(fence, position.x, position.y, position.z / 8, clearanceHeight, edge)) { - *ebx = MONEY32_UNDEFINED; - return; - } - } - - if (!map_check_free_elements_and_reorganise(1)){ - *ebx = MONEY32_UNDEFINED; - return; - } - - if (flags & GAME_COMMAND_FLAG_APPLY){ - if (gGameCommandNestLevel == 1 && !(*ebx & GAME_COMMAND_FLAG_GHOST)) { - rct_xyz16 coord; - coord.x = position.x + 16; - coord.y = position.y + 16; - coord.z = map_element_height(coord.x, coord.y); - network_set_player_last_action_coord(network_get_player_index(game_command_playerid), coord); - } - - map_element = map_element_insert(position.x / 32, position.y / 32, position.z / 8, 0); - assert(map_element != NULL); - - map_animation_create(MAP_ANIMATION_TYPE_WALL, position.x, position.y, position.z / 8); - - map_element->clearance_height = clearanceHeight; - - map_element->type = bp | edge | MAP_ELEMENT_TYPE_FENCE; - - map_element->properties.fence.colour_1 = primary_colour; - map_element->properties.fence.colour_1 |= (secondary_colour & 7) << 5; - map_element->flags |= (secondary_colour & 0x18) << 2; - - if (gWallAcrossTrack) { - map_element->properties.fence.animation |= (1 << 2); - } - - map_element->properties.fence.type = fence_type; - if (banner_index != 0xFF){ - map_element->properties.fence.banner_index = banner_index; - } - - if (fence->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR){ - map_element->properties.fence.colour_3 = tertiary_colour; - } - - if (flags & (1 << 6)){ - map_element->flags |= MAP_ELEMENT_FLAG_GHOST; - } - - gSceneryMapElement = map_element; - map_invalidate_tile_zoom1(position.x, position.y, map_element->base_height * 8, map_element->base_height * 8 + 72); - } - - if (gParkFlags & PARK_FLAGS_NO_MONEY){ - *ebx = 0; - } - else{ - *ebx = fence->wall.price; - } -} - -money32 map_place_fence( - sint32 type, sint32 x, sint32 y, sint32 z, sint32 edge, sint32 primaryColour, sint32 secondaryColour, sint32 tertiaryColour, sint32 flags -) { - sint32 eax, ebx, ecx, edx, esi, edi, ebp; - - eax = x; - ebx = flags | (type << 8); - ecx = y; - edx = edge | (primaryColour << 8); - edi = z; - ebp = secondaryColour | (tertiaryColour << 8); - game_command_place_fence(&eax, &ebx, &ecx, &edx, &esi, &edi, &ebp); - return ebx; -} - /** * * rct2: 0x006B893C @@ -4277,7 +3676,7 @@ bool map_element_check_address(const rct_map_element * const element) * * rct2: 0x0068BB18 */ -static void map_obstruction_set_error_text(rct_map_element *mapElement) +void map_obstruction_set_error_text(rct_map_element *mapElement) { rct_string_id errorStringId; rct_ride *ride; @@ -4447,32 +3846,6 @@ sint32 map_can_construct_at(sint32 x, sint32 y, sint32 zLow, sint32 zHigh, uint8 return map_can_construct_with_clear_at(x, y, zLow, zHigh, NULL, bl, 0, NULL); } -/** - * - * rct2: 0x006E5935 - */ -void map_remove_intersecting_walls(sint32 x, sint32 y, sint32 z0, sint32 z1, sint32 direction) -{ - rct_map_element *mapElement; - - mapElement = map_get_first_element_at(x >> 5, y >> 5); - do { - if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) - continue; - - if (mapElement->clearance_height <= z0 || mapElement->base_height >= z1) - continue; - - if (direction != (mapElement->type & 3)) - continue; - - map_element_remove_banner_entry(mapElement); - map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->base_height * 8 + 72); - map_element_remove(mapElement); - mapElement--; - } while (!map_element_is_last_for_tile(mapElement++)); -} - /** * Updates grass length, scenery age and jumping fountains. * @@ -4900,22 +4273,6 @@ rct_map_element *map_get_large_scenery_segment(sint32 x, sint32 y, sint32 z, sin return NULL; } -rct_map_element *map_get_fence_element_at(sint32 x, sint32 y, sint32 z, sint32 direction) -{ - rct_map_element *mapElement = map_get_first_element_at(x >> 5, y >> 5); - do { - if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) - continue; - if (mapElement->base_height != z) - continue; - if (map_element_get_direction(mapElement) != direction) - continue; - - return mapElement; - } while (!map_element_is_last_for_tile(mapElement++)); - return NULL; -} - rct_map_element *map_get_park_entrance_element_at(sint32 x, sint32 y, sint32 z, bool ghost) { rct_map_element* mapElement = map_get_first_element_at(x >> 5, y >> 5); @@ -5026,42 +4383,6 @@ bool sign_set_colour(sint32 x, sint32 y, sint32 z, sint32 direction, sint32 sequ return true; } -/** - * - * rct2: 0x006E588E - */ -void map_remove_walls_at(sint32 x, sint32 y, sint32 z0, sint32 z1) -{ - rct_map_element *mapElement; - - z0 /= 8; - z1 /= 8; -repeat: - mapElement = map_get_first_element_at(x >> 5, y >> 5); - do { - if (map_element_get_type(mapElement) != MAP_ELEMENT_TYPE_FENCE) - continue; - if (z0 >= mapElement->clearance_height) - continue; - if (z1 <= mapElement->base_height) - continue; - - map_element_remove_banner_entry(mapElement); - map_invalidate_tile_zoom1(x, y, mapElement->base_height * 8, mapElement->base_height * 8 + 72); - map_element_remove(mapElement); - goto repeat; - } while (!map_element_is_last_for_tile(mapElement++)); -} - -/** - * - * rct2: 0x006E57E6 - */ -void map_remove_walls_at_z(sint32 x, sint32 y, sint32 z) -{ - map_remove_walls_at(x, y, z, z + 48); -} - static void translate_3d_to_2d(sint32 rotation, sint32 *x, sint32 *y) { sint32 rx, ry; diff --git a/src/openrct2/world/map.h b/src/openrct2/world/map.h index 71399fc4c0..158125b6b8 100644 --- a/src/openrct2/world/map.h +++ b/src/openrct2/world/map.h @@ -538,6 +538,8 @@ rct_map_element *map_get_track_element_at_of_type_from_ride(sint32 x, sint32 y, rct_map_element *map_get_track_element_at_from_ride(sint32 x, sint32 y, sint32 z, sint32 rideIndex); rct_map_element *map_get_track_element_at_with_direction_from_ride(sint32 x, sint32 y, sint32 z, sint32 direction, sint32 rideIndex); +bool map_is_location_at_edge(sint32 x, sint32 y); +void map_obstruction_set_error_text(rct_map_element *mapElement); uint8 fence_get_animation_frame(rct_map_element *fenceElement); #endif