diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index aa362d26e9..f28b1f9d0d 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -31,6 +31,7 @@ constexpr int32_t WINDOW_SCENERY_HEIGHT = 180; constexpr int32_t SCENERY_BUTTON_WIDTH = 66; constexpr int32_t SCENERY_BUTTON_HEIGHT = 80; constexpr int32_t SCENERY_WINDOW_TABS = MAX_SCENERY_GROUP_OBJECTS + 1; // The + 1 is for the 'Miscellaneous' tab +constexpr uint16_t SCENERY_ENTRIES_PER_TAB = 1024; // clang-format off enum { @@ -56,7 +57,7 @@ enum { WINDOW_SCENERY_TAB_20 }; -uint16_t gWindowSceneryTabSelections[SCENERY_WINDOW_TABS]; +ScenerySelection gWindowSceneryTabSelections[SCENERY_WINDOW_TABS]; uint8_t gWindowSceneryActiveTabIndex; uint8_t gWindowSceneryPaintEnabled; uint8_t gWindowSceneryRotation; @@ -191,25 +192,25 @@ static rct_widget window_scenery_widgets[] = { void window_scenery_update_scroll(rct_window* w); // rct2: 0x00F64F2C -static uint16_t window_scenery_tab_entries[SCENERY_WINDOW_TABS][SCENERY_ENTRIES_BY_TAB + 1]; +static ScenerySelection window_scenery_tab_entries[SCENERY_WINDOW_TABS][SCENERY_ENTRIES_PER_TAB + 1]; /** * Was part of 0x006DFA00 * The same code repeated five times for every scenery entry type */ -static void init_scenery_entry(rct_scenery_entry* sceneryEntry, int32_t index, uint8_t sceneryTabId) +static void init_scenery_entry(rct_scenery_entry* sceneryEntry, const ScenerySelection& selection, uint8_t sceneryTabId) { - Guard::ArgumentInRange(index, 0, WINDOW_SCENERY_TAB_SELECTION_UNDEFINED); - if (scenery_is_invented(index) || gCheatsIgnoreResearchStatus) + Guard::ArgumentInRange(selection.EntryIndex, 0, WINDOW_SCENERY_TAB_SELECTION_UNDEFINED); + if (scenery_is_invented(selection) || gCheatsIgnoreResearchStatus) { if (sceneryTabId != 0xFF) { - for (int32_t i = 0; i < SCENERY_ENTRIES_BY_TAB; i++) + for (int32_t i = 0; i < SCENERY_ENTRIES_PER_TAB; i++) { - if (window_scenery_tab_entries[sceneryTabId][i] == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + if (window_scenery_tab_entries[sceneryTabId][i].IsUndefined()) { - window_scenery_tab_entries[sceneryTabId][i] = index; - window_scenery_tab_entries[sceneryTabId][i + 1] = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + window_scenery_tab_entries[sceneryTabId][i] = selection; + window_scenery_tab_entries[sceneryTabId][i + 1].SetUndefined(); return; } } @@ -219,9 +220,9 @@ static void init_scenery_entry(rct_scenery_entry* sceneryEntry, int32_t index, u { int32_t counter = 0; - while (window_scenery_tab_entries[i][counter] != WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + while (!window_scenery_tab_entries[i][counter].IsUndefined()) { - if (window_scenery_tab_entries[i][counter] == index) + if (window_scenery_tab_entries[i][counter] == selection) { return; } @@ -230,12 +231,12 @@ static void init_scenery_entry(rct_scenery_entry* sceneryEntry, int32_t index, u } } - for (int32_t i = 0; i < SCENERY_ENTRIES_BY_TAB; i++) + for (int32_t i = 0; i < SCENERY_ENTRIES_PER_TAB; i++) { - if (window_scenery_tab_entries[SCENERY_WINDOW_TABS - 1][i] == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + if (window_scenery_tab_entries[SCENERY_WINDOW_TABS - 1][i].IsUndefined()) { - window_scenery_tab_entries[SCENERY_WINDOW_TABS - 1][i] = index; - window_scenery_tab_entries[SCENERY_WINDOW_TABS - 1][i + 1] = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + window_scenery_tab_entries[SCENERY_WINDOW_TABS - 1][i] = selection; + window_scenery_tab_entries[SCENERY_WINDOW_TABS - 1][i + 1].SetUndefined(); break; } } @@ -252,7 +253,7 @@ void window_scenery_init() for (int32_t scenerySetIndex = 0; scenerySetIndex < SCENERY_WINDOW_TABS; scenerySetIndex++) { - window_scenery_tab_entries[scenerySetIndex][0] = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + window_scenery_tab_entries[scenerySetIndex][0].SetUndefined(); if (scenerySetIndex == MAX_SCENERY_GROUP_OBJECTS) continue; @@ -263,11 +264,11 @@ void window_scenery_init() int32_t sceneryTabEntryCount = 0; for (int32_t i = 0; i < sceneryGroupEntry->entry_count; i++) { - uint16_t sceneryEntryId = sceneryGroupEntry->scenery_entries[i]; - if (scenery_is_invented(sceneryEntryId) || gCheatsIgnoreResearchStatus) + auto sceneryEntry = sceneryGroupEntry->scenery_entries[i]; + if (scenery_is_invented(sceneryEntry) || gCheatsIgnoreResearchStatus) { - window_scenery_tab_entries[scenerySetIndex][sceneryTabEntryCount] = sceneryEntryId; - window_scenery_tab_entries[scenerySetIndex][++sceneryTabEntryCount] = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + window_scenery_tab_entries[scenerySetIndex][sceneryTabEntryCount] = sceneryEntry; + window_scenery_tab_entries[scenerySetIndex][++sceneryTabEntryCount].SetUndefined(); } else { @@ -277,61 +278,53 @@ void window_scenery_init() } // small scenery - for (uint16_t sceneryId = SCENERY_SMALL_SCENERY_ID_MIN; sceneryId <= SCENERY_SMALL_SCENERY_ID_MAX; sceneryId++) + for (uint16_t sceneryId = 0; sceneryId < MAX_SMALL_SCENERY_OBJECTS; sceneryId++) { rct_scenery_entry* sceneryEntry = get_small_scenery_entry(sceneryId); if (sceneryEntry == nullptr) continue; - init_scenery_entry(sceneryEntry, sceneryId, sceneryEntry->small_scenery.scenery_tab_id); + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_SMALL, sceneryId }, sceneryEntry->small_scenery.scenery_tab_id); } // large scenery - for (int32_t sceneryId = SCENERY_LARGE_SCENERY_ID_MIN; sceneryId <= SCENERY_LARGE_SCENERY_ID_MAX; sceneryId++) + for (uint16_t sceneryId = 0; sceneryId < MAX_LARGE_SCENERY_OBJECTS; sceneryId++) { - int32_t largeSceneryIndex = sceneryId - SCENERY_LARGE_SCENERY_ID_MIN; - - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(largeSceneryIndex); + rct_scenery_entry* sceneryEntry = get_large_scenery_entry(sceneryId); if (sceneryEntry == nullptr) continue; - init_scenery_entry(sceneryEntry, sceneryId, sceneryEntry->large_scenery.scenery_tab_id); + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_LARGE, sceneryId }, sceneryEntry->large_scenery.scenery_tab_id); } // walls - for (int32_t sceneryId = SCENERY_WALLS_ID_MIN; sceneryId <= SCENERY_WALLS_ID_MAX; sceneryId++) + for (uint16_t sceneryId = 0; sceneryId < MAX_WALL_SCENERY_OBJECTS; sceneryId++) { - int32_t wallSceneryIndex = sceneryId - SCENERY_WALLS_ID_MIN; - - rct_scenery_entry* sceneryEntry = get_wall_entry(wallSceneryIndex); + rct_scenery_entry* sceneryEntry = get_wall_entry(sceneryId); if (sceneryEntry == nullptr) continue; - init_scenery_entry(sceneryEntry, sceneryId, sceneryEntry->wall.scenery_tab_id); + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_WALL, sceneryId }, sceneryEntry->wall.scenery_tab_id); } // banners - for (int32_t sceneryId = SCENERY_BANNERS_ID_MIN; sceneryId <= SCENERY_BANNERS_ID_MAX; sceneryId++) + for (uint16_t sceneryId = 0; sceneryId < MAX_BANNER_OBJECTS; sceneryId++) { - int32_t bannerIndex = sceneryId - SCENERY_BANNERS_ID_MIN; - - rct_scenery_entry* sceneryEntry = get_banner_entry(bannerIndex); + rct_scenery_entry* sceneryEntry = get_banner_entry(sceneryId); if (sceneryEntry == nullptr) continue; - init_scenery_entry(sceneryEntry, sceneryId, sceneryEntry->banner.scenery_tab_id); + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_BANNER, sceneryId }, sceneryEntry->banner.scenery_tab_id); } // path bits - for (int32_t sceneryId = SCENERY_PATH_SCENERY_ID_MIN; sceneryId <= SCENERY_PATH_SCENERY_ID_MAX; sceneryId++) + for (uint16_t sceneryId = 0; sceneryId < MAX_PATH_ADDITION_OBJECTS; sceneryId++) { - int32_t pathBitIndex = sceneryId - SCENERY_PATH_SCENERY_ID_MIN; - - rct_scenery_entry* sceneryEntry = get_footpath_item_entry(pathBitIndex); + rct_scenery_entry* sceneryEntry = get_footpath_item_entry(sceneryId); if (sceneryEntry == nullptr) continue; - init_scenery_entry(sceneryEntry, sceneryId, sceneryEntry->path_bit.scenery_tab_id); + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_PATH_ITEM, sceneryId }, sceneryEntry->path_bit.scenery_tab_id); } for (rct_widgetindex widgetIndex = WIDX_SCENERY_TAB_1; widgetIndex < WIDX_SCENERY_LIST; widgetIndex++) @@ -385,7 +378,7 @@ void window_scenery_init() if (left != 3 || tabIndex != SCENERY_WINDOW_TABS - 1) { - if (window_scenery_tab_entries[tabIndex][0] == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + if (window_scenery_tab_entries[tabIndex][0].IsUndefined()) continue; if (enabledScenerySets[tabIndex]) @@ -419,11 +412,11 @@ void window_scenery_set_default_placement_configuration() window_scenery_init(); for (int32_t i = 0; i < SCENERY_WINDOW_TABS; i++) - gWindowSceneryTabSelections[i] = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + gWindowSceneryTabSelections[i] = ScenerySelection::CreateUndefined(); for (int32_t i = 0; i < SCENERY_WINDOW_TABS; i++) { - if (window_scenery_tab_entries[i][0] != WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + if (!window_scenery_tab_entries[i][0].IsUndefined()) { gWindowSceneryActiveTabIndex = i; return; @@ -477,7 +470,7 @@ rct_window* window_scenery_open() gWindowSceneryRotation = 3; gSceneryCtrlPressed = false; gSceneryShiftPressed = false; - window->scenery.selected_scenery_id = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + window->scenery.SelectedScenery = ScenerySelection::CreateUndefined(); window->scenery.hover_counter = 0; window_push_others_below(window); gSceneryGhostType = 0; @@ -522,22 +515,22 @@ struct scenery_item { int32_t allRows; int32_t selected_item; - uint16_t sceneryId; + ScenerySelection scenerySelection; }; static scenery_item window_scenery_count_rows_with_selected_item(int32_t tabIndex) { - scenery_item sceneryItem = { 0, 0, WINDOW_SCENERY_TAB_SELECTION_UNDEFINED }; + scenery_item sceneryItem = { 0, 0, ScenerySelection::CreateUndefined() }; int32_t totalItems = 0; - uint16_t id = 0; - uint16_t sceneryId = gWindowSceneryTabSelections[tabIndex]; + ScenerySelection currentEntry = { 0, 0 }; + ScenerySelection scenerySelection = gWindowSceneryTabSelections[tabIndex]; - while ((id = window_scenery_tab_entries[tabIndex][totalItems]) != WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + while ((currentEntry = window_scenery_tab_entries[tabIndex][totalItems]), !currentEntry.IsUndefined()) { - if (id == sceneryId) + if (currentEntry == scenerySelection) { sceneryItem.selected_item = totalItems; - sceneryItem.sceneryId = sceneryId; + sceneryItem.scenerySelection = scenerySelection; } totalItems++; } @@ -550,7 +543,7 @@ static int32_t window_scenery_count_rows() int32_t tabIndex = gWindowSceneryActiveTabIndex; int32_t totalItems = 0; - while (window_scenery_tab_entries[tabIndex][totalItems] != WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + while (!window_scenery_tab_entries[tabIndex][totalItems].IsUndefined()) { totalItems++; } @@ -632,12 +625,12 @@ void window_scenery_update_scroll(rct_window* w) int32_t maxTop = std::max(0, w->scrolls[0].v_bottom - listHeight); int32_t rowSelected = count_rows(sceneryItem.selected_item); - if (sceneryItem.sceneryId == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + if (sceneryItem.scenerySelection.IsUndefined()) { rowSelected = 0; - uint16_t sceneryId = window_scenery_tab_entries[tabIndex][0]; - if (sceneryId != WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) - gWindowSceneryTabSelections[tabIndex] = sceneryId; + ScenerySelection scenery = window_scenery_tab_entries[tabIndex][0]; + if (!scenery.IsUndefined()) + gWindowSceneryTabSelections[tabIndex] = scenery; } w->scrolls[0].v_top = window_scenery_rows_height(rowSelected); @@ -748,9 +741,9 @@ static void window_scenery_dropdown(rct_window* w, rct_widgetindex widgetIndex, */ static void window_scenery_periodic_update(rct_window* w) { - if (w->scenery.selected_scenery_id != WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + if (!w->scenery.SelectedScenery.IsUndefined()) { - w->scenery.selected_scenery_id = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + w->scenery.SelectedScenery = ScenerySelection::CreateUndefined(); } } @@ -822,38 +815,38 @@ static void window_scenery_update(rct_window* w) gCurrentToolId = TOOL_CROSSHAIR; } else if (gWindowSceneryPaintEnabled == 1) - { // the repaint scenery tool is active + { gCurrentToolId = TOOL_PAINT_DOWN; } else { uint16_t tabIndex = gWindowSceneryActiveTabIndex; - int16_t tabSelectedSceneryId = gWindowSceneryTabSelections[tabIndex]; + ScenerySelection tabSelectedScenery = gWindowSceneryTabSelections[tabIndex]; - if (tabSelectedSceneryId != -1) + if (!tabSelectedScenery.IsUndefined()) { - if (tabSelectedSceneryId >= SCENERY_BANNERS_ID_MIN) - { // banner + if (tabSelectedScenery.SceneryType == SCENERY_TYPE_BANNER) + { gCurrentToolId = TOOL_ENTRANCE_DOWN; } - else if (tabSelectedSceneryId >= SCENERY_LARGE_SCENERY_ID_MIN) - { // large scenery + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_LARGE) + { gCurrentToolId = static_cast( - get_large_scenery_entry(tabSelectedSceneryId - SCENERY_LARGE_SCENERY_ID_MIN)->large_scenery.tool_id); + get_large_scenery_entry(tabSelectedScenery.EntryIndex)->large_scenery.tool_id); } - else if (tabSelectedSceneryId >= SCENERY_WALLS_ID_MIN) - { // wall - gCurrentToolId = static_cast( - get_wall_entry(tabSelectedSceneryId - SCENERY_WALLS_ID_MIN)->wall.tool_id); + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_WALL) + { + gCurrentToolId = static_cast(get_wall_entry(tabSelectedScenery.EntryIndex)->wall.tool_id); } - else if (tabSelectedSceneryId >= SCENERY_PATH_SCENERY_ID_MIN) + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_PATH_ITEM) { // path bit gCurrentToolId = static_cast( - get_footpath_item_entry(tabSelectedSceneryId - SCENERY_PATH_SCENERY_ID_MIN)->path_bit.tool_id); + get_footpath_item_entry(tabSelectedScenery.EntryIndex)->path_bit.tool_id); } else { // small scenery - gCurrentToolId = static_cast(get_small_scenery_entry(tabSelectedSceneryId)->small_scenery.tool_id); + gCurrentToolId = static_cast( + get_small_scenery_entry(tabSelectedScenery.EntryIndex)->small_scenery.tool_id); } } } @@ -869,23 +862,23 @@ void window_scenery_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* w *height = window_scenery_rows_height(rows); } -static uint16_t get_scenery_id_by_cursor_pos(const ScreenCoordsXY& screenCoords) +static ScenerySelection get_scenery_id_by_cursor_pos(const ScreenCoordsXY& screenCoords) { int32_t tabSceneryIndex = screenCoords.x / SCENERY_BUTTON_WIDTH + (screenCoords.y / SCENERY_BUTTON_HEIGHT) * 9; uint8_t tabIndex = gWindowSceneryActiveTabIndex; int32_t itemCounter = 0; - uint16_t sceneryId = 0; + ScenerySelection scenery = ScenerySelection::CreateUndefined(); while (itemCounter <= tabSceneryIndex) { - sceneryId = window_scenery_tab_entries[tabIndex][itemCounter]; - if (sceneryId == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) - return WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + scenery = window_scenery_tab_entries[tabIndex][itemCounter]; + if (scenery.IsUndefined()) + return ScenerySelection::CreateUndefined(); itemCounter++; } - return sceneryId; + return scenery; } /** @@ -894,12 +887,12 @@ static uint16_t get_scenery_id_by_cursor_pos(const ScreenCoordsXY& screenCoords) */ void window_scenery_scrollmousedown(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) { - uint16_t sceneryId = get_scenery_id_by_cursor_pos(screenCoords); - if (sceneryId == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + ScenerySelection scenery = get_scenery_id_by_cursor_pos(screenCoords); + if (scenery.IsUndefined()) return; uint8_t tabIndex = gWindowSceneryActiveTabIndex; - gWindowSceneryTabSelections[tabIndex] = sceneryId; + gWindowSceneryTabSelections[tabIndex] = scenery; gWindowSceneryPaintEnabled &= 0xFE; gWindowSceneryEyedropperEnabled = false; @@ -915,10 +908,10 @@ void window_scenery_scrollmousedown(rct_window* w, int32_t scrollIndex, const Sc */ void window_scenery_scrollmouseover(rct_window* w, int32_t scrollIndex, const ScreenCoordsXY& screenCoords) { - uint16_t sceneryId = get_scenery_id_by_cursor_pos(screenCoords); - if (sceneryId != WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + ScenerySelection scenery = get_scenery_id_by_cursor_pos(screenCoords); + if (!scenery.IsUndefined()) { - w->scenery.selected_scenery_id = sceneryId; + w->scenery.SelectedScenery = scenery; w->Invalidate(); } } @@ -995,23 +988,23 @@ void window_scenery_invalidate(rct_window* w) window_scenery_widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].type = WWT_FLATBTN; } - int16_t tabSelectedSceneryId = gWindowSceneryTabSelections[tabIndex]; - if (tabSelectedSceneryId != -1) + ScenerySelection tabSelectedScenery = gWindowSceneryTabSelections[tabIndex]; + if (!tabSelectedScenery.IsUndefined()) { - if (tabSelectedSceneryId <= SCENERY_SMALL_SCENERY_ID_MAX) + if (tabSelectedScenery.SceneryType == SCENERY_TYPE_SMALL) { if (!(gWindowSceneryPaintEnabled & 1)) { window_scenery_widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WWT_FLATBTN; } - rct_scenery_entry* sceneryEntry = get_small_scenery_entry(tabSelectedSceneryId); + rct_scenery_entry* sceneryEntry = get_small_scenery_entry(tabSelectedScenery.EntryIndex); if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_ROTATABLE)) { window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WWT_FLATBTN; } } - else if (tabSelectedSceneryId >= SCENERY_LARGE_SCENERY_ID_MIN) + else if (tabSelectedScenery.SceneryType >= SCENERY_TYPE_LARGE) { window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WWT_FLATBTN; } @@ -1036,30 +1029,30 @@ void window_scenery_invalidate(rct_window* w) window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WWT_COLOURBTN; window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WWT_EMPTY; } - else if (tabSelectedSceneryId != -1) + else if (!tabSelectedScenery.IsUndefined()) { rct_scenery_entry* sceneryEntry = nullptr; - if (tabSelectedSceneryId >= SCENERY_BANNERS_ID_MIN) + if (tabSelectedScenery.SceneryType == SCENERY_TYPE_BANNER) { - sceneryEntry = get_banner_entry(tabSelectedSceneryId - SCENERY_BANNERS_ID_MIN); + sceneryEntry = get_banner_entry(tabSelectedScenery.EntryIndex); if (sceneryEntry->banner.flags & BANNER_ENTRY_FLAG_HAS_PRIMARY_COLOUR) { window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLOURBTN; } } - else if (tabSelectedSceneryId >= SCENERY_LARGE_SCENERY_ID_MIN) + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_LARGE) { - sceneryEntry = get_large_scenery_entry(tabSelectedSceneryId - SCENERY_LARGE_SCENERY_ID_MIN); + sceneryEntry = get_large_scenery_entry(tabSelectedScenery.EntryIndex); if (sceneryEntry->large_scenery.flags & LARGE_SCENERY_FLAG_HAS_PRIMARY_COLOUR) window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLOURBTN; if (sceneryEntry->large_scenery.flags & LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR) window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WWT_COLOURBTN; } - else if (tabSelectedSceneryId >= SCENERY_WALLS_ID_MIN) + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_WALL) { - sceneryEntry = get_wall_entry(tabSelectedSceneryId - SCENERY_WALLS_ID_MIN); + sceneryEntry = get_wall_entry(tabSelectedScenery.EntryIndex); if (sceneryEntry->wall.flags & (WALL_SCENERY_HAS_PRIMARY_COLOUR | WALL_SCENERY_HAS_GLASS)) { window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WWT_COLOURBTN; @@ -1075,9 +1068,9 @@ void window_scenery_invalidate(rct_window* w) } } } - else if (tabSelectedSceneryId <= SCENERY_SMALL_SCENERY_ID_MAX) + else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_SMALL) { - sceneryEntry = get_small_scenery_entry(tabSelectedSceneryId); + sceneryEntry = get_small_scenery_entry(tabSelectedScenery.EntryIndex); if (scenery_small_entry_has_flag( sceneryEntry, SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG_HAS_GLASS)) @@ -1133,50 +1126,48 @@ void window_scenery_paint(rct_window* w, rct_drawpixelinfo* dpi) dpi, imageId, w->windowPos.x + window_scenery_widgets[selectedWidgetId].left, w->windowPos.y + window_scenery_widgets[selectedWidgetId].top, selectedWidgetId); - uint16_t selectedSceneryEntryId = w->scenery.selected_scenery_id; - if (selectedSceneryEntryId == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + ScenerySelection selectedSceneryEntry = w->scenery.SelectedScenery; + if (selectedSceneryEntry.IsUndefined()) { if (gWindowSceneryPaintEnabled & 1) // repaint coloured scenery tool is on return; if (gWindowSceneryEyedropperEnabled) return; - selectedSceneryEntryId = gWindowSceneryTabSelections[tabIndex]; + selectedSceneryEntry = gWindowSceneryTabSelections[tabIndex]; - if (selectedSceneryEntryId == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + if (selectedSceneryEntry.IsUndefined()) return; } uint32_t price = 0; rct_scenery_entry* sceneryEntry = nullptr; - if (selectedSceneryEntryId >= SCENERY_BANNERS_ID_MIN) + switch (selectedSceneryEntry.SceneryType) { - sceneryEntry = get_banner_entry(selectedSceneryEntryId - SCENERY_BANNERS_ID_MIN); - price = sceneryEntry->banner.price; - } - else if (selectedSceneryEntryId >= SCENERY_LARGE_SCENERY_ID_MIN) - { - sceneryEntry = get_large_scenery_entry(selectedSceneryEntryId - SCENERY_LARGE_SCENERY_ID_MIN); - price = sceneryEntry->large_scenery.price * 10; - } - else if (selectedSceneryEntryId >= SCENERY_WALLS_ID_MIN) - { - sceneryEntry = get_wall_entry(selectedSceneryEntryId - SCENERY_WALLS_ID_MIN); - price = sceneryEntry->wall.price; - } - else if (selectedSceneryEntryId >= SCENERY_PATH_SCENERY_ID_MIN) - { - sceneryEntry = get_footpath_item_entry(selectedSceneryEntryId - SCENERY_PATH_SCENERY_ID_MIN); - price = sceneryEntry->path_bit.price; - } - else - { - sceneryEntry = get_small_scenery_entry(selectedSceneryEntryId); - price = sceneryEntry->small_scenery.price * 10; + case SCENERY_TYPE_SMALL: + sceneryEntry = get_small_scenery_entry(selectedSceneryEntry.EntryIndex); + price = sceneryEntry->small_scenery.price * 10; + break; + case SCENERY_TYPE_PATH_ITEM: + sceneryEntry = get_footpath_item_entry(selectedSceneryEntry.EntryIndex); + price = sceneryEntry->path_bit.price; + break; + case SCENERY_TYPE_WALL: + sceneryEntry = get_wall_entry(selectedSceneryEntry.EntryIndex); + price = sceneryEntry->wall.price; + break; + case SCENERY_TYPE_LARGE: + sceneryEntry = get_large_scenery_entry(selectedSceneryEntry.EntryIndex); + price = sceneryEntry->large_scenery.price * 10; + break; + case SCENERY_TYPE_BANNER: + sceneryEntry = get_banner_entry(selectedSceneryEntry.EntryIndex); + price = sceneryEntry->banner.price; + break; } - if (w->scenery.selected_scenery_id == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED && gSceneryPlaceCost != MONEY32_UNDEFINED) + if (w->scenery.SelectedScenery.IsUndefined() && gSceneryPlaceCost != MONEY32_UNDEFINED) { price = gSceneryPlaceCost; } @@ -1208,17 +1199,17 @@ void window_scenery_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t s uint8_t tabIndex = gWindowSceneryActiveTabIndex; int32_t sceneryTabItemIndex = 0; - uint16_t currentSceneryGlobalId = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + ScenerySelection currentSceneryGlobal = ScenerySelection::CreateUndefined(); int16_t left = 0, top = 0; - while ((currentSceneryGlobalId = window_scenery_tab_entries[tabIndex][sceneryTabItemIndex]) - != WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + while ((currentSceneryGlobal = window_scenery_tab_entries[tabIndex][sceneryTabItemIndex]), + !currentSceneryGlobal.IsUndefined()) { - uint16_t tabSelectedSceneryId = gWindowSceneryTabSelections[tabIndex]; + ScenerySelection tabSelectedScenery = gWindowSceneryTabSelections[tabIndex]; if (gWindowSceneryPaintEnabled == 1 || gWindowSceneryEyedropperEnabled) { - if (w->scenery.selected_scenery_id == currentSceneryGlobalId) + if (w->scenery.SelectedScenery == currentSceneryGlobal) { gfx_fill_rect_inset( dpi, left, top, left + SCENERY_BUTTON_WIDTH - 1, top + SCENERY_BUTTON_HEIGHT - 1, w->colours[1], @@ -1227,13 +1218,13 @@ void window_scenery_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t s } else { - if (tabSelectedSceneryId == currentSceneryGlobalId) + if (tabSelectedScenery == currentSceneryGlobal) { gfx_fill_rect_inset( dpi, left, top, left + SCENERY_BUTTON_WIDTH - 1, top + SCENERY_BUTTON_HEIGHT - 1, w->colours[1], (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_MID_LIGHT)); } - else if (w->scenery.selected_scenery_id == currentSceneryGlobalId) + else if (w->scenery.SelectedScenery == currentSceneryGlobal) { gfx_fill_rect_inset( dpi, left, top, left + SCENERY_BUTTON_WIDTH - 1, top + SCENERY_BUTTON_HEIGHT - 1, w->colours[1], @@ -1245,27 +1236,27 @@ void window_scenery_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t s rct_drawpixelinfo clipdpi; if (clip_drawpixelinfo(&clipdpi, dpi, left + 1, top + 1, SCENERY_BUTTON_WIDTH - 2, SCENERY_BUTTON_HEIGHT - 2)) { - if (currentSceneryGlobalId >= SCENERY_BANNERS_ID_MIN) + if (currentSceneryGlobal.SceneryType == SCENERY_TYPE_BANNER) { - sceneryEntry = get_banner_entry(currentSceneryGlobalId - SCENERY_BANNERS_ID_MIN); + sceneryEntry = get_banner_entry(currentSceneryGlobal.EntryIndex); uint32_t imageId = sceneryEntry->image + gWindowSceneryRotation * 2; imageId |= (gWindowSceneryPrimaryColour << 19) | IMAGE_TYPE_REMAP; gfx_draw_sprite(&clipdpi, imageId, 0x21, 0x28, w->colours[1]); gfx_draw_sprite(&clipdpi, imageId + 1, 0x21, 0x28, w->colours[1]); } - else if (currentSceneryGlobalId >= SCENERY_LARGE_SCENERY_ID_MIN) + else if (currentSceneryGlobal.SceneryType == SCENERY_TYPE_LARGE) { - sceneryEntry = get_large_scenery_entry(currentSceneryGlobalId - SCENERY_LARGE_SCENERY_ID_MIN); + sceneryEntry = get_large_scenery_entry(currentSceneryGlobal.EntryIndex); uint32_t imageId = sceneryEntry->image + gWindowSceneryRotation; imageId |= (gWindowSceneryPrimaryColour << 19) | IMAGE_TYPE_REMAP; imageId |= (gWindowScenerySecondaryColour << 24) | IMAGE_TYPE_REMAP_2_PLUS; gfx_draw_sprite(&clipdpi, imageId, 0x21, 0, w->colours[1]); } - else if (currentSceneryGlobalId >= SCENERY_WALLS_ID_MIN) + else if (currentSceneryGlobal.SceneryType == SCENERY_TYPE_WALL) { - sceneryEntry = get_wall_entry(currentSceneryGlobalId - SCENERY_WALLS_ID_MIN); + sceneryEntry = get_wall_entry(currentSceneryGlobal.EntryIndex); uint32_t imageId = sceneryEntry->image; uint8_t tertiaryColour = w->colours[1]; uint16_t spriteTop = (sceneryEntry->wall.height * 2) + 0x32; @@ -1305,16 +1296,16 @@ void window_scenery_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t s } } } - else if (currentSceneryGlobalId >= SCENERY_PATH_SCENERY_ID_MIN) + else if (currentSceneryGlobal.SceneryType == SCENERY_TYPE_PATH_ITEM) { - sceneryEntry = get_footpath_item_entry(currentSceneryGlobalId - SCENERY_PATH_SCENERY_ID_MIN); + sceneryEntry = get_footpath_item_entry(currentSceneryGlobal.EntryIndex); uint32_t imageId = sceneryEntry->image; gfx_draw_sprite(&clipdpi, imageId, 0x0B, 0x10, w->colours[1]); } else { - sceneryEntry = get_small_scenery_entry(currentSceneryGlobalId); + sceneryEntry = get_small_scenery_entry(currentSceneryGlobal.EntryIndex); uint32_t imageId = sceneryEntry->image + gWindowSceneryRotation; if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR)) @@ -1363,33 +1354,33 @@ void window_scenery_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t s } } -static int32_t window_scenery_find_tab_with_scenery_id(int32_t sceneryId) +static int32_t window_scenery_find_tab_with_scenery(const ScenerySelection& scenery) { for (int32_t i = 0; i < SCENERY_WINDOW_TABS; i++) { - for (int32_t j = 0; j < SCENERY_ENTRIES_BY_TAB; j++) + for (int32_t j = 0; j < SCENERY_ENTRIES_PER_TAB; j++) { - uint16_t entry = window_scenery_tab_entries[i][j]; - if (entry == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + ScenerySelection entry = window_scenery_tab_entries[i][j]; + if (entry.IsUndefined()) break; - if (entry == sceneryId) + if (entry == scenery) return i; } } return -1; } -bool window_scenery_set_selected_item(int32_t sceneryId) +bool window_scenery_set_selected_item(const ScenerySelection& scenery) { bool result = false; rct_window* w = window_bring_to_front_by_class(WC_SCENERY); if (w != nullptr) { - int32_t tabIndex = window_scenery_find_tab_with_scenery_id(sceneryId); + int32_t tabIndex = window_scenery_find_tab_with_scenery(scenery); if (tabIndex != -1) { gWindowSceneryActiveTabIndex = tabIndex; - gWindowSceneryTabSelections[tabIndex] = sceneryId; + gWindowSceneryTabSelections[tabIndex] = scenery; audio_play_sound(SoundId::Click1, 0, context_get_width() / 2); w->scenery.hover_counter = -16; @@ -1406,6 +1397,6 @@ void window_scenery_reset_selected_scenery_items() { for (size_t i = 0; i < SCENERY_WINDOW_TABS; i++) { - gWindowSceneryTabSelections[i] = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + gWindowSceneryTabSelections[i].SetUndefined(); } } diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index 7022d57de4..eab4744cab 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -1117,12 +1117,11 @@ static void scenery_eyedropper_tool_down(int16_t x, int16_t y, rct_widgetindex w case VIEWPORT_INTERACTION_ITEM_SCENERY: { SmallSceneryElement* sceneryElement = tileElement->AsSmallScenery(); - int32_t entryIndex = sceneryElement->GetEntryIndex(); + auto entryIndex = sceneryElement->GetEntryIndex(); rct_scenery_entry* sceneryEntry = get_small_scenery_entry(entryIndex); if (sceneryEntry != nullptr) { - int32_t sceneryId = get_scenery_id_from_entry_index(OBJECT_TYPE_SMALL_SCENERY, entryIndex); - if (sceneryId != -1 && window_scenery_set_selected_item(sceneryId)) + if (window_scenery_set_selected_item({ SCENERY_TYPE_SMALL, entryIndex })) { gWindowSceneryRotation = sceneryElement->GetDirectionWithOffset(get_current_rotation()); gWindowSceneryPrimaryColour = sceneryElement->GetPrimaryColour(); @@ -1134,12 +1133,11 @@ static void scenery_eyedropper_tool_down(int16_t x, int16_t y, rct_widgetindex w } case VIEWPORT_INTERACTION_ITEM_WALL: { - int32_t entryIndex = tileElement->AsWall()->GetEntryIndex(); + auto entryIndex = tileElement->AsWall()->GetEntryIndex(); rct_scenery_entry* sceneryEntry = get_wall_entry(entryIndex); if (sceneryEntry != nullptr) { - int32_t sceneryId = get_scenery_id_from_entry_index(OBJECT_TYPE_WALLS, entryIndex); - if (sceneryId != -1 && window_scenery_set_selected_item(sceneryId)) + if (window_scenery_set_selected_item({ SCENERY_TYPE_WALL, entryIndex })) { gWindowSceneryPrimaryColour = tileElement->AsWall()->GetPrimaryColour(); gWindowScenerySecondaryColour = tileElement->AsWall()->GetSecondaryColour(); @@ -1151,12 +1149,11 @@ static void scenery_eyedropper_tool_down(int16_t x, int16_t y, rct_widgetindex w } case VIEWPORT_INTERACTION_ITEM_LARGE_SCENERY: { - int32_t entryIndex = tileElement->AsLargeScenery()->GetEntryIndex(); + auto entryIndex = tileElement->AsLargeScenery()->GetEntryIndex(); rct_scenery_entry* sceneryEntry = get_large_scenery_entry(entryIndex); if (sceneryEntry != nullptr) { - int32_t sceneryId = get_scenery_id_from_entry_index(OBJECT_TYPE_LARGE_SCENERY, entryIndex); - if (sceneryId != -1 && window_scenery_set_selected_item(sceneryId)) + if (window_scenery_set_selected_item({ SCENERY_TYPE_LARGE, entryIndex })) { gWindowSceneryRotation = (get_current_rotation() + tileElement->GetDirection()) & 3; gWindowSceneryPrimaryColour = tileElement->AsLargeScenery()->GetPrimaryColour(); @@ -1174,8 +1171,7 @@ static void scenery_eyedropper_tool_down(int16_t x, int16_t y, rct_widgetindex w auto sceneryEntry = get_banner_entry(banner->type); if (sceneryEntry != nullptr) { - int32_t sceneryId = get_scenery_id_from_entry_index(OBJECT_TYPE_BANNERS, banner->type); - if (sceneryId != -1 && window_scenery_set_selected_item(sceneryId)) + if (window_scenery_set_selected_item({ SCENERY_TYPE_BANNER, banner->type })) { gWindowSceneryEyedropperEnabled = false; } @@ -1185,12 +1181,11 @@ static void scenery_eyedropper_tool_down(int16_t x, int16_t y, rct_widgetindex w } case VIEWPORT_INTERACTION_ITEM_FOOTPATH_ITEM: { - int32_t entryIndex = tileElement->AsPath()->GetAdditionEntryIndex(); + auto entryIndex = tileElement->AsPath()->GetAdditionEntryIndex(); rct_scenery_entry* sceneryEntry = get_footpath_item_entry(entryIndex); if (sceneryEntry != nullptr) { - int32_t sceneryId = get_scenery_id_from_entry_index(OBJECT_TYPE_PATH_BITS, entryIndex); - if (sceneryId != -1 && window_scenery_set_selected_item(sceneryId)) + if (window_scenery_set_selected_item({ SCENERY_TYPE_PATH_ITEM, entryIndex })) { gWindowSceneryEyedropperEnabled = false; } @@ -1211,7 +1206,7 @@ static void scenery_eyedropper_tool_down(int16_t x, int16_t y, rct_widgetindex w * edi : parameter_3 */ static void sub_6E1F34( - int16_t x, int16_t y, uint16_t selected_scenery, CoordsXY& gridPos, uint32_t* parameter_1, uint32_t* parameter_2, + int16_t x, int16_t y, ScenerySelection selection, CoordsXY& gridPos, uint32_t* parameter_1, uint32_t* parameter_2, uint32_t* parameter_3) { rct_window* w = window_find_by_class(WC_SCENERY); @@ -1222,33 +1217,30 @@ static void sub_6E1F34( return; } - // The upper byte of selected_scenery contains the type, the lower byte the index. - uint8_t scenery_type = selected_scenery >> 8; - selected_scenery &= 0xFF; uint16_t maxPossibleHeight = (std::numeric_limits::max() - 32) << MAX_ZOOM_LEVEL; bool can_raise_item = false; - if (scenery_type == SCENERY_TYPE_SMALL) + if (selection.SceneryType == SCENERY_TYPE_SMALL) { - rct_scenery_entry* scenery_entry = get_small_scenery_entry(selected_scenery); + rct_scenery_entry* scenery_entry = get_small_scenery_entry(selection.EntryIndex); maxPossibleHeight -= scenery_entry->small_scenery.height; if (scenery_small_entry_has_flag(scenery_entry, SMALL_SCENERY_FLAG_STACKABLE)) { can_raise_item = true; } } - else if (scenery_type == SCENERY_TYPE_WALL) + else if (selection.SceneryType == SCENERY_TYPE_WALL) { - rct_scenery_entry* scenery_entry = get_wall_entry(selected_scenery); + rct_scenery_entry* scenery_entry = get_wall_entry(selection.EntryIndex); if (scenery_entry) { maxPossibleHeight -= scenery_entry->wall.height; } can_raise_item = true; } - else if (scenery_type == SCENERY_TYPE_LARGE) + else if (selection.SceneryType == SCENERY_TYPE_LARGE) { - rct_scenery_entry* scenery_entry = get_large_scenery_entry(selected_scenery); + rct_scenery_entry* scenery_entry = get_large_scenery_entry(selection.EntryIndex); if (scenery_entry) { int16_t maxClearZ = 0; @@ -1333,20 +1325,20 @@ static void sub_6E1F34( } } - switch (scenery_type) + switch (selection.SceneryType) { case SCENERY_TYPE_SMALL: { // Small scenery - rct_scenery_entry* scenery = get_small_scenery_entry(selected_scenery); + rct_scenery_entry* scenery = get_small_scenery_entry(selection.EntryIndex); if (!scenery_small_entry_has_flag(scenery, SMALL_SCENERY_FLAG_FULL_TILE)) { - uint8_t cl = 0; + uint8_t quadrant = 0; // If CTRL not pressed if (!gSceneryCtrlPressed) { - auto gridCoords = screen_get_map_xy_quadrant({ x, y }, &cl); + auto gridCoords = screen_get_map_xy_quadrant({ x, y }, &quadrant); if (!gridCoords) { gridPos.setNull(); @@ -1379,7 +1371,7 @@ static void sub_6E1F34( { int16_t z = gSceneryCtrlPressZ; - auto mapCoords = screen_get_map_xy_quadrant_with_z({ x, y }, z, &cl); + auto mapCoords = screen_get_map_xy_quadrant_with_z({ x, y }, z, &quadrant); if (!mapCoords) { gridPos.setNull(); @@ -1412,8 +1404,8 @@ static void sub_6E1F34( rotation &= 0x3; // Also places it in lower but think thats for clobbering - *parameter_1 = selected_scenery << 8; - *parameter_2 = (cl ^ (1 << 1)) | (gWindowSceneryPrimaryColour << 8); + *parameter_1 = selection.EntryIndex << 8; + *parameter_2 = (quadrant ^ (1 << 1)) | (gWindowSceneryPrimaryColour << 8); *parameter_3 = rotation | (gWindowScenerySecondaryColour << 16); if (gConfigGeneral.virtual_floor_style != VIRTUAL_FLOOR_STYLE_OFF) @@ -1501,7 +1493,7 @@ static void sub_6E1F34( rotation &= 0x3; // Also places it in lower but think thats for clobbering - *parameter_1 = selected_scenery << 8; + *parameter_1 = selection.EntryIndex << 8; *parameter_2 = 0 | (gWindowSceneryPrimaryColour << 8); *parameter_3 = rotation | (gWindowScenerySecondaryColour << 16); break; @@ -1532,7 +1524,7 @@ static void sub_6E1F34( { *parameter_2 |= LOCATION_NULL; } - *parameter_3 = selected_scenery + 1; + *parameter_3 = selection.EntryIndex + 1; break; } case SCENERY_TYPE_WALL: @@ -1599,7 +1591,7 @@ static void sub_6E1F34( _secondaryColour = gWindowScenerySecondaryColour; _tertiaryColour = gWindowSceneryTertiaryColour; // Also places it in lower but think thats for clobbering - *parameter_1 = selected_scenery << 8; + *parameter_1 = selection.EntryIndex << 8; *parameter_2 = cl | (gWindowSceneryPrimaryColour << 8); *parameter_3 = 0; break; @@ -1672,7 +1664,7 @@ static void sub_6E1F34( *parameter_1 = (rotation << 8); *parameter_2 = gWindowSceneryPrimaryColour | (gWindowScenerySecondaryColour << 8); - *parameter_3 = selected_scenery; + *parameter_3 = selection.EntryIndex; break; } case SCENERY_TYPE_BANNER: @@ -1709,7 +1701,7 @@ static void sub_6E1F34( z /= 2; // Also places it in lower but think thats for clobbering - *parameter_1 = selected_scenery << 8; + *parameter_1 = selection.EntryIndex << 8; *parameter_2 = z | (rotation << 8); *parameter_3 = gWindowSceneryPrimaryColour; break; @@ -1722,6 +1714,64 @@ static void sub_6E1F34( } } +static void sub_6E1F34_small_scenery( + const ScreenCoordsXY& screenCoords, uint16_t sceneryIndex, CoordsXY& gridPos, uint8_t* outQuadrant, + colour_t* outPrimaryColour, colour_t* outSecondaryColour) +{ + uint32_t parameter1 = 0, parameter2 = 0, parameter3 = 0; + sub_6E1F34( + screenCoords.x, screenCoords.y, { SCENERY_TYPE_SMALL, sceneryIndex }, gridPos, ¶meter1, ¶meter2, ¶meter3); + + *outQuadrant = parameter2 & 0xFF; + *outPrimaryColour = (parameter2 >> 8) & 0xFF; + *outSecondaryColour = (parameter3 >> 16) & 0xFF; +} + +static void sub_6E1F34_path_item(const ScreenCoordsXY& screenCoords, uint16_t sceneryIndex, CoordsXY& gridPos, int32_t* outZ) +{ + uint32_t parameter1 = 0, parameter2 = 0, parameter3 = 0; + sub_6E1F34( + screenCoords.x, screenCoords.y, { SCENERY_TYPE_PATH_ITEM, sceneryIndex }, gridPos, ¶meter1, ¶meter2, + ¶meter3); + + *outZ = (parameter2 & 0xFF) * COORDS_Z_STEP; +} + +static void sub_6E1F34_wall( + const ScreenCoordsXY& screenCoords, uint16_t sceneryIndex, CoordsXY& gridPos, colour_t* outPrimaryColour, uint8_t* outEdges) +{ + uint32_t parameter1 = 0, parameter2 = 0, parameter3 = 0; + sub_6E1F34( + screenCoords.x, screenCoords.y, { SCENERY_TYPE_WALL, sceneryIndex }, gridPos, ¶meter1, ¶meter2, ¶meter3); + + *outPrimaryColour = (parameter2 >> 8) & 0xFF; + *outEdges = parameter2 & 0xFF; +} + +static void sub_6E1F34_large_scenery( + const ScreenCoordsXY& screenCoords, uint16_t sceneryIndex, CoordsXY& gridPos, colour_t* outPrimaryColour, + colour_t* outSecondaryColour, Direction* outDirection) +{ + uint32_t parameter1 = 0, parameter2 = 0, parameter3 = 0; + sub_6E1F34( + screenCoords.x, screenCoords.y, { SCENERY_TYPE_LARGE, sceneryIndex }, gridPos, ¶meter1, ¶meter2, ¶meter3); + + *outPrimaryColour = parameter2 & 0xFF; + *outSecondaryColour = (parameter2 >> 8) & 0xFF; + *outDirection = (parameter1 & 0xFF00) >> 8; +} + +static void sub_6E1F34_banner( + const ScreenCoordsXY& screenCoords, uint16_t sceneryIndex, CoordsXY& gridPos, int32_t* outZ, Direction* outDirection) +{ + uint32_t parameter1 = 0, parameter2 = 0, parameter3 = 0; + sub_6E1F34( + screenCoords.x, screenCoords.y, { SCENERY_TYPE_BANNER, sceneryIndex }, gridPos, ¶meter1, ¶meter2, ¶meter3); + + *outDirection = (parameter2 >> 8) & 0xFF; + *outZ = (parameter2 & 0xFF) * COORDS_Z_PER_TINY_Z; +} + /** * * rct2: 0x006E2CC6 @@ -1740,24 +1790,26 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo return; } - uint16_t selectedTab = gWindowSceneryTabSelections[gWindowSceneryActiveTabIndex]; - uint8_t sceneryType = (selectedTab & 0xFF00) >> 8; + ScenerySelection selectedTab = gWindowSceneryTabSelections[gWindowSceneryActiveTabIndex]; + uint8_t sceneryType = selectedTab.SceneryType; + uint16_t selectedScenery = selectedTab.EntryIndex; - if (selectedTab == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED) + if (selectedTab.IsUndefined()) return; CoordsXY gridPos; - uint32_t parameter_1, parameter_2, parameter_3; - - sub_6E1F34(x, y, selectedTab, gridPos, ¶meter_1, ¶meter_2, ¶meter_3); - - if (gridPos.isNull()) - return; switch (sceneryType) { case SCENERY_TYPE_SMALL: { + uint8_t quadrant; + colour_t primaryColour; + colour_t secondaryColour; + sub_6E1F34_small_scenery({ x, y }, selectedScenery, gridPos, &quadrant, &primaryColour, &secondaryColour); + if (gridPos.isNull()) + return; + int32_t quantity = 1; bool isCluster = gWindowSceneryScatterEnabled && (network_get_mode() != NETWORK_MODE_CLIENT @@ -1785,7 +1837,7 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo for (int32_t q = 0; q < quantity; q++) { int32_t zCoordinate = gSceneryPlaceZ; - rct_scenery_entry* scenery = get_small_scenery_entry((parameter_1 >> 8) & 0xFF); + rct_scenery_entry* scenery = get_small_scenery_entry(selectedScenery); int16_t cur_grid_x = gridPos.x; int16_t cur_grid_y = gridPos.y; @@ -1794,8 +1846,7 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo { if (!scenery_small_entry_has_flag(scenery, SMALL_SCENERY_FLAG_FULL_TILE)) { - parameter_2 &= 0xFF00; - parameter_2 |= util_rand() & 3; + quadrant = util_rand() & 3; } int16_t grid_x_offset = (util_rand() % gWindowSceneryScatterSize) - (gWindowSceneryScatterSize / 2); @@ -1820,17 +1871,13 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo zAttemptRange = 20; } - uint8_t quadrant = parameter_2 & 0xFF; - uint8_t primaryColour = (parameter_2 >> 8) & 0xFF; - uint8_t secondaryColour = (parameter_3 >> 16) & 0xFF; - uint8_t type = (parameter_1 >> 8) & 0xFF; auto success = GA_ERROR::UNKNOWN; // Try find a valid z coordinate for (; zAttemptRange != 0; zAttemptRange--) { auto smallSceneryPlaceAction = SmallSceneryPlaceAction( - { cur_grid_x, cur_grid_y, gSceneryPlaceZ, gSceneryPlaceRotation }, quadrant, type, primaryColour, - secondaryColour); + { cur_grid_x, cur_grid_y, gSceneryPlaceZ, gSceneryPlaceRotation }, quadrant, selectedScenery, + primaryColour, secondaryColour); auto res = GameActions::Query(&smallSceneryPlaceAction); success = res->Error; if (res->Error == GA_ERROR::OK) @@ -1852,8 +1899,8 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo if (success == GA_ERROR::OK || ((q + 1 == quantity) && forceError)) { auto smallSceneryPlaceAction = SmallSceneryPlaceAction( - { cur_grid_x, cur_grid_y, gSceneryPlaceZ, gSceneryPlaceRotation }, quadrant, type, primaryColour, - secondaryColour); + { cur_grid_x, cur_grid_y, gSceneryPlaceZ, gSceneryPlaceRotation }, quadrant, selectedScenery, + primaryColour, secondaryColour); smallSceneryPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) { if (result->Error == GA_ERROR::OK) @@ -1878,9 +1925,12 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo } case SCENERY_TYPE_PATH_ITEM: { - auto pathItemType = parameter_3 & 0xFF; - int32_t z = (parameter_2 & 0xFF) * COORDS_Z_STEP; - auto footpathSceneryPlaceAction = FootpathSceneryPlaceAction({ gridPos, z }, pathItemType); + int32_t z; + sub_6E1F34_path_item({ x, y }, selectedScenery, gridPos, &z); + if (gridPos.isNull()) + return; + + auto footpathSceneryPlaceAction = FootpathSceneryPlaceAction({ gridPos, z }, selectedScenery + 1); footpathSceneryPlaceAction.SetCallback([](const GameAction* ga, const GameActionResult* result) { if (result->Error != GA_ERROR::OK) @@ -1894,6 +1944,12 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo } case SCENERY_TYPE_WALL: { + colour_t primaryColour; + uint8_t edges; + sub_6E1F34_wall({ x, y }, selectedScenery, gridPos, &primaryColour, &edges); + if (gridPos.isNull()) + return; + uint8_t zAttemptRange = 1; if (gSceneryPlaceZ != 0 && gSceneryShiftPressed) { @@ -1902,11 +1958,8 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo for (; zAttemptRange != 0; zAttemptRange--) { - auto primaryColour = (parameter_2 >> 8) & 0xFF; - auto edges = parameter_2 & 0xFF; - auto type = (parameter_1 >> 8) & 0xFF; auto wallPlaceAction = WallPlaceAction( - type, { gridPos, gSceneryPlaceZ }, edges, primaryColour, _secondaryColour, _tertiaryColour); + selectedScenery, { gridPos, gSceneryPlaceZ }, edges, primaryColour, _secondaryColour, _tertiaryColour); auto res = GameActions::Query(&wallPlaceAction); if (res->Error == GA_ERROR::OK) @@ -1925,11 +1978,8 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo } } - auto primaryColour = (parameter_2 >> 8) & 0xFF; - auto edges = parameter_2 & 0xFF; - auto type = (parameter_1 >> 8) & 0xFF; auto wallPlaceAction = WallPlaceAction( - type, { gridPos, gSceneryPlaceZ }, edges, primaryColour, _secondaryColour, _tertiaryColour); + selectedScenery, { gridPos, gSceneryPlaceZ }, edges, primaryColour, _secondaryColour, _tertiaryColour); wallPlaceAction.SetCallback([](const GameAction* ga, const GameActionResult* result) { if (result->Error == GA_ERROR::OK) @@ -1942,6 +1992,13 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo } case SCENERY_TYPE_LARGE: { + colour_t primaryColour; + colour_t secondaryColour; + Direction direction; + sub_6E1F34_large_scenery({ x, y }, selectedScenery, gridPos, &primaryColour, &secondaryColour, &direction); + if (gridPos.isNull()) + return; + uint8_t zAttemptRange = 1; if (gSceneryPlaceZ != 0 && gSceneryShiftPressed) { @@ -1950,13 +2007,9 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo for (; zAttemptRange != 0; zAttemptRange--) { - auto primaryColour = parameter_2 & 0xFF; - auto secondaryColour = (parameter_2 >> 8) & 0xFF; - auto largeSceneryType = parameter_3 & 0xFF; - uint8_t direction = (parameter_1 & 0xFF00) >> 8; CoordsXYZD loc = { gridPos, gSceneryPlaceZ, direction }; - auto sceneryPlaceAction = LargeSceneryPlaceAction(loc, largeSceneryType, primaryColour, secondaryColour); + auto sceneryPlaceAction = LargeSceneryPlaceAction(loc, selectedScenery, primaryColour, secondaryColour); auto res = GameActions::Query(&sceneryPlaceAction); if (res->Error == GA_ERROR::OK) @@ -1974,13 +2027,10 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo gSceneryPlaceZ += 8; } } - auto primaryColour = parameter_2 & 0xFF; - auto secondaryColour = (parameter_2 >> 8) & 0xFF; - auto largeSceneryType = parameter_3 & 0xFF; - uint8_t direction = (parameter_1 & 0xFF00) >> 8; + CoordsXYZD loc = { gridPos, gSceneryPlaceZ, direction }; - auto sceneryPlaceAction = LargeSceneryPlaceAction(loc, largeSceneryType, primaryColour, secondaryColour); + auto sceneryPlaceAction = LargeSceneryPlaceAction(loc, selectedScenery, primaryColour, secondaryColour); sceneryPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) { if (result->Error == GA_ERROR::OK) { @@ -1996,18 +2046,21 @@ static void window_top_toolbar_scenery_tool_down(int16_t x, int16_t y, rct_windo } case SCENERY_TYPE_BANNER: { - uint8_t direction = (parameter_2 >> 8) & 0xFF; - int32_t z = (parameter_2 & 0xFF) * 16; + int32_t z; + Direction direction; + sub_6E1F34_banner({ x, y }, selectedScenery, gridPos, &z, &direction); + if (gridPos.isNull()) + return; + CoordsXYZD loc{ gridPos, z, direction }; auto primaryColour = gWindowSceneryPrimaryColour; - auto bannerType = (parameter_1 & 0xFF00) >> 8; auto bannerIndex = create_new_banner(0); if (bannerIndex == BANNER_INDEX_NULL) { context_show_error(STR_CANT_POSITION_THIS_HERE, STR_TOO_MANY_BANNERS_IN_GAME); break; } - auto bannerPlaceAction = BannerPlaceAction(loc, bannerType, bannerIndex, primaryColour); + auto bannerPlaceAction = BannerPlaceAction(loc, selectedScenery, bannerIndex, primaryColour); bannerPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) { if (result->Error == GA_ERROR::OK) { @@ -2483,34 +2536,34 @@ static void top_toolbar_tool_update_water(int16_t x, int16_t y) * On success places ghost scenery and returns cost to place proper */ static money32 try_place_ghost_scenery( - CoordsXY map_tile, uint32_t parameter_1, uint32_t parameter_2, uint32_t parameter_3, uint16_t selected_tab) + CoordsXY map_tile, uint32_t parameter_1, uint32_t parameter_2, uint32_t parameter_3, uint8_t scenery_type, + uint16_t entryIndex) { scenery_remove_ghost_tool_placement(); - uint8_t scenery_type = (selected_tab & 0xFF00) >> 8; money32 cost = 0; TileElement* tileElement; switch (scenery_type) { - case 0: + case SCENERY_TYPE_SMALL: { // Small Scenery // 6e252b uint8_t quadrant = parameter_2 & 0xFF; uint8_t primaryColour = (parameter_2 >> 8) & 0xFF; uint8_t secondaryColour = (parameter_3 >> 16) & 0xFF; - uint8_t type = (parameter_1 >> 8) & 0xFF; uint8_t rotation = parameter_3 & 0xFF; auto smallSceneryPlaceAction = SmallSceneryPlaceAction( - { map_tile.x, map_tile.y, gSceneryPlaceZ, rotation }, quadrant, type, primaryColour, secondaryColour); + { map_tile.x, map_tile.y, gSceneryPlaceZ, rotation }, quadrant, entryIndex, primaryColour, secondaryColour); smallSceneryPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED); auto res = GameActions::Execute(&smallSceneryPlaceAction); if (res->Error != GA_ERROR::OK) return MONEY32_UNDEFINED; gSceneryPlaceRotation = (uint16_t)(parameter_3 & 0xFF); - gSceneryPlaceObject = selected_tab; + gSceneryPlaceObject.SceneryType = SCENERY_TYPE_SMALL; + gSceneryPlaceObject.EntryIndex = entryIndex; tileElement = dynamic_cast(res.get())->tileElement; gSceneryGhostPosition = { map_tile, tileElement->GetBaseZ() }; @@ -2530,13 +2583,12 @@ static money32 try_place_ghost_scenery( cost = res->Cost; break; } - case 1: + case SCENERY_TYPE_PATH_ITEM: { // Path Bits // 6e265b - auto pathItemType = parameter_3 & 0xFF; int32_t z = (parameter_2 & 0xFF) * COORDS_Z_STEP; - auto footpathSceneryPlaceAction = FootpathSceneryPlaceAction({ map_tile.x, map_tile.y, z }, pathItemType); + auto footpathSceneryPlaceAction = FootpathSceneryPlaceAction({ map_tile.x, map_tile.y, z }, entryIndex + 1); footpathSceneryPlaceAction.SetFlags(GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED); footpathSceneryPlaceAction.SetCallback([=](const GameAction* ga, const GameActionResult* result) { if (result->Error != GA_ERROR::OK) @@ -2553,15 +2605,15 @@ static money32 try_place_ghost_scenery( cost = res->Cost; break; } - case 2: + case SCENERY_TYPE_WALL: { // Walls // 6e26b0 auto primaryColour = (parameter_2 >> 8) & 0xFF; auto edges = parameter_2 & 0xFF; - auto type = (parameter_1 >> 8) & 0xFF; auto wallPlaceAction = WallPlaceAction( - type, { map_tile.x, map_tile.y, gSceneryPlaceZ }, edges, primaryColour, _secondaryColour, _tertiaryColour); + entryIndex, { map_tile.x, map_tile.y, gSceneryPlaceZ }, edges, primaryColour, _secondaryColour, + _tertiaryColour); wallPlaceAction.SetFlags( GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND); wallPlaceAction.SetCallback([=](const GameAction* ga, const WallPlaceActionResult* result) { @@ -2580,17 +2632,16 @@ static money32 try_place_ghost_scenery( cost = res->Cost; break; } - case 3: + case SCENERY_TYPE_LARGE: { // Large Scenery // 6e25a7 auto primaryColour = parameter_2 & 0xFF; auto secondaryColour = (parameter_2 >> 8) & 0xFF; - auto sceneryType = parameter_3 & 0xFF; uint8_t direction = (parameter_1 & 0xFF00) >> 8; CoordsXYZD loc = { map_tile.x, map_tile.y, gSceneryPlaceZ, direction }; - auto sceneryPlaceAction = LargeSceneryPlaceAction(loc, sceneryType, primaryColour, secondaryColour); + auto sceneryPlaceAction = LargeSceneryPlaceAction(loc, entryIndex, primaryColour, secondaryColour); sceneryPlaceAction.SetFlags( GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND); auto res = GameActions::Execute(&sceneryPlaceAction); @@ -2617,22 +2668,21 @@ static money32 try_place_ghost_scenery( cost = res->Cost; break; } - case 4: + case SCENERY_TYPE_BANNER: { // Banners // 6e2612 uint8_t direction = (parameter_2 >> 8) & 0xFF; - int32_t z = (parameter_2 & 0xFF) * 16; + int32_t z = (parameter_2 & 0xFF) * COORDS_Z_PER_TINY_Z; CoordsXYZD loc{ map_tile.x, map_tile.y, z, direction }; auto primaryColour = gWindowSceneryPrimaryColour; - auto bannerType = (parameter_1 & 0xFF00) >> 8; auto bannerIndex = create_new_banner(0); if (bannerIndex == BANNER_INDEX_NULL) { // Silently fail as this is just for the ghost break; } - auto bannerPlaceAction = BannerPlaceAction(loc, bannerType, bannerIndex, primaryColour); + auto bannerPlaceAction = BannerPlaceAction(loc, entryIndex, bannerIndex, primaryColour); bannerPlaceAction.SetFlags( GAME_COMMAND_FLAG_GHOST | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND); auto res = GameActions::Execute(&bannerPlaceAction); @@ -2673,20 +2723,20 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) if (gWindowSceneryEyedropperEnabled) return; - int16_t selected_tab = gWindowSceneryTabSelections[gWindowSceneryActiveTabIndex]; + ScenerySelection selection = gWindowSceneryTabSelections[gWindowSceneryActiveTabIndex]; - if (selected_tab == -1) + if (selection.IsUndefined()) { scenery_remove_ghost_tool_placement(); return; } - uint8_t scenery_type = (selected_tab & 0xFF00) >> 8; - uint8_t selected_scenery = selected_tab & 0xFF; + uint8_t sceneryType = selection.SceneryType; + uint16_t selectedScenery = selection.EntryIndex; CoordsXY mapTile = {}; uint32_t parameter1, parameter2, parameter3; - sub_6E1F34(x, y, selected_tab, mapTile, ¶meter1, ¶meter2, ¶meter3); + sub_6E1F34(x, y, selection, mapTile, ¶meter1, ¶meter2, ¶meter3); if (mapTile.isNull()) { @@ -2698,7 +2748,7 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) uint8_t bl; money32 cost = 0; - switch (scenery_type) + switch (sceneryType) { case SCENERY_TYPE_SMALL: gMapSelectFlags |= MAP_SELECT_FLAG_ENABLE; @@ -2723,7 +2773,7 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) gMapSelectPositionB.y = mapTile.y; } - scenery = get_small_scenery_entry(selected_scenery); + scenery = get_small_scenery_entry(selectedScenery); gMapSelectType = MAP_SELECT_TYPE_FULL; if (!scenery_small_entry_has_flag(scenery, SMALL_SCENERY_FLAG_FULL_TILE) && !gWindowSceneryScatterEnabled) @@ -2735,7 +2785,8 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) // If no change in ghost placement if ((gSceneryGhostType & SCENERY_GHOST_FLAG_0) && mapTile == gSceneryGhostPosition - && (parameter2 & 0xFF) == _unkF64F0E && gSceneryPlaceZ == _unkF64F0A && gSceneryPlaceObject == selected_tab) + && (parameter2 & 0xFF) == _unkF64F0E && gSceneryPlaceZ == _unkF64F0A + && gSceneryPlaceObject.SceneryType == SCENERY_TYPE_SMALL && gSceneryPlaceObject.EntryIndex == selectedScenery) { return; } @@ -2753,7 +2804,7 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) for (; bl != 0; bl--) { - cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, selected_tab); + cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, sceneryType, selectedScenery); if (cost != MONEY32_UNDEFINED) break; @@ -2781,7 +2832,7 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) scenery_remove_ghost_tool_placement(); - cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, selected_tab); + cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, sceneryType, selectedScenery); gSceneryPlaceCost = cost; break; @@ -2816,7 +2867,7 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) cost = 0; for (; bl != 0; bl--) { - cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, selected_tab); + cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, sceneryType, selectedScenery); if (cost != MONEY32_UNDEFINED) break; @@ -2827,7 +2878,7 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) break; case SCENERY_TYPE_LARGE: { - scenery = get_large_scenery_entry(selected_scenery); + scenery = get_large_scenery_entry(selectedScenery); gMapSelectionTiles.clear(); for (rct_large_scenery_tile* tile = scenery->large_scenery.tiles; tile->x_offset != (int16_t)(uint16_t)0xFFFF; @@ -2847,14 +2898,15 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) // If no change in ghost placement if ((gSceneryGhostType & SCENERY_GHOST_FLAG_3) && mapTile == gSceneryGhostPosition && gSceneryPlaceZ == _unkF64F0A - && (int16_t)(parameter3 & 0xFFFF) == gSceneryPlaceObject) + && gSceneryPlaceObject.SceneryType == SCENERY_TYPE_LARGE && gSceneryPlaceObject.EntryIndex == selectedScenery) { return; } scenery_remove_ghost_tool_placement(); - gSceneryPlaceObject = (parameter3 & 0xFFFF); + gSceneryPlaceObject.SceneryType = SCENERY_TYPE_LARGE; + gSceneryPlaceObject.EntryIndex = selectedScenery; _unkF64F0A = gSceneryPlaceZ; bl = 1; @@ -2866,7 +2918,7 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) cost = 0; for (; bl != 0; bl--) { - cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, selected_tab); + cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, sceneryType, selectedScenery); if (cost != MONEY32_UNDEFINED) break; @@ -2896,7 +2948,7 @@ static void top_toolbar_tool_update_scenery(int16_t x, int16_t y) scenery_remove_ghost_tool_placement(); - cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, selected_tab); + cost = try_place_ghost_scenery(mapTile, parameter1, parameter2, parameter3, sceneryType, selectedScenery); gSceneryPlaceCost = cost; break; diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index 317273bf88..a0f7158634 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -21,7 +21,7 @@ struct TileElement; struct Vehicle; enum class ScatterToolDensity : uint8_t; -extern uint16_t gWindowSceneryTabSelections[]; +extern ScenerySelection gWindowSceneryTabSelections[]; extern uint8_t gWindowSceneryActiveTabIndex; extern bool gWindowSceneryScatterEnabled; extern uint16_t gWindowSceneryScatterSize; @@ -164,7 +164,7 @@ bool clear_scenery_tool_is_active(); bool water_tool_is_active(); rct_window* window_scenery_open(); -bool window_scenery_set_selected_item(int32_t sceneryId); +bool window_scenery_set_selected_item(const ScenerySelection& scenery); void window_scenery_set_default_placement_configuration(); void window_scenery_init(); void window_scenery_reset_selected_scenery_items(); diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index a61d4f2d89..5f955b2e58 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -13,6 +13,7 @@ #include "../common.h" #include "../ride/RideTypes.h" #include "../world/Location.hpp" +#include "../world/ScenerySelection.h" #include #include @@ -243,7 +244,7 @@ struct ride_variables struct scenery_variables { - uint16_t selected_scenery_id; + ScenerySelection SelectedScenery; int16_t hover_counter; }; diff --git a/src/openrct2/management/Research.cpp b/src/openrct2/management/Research.cpp index 7e8cc93d17..75a502593e 100644 --- a/src/openrct2/management/Research.cpp +++ b/src/openrct2/management/Research.cpp @@ -61,7 +61,7 @@ uint8_t gResearchUncompletedCategories; static bool _researchedRideTypes[RIDE_TYPE_COUNT]; static bool _researchedRideEntries[MAX_RIDE_OBJECTS]; -static bool _researchedSceneryItems[MAX_RESEARCHED_SCENERY_ITEMS]; +static bool _researchedSceneryItems[SCENERY_TYPE_COUNT][UINT16_MAX]; bool gSilentResearch = false; @@ -599,19 +599,21 @@ void ride_entry_set_invented(int32_t rideEntryIndex) _researchedRideEntries[rideEntryIndex] = true; } -bool scenery_is_invented(uint16_t sceneryItem) +bool scenery_is_invented(const ScenerySelection& sceneryItem) { - return _researchedSceneryItems[sceneryItem]; + return _researchedSceneryItems[sceneryItem.SceneryType][sceneryItem.EntryIndex]; } -void scenery_set_invented(uint16_t sceneryItem) +void scenery_set_invented(const ScenerySelection& sceneryItem) { - _researchedSceneryItems[sceneryItem] = true; + assert(sceneryItem.SceneryType < SCENERY_TYPE_COUNT); + _researchedSceneryItems[sceneryItem.SceneryType][sceneryItem.EntryIndex] = true; } -void scenery_set_not_invented(uint16_t sceneryItem) +void scenery_set_not_invented(const ScenerySelection& sceneryItem) { - _researchedSceneryItems[sceneryItem] = false; + assert(sceneryItem.SceneryType < SCENERY_TYPE_COUNT); + _researchedSceneryItems[sceneryItem.SceneryType][sceneryItem.EntryIndex] = false; } bool scenery_group_is_invented(int32_t sgIndex) @@ -628,8 +630,8 @@ bool scenery_group_is_invented(int32_t sgIndex) { for (auto i = 0; i < sgEntry->entry_count; i++) { - auto sceneryEntryIndex = sgEntry->scenery_entries[i]; - if (scenery_is_invented(sceneryEntryIndex)) + auto sceneryEntry = sgEntry->scenery_entries[i]; + if (scenery_is_invented(sceneryEntry)) { invented = true; break; @@ -672,12 +674,18 @@ void set_all_scenery_groups_not_invented() void set_all_scenery_items_invented() { - std::fill(std::begin(_researchedSceneryItems), std::end(_researchedSceneryItems), true); + for (auto sceneryType = 0; sceneryType < SCENERY_TYPE_COUNT; sceneryType++) + { + std::fill(std::begin(_researchedSceneryItems[sceneryType]), std::end(_researchedSceneryItems[sceneryType]), true); + } } void set_all_scenery_items_not_invented() { - std::fill(std::begin(_researchedSceneryItems), std::end(_researchedSceneryItems), false); + for (auto sceneryType = 0; sceneryType < SCENERY_TYPE_COUNT; sceneryType++) + { + std::fill(std::begin(_researchedSceneryItems[sceneryType]), std::end(_researchedSceneryItems[sceneryType]), true); + } } void set_every_ride_type_invented() diff --git a/src/openrct2/management/Research.h b/src/openrct2/management/Research.h index 7673dd973e..f36237df11 100644 --- a/src/openrct2/management/Research.h +++ b/src/openrct2/management/Research.h @@ -63,8 +63,6 @@ enum #define RESEARCH_ITEM_NULL 0xFFFFFFFF #define MAX_RESEARCH_ITEMS 500 -#define MAX_RESEARCHED_TRACK_TYPES 128 -#define MAX_RESEARCHED_SCENERY_ITEMS 1792 #define RESEARCH_ENTRY_RIDE_MASK 0x10000 @@ -129,15 +127,15 @@ void research_insert_scenery_group_entry(uint8_t entryIndex, bool researched); void ride_type_set_invented(uint32_t rideType); void ride_entry_set_invented(int32_t rideEntryIndex); -void scenery_set_invented(uint16_t sceneryItem); -void scenery_set_not_invented(uint16_t sceneryItem); +void scenery_set_invented(const ScenerySelection& sceneryItem); +void scenery_set_not_invented(const ScenerySelection& sceneryItem); bool ride_type_is_invented(uint32_t rideType); bool ride_entry_is_invented(int32_t rideEntryIndex); uint64_t get_available_track_pieces_for_ride_type(uint8_t rideType); bool track_piece_is_available_for_ride_type(uint8_t rideType, int32_t trackType); bool scenery_group_is_invented(int32_t sgIndex); void scenery_group_set_invented(int32_t sgIndex); -bool scenery_is_invented(uint16_t sceneryItem); +bool scenery_is_invented(const ScenerySelection& sceneryItem); void set_all_scenery_items_invented(); void set_all_scenery_items_not_invented(); void set_all_scenery_groups_not_invented(); diff --git a/src/openrct2/object/Object.cpp b/src/openrct2/object/Object.cpp index 35526d4021..a94438750f 100644 --- a/src/openrct2/object/Object.cpp +++ b/src/openrct2/object/Object.cpp @@ -13,6 +13,7 @@ #include "../core/String.hpp" #include "../localisation/Language.h" #include "../localisation/StringIds.h" +#include "../world/Scenery.h" #include "ObjectLimits.h" #include @@ -168,6 +169,25 @@ std::string Object::GetName(int32_t language) const return GetString(language, OBJ_STRING_ID_NAME); } +std::optional rct_object_entry::GetSceneryType() const +{ + switch (GetType()) + { + case OBJECT_TYPE_SMALL_SCENERY: + return SCENERY_TYPE_SMALL; + case OBJECT_TYPE_LARGE_SCENERY: + return SCENERY_TYPE_LARGE; + case OBJECT_TYPE_WALLS: + return SCENERY_TYPE_WALL; + case OBJECT_TYPE_BANNERS: + return SCENERY_TYPE_BANNER; + case OBJECT_TYPE_PATH_BITS: + return SCENERY_TYPE_PATH_ITEM; + default: + return std::nullopt; + } +} + #ifdef __WARN_SUGGEST_FINAL_METHODS__ # pragma GCC diagnostic pop #endif diff --git a/src/openrct2/object/Object.h b/src/openrct2/object/Object.h index 784739399a..581f0f2ee5 100644 --- a/src/openrct2/object/Object.h +++ b/src/openrct2/object/Object.h @@ -13,6 +13,7 @@ #include "ImageTable.h" #include "StringTable.h" +#include #include #include @@ -110,6 +111,8 @@ struct rct_object_entry { return flags & 0x0F; } + + std::optional GetSceneryType() const; }; assert_struct_size(rct_object_entry, 0x10); diff --git a/src/openrct2/object/SceneryGroupObject.cpp b/src/openrct2/object/SceneryGroupObject.cpp index bd641bc22e..62d22154b4 100644 --- a/src/openrct2/object/SceneryGroupObject.cpp +++ b/src/openrct2/object/SceneryGroupObject.cpp @@ -31,9 +31,9 @@ void SceneryGroupObject::ReadLegacy(IReadObjectContext* context, IStream* stream stream->Seek(6, STREAM_SEEK_CURRENT); stream->Seek(0x80 * 2, STREAM_SEEK_CURRENT); _legacyType.entry_count = stream->ReadValue(); - _legacyType.pad_107 = stream->ReadValue(); + stream->Seek(1, STREAM_SEEK_CURRENT); // pad_107; _legacyType.priority = stream->ReadValue(); - _legacyType.pad_109 = stream->ReadValue(); + stream->Seek(1, STREAM_SEEK_CURRENT); // pad_109; _legacyType.entertainer_costumes = stream->ReadValue(); GetStringTable().Read(context, stream, OBJ_STRING_ID_NAME); @@ -82,33 +82,13 @@ void SceneryGroupObject::UpdateEntryIndexes() if (ori->LoadedObject == nullptr) continue; - uint16_t sceneryEntry = objectManager.GetLoadedObjectEntryIndex(ori->LoadedObject); - Guard::Assert(sceneryEntry != UINT8_MAX, GUARD_LINE); + uint16_t entryIndex = objectManager.GetLoadedObjectEntryIndex(ori->LoadedObject); + Guard::Assert(entryIndex != UINT8_MAX, GUARD_LINE); - auto objectType = ori->ObjectEntry.GetType(); - switch (objectType) + auto sceneryType = ori->ObjectEntry.GetSceneryType(); + if (sceneryType != std::nullopt) { - case OBJECT_TYPE_SMALL_SCENERY: - break; - case OBJECT_TYPE_PATH_BITS: - sceneryEntry += SCENERY_PATH_SCENERY_ID_MIN; - break; - case OBJECT_TYPE_WALLS: - sceneryEntry += SCENERY_WALLS_ID_MIN; - break; - case OBJECT_TYPE_LARGE_SCENERY: - sceneryEntry += SCENERY_LARGE_SCENERY_ID_MIN; - break; - case OBJECT_TYPE_BANNERS: - sceneryEntry += SCENERY_BANNERS_ID_MIN; - break; - default: - sceneryEntry = UINT16_MAX; - break; - } - if (sceneryEntry != UINT16_MAX) - { - _legacyType.scenery_entries[_legacyType.entry_count] = sceneryEntry; + _legacyType.scenery_entries[_legacyType.entry_count] = { *sceneryType, entryIndex }; _legacyType.entry_count++; } } diff --git a/src/openrct2/rct2/S6Exporter.cpp b/src/openrct2/rct2/S6Exporter.cpp index cc77213cc2..2c35de2bfa 100644 --- a/src/openrct2/rct2/S6Exporter.cpp +++ b/src/openrct2/rct2/S6Exporter.cpp @@ -880,7 +880,9 @@ void S6Exporter::ExportResearchedSceneryItems() for (uint16_t sceneryEntryIndex = 0; sceneryEntryIndex < RCT2_MAX_RESEARCHED_SCENERY_ITEMS; sceneryEntryIndex++) { - if (scenery_is_invented(sceneryEntryIndex)) + ScenerySelection scenerySelection = { static_cast((sceneryEntryIndex >> 8) & 0xFF), + static_cast(sceneryEntryIndex & 0xFF) }; + if (scenery_is_invented(scenerySelection)) { int32_t quadIndex = sceneryEntryIndex >> 5; int32_t bitIndex = sceneryEntryIndex & 0x1F; diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index dca69159e5..5a0e02bcd8 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -874,7 +874,17 @@ public: bool invented = (_s6.researched_scenery_items[quadIndex] & ((uint32_t)1 << bitIndex)); if (invented) - scenery_set_invented(sceneryEntryIndex); + { + ScenerySelection scenerySelection = { static_cast((sceneryEntryIndex >> 8) & 0xFF), + static_cast(sceneryEntryIndex & 0xFF) }; + + // SV6 has room for 8 types of scenery, and sometimes scenery of non-existing types 5 and 6 is marked as + // "invented". + if (scenerySelection.SceneryType < SCENERY_TYPE_COUNT) + { + scenery_set_invented(scenerySelection); + } + } } } diff --git a/src/openrct2/world/Scenery.cpp b/src/openrct2/world/Scenery.cpp index 6d3d46868f..31208f962a 100644 --- a/src/openrct2/world/Scenery.cpp +++ b/src/openrct2/world/Scenery.cpp @@ -34,7 +34,7 @@ uint8_t gSceneryQuadrant; money32 gSceneryPlaceCost; -int16_t gSceneryPlaceObject; +ScenerySelection gSceneryPlaceObject; int16_t gSceneryPlaceZ; uint8_t gSceneryPlaceRotation; @@ -167,7 +167,8 @@ void scenery_remove_ghost_tool_placement() { gSceneryGhostType &= ~SCENERY_GHOST_FLAG_0; - auto removeSceneryAction = SmallSceneryRemoveAction(gSceneryGhostPosition, gSceneryQuadrant, gSceneryPlaceObject); + auto removeSceneryAction = SmallSceneryRemoveAction( + gSceneryGhostPosition, gSceneryQuadrant, gSceneryPlaceObject.EntryIndex); removeSceneryAction.SetFlags( GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED | GAME_COMMAND_FLAG_NO_SPEND | GAME_COMMAND_FLAG_GHOST); removeSceneryAction.Execute(); @@ -276,25 +277,6 @@ rct_scenery_group_entry* get_scenery_group_entry(int32_t entryIndex) return result; } -int32_t get_scenery_id_from_entry_index(uint8_t objectType, int32_t entryIndex) -{ - switch (objectType) - { - case OBJECT_TYPE_SMALL_SCENERY: - return entryIndex + SCENERY_SMALL_SCENERY_ID_MIN; - case OBJECT_TYPE_PATH_BITS: - return entryIndex + SCENERY_PATH_SCENERY_ID_MIN; - case OBJECT_TYPE_WALLS: - return entryIndex + SCENERY_WALLS_ID_MIN; - case OBJECT_TYPE_LARGE_SCENERY: - return entryIndex + SCENERY_LARGE_SCENERY_ID_MIN; - case OBJECT_TYPE_BANNERS: - return entryIndex + SCENERY_BANNERS_ID_MIN; - default: - return -1; - } -} - int32_t wall_entry_get_door_sound(const rct_scenery_entry* wallEntry) { return (wallEntry->wall.flags2 & WALL_SCENERY_2_DOOR_SOUND_MASK) >> WALL_SCENERY_2_DOOR_SOUND_SHIFT; diff --git a/src/openrct2/world/Scenery.h b/src/openrct2/world/Scenery.h index d29e6024f9..824f11367c 100644 --- a/src/openrct2/world/Scenery.h +++ b/src/openrct2/world/Scenery.h @@ -11,24 +11,12 @@ #define _SCENERY_H_ #include "../common.h" -#include "../object/Object.h" -#include "../object/ObjectLimits.h" #include "../world/Location.hpp" +#include "../world/ScenerySelection.h" #include "TileElement.h" #include -constexpr const uint16_t SCENERY_SMALL_SCENERY_ID_MIN = 0; -constexpr const uint16_t SCENERY_SMALL_SCENERY_ID_MAX = MAX_SMALL_SCENERY_OBJECTS - 1; -constexpr const uint16_t SCENERY_PATH_SCENERY_ID_MIN = 0x100; -constexpr const uint16_t SCENERY_PATH_SCENERY_ID_MAX = SCENERY_PATH_SCENERY_ID_MIN + MAX_PATH_ADDITION_OBJECTS - 1; -constexpr const uint16_t SCENERY_WALLS_ID_MIN = 0x200; -constexpr const uint16_t SCENERY_WALLS_ID_MAX = SCENERY_WALLS_ID_MIN + MAX_WALL_SCENERY_OBJECTS - 1; -constexpr const uint16_t SCENERY_LARGE_SCENERY_ID_MIN = 0x300; -constexpr const uint16_t SCENERY_LARGE_SCENERY_ID_MAX = SCENERY_LARGE_SCENERY_ID_MIN + MAX_LARGE_SCENERY_OBJECTS - 1; -constexpr const uint16_t SCENERY_BANNERS_ID_MIN = 0x400; -constexpr const uint16_t SCENERY_BANNERS_ID_MAX = SCENERY_BANNERS_ID_MIN + MAX_BANNER_OBJECTS - 1; - #define SCENERY_WITHER_AGE_THRESHOLD_1 0x28 #define SCENERY_WITHER_AGE_THRESHOLD_2 0x37 @@ -187,19 +175,17 @@ struct rct_scenery_entry assert_struct_size(rct_scenery_entry, 6 + 21); #endif +#pragma pack(pop) + struct rct_scenery_group_entry { - rct_string_id name; // 0x00 - uint32_t image; // 0x02 - uint16_t scenery_entries[0x80]; // 0x06 - uint8_t entry_count; // 0x106 - uint8_t pad_107; - uint8_t priority; // 0x108 - uint8_t pad_109; - uint32_t entertainer_costumes; // 0x10A + rct_string_id name; + uint32_t image; + ScenerySelection scenery_entries[0x80]; + uint8_t entry_count; + uint8_t priority; + uint32_t entertainer_costumes; }; -assert_struct_size(rct_scenery_group_entry, 14 + 2 * 0x80); -#pragma pack(pop) enum { @@ -228,7 +214,9 @@ enum SCENERY_TYPE_PATH_ITEM, SCENERY_TYPE_WALL, SCENERY_TYPE_LARGE, - SCENERY_TYPE_BANNER + SCENERY_TYPE_BANNER, + + SCENERY_TYPE_COUNT, }; enum @@ -252,13 +240,11 @@ enum class ScatterToolDensity : uint8_t HighDensity }; -#define SCENERY_ENTRIES_BY_TAB 1024 -constexpr auto WINDOW_SCENERY_TAB_SELECTION_UNDEFINED = std::numeric_limits::max(); - extern uint8_t gSceneryQuadrant; extern money32 gSceneryPlaceCost; -extern int16_t gSceneryPlaceObject; +extern ScenerySelection gSceneryPlaceObject; +extern uint16_t gSceneryPlaceObjectEntryIndex; extern int16_t gSceneryPlaceZ; extern uint8_t gSceneryPlaceRotation; @@ -288,7 +274,6 @@ rct_scenery_entry* get_banner_entry(int32_t entryIndex); rct_scenery_entry* get_footpath_item_entry(int32_t entryIndex); rct_scenery_group_entry* get_scenery_group_entry(int32_t entryIndex); -int32_t get_scenery_id_from_entry_index(uint8_t objectType, int32_t entryIndex); int32_t wall_entry_get_door_sound(const rct_scenery_entry* wallEntry); #endif diff --git a/src/openrct2/world/ScenerySelection.h b/src/openrct2/world/ScenerySelection.h new file mode 100644 index 0000000000..71303d9a75 --- /dev/null +++ b/src/openrct2/world/ScenerySelection.h @@ -0,0 +1,41 @@ +/***************************************************************************** + * Copyright (c) 2014-2020 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#pragma once + +#include +#include + +constexpr auto WINDOW_SCENERY_TAB_SELECTION_UNDEFINED = std::numeric_limits::max(); + +struct ScenerySelection +{ + uint8_t SceneryType; + uint16_t EntryIndex; + + inline bool operator==(const ScenerySelection& rhs) + { + return SceneryType == rhs.SceneryType && EntryIndex == rhs.EntryIndex; + } + + bool IsUndefined() const + { + return EntryIndex == WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + } + + void SetUndefined() + { + EntryIndex = WINDOW_SCENERY_TAB_SELECTION_UNDEFINED; + } + + static ScenerySelection CreateUndefined() + { + return ScenerySelection{ 0, WINDOW_SCENERY_TAB_SELECTION_UNDEFINED }; + } +};