diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/engine/client/friends.cpp | 38 | ||||
| -rw-r--r-- | src/engine/client/friends.h | 1 | ||||
| -rw-r--r-- | src/engine/client/serverbrowser.cpp | 157 | ||||
| -rw-r--r-- | src/engine/friends.h | 8 | ||||
| -rw-r--r-- | src/engine/serverbrowser.h | 5 | ||||
| -rw-r--r-- | src/game/client/components/menus.cpp | 6 | ||||
| -rw-r--r-- | src/game/client/components/menus.h | 29 | ||||
| -rw-r--r-- | src/game/client/components/menus_browser.cpp | 166 |
8 files changed, 297 insertions, 113 deletions
diff --git a/src/engine/client/friends.cpp b/src/engine/client/friends.cpp index 9ef00ed1..99f82b50 100644 --- a/src/engine/client/friends.cpp +++ b/src/engine/client/friends.cpp @@ -1,6 +1,7 @@ /* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #include <base/math.h> +#include <base/system.h> #include <engine/config.h> #include <engine/console.h> @@ -44,12 +45,35 @@ const CFriendInfo *CFriends::GetFriend(int Index) const return &m_aFriends[max(0, Index%m_NumFriends)]; } +int CFriends::GetFriendState(const char *pName, const char *pClan) const +{ + int Result = FRIEND_NO; + unsigned NameHash = str_quickhash(pName); + unsigned ClanHash = str_quickhash(pClan); + for(int i = 0; i < m_NumFriends; ++i) + { + if(m_aFriends[i].m_ClanHash == ClanHash) + { + if(m_aFriends[i].m_aName[0] == 0) + Result = FRIEND_CLAN; + else if(m_aFriends[i].m_NameHash == NameHash) + { + Result = FRIEND_PLAYER; + break; + } + } + } + return Result; +} + bool CFriends::IsFriend(const char *pName, const char *pClan, bool PlayersOnly) const { + unsigned NameHash = str_quickhash(pName); + unsigned ClanHash = str_quickhash(pClan); for(int i = 0; i < m_NumFriends; ++i) { - if(!str_comp(m_aFriends[i].m_aClan, pClan) && - ((!PlayersOnly && m_aFriends[i].m_aName[0] == 0) || !str_comp(m_aFriends[i].m_aName, pName))) + if(m_aFriends[i].m_ClanHash == ClanHash && + ((!PlayersOnly && m_aFriends[i].m_aName[0] == 0) || m_aFriends[i].m_NameHash == NameHash)) return true; } return false; @@ -61,22 +85,28 @@ void CFriends::AddFriend(const char *pName, const char *pClan) return; // make sure we don't have the friend already + unsigned NameHash = str_quickhash(pName); + unsigned ClanHash = str_quickhash(pClan); for(int i = 0; i < m_NumFriends; ++i) { - if(!str_comp(m_aFriends[i].m_aName, pName) && !str_comp(m_aFriends[i].m_aClan, pClan)) + if(m_aFriends[i].m_NameHash == NameHash && m_aFriends[i].m_ClanHash == ClanHash) return; } str_copy(m_aFriends[m_NumFriends].m_aName, pName, sizeof(m_aFriends[m_NumFriends].m_aName)); str_copy(m_aFriends[m_NumFriends].m_aClan, pClan, sizeof(m_aFriends[m_NumFriends].m_aClan)); + m_aFriends[m_NumFriends].m_NameHash = NameHash; + m_aFriends[m_NumFriends].m_ClanHash = ClanHash; ++m_NumFriends; } void CFriends::RemoveFriend(const char *pName, const char *pClan) { + unsigned NameHash = str_quickhash(pName); + unsigned ClanHash = str_quickhash(pClan); for(int i = 0; i < m_NumFriends; ++i) { - if(!str_comp(m_aFriends[i].m_aName, pName) && !str_comp(m_aFriends[i].m_aClan, pClan)) + if(m_aFriends[i].m_NameHash == NameHash && m_aFriends[i].m_ClanHash == ClanHash) { RemoveFriend(i); return; diff --git a/src/engine/client/friends.h b/src/engine/client/friends.h index be0cfa49..d4c539e1 100644 --- a/src/engine/client/friends.h +++ b/src/engine/client/friends.h @@ -22,6 +22,7 @@ public: int NumFriends() const { return m_NumFriends; } const CFriendInfo *GetFriend(int Index) const; + int GetFriendState(const char *pName, const char *pClan) const; bool IsFriend(const char *pName, const char *pClan, bool PlayersOnly) const; void AddFriend(const char *pName, const char *pClan); diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index 424acb22..c3ada10e 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -144,101 +144,98 @@ void CServerBrowser::Filter() { int Filtered = 0; - if(g_Config.m_BrFilterFriends) + if(g_Config.m_BrFilterEmpty && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == 0) || m_ppServerlist[i]->m_Info.m_NumClients == 0)) + Filtered = 1; + else if(g_Config.m_BrFilterFull && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == m_ppServerlist[i]->m_Info.m_MaxPlayers) || + m_ppServerlist[i]->m_Info.m_NumClients == m_ppServerlist[i]->m_Info.m_MaxClients)) + Filtered = 1; + else if(g_Config.m_BrFilterPw && m_ppServerlist[i]->m_Info.m_Flags&SERVER_FLAG_PASSWORD) + Filtered = 1; + else if(g_Config.m_BrFilterPure && + (str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "DM") != 0 && + str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "TDM") != 0 && + str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "CTF") != 0)) { Filtered = 1; - for(p = 0; p < m_ppServerlist[i]->m_Info.m_NumClients; p++) - { - if(m_pFriends->IsFriend(m_ppServerlist[i]->m_Info.m_aClients[p].m_aName, m_ppServerlist[i]->m_Info.m_aClients[p].m_aClan, false)) - { - Filtered = 0; - break; - } - } } - else + else if(g_Config.m_BrFilterPureMap && + !(str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm1") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm2") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm6") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm7") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm8") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm9") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf1") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf2") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf3") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf4") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf5") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf6") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf7") == 0) + ) { - if(g_Config.m_BrFilterEmpty && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == 0) || m_ppServerlist[i]->m_Info.m_NumClients == 0)) - Filtered = 1; - else if(g_Config.m_BrFilterFull && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == m_ppServerlist[i]->m_Info.m_MaxPlayers) || - m_ppServerlist[i]->m_Info.m_NumClients == m_ppServerlist[i]->m_Info.m_MaxClients)) - Filtered = 1; - else if(g_Config.m_BrFilterPw && m_ppServerlist[i]->m_Info.m_Flags&SERVER_FLAG_PASSWORD) - Filtered = 1; - else if(g_Config.m_BrFilterPure && - (str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "DM") != 0 && - str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "TDM") != 0 && - str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "CTF") != 0)) - { - Filtered = 1; - } - else if(g_Config.m_BrFilterPureMap && - !(str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm1") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm2") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm6") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm7") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm8") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm9") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf1") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf2") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf3") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf4") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf5") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf6") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf7") == 0) - ) - { - Filtered = 1; - } - else if(g_Config.m_BrFilterPing < m_ppServerlist[i]->m_Info.m_Latency) - Filtered = 1; - else if(g_Config.m_BrFilterCompatversion && str_comp_num(m_ppServerlist[i]->m_Info.m_aVersion, m_aNetVersion, 3) != 0) - Filtered = 1; - else if(g_Config.m_BrFilterServerAddress[0] && !str_find_nocase(m_ppServerlist[i]->m_Info.m_aAddress, g_Config.m_BrFilterServerAddress)) - Filtered = 1; - else if(g_Config.m_BrFilterGametypeStrict && g_Config.m_BrFilterGametype[0] && str_comp_nocase(m_ppServerlist[i]->m_Info.m_aGameType, g_Config.m_BrFilterGametype)) - Filtered = 1; - else if(!g_Config.m_BrFilterGametypeStrict && g_Config.m_BrFilterGametype[0] && !str_find_nocase(m_ppServerlist[i]->m_Info.m_aGameType, g_Config.m_BrFilterGametype)) - Filtered = 1; - else if(g_Config.m_BrFilterString[0] != 0) - { - int MatchFound = 0; - - m_ppServerlist[i]->m_Info.m_QuickSearchHit = 0; + Filtered = 1; + } + else if(g_Config.m_BrFilterPing < m_ppServerlist[i]->m_Info.m_Latency) + Filtered = 1; + else if(g_Config.m_BrFilterCompatversion && str_comp_num(m_ppServerlist[i]->m_Info.m_aVersion, m_aNetVersion, 3) != 0) + Filtered = 1; + else if(g_Config.m_BrFilterServerAddress[0] && !str_find_nocase(m_ppServerlist[i]->m_Info.m_aAddress, g_Config.m_BrFilterServerAddress)) + Filtered = 1; + else if(g_Config.m_BrFilterGametypeStrict && g_Config.m_BrFilterGametype[0] && str_comp_nocase(m_ppServerlist[i]->m_Info.m_aGameType, g_Config.m_BrFilterGametype)) + Filtered = 1; + else if(!g_Config.m_BrFilterGametypeStrict && g_Config.m_BrFilterGametype[0] && !str_find_nocase(m_ppServerlist[i]->m_Info.m_aGameType, g_Config.m_BrFilterGametype)) + Filtered = 1; + else if(g_Config.m_BrFilterString[0] != 0) + { + int MatchFound = 0; - // match against server name - if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aName, g_Config.m_BrFilterString)) - { - MatchFound = 1; - m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_SERVERNAME; - } + m_ppServerlist[i]->m_Info.m_QuickSearchHit = 0; - // match against players - for(p = 0; p < m_ppServerlist[i]->m_Info.m_NumClients; p++) - { - if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aName, g_Config.m_BrFilterString) || - str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aClan, g_Config.m_BrFilterString)) - { - MatchFound = 1; - m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_PLAYER; - break; - } - } + // match against server name + if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aName, g_Config.m_BrFilterString)) + { + MatchFound = 1; + m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_SERVERNAME; + } - // match against map - if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aMap, g_Config.m_BrFilterString)) + // match against players + for(p = 0; p < m_ppServerlist[i]->m_Info.m_NumClients; p++) + { + if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aName, g_Config.m_BrFilterString) || + str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aClan, g_Config.m_BrFilterString)) { MatchFound = 1; - m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_MAPNAME; + m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_PLAYER; + break; } + } - if(!MatchFound) - Filtered = 1; + // match against map + if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aMap, g_Config.m_BrFilterString)) + { + MatchFound = 1; + m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_MAPNAME; } + + if(!MatchFound) + Filtered = 1; } if(Filtered == 0) - m_pSortedServerlist[m_NumSortedServers++] = i; + { + // check for friend + m_ppServerlist[i]->m_Info.m_FriendState = IFriends::FRIEND_NO; + for(p = 0; p < m_ppServerlist[i]->m_Info.m_NumClients; p++) + { + m_ppServerlist[i]->m_Info.m_aClients[p].m_FriendState = m_pFriends->GetFriendState(m_ppServerlist[i]->m_Info.m_aClients[p].m_aName, + m_ppServerlist[i]->m_Info.m_aClients[p].m_aClan); + m_ppServerlist[i]->m_Info.m_FriendState = max(m_ppServerlist[i]->m_Info.m_FriendState, m_ppServerlist[i]->m_Info.m_aClients[p].m_FriendState); + } + + if(!g_Config.m_BrFilterFriends || m_ppServerlist[i]->m_Info.m_FriendState != IFriends::FRIEND_NO) + m_pSortedServerlist[m_NumSortedServers++] = i; + } } } diff --git a/src/engine/friends.h b/src/engine/friends.h index bf9df904..164e3461 100644 --- a/src/engine/friends.h +++ b/src/engine/friends.h @@ -11,6 +11,8 @@ struct CFriendInfo { char m_aName[MAX_NAME_LENGTH]; char m_aClan[MAX_CLAN_LENGTH]; + unsigned m_NameHash; + unsigned m_ClanHash; }; class IFriends : public IInterface @@ -19,6 +21,10 @@ class IFriends : public IInterface public: enum { + FRIEND_NO=0, + FRIEND_CLAN, + FRIEND_PLAYER, + MAX_FRIENDS=128, }; @@ -26,11 +32,11 @@ public: virtual int NumFriends() const = 0; virtual const CFriendInfo *GetFriend(int Index) const = 0; + virtual int GetFriendState(const char *pName, const char *pClan) const = 0; virtual bool IsFriend(const char *pName, const char *pClan, bool PlayersOnly) const = 0; virtual void AddFriend(const char *pName, const char *pClan) = 0; virtual void RemoveFriend(const char *pName, const char *pClan) = 0; - virtual void RemoveFriend(int Index) = 0; }; #endif diff --git a/src/engine/serverbrowser.h b/src/engine/serverbrowser.h index 3ca59f9c..1a49eaf0 100644 --- a/src/engine/serverbrowser.h +++ b/src/engine/serverbrowser.h @@ -24,7 +24,9 @@ public: int m_Country; int m_Score; bool m_Player; - } ; + + int m_FriendState; + }; int m_SortedIndex; int m_ServerIndex; @@ -32,6 +34,7 @@ public: NETADDR m_NetAddr; int m_QuickSearchHit; + int m_FriendState; int m_MaxClients; int m_NumClients; diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index 64754c68..6ec18ce1 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -734,6 +734,8 @@ void CMenus::OnInit() Console()->Chain("add_favorite", ConchainServerbrowserUpdate, this); Console()->Chain("remove_favorite", ConchainServerbrowserUpdate, this); + Console()->Chain("add_friend", ConchainFriendlistUpdate, this); + Console()->Chain("remove_friend", ConchainFriendlistUpdate, this); // setup load amount m_LoadCurrent = 0; @@ -1205,7 +1207,9 @@ int CMenus::Render() // remove friend if(m_FriendlistSelectedIndex >= 0) { - m_pClient->Friends()->RemoveFriend(m_FriendlistSelectedIndex); + m_pClient->Friends()->RemoveFriend(m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_aName, + m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_aClan); + FriendlistOnUpdate(); Client()->ServerBrowserUpdate(); } } diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index 51b8a1f8..959c366e 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -7,6 +7,7 @@ #include <base/tl/sorted_array.h> #include <engine/demo.h> +#include <engine/friends.h> #include <game/voting.h> #include <game/client/component.h> @@ -202,8 +203,34 @@ class CMenus : public CComponent void DemolistPopulate(); static int DemolistFetchCallback(const char *pName, int IsDir, int StorageType, void *pUser); + // friends + struct CFriendItem + { + const CFriendInfo *m_pFriendInfo; + int m_NumFound; + + bool operator<(const CFriendItem &Other) + { + if(m_NumFound && !Other.m_NumFound) + return true; + else if(!m_NumFound && Other.m_NumFound) + return false; + else + { + int Result = str_comp(m_pFriendInfo->m_aName, Other.m_pFriendInfo->m_aName); + if(Result) + return Result < 0; + else + return str_comp(m_pFriendInfo->m_aClan, Other.m_pFriendInfo->m_aClan) < 0; + } + } + }; + + sorted_array<CFriendItem> m_lFriends; int m_FriendlistSelectedIndex; + void FriendlistOnUpdate(); + // found in menus.cpp int Render(); //void render_background(); @@ -225,11 +252,13 @@ class CMenus : public CComponent // found in menus_browser.cpp int m_SelectedIndex; + int m_ScrollOffset; void RenderServerbrowserServerList(CUIRect View); void RenderServerbrowserServerDetail(CUIRect View); void RenderServerbrowserFilters(CUIRect View); void RenderServerbrowserFriends(CUIRect View); void RenderServerbrowser(CUIRect MainView); + static void ConchainFriendlistUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); static void ConchainServerbrowserUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData); // found in menus_settings.cpp diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 09c8c494..5a0ebfb6 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -154,6 +154,11 @@ void CMenus::RenderServerbrowserServerList(CUIRect View) int ScrollNum = NumServers-Num+1; if(ScrollNum > 0) { + if(m_ScrollOffset) + { + s_ScrollValue = (float)(m_ScrollOffset)/ScrollNum; + m_ScrollOffset = 0; + } if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View)) s_ScrollValue -= 3.0f/ScrollNum; if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View)) @@ -213,16 +218,14 @@ void CMenus::RenderServerbrowserServerList(CUIRect View) m_SelectedIndex = -1; - for (int i = 0; i < NumServers; i++) - { - const CServerInfo *pItem = ServerBrowser()->SortedGet(i); - NumPlayers += pItem->m_NumPlayers; - } + // reset friend counter + for(int i = 0; i < m_lFriends.size(); m_lFriends[i++].m_NumFound = 0); for (int i = 0; i < NumServers; i++) { int ItemIndex = i; const CServerInfo *pItem = ServerBrowser()->SortedGet(ItemIndex); + NumPlayers += pItem->m_NumPlayers; CUIRect Row; CUIRect SelectHitBox; @@ -234,6 +237,28 @@ void CMenus::RenderServerbrowserServerList(CUIRect View) if(Selected) m_SelectedIndex = i; + // update friend counter + if(pItem->m_FriendState != IFriends::FRIEND_NO) + { + for(int j = 0; j < pItem->m_NumClients; ++j) + { + if(pItem->m_aClients[j].m_FriendState != IFriends::FRIEND_NO) + { + unsigned NameHash = str_quickhash(pItem->m_aClients[j].m_aName); + unsigned ClanHash = str_quickhash(pItem->m_aClients[j].m_aClan); + for(int f = 0; f < m_lFriends.size(); ++f) + { + if(ClanHash == m_lFriends[f].m_pFriendInfo->m_ClanHash && + (!m_lFriends[f].m_pFriendInfo->m_aName[0] || NameHash == m_lFriends[f].m_pFriendInfo->m_NameHash)) + { + m_lFriends[f].m_NumFound++; + break; + } + } + } + } + } + // make sure that only those in view can be selected if(Row.y+Row.h > OriginalView.y && Row.y < OriginalView.y+OriginalView.h) { @@ -353,6 +378,15 @@ void CMenus::RenderServerbrowserServerList(CUIRect View) } else if(ID == COL_PLAYERS) { + CUIRect Icon; + Button.VMargin(4.0f, &Button); + if(pItem->m_FriendState != IFriends::FRIEND_NO) + { + Button.VSplitLeft(Button.h, &Icon, &Button); + Icon.Margin(2.0f, &Icon); + DoButton_Icon(IMAGE_BROWSEICONS, SPRITE_BROWSE_HEART, &Icon); + } + if(g_Config.m_BrFilterSpectators) str_format(aTemp, sizeof(aTemp), "%i/%i", pItem->m_NumPlayers, pItem->m_MaxPlayers); else @@ -463,7 +497,7 @@ void CMenus::RenderServerbrowserFilters(CUIRect View) g_Config.m_BrFilterFull ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); - if (DoButton_CheckBox(&g_Config.m_BrFilterFriends, Localize("Show friends"), g_Config.m_BrFilterFriends, &Button)) + if (DoButton_CheckBox(&g_Config.m_BrFilterFriends, Localize("Show friends only"), g_Config.m_BrFilterFriends, &Button)) g_Config.m_BrFilterFriends ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); @@ -622,14 +656,26 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View) RenderTools()->DrawUIRect(&ServerScoreBoard, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); UI()->DoLabelScaled(&ServerHeader, Localize("Scoreboard"), FontSize+2.0f, 0); - if (pSelectedServer) + if(pSelectedServer) { ServerScoreBoard.Margin(3.0f, &ServerScoreBoard); for (int i = 0; i < pSelectedServer->m_NumClients; i++) { CUIRect Name, Clan, Score, Flag; ServerScoreBoard.HSplitTop(25.0f, &Name, &ServerScoreBoard); - RenderTools()->DrawUIRect(&Name, vec4(1,1,1,(i%2+1)*0.05f), CUI::CORNER_ALL, 4.0f); + if(UI()->DoButtonLogic(&pSelectedServer->m_aClients[i], "", 0, &Name)) + { + if(pSelectedServer->m_aClients[i].m_FriendState == IFriends::FRIEND_PLAYER) + m_pClient->Friends()->RemoveFriend(pSelectedServer->m_aClients[i].m_aName, pSelectedServer->m_aClients[i].m_aClan); + else + m_pClient->Friends()->AddFriend(pSelectedServer->m_aClients[i].m_aName, pSelectedServer->m_aClients[i].m_aClan); + FriendlistOnUpdate(); + Client()->ServerBrowserUpdate(); + } + + vec4 Colour = pSelectedServer->m_aClients[i].m_FriendState == IFriends::FRIEND_NO ? vec4(1.0f, 1.0f, 1.0f, (i%2+1)*0.05f) : + vec4(0.5f, 1.0f, 0.5f, 0.15f+(i%2+1)*0.05f); + RenderTools()->DrawUIRect(&Name, Colour, CUI::CORNER_ALL, 4.0f); Name.VSplitLeft(5.0f, 0, &Name); Name.VSplitLeft(30.0f, &Score, &Name); Name.VSplitRight(34.0f, &Name, &Flag); @@ -701,45 +747,102 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View) } } +void CMenus::FriendlistOnUpdate() +{ + m_lFriends.clear(); + for(int i = 0; i < m_pClient->Friends()->NumFriends(); ++i) + { + CFriendItem Item; + Item.m_pFriendInfo = m_pClient->Friends()->GetFriend(i); + Item.m_NumFound = 0; + m_lFriends.add_unsorted(Item); + } + m_lFriends.sort_range(); +} + void CMenus::RenderServerbrowserFriends(CUIRect View) { + static int s_Inited = 0; + if(!s_Inited) + { + FriendlistOnUpdate(); + s_Inited = 1; + } + CUIRect ServerFriends = View, FilterHeader; - const float FontSize = 12.0f; + const float FontSize = 10.0f; // header ServerFriends.HSplitTop(ms_ListheaderHeight, &FilterHeader, &ServerFriends); RenderTools()->DrawUIRect(&FilterHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f); RenderTools()->DrawUIRect(&ServerFriends, vec4(0,0,0,0.15f), 0, 4.0f); - UI()->DoLabelScaled(&FilterHeader, Localize("Friends"), FontSize+2.0f, 0); + UI()->DoLabelScaled(&FilterHeader, Localize("Friends"), FontSize+4.0f, 0); CUIRect Button, List; - ServerFriends.VSplitLeft(5.0f, 0, &ServerFriends); ServerFriends.Margin(3.0f, &ServerFriends); - ServerFriends.VMargin(5.0f, &ServerFriends); + ServerFriends.VMargin(3.0f, &ServerFriends); ServerFriends.HSplitBottom(100.0f, &List, &ServerFriends); // friends list(remove friend) - static int s_FriendList = 0; static float s_ScrollValue = 0; - UiDoListboxStart(&s_FriendList, &List, 40.0f, "", "", m_pClient->Friends()->NumFriends(), 1, m_FriendlistSelectedIndex, s_ScrollValue); + UiDoListboxStart(&m_lFriends, &List, 30.0f, "", "", m_lFriends.size(), 1, m_FriendlistSelectedIndex, s_ScrollValue); - for(int i = 0; i < m_pClient->Friends()->NumFriends(); ++i) + m_lFriends.sort_range(); + for(int i = 0; i < m_lFriends.size(); ++i) { - const CFriendInfo *pFriend = m_pClient->Friends()->GetFriend(i); - CListboxItem Item = UiDoListboxNextItem(pFriend); + CListboxItem Item = UiDoListboxNextItem(&m_lFriends[i]); if(Item.m_Visible) { - Item.m_Rect.Margin(2.5f, &Item.m_Rect); - RenderTools()->DrawUIRect(&Item.m_Rect, vec4(1.0f, 1.0f, 1.0f, 0.1f), CUI::CORNER_ALL, 4.0f); - Item.m_Rect.Margin(2.5f, &Item.m_Rect); - Item.m_Rect.HSplitTop(14.0f, &Item.m_Rect, &Button); - UI()->DoLabelScaled(&Item.m_Rect, pFriend->m_aName, FontSize, -1); - UI()->DoLabelScaled(&Button, pFriend->m_aClan, FontSize, -1); + Item.m_Rect.Margin(1.5f, &Item.m_Rect); + CUIRect OnState; + Item.m_Rect.VSplitRight(30.0f, &Item.m_Rect, &OnState); + RenderTools()->DrawUIRect(&Item.m_Rect, vec4(1.0f, 1.0f, 1.0f, 0.1f), CUI::CORNER_L, 4.0f); + + Item.m_Rect.VMargin(2.5f, &Item.m_Rect); + Item.m_Rect.HSplitTop(12.0f, &Item.m_Rect, &Button); + UI()->DoLabelScaled(&Item.m_Rect, m_lFriends[i].m_pFriendInfo->m_aName, FontSize, -1); + UI()->DoLabelScaled(&Button, m_lFriends[i].m_pFriendInfo->m_aClan, FontSize, -1); + + RenderTools()->DrawUIRect(&OnState, m_lFriends[i].m_NumFound ? vec4(0.0f, 1.0f, 0.0f, 0.25f) : vec4(1.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_R, 4.0f); + OnState.HMargin((OnState.h-FontSize)/3, &OnState); + OnState.VMargin(5.0f, &OnState); + char aBuf[64]; + str_format(aBuf, sizeof(aBuf), "%i", m_lFriends[i].m_NumFound); + UI()->DoLabelScaled(&OnState, aBuf, FontSize+2, 1); } } - m_FriendlistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, 0); + bool Activated = false; + m_FriendlistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated); + + // activate found server with friend + if(Activated && !m_EnterPressed && m_lFriends[m_FriendlistSelectedIndex].m_NumFound) + { + bool Found = false; + int NumServers = ServerBrowser()->NumSortedServers(); + for (int i = 0; i < NumServers && !Found; i++) + { + int ItemIndex = m_SelectedIndex != -1 ? (m_SelectedIndex+i+1)%NumServers : i; + const CServerInfo *pItem = ServerBrowser()->SortedGet(ItemIndex); + if(pItem->m_FriendState != IFriends::FRIEND_NO) + { + for(int j = 0; j < pItem->m_NumClients && !Found; ++j) + { + if(pItem->m_aClients[j].m_FriendState != IFriends::FRIEND_NO && + str_quickhash(pItem->m_aClients[j].m_aClan) == m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_ClanHash && + (!m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_aName[0] || + str_quickhash(pItem->m_aClients[j].m_aName) == m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_NameHash)) + { + str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress, sizeof(g_Config.m_UiServerAddress)); + m_ScrollOffset = ItemIndex; + m_SelectedIndex = ItemIndex; + Found = true; + } + } + } + } + } ServerFriends.HSplitTop(2.5f, 0, &ServerFriends); ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends); @@ -774,10 +877,11 @@ void CMenus::RenderServerbrowserFriends(CUIRect View) ServerFriends.HSplitTop(3.0f, 0, &ServerFriends); ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends); - static int s_RemoveButton = 0; - if(DoButton_Menu(&s_RemoveButton, Localize("Add Friend"), 0, &Button)) + static int s_AddButton = 0; + if(DoButton_Menu(&s_AddButton, Localize("Add Friend"), 0, &Button)) { m_pClient->Friends()->AddFriend(s_aName, s_aClan); + FriendlistOnUpdate(); Client()->ServerBrowserUpdate(); } } @@ -916,6 +1020,16 @@ void CMenus::RenderServerbrowser(CUIRect MainView) } } +void CMenus::ConchainFriendlistUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) +{ + pfnCallback(pResult, pCallbackUserData); + if(pResult->NumArguments() == 2 && ((CMenus *)pUserData)->Client()->State() == IClient::STATE_OFFLINE) + { + ((CMenus *)pUserData)->FriendlistOnUpdate(); + ((CMenus *)pUserData)->Client()->ServerBrowserUpdate(); + } +} + void CMenus::ConchainServerbrowserUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData) { pfnCallback(pResult, pCallbackUserData); |