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

Revision 247, 30.1 kB (checked in by yumileroy, 17 years ago)

Merge 246 and 247.

Original author: megamage
Date: 2008-11-16 17:22:48-06:00

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