• This is a read only backup of the old Emudevs forum. If you want to have anything removed, please message me on Discord: KittyKaev

Arena teams 2v2, 3v3 and 5v5 stats viewer

Jameyboor

Retired Staff
Good day everyone,

I realized that I did not release anything recently, that's why I made this arena stats viewer.

The npc can show :
the arena stats of a specific player.
the arena stats of a specific team.
the top 10 arena stats per arena type.


there are even some booleans that you can set to your preferences :
Code:
const bool INFO_VIA_GOSSIP = true;
const bool USE_QUERIES = true;
INFO_VIA_GOSSIP:
if set to true, the info will be displayed in a gossip menu ( like in the screenshots ), if set to false, it will be displayed through the whispering of the npc.
USE_QUERIES:
if set to true, the script is allowed to use SQL queries to make the script more functional, if you have some kind of crappy VPS this could lead to a bit lag, that's why I made an option to turn it off ( set to false ), if set to false, some function will not work anymore, like checking the arena stats of a player that is offline, the npc will then just notify that the player is offline instead of showing the stats.

I've tested some options and they all seem to work, but as always, please report any bugs you might encounter when using this npc, here is the code:
Code:
/*
*╔═╦═╦═╦╦╦══╦═╦╗─╔╦══╗ 
*║╦╣║║║║║╠╗╗║╦╣╚╦╝║══╣
*║╩╣║║║║║╠╩╝║╩╬╗║╔╬══║
*╚═╩╩═╩╩═╩══╩═╝╚═╝╚══╝
*           (http://emudevs.com)
*/

#include "ScriptPCH.h"
#include "ArenaTeamMgr.h"
#include "ArenaTeam.h"

#pragma warning(disable:4018)

const bool INFO_VIA_GOSSIP = true;
const bool USE_QUERIES = true;

typedef std::vector<ArenaTeam*> RankingContainer;

bool order(ArenaTeam* &a, ArenaTeam* &b)
{
	return a->GetStats().Rating > b->GetStats().Rating;
}

std::string GetTypeAsString(uint32 type)
{
	if(type == 2)
		return "2v2";
	else if(type == 3)
		return "3v3";
	return "5v5";
}

void SendTeamInfo(Player* player, Creature* creature, const char* code)
{
	ArenaTeam* team = sArenaTeamMgr->GetArenaTeamByName(code);
	if(!team)
	{
		player->GetSession()->SendNotification("That team does not exist");
		player->PlayerTalkClass->SendCloseGossip();
		return;
	}

	std::ostringstream info;

	info << "Team " << team->GetName() << ", type : " << GetTypeAsString(team->GetType()) << ", arena info : \n";
	INFO_VIA_GOSSIP ? player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, info.str().c_str(), GOSSIP_SENDER_MAIN, 0) : creature->MonsterWhisper(info.str().c_str(), player->GetGUID());
	info.str("");
	info.clear();

	uint32 rank          = team->GetStats().Rank;
	uint32 rating        = team->GetStats().Rating;

	uint32 weekGames     = team->GetStats().WeekGames;
	uint32 weekWins      = team->GetStats().WeekWins;
	uint32 weekLosses    = weekGames - weekWins;

	uint32 seasonGames   = team->GetStats().SeasonGames;
	uint32 seasonWins    = team->GetStats().SeasonWins;
	uint32 seasonLosses  = seasonGames - seasonWins;

	Player* captain = ObjectAccessor::FindPlayer(team->GetCaptain());
	std::string captainName;
	bool captainValid;

	if(!captain || !captain->GetSession())
	{
		if(USE_QUERIES)
		{
			QueryResult result = CharacterDatabase.PQuery("SELECT `name` FROM `characters` WHERE `guid` = %u", team->GetCaptain());
			if(result)
			{
				Field* fields = result->Fetch();
				captainName = fields[0].GetString();
				captainValid = true;
			}
		}
		else
			captainValid = false;
	}
	else
	{
		captainName = captain->GetName();
		captainValid = true;
	}


	info << "Rank : " << (uint16)rank;
	if(captainValid) info << "\nCaptain Name : " << captainName;
	info << "\nRating : " << (uint32)rating
		<< "\nMembers : ";

	for(ArenaTeam::MemberList::iterator itr = team->m_membersBegin(); itr != team->m_membersEnd(); ++itr)
	{
		info << itr->Name;
		if(std::distance(team->m_membersBegin(), itr) < team->GetType() -1 )
			info << ", ";
	}
	info << "\nWeek Games : "
		<< (uint32)weekGames << ", Wins : " << (uint32)weekWins << ", Losses : " << (uint32)weekLosses
	    << "\nSeason Games : "
		<< (uint32)seasonGames << ", Wins : " << (uint32)seasonWins << ", Losses : " << (uint32)seasonLosses;

	INFO_VIA_GOSSIP ? player->ADD_GOSSIP_ITEM(0, info.str().c_str(), GOSSIP_SENDER_MAIN, 0) : creature->MonsterWhisper(info.str().c_str(), player->GetGUID());

	if(INFO_VIA_GOSSIP)
		player->SEND_GOSSIP_MENU(907, creature->GetGUID());
}

void SendSoloInfo(Player* player, Creature* creature, uint32 teamId, uint64 target, uint32 type)
{
	std::ostringstream info;
	info << "Player : " << player->GetName() << ", type : " << GetTypeAsString(type) << ", arena info : \n";
	INFO_VIA_GOSSIP ? player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, info.str().c_str(), GOSSIP_SENDER_MAIN, 0) : creature->MonsterWhisper(info.str().c_str(), player->GetGUID());
	info.str("");
	info.clear();
	ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId);
	info << "Player stats : \n";
	for(ArenaTeam::MemberList::iterator itr = team->m_membersBegin(); itr != team->m_membersEnd(); ++itr)
	{
		if(target == itr->Guid)
		{
			std::ostringstream ss;

			std::string name      = itr->Name;
			std::string teamName  = team->GetName();
			uint32 MMR            = itr->MatchMakerRating;
			uint32 personalRating = itr->PersonalRating;

			uint32 seasonGames    = itr->SeasonGames;
			uint32 seasonWins     = itr->SeasonWins;
			uint32 seasonLosses   = seasonGames - seasonWins;

			uint32 weekGames      = itr->WeekGames;
			uint32 weekWins       = itr->WeekWins;
			uint32 weekLosses     = weekGames - weekWins;

			ss << "Name : " << name  << "\nTeam Name : " << teamName << "\nMatchMaker Rating : " << (uint32)MMR << "\nPersonal Rating : " 
				<< (uint32)personalRating << "\nSeason Games : " << (uint32)seasonGames
				<< "\nSeason Wins : " << (uint32)seasonWins << "\nSeason Losses : " << (uint32)seasonLosses << "\nWeek Games : " 
				<< (uint32)weekGames << "\nWeek Wins : " << (uint32)weekWins
				<< "\nWeek Losses : " << (uint32)weekLosses << "\n\n";

			INFO_VIA_GOSSIP ? player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, ss.str().c_str(), GOSSIP_SENDER_MAIN, 0) : creature->MonsterWhisper(ss.str().c_str(), player->GetGUID());
		}

	}


	if(INFO_VIA_GOSSIP)
		player->SEND_GOSSIP_MENU(907, creature->GetGUID());
}

void SendTopInfo(Player* player, Creature* creature, RankingContainer RankingHolder, uint32 type)
{
	std::ostringstream info;
	info << "Top 10 " << GetTypeAsString(type) << " arena teams: \n\n";
	INFO_VIA_GOSSIP ? player->ADD_GOSSIP_ITEM(0, info.str().c_str(), GOSSIP_SENDER_MAIN, 0) : creature->MonsterWhisper(info.str().c_str(), player->GetGUID());
	uint16 rank = 1;
	for(RankingContainer::iterator itr = RankingHolder.begin(); itr != RankingHolder.end(); ++itr)
	{
		if(rank > 10)
			break;
		std::ostringstream ss;

		std::string teamName    = (*itr)->GetName();

		Player* captain = ObjectAccessor::FindPlayer((*itr)->GetCaptain());
		std::string captainName;
		bool captainValid;

		if(!captain || !captain->GetSession())
		{
			if(USE_QUERIES)
			{
				QueryResult result = CharacterDatabase.PQuery("SELECT `name` FROM `characters` WHERE `guid` = %u", (*itr)->GetCaptain());
				if(result)
				{
					Field* fields = result->Fetch();
					captainName = fields[0].GetString();
					captainValid = true;
				}
			}
			else
				captainValid = false;
		}
		else
		{
			captainName = captain->GetName();
			captainValid = true;
		}

		uint32 rating           = (*itr)->GetRating();
		uint32 seasonGames      = (*itr)->GetStats().SeasonGames;
		uint32 seasonWins       = (*itr)->GetStats().SeasonWins;
		uint32 seasonLosses     = seasonGames - seasonWins;

		ss << "Rank : " << (uint16)rank << "\nTeam Name : " << teamName; 
		if(captainValid) ss << "\nCaptain Name : " << captainName;
		ss << "\nRating : " << (uint32)rating
			<< "\nMembers : ";

		for(ArenaTeam::MemberList::iterator it = (*itr)->m_membersBegin(); it != (*itr)->m_membersEnd(); ++it)
		{
			ss << it->Name;
			if(std::distance((*itr)->m_membersBegin(), it) < type -1 )
				ss << ", ";
		}

		ss << "\nSeason Games : "
			<< (uint32)seasonGames << ", Wins : " << (uint32)seasonWins << ", Losses : " << (uint32)seasonLosses;

		INFO_VIA_GOSSIP ? player->ADD_GOSSIP_ITEM(0, ss.str().c_str(), GOSSIP_SENDER_MAIN, 0) : creature->MonsterWhisper(ss.str().c_str(), player->GetGUID());
		++rank;
	}
	if(rank < 11)
	{
		--rank;
		std::ostringstream ss;
		ss << (uint16)rank << " team(s) displayed, no more available";
		INFO_VIA_GOSSIP ? player->ADD_GOSSIP_ITEM(0, ss.str().c_str(), GOSSIP_SENDER_MAIN, 0) : creature->MonsterWhisper(ss.str().c_str(), player->GetGUID());
	}
	if(INFO_VIA_GOSSIP)
		player->SEND_GOSSIP_MENU(907, creature->GetGUID());
}

void FillAndSortHolder(uint32 type, RankingContainer& RankingHolder)
{
	for(ArenaTeamMgr::ArenaTeamContainer::iterator itr = sArenaTeamMgr->GetArenaTeamMapBegin(); itr != sArenaTeamMgr->GetArenaTeamMapEnd(); ++itr)
	{
		if(itr->second->GetType() != type)
			continue;
		RankingHolder.push_back(itr->second);
	}
	std::sort(RankingHolder.begin(), RankingHolder.end(), order);
}

uint32 GetTeamByDb(uint64 GUID, uint32 type)
{
	QueryResult result = CharacterDatabase.PQuery("SELECT `arenaTeamId` FROM `arena_team_member` WHERE `guid` = %u", GUID);

	if(!result)
		return NULL;

	std::vector<ArenaTeam*> teamIds;

	do{
		Field* fields = result->Fetch();
		teamIds.push_back(sArenaTeamMgr->GetArenaTeamById(fields[0].GetUInt32()));
	}while(result->NextRow());

	for(RankingContainer::iterator itr = teamIds.begin(); itr != teamIds.end(); ++itr)
	{
		if((*itr)->GetType() == type)
			return (*itr)->GetId();
	}
	return NULL;
}

uint32 GetGuidByDb(const char* name)
{
	QueryResult check = CharacterDatabase.PQuery("SELECT `guid` FROM `characters` WHERE `name` = '%s'", name);

	if(!check)
		return NULL;
	Field* fields = check->Fetch();
	return fields[0].GetUInt64();
}

uint32 GetArenaTeamId(uint64 Guid, uint32 type)
{
	Player* player = ObjectAccessor::FindPlayer(Guid);
	if(!player || !player->GetSession())
	{
		if(USE_QUERIES)
			return GetTeamByDb(Guid, type);
		return NULL;
	}
	return player->GetArenaTeamId(ArenaTeam::GetSlotByType(type));
}

bool IsEmptyBracket(uint32 type)
{
	for(ArenaTeamMgr::ArenaTeamContainer::iterator itr = sArenaTeamMgr->GetArenaTeamMapBegin(); itr != sArenaTeamMgr->GetArenaTeamMapEnd(); ++itr)
	{
		if(itr->second->GetType() == type)
			return false;
	}
	return true;
}

void SendOptions(Player* player, Creature* creature, const char* code)
{
	uint64 Guid;
	Player* target = ObjectAccessor::FindPlayerByName(code);

	if(!target || !target->GetSession())
	{
		if(USE_QUERIES)
			Guid = GetGuidByDb(code);
		else
		{
			player->GetSession()->SendNotification("Player does not exist or is offline");
			player->PlayerTalkClass->SendCloseGossip();
			return;
		}
	}
	else
		Guid = target->GetGUID();

	if(!Guid)
	{
		player->GetSession()->SendNotification("Player does not exist");
		player->PlayerTalkClass->SendCloseGossip();
		return;
	}

	if(!GetArenaTeamId(Guid, 2) && !GetArenaTeamId(Guid, 3) && !GetArenaTeamId(Guid, 5))
	{
		player->GetSession()->SendNotification("Player is not in any arena team");
		player->PlayerTalkClass->SendCloseGossip();
		return;
	}

	for(int i = 2; i < 6; ++i)
	{
		if(i == 4)
			continue;

		uint16 action = (i != 5 ? i*2-(i == 3 ? 1 : 0) : i+1);

		if(GetArenaTeamId(Guid, i))
			player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, GetTypeAsString(i), Guid, action);
	}
	player->SEND_GOSSIP_MENU(907, creature->GetGUID());

}

class Top_Arena_View_NPC : public CreatureScript
{
public:
	Top_Arena_View_NPC() : CreatureScript("Arena_NPC") {}

	bool OnGossipHello(Player* player, Creature* creature)
	{
		player->ADD_GOSSIP_ITEM_EXTENDED(0, "Show arena stats of a specific player", GOSSIP_SENDER_MAIN, 1, "Enter the name of the player please", 0, true);
		player->ADD_GOSSIP_ITEM(0, "Show the top 10 arena stats", GOSSIP_SENDER_MAIN, 2);
		player->ADD_GOSSIP_ITEM_EXTENDED(0, "Show arena stats of a specific team", GOSSIP_SENDER_MAIN, 3, "Enter the name of the team please", 0, true);
		player->SEND_GOSSIP_MENU(907, creature->GetGUID());
		return true;
	}

	bool OnGossipSelectCode(Player* player, Creature* creature, uint32 sender, uint32 action, const char* code)
	{
		player->PlayerTalkClass->ClearMenus();
		switch(action)
		{
		case 1:
			SendOptions(player, creature, code);
			return true;
			break;
		case 3:
			SendTeamInfo(player, creature, code);
			return true;
		}
		return true;
	}

	bool OnGossipSelect(Player* player, Creature* creature, uint32 sender, uint32 action)
	{
		player->PlayerTalkClass->ClearMenus();
		switch(action)
		{
		case 2:
			player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, "2v2", GOSSIP_SENDER_MAIN, 7);
			player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, "3v3", GOSSIP_SENDER_MAIN, 8);
			player->ADD_GOSSIP_ITEM(GOSSIP_ICON_BATTLE, "5v5", GOSSIP_SENDER_MAIN, 9);
			player->SEND_GOSSIP_MENU(907, creature->GetGUID());
			break;

			//GetArenaTeamId can't return NULL, already checked in SendOptions, NULL returns will not be displayed in the gossip menu, just send the info.
		case 4:        
			SendSoloInfo(player, creature, GetArenaTeamId(sender, 2), sender, 2);
			break;

		case 5:
			SendSoloInfo(player, creature, GetArenaTeamId(sender, 3), sender, 3);
			break;

		case 6:
			SendSoloInfo(player, creature, GetArenaTeamId(sender, 5), sender, 5);
			break;

		case 7:
			{
				if(IsEmptyBracket(2))
				{
					player->GetSession()->SendNotification("No teams available");
					player->PlayerTalkClass->SendCloseGossip();
					return false;
				}
				RankingContainer Rankingholder;
				FillAndSortHolder(2, Rankingholder); //2v2
				SendTopInfo(player, creature, Rankingholder, 2);
			}break;

		case 8:
			{
				if(IsEmptyBracket(3))
				{
					player->GetSession()->SendNotification("No teams available");
					player->PlayerTalkClass->SendCloseGossip();
					return false;
				}
				RankingContainer Rankingholder;
				FillAndSortHolder(3, Rankingholder); //3v3
				SendTopInfo(player, creature, Rankingholder, 3);
			}break;

		case 9:
			{
				if(IsEmptyBracket(5))
				{
					player->GetSession()->SendNotification("No teams available");
					player->PlayerTalkClass->SendCloseGossip();
					return false;
				}
				RankingContainer Rankingholder;
				FillAndSortHolder(5, Rankingholder); //5v5
				SendTopInfo(player, creature, Rankingholder, 5);
			}break;

		}
		return true;
	}
};
void AddSC_Arena_NPC()
{
	new Top_Arena_View_NPC();
}

some screens of it in action :

9xwb.png

yiwo.png

k1dn.png

9jq.png


IM OUT /tableflip
 
Last edited:

Shadowpower

Enthusiast
Gonna test it now , thank you!

and i got this error

3>..\..\..\..\TrinityCore - Copy\TrinityCore - Copy\src\server\scripts\Custom\toparena.cpp(94): warning C4018: '<' : signed/unsigned mismatch
3>..\..\..\..\TrinityCore - Copy\TrinityCore - Copy\src\server\scripts\Custom\toparena.cpp(204): warning C4018: '<' : signed/unsigned mismatch
 

Jameyboor

Retired Staff
Hmm, apparently the rank does not work as intended as Parranoia already told me, I will edit the system to sort according to rating, and rating alone.
 

Jameyboor

Retired Staff
the top is upside down , rating up when scroll down

As I said, the teams get sorted on rating, and it seems that all of the teams in the screenshot have 1 rating, that's why it does not work properly, can you give me another image with multiple teams that have different rating values so I can be sure to either flag the script as bugged, and fix it or not.
 
Top