diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index e7cdd31ead..4e04cf2591 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -58,8 +58,8 @@ enum { WINDOW_SCENERY_TAB_20 }; -ScenerySelection gWindowSceneryTabSelections[SCENERY_WINDOW_TABS]; -uint8_t gWindowSceneryActiveTabIndex; +std::vector gWindowSceneryTabSelections; +size_t gWindowSceneryActiveTabIndex; uint8_t gWindowSceneryPaintEnabled; uint8_t gWindowSceneryRotation; colour_t gWindowSceneryPrimaryColour; @@ -106,26 +106,26 @@ enum WINDOW_SCENERY_LIST_WIDGET_IDX { WIDX_SCENERY_TITLE, // 2 WIDX_SCENERY_CLOSE, // 4 WIDX_SCENERY_TAB_CONTENT_PANEL, // 8 - WIDX_SCENERY_TAB_1, // 10 - WIDX_SCENERY_TAB_2, // 20 - WIDX_SCENERY_TAB_3, // 40 - WIDX_SCENERY_TAB_4, // 80 - WIDX_SCENERY_TAB_5, // 100 - WIDX_SCENERY_TAB_6, // 200 - WIDX_SCENERY_TAB_7, // 400 - WIDX_SCENERY_TAB_8, // 800 - WIDX_SCENERY_TAB_9, // 1000 - WIDX_SCENERY_TAB_10, // 2000 - WIDX_SCENERY_TAB_11, // 4000 - WIDX_SCENERY_TAB_12, // 8000 - WIDX_SCENERY_TAB_13, // 10000 - WIDX_SCENERY_TAB_14, // 20000 - WIDX_SCENERY_TAB_15, // 40000 - WIDX_SCENERY_TAB_16, // 80000 - WIDX_SCENERY_TAB_17, // 100000 - WIDX_SCENERY_TAB_18, // 200000 - WIDX_SCENERY_TAB_19, // 400000 - WIDX_SCENERY_TAB_20, // 800000 + // WIDX_SCENERY_TAB_1, // 10 + // WIDX_SCENERY_TAB_2, // 20 + // WIDX_SCENERY_TAB_3, // 40 + // WIDX_SCENERY_TAB_4, // 80 + // WIDX_SCENERY_TAB_5, // 100 + // WIDX_SCENERY_TAB_6, // 200 + // WIDX_SCENERY_TAB_7, // 400 + // WIDX_SCENERY_TAB_8, // 800 + // WIDX_SCENERY_TAB_9, // 1000 + // WIDX_SCENERY_TAB_10, // 2000 + // WIDX_SCENERY_TAB_11, // 4000 + // WIDX_SCENERY_TAB_12, // 8000 + // WIDX_SCENERY_TAB_13, // 10000 + // WIDX_SCENERY_TAB_14, // 20000 + // WIDX_SCENERY_TAB_15, // 40000 + // WIDX_SCENERY_TAB_16, // 80000 + // WIDX_SCENERY_TAB_17, // 100000 + // WIDX_SCENERY_TAB_18, // 200000 + // WIDX_SCENERY_TAB_19, // 400000 + // WIDX_SCENERY_TAB_20, // 800000 WIDX_SCENERY_LIST, // 1000000 WIDX_SCENERY_ROTATE_OBJECTS_BUTTON, // 2000000 WIDX_SCENERY_REPAINT_SCENERY_BUTTON, // 4000000 @@ -134,6 +134,7 @@ enum WINDOW_SCENERY_LIST_WIDGET_IDX { WIDX_SCENERY_TERTIARY_COLOUR_BUTTON, // 20000000 WIDX_SCENERY_EYEDROPPER_BUTTON, // 40000000 WIDX_SCENERY_BUILD_CLUSTER_BUTTON, // 80000000 + WIDX_SCENERY_TAB_1, }; validate_global_widx(WC_SCENERY, WIDX_SCENERY_TAB_1); @@ -143,26 +144,6 @@ validate_global_widx(WC_SCENERY, WIDX_SCENERY_EYEDROPPER_BUTTON); static rct_widget window_scenery_widgets[] = { WINDOW_SHIM(WINDOW_TITLE, WINDOW_SCENERY_WIDTH, WINDOW_SCENERY_HEIGHT), MakeWidget ({ 0, 43}, {634, 99}, WindowWidgetType::Resize, WindowColour::Secondary ), // 8 0x009DE2C8 - MakeTab ({ 3, 17}, STR_STRING_DEFINED_TOOLTIP ), // 10 0x009DE2D8 - MakeTab ({ 34, 17}, STR_STRING_DEFINED_TOOLTIP ), // 20 0x009DE2E8 - MakeTab ({ 65, 17}, STR_STRING_DEFINED_TOOLTIP ), // 40 0x009DE2F8 - MakeTab ({ 96, 17}, STR_STRING_DEFINED_TOOLTIP ), // 80 0x009DE308 - MakeTab ({127, 17}, STR_STRING_DEFINED_TOOLTIP ), // 100 0x009DE318 - MakeTab ({158, 17}, STR_STRING_DEFINED_TOOLTIP ), // 200 0x009DE328 - MakeTab ({189, 17}, STR_STRING_DEFINED_TOOLTIP ), // 400 0x009DE338 - MakeTab ({220, 17}, STR_STRING_DEFINED_TOOLTIP ), // 800 0x009DE348 - MakeTab ({251, 17}, STR_STRING_DEFINED_TOOLTIP ), // 1000 0x009DE358 - MakeTab ({282, 17}, STR_STRING_DEFINED_TOOLTIP ), // 2000 0x009DE368 - MakeTab ({313, 17}, STR_STRING_DEFINED_TOOLTIP ), // 4000 0x009DE378 - MakeTab ({344, 17}, STR_STRING_DEFINED_TOOLTIP ), // 8000 0x009DE388 - MakeTab ({375, 17}, STR_STRING_DEFINED_TOOLTIP ), // 10000 0x009DE398 - MakeTab ({406, 17}, STR_STRING_DEFINED_TOOLTIP ), // 20000 0x009DE3A8 - MakeTab ({437, 17}, STR_STRING_DEFINED_TOOLTIP ), // 40000 0x009DE3B8 - MakeTab ({468, 17}, STR_STRING_DEFINED_TOOLTIP ), // 80000 0x009DE3C8 - MakeTab ({468, 17}, STR_STRING_DEFINED_TOOLTIP ), // 100000 0x009DE3D8 - MakeTab ({468, 17}, STR_STRING_DEFINED_TOOLTIP ), // 200000 0x009DE3E8 - MakeTab ({468, 17}, STR_STRING_DEFINED_TOOLTIP ), // 400000 0x009DE3F8 - MakeRemapWidget({468, 17}, { 31, 27}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB_QUESTION, STR_STRING_DEFINED_TOOLTIP ), // 800000 0x009DE408 MakeWidget ({ 2, 47}, {607, 80}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL ), // 1000000 0x009DE418 MakeWidget ({609, 44}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_ROTATE_ARROW, STR_ROTATE_OBJECTS_90 ), // 2000000 0x009DE428 MakeWidget ({609, 68}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Secondary, SPR_PAINTBRUSH, STR_SCENERY_PAINTBRUSH_TIP ), // 4000000 0x009DE438 @@ -177,56 +158,170 @@ static rct_widget window_scenery_widgets[] = { void window_scenery_update_scroll(rct_window* w); -// rct2: 0x00F64F2C -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, const ScenerySelection& selection, ObjectEntryIndex sceneryTabId) +struct SceneryTabInfo { - Guard::ArgumentInRange(selection.EntryIndex, 0, WINDOW_SCENERY_TAB_SELECTION_UNDEFINED); - if (scenery_is_invented(selection) || gCheatsIgnoreResearchStatus) + ObjectEntryIndex SceneryGroupIndex = OBJECT_ENTRY_INDEX_NULL; + std::vector Entries; + + bool IsMisc() const { - if (sceneryTabId < SCENERY_WINDOW_TABS) + return SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL; + } + + bool Contains(ScenerySelection entry) const + { + auto it = std::find(Entries.begin(), Entries.end(), entry); + return it != Entries.end(); + } + + void AddEntry(ScenerySelection entry) + { + if (!Contains(entry)) { - for (int32_t i = 0; i < SCENERY_ENTRIES_PER_TAB; i++) + Entries.push_back(entry); + } + } + + const rct_scenery_group_entry* GetSceneryGroupEntry() const + { + return get_scenery_group_entry(SceneryGroupIndex); + } +}; + +static std::vector _tabEntries; +static std::vector _widgets; +static size_t _numSceneryTabs; +static ScenerySelection _selectedScenery; +static int16_t _hoverCounter; + +static ScenerySelection GetSelectedScenery(size_t tabIndex) +{ + if (gWindowSceneryTabSelections.size() > tabIndex) + { + return gWindowSceneryTabSelections[tabIndex]; + } + return {}; +} + +static void SetSelectedScenery(size_t tabIndex, ScenerySelection value) +{ + if (gWindowSceneryTabSelections.size() <= tabIndex) + { + gWindowSceneryTabSelections.resize(tabIndex + 1); + } + gWindowSceneryTabSelections[tabIndex] = value; +} + +static SceneryTabInfo* GetSceneryTabInfoForGroup(ObjectEntryIndex sceneryGroupIndex) +{ + if (sceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + { + return &_tabEntries[_tabEntries.size() - 1]; + } + else if (_tabEntries.size() > sceneryGroupIndex) + { + return &_tabEntries[sceneryGroupIndex]; + } + else + { + return nullptr; + } +} + +static void init_scenery_entry( + const rct_scenery_entry* sceneryEntry, const ScenerySelection& selection, ObjectEntryIndex sceneryGroupIndex) +{ + Guard::ArgumentInRange(selection.EntryIndex, 0, OBJECT_ENTRY_INDEX_NULL); + + if (gCheatsIgnoreResearchStatus || scenery_is_invented(selection)) + { + // Check if in any other groups + for (const auto& otherTab : _tabEntries) + { + if (otherTab.Contains(selection)) { - if (window_scenery_tab_entries[sceneryTabId][i].IsUndefined()) - { - window_scenery_tab_entries[sceneryTabId][i] = selection; - window_scenery_tab_entries[sceneryTabId][i + 1].SetUndefined(); - return; - } + return; } } - for (int32_t i = 0; i < SCENERY_WINDOW_TABS - 1; i++) + auto tabInfo = GetSceneryTabInfoForGroup(sceneryGroupIndex); + if (tabInfo == nullptr) { - int32_t counter = 0; + // Misc tab + tabInfo = GetSceneryTabInfoForGroup(OBJECT_ENTRY_INDEX_NULL); + } + if (tabInfo != nullptr) + { + tabInfo->AddEntry(selection); + } + } +} - while (!window_scenery_tab_entries[i][counter].IsUndefined()) +static void window_scenery_sort_tabs() +{ + std::sort(_tabEntries.begin(), _tabEntries.end(), [](const SceneryTabInfo& a, const SceneryTabInfo& b) { + if (a.SceneryGroupIndex == b.SceneryGroupIndex) + return false; + + if (a.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + return false; + else if (b.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + return true; + + auto entryA = a.GetSceneryGroupEntry(); + auto entryB = b.GetSceneryGroupEntry(); + return entryA->priority < entryB->priority; + }); +} + +static void window_scenery_prepare_widgets(rct_window* w) +{ + _widgets.clear(); + for (const auto& widget : window_scenery_widgets) + { + _widgets.push_back(widget); + } + + // Remove WWT_LAST + auto lastWidget = _widgets.back(); + _widgets.pop_back(); + + // Add tabs + ScreenCoordsXY pos = { 3, 17 }; + auto finalTabRight = 0; + for (const auto& tabInfo : _tabEntries) + { + auto widget = MakeTab(pos, STR_STRING_DEFINED_TOOLTIP); + finalTabRight = widget.right; + pos.x += 31; + + if (tabInfo.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + { + widget.image = SPR_TAB_QUESTION | IMAGE_TYPE_REMAP; + } + else + { + auto sceneryGroupEntry = get_scenery_group_entry(tabInfo.SceneryGroupIndex); + if (sceneryGroupEntry != nullptr) { - if (window_scenery_tab_entries[i][counter] == selection) - { - return; - } - - counter++; + widget.image = sceneryGroupEntry->image | IMAGE_TYPE_REMAP; } } - for (int32_t i = 0; i < SCENERY_ENTRIES_PER_TAB; i++) - { - if (window_scenery_tab_entries[SCENERY_WINDOW_TABS - 1][i].IsUndefined()) - { - window_scenery_tab_entries[SCENERY_WINDOW_TABS - 1][i] = selection; - window_scenery_tab_entries[SCENERY_WINDOW_TABS - 1][i + 1].SetUndefined(); - break; - } - } + _widgets.push_back(widget); + } + + _widgets.push_back(lastWidget); + + w->widgets = _widgets.data(); + + w->enabled_widgets = (1 << WIDX_SCENERY_CLOSE) | (1 << WIDX_SCENERY_ROTATE_OBJECTS_BUTTON) + | (1 << WIDX_SCENERY_PRIMARY_COLOUR_BUTTON) | (1 << WIDX_SCENERY_SECONDARY_COLOUR_BUTTON) + | (1 << WIDX_SCENERY_REPAINT_SCENERY_BUTTON) | (1 << WIDX_SCENERY_TERTIARY_COLOUR_BUTTON) + | (1 << WIDX_SCENERY_EYEDROPPER_BUTTON) | (1ULL << WIDX_SCENERY_BUILD_CLUSTER_BUTTON); + for (size_t i = 0; i < _tabEntries.size(); i++) + { + w->enabled_widgets |= (1ULL << (WIDX_SCENERY_TAB_1 + i)); } } @@ -234,158 +329,106 @@ static void init_scenery_entry( * * rct2: 0x006DFA00 */ -void window_scenery_init() +static void window_scenery_init(rct_window* w) { - bool enabledScenerySets[SCENERY_WINDOW_TABS] = { false }; + _tabEntries.clear(); - for (int32_t scenerySetIndex = 0; scenerySetIndex < SCENERY_WINDOW_TABS; scenerySetIndex++) + auto maxTabs = 32; + for (ObjectEntryIndex scenerySetIndex = 0; scenerySetIndex < maxTabs - 1; scenerySetIndex++) { - window_scenery_tab_entries[scenerySetIndex][0].SetUndefined(); - if (scenerySetIndex == MAX_SCENERY_GROUP_OBJECTS) - continue; - - rct_scenery_group_entry* sceneryGroupEntry = get_scenery_group_entry(scenerySetIndex); - if (sceneryGroupEntry == nullptr) - continue; - - int32_t sceneryTabEntryCount = 0; - for (int32_t i = 0; i < sceneryGroupEntry->entry_count; i++) + const auto* sceneryGroupEntry = get_scenery_group_entry(scenerySetIndex); + if (sceneryGroupEntry != nullptr) { - auto sceneryEntry = sceneryGroupEntry->scenery_entries[i]; - if (scenery_is_invented(sceneryEntry) || gCheatsIgnoreResearchStatus) + SceneryTabInfo tabInfo; + tabInfo.SceneryGroupIndex = scenerySetIndex; + for (size_t i = 0; i < sceneryGroupEntry->entry_count; i++) { - window_scenery_tab_entries[scenerySetIndex][sceneryTabEntryCount] = sceneryEntry; - window_scenery_tab_entries[scenerySetIndex][++sceneryTabEntryCount].SetUndefined(); + auto sceneryEntry = sceneryGroupEntry->scenery_entries[i]; + if (scenery_is_invented(sceneryEntry) || gCheatsIgnoreResearchStatus) + { + tabInfo.Entries.push_back(sceneryEntry); + } } - else + if (tabInfo.Entries.size() > 0) { - enabledScenerySets[scenerySetIndex] = true; + _tabEntries.push_back(std::move(tabInfo)); } } } + // Add misc tab + _tabEntries.emplace_back(); + // small scenery for (ObjectEntryIndex 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, { SCENERY_TYPE_SMALL, sceneryId }, sceneryEntry->small_scenery.scenery_tab_id); + const auto* sceneryEntry = get_small_scenery_entry(sceneryId); + if (sceneryEntry != nullptr) + { + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_SMALL, sceneryId }, sceneryEntry->small_scenery.scenery_tab_id); + } } // large scenery for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_LARGE_SCENERY_OBJECTS; sceneryId++) { - rct_scenery_entry* sceneryEntry = get_large_scenery_entry(sceneryId); - if (sceneryEntry == nullptr) - continue; - - init_scenery_entry(sceneryEntry, { SCENERY_TYPE_LARGE, sceneryId }, sceneryEntry->large_scenery.scenery_tab_id); + const auto* sceneryEntry = get_large_scenery_entry(sceneryId); + if (sceneryEntry != nullptr) + { + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_LARGE, sceneryId }, sceneryEntry->large_scenery.scenery_tab_id); + } } // walls for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_WALL_SCENERY_OBJECTS; sceneryId++) { - rct_scenery_entry* sceneryEntry = get_wall_entry(sceneryId); - if (sceneryEntry == nullptr) - continue; - - init_scenery_entry(sceneryEntry, { SCENERY_TYPE_WALL, sceneryId }, sceneryEntry->wall.scenery_tab_id); + const auto* sceneryEntry = get_wall_entry(sceneryId); + if (sceneryEntry != nullptr) + { + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_WALL, sceneryId }, sceneryEntry->wall.scenery_tab_id); + } } // banners for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_BANNER_OBJECTS; sceneryId++) { - rct_scenery_entry* sceneryEntry = get_banner_entry(sceneryId); - if (sceneryEntry == nullptr) - continue; - - init_scenery_entry(sceneryEntry, { SCENERY_TYPE_BANNER, sceneryId }, sceneryEntry->banner.scenery_tab_id); + const auto* sceneryEntry = get_banner_entry(sceneryId); + if (sceneryEntry != nullptr) + { + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_BANNER, sceneryId }, sceneryEntry->banner.scenery_tab_id); + } } // path bits for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_PATH_ADDITION_OBJECTS; sceneryId++) { - rct_scenery_entry* sceneryEntry = get_footpath_item_entry(sceneryId); - if (sceneryEntry == nullptr) - continue; - - 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++) - window_scenery_widgets[widgetIndex].type = WindowWidgetType::Empty; - - uint8_t tabIndexes[SCENERY_WINDOW_TABS]; - uint8_t order[SCENERY_WINDOW_TABS]; - int32_t usedValues = 0; - - for (int32_t scenerySetId = 0; scenerySetId < MAX_SCENERY_GROUP_OBJECTS; scenerySetId++) - { - rct_scenery_group_entry* sceneryEntry = get_scenery_group_entry(scenerySetId); - if (sceneryEntry == nullptr) - continue; - - tabIndexes[usedValues] = scenerySetId; - order[usedValues] = sceneryEntry->priority; - - usedValues++; - } - - while (true) - { - bool finished = true; - for (int32_t i = 1; i < usedValues; i++) + const auto* sceneryEntry = get_footpath_item_entry(sceneryId); + if (sceneryEntry != nullptr) { - if (order[i - 1] > order[i]) - { - uint8_t tmp = tabIndexes[i - 1]; - tabIndexes[i - 1] = tabIndexes[i]; - tabIndexes[i] = tmp; - tmp = order[i - 1]; - order[i - 1] = order[i]; - order[i] = tmp; - finished = false; - } + init_scenery_entry(sceneryEntry, { SCENERY_TYPE_PATH_ITEM, sceneryId }, sceneryEntry->path_bit.scenery_tab_id); } - - if (finished) - break; } - tabIndexes[usedValues] = SCENERY_WINDOW_TABS - 1; - usedValues++; - - uint16_t left = 3; - for (int32_t i = 0; i < usedValues; i++) + // Remove misc tab if empty + if (_tabEntries.back().Entries.size() == 0) { - uint32_t tabIndex = tabIndexes[i]; - rct_widget* tabWidget = &window_scenery_widgets[tabIndex + WIDX_SCENERY_TAB_1]; - - if (left != 3 || tabIndex != SCENERY_WINDOW_TABS - 1) - { - if (window_scenery_tab_entries[tabIndex][0].IsUndefined()) - continue; - - if (enabledScenerySets[tabIndex]) - continue; - } - - tabWidget->type = WindowWidgetType::Tab; - tabWidget->left = left; - tabWidget->right = left + 0x1E; - left += 0x1F; - - if (tabIndex >= SCENERY_WINDOW_TABS - 1) - continue; - - tabWidget->image = get_scenery_group_entry(tabIndex)->image | IMAGE_TYPE_REMAP; + _tabEntries.pop_back(); } + window_scenery_sort_tabs(); + window_scenery_prepare_widgets(w); window_invalidate_by_class(WC_SCENERY); } +void window_scenery_init() +{ + auto w = window_find_by_class(WC_SCENERY); + if (w != nullptr) + { + window_scenery_init(w); + } +} + /** * * rct2: 0x006DFEE4 @@ -396,29 +439,11 @@ void window_scenery_set_default_placement_configuration() gWindowSceneryPrimaryColour = COLOUR_BORDEAUX_RED; gWindowScenerySecondaryColour = COLOUR_YELLOW; gWindowSceneryTertiaryColour = COLOUR_DARK_BROWN; + window_scenery_init(); - for (int32_t i = 0; i < SCENERY_WINDOW_TABS; i++) - gWindowSceneryTabSelections[i] = ScenerySelection::CreateUndefined(); - - for (int32_t i = 0; i < SCENERY_WINDOW_TABS; i++) - { - if (!window_scenery_tab_entries[i][0].IsUndefined()) - { - gWindowSceneryActiveTabIndex = i; - return; - } - } - - for (int32_t i = 0; i < 16; i++) - { - rct_widget* tabWidget = &window_scenery_widgets[WIDX_SCENERY_TAB_1 + i]; - if (tabWidget->type != WindowWidgetType::Empty) - { - gWindowSceneryActiveTabIndex = i; - return; - } - } + gWindowSceneryTabSelections.clear(); + gWindowSceneryActiveTabIndex = 0; } /** @@ -427,29 +452,16 @@ void window_scenery_set_default_placement_configuration() */ rct_window* window_scenery_open() { - rct_window* window; - // Check if window is already open - window = window_bring_to_front_by_class(WC_SCENERY); + auto window = window_bring_to_front_by_class(WC_SCENERY); if (window != nullptr) return window; - window_scenery_init(); - window = WindowCreate( ScreenCoordsXY(context_get_width() - WINDOW_SCENERY_WIDTH, 0x1D), WINDOW_SCENERY_WIDTH, WINDOW_SCENERY_HEIGHT, &window_scenery_events, WC_SCENERY, WF_NO_SCROLLING); - window->widgets = window_scenery_widgets; - window->enabled_widgets = (1 << WIDX_SCENERY_CLOSE) | (1 << WIDX_SCENERY_ROTATE_OBJECTS_BUTTON) | (1 << WIDX_SCENERY_TAB_1) - | (1 << WIDX_SCENERY_TAB_2) | (1 << WIDX_SCENERY_TAB_3) | (1 << WIDX_SCENERY_TAB_4) | (1 << WIDX_SCENERY_TAB_5) - | (1 << WIDX_SCENERY_TAB_6) | (1 << WIDX_SCENERY_TAB_7) | (1 << WIDX_SCENERY_TAB_8) | (1 << WIDX_SCENERY_TAB_9) - | (1 << WIDX_SCENERY_TAB_10) | (1 << WIDX_SCENERY_TAB_11) | (1 << WIDX_SCENERY_TAB_12) | (1 << WIDX_SCENERY_TAB_13) - | (1 << WIDX_SCENERY_TAB_14) | (1 << WIDX_SCENERY_TAB_15) | (1 << WIDX_SCENERY_TAB_16) | (1 << WIDX_SCENERY_TAB_17) - | (1 << WIDX_SCENERY_TAB_18) | (1 << WIDX_SCENERY_TAB_19) | (1 << WIDX_SCENERY_TAB_20) - | (1 << WIDX_SCENERY_PRIMARY_COLOUR_BUTTON) | (1 << WIDX_SCENERY_SECONDARY_COLOUR_BUTTON) - | (1 << WIDX_SCENERY_REPAINT_SCENERY_BUTTON) | (1 << WIDX_SCENERY_TERTIARY_COLOUR_BUTTON) - | (1 << WIDX_SCENERY_EYEDROPPER_BUTTON) | (1ULL << WIDX_SCENERY_BUILD_CLUSTER_BUTTON); + window_scenery_init(window); WindowInitScrollWidgets(window); window_scenery_update_scroll(window); @@ -457,8 +469,8 @@ rct_window* window_scenery_open() gWindowSceneryRotation = 3; gSceneryCtrlPressed = false; gSceneryShiftPressed = false; - window->scenery.SelectedScenery = ScenerySelection::CreateUndefined(); - window->scenery.hover_counter = 0; + _selectedScenery = {}; + _hoverCounter = 0; window_push_others_below(window); gSceneryGhostType = 0; gSceneryPlaceCost = MONEY32_UNDEFINED; @@ -491,10 +503,9 @@ void window_scenery_close(rct_window* w) tool_cancel(); } -static int32_t count_rows(int32_t items) +template constexpr static T count_rows(T items) { - int32_t rows = items / 9; - + auto rows = items / 9; return rows; } @@ -505,46 +516,35 @@ struct scenery_item ScenerySelection scenerySelection; }; -static scenery_item window_scenery_count_rows_with_selected_item(int32_t tabIndex) +static scenery_item window_scenery_count_rows_with_selected_item(size_t tabIndex) { - scenery_item sceneryItem = { 0, 0, ScenerySelection::CreateUndefined() }; - int32_t totalItems = 0; - ScenerySelection currentEntry = { 0, 0 }; - ScenerySelection scenerySelection = gWindowSceneryTabSelections[tabIndex]; - - for (totalItems = 0; totalItems < SCENERY_ENTRIES_PER_TAB + 1; ++totalItems) + scenery_item sceneryItem = { 0, 0, ScenerySelection() }; + const auto& scenerySelection = GetSelectedScenery(tabIndex); + const auto& tabInfo = _tabEntries[tabIndex]; + for (size_t i = 0; i < tabInfo.Entries.size(); i++) { - currentEntry = window_scenery_tab_entries[tabIndex][totalItems]; - if (currentEntry.IsUndefined()) - break; - + const auto& currentEntry = tabInfo.Entries[i]; if (currentEntry == scenerySelection) { - sceneryItem.selected_item = totalItems; + sceneryItem.selected_item = static_cast(i); sceneryItem.scenerySelection = scenerySelection; } } - sceneryItem.allRows = count_rows(totalItems + 8); + sceneryItem.allRows = static_cast(count_rows(tabInfo.Entries.size() + 8)); return sceneryItem; } -static int32_t window_scenery_count_rows() +static size_t window_scenery_count_rows() { - int32_t tabIndex = gWindowSceneryActiveTabIndex; - int32_t totalItems = 0; - - while (!window_scenery_tab_entries[tabIndex][totalItems].IsUndefined()) - { - totalItems++; - } - - int32_t rows = count_rows(totalItems + 8); + auto tabIndex = gWindowSceneryActiveTabIndex; + auto totalItems = _tabEntries[tabIndex].Entries.size(); + auto rows = count_rows(totalItems + 8); return rows; } -static int32_t window_scenery_rows_height(int32_t rows) +static int32_t window_scenery_rows_height(size_t rows) { - return rows * SCENERY_BUTTON_HEIGHT; + return static_cast(rows * SCENERY_BUTTON_HEIGHT); } /** @@ -607,20 +607,22 @@ static void window_scenery_mouseup(rct_window* w, rct_widgetindex widgetIndex) */ void window_scenery_update_scroll(rct_window* w) { - int32_t tabIndex = gWindowSceneryActiveTabIndex; - int32_t listHeight = w->height - 14 - window_scenery_widgets[WIDX_SCENERY_LIST].top - 1; + auto tabIndex = gWindowSceneryActiveTabIndex; + int32_t listHeight = w->height - 14 - w->widgets[WIDX_SCENERY_LIST].top - 1; scenery_item sceneryItem = window_scenery_count_rows_with_selected_item(tabIndex); w->scrolls[0].v_bottom = window_scenery_rows_height(sceneryItem.allRows) + 1; int32_t maxTop = std::max(0, w->scrolls[0].v_bottom - listHeight); - int32_t rowSelected = count_rows(sceneryItem.selected_item); + auto rowSelected = count_rows(sceneryItem.selected_item); if (sceneryItem.scenerySelection.IsUndefined()) { rowSelected = 0; - ScenerySelection scenery = window_scenery_tab_entries[tabIndex][0]; + auto& scenery = _tabEntries[tabIndex].Entries[0]; if (!scenery.IsUndefined()) - gWindowSceneryTabSelections[tabIndex] = scenery; + { + SetSelectedScenery(tabIndex, scenery); + } } w->scrolls[0].v_top = window_scenery_rows_height(rowSelected); @@ -689,7 +691,7 @@ static void window_scenery_mousedown(rct_window* w, rct_widgetindex widgetIndex, break; } - if (widgetIndex >= WIDX_SCENERY_TAB_1 && widgetIndex <= WIDX_SCENERY_TAB_20) + if (widgetIndex >= WIDX_SCENERY_TAB_1) { gWindowSceneryActiveTabIndex = widgetIndex - WIDX_SCENERY_TAB_1; w->Invalidate(); @@ -730,9 +732,9 @@ static void window_scenery_dropdown(rct_window* w, rct_widgetindex widgetIndex, */ static void window_scenery_periodic_update(rct_window* w) { - if (!w->scenery.SelectedScenery.IsUndefined()) + if (!_selectedScenery.IsUndefined()) { - w->scenery.SelectedScenery = ScenerySelection::CreateUndefined(); + _selectedScenery = {}; } } @@ -753,8 +755,8 @@ static void window_scenery_update(rct_window* w) rct_widgetindex widgetIndex = window_find_widget_from_point(w, state->position); if (widgetIndex >= WIDX_SCENERY_TAB_CONTENT_PANEL) { - w->scenery.hover_counter++; - if (w->scenery.hover_counter < 8) + _hoverCounter++; + if (_hoverCounter < 8) { if (input_get_state() != InputState::ScrollLeft) { @@ -781,7 +783,7 @@ static void window_scenery_update(rct_window* w) } else { - w->scenery.hover_counter = 0; + _hoverCounter = 0; if (input_get_state() != InputState::ScrollLeft) { w->min_width = WINDOW_SCENERY_WIDTH; @@ -809,9 +811,8 @@ static void window_scenery_update(rct_window* w) } else { - uint16_t tabIndex = gWindowSceneryActiveTabIndex; - ScenerySelection tabSelectedScenery = gWindowSceneryTabSelections[tabIndex]; - + auto tabIndex = gWindowSceneryActiveTabIndex; + auto tabSelectedScenery = GetSelectedScenery(tabIndex); if (!tabSelectedScenery.IsUndefined()) { if (tabSelectedScenery.SceneryType == SCENERY_TYPE_BANNER) @@ -846,26 +847,24 @@ static void window_scenery_update(rct_window* w) */ void window_scenery_scrollgetsize(rct_window* w, int32_t scrollIndex, int32_t* width, int32_t* height) { - int32_t rows = window_scenery_count_rows(); + auto rows = window_scenery_count_rows(); *height = window_scenery_rows_height(rows); } 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; - ScenerySelection scenery = ScenerySelection::CreateUndefined(); - while (itemCounter <= tabSceneryIndex) + ScenerySelection scenery{}; + auto tabIndex = gWindowSceneryActiveTabIndex; + if (tabIndex < _tabEntries.size()) { - scenery = window_scenery_tab_entries[tabIndex][itemCounter]; - if (scenery.IsUndefined()) - return ScenerySelection::CreateUndefined(); - - itemCounter++; + auto& tabInfo = _tabEntries[tabIndex]; + if (tabSceneryIndex < tabInfo.Entries.size()) + { + return tabInfo.Entries[tabSceneryIndex]; + } } - return scenery; } @@ -879,13 +878,12 @@ void window_scenery_scrollmousedown(rct_window* w, int32_t scrollIndex, const Sc if (scenery.IsUndefined()) return; - uint8_t tabIndex = gWindowSceneryActiveTabIndex; - gWindowSceneryTabSelections[tabIndex] = scenery; + SetSelectedScenery(gWindowSceneryActiveTabIndex, scenery); gWindowSceneryPaintEnabled &= 0xFE; gWindowSceneryEyedropperEnabled = false; OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, w->windowPos.x + (w->width / 2)); - w->scenery.hover_counter = -16; + _hoverCounter = -16; gSceneryPlaceCost = MONEY32_UNDEFINED; w->Invalidate(); } @@ -899,7 +897,7 @@ void window_scenery_scrollmouseover(rct_window* w, int32_t scrollIndex, const Sc ScenerySelection scenery = get_scenery_id_by_cursor_pos(screenCoords); if (!scenery.IsUndefined()) { - w->scenery.SelectedScenery = scenery; + _selectedScenery = scenery; w->Invalidate(); } } @@ -910,36 +908,31 @@ void window_scenery_scrollmouseover(rct_window* w, int32_t scrollIndex, const Sc */ OpenRCT2String window_scenery_tooltip(rct_window* w, const rct_widgetindex widgetIndex, const rct_string_id fallback) { - auto ft = Formatter(); - - switch (widgetIndex) + if (widgetIndex >= WIDX_SCENERY_TAB_1) { - case WIDX_SCENERY_TAB_1: - case WIDX_SCENERY_TAB_2: - case WIDX_SCENERY_TAB_3: - case WIDX_SCENERY_TAB_4: - case WIDX_SCENERY_TAB_5: - case WIDX_SCENERY_TAB_6: - case WIDX_SCENERY_TAB_7: - case WIDX_SCENERY_TAB_8: - case WIDX_SCENERY_TAB_9: - case WIDX_SCENERY_TAB_10: - case WIDX_SCENERY_TAB_11: - case WIDX_SCENERY_TAB_12: - case WIDX_SCENERY_TAB_13: - case WIDX_SCENERY_TAB_14: - case WIDX_SCENERY_TAB_15: - case WIDX_SCENERY_TAB_16: - case WIDX_SCENERY_TAB_17: - case WIDX_SCENERY_TAB_18: - case WIDX_SCENERY_TAB_19: - ft.Add(get_scenery_group_entry(widgetIndex - WIDX_SCENERY_TAB_1)->name); - break; - case WIDX_SCENERY_TAB_20: - ft.Add(STR_MISCELLANEOUS); - break; + auto tabIndex = widgetIndex - WIDX_SCENERY_TAB_1; + if (_tabEntries.size() > tabIndex) + { + const auto& tabInfo = _tabEntries[tabIndex]; + if (tabInfo.IsMisc()) + { + auto ft = Formatter(); + ft.Add(STR_MISCELLANEOUS); + return { fallback, ft }; + } + else + { + auto sceneryEntry = tabInfo.GetSceneryGroupEntry(); + if (sceneryEntry != nullptr) + { + auto ft = Formatter(); + ft.Add(sceneryEntry->name); + return { fallback, ft }; + } + } + } } - return { fallback, ft }; + return { STR_NONE }; } /** @@ -948,18 +941,15 @@ OpenRCT2String window_scenery_tooltip(rct_window* w, const rct_widgetindex widge */ void window_scenery_invalidate(rct_window* w) { - uint16_t tabIndex = gWindowSceneryActiveTabIndex; - uint32_t titleStringId = STR_MISCELLANEOUS; - if (tabIndex < SCENERY_WINDOW_TABS - 1) + rct_string_id titleStringId = STR_MISCELLANEOUS; + auto tabIndex = gWindowSceneryActiveTabIndex; + const auto* sgEntry = get_scenery_group_entry(static_cast(tabIndex)); + if (sgEntry != nullptr) { - rct_scenery_group_entry* sgEntry = get_scenery_group_entry(tabIndex); - if (sgEntry != nullptr) - { - titleStringId = sgEntry->name; - } + titleStringId = sgEntry->name; } - window_scenery_widgets[WIDX_SCENERY_TITLE].text = titleStringId; + w->widgets[WIDX_SCENERY_TITLE].text = titleStringId; w->pressed_widgets = 0; w->pressed_widgets |= 1ULL << (tabIndex + WIDX_SCENERY_TAB_1); @@ -970,55 +960,54 @@ void window_scenery_invalidate(rct_window* w) if (gWindowSceneryScatterEnabled) w->pressed_widgets |= (1ULL << WIDX_SCENERY_BUILD_CLUSTER_BUTTON); - window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::Empty; - window_scenery_widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].type = WindowWidgetType::Empty; - window_scenery_widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WindowWidgetType::Empty; + w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::Empty; + w->widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].type = WindowWidgetType::Empty; + w->widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WindowWidgetType::Empty; if (!(gWindowSceneryPaintEnabled & 1)) { - window_scenery_widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].type = WindowWidgetType::FlatBtn; + w->widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].type = WindowWidgetType::FlatBtn; } - ScenerySelection tabSelectedScenery = gWindowSceneryTabSelections[tabIndex]; + auto tabSelectedScenery = GetSelectedScenery(tabIndex); if (!tabSelectedScenery.IsUndefined()) { if (tabSelectedScenery.SceneryType == SCENERY_TYPE_SMALL) { if (!(gWindowSceneryPaintEnabled & 1)) { - window_scenery_widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WindowWidgetType::FlatBtn; + w->widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].type = WindowWidgetType::FlatBtn; } 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 = WindowWidgetType::FlatBtn; + w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::FlatBtn; } } else if (tabSelectedScenery.SceneryType >= SCENERY_TYPE_LARGE) { - window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::FlatBtn; + w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::FlatBtn; } } - window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowSceneryPrimaryColour) + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowSceneryPrimaryColour) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; - window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1( - gWindowScenerySecondaryColour) + w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowScenerySecondaryColour) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; - window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowSceneryTertiaryColour) + w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].image = SPRITE_ID_PALETTE_COLOUR_1(gWindowSceneryTertiaryColour) | IMAGE_TYPE_TRANSPARENT | SPR_PALETTE_BTN; - window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; - window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; - window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; + w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; + w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; if (gWindowSceneryPaintEnabled & 1) { // repaint coloured scenery tool is on - window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; - window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; - window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; - window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::Empty; + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].type = WindowWidgetType::Empty; } else if (!tabSelectedScenery.IsUndefined()) { @@ -1029,7 +1018,7 @@ void window_scenery_invalidate(rct_window* w) 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 = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; } } else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_LARGE) @@ -1037,25 +1026,25 @@ void window_scenery_invalidate(rct_window* w) 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 = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; if (sceneryEntry->large_scenery.flags & LARGE_SCENERY_FLAG_HAS_SECONDARY_COLOUR) - window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; } else if (tabSelectedScenery.SceneryType == SCENERY_TYPE_WALL) { 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 = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_SECONDARY_COLOUR) { - window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; if (sceneryEntry->wall.flags2 & WALL_SCENERY_2_NO_SELECT_PRIMARY_COLOUR) - window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::Empty; if (sceneryEntry->wall.flags & WALL_SCENERY_HAS_TERNARY_COLOUR) - window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; } } } @@ -1066,39 +1055,96 @@ void window_scenery_invalidate(rct_window* w) if (scenery_small_entry_has_flag( sceneryEntry, SMALL_SCENERY_FLAG_HAS_PRIMARY_COLOUR | SMALL_SCENERY_FLAG_HAS_GLASS)) { - window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; if (scenery_small_entry_has_flag(sceneryEntry, SMALL_SCENERY_FLAG_HAS_SECONDARY_COLOUR)) - window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; + w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].type = WindowWidgetType::ColourBtn; } } } - window_scenery_widgets[WIDX_SCENERY_BACKGROUND].right = w->width - 1; - window_scenery_widgets[WIDX_SCENERY_BACKGROUND].bottom = w->height - 1; - window_scenery_widgets[WIDX_SCENERY_TAB_CONTENT_PANEL].right = w->width - 1; - window_scenery_widgets[WIDX_SCENERY_TAB_CONTENT_PANEL].bottom = w->height - 1; - window_scenery_widgets[WIDX_SCENERY_TITLE].right = w->width - 2; - window_scenery_widgets[WIDX_SCENERY_CLOSE].left = w->width - 13; - window_scenery_widgets[WIDX_SCENERY_CLOSE].right = window_scenery_widgets[WIDX_SCENERY_CLOSE].left + 10; - window_scenery_widgets[WIDX_SCENERY_LIST].right = w->width - 26; - window_scenery_widgets[WIDX_SCENERY_LIST].bottom = w->height - 14; + auto windowWidth = w->width; + if (_tabEntries.size() > 0) + { + auto lastTabIndex = _tabEntries.size() - 1; + const auto lastTabWidget = &w->widgets[WIDX_SCENERY_TAB_1 + lastTabIndex]; + windowWidth = std::max(windowWidth, lastTabWidget->right + 3); + } + w->min_width = windowWidth; + w->max_width = windowWidth; - window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].left = w->width - 25; - window_scenery_widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].left = w->width - 25; - window_scenery_widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].left = w->width - 25; - window_scenery_widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].left = w->width - 25; - window_scenery_widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].right = w->width - 2; - window_scenery_widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].right = w->width - 2; - window_scenery_widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].right = w->width - 2; - window_scenery_widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].right = w->width - 2; + w->widgets[WIDX_SCENERY_BACKGROUND].right = windowWidth - 1; + w->widgets[WIDX_SCENERY_BACKGROUND].bottom = w->height - 1; + w->widgets[WIDX_SCENERY_TAB_CONTENT_PANEL].right = windowWidth - 1; + w->widgets[WIDX_SCENERY_TAB_CONTENT_PANEL].bottom = w->height - 1; + w->widgets[WIDX_SCENERY_TITLE].right = windowWidth - 2; + w->widgets[WIDX_SCENERY_CLOSE].left = windowWidth - 13; + w->widgets[WIDX_SCENERY_CLOSE].right = w->widgets[WIDX_SCENERY_CLOSE].left + 10; + w->widgets[WIDX_SCENERY_LIST].right = windowWidth - 26; + w->widgets[WIDX_SCENERY_LIST].bottom = w->height - 14; - window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].left = w->width - 19; - window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].left = w->width - 19; - window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].left = w->width - 19; - window_scenery_widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].right = w->width - 8; - window_scenery_widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].right = w->width - 8; - window_scenery_widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].right = w->width - 8; + w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].left = windowWidth - 25; + w->widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].left = windowWidth - 25; + w->widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].left = windowWidth - 25; + w->widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].left = windowWidth - 25; + w->widgets[WIDX_SCENERY_ROTATE_OBJECTS_BUTTON].right = windowWidth - 2; + w->widgets[WIDX_SCENERY_REPAINT_SCENERY_BUTTON].right = windowWidth - 2; + w->widgets[WIDX_SCENERY_EYEDROPPER_BUTTON].right = windowWidth - 2; + w->widgets[WIDX_SCENERY_BUILD_CLUSTER_BUTTON].right = windowWidth - 2; + + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].left = windowWidth - 19; + w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].left = windowWidth - 19; + w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].left = windowWidth - 19; + w->widgets[WIDX_SCENERY_PRIMARY_COLOUR_BUTTON].right = windowWidth - 8; + w->widgets[WIDX_SCENERY_SECONDARY_COLOUR_BUTTON].right = windowWidth - 8; + w->widgets[WIDX_SCENERY_TERTIARY_COLOUR_BUTTON].right = windowWidth - 8; +} + +static std::pair window_scenery_get_name_and_price(ScenerySelection selectedScenery) +{ + rct_string_id name = STR_UNKNOWN_OBJECT_TYPE; + money32 price = MONEY32_UNDEFINED; + if (selectedScenery.IsUndefined() && gSceneryPlaceCost != MONEY32_UNDEFINED) + { + price = gSceneryPlaceCost; + } + else + { + rct_scenery_entry* sceneryEntry = nullptr; + switch (selectedScenery.SceneryType) + { + case SCENERY_TYPE_SMALL: + sceneryEntry = get_small_scenery_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + price = sceneryEntry->small_scenery.price * 10; + break; + case SCENERY_TYPE_PATH_ITEM: + sceneryEntry = get_footpath_item_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + price = sceneryEntry->path_bit.price; + break; + case SCENERY_TYPE_WALL: + sceneryEntry = get_wall_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + price = sceneryEntry->wall.price; + break; + case SCENERY_TYPE_LARGE: + sceneryEntry = get_large_scenery_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + price = sceneryEntry->large_scenery.price * 10; + break; + case SCENERY_TYPE_BANNER: + sceneryEntry = get_banner_entry(selectedScenery.EntryIndex); + if (sceneryEntry != nullptr) + price = sceneryEntry->banner.price; + break; + } + if (sceneryEntry != nullptr) + { + name = sceneryEntry->name; + } + } + return { name, price }; } /** @@ -1109,17 +1155,15 @@ void window_scenery_paint(rct_window* w, rct_drawpixelinfo* dpi) { WindowDrawWidgets(w, dpi); - uint16_t tabIndex = gWindowSceneryActiveTabIndex; - uint16_t selectedWidgetId = tabIndex + 4; - uint32_t imageId = ((w->colours[1] << 19) | window_scenery_widgets[selectedWidgetId].image) + 1ul; + auto tabIndex = gWindowSceneryActiveTabIndex; + auto selectedWidgetId = static_cast(WIDX_SCENERY_TAB_1 + tabIndex); + uint32_t imageId = ((w->colours[1] << 19) | w->widgets[selectedWidgetId].image) + 1ul; gfx_draw_sprite( - dpi, imageId, - w->windowPos - + ScreenCoordsXY{ window_scenery_widgets[selectedWidgetId].left, window_scenery_widgets[selectedWidgetId].top }, + dpi, imageId, w->windowPos + ScreenCoordsXY{ w->widgets[selectedWidgetId].left, w->widgets[selectedWidgetId].top }, selectedWidgetId); - ScenerySelection selectedSceneryEntry = w->scenery.SelectedScenery; + auto selectedSceneryEntry = _selectedScenery; if (selectedSceneryEntry.IsUndefined()) { if (gWindowSceneryPaintEnabled & 1) // repaint coloured scenery tool is on @@ -1127,48 +1171,16 @@ void window_scenery_paint(rct_window* w, rct_drawpixelinfo* dpi) if (gWindowSceneryEyedropperEnabled) return; - selectedSceneryEntry = gWindowSceneryTabSelections[tabIndex]; - + selectedSceneryEntry = GetSelectedScenery(tabIndex); if (selectedSceneryEntry.IsUndefined()) return; } - uint32_t price = 0; - - rct_scenery_entry* sceneryEntry = nullptr; - switch (selectedSceneryEntry.SceneryType) - { - 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.SelectedScenery.IsUndefined() && gSceneryPlaceCost != MONEY32_UNDEFINED) - { - price = gSceneryPlaceCost; - } - - if (!(gParkFlags & PARK_FLAGS_NO_MONEY)) + auto [name, price] = window_scenery_get_name_and_price(selectedSceneryEntry); + if (price != MONEY32_UNDEFINED && !(gParkFlags & PARK_FLAGS_NO_MONEY)) { auto ft = Formatter(); - ft.Add(price); + ft.Add(price); // -14 DrawTextBasic( @@ -1177,7 +1189,7 @@ void window_scenery_paint(rct_window* w, rct_drawpixelinfo* dpi) } auto ft = Formatter(); - ft.Add(sceneryEntry != nullptr ? sceneryEntry->name : static_cast(STR_UNKNOWN_OBJECT_TYPE)); + ft.Add(name); DrawTextEllipsised(dpi, { w->windowPos.x + 3, w->windowPos.y + w->height - 13 }, w->width - 19, STR_BLACK_STRING, ft); } @@ -1189,21 +1201,18 @@ void window_scenery_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t s { gfx_clear(dpi, ColourMapA[w->colours[1]].mid_light); - uint8_t tabIndex = gWindowSceneryActiveTabIndex; + auto tabIndex = gWindowSceneryActiveTabIndex; ScreenCoordsXY topLeft{ 0, 0 }; - for (int32_t sceneryTabItemIndex = 0; sceneryTabItemIndex < SCENERY_ENTRIES_PER_TAB + 1; ++sceneryTabItemIndex) + const auto& tabInfo = _tabEntries[tabIndex]; + for (int32_t sceneryTabItemIndex = 0; sceneryTabItemIndex < tabInfo.Entries.size(); sceneryTabItemIndex++) { - ScenerySelection currentSceneryGlobal = window_scenery_tab_entries[tabIndex][sceneryTabItemIndex]; - if (currentSceneryGlobal.IsUndefined()) - break; - - ScenerySelection tabSelectedScenery = gWindowSceneryTabSelections[tabIndex]; - + const auto& currentSceneryGlobal = tabInfo.Entries[sceneryTabItemIndex]; + auto tabSelectedScenery = GetSelectedScenery(tabIndex); if (gWindowSceneryPaintEnabled == 1 || gWindowSceneryEyedropperEnabled) { - if (w->scenery.SelectedScenery == currentSceneryGlobal) + if (_selectedScenery == currentSceneryGlobal) { gfx_fill_rect_inset( dpi, { topLeft, topLeft + ScreenCoordsXY{ SCENERY_BUTTON_WIDTH - 1, SCENERY_BUTTON_HEIGHT - 1 } }, @@ -1218,7 +1227,7 @@ void window_scenery_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t s dpi, { topLeft, topLeft + ScreenCoordsXY{ SCENERY_BUTTON_WIDTH - 1, SCENERY_BUTTON_HEIGHT - 1 } }, w->colours[1], (INSET_RECT_FLAG_BORDER_INSET | INSET_RECT_FLAG_FILL_MID_LIGHT)); } - else if (w->scenery.SelectedScenery == currentSceneryGlobal) + else if (_selectedScenery == currentSceneryGlobal) { gfx_fill_rect_inset( dpi, { topLeft, topLeft + ScreenCoordsXY{ SCENERY_BUTTON_WIDTH - 1, SCENERY_BUTTON_HEIGHT - 1 } }, @@ -1349,20 +1358,20 @@ void window_scenery_scrollpaint(rct_window* w, rct_drawpixelinfo* dpi, int32_t s } } -static int32_t window_scenery_find_tab_with_scenery(const ScenerySelection& scenery) +static std::optional window_scenery_find_tab_with_scenery(const ScenerySelection& scenery) { - for (int32_t i = 0; i < SCENERY_WINDOW_TABS; i++) + for (const auto& tabInfo : _tabEntries) { - for (int32_t j = 0; j < SCENERY_ENTRIES_PER_TAB; j++) + for (size_t i = 0; i < tabInfo.Entries.size(); i++) { - ScenerySelection entry = window_scenery_tab_entries[i][j]; - if (entry.IsUndefined()) - break; + const auto& entry = tabInfo.Entries[i]; if (entry == scenery) + { return i; + } } } - return -1; + return {}; } bool window_scenery_set_selected_item(const ScenerySelection& scenery) @@ -1371,14 +1380,14 @@ bool window_scenery_set_selected_item(const ScenerySelection& scenery) rct_window* w = window_bring_to_front_by_class(WC_SCENERY); if (w != nullptr) { - int32_t tabIndex = window_scenery_find_tab_with_scenery(scenery); - if (tabIndex != -1) + auto tabIndex = window_scenery_find_tab_with_scenery(scenery); + if (tabIndex) { - gWindowSceneryActiveTabIndex = tabIndex; - gWindowSceneryTabSelections[tabIndex] = scenery; + gWindowSceneryActiveTabIndex = *tabIndex; + SetSelectedScenery(*tabIndex, scenery); OpenRCT2::Audio::Play(OpenRCT2::Audio::SoundId::Click1, 0, context_get_width() / 2); - w->scenery.hover_counter = -16; + _hoverCounter = -16; gSceneryPlaceCost = MONEY32_UNDEFINED; w->Invalidate(); result = true; @@ -1390,8 +1399,5 @@ bool window_scenery_set_selected_item(const ScenerySelection& scenery) // Used after removing objects, in order to avoid crashes. void window_scenery_reset_selected_scenery_items() { - for (size_t i = 0; i < SCENERY_WINDOW_TABS; i++) - { - gWindowSceneryTabSelections[i].SetUndefined(); - } + gWindowSceneryTabSelections.clear(); } diff --git a/src/openrct2-ui/windows/TopToolbar.cpp b/src/openrct2-ui/windows/TopToolbar.cpp index b177c14a8f..bcc1cb762f 100644 --- a/src/openrct2-ui/windows/TopToolbar.cpp +++ b/src/openrct2-ui/windows/TopToolbar.cpp @@ -1701,13 +1701,11 @@ static void window_top_toolbar_scenery_tool_down(const ScreenCoordsXY& windowPos return; } - ScenerySelection selectedTab = gWindowSceneryTabSelections[gWindowSceneryActiveTabIndex]; + auto selectedTab = gWindowSceneryTabSelections.size() > gWindowSceneryActiveTabIndex + ? gWindowSceneryTabSelections[gWindowSceneryActiveTabIndex] + : ScenerySelection{}; uint8_t sceneryType = selectedTab.SceneryType; uint16_t selectedScenery = selectedTab.EntryIndex; - - if (selectedTab.IsUndefined()) - return; - CoordsXY gridPos; switch (sceneryType) @@ -2611,8 +2609,13 @@ static void top_toolbar_tool_update_scenery(const ScreenCoordsXY& screenPos) if (gWindowSceneryEyedropperEnabled) return; - ScenerySelection selection = gWindowSceneryTabSelections[gWindowSceneryActiveTabIndex]; + if (gWindowSceneryActiveTabIndex >= gWindowSceneryTabSelections.size()) + { + scenery_remove_ghost_tool_placement(); + return; + } + const auto selection = gWindowSceneryTabSelections[gWindowSceneryActiveTabIndex]; if (selection.IsUndefined()) { scenery_remove_ghost_tool_placement(); diff --git a/src/openrct2-ui/windows/Window.h b/src/openrct2-ui/windows/Window.h index 1f14dd0289..f724560e09 100644 --- a/src/openrct2-ui/windows/Window.h +++ b/src/openrct2-ui/windows/Window.h @@ -23,8 +23,8 @@ struct Vehicle; enum class GuestListFilterType : int32_t; enum class ScatterToolDensity : uint8_t; -extern ScenerySelection gWindowSceneryTabSelections[]; -extern uint8_t gWindowSceneryActiveTabIndex; +extern std::vector gWindowSceneryTabSelections; +extern size_t gWindowSceneryActiveTabIndex; extern bool gWindowSceneryScatterEnabled; extern uint16_t gWindowSceneryScatterSize; extern ScatterToolDensity gWindowSceneryScatterDensity; diff --git a/src/openrct2/interface/Window.h b/src/openrct2/interface/Window.h index 0a0ceffa35..abee63b0ec 100644 --- a/src/openrct2/interface/Window.h +++ b/src/openrct2/interface/Window.h @@ -324,12 +324,6 @@ struct ride_variables int32_t var_486; }; -struct scenery_variables -{ - ScenerySelection SelectedScenery; - int16_t hover_counter; -}; - struct track_list_variables { bool track_list_being_updated; @@ -540,9 +534,9 @@ enum #define WC_RIDE_CONSTRUCTION__WIDX_ENTRANCE 29 #define WC_RIDE_CONSTRUCTION__WIDX_EXIT 30 #define WC_RIDE_CONSTRUCTION__WIDX_ROTATE 32 -#define WC_SCENERY__WIDX_SCENERY_TAB_1 4 -#define WC_SCENERY__WIDX_SCENERY_ROTATE_OBJECTS_BUTTON 25 -#define WC_SCENERY__WIDX_SCENERY_EYEDROPPER_BUTTON 30 +#define WC_SCENERY__WIDX_SCENERY_TAB_1 12 +#define WC_SCENERY__WIDX_SCENERY_ROTATE_OBJECTS_BUTTON 5 +#define WC_SCENERY__WIDX_SCENERY_EYEDROPPER_BUTTON 10 #define WC_PEEP__WIDX_PATROL 10 #define WC_PEEP__WIDX_ACTION_LBL 13 #define WC_PEEP__WIDX_PICKUP 14 diff --git a/src/openrct2/interface/Window_internal.h b/src/openrct2/interface/Window_internal.h index 2864c94bb7..89bfcac48f 100644 --- a/src/openrct2/interface/Window_internal.h +++ b/src/openrct2/interface/Window_internal.h @@ -60,7 +60,6 @@ struct rct_window news_variables news; map_variables map; ride_variables ride; - scenery_variables scenery; track_list_variables track_list; error_variables error; void* custom_info; diff --git a/src/openrct2/world/ScenerySelection.h b/src/openrct2/world/ScenerySelection.h index 7c3a7a83b2..716298b596 100644 --- a/src/openrct2/world/ScenerySelection.h +++ b/src/openrct2/world/ScenerySelection.h @@ -18,26 +18,16 @@ constexpr auto WINDOW_SCENERY_TAB_SELECTION_UNDEFINED = std::numeric_limits