Core/Arena: A more accurate implementation of rating gain/loss. This fixes the strange behaviour personal rating could have, as well as implements the bigger rating scale added in patch 3.1.
Fixes #230
This commit is contained in:
@@ -606,27 +606,52 @@ float ArenaTeam::GetChanceAgainst(uint32 ownRating, uint32 opponentRating)
|
||||
{
|
||||
// Returns the chance to win against a team with the given rating, used in the rating adjustment calculation
|
||||
// ELO system
|
||||
return 1.0f / (1.0f + exp(log(10.0f) * (float)((float)opponentRating - (float)ownRating) / 400.0f));
|
||||
return 1.0f / (1.0f + exp(log(10.0f) * (float)((float)opponentRating - (float)ownRating) / 650.0f));
|
||||
}
|
||||
|
||||
int32 ArenaTeam::GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won, bool calculateMatchMakerRating)
|
||||
int32 ArenaTeam::GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won /*, float& confidence_factor*/)
|
||||
{
|
||||
// 'Chance' calculation - to beat the opponent
|
||||
// This is a simulation. Not much info on how it really works
|
||||
float chance = GetChanceAgainst(ownRating, opponentRating);
|
||||
float won_mod = (won) ? 1.0f : 0.0f;
|
||||
float mod = won_mod - chance;
|
||||
|
||||
// Work in progress:
|
||||
/*
|
||||
// This is a simulation, as there is not much info on how it really works
|
||||
float confidence_mod = min(1.0f - fabs(mod), 0.5f);
|
||||
|
||||
// Apply confidence factor to the mod:
|
||||
mod *= confidence_factor
|
||||
|
||||
// And only after that update the new confidence factor
|
||||
confidence_factor -= ((confidence_factor - 1.0f) * confidence_mod) / confidence_factor;
|
||||
*/
|
||||
|
||||
// Real rating modification
|
||||
mod *= 24.0f;
|
||||
|
||||
return (int32)ceil(mod);
|
||||
}
|
||||
|
||||
int32 ArenaTeam::GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won /*, float confidence_factor*/)
|
||||
{
|
||||
// 'Chance' calculation - to beat the opponent
|
||||
// This is a simulation. Not much info on how it really works
|
||||
float chance = GetChanceAgainst(ownRating, opponentRating);
|
||||
float won_mod = (won) ? 1.0f : 0.0f;
|
||||
|
||||
// Calculate the rating modification
|
||||
// Simulation on how it works. Not much info on how it really works
|
||||
float mod;
|
||||
|
||||
if (won && !calculateMatchMakerRating)
|
||||
// TODO: Replace this hack with using the confidence factor (limiting the factor to 2.0f)
|
||||
if (won && ownRating < 1300)
|
||||
{
|
||||
if (ownRating < 1000)
|
||||
mod = 48.0f * (won_mod - chance);
|
||||
else if (ownRating < 1300)
|
||||
mod = (24.0f + (24.0f * (1300.0f - int32(ownRating)) / 300.0f)) * (won_mod - chance);
|
||||
else
|
||||
mod = 24.0f * (won_mod - chance);
|
||||
mod = (24.0f + (24.0f * (1300.0f - float(ownRating)) / 300.0f)) * (won_mod - chance);
|
||||
}
|
||||
else
|
||||
mod = 24.0f * (won_mod - chance);
|
||||
@@ -634,15 +659,6 @@ int32 ArenaTeam::GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won,
|
||||
return (int32)ceil(mod);
|
||||
}
|
||||
|
||||
int32 ArenaTeam::GetPersonalRatingMod(int32 baseRating, uint32 ownRating, uint32 opponentRating)
|
||||
{
|
||||
// Max (2 * team rating gain/loss), min 0 gain/loss
|
||||
float chance = GetChanceAgainst(ownRating, opponentRating);
|
||||
chance *= 2.0f;
|
||||
|
||||
return (int32)ceil(float(baseRating) * chance);
|
||||
}
|
||||
|
||||
void ArenaTeam::FinishGame(int32 mod)
|
||||
{
|
||||
// Rating can only drop to 0
|
||||
@@ -672,14 +688,17 @@ void ArenaTeam::FinishGame(int32 mod)
|
||||
}
|
||||
}
|
||||
|
||||
int32 ArenaTeam::WonAgainst(uint32 againstRating)
|
||||
int32 ArenaTeam::WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change)
|
||||
{
|
||||
// Called when the team has won
|
||||
// Own team rating versus opponents matchmaker rating
|
||||
int32 mod = GetRatingMod(Stats.Rating, againstRating, true);
|
||||
// Change in Matchmaker rating
|
||||
int32 mod = GetMatchmakerRatingMod(Own_MMRating, Opponent_MMRating, true);
|
||||
|
||||
// Change in Team Rating
|
||||
rating_change = GetRatingMod(Stats.Rating, Opponent_MMRating, true);
|
||||
|
||||
// Modify the team stats accordingly
|
||||
FinishGame(mod);
|
||||
FinishGame(rating_change);
|
||||
|
||||
// Update number of wins per season and week
|
||||
Stats.WeekWins += 1;
|
||||
@@ -689,20 +708,23 @@ int32 ArenaTeam::WonAgainst(uint32 againstRating)
|
||||
return mod;
|
||||
}
|
||||
|
||||
int32 ArenaTeam::LostAgainst(uint32 againstRating)
|
||||
int32 ArenaTeam::LostAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change)
|
||||
{
|
||||
// Called when the team has lost
|
||||
// Own team rating versus opponents matchmaker rating
|
||||
int32 mod = GetRatingMod(Stats.Rating, againstRating, false);
|
||||
// Change in Matchmaker Rating
|
||||
int32 mod = GetMatchmakerRatingMod(Own_MMRating, Opponent_MMRating, false);
|
||||
|
||||
// Change in Team Rating
|
||||
rating_change = GetRatingMod(Stats.Rating, Opponent_MMRating, false);
|
||||
|
||||
// Modify the team stats accordingly
|
||||
FinishGame(mod);
|
||||
FinishGame(rating_change);
|
||||
|
||||
// return the rating change, used to display it on the results screen
|
||||
return mod;
|
||||
}
|
||||
|
||||
void ArenaTeam::MemberLost(Player* plr, uint32 againstMatchmakerRating, int32 teamratingchange)
|
||||
void ArenaTeam::MemberLost(Player* plr, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
|
||||
{
|
||||
// Called for each participant of a match after losing
|
||||
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
@@ -710,12 +732,11 @@ void ArenaTeam::MemberLost(Player* plr, uint32 againstMatchmakerRating, int32 te
|
||||
if (itr->Guid == plr->GetGUID())
|
||||
{
|
||||
// Update personal rating
|
||||
int32 mod = GetPersonalRatingMod(teamratingchange, itr->PersonalRating, (Stats.Rating - teamratingchange));
|
||||
int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, false);
|
||||
itr->ModifyPersonalRating(plr, mod, GetSlot());
|
||||
|
||||
// Update matchmaker rating
|
||||
mod = GetRatingMod(itr->MatchMakerRating, againstMatchmakerRating, false, true);
|
||||
itr->ModifyMatchmakerRating(mod, GetSlot());
|
||||
itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot());
|
||||
|
||||
// Update personal played stats
|
||||
itr->WeekGames +=1;
|
||||
@@ -729,7 +750,7 @@ void ArenaTeam::MemberLost(Player* plr, uint32 againstMatchmakerRating, int32 te
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchMakerRating, int32 ratingChange)
|
||||
void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
|
||||
{
|
||||
// Called for offline player after ending rated arena match!
|
||||
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
@@ -737,12 +758,11 @@ void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchMakerRating, i
|
||||
if (itr->Guid == guid)
|
||||
{
|
||||
// update personal rating
|
||||
int32 mod = GetPersonalRatingMod(ratingChange, itr->PersonalRating, (Stats.Rating - ratingChange));
|
||||
int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, false);
|
||||
itr->ModifyPersonalRating(NULL, mod, GetSlot());
|
||||
|
||||
// update matchmaker rating
|
||||
mod = GetRatingMod(itr->MatchMakerRating, againstMatchMakerRating, false, true);
|
||||
itr->ModifyMatchmakerRating(mod, GetSlot());
|
||||
itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot());
|
||||
|
||||
// update personal played stats
|
||||
itr->WeekGames += 1;
|
||||
@@ -752,7 +772,7 @@ void ArenaTeam::OfflineMemberLost(uint64 guid, uint32 againstMatchMakerRating, i
|
||||
}
|
||||
}
|
||||
|
||||
void ArenaTeam::MemberWon(Player* plr, uint32 againstMatchMakerRating, int32 ratingChange)
|
||||
void ArenaTeam::MemberWon(Player* plr, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange)
|
||||
{
|
||||
// called for each participant after winning a match
|
||||
for (MemberList::iterator itr = Members.begin(); itr != Members.end(); ++itr)
|
||||
@@ -760,12 +780,11 @@ void ArenaTeam::MemberWon(Player* plr, uint32 againstMatchMakerRating, int32 rat
|
||||
if (itr->Guid == plr->GetGUID())
|
||||
{
|
||||
// update personal rating
|
||||
int32 mod = GetPersonalRatingMod(ratingChange, (Stats.Rating - ratingChange), itr->PersonalRating);
|
||||
int32 mod = GetRatingMod(itr->PersonalRating, againstMatchmakerRating, true);
|
||||
itr->ModifyPersonalRating(plr, mod, GetSlot());
|
||||
|
||||
// update matchmaker rating
|
||||
mod = GetRatingMod(itr->MatchMakerRating, againstMatchMakerRating, true, true);
|
||||
itr->ModifyMatchmakerRating(mod, GetSlot());
|
||||
itr->ModifyMatchmakerRating(MatchmakerRatingChange, GetSlot());
|
||||
|
||||
// update personal stats
|
||||
itr->WeekGames +=1;
|
||||
|
||||
@@ -164,14 +164,14 @@ class ArenaTeam
|
||||
void Inspect(WorldSession* session, uint64 guid);
|
||||
|
||||
uint32 GetPoints(uint32 MemberRating);
|
||||
int32 GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won, bool calculating_mmr = false);
|
||||
int32 GetPersonalRatingMod(int32 base_rating, uint32 ownRating, uint32 opponentRating);
|
||||
int32 GetMatchmakerRatingMod(uint32 ownRating, uint32 opponentRating, bool won);
|
||||
int32 GetRatingMod(uint32 ownRating, uint32 opponentRating, bool won);
|
||||
float GetChanceAgainst(uint32 ownRating, uint32 opponentRating);
|
||||
int32 WonAgainst(uint32 againstRating);
|
||||
void MemberWon(Player* plr, uint32 againstMatchmakerRating, int32 teamratingchange = 12);
|
||||
int32 LostAgainst(uint32 againstRating);
|
||||
void MemberLost(Player* plr, uint32 againstMatchmakerRating, int32 teamratingchange = -12);
|
||||
void OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 teamratingchange = -12);
|
||||
int32 WonAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change);
|
||||
void MemberWon(Player* plr, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange);
|
||||
int32 LostAgainst(uint32 Own_MMRating, uint32 Opponent_MMRating, int32& rating_change);
|
||||
void MemberLost(Player* plr, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange = -12);
|
||||
void OfflineMemberLost(uint64 guid, uint32 againstMatchmakerRating, int32 MatchmakerRatingChange = -12);
|
||||
|
||||
void UpdateArenaPointsHelper(std::map<uint32, uint32> & PlayerPoints);
|
||||
|
||||
|
||||
@@ -656,9 +656,11 @@ void Battleground::EndBattleground(uint32 winner)
|
||||
uint32 loser_team_rating = 0;
|
||||
uint32 loser_matchmaker_rating = 0;
|
||||
int32 loser_change = 0;
|
||||
int32 loser_matchmaker_change = 0;
|
||||
uint32 winner_team_rating = 0;
|
||||
uint32 winner_matchmaker_rating = 0;
|
||||
int32 winner_change = 0;
|
||||
int32 winner_matchmaker_change = 0;
|
||||
WorldPacket data;
|
||||
int32 winmsg_id = 0;
|
||||
|
||||
@@ -700,10 +702,12 @@ void Battleground::EndBattleground(uint32 winner)
|
||||
loser_matchmaker_rating = GetArenaMatchmakerRating(GetOtherTeam(winner));
|
||||
winner_team_rating = winner_arena_team->GetRating();
|
||||
winner_matchmaker_rating = GetArenaMatchmakerRating(winner);
|
||||
winner_change = winner_arena_team->WonAgainst(loser_matchmaker_rating);
|
||||
loser_change = loser_arena_team->LostAgainst(winner_matchmaker_rating);
|
||||
sLog->outArena("--- Winner rating: %u, Loser rating: %u, Winner MMR: %u, Loser MMR: %u, Winner change: %d, Loser change: %d ---", winner_team_rating, loser_team_rating,
|
||||
winner_matchmaker_rating, loser_matchmaker_rating, winner_change, loser_change);
|
||||
winner_matchmaker_change = winner_arena_team->WonAgainst(winner_matchmaker_rating, loser_matchmaker_rating, winner_change);
|
||||
loser_matchmaker_change = loser_arena_team->LostAgainst(loser_matchmaker_rating, winner_matchmaker_rating, loser_change);
|
||||
sLog->outArena("--- Winner: old rating: %u, rating gain: %d, old MMR: %u, MMR gain: %d --- Loser: old rating: %u, rating loss: %d, old MMR: %u, MMR loss: %d ---", winner_team_rating, winner_change, winner_matchmaker_rating,
|
||||
winner_matchmaker_change, loser_team_rating, loser_change, loser_matchmaker_rating, loser_matchmaker_change);
|
||||
SetArenaMatchmakerRating(winner, winner_matchmaker_rating + winner_matchmaker_change);
|
||||
SetArenaMatchmakerRating(GetOtherTeam(winner), loser_matchmaker_rating + loser_matchmaker_change);
|
||||
SetArenaTeamRatingChangeForTeam(winner, winner_change);
|
||||
SetArenaTeamRatingChangeForTeam(GetOtherTeam(winner), loser_change);
|
||||
sLog->outArena("Arena match Type: %u for Team1Id: %u - Team2Id: %u ended. WinnerTeamId: %u. Winner rating: +%d, Loser rating: %d", m_ArenaType, m_ArenaTeamIds[BG_TEAM_ALLIANCE], m_ArenaTeamIds[BG_TEAM_HORDE], winner_arena_team->GetId(), winner_change, loser_change);
|
||||
@@ -738,9 +742,9 @@ void Battleground::EndBattleground(uint32 winner)
|
||||
if (isArena() && isRated() && winner_arena_team && loser_arena_team && winner_arena_team != loser_arena_team)
|
||||
{
|
||||
if (team == winner)
|
||||
winner_arena_team->OfflineMemberLost(itr->first, loser_matchmaker_rating, winner_change);
|
||||
winner_arena_team->OfflineMemberLost(itr->first, loser_matchmaker_rating, winner_matchmaker_change);
|
||||
else
|
||||
loser_arena_team->OfflineMemberLost(itr->first, winner_matchmaker_rating, loser_change);
|
||||
loser_arena_team->OfflineMemberLost(itr->first, winner_matchmaker_rating, loser_matchmaker_change);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -778,11 +782,11 @@ void Battleground::EndBattleground(uint32 winner)
|
||||
if (member)
|
||||
plr->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, member->PersonalRating);
|
||||
|
||||
winner_arena_team->MemberWon(plr, loser_matchmaker_rating, winner_change);
|
||||
winner_arena_team->MemberWon(plr, loser_matchmaker_rating, winner_matchmaker_change);
|
||||
}
|
||||
else
|
||||
{
|
||||
loser_arena_team->MemberLost(plr, winner_matchmaker_rating, loser_change);
|
||||
loser_arena_team->MemberLost(plr, winner_matchmaker_rating, loser_matchmaker_change);
|
||||
|
||||
// Arena lost => reset the win_rated_arena having the "no_lose" condition
|
||||
plr->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE);
|
||||
|
||||
Reference in New Issue
Block a user