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:
Liberate
2011-07-30 22:46:45 +02:00
parent b2d37062a0
commit 6cfb87639c
3 changed files with 74 additions and 51 deletions
+55 -36
View File
@@ -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;
+7 -7
View File
@@ -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);
+12 -8
View File
@@ -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);