TrinityCore
ArenaTeam.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "ArenaTeam.h"
19#include "ArenaTeamMgr.h"
20#include "CharacterCache.h"
21#include "DatabaseEnv.h"
22#include "Group.h"
23#include "Log.h"
24#include "Map.h"
25#include "ObjectAccessor.h"
26#include "ObjectMgr.h"
27#include "Player.h"
28#include "World.h"
29#include "WorldPacket.h"
30#include "WorldSession.h"
31
33 : TeamId(0), Type(0), TeamName(), CaptainGuid(), BackgroundColor(0), EmblemStyle(0), EmblemColor(0),
34 BorderStyle(0), BorderColor(0)
35{
36 Stats.WeekGames = 0;
37 Stats.SeasonGames = 0;
38 Stats.Rank = 0;
39 Stats.Rating = sWorld->getIntConfig(CONFIG_ARENA_START_RATING);
40 Stats.WeekWins = 0;
41 Stats.SeasonWins = 0;
42}
43
45{ }
46
47bool ArenaTeam::Create(ObjectGuid captainGuid, uint8 type, std::string const& teamName, uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor)
48{
49 // Check if captain exists
50 if (!sCharacterCache->GetCharacterCacheByGuid(captainGuid))
51 return false;
52
53 // Check if arena team name is already taken
54 if (sArenaTeamMgr->GetArenaTeamByName(teamName))
55 return false;
56
57 // Generate new arena team id
58 TeamId = sArenaTeamMgr->GenerateArenaTeamId();
59
60 // Assign member variables
61 CaptainGuid = captainGuid;
62 Type = type;
63 TeamName = teamName;
64 BackgroundColor = backgroundColor;
65 EmblemStyle = emblemStyle;
66 EmblemColor = emblemColor;
67 BorderStyle = borderStyle;
68 BorderColor = borderColor;
69 ObjectGuid::LowType captainLowGuid = captainGuid.GetCounter();
70
71 // Save arena team to db
73 stmt->setUInt32(0, TeamId);
74 stmt->setString(1, TeamName);
75 stmt->setUInt64(2, captainLowGuid);
76 stmt->setUInt8(3, Type);
77 stmt->setUInt16(4, Stats.Rating);
78 stmt->setUInt32(5, BackgroundColor);
79 stmt->setUInt8(6, EmblemStyle);
80 stmt->setUInt32(7, EmblemColor);
81 stmt->setUInt8(8, BorderStyle);
82 stmt->setUInt32(9, BorderColor);
83 CharacterDatabase.Execute(stmt);
84
85 // Add captain as member
87
88 TC_LOG_DEBUG("bg.arena", "New ArenaTeam created [Id: {}, Name: {}] [Type: {}] [Captain low GUID: {}]", GetId(), GetName(), GetType(), captainLowGuid);
89 return true;
90}
91
93{
94 std::string playerName;
95 uint8 playerClass;
96
97 // Check if arena team is full (Can't have more than type * 2 players)
98 if (GetMembersSize() >= GetType() * 2)
99 return false;
100
101 // Get player name and class either from db or character cache
102 Player* player = ObjectAccessor::FindPlayer(playerGuid);
103 if (player)
104 {
105 playerClass = player->GetClass();
106 playerName = player->GetName();
107 }
108 else if (CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(playerGuid))
109 {
110 playerName = characterInfo->Name;
111 playerClass = characterInfo->Class;
112 }
113 else
114 return false;
115
116 // Check if player is already in a similar arena team
117 if ((player && player->GetArenaTeamId(GetSlot())) || sCharacterCache->GetCharacterArenaTeamIdByGuid(playerGuid, GetType()) != 0)
118 {
119 TC_LOG_DEBUG("bg.arena", "Arena: {} {} already has an arena team of type {}", playerGuid.ToString(), playerName, GetType());
120 return false;
121 }
122
123 // Set player's personal rating
124 uint16 personalRating = 0;
125
126 if (sWorld->getIntConfig(CONFIG_ARENA_START_PERSONAL_RATING) > 0)
127 personalRating = uint16(sWorld->getIntConfig(CONFIG_ARENA_START_PERSONAL_RATING));
128 else if (GetRating() >= 1000)
129 personalRating = 1000;
130
131 // Try to get player's match maker rating from db and fall back to config setting if not found
133 stmt->setUInt64(0, playerGuid.GetCounter());
134 stmt->setUInt8(1, GetSlot());
135 PreparedQueryResult result = CharacterDatabase.Query(stmt);
136
137 uint32 matchMakerRating;
138 if (result)
139 matchMakerRating = (*result)[0].GetUInt16();
140 else
141 matchMakerRating = sWorld->getIntConfig(CONFIG_ARENA_START_MATCHMAKER_RATING);
142
143 // Remove all player signatures from other petitions
144 // This will prevent player from joining too many arena teams and corrupt arena team data integrity
145 //Player::RemovePetitionsAndSigns(playerGuid, static_cast<CharterTypes>(GetType())); /// @todo arena teams removed in 5.4
146
147 // Feed data to the struct
148 ArenaTeamMember newMember;
149 newMember.Name = playerName;
150 newMember.Guid = playerGuid;
151 newMember.Class = playerClass;
152 newMember.SeasonGames = 0;
153 newMember.WeekGames = 0;
154 newMember.SeasonWins = 0;
155 newMember.WeekWins = 0;
156 newMember.PersonalRating = personalRating;
157 newMember.MatchMakerRating = matchMakerRating;
158
159 Members.push_back(newMember);
160 sCharacterCache->UpdateCharacterArenaTeamId(playerGuid, GetSlot(), GetId());
161
162 // Save player's arena team membership to db
163 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_ARENA_TEAM_MEMBER);
164 stmt->setUInt32(0, TeamId);
165 stmt->setUInt64(1, playerGuid.GetCounter());
166 stmt->setUInt16(2, personalRating);
167 CharacterDatabase.Execute(stmt);
168
169 // Inform player if online
170 if (player)
171 {
172 player->SetInArenaTeam(TeamId, GetSlot(), GetType());
173 player->SetArenaTeamIdInvited(0);
174
175 // Hide promote/remove buttons
176 if (CaptainGuid != playerGuid)
178 }
179
180 TC_LOG_DEBUG("bg.arena", "Player: {} [{}] joined arena team type: {} [Id: {}, Name: {}].", playerName, playerGuid.ToString(), GetType(), GetId(), GetName());
181
182 return true;
183}
184
186{
187 if (!result)
188 return false;
189
190 Field* fields = result->Fetch();
191
192 TeamId = fields[0].GetUInt32();
193 TeamName = fields[1].GetString();
194 CaptainGuid = ObjectGuid::Create<HighGuid::Player>(fields[2].GetUInt64());
195 Type = fields[3].GetUInt8();
196 BackgroundColor = fields[4].GetUInt32();
197 EmblemStyle = fields[5].GetUInt8();
198 EmblemColor = fields[6].GetUInt32();
199 BorderStyle = fields[7].GetUInt8();
200 BorderColor = fields[8].GetUInt32();
201 Stats.Rating = fields[9].GetUInt16();
202 Stats.WeekGames = fields[10].GetUInt16();
203 Stats.WeekWins = fields[11].GetUInt16();
204 Stats.SeasonGames = fields[12].GetUInt16();
205 Stats.SeasonWins = fields[13].GetUInt16();
206 Stats.Rank = fields[14].GetUInt32();
207
208 return true;
209}
210
212{
213 if (!result)
214 return false;
215
216 bool captainPresentInTeam = false;
217
218 do
219 {
220 Field* fields = result->Fetch();
221
222 // Prevent crash if db records are broken when all members in result are already processed and current team doesn't have any members
223 if (!fields)
224 break;
225
226 uint32 arenaTeamId = fields[0].GetUInt32();
227
228 // We loaded all members for this arena_team already, break cycle
229 if (arenaTeamId > TeamId)
230 break;
231
232 ArenaTeamMember newMember;
233 newMember.Guid = ObjectGuid::Create<HighGuid::Player>(fields[1].GetUInt64());
234 newMember.WeekGames = fields[2].GetUInt16();
235 newMember.WeekWins = fields[3].GetUInt16();
236 newMember.SeasonGames = fields[4].GetUInt16();
237 newMember.SeasonWins = fields[5].GetUInt16();
238 newMember.Name = fields[6].GetString();
239 newMember.Class = fields[7].GetUInt8();
240 newMember.PersonalRating = fields[8].GetUInt16();
241 newMember.MatchMakerRating = fields[9].GetUInt16() > 0 ? fields[9].GetUInt16() : sWorld->getIntConfig(CONFIG_ARENA_START_MATCHMAKER_RATING);
242
243 // Delete member if character information is missing
244 if (newMember.Name.empty())
245 {
246 TC_LOG_ERROR("sql.sql", "ArenaTeam {} has member with empty name - probably {} doesn't exist, deleting him from memberlist!", arenaTeamId, newMember.Guid.ToString());
247 DelMember(newMember.Guid, true);
248 continue;
249 }
250
251 // Check if team team has a valid captain
252 if (newMember.Guid == GetCaptain())
253 captainPresentInTeam = true;
254
255 // Put the player in the team
256 Members.push_back(newMember);
257 sCharacterCache->UpdateCharacterArenaTeamId(newMember.Guid, GetSlot(), GetId());
258 }
259 while (result->NextRow());
260
261 if (Empty() || !captainPresentInTeam)
262 {
263 // Arena team is empty or captain is not in team, delete from db
264 TC_LOG_DEBUG("bg.arena", "ArenaTeam {} does not have any members or its captain is not in team, disbanding it...", TeamId);
265 return false;
266 }
267
268 return true;
269}
270
271bool ArenaTeam::SetName(std::string const& name)
272{
273 if (TeamName == name || name.empty() || name.length() > 24 || sObjectMgr->IsReservedName(name) || !ObjectMgr::IsValidCharterName(name))
274 return false;
275
276 TeamName = name;
278 stmt->setString(0, TeamName);
279 stmt->setUInt32(1, GetId());
280 CharacterDatabase.Execute(stmt);
281 return true;
282}
283
285{
286 // Disable remove/promote buttons
288 if (oldCaptain)
290
291 // Set new captain
292 CaptainGuid = guid;
293
294 // Update database
296 stmt->setUInt64(0, guid.GetCounter());
297 stmt->setUInt32(1, GetId());
298 CharacterDatabase.Execute(stmt);
299
300 // Enable remove/promote buttons
301 if (Player* newCaptain = ObjectAccessor::FindPlayer(guid))
302 {
303 newCaptain->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_MEMBER, 0);
304 if (oldCaptain)
305 {
306 TC_LOG_DEBUG("bg.arena", "Player: {} {} promoted player: {} {} to leader of arena team [Id: {}, Name: {}] [Type: {}].",
307 oldCaptain->GetName(), oldCaptain->GetGUID().ToString(), newCaptain->GetName(),
308 newCaptain->GetGUID().ToString(), GetId(), GetName(), GetType());
309 }
310 }
311}
312
313void ArenaTeam::DelMember(ObjectGuid guid, bool cleanDb)
314{
315 // Remove member from team
316 for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
317 {
318 if (itr->Guid == guid)
319 {
320 Members.erase(itr);
321 sCharacterCache->UpdateCharacterArenaTeamId(guid, GetSlot(), 0);
322 break;
323 }
324 }
325
326 // Remove arena team info from player data
327 if (Player* player = ObjectAccessor::FindPlayer(guid))
328 {
329 // delete all info regarding this team
330 for (uint32 i = 0; i < ARENA_TEAM_END; ++i)
331 player->SetArenaTeamInfoField(GetSlot(), ArenaTeamInfoType(i), 0);
332 TC_LOG_DEBUG("bg.arena", "Player: {} {} left arena team type: {} [Id: {}, Name: {}].", player->GetName(), player->GetGUID().ToString(), GetType(), GetId(), GetName());
333 }
334
335 // Only used for single member deletion, for arena team disband we use a single query for more efficiency
336 if (cleanDb)
337 {
339 stmt->setUInt32(0, GetId());
340 stmt->setUInt64(1, guid.GetCounter());
341 CharacterDatabase.Execute(stmt);
342 }
343}
344
346{
347 // Broadcast update
348 if (session)
349 {
350 if (Player* player = session->GetPlayer())
351 TC_LOG_DEBUG("bg.arena", "Player: {} {} disbanded arena team type: {} [Id: {}, Name: {}].", player->GetName(), player->GetGUID().ToString(), GetType(), GetId(), GetName());
352 }
353
354 // Remove all members from arena team
355 while (!Members.empty())
356 DelMember(Members.front().Guid, false);
357
358 // Update database
359 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
360
362 stmt->setUInt32(0, TeamId);
363 trans->Append(stmt);
364
365 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARENA_TEAM_MEMBERS);
366 stmt->setUInt32(0, TeamId);
367 trans->Append(stmt);
368
369 CharacterDatabase.CommitTransaction(trans);
370
371 // Remove arena team from ArenaTeamMgr
372 sArenaTeamMgr->RemoveArenaTeam(TeamId);
373}
374
376{
377 // Remove all members from arena team
378 while (!Members.empty())
379 DelMember(Members.front().Guid, false);
380
381 // Update database
382 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
383
385 stmt->setUInt32(0, TeamId);
386 trans->Append(stmt);
387
388 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ARENA_TEAM_MEMBERS);
389 stmt->setUInt32(0, TeamId);
390 trans->Append(stmt);
391
392 CharacterDatabase.CommitTransaction(trans);
393
394 // Remove arena team from ArenaTeamMgr
395 sArenaTeamMgr->RemoveArenaTeam(TeamId);
396}
397
399{
401 data << uint32(GetId()); // team id
402 data << uint32(Stats.Rating); // rating
403 data << uint32(Stats.WeekGames); // games this week
404 data << uint32(Stats.WeekWins); // wins this week
405 data << uint32(Stats.SeasonGames); // played this season
406 data << uint32(Stats.SeasonWins); // wins this season
407 data << uint32(Stats.Rank); // rank
408 session->SendPacket(&data);
409}
410
412{
413 // This is called after a rated match ended
414 // Updates arena team stats for every member of the team (not only the ones who participated!)
415 for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
416 if (Player* player = ObjectAccessor::FindConnectedPlayer(itr->Guid))
417 SendStats(player->GetSession());
418}
419
421{
422 ArenaTeamMember* member = GetMember(guid);
423 if (!member)
424 return;
425
426 //WorldPacket data(MSG_INSPECT_ARENA_TEAMS, 8+1+4*6);
427 //data << guid; // player guid
428 //data << uint8(GetSlot()); // slot (0...2)
429 //data << uint32(GetId()); // arena team id
430 //data << uint32(Stats.Rating); // rating
431 //data << uint32(Stats.SeasonGames); // season played
432 //data << uint32(Stats.SeasonWins); // season wins
433 //data << uint32(member->SeasonGames); // played (count of all games, that the inspected member participated...)
434 //data << uint32(member->PersonalRating); // personal rating
435 //session->SendPacket(&data);
436}
437
439{
440 if (int32(PersonalRating) + mod < 0)
441 PersonalRating = 0;
442 else
443 PersonalRating += mod;
444
445 if (player)
446 {
449 }
450}
451
453{
454 if (int32(MatchMakerRating) + mod < 0)
456 else
457 MatchMakerRating += mod;
458}
459
461{
462 for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
463 if (Player* player = ObjectAccessor::FindConnectedPlayer(itr->Guid))
464 player->SendDirectMessage(packet);
465}
466
468{
469 switch (type)
470 {
471 case ARENA_TEAM_2v2: return 0;
472 case ARENA_TEAM_3v3: return 1;
473 case ARENA_TEAM_5v5: return 2;
474 default:
475 break;
476 }
477 TC_LOG_ERROR("bg.arena", "FATAL: Unknown arena team type {} for some arena team", type);
478 return 0xFF;
479}
480
482{
483 switch (slot)
484 {
485 case 0: return ARENA_TEAM_2v2;
486 case 1: return ARENA_TEAM_3v3;
487 case 2: return ARENA_TEAM_5v5;
488 default:
489 break;
490 }
491 TC_LOG_ERROR("bg.arena", "FATAL: Unknown arena team slot {} for some arena team", slot);
492 return 0xFF;
493}
494
496{
497 for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
498 if (itr->Guid == guid)
499 return true;
500
501 return false;
502}
503
505{
506 if (!group)
507 return 0;
508
509 uint32 matchMakerRating = 0;
510 uint32 playerDivider = 0;
511 for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
512 {
513 // Skip if player is not online
515 continue;
516
517 // Skip if player is not a member of group
518 if (!group->IsMember(itr->Guid))
519 continue;
520
521 matchMakerRating += itr->MatchMakerRating;
522 ++playerDivider;
523 }
524
525 // x/0 = crash
526 if (playerDivider == 0)
527 playerDivider = 1;
528
529 matchMakerRating /= playerDivider;
530
531 return matchMakerRating;
532}
533
534float ArenaTeam::GetChanceAgainst(uint32 ownRating, uint32 opponentRating)
535{
536 // Returns the chance to win against a team with the given rating, used in the rating adjustment calculation
537 // ELO system
538 return 1.0f / (1.0f + std::exp(std::log(10.0f) * (float(opponentRating) - float(ownRating)) / 650.0f));
539}
540
541int32 ArenaTeam::GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won)
542{
543 // 'Chance' calculation - to beat the opponent
544 // This is a simulation. Not much info on how it really works
545 float chance = GetChanceAgainst(ownRating, opponentRating);
546 float won_mod = (won) ? 1.0f : 0.0f;
547 float mod = won_mod - chance;
548
549 // Work in progress:
550 /*
551 // This is a simulation, as there is not much info on how it really works
552 float confidence_mod = min(1.0f - fabs(mod), 0.5f);
553
554 // Apply confidence factor to the mod:
555 mod *= confidence_factor
556
557 // And only after that update the new confidence factor
558 confidence_factor -= ((confidence_factor - 1.0f) * confidence_mod) / confidence_factor;
559 */
560
561 // Real rating modification
562 mod *= sWorld->getFloatConfig(CONFIG_ARENA_MATCHMAKER_RATING_MODIFIER);
563
564 return (int32)ceil(mod);
565}
566
567int32 ArenaTeam::GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won /*, float confidence_factor*/)
568{
569 // 'Chance' calculation - to beat the opponent
570 // This is a simulation. Not much info on how it really works
571 float chance = GetChanceAgainst(ownRating, opponentRating);
572
573 // Calculate the rating modification
574 float mod;
575
577 if (won)
578 {
579 if (ownRating < 1300)
580 {
581 float win_rating_modifier1 = sWorld->getFloatConfig(CONFIG_ARENA_WIN_RATING_MODIFIER_1);
582
583 if (ownRating < 1000)
584 mod = win_rating_modifier1 * (1.0f - chance);
585 else
586 mod = ((win_rating_modifier1 / 2.0f) + ((win_rating_modifier1 / 2.0f) * (1300.0f - float(ownRating)) / 300.0f)) * (1.0f - chance);
587 }
588 else
589 mod = sWorld->getFloatConfig(CONFIG_ARENA_WIN_RATING_MODIFIER_2) * (1.0f - chance);
590 }
591 else
592 mod = sWorld->getFloatConfig(CONFIG_ARENA_LOSE_RATING_MODIFIER) * (-chance);
593
594 return (int32)ceil(mod);
595}
596
598{
599 // Rating can only drop to 0
600 if (int32(Stats.Rating) + mod < 0)
601 Stats.Rating = 0;
602 else
603 {
604 Stats.Rating += mod;
605
606 // Check if rating related achivements are met
607 for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
608 if (Player* member = ObjectAccessor::FindConnectedPlayer(itr->Guid))
609 member->UpdateCriteria(CriteriaType::EarnTeamArenaRating, Stats.Rating, Type);
610 }
611
612 // Update number of games played per season or week
613 Stats.WeekGames += 1;
614 Stats.SeasonGames += 1;
615
616 // Update team's rank, start with rank 1 and increase until no team with more rating was found
617 Stats.Rank = 1;
618 for (auto [teamId, team] : sArenaTeamMgr->GetArenaTeams())
619 if (team->GetType() == Type && team->GetStats().Rating > Stats.Rating)
620 ++Stats.Rank;
621}
622
623int32 ArenaTeam::WonAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& ratingChange)
624{
625 // Called when the team has won
626 // Change in Matchmaker rating
627 int32 mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, true);
628
629 // Change in Team Rating
630 ratingChange = GetRatingMod(Stats.Rating, opponentMMRating, true);
631
632 // Modify the team stats accordingly
633 FinishGame(ratingChange);
634
635 // Update number of wins per season and week
636 Stats.WeekWins += 1;
637 Stats.SeasonWins += 1;
638
639 // Return the rating change, used to display it on the results screen
640 return mod;
641}
642
643int32 ArenaTeam::LostAgainst(uint32 ownMMRating, uint32 opponentMMRating, int32& ratingChange)
644{
645 // Called when the team has lost
646 // Change in Matchmaker Rating
647 int32 mod = GetMatchmakerRatingMod(ownMMRating, opponentMMRating, false);
648
649 // Change in Team Rating
650 ratingChange = GetRatingMod(Stats.Rating, opponentMMRating, false);
651
652 // Modify the team stats accordingly
653 FinishGame(ratingChange);
654
655 // return the rating change, used to display it on the results screen
656 return mod;
657}
658
659void ArenaTeam::MemberLost(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange)
660{
661 // Called for each participant of a match after losing
662 for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
663 {
664 if (itr->Guid == player->GetGUID())
665 {
666 // Update personal rating
667 int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, false);
668 itr->ModifyPersonalRating(player, mod, GetType());
669
670 // Update matchmaker rating
671 itr->ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
672
673 // Update personal played stats
674 itr->WeekGames +=1;
675 itr->SeasonGames +=1;
676
677 // update the unit fields
678 player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_GAMES_WEEK, itr->WeekGames);
679 player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_GAMES_SEASON, itr->SeasonGames);
680 return;
681 }
682 }
683}
684
685void ArenaTeam::OfflineMemberLost(ObjectGuid guid, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
686{
687 // Called for offline player after ending rated arena match!
688 for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
689 {
690 if (itr->Guid == guid)
691 {
692 // update personal rating
693 int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, false);
694 itr->ModifyPersonalRating(nullptr, mod, GetType());
695
696 // update matchmaker rating
697 itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot());
698
699 // update personal played stats
700 itr->WeekGames += 1;
701 itr->SeasonGames += 1;
702 return;
703 }
704 }
705}
706
707void ArenaTeam::MemberWon(Player* player, uint32 againstMatchmakerRating, int32 matchmakerRatingChange)
708{
709 // called for each participant after winning a match
710 for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
711 {
712 if (itr->Guid == player->GetGUID())
713 {
714 // update personal rating
715 int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, true);
716 itr->ModifyPersonalRating(player, mod, GetType());
717
718 // update matchmaker rating
719 itr->ModifyMatchmakerRating(matchmakerRatingChange, GetSlot());
720
721 // update personal stats
722 itr->WeekGames +=1;
723 itr->SeasonGames +=1;
724 itr->SeasonWins += 1;
725 itr->WeekWins += 1;
726 // update unit fields
727 player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_GAMES_WEEK, itr->WeekGames);
728 player->SetArenaTeamInfoField(GetSlot(), ARENA_TEAM_GAMES_SEASON, itr->SeasonGames);
729 return;
730 }
731 }
732}
733
734void ArenaTeam::SaveToDB(bool forceMemberSave)
735{
736 // Save team and member stats to db
737 // Called after a match has ended or when calculating arena_points
738
739 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
740
742 stmt->setUInt16(0, Stats.Rating);
743 stmt->setUInt16(1, Stats.WeekGames);
744 stmt->setUInt16(2, Stats.WeekWins);
745 stmt->setUInt16(3, Stats.SeasonGames);
746 stmt->setUInt16(4, Stats.SeasonWins);
747 stmt->setUInt32(5, Stats.Rank);
748 stmt->setUInt32(6, GetId());
749 trans->Append(stmt);
750
751 for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
752 {
753 // Save the effort and go
754 if (itr->WeekGames == 0 && !forceMemberSave)
755 continue;
756
757 stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ARENA_TEAM_MEMBER);
758 stmt->setUInt16(0, itr->PersonalRating);
759 stmt->setUInt16(1, itr->WeekGames);
760 stmt->setUInt16(2, itr->WeekWins);
761 stmt->setUInt16(3, itr->SeasonGames);
762 stmt->setUInt16(4, itr->SeasonWins);
763 stmt->setUInt32(5, GetId());
764 stmt->setUInt64(6, itr->Guid.GetCounter());
765 trans->Append(stmt);
766
767 stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHARACTER_ARENA_STATS);
768 stmt->setUInt64(0, itr->Guid.GetCounter());
769 stmt->setUInt8(1, GetSlot());
770 stmt->setUInt16(2, itr->MatchMakerRating);
771 trans->Append(stmt);
772 }
773
774 CharacterDatabase.CommitTransaction(trans);
775}
776
778{
779 // No need to go further than this
780 if (Stats.WeekGames == 0)
781 return false;
782
783 // Reset team stats
784 Stats.WeekGames = 0;
785 Stats.WeekWins = 0;
786
787 // Reset member stats
788 for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
789 {
790 itr->WeekGames = 0;
791 itr->WeekWins = 0;
792 }
793
794 return true;
795}
796
798{
799 for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr)
800 if (Player* player = ObjectAccessor::FindPlayer(itr->Guid))
801 if (player->GetMap()->IsBattleArena())
802 return true;
803
804 return false;
805}
806
807ArenaTeamMember* ArenaTeam::GetMember(const std::string& name)
808{
809 for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
810 if (itr->Name == name)
811 return &(*itr);
812
813 return nullptr;
814}
815
817{
818 for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
819 if (itr->Guid == guid)
820 return &(*itr);
821
822 return nullptr;
823}
#define sArenaTeamMgr
Definition: ArenaTeamMgr.h:53
@ ARENA_TEAM_5v5
Definition: ArenaTeam.h:80
@ ARENA_TEAM_2v2
Definition: ArenaTeam.h:78
@ ARENA_TEAM_3v3
Definition: ArenaTeam.h:79
#define sCharacterCache
@ CHAR_DEL_ARENA_TEAM_MEMBERS
@ CHAR_DEL_ARENA_TEAM
@ CHAR_UPD_ARENA_TEAM_STATS
@ CHAR_INS_ARENA_TEAM_MEMBER
@ CHAR_REP_CHARACTER_ARENA_STATS
@ CHAR_UPD_ARENA_TEAM_MEMBER
@ CHAR_SEL_MATCH_MAKER_RATING
@ CHAR_UPD_ARENA_TEAM_NAME
@ CHAR_UPD_ARENA_TEAM_CAPTAIN
@ CHAR_INS_ARENA_TEAM
@ CHAR_DEL_ARENA_TEAM_MEMBER
@ EarnPersonalArenaRating
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< ResultSet > QueryResult
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
Definition: DatabaseEnv.cpp:21
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
#define TC_LOG_DEBUG(filterType__,...)
Definition: Log.h:156
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
#define sObjectMgr
Definition: ObjectMgr.h:1946
ArenaTeamInfoType
Definition: Player.h:788
@ ARENA_TEAM_GAMES_WEEK
Definition: Player.h:792
@ ARENA_TEAM_END
Definition: Player.h:796
@ ARENA_TEAM_PERSONAL_RATING
Definition: Player.h:795
@ ARENA_TEAM_MEMBER
Definition: Player.h:791
@ ARENA_TEAM_GAMES_SEASON
Definition: Player.h:793
TeamId
Stats
void SaveToDB(bool forceMemberSave=false)
Definition: ArenaTeam.cpp:734
uint32 EmblemColor
Definition: ArenaTeam.h:184
ObjectGuid CaptainGuid
Definition: ArenaTeam.h:180
void Inspect(WorldSession *session, ObjectGuid guid)
Definition: ArenaTeam.cpp:420
bool Empty() const
Definition: ArenaTeam.h:141
ObjectGuid GetCaptain() const
Definition: ArenaTeam.h:128
uint32 GetRating() const
Definition: ArenaTeam.h:132
bool LoadArenaTeamFromDB(QueryResult arenaTeamDataResult)
Definition: ArenaTeam.cpp:185
void OfflineMemberLost(ObjectGuid guid, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange=-12)
Definition: ArenaTeam.cpp:685
int32 LostAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32 &rating_change)
Definition: ArenaTeam.cpp:643
float GetChanceAgainst(uint32 ownRating, uint32 opponentRating)
Definition: ArenaTeam.cpp:534
uint32 BorderColor
Definition: ArenaTeam.h:186
int32 GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won)
Definition: ArenaTeam.cpp:567
size_t GetMembersSize() const
Definition: ArenaTeam.h:140
void DelMember(ObjectGuid guid, bool cleanDb)
Definition: ArenaTeam.cpp:313
void MemberLost(Player *player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange=-12)
Definition: ArenaTeam.cpp:659
bool IsMember(ObjectGuid guid) const
Definition: ArenaTeam.cpp:495
uint8 Type
Definition: ArenaTeam.h:178
bool SetName(std::string const &name)
Definition: ArenaTeam.cpp:271
uint8 EmblemStyle
Definition: ArenaTeam.h:183
bool FinishWeek()
Definition: ArenaTeam.cpp:777
bool Create(ObjectGuid captainGuid, uint8 type, std::string const &teamName, uint32 backgroundColor, uint8 emblemStyle, uint32 emblemColor, uint8 borderStyle, uint32 borderColor)
Definition: ArenaTeam.cpp:47
uint8 BorderStyle
Definition: ArenaTeam.h:185
int32 GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won)
Definition: ArenaTeam.cpp:541
void SendStats(WorldSession *session)
Definition: ArenaTeam.cpp:398
int32 WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32 &rating_change)
Definition: ArenaTeam.cpp:623
uint8 GetSlot() const
Definition: ArenaTeam.h:125
void SetCaptain(ObjectGuid guid)
Definition: ArenaTeam.cpp:284
bool AddMember(ObjectGuid PlayerGuid)
Definition: ArenaTeam.cpp:92
ArenaTeamMember * GetMember(ObjectGuid guid)
Definition: ArenaTeam.cpp:816
void FinishGame(int32 mod)
Definition: ArenaTeam.cpp:597
uint32 GetType() const
Definition: ArenaTeam.h:124
std::string TeamName
Definition: ArenaTeam.h:179
MemberList Members
Definition: ArenaTeam.h:188
void NotifyStatsChanged()
Definition: ArenaTeam.cpp:411
uint32 BackgroundColor
Definition: ArenaTeam.h:182
void BroadcastPacket(WorldPacket *packet)
Definition: ArenaTeam.cpp:460
void Disband()
Definition: ArenaTeam.cpp:375
uint32 GetAverageMMR(Group *group) const
Definition: ArenaTeam.cpp:504
bool IsFighting() const
Definition: ArenaTeam.cpp:797
std::string const & GetName() const
Definition: ArenaTeam.h:129
static uint8 GetTypeBySlot(uint8 slot)
Definition: ArenaTeam.cpp:481
bool LoadMembersFromDB(QueryResult arenaTeamMembersResult)
Definition: ArenaTeam.cpp:211
uint32 GetId() const
Definition: ArenaTeam.h:123
void MemberWon(Player *player, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
Definition: ArenaTeam.cpp:707
static uint8 GetSlotByType(uint32 type)
Definition: ArenaTeam.cpp:467
Class used to access individual fields of database query result.
Definition: Field.h:90
uint8 GetUInt8() const
Definition: Field.cpp:30
std::string GetString() const
Definition: Field.cpp:118
uint16 GetUInt16() const
Definition: Field.cpp:46
uint32 GetUInt32() const
Definition: Field.cpp:62
Definition: Group.h:197
bool IsMember(ObjectGuid guid) const
Definition: Group.cpp:1695
LowType GetCounter() const
Definition: ObjectGuid.h:293
std::string ToString() const
Definition: ObjectGuid.cpp:554
uint64 LowType
Definition: ObjectGuid.h:278
static bool IsValidCharterName(std::string_view name)
Definition: ObjectMgr.cpp:8712
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
void SetArenaTeamInfoField(uint8 slot, ArenaTeamInfoType type, uint32 value)
Definition: Player.cpp:7435
void SetInArenaTeam(uint32 ArenaTeamId, uint8 slot, uint8 type)
Definition: Player.cpp:7439
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
void SetArenaTeamIdInvited(uint32 ArenaTeamId)
Definition: Player.h:2006
uint32 GetArenaTeamId(uint8) const
Definition: Player.h:2004
void setUInt8(const uint8 index, const uint8 value)
void setUInt32(const uint8 index, const uint32 value)
void setUInt16(const uint8 index, const uint16 value)
void setString(const uint8 index, const std::string &value)
void setUInt64(const uint8 index, const uint64 value)
uint8 GetClass() const
Definition: Unit.h:752
std::string const & GetName() const
Definition: Object.h:555
Player session in the World.
Definition: WorldSession.h:963
Player * GetPlayer() const
void SendPacket(WorldPacket const *packet, bool forced=false)
Send a packet to the client.
@ SMSG_ARENA_TEAM_STATS
Definition: Opcodes.h:2090
#define sWorld
Definition: World.h:931
@ CONFIG_ARENA_START_MATCHMAKER_RATING
Definition: World.h:350
@ CONFIG_ARENA_START_RATING
Definition: World.h:348
@ CONFIG_ARENA_START_PERSONAL_RATING
Definition: World.h:349
@ CONFIG_ARENA_WIN_RATING_MODIFIER_1
Definition: World.h:219
@ CONFIG_ARENA_WIN_RATING_MODIFIER_2
Definition: World.h:220
@ CONFIG_ARENA_LOSE_RATING_MODIFIER
Definition: World.h:221
@ CONFIG_ARENA_MATCHMAKER_RATING_MODIFIER
Definition: World.h:222
TC_GAME_API Player * FindPlayer(ObjectGuid const &)
TC_GAME_API Player * FindConnectedPlayer(ObjectGuid const &)
uint16 PersonalRating
Definition: ArenaTeam.h:92
void ModifyPersonalRating(Player *player, int32 mod, uint32 type)
Definition: ArenaTeam.cpp:438
uint16 WeekWins
Definition: ArenaTeam.h:89
uint16 SeasonWins
Definition: ArenaTeam.h:91
std::string Name
Definition: ArenaTeam.h:86
uint16 WeekGames
Definition: ArenaTeam.h:88
void ModifyMatchmakerRating(int32 mod, uint32 slot)
Definition: ArenaTeam.cpp:452
ObjectGuid Guid
Definition: ArenaTeam.h:85
uint16 MatchMakerRating
Definition: ArenaTeam.h:93
uint16 SeasonGames
Definition: ArenaTeam.h:90