aboutsummaryrefslogtreecommitdiff
path: root/src/game/ArenaTeam.cpp
diff options
context:
space:
mode:
authorw12x <none@none>2008-10-05 08:48:32 -0500
committerw12x <none@none>2008-10-05 08:48:32 -0500
commit6f0c3469a63c97eef57f36f1a39fed0b281b7cc9 (patch)
tree7089d31e4493160bed067ac9da519841704b230a /src/game/ArenaTeam.cpp
parent8b3fcc37c624c3ee4808d63160f563c070950cb4 (diff)
[svn] -enabled instantiated battlegrounds
-enabled arena matches -rewritten battleground queuing to support joining as group -removed queue announcements --HG-- branch : trunk
Diffstat (limited to 'src/game/ArenaTeam.cpp')
-rw-r--r--src/game/ArenaTeam.cpp332
1 files changed, 302 insertions, 30 deletions
diff --git a/src/game/ArenaTeam.cpp b/src/game/ArenaTeam.cpp
index 578340a4a8d..21ed6c66b31 100644
--- a/src/game/ArenaTeam.cpp
+++ b/src/game/ArenaTeam.cpp
@@ -51,7 +51,7 @@ bool ArenaTeam::create(uint64 captainGuid, uint32 type, std::string ArenaTeamNam
if(objmgr.GetArenaTeamByName(ArenaTeamName)) // arena team with this name already exist
return false;
- sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid));
+ sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid));
CaptainGuid = captainGuid;
Name = ArenaTeamName;
@@ -138,10 +138,8 @@ bool ArenaTeam::AddMember(uint64 PlayerGuid)
{
pl->SetInArenaTeam(Id, GetSlot());
pl->SetArenaTeamIdInvited(0);
- }
- else
- {
- Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), Id, PlayerGuid);
+ // personal rating
+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500);
}
// hide promote/remove buttons
@@ -149,18 +147,39 @@ bool ArenaTeam::AddMember(uint64 PlayerGuid)
{
if(pl)
pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
- else
- Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1, PlayerGuid);
}
+
+ // setuint32valueindb is asynch, can't be used here
+ Tokens tokens;
+ if(!Player::LoadValuesArrayFromDB(tokens,PlayerGuid))
+ return false;
+
+ // arena team id
+ uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6);
+ char buf[11];
+ snprintf(buf,11,"%u",Id);
+ tokens[index] = buf;
+ // pers rating
+ index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5;
+ buf[11];
+ snprintf(buf,11,"%u",1500);
+ tokens[index] = buf;
+ // hide promote/remove buttons
+ if(CaptainGuid != PlayerGuid)
+ {
+ index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6);
+ buf[11];
+ snprintf(buf,11,"%u",1);
+ tokens[index] = buf;
+ }
+
+ Player::SaveValuesArrayInDB(tokens,PlayerGuid);
+
return true;
}
bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId)
{
- LoadStatsFromDB(ArenaTeamId);
- LoadMembersFromDB(ArenaTeamId);
-
- // 0 1 2 3 4 5 6 7 8
QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
if(!result)
@@ -180,6 +199,22 @@ bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId)
delete result;
+ // only load here, so additional checks can be made
+ LoadStatsFromDB(ArenaTeamId);
+ LoadMembersFromDB(ArenaTeamId);
+
+ if(!GetMembersSize())
+ {
+ // arena team is empty, delete from db
+ CharacterDatabase.BeginTransaction();
+ CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
+ CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
+ CharacterDatabase.CommitTransaction();
+ // return false
+ return false;
+ }
+
return true;
}
@@ -207,7 +242,7 @@ void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId)
{
Field *fields;
- QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
+ QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season,points_to_add FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
if(!result)
return;
@@ -216,6 +251,14 @@ void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId)
fields = result->Fetch();
ArenaTeamMember newmember;
newmember.guid = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
+ // check if this member is in this arenateam
+ // based on character data field
+ if(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6),newmember.guid) != ArenaTeamId)
+ {
+ // the player's registered arena team for this slot isn't this team, so delete member info from here
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u' AND arenateamid = '%u'",fields[0].GetUInt32(), ArenaTeamId);
+ continue;
+ }
LoadPlayerStats(&newmember);
newmember.played_week = fields[1].GetUInt32();
newmember.wons_week = fields[2].GetUInt32();
@@ -276,17 +319,36 @@ void ArenaTeam::DelMember(uint64 guid)
}
Player *player = objmgr.GetPlayer(guid);
+ // this will be ugly. because of the asynchronous sql handling, we have to set all the fields of the player at once, and save them at once, or else the save will only modify the last field.
+ // rip off of setuint32valueindb
if(player)
{
player->SetInArenaTeam(0, GetSlot());
player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);
+ // delete all info regarding this team
+ for(int i = 0; i < 6; ++i)
+ {
+ player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0);
+ }
}
- else
+
+ // we have to do it this way, setuint32valueindb is asynch, unsafe to use multiple times in a row on the same player
+ Tokens tokens;
+ if(!Player::LoadValuesArrayFromDB(tokens,guid))
+ return;
+
+ for(int i = 0; i < 6; ++i)
{
- Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), 0, guid);
+ uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i;
+ char buf[11];
+ snprintf(buf,11,"%u",0);
+ tokens[index] = buf;
}
- CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u'", GUID_LOPART(guid));
+ Player::SaveValuesArrayInDB(tokens,guid);
+
+ // only delete from this arena team!
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid));
}
void ArenaTeam::Disband(WorldSession *session)
@@ -313,6 +375,7 @@ void ArenaTeam::Disband(WorldSession *session)
CharacterDatabase.BeginTransaction();
CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);
+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id);
CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id);
CharacterDatabase.CommitTransaction();
objmgr.RemoveArenaTeam(this);
@@ -342,7 +405,7 @@ void ArenaTeam::Roster(WorldSession *session)
data << uint32(itr->wons_week); // wins this week
data << uint32(itr->played_season); // played this season
data << uint32(itr->wons_season); // wins this season
- data << uint32(0); // personal rating?
+ data << uint32(pl->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5)); // personal rating?
}
else
{
@@ -356,7 +419,7 @@ void ArenaTeam::Roster(WorldSession *session)
data << uint32(itr->wons_week); // wins this week
data << uint32(itr->played_season); // played this season
data << uint32(itr->wons_season); // wins this season
- data << uint32(0); // personal rating?
+ data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, itr->guid)); // personal rating?
}
}
session->SendPacket(&data);
@@ -391,6 +454,18 @@ void ArenaTeam::Stats(WorldSession *session)
session->SendPacket(&data);
}
+void ArenaTeam::NotifyStatsChanged()
+{
+ // this is called after a rated match ended
+ // updates arena team stats for every member of the team (not only the ones who participated!)
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ Player * plr=objmgr.GetPlayer(itr->guid);
+ if(plr)
+ Stats(plr->GetSession());
+ }
+}
+
void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
{
WorldPacket data(MSG_INSPECT_ARENA_TEAMS, 8+1+4*6);
@@ -398,10 +473,20 @@ void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
data << uint8(GetSlot()); // slot (0...2)
data << uint32(GetId()); // arena team id
data << uint32(stats.rating); // rating
- data << uint32(stats.games); // games
- data << uint32(stats.wins); // wins
- data << uint32(stats.played); // played (count of all games, that played...)
- data << uint32(0); // 2.3.3 personal rating?
+ data << uint32(stats.played); // season played
+ data << uint32(stats.wins2); // season wins
+ uint32 participated = 0;
+ for(MemberList::iterator itr = members.begin(); itr!= members.end(); ++itr)
+ {
+ if(itr->guid == guid)
+ {
+ participated = itr->played_season;
+ break;
+ }
+ }
+ data << uint32(participated); // played (count of all games, that the inspected member participated...)
+ data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, guid)); // unk, 2.3.3 (personal rating?)
+
session->SendPacket(&data);
}
@@ -494,24 +579,211 @@ bool ArenaTeam::HaveMember( uint64 guid ) const
return false;
}
+uint32 ArenaTeam::GetPoints(uint32 MemberRating)
+{
+ // returns how many points would be awarded with this team type with this rating
+ float points;
+
+ uint32 rating = MemberRating + 150 < stats.rating ? MemberRating : stats.rating;
+
+ if(rating<=1500)
+ {
+ points = (float)rating * 0.22f + 14.0f;
+ }
+ else
+ {
+ points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating));
+ }
+
+ // type penalties for <5v5 teams
+ if(Type == ARENA_TEAM_2v2)
+ points *= 0.76f;
+ else if(Type == ARENA_TEAM_3v3)
+ points *= 0.88f;
+
+ return (uint32) points;
+}
+
+float ArenaTeam::GetChanceAgainst(uint32 rating)
+{
+ // 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)rating - (float)stats.rating)/400.0f));
+}
+
+int32 ArenaTeam::WonAgainstChance(float chance)
+{
+ // called when the team has won, and had 'chance' calculated chance to beat the opponent
+ // calculate the rating modification (ELO system with k=32)
+ int32 mod = (int32)floor(32.0f * (1.0f - chance));
+ // modify the team stats accordingly
+ stats.rating += mod;
+ stats.games += 1;
+ stats.wins += 1;
+ stats.played += 1;
+ stats.wins2 += 1;
+/* this should be done in .flusharenapoints; not a breaker though.
+ uint32 higher_rank = 0;
+ QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT(arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
+ if(result)
+ {
+ higher_rank = result->Fetch()->GetUInt32();
+ delete result;
+ }
+ stats.rank = higher_rank + 1;*/
+ // return the rating change, used to display it on the results screen
+ return mod;
+}
+
+int32 ArenaTeam::LostAgainstChance(float chance)
+{
+ // called when the team has lost, and had 'chance' calculated chance to beat the opponent
+ // calculate the rating modification (ELO system with k=32)
+ int32 mod = (int32)ceil(32.0f * (0.0f - chance));
+ // modify the team stats accordingly
+ stats.rating += mod;
+ stats.games += 1;
+ stats.played += 1;
+/* uint32 higher_rank = 0;
+ QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT (arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
+ if(result)
+ {
+ higher_rank = result->Fetch()->GetUInt32();
+ delete result;
+ }
+ stats.rank = higher_rank + 1;*/
+ // return the rating adjustment for display
+ return mod;
+}
+
+void ArenaTeam::MemberLost(Player * plr, uint32 againstrating)
+{
+ // 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 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
+ float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
+ int32 mod = (int32)ceil(32.0f * (0.0f - chance));
+ personalrating += mod;
+ if(personalrating < 0)
+ personalrating = 0;
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
+ // update personal played stats
+ itr->played_week +=1;
+ itr->played_season +=1;
+ // update the unit fields
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);
+ return;
+ }
+ }
+}
+
+void ArenaTeam::MemberWon(Player * plr, uint32 againstrating)
+{
+ // 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 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
+ float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
+ int32 mod = (int32)floor(32.0f * (1.0f - chance));
+ personalrating += mod;
+ if(personalrating < 0)
+ personalrating = 0;
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
+ // update personal stats
+ itr->played_week +=1;
+ itr->played_season +=1;
+ itr->wons_season += 1;
+ itr->wons_week += 1;
+ // update unit fields
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);
+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);
+ return;
+ }
+ }
+}
+
+void ArenaTeam::UpdateArenaPointsHelper()
+{
+ // called after a match has ended and the stats are already modified
+ // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons)
+ // 10 played games per week is a minimum
+ if(stats.games < 10)
+ return;
+ // to get points, a player has to participate in at least 30% of the matches
+ uint32 min_plays = ceil(stats.games * 0.3);
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ // the player participated in enough games, update his points
+ if(itr->played_week >= min_plays)
+ {
+ // do it separately for online and offline players
+ // online players might have modified personal rating in MemberLost/MemberWon, that's not already saved to DB because of asynch queries
+ // offline player cant have a personal rating not matching the db
+ Player * plr = objmgr.GetPlayer(itr->guid);
+ uint32 points_to_add = 0;
+ if(plr)
+ points_to_add = GetPoints(plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5));
+ else
+ points_to_add = GetPoints(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5,itr->guid));
+ // it's enough to set the points in memory, the saving is done in separate function
+ CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, Id, itr->guid);
+ }
+ // the player failed to participate in enough games, so no points for him
+ else
+ {
+ CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", 0, Id, itr->guid);
+ }
+ }
+}
+
+void ArenaTeam::SaveToDB()
+{
+ // save team and member stats to db
+ // called after a match has ended
+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games, stats.played, stats.rank, stats.wins, stats.wins2, GetId());
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->played_week, itr->wons_week, itr->played_season, itr->wons_season, Id, itr->guid);
+ }
+}
+
+void ArenaTeam::FinishWeek()
+{
+ stats.games = 0; // played this week
+ stats.wins = 0; // wins this week
+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
+ {
+ itr->played_week = 0;
+ itr->wons_week = 0;
+ }
+}
+
/*
arenateam fields (id from 2.3.3 client):
1414 - arena team id 2v2
1415 - 0=captain, 1=member
-1416 - played this season
-1417 - played this week
+1416 - played this week
+1417 - played this season
1418 - unk
-1419 - unk
+1419 - personal arena rating
1420 - arena team id 3v3
1421 - 0=captain, 1=member
-1422 - played this season
-1423 - played this week
+1422 - played this week
+1423 - played this season
1424 - unk
-1425 - unk
+1425 - personal arena rating
1426 - arena team id 5v5
1427 - 0=captain, 1=member
-1428 - played this season
-1429 - played this week
+1428 - played this week
+1429 - played this season
1430 - unk
-1431 - unk
+1431 - personal arena rating
*/