diff --git a/src/openrct2-ui/windows/Player.cpp b/src/openrct2-ui/windows/Player.cpp index 07a6092f48..c6d91db540 100644 --- a/src/openrct2-ui/windows/Player.cpp +++ b/src/openrct2-ui/windows/Player.cpp @@ -8,18 +8,13 @@ *****************************************************************************/ #include -#include #include #include -#include #include #include #include -#include #include -#include #include -#include #include #include #include @@ -79,550 +74,599 @@ static Widget *window_player_page_widgets[] = { #pragma endregion +// clang-format on + +class PlayerWindow final : public Window +{ +public: + void Init(const uint8_t id) + { + number = id; + InitScrollWidgets(); + SetPage(WINDOW_PLAYER_PAGE_OVERVIEW); + } + #pragma region Events -static void WindowPlayerOverviewClose(WindowBase *w); -static void WindowPlayerOverviewMouseUp(WindowBase *w, WidgetIndex widgetIndex); -static void WindowPlayerOverviewResize(WindowBase *w); -static void WindowPlayerOverviewMouseDown(WindowBase *w, WidgetIndex widgetIndex, Widget *widget); -static void WindowPlayerOverviewDropdown(WindowBase *w, WidgetIndex widgetIndex, int32_t dropdownIndex); -static void WindowPlayerOverviewUpdate(WindowBase* w); -static void WindowPlayerOverviewInvalidate(WindowBase *w); -static void WindowPlayerOverviewPaint(WindowBase *w, DrawPixelInfo *dpi); + void OnOpen() override + { + page = 0; + frame_no = 0; + list_information_type = 0; + picked_peep_frame = 0; + min_width = 210; + min_height = 134; + max_width = 500; + max_height = 450; + no_list_items = 0; + selected_list_item = -1; -static WindowEventList window_player_overview_events([](auto& events) -{ - events.close = &WindowPlayerOverviewClose; - events.mouse_up = &WindowPlayerOverviewMouseUp; - events.resize = &WindowPlayerOverviewResize; - events.mouse_down = &WindowPlayerOverviewMouseDown; - events.dropdown = &WindowPlayerOverviewDropdown; - events.update = &WindowPlayerOverviewUpdate; - events.invalidate = &WindowPlayerOverviewInvalidate; - events.paint = &WindowPlayerOverviewPaint; -}); + Invalidate(); -static void WindowPlayerStatisticsClose(WindowBase *w); -static void WindowPlayerStatisticsMouseUp(WindowBase *w, WidgetIndex widgetIndex); -static void WindowPlayerStatisticsResize(WindowBase *w); -static void WindowPlayerStatisticsUpdate(WindowBase* w); -static void WindowPlayerStatisticsInvalidate(WindowBase *w); -static void WindowPlayerStatisticsPaint(WindowBase *w, DrawPixelInfo *dpi); + widgets = window_player_page_widgets[WINDOW_PLAYER_PAGE_OVERVIEW]; + hold_down_widgets = 0; + pressed_widgets = 0; + } -static WindowEventList window_player_statistics_events([](auto& events) -{ - events.close = &WindowPlayerStatisticsClose; - events.mouse_up = &WindowPlayerStatisticsMouseUp; - events.resize = &WindowPlayerStatisticsResize; - events.update = &WindowPlayerStatisticsUpdate; - events.invalidate = &WindowPlayerStatisticsInvalidate; - events.paint = &WindowPlayerStatisticsPaint; -}); + void OnClose() override + { + switch (page) + { + case WINDOW_PLAYER_PAGE_STATISTICS: + OnCloseStatistics(); + break; + } + } -static WindowEventList *window_player_page_events[] = { - &window_player_overview_events, - &window_player_statistics_events, -}; + void OnResize() override + { + switch (page) + { + case WINDOW_PLAYER_PAGE_OVERVIEW: + OnResizeOverview(); + break; + + case WINDOW_PLAYER_PAGE_STATISTICS: + OnResizeStatistics(); + break; + } + } + + void OnUpdate() override + { + switch (page) + { + case WINDOW_PLAYER_PAGE_OVERVIEW: + OnUpdateOverview(); + break; + + case WINDOW_PLAYER_PAGE_STATISTICS: + OnUpdateStatistics(); + break; + } + } + + void OnPrepareDraw() override + { + switch (page) + { + case WINDOW_PLAYER_PAGE_OVERVIEW: + OnPrepareDrawOverview(); + break; + + case WINDOW_PLAYER_PAGE_STATISTICS: + OnPrepareDrawStatistics(); + break; + } + } + + void OnDraw(DrawPixelInfo& dpi) override + { + switch (page) + { + case WINDOW_PLAYER_PAGE_OVERVIEW: + OnDrawOverview(&dpi); + break; + + case WINDOW_PLAYER_PAGE_STATISTICS: + OnDrawStatistics(&dpi); + break; + } + } + + void OnMouseDown(WidgetIndex widgetIndex) override + { + switch (page) + { + case WINDOW_PLAYER_PAGE_OVERVIEW: + OnMouseDownOverview(widgetIndex); + break; + } + } + + void OnMouseUp(WidgetIndex widgetIndex) override + { + switch (widgetIndex) + { + case WIDX_CLOSE: + Close(); + return; + case WIDX_TAB_1: + case WIDX_TAB_2: + SetPage(widgetIndex - WIDX_TAB_1); + return; + } + + switch (page) + { + case WINDOW_PLAYER_PAGE_OVERVIEW: + OnMouseUpOverview(widgetIndex); + break; + } + } + + void OnDropdown(WidgetIndex widgetIndex, int32_t selectedIndex) override + { + switch (page) + { + case WINDOW_PLAYER_PAGE_OVERVIEW: + OnDropdownOverview(widgetIndex, selectedIndex); + break; + } + } #pragma endregion -// clang-format on - -static void WindowPlayerSetPage(WindowBase* w, int32_t page); -static void WindowPlayerDrawTabImages(DrawPixelInfo* dpi, WindowBase* w); -static void WindowPlayerUpdateViewport(WindowBase* w, bool scroll); -static void WindowPlayerUpdateTitle(WindowBase* w); - -WindowBase* WindowPlayerOpen(uint8_t id) -{ - WindowBase* window; - - window = WindowBringToFrontByNumber(WindowClass::Player, id); - if (window == nullptr) +private: + void SetPage(int32_t newPage) { - window = WindowCreateAutoPos(240, 170, &window_player_overview_events, WindowClass::Player, WF_RESIZABLE); - window->number = id; - window->page = 0; - window->frame_no = 0; - window->list_information_type = 0; - window->picked_peep_frame = 0; - window->min_width = 210; - window->min_height = 134; - window->max_width = 500; - window->max_height = 450; + int32_t originalPage = page; - window->no_list_items = 0; - window->selected_list_item = -1; - } + page = newPage; + frame_no = 0; + no_list_items = 0; + selected_list_item = -1; - window->page = 0; - window->Invalidate(); + hold_down_widgets = 0; + pressed_widgets = 0; + widgets = window_player_page_widgets[newPage]; + Invalidate(); + OnResize(); + OnPrepareDraw(); + InitScrollWidgets(); + Invalidate(); - window->widgets = window_player_page_widgets[WINDOW_PLAYER_PAGE_OVERVIEW]; - window->hold_down_widgets = 0; - window->event_handlers = window_player_page_events[WINDOW_PLAYER_PAGE_OVERVIEW]; - window->pressed_widgets = 0; - - WindowInitScrollWidgets(*window); - WindowPlayerSetPage(window, WINDOW_PLAYER_PAGE_OVERVIEW); - - return window; -} - -static void WindowPlayerOverviewShowGroupDropdown(WindowBase* w, Widget* widget) -{ - Widget* dropdownWidget; - int32_t numItems, i; - int32_t player = NetworkGetPlayerIndex(static_cast(w->number)); - if (player == -1) - { - return; - } - - dropdownWidget = widget - 1; - - numItems = NetworkGetNumGroups(); - - WindowDropdownShowTextCustomWidth( - { w->windowPos.x + dropdownWidget->left, w->windowPos.y + dropdownWidget->top }, dropdownWidget->height() + 1, - w->colours[1], 0, 0, numItems, widget->right - dropdownWidget->left); - - for (i = 0; i < NetworkGetNumGroups(); i++) - { - gDropdownItems[i].Format = STR_OPTIONS_DROPDOWN_ITEM; - gDropdownItems[i].Args = reinterpret_cast(NetworkGetGroupName(i)); - } - - Dropdown::SetChecked(NetworkGetGroupIndex(NetworkGetPlayerGroup(player)), true); -} - -void WindowPlayerOverviewClose(WindowBase* w) -{ -} - -void WindowPlayerOverviewMouseUp(WindowBase* w, WidgetIndex widgetIndex) -{ - switch (widgetIndex) - { - case WIDX_CLOSE: - WindowClose(*w); - break; - case WIDX_TAB_1: - case WIDX_TAB_2: - WindowPlayerSetPage(w, widgetIndex - WIDX_TAB_1); - break; - case WIDX_LOCATE: + if (page == WINDOW_PLAYER_PAGE_OVERVIEW) { - WindowBase* mainWindow = WindowGetMain(); - if (mainWindow != nullptr) + if (viewport == nullptr) { - int32_t player = NetworkGetPlayerIndex(static_cast(w->number)); - if (player == -1) - { - return; - } - auto coord = NetworkGetPlayerLastActionCoord(player); - if (coord.x || coord.y || coord.z) - { - WindowScrollToLocation(*mainWindow, coord); - } + const auto viewportFocus = Focus(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ()); + ViewportCreate(this, windowPos, width, height, viewportFocus); + flags |= WF_NO_SCROLLING; + OnPrepareDraw(); + UpdateViewport(false); } - } - break; - case WIDX_KICK: - { - auto kickPlayerAction = PlayerKickAction(w->number); - GameActions::Execute(&kickPlayerAction); - } - break; - } -} - -void WindowPlayerOverviewMouseDown(WindowBase* w, WidgetIndex widgetIndex, Widget* widget) -{ - switch (widgetIndex) - { - case WIDX_GROUP_DROPDOWN: - WindowPlayerOverviewShowGroupDropdown(w, widget); - break; - } -} - -void WindowPlayerOverviewDropdown(WindowBase* w, WidgetIndex widgetIndex, int32_t dropdownIndex) -{ - const auto playerId = static_cast(w->number); - const auto playerIdx = NetworkGetPlayerIndex(playerId); - if (playerIdx == -1) - { - return; - } - if (dropdownIndex == -1) - { - return; - } - const auto groupId = NetworkGetGroupID(dropdownIndex); - const auto windowHandle = std::make_pair(w->classification, w->number); - auto playerSetGroupAction = PlayerSetGroupAction(playerId, groupId); - playerSetGroupAction.SetCallback([windowHandle](const GameAction* ga, const GameActions::Result* result) { - if (result->Error == GameActions::Status::Ok) - { - WindowInvalidateByNumber(windowHandle.first, windowHandle.second); - } - }); - GameActions::Execute(&playerSetGroupAction); -} - -void WindowPlayerOverviewResize(WindowBase* w) -{ - WindowSetResize(*w, 240, 170, 500, 300); -} - -void WindowPlayerOverviewUpdate(WindowBase* w) -{ - w->frame_no++; - WidgetInvalidate(*w, WIDX_TAB_1 + w->page); - - if (NetworkGetPlayerIndex(static_cast(w->number)) == -1) - { - WindowClose(*w); - return; - } - - // Update viewport - bool scroll = true; - - // Use this spare window field for rotation check - if (w->var_4AE != GetCurrentRotation()) - { - w->var_4AE = GetCurrentRotation(); - scroll = false; - } - WindowPlayerUpdateViewport(w, scroll); -} - -void WindowPlayerOverviewPaint(WindowBase* w, DrawPixelInfo* dpi) -{ - WindowDrawWidgets(*w, dpi); - WindowPlayerDrawTabImages(dpi, w); - - int32_t player = NetworkGetPlayerIndex(static_cast(w->number)); - if (player == -1) - { - return; - } - - // Draw current group - int32_t groupindex = NetworkGetGroupIndex(NetworkGetPlayerGroup(player)); - if (groupindex != -1) - { - Widget* widget = &window_player_overview_widgets[WIDX_GROUP]; - - thread_local std::string _buffer; - _buffer.assign("{WINDOW_COLOUR_2}"); - _buffer += NetworkGetGroupName(groupindex); - auto ft = Formatter(); - ft.Add(_buffer.c_str()); - - DrawTextEllipsised( - *dpi, w->windowPos + ScreenCoordsXY{ widget->midX() - 5, widget->top }, widget->width() - 8, STR_STRING, ft, - { TextAlignment::CENTRE }); - } - - // Draw ping - auto screenCoords = w->windowPos + ScreenCoordsXY{ 90, 24 }; - - auto ft = Formatter(); - ft.Add(STR_PING); - DrawTextBasic(*dpi, screenCoords, STR_WINDOW_COLOUR_2_STRINGID, ft); - char ping[64]; - snprintf(ping, 64, "%d ms", NetworkGetPlayerPing(player)); - GfxDrawString(*dpi, screenCoords + ScreenCoordsXY(30, 0), ping, { w->colours[2] }); - - // Draw last action - screenCoords = w->windowPos + ScreenCoordsXY{ w->width / 2, w->height - 13 }; - int32_t width = w->width - 8; - int32_t lastaction = NetworkGetPlayerLastAction(player, 0); - ft = Formatter(); - if (lastaction != -999) - { - ft.Add(NetworkGetActionNameStringID(lastaction)); - } - else - { - ft.Add(STR_ACTION_NA); - } - DrawTextEllipsised(*dpi, screenCoords, width, STR_LAST_ACTION_RAN, ft, { TextAlignment::CENTRE }); - - if (w->viewport != nullptr && w->var_492 != -1) - { - WindowDrawViewport(dpi, *w); - } -} - -void WindowPlayerOverviewInvalidate(WindowBase* w) -{ - int32_t playerIndex = NetworkGetPlayerIndex(static_cast(w->number)); - if (playerIndex == -1) - { - return; - } - - if (window_player_page_widgets[w->page] != w->widgets) - { - w->widgets = window_player_page_widgets[w->page]; - WindowInitScrollWidgets(*w); - } - - w->pressed_widgets &= ~(WIDX_TAB_1); - w->pressed_widgets &= ~(WIDX_TAB_2); - w->pressed_widgets |= 1uLL << (w->page + WIDX_TAB_1); - - WindowPlayerUpdateTitle(w); - - w->ResizeFrameWithPage(); - w->widgets[WIDX_LOCATE].right = w->width - 2; - w->widgets[WIDX_LOCATE].left = w->width - 25; - w->widgets[WIDX_KICK].right = w->width - 2; - w->widgets[WIDX_KICK].left = w->width - 25; - w->widgets[WIDX_VIEWPORT].right = w->width - 26; - w->widgets[WIDX_VIEWPORT].bottom = w->height - 14; - - int32_t groupDropdownWidth = w->widgets[WIDX_GROUP].width(); - w->widgets[WIDX_GROUP].left = (w->width - groupDropdownWidth) / 2; - w->widgets[WIDX_GROUP].right = w->widgets[WIDX_GROUP].left + groupDropdownWidth; - w->widgets[WIDX_GROUP_DROPDOWN].left = w->widgets[WIDX_GROUP].right - 10; - w->widgets[WIDX_GROUP_DROPDOWN].right = w->widgets[WIDX_GROUP].right; - - WindowAlignTabs(w, WIDX_TAB_1, WIDX_TAB_2); - - Viewport* viewport = w->viewport; - if (viewport != nullptr) - { - Widget* viewportWidget = &window_player_overview_widgets[WIDX_VIEWPORT]; - - viewport->pos = w->windowPos + ScreenCoordsXY{ viewportWidget->left, viewportWidget->top }; - viewport->width = viewportWidget->width(); - viewport->height = viewportWidget->height(); - viewport->view_width = viewport->zoom.ApplyTo(viewport->width); - viewport->view_height = viewport->zoom.ApplyTo(viewport->height); - } - - // Only enable kick button for other players - const bool canKick = NetworkCanPerformAction(NetworkGetCurrentPlayerGroupIndex(), NetworkPermission::KickPlayer); - const bool isServer = NetworkGetPlayerFlags(playerIndex) & NETWORK_PLAYER_FLAG_ISSERVER; - const bool isOwnWindow = (NetworkGetCurrentPlayerId() == w->number); - WidgetSetEnabled(*w, WIDX_KICK, canKick && !isOwnWindow && !isServer); -} - -void WindowPlayerStatisticsClose(WindowBase* w) -{ - if (w->error.var_480) - { - w->error.var_480 = 0; - } -} - -void WindowPlayerStatisticsMouseUp(WindowBase* w, WidgetIndex widgetIndex) -{ - switch (widgetIndex) - { - case WIDX_CLOSE: - WindowClose(*w); - break; - case WIDX_TAB_1: - case WIDX_TAB_2: - WindowPlayerSetPage(w, widgetIndex - WIDX_TAB_1); - break; - } -} - -void WindowPlayerStatisticsResize(WindowBase* w) -{ - WindowSetResize(*w, 210, 80, 210, 80); -} - -void WindowPlayerStatisticsUpdate(WindowBase* w) -{ - w->frame_no++; - WidgetInvalidate(*w, WIDX_TAB_1 + w->page); - - if (NetworkGetPlayerIndex(static_cast(w->number)) == -1) - { - WindowClose(*w); - } -} - -void WindowPlayerStatisticsInvalidate(WindowBase* w) -{ - if (window_player_page_widgets[w->page] != w->widgets) - { - w->widgets = window_player_page_widgets[w->page]; - WindowInitScrollWidgets(*w); - } - - w->pressed_widgets &= ~(WIDX_TAB_1); - w->pressed_widgets &= ~(WIDX_TAB_2); - w->pressed_widgets |= 1uLL << (w->page + WIDX_TAB_1); - - WindowPlayerUpdateTitle(w); - - w->ResizeFrameWithPage(); - - WindowAlignTabs(w, WIDX_TAB_1, WIDX_TAB_2); -} - -void WindowPlayerStatisticsPaint(WindowBase* w, DrawPixelInfo* dpi) -{ - WindowDrawWidgets(*w, dpi); - WindowPlayerDrawTabImages(dpi, w); - - int32_t player = NetworkGetPlayerIndex(static_cast(w->number)); - if (player == -1) - { - return; - } - - auto screenCoords = w->windowPos - + ScreenCoordsXY{ window_player_overview_widgets[WIDX_PAGE_BACKGROUND].left + 4, - window_player_overview_widgets[WIDX_PAGE_BACKGROUND].top + 4 }; - - auto ft = Formatter(); - ft.Add(NetworkGetPlayerCommandsRan(player)); - DrawTextBasic(*dpi, screenCoords, STR_COMMANDS_RAN, ft); - - screenCoords.y += LIST_ROW_HEIGHT; - - ft = Formatter(); - ft.Add(NetworkGetPlayerMoneySpent(player)); - DrawTextBasic(*dpi, screenCoords, STR_MONEY_SPENT, ft); -} - -static void WindowPlayerSetPage(WindowBase* w, int32_t page) -{ - int32_t originalPage = w->page; - - w->page = page; - w->frame_no = 0; - w->no_list_items = 0; - w->selected_list_item = -1; - - w->hold_down_widgets = 0; - w->event_handlers = window_player_page_events[page]; - w->pressed_widgets = 0; - w->widgets = window_player_page_widgets[page]; - w->Invalidate(); - WindowEventResizeCall(w); - WindowEventInvalidateCall(w); - WindowInitScrollWidgets(*w); - w->Invalidate(); - - if (page == WINDOW_PLAYER_PAGE_OVERVIEW) - { - if (w->viewport == nullptr) - { - const auto focus = Focus(TileCoordsXYZ(128, 128, 0).ToCoordsXYZ()); - ViewportCreate(w, w->windowPos, w->width, w->height, focus); - w->flags |= WF_NO_SCROLLING; - WindowEventInvalidateCall(w); - WindowPlayerUpdateViewport(w, false); - } - else if (originalPage != page) - { - WindowEventInvalidateCall(w); - WindowPlayerUpdateViewport(w, false); - } - } - else - { - w->RemoveViewport(); - } -} - -static void WindowPlayerDrawTabImages(DrawPixelInfo* dpi, WindowBase* w) -{ - Widget* widget; - - // Tab 1 - if (!WidgetIsDisabled(*w, WIDX_TAB_1)) - { - widget = &w->widgets[WIDX_TAB_1]; - auto screenCoords = w->windowPos + ScreenCoordsXY{ widget->left, widget->top }; - GfxDrawSprite(dpi, ImageId(SPR_PEEP_LARGE_FACE_NORMAL), screenCoords); - } - - // Tab 2 - if (!WidgetIsDisabled(*w, WIDX_TAB_2)) - { - widget = &w->widgets[WIDX_TAB_2]; - auto screenCoords = w->windowPos + ScreenCoordsXY{ widget->left, widget->top }; - int32_t imageId = SPR_TAB_FINANCES_SUMMARY_0; - - if (w->page == WINDOW_PLAYER_PAGE_STATISTICS) - { - imageId += (w->frame_no / 2) & 7; - } - - GfxDrawSprite(dpi, ImageId(imageId), screenCoords); - } -} - -static void WindowPlayerUpdateViewport(WindowBase* w, bool scroll) -{ - int32_t playerIndex = NetworkGetPlayerIndex(static_cast(w->number)); - if (playerIndex == -1) - { - return; - } - - Viewport* viewport = w->viewport; - if (viewport != nullptr) - { - auto coord = NetworkGetPlayerLastActionCoord(playerIndex); - if (coord.x != 0 || coord.y != 0 || coord.z != 0) - { - auto centreLoc = centre_2d_coordinates(coord, viewport); - if (!centreLoc.has_value()) + else if (originalPage != page) { - return; + OnPrepareDraw(); + UpdateViewport(false); } - // Don't scroll if the view was originally undefined - if (w->var_492 == -1) - { - scroll = false; - } - - if (!scroll || w->savedViewPos != centreLoc.value()) - { - w->flags |= WF_SCROLLING_TO_LOCATION; - w->savedViewPos = centreLoc.value(); - if (!scroll) - { - w->viewport->viewPos = centreLoc.value(); - } - WidgetInvalidate(*w, WIDX_VIEWPORT); - } - - // Draw the viewport - w->var_492 = 0; } else { - // Don't draw the viewport - w->var_492 = -1; + RemoveViewport(); } } -} -static void WindowPlayerUpdateTitle(WindowBase* w) + void DrawTabImages(DrawPixelInfo* dpi) + { + Widget* widget; + + // Tab 1 + if (!IsWidgetDisabled(WIDX_TAB_1)) + { + widget = &this->widgets[WIDX_TAB_1]; + auto screenCoords = windowPos + ScreenCoordsXY{ widget->left, widget->top }; + GfxDrawSprite(dpi, ImageId(SPR_PEEP_LARGE_FACE_NORMAL), screenCoords); + } + + // Tab 2 + if (!IsWidgetDisabled(WIDX_TAB_2)) + { + widget = &this->widgets[WIDX_TAB_2]; + auto screenCoords = windowPos + ScreenCoordsXY{ widget->left, widget->top }; + int32_t imageId = SPR_TAB_FINANCES_SUMMARY_0; + + if (page == WINDOW_PLAYER_PAGE_STATISTICS) + { + imageId += (frame_no / 2) & 7; + } + + GfxDrawSprite(dpi, ImageId(imageId), screenCoords); + } + } + + void UpdateViewport(bool scroll) + { + int32_t playerIndex = NetworkGetPlayerIndex(static_cast(number)); + if (playerIndex == -1) + { + return; + } + + if (viewport != nullptr) + { + auto coord = NetworkGetPlayerLastActionCoord(playerIndex); + if (coord.x != 0 || coord.y != 0 || coord.z != 0) + { + auto centreLoc = centre_2d_coordinates(coord, viewport); + if (!centreLoc.has_value()) + { + return; + } + // Don't scroll if the view was originally undefined + if (var_492 == -1) + { + scroll = false; + } + + if (!scroll || savedViewPos != centreLoc.value()) + { + flags |= WF_SCROLLING_TO_LOCATION; + savedViewPos = centreLoc.value(); + if (!scroll) + { + viewport->viewPos = centreLoc.value(); + } + InvalidateWidget(WIDX_VIEWPORT); + } + + // Draw the viewport + var_492 = 0; + } + else + { + // Don't draw the viewport + var_492 = -1; + } + } + } + + void UpdateTitle() + { + auto ft = Formatter::Common(); + int32_t player = NetworkGetPlayerIndex(static_cast(number)); + if (player != -1) + { + ft.Add(NetworkGetPlayerName(player)); // set title caption to player name + } + else + { + ft.Add(""); + } + } + +#pragma region Overview + + void OnResizeOverview() + { + WindowSetResize(*this, 240, 170, 500, 300); + } + + void OnUpdateOverview() + { + frame_no++; + InvalidateWidget(WIDX_TAB_1 + page); + + if (NetworkGetPlayerIndex(static_cast(number)) == -1) + { + Close(); + return; + } + + // Update viewport + bool scroll = true; + + // Use this spare window field for rotation check + if (var_4AE != GetCurrentRotation()) + { + var_4AE = GetCurrentRotation(); + scroll = false; + } + UpdateViewport(scroll); + } + + void OnPrepareDrawOverview() + { + int32_t playerIndex = NetworkGetPlayerIndex(static_cast(number)); + if (playerIndex == -1) + { + return; + } + + if (window_player_page_widgets[page] != widgets) + { + widgets = window_player_page_widgets[page]; + InitScrollWidgets(); + } + + pressed_widgets &= ~(WIDX_TAB_1); + pressed_widgets &= ~(WIDX_TAB_2); + pressed_widgets |= 1uLL << (page + WIDX_TAB_1); + + UpdateTitle(); + + ResizeFrameWithPage(); + widgets[WIDX_LOCATE].right = width - 2; + widgets[WIDX_LOCATE].left = width - 25; + widgets[WIDX_KICK].right = width - 2; + widgets[WIDX_KICK].left = width - 25; + widgets[WIDX_VIEWPORT].right = width - 26; + widgets[WIDX_VIEWPORT].bottom = height - 14; + + int32_t groupDropdownWidth = widgets[WIDX_GROUP].width(); + widgets[WIDX_GROUP].left = (width - groupDropdownWidth) / 2; + widgets[WIDX_GROUP].right = widgets[WIDX_GROUP].left + groupDropdownWidth; + widgets[WIDX_GROUP_DROPDOWN].left = widgets[WIDX_GROUP].right - 10; + widgets[WIDX_GROUP_DROPDOWN].right = widgets[WIDX_GROUP].right; + + WindowAlignTabs(this, WIDX_TAB_1, WIDX_TAB_2); + + if (viewport != nullptr) + { + Widget* viewportWidget = &window_player_overview_widgets[WIDX_VIEWPORT]; + + viewport->pos = windowPos + ScreenCoordsXY{ viewportWidget->left, viewportWidget->top }; + viewport->width = viewportWidget->width(); + viewport->height = viewportWidget->height(); + viewport->view_width = viewport->zoom.ApplyTo(viewport->width); + viewport->view_height = viewport->zoom.ApplyTo(viewport->height); + } + + // Only enable kick button for other players + const bool canKick = NetworkCanPerformAction(NetworkGetCurrentPlayerGroupIndex(), NetworkPermission::KickPlayer); + const bool isServer = NetworkGetPlayerFlags(playerIndex) & NETWORK_PLAYER_FLAG_ISSERVER; + const bool isOwnWindow = (NetworkGetCurrentPlayerId() == number); + WidgetSetEnabled(*this, WIDX_KICK, canKick && !isOwnWindow && !isServer); + } + + void OnDrawOverview(DrawPixelInfo* dpi) + { + DrawWidgets(*dpi); + DrawTabImages(dpi); + + int32_t player = NetworkGetPlayerIndex(static_cast(number)); + if (player == -1) + { + return; + } + + // Draw current group + int32_t groupindex = NetworkGetGroupIndex(NetworkGetPlayerGroup(player)); + if (groupindex != -1) + { + Widget* widget = &window_player_overview_widgets[WIDX_GROUP]; + + thread_local std::string _buffer; + _buffer.assign("{WINDOW_COLOUR_2}"); + _buffer += NetworkGetGroupName(groupindex); + auto ft = Formatter(); + ft.Add(_buffer.c_str()); + + DrawTextEllipsised( + *dpi, windowPos + ScreenCoordsXY{ widget->midX() - 5, widget->top }, widget->width() - 8, STR_STRING, ft, + { TextAlignment::CENTRE }); + } + + // Draw ping + auto screenCoords = windowPos + ScreenCoordsXY{ 90, 24 }; + + auto ft = Formatter(); + ft.Add(STR_PING); + DrawTextBasic(*dpi, screenCoords, STR_WINDOW_COLOUR_2_STRINGID, ft); + char ping[64]; + snprintf(ping, 64, "%d ms", NetworkGetPlayerPing(player)); + GfxDrawString(*dpi, screenCoords + ScreenCoordsXY(30, 0), ping, { colours[2] }); + + // Draw last action + screenCoords = windowPos + ScreenCoordsXY{ width / 2, height - 13 }; + int32_t updatedWidth = this->width - 8; + int32_t lastaction = NetworkGetPlayerLastAction(player, 0); + ft = Formatter(); + if (lastaction != -999) + { + ft.Add(NetworkGetActionNameStringID(lastaction)); + } + else + { + ft.Add(STR_ACTION_NA); + } + DrawTextEllipsised(*dpi, screenCoords, updatedWidth, STR_LAST_ACTION_RAN, ft, { TextAlignment::CENTRE }); + + if (viewport != nullptr && var_492 != -1) + { + WindowDrawViewport(dpi, *this); + } + } + + void OnMouseDownOverview(WidgetIndex widgetIndex) + { + auto* widget = &widgets[widgetIndex]; + switch (widgetIndex) + { + case WIDX_GROUP_DROPDOWN: + ShowGroupDropdownOverview(widget); + break; + } + } + + void OnMouseUpOverview(WidgetIndex widgetIndex) + { + switch (widgetIndex) + { + case WIDX_LOCATE: + { + WindowBase* mainWindow = WindowGetMain(); + if (mainWindow != nullptr) + { + int32_t player = NetworkGetPlayerIndex(static_cast(number)); + if (player == -1) + { + return; + } + auto coord = NetworkGetPlayerLastActionCoord(player); + if (coord.x || coord.y || coord.z) + { + WindowScrollToLocation(*mainWindow, coord); + } + } + } + break; + case WIDX_KICK: + { + auto kickPlayerAction = PlayerKickAction(number); + GameActions::Execute(&kickPlayerAction); + } + break; + } + } + + void OnDropdownOverview(WidgetIndex widgetIndex, int32_t dropdownIndex) + { + const auto playerId = static_cast(number); + const auto playerIdx = NetworkGetPlayerIndex(playerId); + if (playerIdx == -1) + { + return; + } + if (dropdownIndex == -1) + { + return; + } + const auto groupId = NetworkGetGroupID(dropdownIndex); + const auto windowHandle = std::make_pair(classification, number); + auto playerSetGroupAction = PlayerSetGroupAction(playerId, groupId); + playerSetGroupAction.SetCallback([windowHandle](const GameAction* ga, const GameActions::Result* result) { + if (result->Error == GameActions::Status::Ok) + { + WindowInvalidateByNumber(windowHandle.first, windowHandle.second); + } + }); + GameActions::Execute(&playerSetGroupAction); + } + + void ShowGroupDropdownOverview(Widget* widget) + { + Widget* dropdownWidget; + int32_t numItems, i; + int32_t player = NetworkGetPlayerIndex(static_cast(number)); + if (player == -1) + { + return; + } + + dropdownWidget = widget - 1; + + numItems = NetworkGetNumGroups(); + + WindowDropdownShowTextCustomWidth( + { windowPos.x + dropdownWidget->left, windowPos.y + dropdownWidget->top }, dropdownWidget->height() + 1, colours[1], + 0, 0, numItems, widget->right - dropdownWidget->left); + + for (i = 0; i < NetworkGetNumGroups(); i++) + { + gDropdownItems[i].Format = STR_OPTIONS_DROPDOWN_ITEM; + gDropdownItems[i].Args = reinterpret_cast(NetworkGetGroupName(i)); + } + + Dropdown::SetChecked(NetworkGetGroupIndex(NetworkGetPlayerGroup(player)), true); + } + +#pragma endregion + +#pragma region Statistics + + void OnCloseStatistics() + { + if (error.var_480) + { + error.var_480 = 0; + } + } + + void OnResizeStatistics() + { + WindowSetResize(*this, 210, 80, 210, 80); + } + + void OnUpdateStatistics() + { + frame_no++; + InvalidateWidget(WIDX_TAB_1 + page); + + if (NetworkGetPlayerIndex(static_cast(number)) == -1) + { + Close(); + } + } + + void OnPrepareDrawStatistics() + { + if (window_player_page_widgets[page] != widgets) + { + widgets = window_player_page_widgets[page]; + InitScrollWidgets(); + } + + pressed_widgets &= ~(WIDX_TAB_1); + pressed_widgets &= ~(WIDX_TAB_2); + pressed_widgets |= 1uLL << (page + WIDX_TAB_1); + + UpdateTitle(); + + ResizeFrameWithPage(); + + WindowAlignTabs(this, WIDX_TAB_1, WIDX_TAB_2); + } + + void OnDrawStatistics(DrawPixelInfo* dpi) + { + DrawWidgets(*dpi); + DrawTabImages(dpi); + + int32_t player = NetworkGetPlayerIndex(static_cast(number)); + if (player == -1) + { + return; + } + + auto screenCoords = windowPos + + ScreenCoordsXY{ window_player_overview_widgets[WIDX_PAGE_BACKGROUND].left + 4, + window_player_overview_widgets[WIDX_PAGE_BACKGROUND].top + 4 }; + + auto ft = Formatter(); + ft.Add(NetworkGetPlayerCommandsRan(player)); + DrawTextBasic(*dpi, screenCoords, STR_COMMANDS_RAN, ft); + + screenCoords.y += LIST_ROW_HEIGHT; + + ft = Formatter(); + ft.Add(NetworkGetPlayerMoneySpent(player)); + DrawTextBasic(*dpi, screenCoords, STR_MONEY_SPENT, ft); + } + +#pragma endregion +}; + +WindowBase* WindowPlayerOpen(uint8_t id) { - auto ft = Formatter::Common(); - int32_t player = NetworkGetPlayerIndex(static_cast(w->number)); - if (player != -1) + auto* window = static_cast(WindowBringToFrontByNumber(WindowClass::Player, id)); + if (window == nullptr) { - ft.Add(NetworkGetPlayerName(player)); // set title caption to player name - } - else - { - ft.Add(""); + window = WindowCreate(WindowClass::Player, 240, 170, WF_RESIZABLE); } + + window->Init(id); + + return window; }