about summary refs log tree commit diff
path: root/src/game/client/components/menus_browser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/client/components/menus_browser.cpp')
-rw-r--r--src/game/client/components/menus_browser.cpp217
1 files changed, 179 insertions, 38 deletions
diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp
index 3ab02db8..a9c434b3 100644
--- a/src/game/client/components/menus_browser.cpp
+++ b/src/game/client/components/menus_browser.cpp
@@ -154,9 +154,14 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
 	int ScrollNum = NumServers-Num+1;
 	if(ScrollNum > 0)
 	{
-		if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP))
+		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))
+		if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View))
 			s_ScrollValue += 3.0f/ScrollNum;
 	}
 	else
@@ -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,29 @@ 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++;
+							if(m_lFriends[f].m_pFriendInfo->m_aName[0])
+								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 +379,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 +498,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);
@@ -482,6 +517,10 @@ void CMenus::RenderServerbrowserFilters(CUIRect View)
 	if (DoButton_CheckBox((char *)&g_Config.m_BrFilterPureMap, Localize("Standard map"), g_Config.m_BrFilterPureMap, &Button))
 		g_Config.m_BrFilterPureMap ^= 1;
 
+	ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter);
+	if (DoButton_CheckBox((char *)&g_Config.m_BrFilterGametypeStrict, Localize("Strict gametype filter"), g_Config.m_BrFilterGametypeStrict, &Button))
+		g_Config.m_BrFilterGametypeStrict ^= 1;
+
 	ServerFilter.HSplitTop(5.0f, 0, &ServerFilter);
 
 	ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter);
@@ -515,21 +554,46 @@ void CMenus::RenderServerbrowserFilters(CUIRect View)
 	if(DoEditBox(&g_Config.m_BrFilterServerAddress, &Button, g_Config.m_BrFilterServerAddress, sizeof(g_Config.m_BrFilterServerAddress), FontSize, &OffsetAddr))
 		Client()->ServerBrowserUpdate();
 
+	// player country
+	{
+		CUIRect Rect;
+		ServerFilter.HSplitTop(3.0f, 0, &ServerFilter);
+		ServerFilter.HSplitTop(26.0f, &Button, &ServerFilter);
+		Button.VSplitRight(60.0f, &Button, &Rect);
+		Button.HMargin(3.0f, &Button);
+		if(DoButton_CheckBox(&g_Config.m_BrFilterCountry, Localize("Player country:"), g_Config.m_BrFilterCountry, &Button))
+			g_Config.m_BrFilterCountry ^= 1;
+
+		float OldWidth = Rect.w;
+		Rect.w = Rect.h*2;
+		Rect.x += (OldWidth-Rect.w)/2.0f;
+		vec4 Color(1.0f, 1.0f, 1.0f, g_Config.m_BrFilterCountry?1.0f: 0.5f);
+		m_pClient->m_pCountryFlags->Render(g_Config.m_BrFilterCountryIndex, &Color, Rect.x, Rect.y, Rect.w, Rect.h);
+
+		if(g_Config.m_BrFilterCountry && UI()->DoButtonLogic(&g_Config.m_BrFilterCountryIndex, "", 0, &Rect))
+			m_Popup = POPUP_COUNTRY;
+	}
+
 	ServerFilter.HSplitBottom(5.0f, &ServerFilter, 0);
 	ServerFilter.HSplitBottom(ms_ButtonHeight-2.0f, &ServerFilter, &Button);
 	static int s_ClearButton = 0;
 	if(DoButton_Menu(&s_ClearButton, Localize("Reset filter"), 0, &Button))
 	{
+		g_Config.m_BrFilterString[0] = 0;
 		g_Config.m_BrFilterFull = 0;
 		g_Config.m_BrFilterEmpty = 0;
+		g_Config.m_BrFilterSpectators = 0;
+		g_Config.m_BrFilterFriends = 0;
+		g_Config.m_BrFilterCountry = 0;
+		g_Config.m_BrFilterCountryIndex = -1;
 		g_Config.m_BrFilterPw = 0;
 		g_Config.m_BrFilterPing = 999;
 		g_Config.m_BrFilterGametype[0] = 0;
+		g_Config.m_BrFilterGametypeStrict = 0;
 		g_Config.m_BrFilterServerAddress[0] = 0;
-		g_Config.m_BrFilterCompatversion = 1;
-		g_Config.m_BrFilterString[0] = 0;
 		g_Config.m_BrFilterPure = 1;
 		g_Config.m_BrFilterPureMap = 1;
+		g_Config.m_BrFilterCompatversion = 1;
 		Client()->ServerBrowserUpdate();
 	}
 }
@@ -617,25 +681,38 @@ 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.VSplitLeft(5.0f, 0, &ServerScoreBoard);
 		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);
+			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);
 			Flag.HMargin(4.0f, &Flag);
-			Name.HSplitTop(12.0f, &Name, &Clan);
+			Name.HSplitTop(11.0f, &Name, &Clan);
 
 			// score
 			if(pSelectedServer->m_aClients[i].m_Player)
 			{
 				char aTemp[16];
 				str_format(aTemp, sizeof(aTemp), "%d", pSelectedServer->m_aClients[i].m_Score);
-				TextRender()->SetCursor(&Cursor, Score.x, Score.y+(Score.h-FontSize)/2.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
+				TextRender()->SetCursor(&Cursor, Score.x, Score.y+(Score.h-FontSize)/4.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
 				Cursor.m_LineWidth = Score.w;
 				TextRender()->TextEx(&Cursor, aTemp, -1);
 			}
@@ -685,55 +762,108 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
 				TextRender()->TextEx(&Cursor, pClan, -1);
 
 			// flag
-			Graphics()->TextureSet(m_pClient->m_pCountryFlags->Get(pSelectedServer->m_aClients[i].m_Country)->m_Texture);
-			Graphics()->QuadsBegin();
-			Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
-			IGraphics::CQuadItem QuadItem(Flag.x, Flag.y, Flag.w, Flag.h);
-			Graphics()->QuadsDrawTL(&QuadItem, 1);
-			Graphics()->QuadsEnd();
+			vec4 Color(1.0f, 1.0f, 1.0f, 0.5f);
+			m_pClient->m_pCountryFlags->Render(pSelectedServer->m_aClients[i].m_Country, &Color, Flag.x, Flag.y, Flag.w, Flag.h);
 		}
 	}
 }
 
+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);
@@ -768,10 +898,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();
 		}
 	}
@@ -910,6 +1041,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);