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

Revision 111, 29.9 kB (checked in by yumileroy, 17 years ago)

[svn] * Fixed xp calculation for low level characters when grouped with a higher level player. Patch provided by Reiner030.
* Fixed positive spells being not resistable when cast on hostile units. Patch provided by QAston.
* Fixed compile warnings in gcc. Patch provided by WarHead?.

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