root/trunk/src/game/ArenaTeam.cpp @ 28

Revision 9, 29.8 kB (checked in by yumileroy, 17 years ago)

[svn] -enabled instantiated battlegrounds
-enabled arena matches
-rewritten battleground queuing to support joining as group
-removed queue announcements

Original author: w12x
Date: 2008-10-05 08:48:32-05:00

Line 
1/*
2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18
19#include "WorldPacket.h"
20#include "ObjectMgr.h"
21#include "ArenaTeam.h"
22
23ArenaTeam::ArenaTeam()
24{
25    Id              = 0;
26    Type            = 0;
27    Name            = "";
28    CaptainGuid     = 0;
29    BackgroundColor = 0;                                    // background
30    EmblemStyle     = 0;                                    // icon
31    EmblemColor     = 0;                                    // icon color
32    BorderStyle     = 0;                                    // border
33    BorderColor     = 0;                                    // border color
34    stats.games     = 0;
35    stats.played    = 0;
36    stats.rank      = 0;
37    stats.rating    = 1500;
38    stats.wins      = 0;
39    stats.wins2     = 0;
40}
41
42ArenaTeam::~ArenaTeam()
43{
44
45}
46
47bool ArenaTeam::create(uint64 captainGuid, uint32 type, std::string ArenaTeamName)
48{
49    if(!objmgr.GetPlayer(captainGuid))                      // player not exist
50        return false;
51    if(objmgr.GetArenaTeamByName(ArenaTeamName))            // arena team with this name already exist
52        return false;
53
54    sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid));
55
56    CaptainGuid = captainGuid;
57    Name = ArenaTeamName;
58    Type = type;
59
60    QueryResult *result = CharacterDatabase.Query("SELECT MAX(arenateamid) FROM arena_team");
61    if( result )
62    {
63        Id = (*result)[0].GetUInt32()+1;
64        delete result;
65    }
66    else Id = 1;
67
68    // ArenaTeamName already assigned to ArenaTeam::name, use it to encode string for DB
69    CharacterDatabase.escape_string(ArenaTeamName);
70
71    CharacterDatabase.BeginTransaction();
72    // CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid='%u'", Id); - MAX(arenateam)+1 not exist
73    CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid='%u'", Id);
74    CharacterDatabase.PExecute("INSERT INTO arena_team (arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor) "
75        "VALUES('%u','%s','%u','%u','%u','%u','%u','%u','%u')",
76        Id, ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid), Type, BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor);
77    CharacterDatabase.PExecute("INSERT INTO arena_team_stats (arenateamid, rating, games, wins, played, wins2, rank) VALUES "
78        "('%u', '%u', '%u', '%u', '%u', '%u', '%u')", Id,stats.rating,stats.games,stats.wins,stats.played,stats.wins2,stats.rank);
79
80    CharacterDatabase.CommitTransaction();
81
82    AddMember(CaptainGuid);
83    return true;
84}
85
86bool ArenaTeam::AddMember(uint64 PlayerGuid)
87{
88    std::string plName;
89    uint8 plClass;
90
91    if(GetMembersSize() >= GetType() * 2)
92    {
93        // arena team is full (can't have more than type * 2 players!)
94        // return false
95        return false;
96    }
97
98    if(!objmgr.GetPlayerNameByGUID(PlayerGuid, plName))     // player doesnt exist
99        return false;
100                                                            // player already in arenateam of that size
101    if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetType()) != 0)
102    {
103        sLog.outError("Arena::AddMember() : player already in this sized team");
104        return false;
105    }
106
107    // remove all player signs from another petitions
108    // this will be prevent attempt joining player to many arenateams and corrupt arena team data integrity
109    Player::RemovePetitionsAndSigns(PlayerGuid, GetType());
110
111    Player *pl = objmgr.GetPlayer(PlayerGuid);
112    if(pl)
113    {
114        plClass = (uint8)pl->getClass();
115    }
116    else
117    {
118        QueryResult *result = CharacterDatabase.PQuery("SELECT class FROM characters WHERE guid='%u'", GUID_LOPART(PlayerGuid));
119        if(!result)
120            return false;
121        plClass = (*result)[0].GetUInt8();
122        delete result;
123    }
124
125    ArenaTeamMember newmember;
126    newmember.name          = plName;
127    newmember.guid          = PlayerGuid;
128    newmember.Class         = plClass;
129    newmember.played_season = 0;
130    newmember.played_week   = 0;
131    newmember.wons_season   = 0;
132    newmember.wons_week     = 0;
133    members.push_back(newmember);
134
135    CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid,guid) VALUES ('%u', '%u')", Id, GUID_LOPART(newmember.guid));
136
137    if(pl)
138    {
139        pl->SetInArenaTeam(Id, GetSlot());
140        pl->SetArenaTeamIdInvited(0);
141        // personal rating
142        pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500);
143    }
144
145    // hide promote/remove buttons
146    if(CaptainGuid != PlayerGuid)
147    {
148        if(pl)
149            pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
150    }
151
152    // setuint32valueindb is asynch, can't be used here
153    Tokens tokens;
154    if(!Player::LoadValuesArrayFromDB(tokens,PlayerGuid))
155        return false;
156
157    // arena team id
158    uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6);
159    char buf[11];
160    snprintf(buf,11,"%u",Id);
161    tokens[index] = buf;
162    // pers rating
163    index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5;
164    buf[11];
165    snprintf(buf,11,"%u",1500);
166    tokens[index] = buf;
167    // hide promote/remove buttons
168    if(CaptainGuid != PlayerGuid)
169    {
170        index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6);
171        buf[11];
172        snprintf(buf,11,"%u",1);
173        tokens[index] = buf;
174    }
175
176    Player::SaveValuesArrayInDB(tokens,PlayerGuid);
177
178    return true;
179}
180
181bool ArenaTeam::LoadArenaTeamFromDB(uint32 ArenaTeamId)
182{
183    QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid,name,captainguid,type,BackgroundColor,EmblemStyle,EmblemColor,BorderStyle,BorderColor FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
184
185    if(!result)
186        return false;
187
188    Field *fields = result->Fetch();
189
190    Id = fields[0].GetUInt32();
191    Name = fields[1].GetCppString();
192    CaptainGuid  = MAKE_NEW_GUID(fields[2].GetUInt32(), 0, HIGHGUID_PLAYER);
193    Type = fields[3].GetUInt32();
194    BackgroundColor = fields[4].GetUInt32();
195    EmblemStyle = fields[5].GetUInt32();
196    EmblemColor = fields[6].GetUInt32();
197    BorderStyle = fields[7].GetUInt32();
198    BorderColor = fields[8].GetUInt32();
199
200    delete result;
201
202    // only load here, so additional checks can be made
203    LoadStatsFromDB(ArenaTeamId);
204    LoadMembersFromDB(ArenaTeamId);
205
206    if(!GetMembersSize())
207    {
208        // arena team is empty, delete from db
209        CharacterDatabase.BeginTransaction();
210        CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", ArenaTeamId);
211        CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);
212        CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
213        CharacterDatabase.CommitTransaction();
214        // return false
215        return false;
216    }
217
218    return true;
219}
220
221void ArenaTeam::LoadStatsFromDB(uint32 ArenaTeamId)
222{
223    //                                                     0      1     2    3      4     5
224    QueryResult *result = CharacterDatabase.PQuery("SELECT rating,games,wins,played,wins2,rank FROM arena_team_stats WHERE arenateamid = '%u'", ArenaTeamId);
225
226    if(!result)
227        return;
228
229    Field *fields = result->Fetch();
230
231    stats.rating    = fields[0].GetUInt32();
232    stats.games     = fields[1].GetUInt32();
233    stats.wins      = fields[2].GetUInt32();
234    stats.played    = fields[3].GetUInt32();
235    stats.wins2     = fields[4].GetUInt32();
236    stats.rank      = fields[5].GetUInt32();
237
238    delete result;
239}
240
241void ArenaTeam::LoadMembersFromDB(uint32 ArenaTeamId)
242{
243    Field *fields;
244
245    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);
246    if(!result)
247        return;
248
249    do
250    {
251        fields = result->Fetch();
252        ArenaTeamMember newmember;
253        newmember.guid          = MAKE_NEW_GUID(fields[0].GetUInt32(), 0, HIGHGUID_PLAYER);
254        // check if this member is in this arenateam
255        // based on character data field
256        if(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6),newmember.guid) != ArenaTeamId)
257        {
258            // the player's registered arena team for this slot isn't this team, so delete member info from here
259            CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u' AND arenateamid = '%u'",fields[0].GetUInt32(), ArenaTeamId);
260            continue;
261        }
262        LoadPlayerStats(&newmember);
263        newmember.played_week   = fields[1].GetUInt32();
264        newmember.wons_week     = fields[2].GetUInt32();
265        newmember.played_season = fields[3].GetUInt32();
266        newmember.wons_season   = fields[4].GetUInt32();
267        members.push_back(newmember);
268    }while( result->NextRow() );
269    delete result;
270}
271
272void ArenaTeam::LoadPlayerStats(ArenaTeamMember *member)
273{
274    Field *fields;
275
276    QueryResult *result = CharacterDatabase.PQuery("SELECT name,class FROM characters WHERE guid = '%u'", GUID_LOPART(member->guid));
277    if(!result)
278        return;
279    fields = result->Fetch();
280    member->name  = fields[0].GetCppString();
281    member->Class = fields[1].GetUInt8();
282
283    delete result;
284}
285
286void ArenaTeam::SetCaptain(uint64 guid)
287{
288    // disable remove/promote buttons
289    Player *oldcaptain = objmgr.GetPlayer(GetCaptain());
290    if(oldcaptain)
291        oldcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1);
292    else
293        Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 1, GetCaptain());
294
295    // set new captain
296    CaptainGuid = guid;
297
298    // update database
299    CharacterDatabase.PExecute("UPDATE arena_team SET captainguid = '%u' WHERE arenateamid = '%u'", GUID_LOPART(guid), Id);
300
301    // enable remove/promote buttons
302    Player *newcaptain = objmgr.GetPlayer(guid);
303    if(newcaptain)
304        newcaptain->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0);
305    else
306        Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 1 + (GetSlot() * 6), 0, guid);
307}
308
309void ArenaTeam::DelMember(uint64 guid)
310{
311    MemberList::iterator itr;
312    for (itr = members.begin(); itr != members.end(); itr++)
313    {
314        if (itr->guid == guid)
315        {
316            members.erase(itr);
317            break;
318        }
319    }
320
321    Player *player = objmgr.GetPlayer(guid);
322    // 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.
323    // rip off of setuint32valueindb
324    if(player)
325    {
326        player->SetInArenaTeam(0, GetSlot());
327        player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);
328        // delete all info regarding this team
329        for(int i = 0; i < 6; ++i)
330        {
331            player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0);
332        }
333    }
334
335    // we have to do it this way, setuint32valueindb is asynch, unsafe to use multiple times in a row on the same player
336    Tokens tokens;
337    if(!Player::LoadValuesArrayFromDB(tokens,guid))
338        return;
339
340    for(int i = 0; i < 6; ++i)
341    {
342        uint16 index = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i;
343        char buf[11];
344        snprintf(buf,11,"%u",0);
345        tokens[index] = buf;
346    }
347
348    Player::SaveValuesArrayInDB(tokens,guid);
349
350    // only delete from this arena team!
351    CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid));
352}
353
354void ArenaTeam::Disband(WorldSession *session)
355{
356    // event
357    WorldPacket data;
358    session->BuildArenaTeamEventPacket(&data, ERR_ARENA_TEAM_DISBANDED_S, 2, session->GetPlayerName(), GetName(), "");
359    BroadcastPacket(&data);
360
361    uint32 count = members.size();
362    uint64 *memberGuids = new uint64[count];
363
364    MemberList::iterator itr;
365    uint32 i=0;
366    for(itr = members.begin(); itr != members.end(); itr++)
367    {
368        memberGuids[i] = itr->guid;
369        ++i;
370    }
371
372    for(uint32 j = 0; j < count; j++)
373        DelMember(memberGuids[j]);
374    delete[] memberGuids;
375
376    CharacterDatabase.BeginTransaction();
377    CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);
378    CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id);
379    CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id);
380    CharacterDatabase.CommitTransaction();
381    objmgr.RemoveArenaTeam(this);
382}
383
384void ArenaTeam::Roster(WorldSession *session)
385{
386    Player *pl = NULL;
387
388    WorldPacket data(SMSG_ARENA_TEAM_ROSTER, 100);
389    data << uint32(GetId());                                // arena team id
390    data << uint32(GetMembersSize());                       // members count
391    data << uint32(GetType());                              // arena team type?
392
393    for (MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
394    {
395        pl = objmgr.GetPlayer(itr->guid);
396        if(pl)
397        {
398            data << uint64(pl->GetGUID());                  // guid
399            data << uint8(1);                               // online flag
400            data << pl->GetName();                          // member name
401            data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
402            data << uint8(pl->getLevel());                  // unknown, probably level
403            data << uint8(pl->getClass());                  // class
404            data << uint32(itr->played_week);               // played this week
405            data << uint32(itr->wons_week);                 // wins this week
406            data << uint32(itr->played_season);             // played this season
407            data << uint32(itr->wons_season);               // wins this season
408            data << uint32(pl->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5));                              // personal rating?
409        }
410        else
411        {
412            data << uint64(itr->guid);                      // guid
413            data << uint8(0);                               // online flag
414            data << itr->name;                              // member name
415            data << uint32(itr->guid == GetCaptain() ? 0 : 1);// unknown
416            data << uint8(0);                               // unknown, level?
417            data << uint8(itr->Class);                      // class
418            data << uint32(itr->played_week);               // played this week
419            data << uint32(itr->wons_week);                 // wins this week
420            data << uint32(itr->played_season);             // played this season
421            data << uint32(itr->wons_season);               // wins this season
422            data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, itr->guid));                              // personal rating?
423        }
424    }
425    session->SendPacket(&data);
426    sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_ROSTER");
427}
428
429void ArenaTeam::Query(WorldSession *session)
430{
431    WorldPacket data(SMSG_ARENA_TEAM_QUERY_RESPONSE, 4*7+GetName().size()+1);
432    data << uint32(GetId());                                // team id
433    data << GetName();                                      // team name
434    data << uint32(GetType());                              // arena team type (2=2x2, 3=3x3 or 5=5x5)
435    data << uint32(BackgroundColor);                        // background color
436    data << uint32(EmblemStyle);                            // emblem style
437    data << uint32(EmblemColor);                            // emblem color
438    data << uint32(BorderStyle);                            // border style
439    data << uint32(BorderColor);                            // border color
440    session->SendPacket(&data);
441    sLog.outDebug("WORLD: Sent SMSG_ARENA_TEAM_QUERY_RESPONSE");
442}
443
444void ArenaTeam::Stats(WorldSession *session)
445{
446    WorldPacket data(SMSG_ARENA_TEAM_STATS, 4*7);
447    data << uint32(GetId());                                // arena team id
448    data << uint32(stats.rating);                           // rating
449    data << uint32(stats.games);                            // games
450    data << uint32(stats.wins);                             // wins
451    data << uint32(stats.played);                           // played
452    data << uint32(stats.wins2);                            // wins(again o_O)
453    data << uint32(stats.rank);                             // rank
454    session->SendPacket(&data);
455}
456
457void ArenaTeam::NotifyStatsChanged()
458{
459    // this is called after a rated match ended
460    // updates arena team stats for every member of the team (not only the ones who participated!)
461    for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)
462    {
463        Player * plr=objmgr.GetPlayer(itr->guid);
464        if(plr)
465            Stats(plr->GetSession());
466    }
467}
468
469void ArenaTeam::InspectStats(WorldSession *session, uint64 guid)
470{
471    WorldPacket data(MSG_INSPECT_ARENA_TEAMS, 8+1+4*6);
472    data << uint64(guid);                                   // player guid
473    data << uint8(GetSlot());                               // slot (0...2)
474    data << uint32(GetId());                                // arena team id
475    data << uint32(stats.rating);                           // rating
476    data << uint32(stats.played);                           // season played
477    data << uint32(stats.wins2);                            // season wins
478    uint32 participated = 0;
479    for(MemberList::iterator itr = members.begin(); itr!= members.end(); ++itr)
480    {
481        if(itr->guid == guid)
482        {
483            participated = itr->played_season;
484            break;
485        }
486    }
487    data << uint32(participated);                            // played (count of all games, that the inspected member participated...)
488    data << uint32(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + GetSlot() * 6 + 5, guid));                                       // unk, 2.3.3 (personal rating?)
489
490    session->SendPacket(&data);
491}
492
493void ArenaTeam::SetEmblem(uint32 backgroundColor, uint32 emblemStyle, uint32 emblemColor, uint32 borderStyle, uint32 borderColor)
494{
495    BackgroundColor = backgroundColor;
496    EmblemStyle = emblemStyle;
497    EmblemColor = emblemColor;
498    BorderStyle = borderStyle;
499    BorderColor = borderColor;
500
501    CharacterDatabase.PExecute("UPDATE arena_team SET BackgroundColor='%u', EmblemStyle='%u', EmblemColor='%u', BorderStyle='%u', BorderColor='%u' WHERE arenateamid='%u'", BackgroundColor, EmblemStyle, EmblemColor, BorderStyle, BorderColor, Id);
502}
503
504void ArenaTeam::SetStats(uint32 stat_type, uint32 value)
505{
506    switch(stat_type)
507    {
508        case STAT_TYPE_RATING:
509            stats.rating = value;
510            CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u' WHERE arenateamid = '%u'", value, GetId());
511            break;
512        case STAT_TYPE_GAMES:
513            stats.games = value;
514            CharacterDatabase.PExecute("UPDATE arena_team_stats SET games = '%u' WHERE arenateamid = '%u'", value, GetId());
515            break;
516        case STAT_TYPE_WINS:
517            stats.wins = value;
518            CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins = '%u' WHERE arenateamid = '%u'", value, GetId());
519            break;
520        case STAT_TYPE_PLAYED:
521            stats.played = value;
522            CharacterDatabase.PExecute("UPDATE arena_team_stats SET played = '%u' WHERE arenateamid = '%u'", value, GetId());
523            break;
524        case STAT_TYPE_WINS2:
525            stats.wins2 = value;
526            CharacterDatabase.PExecute("UPDATE arena_team_stats SET wins2 = '%u' WHERE arenateamid = '%u'", value, GetId());
527            break;
528        case STAT_TYPE_RANK:
529            stats.rank = value;
530            CharacterDatabase.PExecute("UPDATE arena_team_stats SET rank = '%u' WHERE arenateamid = '%u'", value, GetId());
531            break;
532        default:
533            sLog.outDebug("unknown stat type in ArenaTeam::SetStats() %u", stat_type);
534            break;
535    }
536}
537
538uint8 ArenaTeam::GetSlot() const
539{
540    uint8 slot = GetSlotByType(GetType());
541    if(slot >= MAX_ARENA_SLOT)
542    {
543        sLog.outError("Unknown arena team type %u for arena team %u", uint32(GetType()), GetId());
544        return 0;                                           // better return existed slot to prevent untelated data curruption
545    }
546
547    return slot;
548}
549
550void ArenaTeam::BroadcastPacket(WorldPacket *packet)
551{
552    for (MemberList::iterator itr = members.begin(); itr != members.end(); itr++)
553    {
554        Player *player = objmgr.GetPlayer(itr->guid);
555        if(player)
556            player->GetSession()->SendPacket(packet);
557    }
558}
559
560uint8 ArenaTeam::GetSlotByType( uint32 type )
561{
562    switch(type)
563    {
564        case ARENA_TEAM_2v2: return 0;
565        case ARENA_TEAM_3v3: return 1;
566        case ARENA_TEAM_5v5: return 2;
567        default:
568            break;
569    }
570    return 0xFF;
571}
572
573bool ArenaTeam::HaveMember( uint64 guid ) const
574{
575    for (MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)
576        if(itr->guid==guid)
577            return true;
578
579    return false;
580}
581
582uint32 ArenaTeam::GetPoints(uint32 MemberRating)
583{
584    // returns how many points would be awarded with this team type with this rating
585    float points;
586
587    uint32 rating = MemberRating + 150 < stats.rating ? MemberRating : stats.rating;
588
589    if(rating<=1500)
590    {
591        points = (float)rating * 0.22f + 14.0f;
592    }
593    else
594    {
595        points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)rating));
596    }
597
598    // type penalties for <5v5 teams
599    if(Type == ARENA_TEAM_2v2)
600        points *= 0.76f;
601    else if(Type == ARENA_TEAM_3v3)
602        points *= 0.88f;
603
604    return (uint32) points;
605}
606
607float ArenaTeam::GetChanceAgainst(uint32 rating)
608{
609    // returns the chance to win against a team with the given rating, used in the rating adjustment calculation
610    // ELO system
611    return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)rating - (float)stats.rating)/400.0f));
612}
613
614int32 ArenaTeam::WonAgainstChance(float chance)
615{
616    // called when the team has won, and had 'chance' calculated chance to beat the opponent
617    // calculate the rating modification (ELO system with k=32)
618    int32 mod = (int32)floor(32.0f * (1.0f - chance));
619    // modify the team stats accordingly
620    stats.rating += mod;
621    stats.games += 1;
622    stats.wins += 1;
623    stats.played += 1;
624    stats.wins2 += 1;
625/*  this should be done in .flusharenapoints; not a breaker though.
626    uint32 higher_rank = 0;
627    QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT(arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
628    if(result)
629    {
630        higher_rank = result->Fetch()->GetUInt32();
631        delete result;
632    }
633    stats.rank = higher_rank + 1;*/
634    // return the rating change, used to display it on the results screen
635    return mod;
636}
637
638int32 ArenaTeam::LostAgainstChance(float chance)
639{
640    // called when the team has lost, and had 'chance' calculated chance to beat the opponent
641    // calculate the rating modification (ELO system with k=32)
642    int32 mod = (int32)ceil(32.0f * (0.0f - chance));
643    // modify the team stats accordingly
644    stats.rating += mod;
645    stats.games += 1;
646    stats.played += 1;
647/*    uint32 higher_rank = 0;
648    QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT (arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);
649    if(result)
650    {
651        higher_rank = result->Fetch()->GetUInt32();
652        delete result;
653    }
654    stats.rank = higher_rank + 1;*/
655    // return the rating adjustment for display
656    return mod;
657}
658
659void ArenaTeam::MemberLost(Player * plr, uint32 againstrating)
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 == plr->GetGUID())
665        {
666            // update personal rating
667            int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
668            float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
669            int32 mod = (int32)ceil(32.0f * (0.0f - chance));
670            personalrating += mod;
671            if(personalrating < 0)
672                personalrating = 0;
673            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
674            // update personal played stats
675            itr->played_week +=1;
676            itr->played_season +=1;
677            // update the unit fields
678            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);
679            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);
680            return;
681        }
682    }
683}
684
685void ArenaTeam::MemberWon(Player * plr, uint32 againstrating)
686{
687    // called for each participant after winning a match
688    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)
689    {
690        if(itr->guid == plr->GetGUID())
691        {
692            // update personal rating
693            int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);
694            float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));
695            int32 mod = (int32)floor(32.0f * (1.0f - chance));
696            personalrating += mod;
697            if(personalrating < 0)
698                personalrating = 0;
699            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);
700            // update personal stats
701            itr->played_week +=1;
702            itr->played_season +=1;
703            itr->wons_season += 1;
704            itr->wons_week += 1;
705            // update unit fields
706            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);
707            plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);
708            return;
709        }
710    }
711}
712
713void ArenaTeam::UpdateArenaPointsHelper()
714{
715    // called after a match has ended and the stats are already modified
716    // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons)
717    // 10 played games per week is a minimum
718    if(stats.games < 10)
719        return;
720    // to get points, a player has to participate in at least 30% of the matches
721    uint32 min_plays = ceil(stats.games * 0.3);
722    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)
723    {
724        // the player participated in enough games, update his points
725        if(itr->played_week >= min_plays)
726        {
727            // do it separately for online and offline players
728            // online players might have modified personal rating in MemberLost/MemberWon, that's not already saved to DB because of asynch queries
729            // offline player cant have a personal rating not matching the db
730            Player * plr = objmgr.GetPlayer(itr->guid);
731            uint32 points_to_add = 0;
732            if(plr)
733                points_to_add = GetPoints(plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5));
734            else
735                points_to_add = GetPoints(Player::GetUInt32ValueFromDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5,itr->guid));
736            // it's enough to set the points in memory, the saving is done in separate function
737            CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", points_to_add, Id, itr->guid);
738        }
739        // the player failed to participate in enough games, so no points for him
740        else
741        {
742            CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", 0, Id, itr->guid);
743        }
744    }
745}
746
747void ArenaTeam::SaveToDB()
748{
749    // save team and member stats to db
750    // called after a match has ended
751    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());
752    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)
753    {
754        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);
755    }
756}
757
758void ArenaTeam::FinishWeek()
759{
760    stats.games = 0; // played this week
761    stats.wins = 0; // wins this week
762    for(MemberList::iterator itr = members.begin(); itr !=  members.end(); ++itr)
763    {
764        itr->played_week = 0;
765        itr->wons_week = 0;
766    }
767}
768
769/*
770arenateam fields (id from 2.3.3 client):
7711414 - arena team id 2v2
7721415 - 0=captain, 1=member
7731416 - played this week
7741417 - played this season
7751418 - unk
7761419 - personal arena rating
7771420 - arena team id 3v3
7781421 - 0=captain, 1=member
7791422 - played this week
7801423 - played this season
7811424 - unk
7821425 - personal arena rating
7831426 - arena team id 5v5
7841427 - 0=captain, 1=member
7851428 - played this week
7861429 - played this season
7871430 - unk
7881431 - personal arena rating
789*/
Note: See TracBrowser for help on using the browser.