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);