From 04aeed8692dbb9d5148361ea525e2056640eb777 Mon Sep 17 00:00:00 2001 From: Josh Trzebiatowski Date: Wed, 22 Feb 2023 17:31:21 -0600 Subject: [PATCH] Add "All Scenery" tab to scenery window --- contributors.md | 1 + data/language/en-GB.txt | 1 + distribution/changelog.txt | 1 + resources/g2/icons/infinity.png | Bin 0 -> 1041 bytes resources/g2/sprites.json | 4 + src/openrct2-ui/windows/Scenery.cpp | 143 +++++++++++++++++++++----- src/openrct2/localisation/StringIds.h | 1 + src/openrct2/scripting/IconNames.hpp | 1 + src/openrct2/sprites.h | 1 + 9 files changed, 125 insertions(+), 28 deletions(-) create mode 100644 resources/g2/icons/infinity.png diff --git a/contributors.md b/contributors.md index d8b188be2f..b2d321f372 100644 --- a/contributors.md +++ b/contributors.md @@ -103,6 +103,7 @@ The following people are not part of the development team, but have been contrib * (8street) - Misc. * Umar Ahmed (umar-ahmed) - MacOS file watcher * Andrew Arnold (fidwell) - Added window support for more scenery groups. +* Josh Trzebiatowski (trzejos) - Ride and scenery filtering ## Bug fixes * (KirilAngelov) diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 7c61d5a50e..5161b923cb 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -3649,6 +3649,7 @@ STR_6543 :Contributors… STR_6544 :Loan cannot be negative! STR_6545 :Use RCT1 interest calculation STR_6546 :Use the interest calculation algorithm of RollerCoaster Tycoon 1, which used a fixed percentage of approximately 1.33%. +STR_6547 :All Scenery ############# # Scenarios # diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 9957f302e0..63c0600caf 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -5,6 +5,7 @@ - Feature: [#18732] [Plugin] API to get the guests thoughts. - Feature: [#18744] Cheat to allow using a regular path as a queue path. - Feature: [#19023] Add Canadian French translation. +- Feature: [#19341] Add "All Scenery" tab to scenery window. - Feature: [#19378] Add command to combine CSG1i.DAT and CSG1.DAT. - Feature: [objects#226] Port RCT1 Corkscrew Coaster train. - Feature: [objects#229] Port RCT1 go karts with helmets. diff --git a/resources/g2/icons/infinity.png b/resources/g2/icons/infinity.png new file mode 100644 index 0000000000000000000000000000000000000000..6e7e99ef8d5c8ea3c466281a1b9d5ee7741b7770 GIT binary patch literal 1041 zcmWktacJXo6nlLnQ&#Pdc6lSS_GS|1*R@N@lS{9y zrIIVjwe`2&_#rt95P)-MR~LuFBO@cDqoaX9U~Ft`e0+RjVgkdkU@$m2IT?;bA`BB1 z1YVX!RZZx+mdoWzrE;}ebKO1P?+*q{6nG9KaXOI*rPE|48_gHEk|kBDO1+`Cyh5jI z3p5tzrZq8a#7R@7$~v=?6B?y>tE&0Ue9yO!`fiK>g@z0dri@iItWm(*mC&F?pk5RW z6m)DNJo#xH3WRpsb(tOVBC!9g1epG55 z*E*=(r$WGzSS*SscrqNxx4l9bN2FM45VCaRV*C{hkg z$yz1W`o!vX^;V0uwuMAOPN&suR%4<$Hd^8tM_?LabWfst@d#2#WKhUrP>n~Ph!EP+ zL#YQpu(7f%!|6YMzC0ASmKNq$H-CL~YyQNyPXz;mQzu3QgzkPd`RwW|;zwuSxnbRY za{J5urgQc4d&R@^rCaa4IQN1Q;clMXy5Ol-uAD!7_~YNF_LEQiH22-xpJrEr*Jh~; zjCJO}{lDFR?q0pK$vmUrcYfivuXmZJ=il#q@z~l!-ycx&^w+zO|LJ;{rpK<|+?|>I sko@faUqAlan`6JZ_S<0t-49)a)0@w|{y}*6c$gBF7MB-pKY#JY|A2DAwEzGB literal 0 HcmV?d00001 diff --git a/resources/g2/sprites.json b/resources/g2/sprites.json index 7e8f3b79c2..53b5006c68 100644 --- a/resources/g2/sprites.json +++ b/resources/g2/sprites.json @@ -197,6 +197,10 @@ { "path": "icons/rct1_simulate_on_pressed.png" }, + { + "path": "icons/infinity.png", + "palette": "keep" + }, { "path": "tool/normal_selection_6x6.png", "x_offset": 1, diff --git a/src/openrct2-ui/windows/Scenery.cpp b/src/openrct2-ui/windows/Scenery.cpp index ab0307483f..b118884564 100644 --- a/src/openrct2-ui/windows/Scenery.cpp +++ b/src/openrct2-ui/windows/Scenery.cpp @@ -42,10 +42,13 @@ constexpr int32_t WINDOW_SCENERY_MIN_WIDTH = 634; constexpr int32_t WINDOW_SCENERY_MIN_HEIGHT = 195; constexpr int32_t SCENERY_BUTTON_WIDTH = 66; constexpr int32_t SCENERY_BUTTON_HEIGHT = 80; +constexpr int32_t InitTabPosX = 3; +constexpr int32_t InitTabPosY = 17; constexpr int32_t TabWidth = 31; constexpr int32_t TabHeight = 28; -constexpr int32_t MaxTabs = 257; // 255 selected tabs + misc + search -constexpr int32_t MaxTabsPerRow = 20; +constexpr int32_t ReservedTabCount = 2; +constexpr int32_t MaxTabs = 257; // 255 selected tabs + misc + all +constexpr int32_t MaxTabsPerRow = 19; constexpr uint8_t SceneryContentScrollIndex = 0; @@ -104,6 +107,13 @@ bool gWindowSceneryEyedropperEnabled; class SceneryWindow final : public Window { private: + enum SceneryTabType + { + SCENERY_TAB_TYPE_GROUP, + SCENERY_TAB_TYPE_MISC, + SCENERY_TAB_TYPE_ALL, + }; + struct SceneryItem { int32_t allRows; @@ -113,13 +123,24 @@ private: struct SceneryTabInfo { + SceneryTabType Type = SCENERY_TAB_TYPE_GROUP; ObjectEntryIndex SceneryGroupIndex = OBJECT_ENTRY_INDEX_NULL; - std::deque Entries; + std::deque Entries{}; u8string Filter = ""; bool IsMisc() const { - return SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL; + return Type == SCENERY_TAB_TYPE_MISC; + } + + bool IsAll() const + { + return Type == SCENERY_TAB_TYPE_ALL; + } + + bool IsSceneryGroup() const + { + return Type == SCENERY_TAB_TYPE_GROUP; } bool Contains(const ScenerySelection& entry) const @@ -537,6 +558,13 @@ public: return { fallback, ft }; } + if (tabInfo.IsAll()) + { + auto ft = Formatter(); + ft.Add(STR_ALL_SCENERY); + return { fallback, ft }; + } + const auto* sceneryEntry = tabInfo.GetSceneryGroupEntry(); if (sceneryEntry != nullptr) { @@ -557,10 +585,17 @@ public: if (tabIndex < _tabEntries.size()) { const auto& tabInfo = _tabEntries[tabIndex]; - const auto* sgEntry = tabInfo.GetSceneryGroupEntry(); - if (sgEntry != nullptr) + if (tabInfo.IsAll()) { - titleStringId = sgEntry->name; + titleStringId = STR_ALL_SCENERY; + } + else + { + const auto* sgEntry = tabInfo.GetSceneryGroupEntry(); + if (sgEntry != nullptr) + { + titleStringId = sgEntry->name; + } } } widgets[WIDX_SCENERY_TITLE].text = titleStringId; @@ -684,6 +719,15 @@ public: const auto lastTabIndex = GetMaxTabCountInARow() == MaxTabsPerRow ? MaxTabsPerRow - 1 : _tabEntries.size() - 1; const auto lastTabWidget = &widgets[WIDX_SCENERY_TAB_1 + lastTabIndex]; windowWidth = std::max(windowWidth, lastTabWidget->right + 3); + + if (_tabEntries.back().IsAll()) + { + auto allTabWidget = &widgets[WIDX_SCENERY_TAB_1 + _tabEntries.size() - 1]; + allTabWidget->left = windowWidth - TabWidth - 6; + allTabWidget->right = windowWidth - 7; + allTabWidget->top = InitTabPosY; + allTabWidget->bottom = InitTabPosY + TabHeight; + } } widgets[WIDX_SCENERY_BACKGROUND].right = windowWidth - 1; @@ -811,7 +855,7 @@ public: { _tabEntries.clear(); - for (ObjectEntryIndex scenerySetIndex = 0; scenerySetIndex < MaxTabs - 1; scenerySetIndex++) + for (ObjectEntryIndex scenerySetIndex = 0; scenerySetIndex < MaxTabs - ReservedTabCount; scenerySetIndex++) { const auto* sceneryGroupEntry = OpenRCT2::ObjectManager::GetObjectEntry(scenerySetIndex); if (sceneryGroupEntry != nullptr && SceneryGroupIsInvented(scenerySetIndex)) @@ -832,8 +876,12 @@ public: } } - // Add misc tab - _tabEntries.emplace_back(); + // Sort scenery group tabs before adding other tabs + SortTabs(); + + // Add misc and all tab + _tabEntries.emplace_back(SceneryWindow::SceneryTabInfo{ SCENERY_TAB_TYPE_MISC }); + _tabEntries.emplace_back(SceneryWindow::SceneryTabInfo{ SCENERY_TAB_TYPE_ALL }); // small scenery for (ObjectEntryIndex sceneryId = 0; sceneryId < MAX_SMALL_SCENERY_OBJECTS; sceneryId++) @@ -885,16 +933,15 @@ public: } } - // Remove misc tab if empty - if (_tabEntries.back().Entries.size() == 0) - { - _tabEntries.pop_back(); - } + // Remove empty tabs + _tabEntries.erase( + std::remove_if( + _tabEntries.begin(), _tabEntries.end(), [](const SceneryTabInfo& tabInfo) { return tabInfo.Entries.empty(); }), + _tabEntries.end()); // Set required width _requiredWidth = std::min(static_cast(_tabEntries.size()), MaxTabsPerRow) * TabWidth + 5; - SortTabs(); PrepareWidgets(); WindowInvalidateByClass(WindowClass::Scenery); } @@ -1020,13 +1067,30 @@ private: _tabSelections[tabIndex] = value; } - SceneryTabInfo* GetSceneryTabInfoForGroup(const ObjectEntryIndex sceneryGroupIndex) + SceneryTabInfo* GetSceneryTabInfoForMisc() { - if (sceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + if (_tabEntries.size() >= 2) { - return &_tabEntries[_tabEntries.size() - 1]; + if (_tabEntries[_tabEntries.size() - 2].IsMisc()) + return &_tabEntries[_tabEntries.size() - 2]; } + return nullptr; + } + + SceneryTabInfo* GetSceneryTabInfoForAll() + { + if (!_tabEntries.empty()) + { + if (_tabEntries.back().IsAll()) + return &_tabEntries.back(); + } + + return nullptr; + } + + SceneryTabInfo* GetSceneryTabInfoForGroup(const ObjectEntryIndex sceneryGroupIndex) + { for (auto& tabEntry : _tabEntries) { if (tabEntry.SceneryGroupIndex == sceneryGroupIndex) @@ -1072,12 +1136,19 @@ private: // If scenery is no tab, add it to misc if (!tabIndex.has_value()) { - auto* tabInfo = GetSceneryTabInfoForGroup(OBJECT_ENTRY_INDEX_NULL); + auto* tabInfo = GetSceneryTabInfoForMisc(); if (tabInfo != nullptr) { tabInfo->AddEntryToBack(selection); } } + + // Add all scenery to all tab + auto tabInfo = GetSceneryTabInfoForAll(); + if (tabInfo != nullptr) + { + tabInfo->AddEntryToBack(selection); + } } } @@ -1177,19 +1248,35 @@ private: // Add tabs _actualMinHeight = WINDOW_SCENERY_MIN_HEIGHT; - int32_t xInit = 3; + int32_t xInit = InitTabPosX; int32_t tabsInThisRow = 0; - ScreenCoordsXY pos = { xInit, 17 }; + ScreenCoordsXY pos = { xInit, InitTabPosY }; for (const auto& tabInfo : _tabEntries) { auto widget = MakeTab(pos, STR_STRING_DEFINED_TOOLTIP); pos.x += TabWidth; - if (tabInfo.SceneryGroupIndex == OBJECT_ENTRY_INDEX_NULL) + if (tabInfo.IsMisc()) { widget.image = ImageId(SPR_TAB_QUESTION, FilterPaletteID::PaletteNull); } + else if (tabInfo.IsAll()) + { + widget.image = ImageId(SPR_TAB, FilterPaletteID::PaletteNull); + } + else if (tabInfo.IsSceneryGroup()) + { + // Default tab image + widget.image = ImageId(SPR_TAB_QUESTION, FilterPaletteID::PaletteNull); + + // Scenery Group image + auto scgEntry = tabInfo.GetSceneryGroupEntry(); + if (scgEntry != nullptr) + { + widget.image = ImageId(scgEntry->image, colours[1]); + } + } _widgets.push_back(widget); @@ -1362,12 +1449,12 @@ private: for (size_t tabIndex = 0; tabIndex < _tabEntries.size(); tabIndex++) { auto widgetIndex = static_cast(WIDX_SCENERY_TAB_1 + tabIndex); - auto scgEntry = _tabEntries[tabIndex].GetSceneryGroupEntry(); - if (scgEntry != nullptr) + auto widgetCoordsXY = ScreenCoordsXY(widgets[widgetIndex].left, widgets[widgetIndex].top); + + if (_tabEntries[tabIndex].IsAll()) { - auto imageOffset = tabIndex == _activeTabIndex ? 1 : 0; - auto imageId = ImageId(scgEntry->image + imageOffset, colours[1]); - GfxDrawSprite(&dpi, imageId, offset + ScreenCoordsXY{ widgets[widgetIndex].left, widgets[widgetIndex].top }); + auto imageId = ImageId(SPR_G2_INFINITY, FilterPaletteID::PaletteNull); + GfxDrawSprite(&dpi, imageId, offset + widgetCoordsXY + ScreenCoordsXY(2, 6)); } } } diff --git a/src/openrct2/localisation/StringIds.h b/src/openrct2/localisation/StringIds.h index 0d15d201a4..eb04eb6df9 100644 --- a/src/openrct2/localisation/StringIds.h +++ b/src/openrct2/localisation/StringIds.h @@ -3943,6 +3943,7 @@ enum : uint16_t STR_RCT1_INTEREST = 6545, STR_RCT1_INTEREST_TIP = 6546, + STR_ALL_SCENERY = 6547, // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working /* MAX_STR_COUNT = 32768 */ // MAX_STR_COUNT - upper limit for number of strings, not the current count strings diff --git a/src/openrct2/scripting/IconNames.hpp b/src/openrct2/scripting/IconNames.hpp index b1d153479a..d26040e5d3 100644 --- a/src/openrct2/scripting/IconNames.hpp +++ b/src/openrct2/scripting/IconNames.hpp @@ -84,6 +84,7 @@ namespace OpenRCT2::Scripting { "rct1_simulate_off_pressed", SPR_G2_RCT1_SIMULATE_BUTTON_1 }, { "rct1_simulate_on", SPR_G2_RCT1_SIMULATE_BUTTON_2 }, { "rct1_simulate_on_pressed", SPR_G2_RCT1_SIMULATE_BUTTON_3 }, + { "infinity", SPR_G2_INFINITY }, { "normal_selection_6x6", SPR_G2_LAND_TOOL_SIZE_6 }, { "mountain_tool_even", SPR_G2_MOUNTAIN_TOOL_EVEN }, { "mountain_tool_odd", SPR_G2_MOUNTAIN_TOOL_ODD }, diff --git a/src/openrct2/sprites.h b/src/openrct2/sprites.h index 46cccffd75..48c586b929 100644 --- a/src/openrct2/sprites.h +++ b/src/openrct2/sprites.h @@ -945,6 +945,7 @@ enum SPR_G2_RCT1_SIMULATE_BUTTON_1, SPR_G2_RCT1_SIMULATE_BUTTON_2, SPR_G2_RCT1_SIMULATE_BUTTON_3, + SPR_G2_INFINITY, SPR_G2_LAND_TOOL_SIZE_6, SPR_G2_MOUNTAIN_TOOL_EVEN, SPR_G2_MOUNTAIN_TOOL_ODD,