From 88a0bb4270f979ed06554ba9e67642f7f801de1d Mon Sep 17 00:00:00 2001 From: Broxzier Date: Sun, 15 Jan 2017 13:53:19 +0100 Subject: [PATCH] Add support for inserting corrupt elements in MP This PR adds three new files, one to expose some of the funcitons for the tile inspector window, and two completely new ones for the tile inspector logic, which handles what happens. This commit adds the logic for inserting corrupt elements, while keeping the list on both server and client correct (e.g. client has the same tile selected, and keeps the same element in focus when the tiles gets changed) --- src/openrct2/game.c | 2 + src/openrct2/game.h | 2 + src/openrct2/libopenrct2.vcxproj | 3 + src/openrct2/windows/tile_inspector.c | 53 ++++-------- src/openrct2/windows/tile_inspector.h | 39 +++++++++ src/openrct2/windows/top_toolbar.c | 1 - src/openrct2/world/map.c | 38 +++++++++ src/openrct2/world/map.h | 2 + src/openrct2/world/tile_inspector.c | 115 ++++++++++++++++++++++++++ src/openrct2/world/tile_inspector.h | 34 ++++++++ 10 files changed, 250 insertions(+), 39 deletions(-) create mode 100644 src/openrct2/windows/tile_inspector.h create mode 100644 src/openrct2/world/tile_inspector.c create mode 100644 src/openrct2/world/tile_inspector.h 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);