From d0f286babed5f5827fd39751a33b8c5f2d889a05 Mon Sep 17 00:00:00 2001 From: oy Date: Sat, 17 Nov 2018 12:45:57 +0100 Subject: [PATCH] Added friends tab --- src/engine/client/serverbrowser.h | 1 + src/engine/serverbrowser.h | 1 + src/game/client/components/menus.h | 12 ++ src/game/client/components/menus_browser.cpp | 203 +++++++++++++++++++ 4 files changed, 217 insertions(+) diff --git a/src/engine/client/serverbrowser.h b/src/engine/client/serverbrowser.h index b29a1d4f7..a7e07ed11 100644 --- a/src/engine/client/serverbrowser.h +++ b/src/engine/client/serverbrowser.h @@ -32,6 +32,7 @@ public: int NumServers() const { return m_aServerlist[m_ActServerlistType].m_NumServers; } int NumPlayers() const { return m_aServerlist[m_ActServerlistType].m_NumPlayers; } + const CServerInfo *Get(int Index) const { return &m_aServerlist[m_ActServerlistType].m_ppServerlist[Index]->m_Info; }; int NumSortedServers(int FilterIndex) const { return m_ServerBrowserFilter.GetNumSortedServers(FilterIndex); } int NumSortedPlayers(int FilterIndex) const { return m_ServerBrowserFilter.GetNumSortedPlayers(FilterIndex); } diff --git a/src/engine/serverbrowser.h b/src/engine/serverbrowser.h index a83036fc0..ec4481d8e 100644 --- a/src/engine/serverbrowser.h +++ b/src/engine/serverbrowser.h @@ -123,6 +123,7 @@ public: virtual int NumServers() const = 0; virtual int NumPlayers() const = 0; + virtual const CServerInfo *Get(int Index) const = 0; virtual int NumSortedServers(int Index) const = 0; virtual int NumSortedPlayers(int Index) const = 0; diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index 7f8a18423..b963578b6 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -312,6 +312,9 @@ private: int m_NumFound; const CFriendInfo *m_pFriendInfo; const CServerInfo *m_pServerInfo; + char m_aName[MAX_NAME_LENGTH]; + char m_aClan[MAX_CLAN_LENGTH]; + bool m_IsPlayer; CClanFriendItem m_ClanFriend; @@ -355,6 +358,15 @@ private: int m_FriendlistSelectedIndex; const CFriendInfo *m_pDeleteFriendInfo; CSelectedFriend m_SelectedFriend; + enum + { + FRIEND_PLAYER_ON = 0, + FRIEND_CLAN_ON, + FRIEND_OFF, + NUM_FRIEND_TYPES + }; + array m_lFriendList[NUM_FRIEND_TYPES]; + const CFriendItem *m_pDeleteFriend; bool SortCompareName(int Index1, int Index2) const; bool SortCompareClan(int Index1, int Index2) const; diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 0ed5c3a5c..dd93839a9 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -1379,7 +1379,210 @@ void CMenus::RenderServerbrowserSidebar(CUIRect View) void CMenus::RenderServerbrowserFriendTab(CUIRect View) { + CUIRect Button, Icon, Label, Rect; + CUIRect BottomArea, ButtonBackground; + const float FontSize = 10.0f; + static bool s_ListExtended[NUM_FRIEND_TYPES] = { 1, 1, 0 }; + static const char *s_HeaderCaption[NUM_FRIEND_TYPES] = { Localize("Online players (%d)"), Localize("Online clanmates (%d)"), Localize("Offline (%d)") }; + View.HSplitBottom(3*ms_ListheaderHeight, &View, &BottomArea); + + // calculate friends + // todo: optimize this + m_pDeleteFriend = 0; + m_lFriendList[0].clear(); + m_lFriendList[1].clear(); + m_lFriendList[2].clear(); + for(int f = 0; f < m_pClient->Friends()->NumFriends(); ++f) + { + const CFriendInfo *pFriendInfo = m_pClient->Friends()->GetFriend(f); + CFriendItem FriendItem; + FriendItem.m_pServerInfo = 0; + str_copy(FriendItem.m_aName, pFriendInfo->m_aName, sizeof(FriendItem.m_aName)); + str_copy(FriendItem.m_aClan, pFriendInfo->m_aClan, sizeof(FriendItem.m_aClan)); + FriendItem.m_IsPlayer = false; + m_lFriendList[2].add(FriendItem); + } + + for(int ServerIndex = 0; ServerIndex < ServerBrowser()->NumServers(); ++ServerIndex) + { + const CServerInfo *pEntry = ServerBrowser()->Get(ServerIndex); + if(pEntry->m_FriendState == IFriends::FRIEND_NO) + continue; + + for(int j = 0; j < pEntry->m_NumClients; ++j) + { + if(pEntry->m_aClients[j].m_FriendState == IFriends::FRIEND_NO) + continue; + + CFriendItem FriendItem; + FriendItem.m_pServerInfo = pEntry; + str_copy(FriendItem.m_aName, pEntry->m_aClients[j].m_aName, sizeof(FriendItem.m_aName)); + str_copy(FriendItem.m_aClan, pEntry->m_aClients[j].m_aClan, sizeof(FriendItem.m_aClan)); + FriendItem.m_IsPlayer = pEntry->m_aClients[j].m_Player; + + if(pEntry->m_aClients[j].m_FriendState == IFriends::FRIEND_PLAYER) + m_lFriendList[0].add(FriendItem); + else + m_lFriendList[1].add(FriendItem); + + for(int f = 0; f < m_lFriendList[2].size(); ++f) + { + if((!m_lFriendList[2][f].m_aName[0] || !str_comp(m_lFriendList[2][f].m_aName, pEntry->m_aClients[j].m_aName)) && !str_comp(m_lFriendList[2][f].m_aClan, pEntry->m_aClients[j].m_aClan)) + m_lFriendList[2].remove_index(f--); + } + } + } + + // scrollbar + UI()->ClipEnable(&View); + float Length = 0.0f; + for(int i = 0; i < NUM_FRIEND_TYPES; ++i) + { + Length += ms_ListheaderHeight + 2.0f; + if(s_ListExtended[i]) + Length += (20.0f+ms_ListheaderHeight+2.0f)*m_lFriendList[i].size(); + } + static float s_ScrollValue = 0.0f; + int ScrollNum = (int)((Length - View.h)/ms_ListheaderHeight)+1; + if(ScrollNum > 0) + { + if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View)) + s_ScrollValue = clamp(s_ScrollValue - 3.0f/ScrollNum, 0.0f, 1.0f); + if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View)) + s_ScrollValue = clamp(s_ScrollValue + 3.0f / ScrollNum, 0.0f, 1.0f); + } + if(Length > View.h) + { + View.VSplitRight(8.0f, &View, &Button); + Button.HMargin(5.0f, &Button); + s_ScrollValue = DoScrollbarV(&s_ScrollValue, &Button, s_ScrollValue); + View.y += (View.h - Length) * s_ScrollValue; + } + + // show lists + for(int i = 0; i < NUM_FRIEND_TYPES; ++i) + { + CUIRect Header; + char aBuf[64] = { 0 }; + View.HSplitTop(ms_ListheaderHeight, &Header, &View); + if(s_ListExtended[i]) + { + // entries + for(int f = 0; f < m_lFriendList[i].size(); ++f) + { + View.HSplitTop(20.0f + ms_ListheaderHeight, &Rect, &View); + RenderTools()->DrawUIRect(&Rect, vec4(0.5f, 0.5f, 0.5f, 0.5f), CUI::CORNER_ALL, 5.0f); + Rect.VMargin(2.0f, &Rect); + Rect.VSplitRight(45.0f, &Rect, &Icon); + Rect.HSplitTop(20.0f, &Button, 0); + // name + Rect.HSplitTop(10.0f, &Button, &Rect); + vec4 Colour = (i == FRIEND_PLAYER_ON) ? vec4(0.5f, 1.0f, 0.5f, 0.15f) : + (i == FRIEND_CLAN_ON || !m_lFriendList[i][f].m_aName[0]) ? vec4(0.0f, 0.0f, 0.0f, 0.15f) : vec4(1.0f, 0.5f, 0.5f, 0.15f); + RenderTools()->DrawUIRect(&Button, Colour, CUI::CORNER_T, 4.0f); + Button.VSplitLeft(2.0f, 0, &Button); + UI()->DoLabelScaled(&Button, m_lFriendList[i][f].m_aName, FontSize - 2, CUI::ALIGN_LEFT); + // clan + Rect.HSplitTop(10.0f, &Button, &Rect); + Colour = (i != FRIEND_OFF) ? vec4(0.5f, 1.0f, 0.5f, 0.15f) : vec4(1.0f, 0.5f, 0.5f, 0.15f); + RenderTools()->DrawUIRect(&Button, Colour, CUI::CORNER_B, 4.0f); + Button.VSplitLeft(2.0f, 0, &Button); + UI()->DoLabelScaled(&Button, m_lFriendList[i][f].m_aClan, FontSize - 2, CUI::ALIGN_LEFT); + // info + if(m_lFriendList[i][f].m_pServerInfo) + { + Rect.HSplitTop(ms_ListheaderHeight, &Button, &Rect); + Button.VSplitLeft(2.0f, 0, &Button); + if(m_lFriendList[i][f].m_IsPlayer) + str_format(aBuf, sizeof(aBuf), Localize("Playing '%s' on '%s'"), m_lFriendList[i][f].m_pServerInfo->m_aGameType, m_lFriendList[i][f].m_pServerInfo->m_aMap); + else + str_format(aBuf, sizeof(aBuf), Localize("Watching '%s' on '%s'"), m_lFriendList[i][f].m_pServerInfo->m_aGameType, m_lFriendList[i][f].m_pServerInfo->m_aMap); + Button.HMargin(2.0f, &Button); + UI()->DoLabelScaled(&Button, aBuf, FontSize - 2, CUI::ALIGN_LEFT); + } + // delete button + Icon.HSplitTop(20.0f, &Rect, 0); + Rect.VSplitRight(10.0f, &Button, &Icon); + Icon.HMargin((Icon.h - Icon.w) / 2, &Icon); + if(DoButton_SpriteClean(IMAGE_TOOLICONS, SPRITE_TOOL_X_B, &Icon)) + { + m_pDeleteFriend = &m_lFriendList[i][f]; + } + // join button + if(m_lFriendList[i][f].m_pServerInfo) + { + Button.Margin((Button.h - ms_ListheaderHeight + 2.0f) / 2, &Button); + RenderTools()->DrawUIRect(&Button, vec4(1.0f, 1.0f, 1.0f, 0.15f), CUI::CORNER_ALL, 4.0f); + Label.HMargin(2.0f, &Label); + UI()->DoLabelScaled(&Button, Localize("Join"), FontSize, CUI::ALIGN_CENTER); + if(UI()->MouseInside(&Button) && Input()->KeyPress(KEY_MOUSE_1)) // todo: fix me + { + str_copy(g_Config.m_UiServerAddress, m_lFriendList[i][f].m_pServerInfo->m_aAddress, sizeof(g_Config.m_UiServerAddress)); + Client()->Connect(g_Config.m_UiServerAddress); + } + } + if(f < m_lFriendList[i].size()-1) + View.HSplitTop(2.0f, 0, &View); + } + } + View.HSplitTop(2.0f, 0, &View); + + // header + RenderTools()->DrawUIRect(&Header, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 5.0f); + Header.VSplitLeft(Header.h, &Icon, &Label); + DoIcon(IMAGE_MENUICONS, s_ListExtended[i] ? SPRITE_MENU_EXPANDED : SPRITE_MENU_COLLAPSED, &Icon); + str_format(aBuf, sizeof(aBuf), s_HeaderCaption[i], m_lFriendList[i].size()); + Label.HMargin(2.0f, &Label); + UI()->DoLabelScaled(&Label, aBuf, FontSize, CUI::ALIGN_LEFT); + static int s_HeaderButton[NUM_FRIEND_TYPES] = { 0 }; + if(UI()->DoButtonLogic(&s_HeaderButton[i], "", 0, &Header)) + { + s_ListExtended[i] ^= 1; + } + } + UI()->ClipDisable(); + + // add friend + BottomArea.HSplitTop(ms_ListheaderHeight, &Button, &BottomArea); + Button.VSplitLeft(50.0f, &Label, &Button); + UI()->DoLabelScaled(&Label, Localize("Name"), FontSize, CUI::ALIGN_LEFT); + static char s_aName[MAX_NAME_LENGTH] = { 0 }; + static float s_OffsetName = 0.0f; + DoEditBox(&s_aName, &Button, s_aName, sizeof(s_aName), Button.h*ms_FontmodHeight*0.8f, &s_OffsetName); + + BottomArea.HSplitTop(ms_ListheaderHeight, &Button, &BottomArea); + Button.VSplitLeft(50.0f, &Label, &Button); + UI()->DoLabelScaled(&Label, Localize("Clan"), FontSize, CUI::ALIGN_LEFT); + static char s_aClan[MAX_CLAN_LENGTH] = { 0 }; + static float s_OffsetClan = 0.0f; + DoEditBox(&s_aClan, &Button, s_aClan, sizeof(s_aClan), Button.h*ms_FontmodHeight*0.8f, &s_OffsetClan); + + BottomArea.HSplitTop(ms_ListheaderHeight, &Button, &BottomArea); + RenderTools()->DrawUIRect(&Button, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 5.0f); + Button.VSplitLeft(Button.h, &Icon, &Label); + Label.HMargin(2.0f, &Label); + UI()->DoLabelScaled(&Label, Localize("Add friend"), FontSize, CUI::ALIGN_CENTER); + if(s_aName[0] || s_aClan[0]) + DoIcon(IMAGE_FRIENDICONS, UI()->MouseInside(&Button)?SPRITE_FRIEND_PLUS_A:SPRITE_FRIEND_PLUS_B, &Icon); + static CButtonContainer s_AddFriend; + if((s_aName[0] || s_aClan[0]) && UI()->DoButtonLogic(&s_AddFriend, "", 0, &Button)) + { + m_pClient->Friends()->AddFriend(s_aName, s_aClan); + FriendlistOnUpdate(); + Client()->ServerBrowserUpdate(); + s_aName[0] = 0; + s_aClan[0] = 0; + } + + // delete friend + if(m_pDeleteFriend) + { + m_pClient->Friends()->RemoveFriend(m_pDeleteFriend->m_aName, m_pDeleteFriend->m_aClan); + FriendlistOnUpdate(); + Client()->ServerBrowserUpdate(); + m_pDeleteFriend = 0; + } } void CMenus::RenderServerbrowserFilterTab(CUIRect View)