/***************************************************************************** * Copyright (c) 2014-2024 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. *****************************************************************************/ #include "../interface/Theme.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace OpenRCT2::Ui::Windows { // clang-format off enum WindowGameBottomToolbarWidgetIdx { WIDX_LEFT_OUTSET, WIDX_LEFT_INSET, WIDX_MONEY, WIDX_GUESTS, WIDX_PARK_RATING, WIDX_MIDDLE_OUTSET, WIDX_MIDDLE_INSET, WIDX_NEWS_SUBJECT, WIDX_NEWS_LOCATE, WIDX_RIGHT_OUTSET, WIDX_RIGHT_INSET, WIDX_DATE }; static Widget window_game_bottom_toolbar_widgets[] = { MakeWidget({ 0, 0}, {142, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Left outset panel MakeWidget({ 2, 2}, {138, 30}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Left inset panel MakeWidget({ 2, 1}, {138, 12}, WindowWidgetType::FlatBtn, WindowColour::Primary , 0xFFFFFFFF, STR_PROFIT_PER_WEEK_AND_PARK_VALUE_TIP), // Money window MakeWidget({ 2, 11}, {138, 12}, WindowWidgetType::FlatBtn, WindowColour::Primary ), // Guests window MakeWidget({ 2, 21}, {138, 11}, WindowWidgetType::FlatBtn, WindowColour::Primary , 0xFFFFFFFF, STR_PARK_RATING_TIP ), // Park rating window MakeWidget({142, 0}, {356, 34}, WindowWidgetType::ImgBtn, WindowColour::Tertiary ), // Middle outset panel MakeWidget({144, 2}, {352, 30}, WindowWidgetType::FlatBtn, WindowColour::Tertiary ), // Middle inset panel MakeWidget({147, 5}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Tertiary, 0xFFFFFFFF, STR_SHOW_SUBJECT_TIP ), // Associated news item window MakeWidget({469, 5}, { 24, 24}, WindowWidgetType::FlatBtn, WindowColour::Tertiary, ImageId(SPR_LOCATE), STR_LOCATE_SUBJECT_TIP ), // Scroll to news item target MakeWidget({498, 0}, {142, 34}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Right outset panel MakeWidget({500, 2}, {138, 30}, WindowWidgetType::ImgBtn, WindowColour::Primary ), // Right inset panel MakeWidget({500, 2}, {138, 12}, WindowWidgetType::FlatBtn, WindowColour::Primary ), // Date kWidgetsEnd, }; // clang-format on uint8_t gToolbarDirtyFlags; class GameBottomToolbar final : public Window { private: void DrawLeftPanel(DrawPixelInfo& dpi) { const auto topLeft = windowPos + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].left + 1, window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].top + 1 }; const auto bottomRight = windowPos + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].right - 1, window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET].bottom - 1 }; // Draw green inset rectangle on panel GfxFillRectInset(dpi, { topLeft, bottomRight }, colours[1], INSET_RECT_F_30); // Figure out how much line height we have to work with. uint32_t line_height = FontGetLineHeight(FontStyle::Medium); auto& gameState = GetGameState(); // Draw money if (!(gameState.Park.Flags & PARK_FLAGS_NO_MONEY)) { Widget widget = window_game_bottom_toolbar_widgets[WIDX_MONEY]; auto screenCoords = ScreenCoordsXY{ windowPos.x + widget.midX(), windowPos.y + widget.midY() - (line_height == 10 ? 5 : 6) }; colour_t colour = (gHoverWidget.window_classification == WindowClass::BottomToolbar && gHoverWidget.widget_index == WIDX_MONEY ? COLOUR_WHITE : NOT_TRANSLUCENT(colours[0])); StringId stringId = gameState.Cash < 0 ? STR_BOTTOM_TOOLBAR_CASH_NEGATIVE : STR_BOTTOM_TOOLBAR_CASH; auto ft = Formatter(); ft.Add(gameState.Cash); DrawTextBasic(dpi, screenCoords, stringId, ft, { colour, TextAlignment::CENTRE }); } static constexpr StringId _guestCountFormats[] = { STR_BOTTOM_TOOLBAR_NUM_GUESTS_STABLE, STR_BOTTOM_TOOLBAR_NUM_GUESTS_DECREASE, STR_BOTTOM_TOOLBAR_NUM_GUESTS_INCREASE, }; static constexpr StringId _guestCountFormatsSingular[] = { STR_BOTTOM_TOOLBAR_NUM_GUESTS_STABLE_SINGULAR, STR_BOTTOM_TOOLBAR_NUM_GUESTS_DECREASE_SINGULAR, STR_BOTTOM_TOOLBAR_NUM_GUESTS_INCREASE_SINGULAR, }; // Draw guests { Widget widget = window_game_bottom_toolbar_widgets[WIDX_GUESTS]; auto screenCoords = ScreenCoordsXY{ windowPos.x + widget.midX(), windowPos.y + widget.midY() - 6 }; StringId stringId = gameState.NumGuestsInPark == 1 ? _guestCountFormatsSingular[gameState.GuestChangeModifier] : _guestCountFormats[gameState.GuestChangeModifier]; colour_t colour = (gHoverWidget.window_classification == WindowClass::BottomToolbar && gHoverWidget.widget_index == WIDX_GUESTS ? COLOUR_WHITE : NOT_TRANSLUCENT(colours[0])); auto ft = Formatter(); ft.Add(gameState.NumGuestsInPark); DrawTextBasic(dpi, screenCoords, stringId, ft, { colour, TextAlignment::CENTRE }); } // Draw park rating { Widget widget = window_game_bottom_toolbar_widgets[WIDX_PARK_RATING]; auto screenCoords = windowPos + ScreenCoordsXY{ widget.left + 11, widget.midY() - 5 }; DrawParkRating(dpi, colours[3], screenCoords, std::max(10, ((gameState.Park.Rating / 4) * 263) / 256)); } } void DrawParkRating(DrawPixelInfo& dpi, int32_t colour, const ScreenCoordsXY& coords, uint8_t factor) { int16_t bar_width = (factor * 114) / 255; GfxFillRectInset( dpi, { coords + ScreenCoordsXY{ 1, 1 }, coords + ScreenCoordsXY{ 114, 9 } }, colours[1], INSET_RECT_F_30); if (!(colour & kBarBlink) || GameIsPaused() || (gCurrentRealTimeTicks & 8)) { if (bar_width > 2) { GfxFillRectInset( dpi, { coords + ScreenCoordsXY{ 2, 2 }, coords + ScreenCoordsXY{ bar_width - 1, 8 } }, colour, 0); } } // Draw thumbs on the sides GfxDrawSprite(dpi, ImageId(SPR_RATING_LOW), coords - ScreenCoordsXY{ 14, 0 }); GfxDrawSprite(dpi, ImageId(SPR_RATING_HIGH), coords + ScreenCoordsXY{ 114, 0 }); } void DrawRightPanel(DrawPixelInfo& dpi) { const auto topLeft = windowPos + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + 1, window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].top + 1 }; const auto bottomRight = windowPos + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right - 1, window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].bottom - 1 }; // Draw green inset rectangle on panel GfxFillRectInset(dpi, { topLeft, bottomRight }, colours[1], INSET_RECT_F_30); auto screenCoords = ScreenCoordsXY{ (window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right) / 2 + windowPos.x, window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].top + windowPos.y + 2 }; // Date auto& date = GetDate(); int32_t year = date.GetYear() + 1; int32_t month = date.GetMonth(); int32_t day = date.GetDay(); colour_t colour = (gHoverWidget.window_classification == WindowClass::BottomToolbar && gHoverWidget.widget_index == WIDX_DATE ? COLOUR_WHITE : NOT_TRANSLUCENT(colours[0])); StringId stringId = DateFormatStringFormatIds[gConfigGeneral.DateFormat]; auto ft = Formatter(); ft.Add(DateDayNames[day]); ft.Add(month); ft.Add(year); DrawTextBasic(dpi, screenCoords, stringId, ft, { colour, TextAlignment::CENTRE }); // Figure out how much line height we have to work with. uint32_t line_height = FontGetLineHeight(FontStyle::Medium); // Temperature screenCoords = { windowPos.x + window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + 15, static_cast(screenCoords.y + line_height + 1) }; int32_t temperature = OpenRCT2::GetGameState().ClimateCurrent.Temperature; StringId format = STR_CELSIUS_VALUE; if (gConfigGeneral.TemperatureFormat == TemperatureUnit::Fahrenheit) { temperature = ClimateCelsiusToFahrenheit(temperature); format = STR_FAHRENHEIT_VALUE; } ft = Formatter(); ft.Add(temperature); DrawTextBasic(dpi, screenCoords + ScreenCoordsXY{ 0, 6 }, format, ft); screenCoords.x += 30; // Current weather auto currentWeatherSpriteId = ClimateGetWeatherSpriteId(OpenRCT2::GetGameState().ClimateCurrent); GfxDrawSprite(dpi, ImageId(currentWeatherSpriteId), screenCoords); // Next weather auto nextWeatherSpriteId = ClimateGetWeatherSpriteId(GetGameState().ClimateNext); if (currentWeatherSpriteId != nextWeatherSpriteId) { if (GetGameState().ClimateUpdateTimer < 960) { GfxDrawSprite(dpi, ImageId(SPR_NEXT_WEATHER), screenCoords + ScreenCoordsXY{ 27, 5 }); GfxDrawSprite(dpi, ImageId(nextWeatherSpriteId), screenCoords + ScreenCoordsXY{ 40, 0 }); } } } void DrawNewsItem(DrawPixelInfo& dpi) { auto* middleOutsetWidget = &window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET]; auto* newsItem = News::GetItem(0); // Current news item GfxFillRectInset( dpi, { windowPos + ScreenCoordsXY{ middleOutsetWidget->left + 1, middleOutsetWidget->top + 1 }, windowPos + ScreenCoordsXY{ middleOutsetWidget->right - 1, middleOutsetWidget->bottom - 1 } }, colours[2], INSET_RECT_F_30); // Text auto screenCoords = windowPos + ScreenCoordsXY{ middleOutsetWidget->midX(), middleOutsetWidget->top + 11 }; int32_t itemWidth = middleOutsetWidget->width() - 62; DrawNewsTicker( dpi, screenCoords, itemWidth, COLOUR_BRIGHT_GREEN, STR_BOTTOM_TOOLBAR_NEWS_TEXT, newsItem->Text, newsItem->Ticks); screenCoords = windowPos + ScreenCoordsXY{ window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].left, window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].top }; switch (newsItem->Type) { case News::ItemType::Ride: GfxDrawSprite(dpi, ImageId(SPR_RIDE), screenCoords); break; case News::ItemType::PeepOnRide: case News::ItemType::Peep: { if (newsItem->HasButton()) break; DrawPixelInfo cliped_dpi; if (!ClipDrawPixelInfo(cliped_dpi, dpi, screenCoords + ScreenCoordsXY{ 1, 1 }, 22, 22)) { break; } auto peep = TryGetEntity(EntityId::FromUnderlying(newsItem->Assoc)); if (peep == nullptr) return; auto clipCoords = ScreenCoordsXY{ 10, 19 }; auto* staff = peep->As(); if (staff != nullptr && staff->AssignedStaffType == StaffType::Entertainer) { clipCoords.y += 3; } uint32_t image_id_base = GetPeepAnimation(peep->SpriteType).base_image; image_id_base += frame_no & 0xFFFFFFFC; image_id_base++; auto image_id = ImageId(image_id_base, peep->TshirtColour, peep->TrousersColour); GfxDrawSprite(cliped_dpi, image_id, clipCoords); auto* guest = peep->As(); if (guest != nullptr) { if (image_id_base >= 0x2A1D && image_id_base < 0x2A3D) { GfxDrawSprite(cliped_dpi, ImageId(image_id_base + 32, guest->BalloonColour), clipCoords); } else if (image_id_base >= 0x2BBD && image_id_base < 0x2BDD) { GfxDrawSprite(cliped_dpi, ImageId(image_id_base + 32, guest->UmbrellaColour), clipCoords); } else if (image_id_base >= 0x29DD && image_id_base < 0x29FD) { GfxDrawSprite(cliped_dpi, ImageId(image_id_base + 32, guest->HatColour), clipCoords); } } break; } case News::ItemType::Money: case News::ItemType::Campaign: GfxDrawSprite(dpi, ImageId(SPR_FINANCE), screenCoords); break; case News::ItemType::Research: GfxDrawSprite(dpi, ImageId(newsItem->Assoc < 0x10000 ? SPR_NEW_SCENERY : SPR_NEW_RIDE), screenCoords); break; case News::ItemType::Peeps: GfxDrawSprite(dpi, ImageId(SPR_GUESTS), screenCoords); break; case News::ItemType::Award: GfxDrawSprite(dpi, ImageId(SPR_AWARD), screenCoords); break; case News::ItemType::Graph: GfxDrawSprite(dpi, ImageId(SPR_GRAPH), screenCoords); break; case News::ItemType::Null: case News::ItemType::Blank: case News::ItemType::Count: break; } } void DrawMiddlePanel(DrawPixelInfo& dpi) { Widget* middleOutsetWidget = &window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET]; GfxFillRectInset( dpi, { windowPos + ScreenCoordsXY{ middleOutsetWidget->left + 1, middleOutsetWidget->top + 1 }, windowPos + ScreenCoordsXY{ middleOutsetWidget->right - 1, middleOutsetWidget->bottom - 1 } }, colours[1], INSET_RECT_F_30); // Figure out how much line height we have to work with. uint32_t line_height = FontGetLineHeight(FontStyle::Medium); ScreenCoordsXY middleWidgetCoords( windowPos.x + middleOutsetWidget->midX(), windowPos.y + middleOutsetWidget->top + line_height + 1); int32_t panelWidth = middleOutsetWidget->width() - 62; // Check if there is a map tooltip to draw StringId stringId; auto ft = GetMapTooltip(); std::memcpy(&stringId, ft.Data(), sizeof(StringId)); if (stringId == STR_NONE) { DrawTextWrapped( dpi, middleWidgetCoords, panelWidth, STR_TITLE_SEQUENCE_OPENRCT2, ft, { colours[0], TextAlignment::CENTRE }); } else { // Show tooltip in bottom toolbar DrawTextWrapped(dpi, middleWidgetCoords, panelWidth, STR_STRINGID, ft, { colours[0], TextAlignment::CENTRE }); } } void InvalidateDirtyWidgets() { if (gToolbarDirtyFlags & BTM_TB_DIRTY_FLAG_MONEY) { gToolbarDirtyFlags &= ~BTM_TB_DIRTY_FLAG_MONEY; InvalidateWidget(WIDX_LEFT_INSET); } if (gToolbarDirtyFlags & BTM_TB_DIRTY_FLAG_DATE) { gToolbarDirtyFlags &= ~BTM_TB_DIRTY_FLAG_DATE; InvalidateWidget(WIDX_RIGHT_INSET); } if (gToolbarDirtyFlags & BTM_TB_DIRTY_FLAG_PEEP_COUNT) { gToolbarDirtyFlags &= ~BTM_TB_DIRTY_FLAG_PEEP_COUNT; InvalidateWidget(WIDX_LEFT_INSET); } if (gToolbarDirtyFlags & BTM_TB_DIRTY_FLAG_CLIMATE) { gToolbarDirtyFlags &= ~BTM_TB_DIRTY_FLAG_CLIMATE; InvalidateWidget(WIDX_RIGHT_INSET); } if (gToolbarDirtyFlags & BTM_TB_DIRTY_FLAG_PARK_RATING) { gToolbarDirtyFlags &= ~BTM_TB_DIRTY_FLAG_PARK_RATING; InvalidateWidget(WIDX_LEFT_INSET); } } public: GameBottomToolbar() { widgets = window_game_bottom_toolbar_widgets; frame_no = 0; InitScrollWidgets(); // Reset the middle widget to not show by default. // If it is required to be shown news_update will reshow it. window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty; } void OnMouseUp(WidgetIndex widgetIndex) override { News::Item* newsItem; switch (widgetIndex) { case WIDX_LEFT_OUTSET: case WIDX_MONEY: if (!(GetGameState().Park.Flags & PARK_FLAGS_NO_MONEY)) ContextOpenWindow(WindowClass::Finances); break; case WIDX_GUESTS: ContextOpenWindowView(WV_PARK_GUESTS); break; case WIDX_PARK_RATING: ContextOpenWindowView(WV_PARK_RATING); break; case WIDX_MIDDLE_INSET: if (News::IsQueueEmpty()) { ContextOpenWindow(WindowClass::RecentNews); } else { News::CloseCurrentItem(); } break; case WIDX_NEWS_SUBJECT: newsItem = News::GetItem(0); News::OpenSubject(newsItem->Type, newsItem->Assoc); break; case WIDX_NEWS_LOCATE: if (News::IsQueueEmpty()) break; { newsItem = News::GetItem(0); auto subjectLoc = News::GetSubjectLocation(newsItem->Type, newsItem->Assoc); if (!subjectLoc.has_value()) break; WindowBase* mainWindow = WindowGetMain(); if (mainWindow != nullptr) WindowScrollToLocation(*mainWindow, subjectLoc.value()); } break; case WIDX_RIGHT_OUTSET: case WIDX_DATE: ContextOpenWindow(WindowClass::RecentNews); break; } } OpenRCT2String OnTooltip(WidgetIndex widgetIndex, StringId fallback) override { const auto& gameState = GetGameState(); auto ft = Formatter(); switch (widgetIndex) { case WIDX_MONEY: ft.Add(gameState.CurrentProfit); ft.Add(gameState.Park.Value); break; case WIDX_PARK_RATING: ft.Add(gameState.Park.Rating); break; } return { fallback, ft }; } void OnPrepareDraw() override { // Figure out how much line height we have to work with. uint32_t line_height = FontGetLineHeight(FontStyle::Medium); // Reset dimensions as appropriate -- in case we're switching languages. height = line_height * 2 + 12; windowPos.y = ContextGetHeight() - height; // Change height of widgets in accordance with line height. widgets[WIDX_LEFT_OUTSET].bottom = widgets[WIDX_MIDDLE_OUTSET].bottom = widgets[WIDX_RIGHT_OUTSET].bottom = line_height * 3 + 3; widgets[WIDX_LEFT_INSET].bottom = widgets[WIDX_MIDDLE_INSET].bottom = widgets[WIDX_RIGHT_INSET].bottom = line_height * 3 + 1; // Reposition left widgets in accordance with line height... depending on whether there is money in play. if (GetGameState().Park.Flags & PARK_FLAGS_NO_MONEY) { widgets[WIDX_MONEY].type = WindowWidgetType::Empty; widgets[WIDX_GUESTS].top = 1; widgets[WIDX_GUESTS].bottom = line_height + 7; widgets[WIDX_PARK_RATING].top = line_height + 8; widgets[WIDX_PARK_RATING].bottom = height - 1; } else { widgets[WIDX_MONEY].type = WindowWidgetType::FlatBtn; widgets[WIDX_MONEY].bottom = widgets[WIDX_MONEY].top + line_height; widgets[WIDX_GUESTS].top = widgets[WIDX_MONEY].bottom + 1; widgets[WIDX_GUESTS].bottom = widgets[WIDX_GUESTS].top + line_height; widgets[WIDX_PARK_RATING].top = widgets[WIDX_GUESTS].bottom - 1; widgets[WIDX_PARK_RATING].bottom = height - 1; } // Reposition right widgets in accordance with line height, too. widgets[WIDX_DATE].bottom = line_height + 1; // Anchor the middle and right panel to the right int32_t x = ContextGetWidth(); width = x; x--; window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right = x; x -= 2; window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].right = x; x -= 137; window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].left = x; x -= 2; window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left = x; x--; window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].right = x; x -= 2; window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].right = x; x -= 3; window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].right = x; x -= 23; window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].left = x; window_game_bottom_toolbar_widgets[WIDX_DATE].left = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].left + 2; window_game_bottom_toolbar_widgets[WIDX_DATE].right = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET].right - 2; window_game_bottom_toolbar_widgets[WIDX_LEFT_INSET].type = WindowWidgetType::Empty; window_game_bottom_toolbar_widgets[WIDX_RIGHT_INSET].type = WindowWidgetType::Empty; if (News::IsQueueEmpty()) { if (!(ThemeGetFlags() & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR)) { window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::Empty; window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::Empty; window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty; window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty; } else { window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn; window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn; window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty; window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::Empty; window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].colour = 0; window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].colour = 0; } } else { News::Item* newsItem = News::GetItem(0); window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].type = WindowWidgetType::ImgBtn; window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].type = WindowWidgetType::FlatBtn; window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::FlatBtn; window_game_bottom_toolbar_widgets[WIDX_NEWS_LOCATE].type = WindowWidgetType::FlatBtn; window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET].colour = 2; window_game_bottom_toolbar_widgets[WIDX_MIDDLE_INSET].colour = 2; disabled_widgets &= ~(1uLL << WIDX_NEWS_SUBJECT); disabled_widgets &= ~(1uLL << WIDX_NEWS_LOCATE); // Find out if the news item is no longer valid auto subjectLoc = News::GetSubjectLocation(newsItem->Type, newsItem->Assoc); if (!subjectLoc.has_value()) disabled_widgets |= (1uLL << WIDX_NEWS_LOCATE); if (!(newsItem->TypeHasSubject())) { disabled_widgets |= (1uLL << WIDX_NEWS_SUBJECT); window_game_bottom_toolbar_widgets[WIDX_NEWS_SUBJECT].type = WindowWidgetType::Empty; } if (newsItem->HasButton()) { disabled_widgets |= (1uLL << WIDX_NEWS_SUBJECT); disabled_widgets |= (1uLL << WIDX_NEWS_LOCATE); } } } void OnDraw(DrawPixelInfo& dpi) override { auto leftWidget = window_game_bottom_toolbar_widgets[WIDX_LEFT_OUTSET]; auto rightWidget = window_game_bottom_toolbar_widgets[WIDX_RIGHT_OUTSET]; auto middleWidget = window_game_bottom_toolbar_widgets[WIDX_MIDDLE_OUTSET]; // Draw panel grey backgrounds auto leftTop = windowPos + ScreenCoordsXY{ leftWidget.left, leftWidget.top }; auto rightBottom = windowPos + ScreenCoordsXY{ leftWidget.right, leftWidget.bottom }; GfxFilterRect(dpi, { leftTop, rightBottom }, FilterPaletteID::Palette51); leftTop = windowPos + ScreenCoordsXY{ rightWidget.left, rightWidget.top }; rightBottom = windowPos + ScreenCoordsXY{ rightWidget.right, rightWidget.bottom }; GfxFilterRect(dpi, { leftTop, rightBottom }, FilterPaletteID::Palette51); if (ThemeGetFlags() & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR) { // Draw grey background leftTop = windowPos + ScreenCoordsXY{ middleWidget.left, middleWidget.top }; rightBottom = windowPos + ScreenCoordsXY{ middleWidget.right, middleWidget.bottom }; GfxFilterRect(dpi, { leftTop, rightBottom }, FilterPaletteID::Palette51); } DrawWidgets(dpi); DrawLeftPanel(dpi); DrawRightPanel(dpi); if (!News::IsQueueEmpty()) { DrawNewsItem(dpi); } else if (ThemeGetFlags() & UITHEME_FLAG_USE_FULL_BOTTOM_TOOLBAR) { DrawMiddlePanel(dpi); } } void OnUpdate() override { frame_no++; if (frame_no >= 24) frame_no = 0; InvalidateDirtyWidgets(); } CursorID OnCursor(WidgetIndex widgetIndex, const ScreenCoordsXY& screenCoords, CursorID cursorId) override { switch (widgetIndex) { case WIDX_MONEY: case WIDX_GUESTS: case WIDX_PARK_RATING: case WIDX_DATE: gTooltipCloseTimeout = gCurrentRealTimeTicks + 2000; break; } return cursorId; } void OnPeriodicUpdate() override { InvalidateDirtyWidgets(); } }; /** * Creates the main game bottom toolbar window. */ WindowBase* GameBottomToolbarOpen() { int32_t screenWidth = ContextGetWidth(); int32_t screenHeight = ContextGetHeight(); // Figure out how much line height we have to work with. uint32_t line_height = FontGetLineHeight(FontStyle::Medium); uint32_t toolbar_height = line_height * 2 + 12; GameBottomToolbar* window = WindowCreate( WindowClass::BottomToolbar, ScreenCoordsXY(0, screenHeight - toolbar_height), screenWidth, toolbar_height, WF_STICK_TO_FRONT | WF_TRANSPARENT | WF_NO_BACKGROUND); return window; } void WindowGameBottomToolbarInvalidateNewsItem() { if (gScreenFlags == SCREEN_FLAGS_PLAYING) { WidgetInvalidateByClass(WindowClass::BottomToolbar, WIDX_MIDDLE_OUTSET); } } } // namespace OpenRCT2::Ui::Windows