diff --git a/src/openrct2/game.c b/src/openrct2/game.c index 7cde6ce85d..6aafeca295 100644 --- a/src/openrct2/game.c +++ b/src/openrct2/game.c @@ -1245,4 +1245,6 @@ GAME_COMMAND_POINTER* new_game_command_table[GAME_COMMAND_COUNT] = { game_command_pickup_guest, game_command_pickup_staff, game_command_balloon_press, + game_command_modify_tile, + game_command_modify_element, }; diff --git a/src/openrct2/game.h b/src/openrct2/game.h index 6cdf14cfed..e75d9d7463 100644 --- a/src/openrct2/game.h +++ b/src/openrct2/game.h @@ -93,6 +93,8 @@ enum GAME_COMMAND { GAME_COMMAND_PICKUP_GUEST, GAME_COMMAND_PICKUP_STAFF, GAME_COMMAND_BALLOON_PRESS, + GAME_COMMAND_MODIFY_TILE, + GAME_COMMAND_MODIFY_ELEMENT, GAME_COMMAND_COUNT }; diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj index a97a484aa0..601b403f64 100644 --- a/src/openrct2/libopenrct2.vcxproj +++ b/src/openrct2/libopenrct2.vcxproj @@ -411,6 +411,7 @@ + @@ -584,6 +585,7 @@ + @@ -597,6 +599,7 @@ + diff --git a/src/openrct2/windows/tile_inspector.c b/src/openrct2/windows/tile_inspector.c index f8e54ac580..5bf96cc138 100644 --- a/src/openrct2/windows/tile_inspector.c +++ b/src/openrct2/windows/tile_inspector.c @@ -16,6 +16,8 @@ #include "dropdown.h" #include "error.h" +#include "tile_inspector.h" +#include "../game.h" #include "../input.h" #include "../interface/themes.h" #include "../interface/viewport.h" @@ -28,6 +30,7 @@ #include "../world/footpath.h" #include "../world/map.h" #include "../world/scenery.h" +#include "../world/tile_inspector.h" static const rct_string_id terrainTypeStringIds[] = { STR_TILE_INSPECTOR_TERRAIN_GRASS, @@ -74,19 +77,6 @@ static const rct_string_id fenceSlopeStringIds[] = { STR_TILE_INSPECTOR_FENCE_SLOPED_RIGHT }; -enum WINDOW_TILE_INSPECTOR_PAGES { - PAGE_DEFAULT, - PAGE_SURFACE, - PAGE_PATH, - PAGE_TRACK, - PAGE_SCENERY, - PAGE_ENTRANCE, - PAGE_FENCE, - PAGE_LARGE_SCENERY, - PAGE_BANNER, - PAGE_CORRUPT -}; - enum WINDOW_TILE_INSPECTOR_WIDGET_IDX { WIDX_BACKGROUND, WIDX_TITLE, @@ -460,7 +450,7 @@ static sint32 windowTileInspectorToolMouseX = 0; static sint32 windowTileInspectorToolMouseY = 0; static sint32 windowTileInspectorToolMapX = 0; static sint32 windowTileInspectorToolMapY = 0; -static sint32 windowTileInspectorElementCount = 0; +sint32 windowTileInspectorElementCount = 0; static bool windowTileInspectorApplyToAll = false; static bool windowTileInspectorElementCopied = false; static rct_map_element tileInspectorCopiedElement; @@ -494,8 +484,6 @@ static void window_tile_inspector_scrollmouseover(rct_window *w, sint32 scrollIn static void window_tile_inspector_invalidate(rct_window *w); static void window_tile_inspector_paint(rct_window *w, rct_drawpixelinfo *dpi); static void window_tile_inspector_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, sint32 scrollIndex); -static void window_tile_inspector_set_page(rct_window *w, const sint32 page); -static void window_tile_inspector_auto_set_buttons(rct_window *w); static rct_window_event_list windowTileInspectorEvents = { NULL, @@ -621,23 +609,15 @@ static void window_tile_inspector_load_tile(rct_window* w) static void window_tile_inspector_insert_corrupt_element(rct_window *w) { - // Create new corrupt element - rct_map_element *curruptElement = map_element_insert(windowTileInspectorTileX, windowTileInspectorTileY, -1, 0); // Ugly hack: -1 guarantees this to be placed first - windowTileInspectorElementCount++; - assert(curruptElement != NULL); - curruptElement->type = MAP_ELEMENT_TYPE_CORRUPT; - - // Set the base height to be the same as the selected element - rct_map_element *const selectedElement = window_tile_inspector_get_selected_element(w); - curruptElement->base_height = curruptElement->clearance_height = selectedElement->base_height; - - // Move the corrupt element up until the selected list item is reached - // this way it's placed under the selected element, even when there are multiple elements with the same base height - for (sint32 i = 0; i < w->selected_list_item; i++) { - window_tile_inspector_swap_elements(i, i + 1); - } - - map_invalidate_tile_full(windowTileInspectorTileX << 5, windowTileInspectorTileY << 5); + game_do_command( + TILE_INSPECTOR_ELEMENT_CORRUPT, + GAME_COMMAND_FLAG_APPLY, + windowTileInspectorTileX | (windowTileInspectorTileY << 8), + w->selected_list_item, + GAME_COMMAND_MODIFY_TILE, + 0, + 0 + ); } static void window_tile_inspector_remove_element(sint32 index) @@ -1049,9 +1029,6 @@ static void window_tile_inspector_mouseup(rct_window *w, sint32 widgetIndex) break; case WIDX_BUTTON_CORRUPT: window_tile_inspector_insert_corrupt_element(w); - window_tile_inspector_set_page(w, PAGE_CORRUPT); - window_tile_inspector_auto_set_buttons(w); - window_invalidate(w); break; case WIDX_BUTTON_REMOVE: window_tile_inspector_remove_element(w->selected_list_item); @@ -1518,7 +1495,7 @@ static void window_tile_inspector_scrollgetsize(rct_window *w, sint32 scrollInde *height = windowTileInspectorElementCount * LIST_ITEM_HEIGHT; } -static void window_tile_inspector_set_page(rct_window *w, const sint32 page) +void window_tile_inspector_set_page(rct_window *w, const tile_inspector_page page) { w->page = page; w->widgets = tileInspectorWidgets[page]; @@ -1526,7 +1503,7 @@ static void window_tile_inspector_set_page(rct_window *w, const sint32 page) w->disabled_widgets = windowTileInspectorDisabledWidgets[page]; } -static void window_tile_inspector_auto_set_buttons(rct_window *w) +void window_tile_inspector_auto_set_buttons(rct_window *w) { // X and Y spinners widget_set_enabled(w, WIDX_SPINNER_X_INCREASE, (windowTileInspectorTileSelected && (windowTileInspectorTileX < 255))); diff --git a/src/openrct2/windows/tile_inspector.h b/src/openrct2/windows/tile_inspector.h new file mode 100644 index 0000000000..76c59d9dce --- /dev/null +++ b/src/openrct2/windows/tile_inspector.h @@ -0,0 +1,39 @@ +#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 + +#pragma once + +#include "../common.h" +#include "../interface/window.h" + +typedef enum tile_inspector_page +{ + PAGE_DEFAULT, + PAGE_SURFACE, + PAGE_PATH, + PAGE_TRACK, + PAGE_SCENERY, + PAGE_ENTRANCE, + PAGE_FENCE, + PAGE_LARGE_SCENERY, + PAGE_BANNER, + PAGE_CORRUPT +} tile_inspector_page; + +extern sint32 windowTileInspectorElementCount; + +void window_tile_inspector_set_page(rct_window *w, const tile_inspector_page page); +void window_tile_inspector_auto_set_buttons(rct_window *w); diff --git a/src/openrct2/windows/top_toolbar.c b/src/openrct2/windows/top_toolbar.c index 1d46c7656d..4fa79fb7f7 100644 --- a/src/openrct2/windows/top_toolbar.c +++ b/src/openrct2/windows/top_toolbar.c @@ -719,7 +719,6 @@ static void window_top_toolbar_invalidate(rct_window *w) // Fall-through case NETWORK_MODE_SERVER: window_top_toolbar_widgets[WIDX_FASTFORWARD].type = WWT_EMPTY; - window_top_toolbar_widgets[WIDX_DEBUG].type = WWT_EMPTY; break; } } diff --git a/src/openrct2/world/map.c b/src/openrct2/world/map.c index 9bd8c85b40..7178672d07 100644 --- a/src/openrct2/world/map.c +++ b/src/openrct2/world/map.c @@ -39,6 +39,7 @@ #include "map_animation.h" #include "park.h" #include "scenery.h" +#include "tile_inspector.h" /** * Replaces 0x00993CCC, 0x00993CCE @@ -5604,6 +5605,43 @@ void game_command_set_sign_style(sint32* eax, sint32* ebx, sint32* ecx, sint32* *ebx = 0; } +void game_command_modify_tile(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) +{ + sint32 flags = *ebx; + const tile_inspector_element_type action_type = *eax; + switch (action_type) + { + case TILE_INSPECTOR_ELEMENT_ANY: + case TILE_INSPECTOR_ELEMENT_SURFACE: + case TILE_INSPECTOR_ELEMENT_PATH: + case TILE_INSPECTOR_ELEMENT_TRACK: + case TILE_INSPECTOR_ELEMENT_SCENERY: + case TILE_INSPECTOR_ELEMENT_ENTRANCE: + case TILE_INSPECTOR_ELEMENT_FENCE: + case TILE_INSPECTOR_ELEMENT_SCENERYMULTIPLE: + case TILE_INSPECTOR_ELEMENT_BANNER: + return; + case TILE_INSPECTOR_ELEMENT_CORRUPT: + { + const sint32 x = *ecx & 0xFF; + const sint32 y = (*ecx >> 8) & 0xFF; + const sint16 index = *edx; + *ebx = tile_inspector_insert_corrupt_at(x, y, index, flags); + return; + } + } +} + +void game_command_modify_element(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp) +{ + log_info("Modifying element"); + if (*ebx & GAME_COMMAND_FLAG_APPLY) { + puts("Yeah baby"); + } + + *ebx = 0; +} + /** * Gets the track element at x, y, z. * @param x x units, not tiles. diff --git a/src/openrct2/world/map.h b/src/openrct2/world/map.h index b2fb6df969..ea352d95ef 100644 --- a/src/openrct2/world/map.h +++ b/src/openrct2/world/map.h @@ -473,6 +473,8 @@ void game_command_set_banner_name(sint32* eax, sint32* ebx, sint32* ecx, sint32* void game_command_set_sign_name(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp); void game_command_set_banner_style(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp); void game_command_set_sign_style(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp); +void game_command_modify_tile(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp); +void game_command_modify_element(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp); typedef struct map_element_iterator { sint32 x; diff --git a/src/openrct2/world/tile_inspector.c b/src/openrct2/world/tile_inspector.c new file mode 100644 index 0000000000..67858443d0 --- /dev/null +++ b/src/openrct2/world/tile_inspector.c @@ -0,0 +1,115 @@ +#pragma region Copyright (c) 2014-2017 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 "../game.h" +#include "../interface/window.h" +#include "../windows/tile_inspector.h" +#include "map.h" +#include "tile_inspector.h" + +static void map_swap_elements_at(sint32 x, sint32 y, sint16 first, sint16 second) +{ + rct_map_element *mapElement = map_get_first_element_at(x, y); + rct_map_element *const firstElement = mapElement + first; + rct_map_element *const secondElement = mapElement + second; + + // swap_elements shouldn't be called when there is only one element on the tile + assert(!map_element_is_last_for_tile(mapElement)); + + // Make sure both elements are actually on the current tile + sint16 elementCount = 0; + do + { + elementCount++; + } while (!map_element_is_last_for_tile(mapElement++)); + assert(elementCount > max(first, second)); + + // Swap their memory + rct_map_element temp = *firstElement; + *firstElement = *secondElement; + *secondElement = temp; + + // Swap the 'last map element for tile' flag if either one of them was last + if (map_element_is_last_for_tile(firstElement) || map_element_is_last_for_tile(secondElement)) + { + firstElement->flags ^= MAP_ELEMENT_FLAG_LAST_TILE; + secondElement->flags ^= MAP_ELEMENT_FLAG_LAST_TILE; + } +} + +/** + * Inserts a corrupt element under a given element on a given tile + * @param x, y: The coordinates of the tile + * @param element_index: The nth element on this tile + * Returns 0 on success, MONEY_UNDEFINED otherwise. + */ +sint32 tile_inspector_insert_corrupt_at(sint32 x, sint32 y, sint16 element_index, sint32 flags) +{ + // Make sure there is enough space for the new element + if (!map_check_free_elements_and_reorganise(1)) + { + return MONEY32_UNDEFINED; + } + + if (flags & GAME_COMMAND_FLAG_APPLY) + { + // Create new corrupt element + rct_map_element *curruptElement = map_element_insert(x, y, -1, 0); // Ugly hack: -1 guarantees this to be placed first + if (curruptElement == NULL) + { + log_warning("Failed to insert corrupt element."); + return MONEY32_UNDEFINED; + } + curruptElement->type = MAP_ELEMENT_TYPE_CORRUPT; + + // Set the base height to be the same as the selected element + rct_map_element *const selectedElement = map_get_first_element_at(x, y) + element_index; + curruptElement->base_height = curruptElement->clearance_height = selectedElement->base_height; + + // Move the corrupt element up until the selected list item is reached + // this way it's placed under the selected element, even when there are multiple elements with the same base height + for (sint16 i = 0; i < element_index; i++) + { + map_swap_elements_at(x, y, i, i + 1); + } + + map_invalidate_tile_full(x << 5, y << 5); + + // Update the tile inspector's list for everyone who has the tile selected + rct_window *tile_inspector_window = window_find_by_class(WC_TILE_INSPECTOR); + if (tile_inspector_window != NULL) + { + windowTileInspectorElementCount++; + + // Keep other elements (that are not being hidden) selected + if (tile_inspector_window->selected_list_item > element_index) + { + tile_inspector_window->selected_list_item++; + } + + if (tile_inspector_window->selected_list_item == element_index) + { + window_tile_inspector_set_page(tile_inspector_window, PAGE_CORRUPT); + } + + window_tile_inspector_auto_set_buttons(tile_inspector_window); + window_invalidate(tile_inspector_window); + } + } + + // Nothing went wrong + return 0; +} diff --git a/src/openrct2/world/tile_inspector.h b/src/openrct2/world/tile_inspector.h new file mode 100644 index 0000000000..691ae7aba7 --- /dev/null +++ b/src/openrct2/world/tile_inspector.h @@ -0,0 +1,34 @@ +#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 + +#pragma once + +#include "../common.h" + +typedef enum { + TILE_INSPECTOR_ELEMENT_ANY = 0, + TILE_INSPECTOR_ELEMENT_SURFACE, + TILE_INSPECTOR_ELEMENT_PATH, + TILE_INSPECTOR_ELEMENT_TRACK, + TILE_INSPECTOR_ELEMENT_SCENERY, + TILE_INSPECTOR_ELEMENT_ENTRANCE, + TILE_INSPECTOR_ELEMENT_FENCE, + TILE_INSPECTOR_ELEMENT_SCENERYMULTIPLE, + TILE_INSPECTOR_ELEMENT_BANNER, + TILE_INSPECTOR_ELEMENT_CORRUPT, +} tile_inspector_element_type; + +sint32 tile_inspector_insert_corrupt_at(sint32 x, sint32 y, sint16 element_index, sint32 flags);