Skip to content

Commit

Permalink
Core/Arena: A more accurate implementation of rating gain/loss. This …
Browse files Browse the repository at this point in the history
…fixes the strange behaviour personal rating could have, as well as implements the bigger rating scale added in patch 3.1.

Fixes #230
  • Loading branch information
tbaart committed Jul 30, 2011
1 parent b2d3706 commit 6cfb876
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 51 deletions.
91 changes: 55 additions & 36 deletions src/server/game/Battlegrounds/ArenaTeam.cpp
Expand Up @@ -606,43 +606,59 @@ 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

This comment has been minimized.

Copy link
@Warpten

Warpten Jul 31, 2011

Member

mod *= confidence_factor;

Minor typo that may be left when you fix it :p

// 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);

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
Expand Down Expand Up @@ -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;
Expand All @@ -689,33 +708,35 @@ 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)
{
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;
Expand All @@ -729,20 +750,19 @@ 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)
{
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;
Expand All @@ -752,20 +772,19 @@ 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)
{
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;
Expand Down
14 changes: 7 additions & 7 deletions src/server/game/Battlegrounds/ArenaTeam.h
Expand Up @@ -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);

Expand Down
20 changes: 12 additions & 8 deletions src/server/game/Battlegrounds/Battleground.cpp
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down

4 comments on commit 6cfb876

@2010phenix
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 man
and nice to see you and your work in comunity

@filo
Copy link

@filo filo commented on 6cfb876 Jul 30, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job! But maybe also need to change option in wordserver.conf:
Arena.MaxRatingDifference = 150

to MMR difference (and edit to default mmr difference - I dont know which value is it), because with the introduction of MMR, team rating is only to purchase items.

@tbaart
Copy link
Contributor Author

@tbaart tbaart commented on 6cfb876 Jul 31, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filo: Good one. Will do :)
And thanks 2010phenix :) Glad to be back. I am busy still though, so I might not do as much as i did a year ago ;)

@Jildor
Copy link
Contributor

@Jildor Jildor commented on 6cfb876 Jul 31, 2011

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also solves this?
#698

Please sign in to comment.