rendered paste bodyIndex: src/game/ArenaTeam.cpp===================================================================--- src/game/ArenaTeam.cpp (revision 5306)+++ src/game/ArenaTeam.cpp (working copy)@@ -51,7 +51,7 @@ if(objmgr.GetArenaTeamByName(ArenaTeamName)) // arena team with this name already exist return false; - sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid));+ sLog.outDebug("GUILD: creating arena team %s to leader: %u", ArenaTeamName.c_str(), GUID_LOPART(captainGuid)); CaptainGuid = captainGuid; Name = ArenaTeamName;@@ -88,11 +88,21 @@ std::string plName; uint8 plClass; + if(GetMembersSize() >= GetType() * 2)+ {+ // arena team is full (can't have more than type * 2 players!)+ // return false+ return false;+ }+ if(!objmgr.GetPlayerNameByGUID(PlayerGuid, plName)) // player doesnt exist return false; // player already in arenateam of that size- if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetSlot()) != 0)+ if(Player::GetArenaTeamIdFromDB(PlayerGuid, GetType()) != 0)+ {+ sLog.outError("Arena::AddMember() : player already in this sized team"); return false;+ } // remove all player signs from another petitions // this will be prevent attempt joining player to many arenateams and corrupt arena team data integrity@@ -120,6 +130,7 @@ newmember.played_week = 0; newmember.wons_season = 0; newmember.wons_week = 0;+ newmember.points_to_add = 0; members.push_back(newmember); CharacterDatabase.PExecute("INSERT INTO arena_team_member (arenateamid,guid) VALUES ('%u', '%u')", Id, GUID_LOPART(newmember.guid));@@ -128,10 +139,14 @@ { pl->SetInArenaTeam(Id, GetSlot()); pl->SetArenaTeamIdInvited(0);+ // personal rating+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500); } else { Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), Id, PlayerGuid);+ // personal rating+ Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + 5, 1500, PlayerGuid); } // hide promote/remove buttons@@ -197,7 +212,7 @@ { Field *fields; - QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId);+ QueryResult *result = CharacterDatabase.PQuery("SELECT guid,played_week,wons_week,played_season,wons_season,points_to_add FROM arena_team_member WHERE arenateamid = '%u'", ArenaTeamId); if(!result) return; @@ -211,6 +226,7 @@ newmember.wons_week = fields[2].GetUInt32(); newmember.played_season = fields[3].GetUInt32(); newmember.wons_season = fields[4].GetUInt32();+ newmember.points_to_add = fields[5].GetUInt32(); members.push_back(newmember); }while( result->NextRow() ); delete result;@@ -269,13 +285,22 @@ { player->SetInArenaTeam(0, GetSlot()); player->GetSession()->SendArenaTeamCommandResult(ERR_ARENA_TEAM_QUIT_S, GetName(), "", 0);+ // delete all info regarding this team+ for(int i = 0; i < 6; ++i)+ {+ player->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0);+ Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0, guid);+ } } else {- Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6), 0, guid);+ // delete all info regarding this team+ for(int i = 0; i < 6; ++i)+ Player::SetUInt32ValueInDB(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot() * 6) + i, 0, guid); } - CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE guid = '%u'", GUID_LOPART(guid));+ // only delete from this arena team!+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u' AND guid = '%u'", GetId(), GUID_LOPART(guid)); } void ArenaTeam::Disband(WorldSession *session)@@ -302,6 +327,7 @@ CharacterDatabase.BeginTransaction(); CharacterDatabase.PExecute("DELETE FROM arena_team WHERE arenateamid = '%u'", Id);+ CharacterDatabase.PExecute("DELETE FROM arena_team_member WHERE arenateamid = '%u'", Id); CharacterDatabase.PExecute("DELETE FROM arena_team_stats WHERE arenateamid = '%u'", Id); CharacterDatabase.CommitTransaction(); objmgr.RemoveArenaTeam(this);@@ -380,6 +406,18 @@ session->SendPacket(&data); } +void ArenaTeam::NotifyStatsChanged()+{+ // this is called after a rated match ended+ // updates arena team stats for every member of the team (not only the ones who participated!)+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ Player * plr=objmgr.GetPlayer(itr->guid);+ if(plr)+ Stats(plr->GetSession());+ }+}+ void ArenaTeam::InspectStats(WorldSession *session, uint64 guid) { WorldPacket data(MSG_INSPECT_ARENA_STATS, 8+1+4*6);@@ -387,10 +425,20 @@ data << uint8(GetSlot()); // slot (0...2) data << uint32(GetId()); // arena team id data << uint32(stats.rating); // rating- data << uint32(stats.games); // games- data << uint32(stats.wins); // wins- data << uint32(stats.played); // played (count of all games, that played...)- data << uint32(0); // unk, 2.3.3+ data << uint32(stats.played); // season played+ data << uint32(stats.wins2); // season wins+ uint32 participated = 0;+ for(MemberList::iterator itr = members.begin(); itr!= members.end(); ++itr)+ {+ if(itr->guid == guid)+ {+ participated = itr->played_season;+ break;+ }+ }+ data << uint32(participated); // played (count of all games, that the inspected member participated...)+ data << uint32(0); // unk, 2.3.3 (personal rating?)+ session->SendPacket(&data); } @@ -468,24 +516,204 @@ } } +uint32 ArenaTeam::GetPoints()+{+ // returns how many points would be awarded with this team type with this rating+ float points;++ if(stats.rating<=1500)+ {+ points = (float)stats.rating * 0.22f + 14.0f;+ }+ else+ {+ points = 1511.26f / (1.0f + 1639.28f * exp(-0.00412f * (float)stats.rating));+ }++ // type penalties for <5v5 teams+ if(Type == ARENA_TEAM_2v2)+ points *= 0.76f;+ else if(Type == ARENA_TEAM_3v3)+ points *= 0.88f;++ return (uint32) points;+}++float ArenaTeam::GetChanceAgainst(uint32 rating)+{+ // returns the chance to win against a team with the given rating, used in the rating adjustment calculation+ // ELO system+ return 1.0f/(1.0f+exp(log(10.0f)*(float)((float)rating - (float)stats.rating)/400.0f));+}++int32 ArenaTeam::WonAgainstChance(float chance)+{+ // called when the team has won, and had 'chance' calculated chance to beat the opponent+ // calculate the rating modification (ELO system with k=32)+ int32 mod = (int32)(32.0f * (1.0f - chance));+ // modify the team stats accordingly+ stats.rating += mod;+ stats.games += 1;+ stats.wins += 1;+ stats.played += 1;+ stats.wins2 += 1;+/* this should be done in .flusharenapoints; not a breaker though.+ uint32 higher_rank = 0;+ QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT(arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);+ if(result)+ {+ higher_rank = result->Fetch()->GetUInt32();+ delete result;+ }+ stats.rank = higher_rank + 1;*/+ // return the rating change, used to display it on the results screen+ return mod;+}++int32 ArenaTeam::LostAgainstChance(float chance)+{+ // called when the team has lost, and had 'chance' calculated chance to beat the opponent+ // calculate the rating modification (ELO system with k=32)+ int32 mod = (int32)(32.0f * (0.0f - chance));+ // modify the team stats accordingly+ stats.rating += mod;+ stats.games += 1;+ stats.played += 1;+/* uint32 higher_rank = 0;+ QueryResult *result = CharacterDatabase.PQuery("SELECT DISTINCT COUNT (arenateamid) FROM arena_team_stats WHERE rating > '%u' AND arenateamid <> '%u'",stats.rating, Id);+ if(result)+ {+ higher_rank = result->Fetch()->GetUInt32();+ delete result;+ }+ stats.rank = higher_rank + 1;*/+ // return the rating adjustment for display+ return mod;+}++void ArenaTeam::MemberLost(Player * plr, uint32 againstrating)+{+ // called for each participant of a match after losing+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ if(itr->guid == plr->GetGUID())+ {+ // update personal rating+ int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);+ float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));+ int32 mod = (int32)(32.0f * (0.0f - chance));+ personalrating += mod;+ if(personalrating < 0)+ personalrating = 0;+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);+ // update personal played stats+ itr->played_week +=1;+ itr->played_season +=1;+ // update the unit fields+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);+ return;+ }+ }+}++void ArenaTeam::MemberWon(Player * plr, uint32 againstrating)+{+ // called for each participant after winning a match+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ if(itr->guid == plr->GetGUID())+ {+ // update personal rating+ int32 personalrating = plr->GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5);+ float chance = 1.0f/(1.0f+exp(log(10.0f)*(float)((float)againstrating - (float)personalrating)/400.0f));+ int32 mod = (int32)(32.0f * (1.0f - chance));+ personalrating += mod;+ if(personalrating < 0)+ personalrating = 0;+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (GetSlot()*6) + 5, personalrating);+ // update personal stats+ itr->played_week +=1;+ itr->played_season +=1;+ itr->wons_season += 1;+ itr->wons_week += 1;+ // update unit fields+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 2, itr->played_week);+ plr->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * GetSlot() + 3, itr->played_season);+ return;+ }+ }+}++uint32 ArenaTeam::GetMemberPoints(uint64 guid)+{+ // get the points a member should be awarded+ // called from arena point distribution (.flusharenapoints command)+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ if(itr->guid == guid)+ {+ return itr->points_to_add;+ }+ }+ return 0;+}++void ArenaTeam::UpdateArenaPointsHelper()+{+ // called after a match has ended and the stats are already modified+ // helper function for arena point distribution (this way, when distributing, no actual calculation is required, just a few comparisons)+ // 10 played games per week is a minimum+ if(stats.games < 10)+ return;+ // to get points, a player has to participate in at least 30% of the matches+ uint32 min_plays = stats.games * 0.3;+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ // the player participated in enough games, update his points+ if(itr->played_week >= min_plays)+ {+ // it's enough to set the points in memory, the saving is done in separate function+ itr->points_to_add = GetPoints();+ // CharacterDatabase.PExecute("UPDATE arena_team_member SET points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->points_to_add,Id, itr->guid);+ }+ // the player failed to participate in enough games, so no points for him+ else+ {+ itr->points_to_add = 0;+ }+ }+}++void ArenaTeam::SaveToDB()+{+ // save team and member stats to db+ // called after a match has ended+ CharacterDatabase.PExecute("UPDATE arena_team_stats SET rating = '%u',games = '%u',played = '%u',rank = '%u',wins = '%u',wins2 = '%u' WHERE arenateamid = '%u'", stats.rating, stats.games, stats.played, stats.rank, stats.wins, stats.wins2, GetId());+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ CharacterDatabase.PExecute("UPDATE arena_team_member SET played_week = '%u', wons_week = '%u', played_season = '%u', wons_season = '%u', points_to_add = '%u' WHERE arenateamid = '%u' AND guid = '%u'", itr->played_week, itr->wons_week, itr->played_season, itr->wons_season, itr->points_to_add, Id, itr->guid);+ }+}+ /* arenateam fields (id from 2.3.3 client): 1414 - arena team id 2v2 1415 - 0=captain, 1=member-1416 - played this season-1417 - played this week+1416 - played this week+1417 - played this season 1418 - unk-1419 - unk+1419 - personal arena rating 1420 - arena team id 3v3 1421 - 0=captain, 1=member-1422 - played this season-1423 - played this week+1422 - played this week+1423 - played this season 1424 - unk-1425 - unk+1425 - personal arena rating 1426 - arena team id 5v5 1427 - 0=captain, 1=member-1428 - played this season-1429 - played this week+1428 - played this week+1429 - played this season 1430 - unk-1431 - unk+1431 - personal arena rating */Index: src/game/ArenaTeam.h===================================================================--- src/game/ArenaTeam.h (revision 5306)+++ src/game/ArenaTeam.h (working copy)@@ -92,6 +92,7 @@ uint32 wons_week; uint32 played_season; uint32 wons_season;+ uint32 points_to_add; }; struct ArenaTeamStats@@ -145,6 +146,8 @@ void LoadStatsFromDB(uint32 ArenaTeamId); void LoadPlayerStats(ArenaTeamMember* member); + void SaveToDB();+ void BroadcastPacket(WorldPacket *packet); void Roster(WorldSession *session);@@ -152,6 +155,18 @@ void Stats(WorldSession *session); void InspectStats(WorldSession *session, uint64 guid); + uint32 GetPoints();+ float GetChanceAgainst(uint32 rating);+ int32 WonAgainstChance(float chance);+ void MemberWon(Player * plr, uint32 againstrating);+ int32 LostAgainstChance(float chance);+ void MemberLost(Player * plr, uint32 againstrating);++ void UpdateArenaPointsHelper();+ uint32 GetMemberPoints(uint64 guid);++ void NotifyStatsChanged();+ protected: uint32 Id;Index: src/game/ArenaTeamHandler.cpp===================================================================--- src/game/ArenaTeamHandler.cpp (revision 5306)+++ src/game/ArenaTeamHandler.cpp (working copy)@@ -111,7 +111,7 @@ return; } - if(player->getLevel() != 70)+ if(player->getLevel() < 70) { //SendArenaTeamCommandResult(ARENA_TEAM_INVITE_SS,"",Invitedname,ARENA_TEAM_PLAYER_NOT_FOUND_S); // can't find related opcode@@ -148,6 +148,14 @@ return; } + if(arenateam->GetMembersSize() >= arenateam->GetType() * 2)+ {+ // should send an "arena team is full" or the likes message, I just don't know the proper values so... ERR_INTERNAL+// SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, "", "", ERR_ARENA_TEAM_INTERNAL);+ SendNotification("Your arena team is full, %s cannot join it.", player->GetName());+ return;+ }+ sLog.outDebug("Player %s Invited %s to Join his ArenaTeam", GetPlayer()->GetName(), Invitedname.c_str()); player->SetArenaTeamIdInvited(GetPlayer()->GetArenaTeamId(team_slot));Index: src/game/BattleGround.cpp===================================================================--- src/game/BattleGround.cpp (revision 5306)+++ src/game/BattleGround.cpp (working copy)@@ -24,6 +24,7 @@ #include "Language.h" // for chat messages #include "Chat.h" #include "SpellAuras.h"+#include "ArenaTeam.h" #include "World.h" BattleGround::BattleGround()@@ -45,6 +46,8 @@ m_Name = ""; m_LevelMin = 0; m_LevelMax = 0;+ m_InBGFreeSlotQueue = false;+ m_SetDeleteThis = false; m_MaxPlayersPerTeam = 0; m_MaxPlayers = 0;@@ -65,6 +68,12 @@ m_TeamStartLocO[BG_TEAM_ALLIANCE] = 0; m_TeamStartLocO[BG_TEAM_HORDE] = 0; + m_ArenaTeamIds[BG_TEAM_ALLIANCE] = 0;+ m_ArenaTeamIds[BG_TEAM_HORDE] = 0;++ m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0;+ m_ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0;+ m_BgRaids[BG_TEAM_ALLIANCE] = NULL; m_BgRaids[BG_TEAM_HORDE] = NULL; @@ -74,12 +83,34 @@ BattleGround::~BattleGround() {+ // remove objects and creatures+ // (this is done automatically in mapmanager update, when the instance is reset after the reset time) + int size = m_BgCreatures.size();+ for(int i = 0; i < size; ++i)+ {+ DelCreature(i);+ }+ size = m_BgObjects.size();+ for(int i = 0; i < size; ++i)+ {+ DelObject(i);+ } + // delete bound char instances (this should have been already deleted?)+ CharacterDatabase.PExecute("DELETE FROM `character_instance` WHERE `instance` = '%u'", GetInstanceID());+ // delete creature and go respawn times+ WorldDatabase.PExecute("DELETE FROM `creature_respawn` WHERE `instance` = '%u'",GetInstanceID());+ WorldDatabase.PExecute("DELETE FROM `gameobject_respawn` WHERE `instance` = '%u'",GetInstanceID());+ // delete instance from db+ CharacterDatabase.PExecute("DELETE FROM `instance` WHERE id = '%u'",GetInstanceID());+ // remove from battlegrounds+ sBattleGroundMgr.RemoveBattleGround(GetInstanceID());+ // remove from bg free slot queue+ this->RemoveFromBGFreeSlotQueue(); } void BattleGround::Update(time_t diff) {- if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize()) //BG is empty return;@@ -236,7 +267,10 @@ if(!self && sender == plr) continue; - if(plr->GetTeam() == TeamID)+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+ if(!team) team = plr->GetTeam();++ if(team == TeamID) plr->GetSession()->SendPacket(packet); } }@@ -262,7 +296,10 @@ continue; } - if(plr->GetTeam() == TeamID)+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+ if(!team) team = plr->GetTeam();++ if(team == TeamID) { sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID); plr->GetSession()->SendPacket(&data);@@ -282,7 +319,10 @@ continue; } - if(plr->GetTeam() == TeamID)+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+ if(!team) team = plr->GetTeam();+ + if(team == TeamID) plr->CastSpell(plr, SpellID, true); } }@@ -299,7 +339,10 @@ continue; } - if(plr->GetTeam() == TeamID)+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+ if(!team) team = plr->GetTeam();++ if(team == TeamID) UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor); } }@@ -321,7 +364,10 @@ continue; } - if(plr->GetTeam() == TeamID)+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+ if(!team) team = plr->GetTeam();++ if(team == TeamID) plr->ModifyFactionReputation(factionEntry, Reputation); } }@@ -335,13 +381,22 @@ void BattleGround::EndBattleGround(uint32 winner) {+ this->RemoveFromBGFreeSlotQueue();++ ArenaTeam * winner_arena_team = NULL;+ ArenaTeam * loser_arena_team = NULL;+ uint32 loser_rating = 0;+ uint32 winner_rating = 0; WorldPacket data; Player *Source = NULL; const char *winmsg = ""; if(winner == ALLIANCE) {- winmsg = GetMangosString(LANG_BG_A_WINS);+ if(isBattleGround())+ winmsg = GetMangosString(LANG_BG_A_WINS);+ else+ winmsg = GetMangosString(LANG_ARENA_GOLD_WINS); PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound @@ -349,7 +404,10 @@ } else {- winmsg = GetMangosString(LANG_BG_H_WINS);+ if(isBattleGround())+ winmsg = GetMangosString(LANG_BG_H_WINS);+ else+ winmsg = GetMangosString(LANG_ARENA_GREEN_WINS); PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound @@ -359,6 +417,47 @@ SetStatus(STATUS_WAIT_LEAVE); m_EndTime = 0; + // arena rating calculation+ if(isArena() && isRated())+ {+ if(winner == ALLIANCE)+ {+ winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));+ loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));+ }+ else+ {+ winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));+ loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));+ }+ if(winner_arena_team && loser_arena_team)+ {+ loser_rating = loser_arena_team->GetStats().rating;+ winner_rating = winner_arena_team->GetStats().rating;+ float winner_chance = winner_arena_team->GetChanceAgainst(loser_rating);+ float loser_chance = loser_arena_team->GetChanceAgainst(winner_rating);+ int32 winner_change = winner_arena_team->WonAgainstChance(winner_chance);+ int32 loser_change = loser_arena_team->LostAgainstChance(loser_chance);+ if(winner == ALLIANCE)+ {+ SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);+ SetArenaTeamRatingChangeForTeam(HORDE, loser_change);+ }+ else+ {+ SetArenaTeamRatingChangeForTeam(HORDE, winner_change);+ SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);+ }+ winner_arena_team->UpdateArenaPointsHelper();+ loser_arena_team->UpdateArenaPointsHelper();+ }+ else+ {+ SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);+ SetArenaTeamRatingChangeForTeam(HORDE, 0);+ }+ }+ uint32 mark = 0; for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)@@ -370,14 +469,30 @@ continue; } + // should remove spirit of redemption+ if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))+ plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);+ if(!plr->isAlive()) { plr->ResurrectPlayer(1.0f); plr->SpawnCorpseBones(); } - if(plr->GetTeam() == winner)+ uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());+ if(!team) team = plr->GetTeam();++ // per player calculation+ if(isArena() && isRated() && winner_arena_team && loser_arena_team) {+ if(team == winner)+ winner_arena_team->MemberWon(plr,loser_rating);+ else+ loser_arena_team->MemberLost(plr,winner_rating);+ }++ if(team == winner)+ { if(!Source) Source = plr; switch(GetTypeID())@@ -428,10 +543,25 @@ sBattleGroundMgr.BuildPvpLogDataPacket(&data, this); plr->GetSession()->SendPacket(&data); - sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); plr->GetSession()->SendPacket(&data); } + if(isArena() && isRated() && winner_arena_team && loser_arena_team)+ {+ // save the stat changes+ winner_arena_team->SaveToDB();+ loser_arena_team->SaveToDB();+ // send updated arena team stats to players+ // this way all arena team members will get notified, not only the ones who participated in this match+ winner_arena_team->NotifyStatsChanged();+ loser_arena_team->NotifyStatsChanged();+ }++ // inform invited players about the removal+ sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);+ if(Source) { ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_GLOBAL, Source->GetGUID(), winmsg);@@ -448,11 +578,12 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket) {+ uint32 team = GetPlayerTeam(guid); // Remove from lists/maps std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid); if(itr != m_Players.end()) {- UpdatePlayersCountByTeam(itr->second.Team, true); // -1 player+ UpdatePlayersCountByTeam(team, true); // -1 player m_Players.erase(itr); } @@ -467,6 +598,10 @@ Player *plr = objmgr.GetPlayer(guid); + // should remove spirit of redemption+ if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))+ plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);+ if(plr && !plr->isAlive()) // resurrect on exit { plr->ResurrectPlayer(1.0f);@@ -477,41 +612,103 @@ if(plr) {+ if(!team) team = plr->GetTeam();++ uint32 bgTypeId = GetTypeID();+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());+ // if arena, remove the specific arena auras if(isArena()) {- if(!sWorld.IsFFAPvPRealm())- plr->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);+ plr->RemoveArenaAuras(true); // removes debuffs / dots etc., we don't want the player to die after porting out+ plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);+ plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_GOLD_FLAG);+ plr->RemoveAurasDueToSpell(SPELL_ALLIANCE_GREEN_FLAG);+ plr->RemoveAurasDueToSpell(SPELL_HORDE_GOLD_FLAG);+ plr->RemoveAurasDueToSpell(SPELL_HORDE_GREEN_FLAG);+ bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing) - plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);+ Pet* NewPet = new Pet(plr);+ if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetOldPetNumber(), true))+ delete NewPet;++ (plr)->SetOldPetNumber(0);+ if(isRated() && GetStatus() == STATUS_IN_PROGRESS)+ {+ //left a rated match while the encounter was in progress, consider as loser+ ArenaTeam * winner_arena_team = 0;+ ArenaTeam * loser_arena_team = 0;+ if(team == HORDE)+ {+ winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));+ loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));+ }+ else+ {+ winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));+ loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));+ }+ if(winner_arena_team && loser_arena_team)+ {+ loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());+ }+ } } WorldPacket data; if(SendPacket) {- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0); plr->GetSession()->SendPacket(&data); } // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg- plr->RemoveBattleGroundQueueId(m_TypeID);+ plr->RemoveBattleGroundQueueId(bgQueueTypeId); - DecreaseInvitedCount(plr->GetTeam());+ DecreaseInvitedCount(team); //we should update battleground queue, but only if bg isn't ending if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)- sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].Update(GetTypeID(), GetQueueType());+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType()); if(!plr->GetBattleGroundId()) return; Group * group = plr->GetGroup();- // remove from raid group if exist- if(group && group == GetBgRaid(plr->GetTeam()))+ if(group && group == GetBgRaid(team)) {+ uint32 groupSize = group->GetMembersCount();+ GroupReference * grpRef = group->GetFirstMember();+ Player * grpGuy = grpRef->getSource();+ // get a member of the group, will be used if the group is disbanded+ // if the one we got is the player, get another+ if(grpGuy->GetGUID()==guid)+ {+ if(grpRef->hasNext()) + {+ grpRef = grpRef->next();+ grpGuy = grpRef->getSource();+ }+ else if(grpRef->hasPrev())+ {+ grpRef = (GroupReference*)grpRef->prev();+ grpGuy = grpRef->getSource();+ }+ else+ grpGuy = NULL;+ } if(!group->RemoveMember(guid, 0)) // group was disbanded {- SetBgRaid(plr->GetTeam(), NULL);+ SetBgRaid(team, NULL); delete group;+ if(groupSize >= 2 && grpGuy != 0) // someone's still left in the bg, recreate group for him+ {+ group = new Group;+ SetBgRaid(team, group);+ group->ConvertToRaid();+ group->AddMember(grpGuy->GetGUID(), grpGuy->GetName());+ group->ChangeLeader(grpGuy->GetGUID());+ // we don't have to add other players, since the group is only disbanded if the player count before the leave was exactly 2+ } } } @@ -520,11 +717,12 @@ // Let others know sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);- SendPacketToTeam(plr->GetTeam(), &data, plr, false);+ SendPacketToTeam(team, &data, plr, false); if(Transport) { plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO(), true, false);+ //plr->SetInstanceId(plr->GetBattleGroundEntryPointInstanceId()); //sLog.outDetail("BATTLEGROUND: Sending %s to %f,%f,%f,%f", pl->GetName(), x,y,z,O); } @@ -532,13 +730,29 @@ sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName()); } + // remove player from bg instance!+ CharacterDatabase.PExecute("DELETE FROM `character_instance` WHERE `guid` = '%u' AND `instance` = '%u'", guid, GetInstanceID());++ if(plr)+ {+ // remove player from bg instance!!!+ plr->m_BoundInstances.erase(GetMapId());+ }+ /// there will be code which will add battleground to BGFreeSlotQueue , when battleground instance will exist // we always should check if BG is in that queue before adding.. - if(!GetPlayersSize())+ if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE)) {- Reset();+ // if no players left AND no invitees left, set this bg to delete in next update+ // direct deletion could cause crashes+ m_SetDeleteThis = true;+ // return to prevent addition to freeslotqueue+ return; }++ // a player exited the battleground, so there are free slots. add to queue+ this->AddToBGFreeSlotQueue(); } // this method is called when no players remains in battleground@@ -550,6 +764,8 @@ SetStartTime(0); SetEndTime(0); SetLastResurrectTime(0);+ SetArenaType(0);+ SetRated(false); m_Events = 0; @@ -558,11 +774,12 @@ m_InvitedAlliance = 0; m_InvitedHorde = 0;+ m_InBGFreeSlotQueue = false; m_Players.clear(); m_PlayerScores.clear(); - // reset BGSubclass+ // reset BGSubclass (this cleans up creatures and gos as well) this->ResetBGSubclass(); } @@ -575,52 +792,64 @@ WorldPacket data; BattleGround *bg = NULL;-- /// this code seems not correct:- if(GetTypeID() == BATTLEGROUND_AA)- {- // we must select one of running arena- uint8 arenas[3] = { BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL };- uint8 arena_type = arenas[urand(0, 2)];-- bg = sBattleGroundMgr.GetBattleGround(arena_type);- if(!bg)- return;-- bg->SetStatus(STATUS_WAIT_JOIN);-- bg->SetStartTime(0);- bg->SetLastResurrectTime(0);- } } -void BattleGround::AddPlayer(Player *plr)+void BattleGround::AddPlayer(Player *plr, uint32 team) { // score struct must be created in inherited class+ if(team==0)+ team = plr->GetTeam(); uint64 guid = plr->GetGUID(); BattleGroundPlayer bp; bp.LastOnlineTime = 0;- bp.Team = plr->GetTeam();+ bp.Team = team; // Add to list/maps m_Players[guid] = bp; - UpdatePlayersCountByTeam(plr->GetTeam(), false); // +1 player+ UpdatePlayersCountByTeam(team, false); // +1 player WorldPacket data; sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);- SendPacketToTeam(plr->GetTeam(), &data, plr, false);+ SendPacketToTeam(team, &data, plr, false); + // add arena specific auras if(isArena()) {+ plr->RemoveArenaSpellCooldowns();+ plr->RemoveArenaAuras();+ if(team == ALLIANCE && plr->GetTeam() == ALLIANCE)+ plr->CastSpell(plr,SPELL_ALLIANCE_GOLD_FLAG,true);+ else if(team == HORDE && plr->GetTeam() == ALLIANCE)+ plr->CastSpell(plr,SPELL_ALLIANCE_GREEN_FLAG,true);+ else if(team == ALLIANCE && plr->GetTeam() == HORDE)+ plr->CastSpell(plr,SPELL_HORDE_GOLD_FLAG,true);+ else+ plr->CastSpell(plr,SPELL_HORDE_GREEN_FLAG,true);+ plr->DestroyConjuredItems(true);++ Pet* pet = plr->GetPet();+ if(pet)+ {+ if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)+ {+ (plr)->SetOldPetNumber(pet->GetCharmInfo()->GetPetNumber());+ (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));+ }+ (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);+ }+ else+ (plr)->SetOldPetNumber(0);+ if(GetStatus() == STATUS_WAIT_JOIN) // not started yet {- // temporary disabled- //plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);+ plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);++ plr->SetHealth(plr->GetMaxHealth());+ plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA)); }- plr->SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP); } // Log@@ -630,13 +859,20 @@ /* This method should be called only once ... it adds pointer to queue */ void BattleGround::AddToBGFreeSlotQueue() {- sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);+ // make sure to add only once+ if(!m_InBGFreeSlotQueue)+ {+ sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);+ m_InBGFreeSlotQueue = true;+ } } /* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/ void BattleGround::RemoveFromBGFreeSlotQueue() {- /* uncomment this code when battlegrounds will work like instances+ // set to be able to re-add if needed+ m_InBGFreeSlotQueue = false;+ // uncomment this code when battlegrounds will work like instances for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr) { if ((*itr)->GetInstanceID() == m_InstanceID)@@ -644,7 +880,7 @@ sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr); return; }- }*/+ } } /*@@ -667,6 +903,31 @@ return false; } +// get the number of free slots for team+// works in similar way that HasFreeSlotsForTeam+uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const+{+ //if BG is starting ... invite anyone:+ if (GetStatus() == STATUS_WAIT_JOIN)+ return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;+ //if BG is already started .. do not allow to join too much players of one faction+ uint32 otherTeam;+ if (Team == ALLIANCE)+ otherTeam = GetInvitedCount(HORDE);+ else+ otherTeam = GetInvitedCount(ALLIANCE);+ if (GetStatus() == STATUS_IN_PROGRESS)+ {+ uint32 diff = (otherTeam <= GetInvitedCount(Team)) ? 0 : otherTeam - GetInvitedCount(Team);++ uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;++ return diff < diff2 ? diff : diff2 ;+ }++ return 0;+}+ /* this method isn't called already, it will be useful when more battlegrounds of one type will be available */ bool BattleGround::HasFreeSlots() const {@@ -693,7 +954,9 @@ itr->second->HonorableKills += value; break; case SCORE_BONUS_HONOR: // Honor bonus- itr->second->BonusHonor += value;+ // do not add honor in arenas+ if(isBattleGround()) + itr->second->BonusHonor += value; break; //used only in EY, but in MSG_PVP_LOG_DATA opcode case SCORE_DAMAGE_DONE: // Damage Done@@ -747,49 +1010,30 @@ bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 spawntime) {- GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry);- if(!goinfo)+ GameObject * go = new GameObject(NULL);+ go->SetInstanceId(GetInstanceID());+ if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, GetMapId(),x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1)) {- sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);+ sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);+ delete go; return false; } - uint32 guid = objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT);-- GameObjectData& data = objmgr.NewGOData(guid);-- data.id = entry;- data.mapid = GetMapId();- data.posX = x;- data.posY = y;- data.posZ = z;- data.orientation = o;- data.rotation0 = rotation0;- data.rotation1 = rotation1;- data.rotation2 = rotation2;- data.rotation3 = rotation3;- data.spawntimesecs = spawntime;- data.animprogress = 100;- data.go_state = 1;- objmgr.AddGameobjectToGrid(guid, &data);-- m_BgObjects[type] = MAKE_GUID(guid, HIGHGUID_GAMEOBJECT);-+ m_BgObjects[type] = go; return true; } void BattleGround::DoorOpen(uint32 type) {- GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);+ GameObject *obj = m_BgObjects[type]; if(obj) { obj->SetUInt32Value(GAMEOBJECT_FLAGS,33); obj->SetUInt32Value(GAMEOBJECT_STATE,0);- //obj->SetLootState(GO_CLOSED); } else {- sLog.outError("Object not found");+ sLog.outError("Battleground: DoorOpen: Object not found"); } } @@ -797,32 +1041,31 @@ { if(respawntime == 0) {- GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);+ GameObject *obj = m_BgObjects[type]; if(obj) { //obj->Respawn(); // bugged obj->SetRespawnTime(0);- objmgr.SaveGORespawnTime(obj->GetGUIDLow(), 0, 0);+ objmgr.SaveGORespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);+ MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj); }- else- objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, 0); } else {- GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);+ GameObject *obj = m_BgObjects[type]; if(obj) { obj->SetRespawnTime(respawntime); obj->SetLootState(GO_LOOTED);+ MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj); }- else- objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, time(NULL) + respawntime); } } -Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o)+Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime) { Creature* pCreature = new Creature(NULL);+ pCreature->SetInstanceId(GetInstanceID()); if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), GetMapId(), x, y, z, o, entry, teamval)) { sLog.outError("Can't create creature entry: %u",entry);@@ -833,17 +1076,42 @@ pCreature->AIM_Initialize(); //pCreature->SetDungeonDifficulty(0);- MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature);- m_BgCreatures[type] = pCreature->GetGUID();+ m_BgCreatures[type] = pCreature;+ return pCreature; } +void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)+{+ if(respawntime == 0)+ {+ Creature *obj = m_BgCreatures[type];+ if(obj)+ {+ //obj->Respawn(); // bugged+ obj->SetRespawnTime(0);+ objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);+ MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);+ }+ }+ else+ {+ Creature *obj = m_BgCreatures[type];+ if(obj)+ {+ obj->setDeathState(DEAD);+ obj->SetRespawnTime(respawntime);+ MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);+ }+ }+}+ bool BattleGround::DelCreature(uint32 type) {- Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);+ Creature *cr = m_BgCreatures[type]; if(!cr) {- sLog.outError("Can't find creature guid: %u",m_BgCreatures[type]);+ sLog.outError("Can't find creature."); return false; } cr->CleanupsBeforeDelete();@@ -854,10 +1122,10 @@ bool BattleGround::DelObject(uint32 type) {- GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);+ GameObject *obj = m_BgObjects[type]; if(!obj) {- sLog.outError("Can't find gobject guid: %u",m_BgObjects[type]);+ sLog.outError("Can't find gobject."); return false; } obj->SetRespawnTime(0); // not save respawn time@@ -927,3 +1195,28 @@ { return objmgr.GetMangosString(entry); }++// return the player's team based on battlegroundplayer info+// used in same faction arena matches mainly+uint32 BattleGround::GetPlayerTeam(uint64 guid)+{+ std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);+ if(itr!=m_Players.end())+ return itr->second.Team;+ return 0;+}++uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const+{+ int count = 0;+ for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)+ {+ if(itr->second.Team == Team)+ {+ Player * pl = objmgr.GetPlayer(itr->first);+ if(pl && pl->isAlive())+ ++count;+ }+ }+ return count;+}Index: src/game/BattleGround.h===================================================================--- src/game/BattleGround.h (revision 5306)+++ src/game/BattleGround.h (working copy)@@ -51,7 +51,11 @@ SPELL_SPIRIT_HEAL_CHANNEL = 22011, SPELL_SPIRIT_HEAL = 22012, SPELL_RESURRECTION_VISUAL = 24171,- SPELL_ARENA_PREPARATION = 32727+ SPELL_ARENA_PREPARATION = 32728, // use this one, 32727 causes problems with creature visibility updates, thus client crashes.+ SPELL_ALLIANCE_GOLD_FLAG = 32724,+ SPELL_ALLIANCE_GREEN_FLAG = 32725,+ SPELL_HORDE_GOLD_FLAG = 35774,+ SPELL_HORDE_GREEN_FLAG = 35775 }; enum BattleGroundTimeIntervals@@ -115,6 +119,18 @@ BATTLEGROUND_RL = 8 }; +// handle the queue types and bg types separately to enable joining queue for different sized arenas at the same time+enum BattleGroundQueueTypeId+{+ BATTLEGROUND_QUEUE_AV = 1,+ BATTLEGROUND_QUEUE_WS = 2,+ BATTLEGROUND_QUEUE_AB = 3,+ BATTLEGROUND_QUEUE_EY = 4,+ BATTLEGROUND_QUEUE_2v2 = 5,+ BATTLEGROUND_QUEUE_3v3 = 6,+ BATTLEGROUND_QUEUE_5v5 = 7,+};+ enum ScoreType { SCORE_KILLING_BLOWS = 1,@@ -194,6 +210,7 @@ public: /* Construction */ BattleGround();+ /*BattleGround(const BattleGround& bg);*/ virtual ~BattleGround(); virtual void Update(time_t diff); // must be implemented in BG subclass of BG specific update code, but must in begginning call parent version virtual bool SetupBattleGround() // must be implemented in BG subclass@@ -263,6 +280,7 @@ } bool HasFreeSlotsForTeam(uint32 Team) const; bool HasFreeSlots() const;+ uint32 GetFreeSlotsForTeam(uint32 Team) const; bool isArena() const { return m_IsArena; } bool isBattleGround() const { return !m_IsArena; }@@ -328,6 +346,7 @@ uint8 GetTeamIndexByTeamId(uint32 Team) const { return Team == ALLIANCE ? BG_TEAM_ALLIANCE : BG_TEAM_HORDE; } uint32 GetPlayersCountByTeam(uint32 Team) const { return m_PlayersCount[GetTeamIndexByTeamId(Team)]; }+ uint32 GetAlivePlayersCountByTeam(uint32 Team) const; // used in arenas to correctly handle death in spirit of redemption / last stand etc. (killer = killed) cases void UpdatePlayersCountByTeam(uint32 Team, bool remove) { if(remove)@@ -336,6 +355,12 @@ m_PlayersCount[GetTeamIndexByTeamId(Team)]++; } + // used for rated arena battles+ void SetArenaTeamIdForTeam(uint32 Team, uint32 ArenaTeamId) { m_ArenaTeamIds[ Team == ALLIANCE ? 0 : 1] = ArenaTeamId; }+ uint32 GetArenaTeamIdForTeam(uint32 Team) const { return m_ArenaTeamIds[ Team == ALLIANCE ? 0 : 1]; }+ void SetArenaTeamRatingChangeForTeam(uint32 Team, int32 ArenaTeamId) { m_ArenaTeamRatingChanges[ Team == ALLIANCE ? 0 : 1] = ArenaTeamId; }+ uint32 GetArenaTeamRatingChangeForTeam(uint32 Team) const { return m_ArenaTeamRatingChanges[ Team == ALLIANCE ? 0 : 1]; }+ /* Triggers handle */ // must be implemented in BG subclass virtual void HandleAreaTrigger(Player* /*Source*/, uint32 /*Trigger*/) {}@@ -344,18 +369,19 @@ // must be implemented in BG subclass if need virtual void HandleDropFlag(Player* /*player*/) {} - virtual void AddPlayer(Player *plr); // must be implemented in BG subclass+ virtual void AddPlayer(Player *plr, uint32 team = 0); // must be implemented in BG subclass virtual void RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket); // can be extended in in BG subclass // TODO: make this protected:- typedef std::vector<uint64> BGObjects;- typedef std::vector<uint64> BGCreatures;+ typedef std::vector<GameObject*> BGObjects;+ typedef std::vector<Creature*> BGCreatures; BGObjects m_BgObjects; BGCreatures m_BgCreatures; void SpawnBGObject(uint32 type, uint32 respawntime);+ void SpawnBGCreature(uint32 type, uint32 respawntime); bool AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawntime = 0);- Creature* AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o);+ Creature* AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime = 0); bool DelCreature(uint32 type); bool DelObject(uint32 type); bool AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team);@@ -363,6 +389,11 @@ void DoorOpen(uint32 type); const char *GetMangosString(uint32 entry); + // since arenas can be AvA or Hvh, we have to get the "temporary" team of a player+ uint32 GetPlayerTeam(uint64 guid);++ void SetDeleteThis() {m_SetDeleteThis = true;}+ protected: //this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround void EndNow();@@ -390,6 +421,8 @@ uint32 m_LastResurrectTime; uint32 m_Queue_type; uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5+ bool m_InBGFreeSlotQueue; // used to make sure that BG is only once inserted into the BattleGroundMgr.BGFreeSlotQueue[bgTypeId] deque+ bool m_SetDeleteThis; // used for safe deletion of the bg after end / all players leave // this variable is not used .... it can be found in many other ways... but to store it in BG object instance is useless //uint8 m_BattleGroundType; // 3=BG, 4=arena //instead of uint8 (in previous line) is bool used@@ -415,6 +448,11 @@ /* Players count by team */ uint32 m_PlayersCount[2]; + /* Arena team ids by team */+ uint32 m_ArenaTeamIds[2];++ int32 m_ArenaTeamRatingChanges[2];+ /* Limits */ uint32 m_LevelMin; uint32 m_LevelMax;Index: src/game/BattleGroundAA.cpp===================================================================--- src/game/BattleGroundAA.cpp (revision 5306)+++ src/game/BattleGroundAA.cpp (working copy)@@ -35,9 +35,9 @@ BattleGround::Update(diff); } -void BattleGroundAA::AddPlayer(Player *plr)+void BattleGroundAA::AddPlayer(Player *plr, uint32 team) {- BattleGround::AddPlayer(plr);+ BattleGround::AddPlayer(plr,team); //create score and add it to map, default values are set in constructor BattleGroundAAScore* sc = new BattleGroundAAScore; Index: src/game/BattleGroundAA.h===================================================================--- src/game/BattleGroundAA.h (revision 5306)+++ src/game/BattleGroundAA.h (working copy)@@ -38,7 +38,7 @@ void Update(time_t diff); /* inherited from BattlegroundClass */- virtual void AddPlayer(Player *plr);+ virtual void AddPlayer(Player *plr, uint32 team = 0); void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); bool SetupBattleGround();Index: src/game/BattleGroundAB.cpp===================================================================--- src/game/BattleGroundAB.cpp (revision 5306)+++ src/game/BattleGroundAB.cpp (working copy)@@ -36,6 +36,33 @@ BattleGroundAB::~BattleGroundAB() {+ // despawn objects / creatures here too, maybe the BG ends when the last not-ported invitee leaves the queue+ sLog.outDebug("Arathi Basin: BG ended, objects despawning...");++ // delete everything (for times, when BG will instanced)+ for(uint32 i = 0; i < BG_AB_OBJECT_MAX; i++)+ if (m_bgobjects[i])+ {+ m_bgobjects[i]->SetRespawnTime(0);+ m_bgobjects[i]->Delete();+ m_bgobjects[i] = NULL;+ }++ for(uint32 node = 0; node < BG_AB_NODES_COUNT; node++)+ if (m_bgbuffobjects[node].object)+ {+ m_bgbuffobjects[node].object->SetRespawnTime(0);+ m_bgbuffobjects[node].object->Delete();+ m_bgbuffobjects[node].object = NULL;+ }++ for(uint32 node = 0; node < 7; node++)+ if (m_spiritGuides[node])+ {+ m_spiritGuides[node]->CleanupsBeforeDelete();+ ObjectAccessor::Instance().AddObjectToRemoveList(m_spiritGuides[node]);+ m_spiritGuides[node] = NULL;+ } } void BattleGroundAB::Update(time_t diff)@@ -205,6 +232,7 @@ { uint8 buff = urand(0, 2); m_bgbuffobjects[node].object = new GameObject(NULL);+ m_bgbuffobjects[node].object->SetInstanceId(GetInstanceID()); if (!m_bgbuffobjects[node].object->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_BuffObjects[buff][0], GetMapId(), BG_AB_BuffPositions[node][0], BG_AB_BuffPositions[node][1], BG_AB_BuffPositions[node][2], BG_AB_BuffPositions[node][3], 0, 0, sin(BG_AB_BuffPositions[node][3]/2), cos(BG_AB_BuffPositions[node][3]/2), 0, 0)) ASSERT(0); m_bgbuffobjects[node].spellId = BG_AB_BuffObjects[buff][1];@@ -226,6 +254,7 @@ if (spell) plr->CastSpell(plr, spell, true, 0); m_bgbuffobjects[node].timer = BG_AB_BUFF_RESPAWN_TIME;+ m_bgbuffobjects[node].object->SetRespawnTime(0); m_bgbuffobjects[node].object->Delete(); m_bgbuffobjects[node].object = NULL; break;@@ -237,9 +266,9 @@ } } -void BattleGroundAB::AddPlayer(Player *plr)+void BattleGroundAB::AddPlayer(Player *plr, uint32 team) {- BattleGround::AddPlayer(plr);+ BattleGround::AddPlayer(plr, team); //create score and add it to map, default values are set in the constructor BattleGroundABScore* sc = new BattleGroundABScore; @@ -249,7 +278,7 @@ void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) { - if(GetPlayersSize()==0)+ if(GetPlayersSize()==0 && GetInvitedCount(ALLIANCE)==0 && GetInvitedCount(HORDE)==0) { sLog.outDebug("Arathi Basin: BG ended, objects despawning..."); @@ -257,6 +286,7 @@ for(uint32 i = 0; i < BG_AB_OBJECT_MAX; i++) if (m_bgobjects[i]) {+ m_bgobjects[i]->SetRespawnTime(0); m_bgobjects[i]->Delete(); m_bgobjects[i] = NULL; }@@ -264,6 +294,7 @@ for(uint32 node = 0; node < BG_AB_NODES_COUNT; node++) if (m_bgbuffobjects[node].object) {+ m_bgbuffobjects[node].object->SetRespawnTime(0); m_bgbuffobjects[node].object->Delete(); m_bgbuffobjects[node].object = NULL; }@@ -276,9 +307,10 @@ m_spiritGuides[node] = NULL; } + // no use, the bg will be deleted soonish // re-setup- Reset();- SetupBattleGround();+ // Reset();+ // SetupBattleGround(); // Only change back to STATUS_WAIT_QUEUE if successfully re-setuped } }@@ -342,6 +374,7 @@ else goId = BG_AB_OBJECTID_BANNER_H; m_bgobjects[obj] = new GameObject(NULL);+ m_bgobjects[obj]->SetInstanceId(GetInstanceID()); m_bgobjects[obj]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), goId, GetMapId(), BG_AB_NodePositions[node][0], BG_AB_NodePositions[node][1], BG_AB_NodePositions[node][2], BG_AB_NodePositions[node][3], 0, 0, sin(BG_AB_NodePositions[node][3]/2), cos(BG_AB_NodePositions[node][3]/2), 100, 1); MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]); @@ -349,7 +382,8 @@ if (!type) return; obj = node*8 + ((type == 3) ? (5 + teamIndex) : 7);- MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]);+ if(m_bgobjects[obj])+ MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]); } void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex)@@ -357,13 +391,16 @@ uint8 obj = node*8 + type + teamIndex; if (!m_bgobjects[obj]) return;++ m_bgobjects[obj]->SetRespawnTime(0); m_bgobjects[obj]->Delete(); m_bgobjects[obj] = NULL; // handle aura with banner if (!type) return; obj = node*8 + ((type == 3) ? (5 + teamIndex) : 7);- MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Remove(m_bgobjects[obj], false);+ if(m_bgobjects[obj])+ MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Remove(m_bgobjects[obj], false); } const char* BattleGroundAB::_GetNodeName(uint8 node)@@ -463,6 +500,7 @@ if (m_spiritGuides[node]) return; m_spiritGuides[node] = new Creature(NULL);+ m_spiritGuides[node]->SetInstanceId(GetInstanceID()); if (!m_spiritGuides[node]->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), 529, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], (node>4)?BG_AB_SpiritGuideId[node-5]:BG_AB_SpiritGuideId[m_Nodes[node]-3], (node>4)?BG_AB_SpiritGuideTeamId[node-5]:BG_AB_SpiritGuideTeamId[m_Nodes[node]-3])) ASSERT(0); m_spiritGuides[node]->setDeathState(DEAD);@@ -506,6 +544,7 @@ // despawn buff object if ((node < BG_AB_NODES_COUNT) && (m_bgbuffobjects[node].object)) {+ m_bgbuffobjects[node].object->SetRespawnTime(0); m_bgbuffobjects[node].object->Delete(); m_bgbuffobjects[node].object = NULL; }@@ -626,6 +665,7 @@ for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i) { m_bgobjects[banner] = new GameObject(NULL);+ m_bgobjects[banner]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_NODE_BANNER_0+i, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 100, 1)) return false; }@@ -634,27 +674,32 @@ for (int banner = BG_AB_OBJECT_AURA_ALLY, i = 0; i < 5; banner += 8, ++i) { m_bgobjects[banner] = new GameObject(NULL);+ m_bgobjects[banner]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_A, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0)) return false; } for (int banner = BG_AB_OBJECT_AURA_HORDE, i = 0; i < 5; banner += 8, ++i) { m_bgobjects[banner] = new GameObject(NULL);+ m_bgobjects[banner]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_H, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0)) return false; } for (int banner = BG_AB_OBJECT_AURA_CONTESTED, i = 0; i < 5; banner += 8, ++i) { m_bgobjects[banner] = new GameObject(NULL);+ m_bgobjects[banner]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_C, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0)) return false; } // Starting gates m_bgobjects[BG_AB_OBJECT_GATE_A] = new GameObject(NULL);+ m_bgobjects[BG_AB_OBJECT_GATE_A]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[BG_AB_OBJECT_GATE_A]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_GATE_A, GetMapId(), BG_AB_DoorPositions[0][0], BG_AB_DoorPositions[0][1], BG_AB_DoorPositions[0][2], BG_AB_DoorPositions[0][3], BG_AB_DoorPositions[0][4], BG_AB_DoorPositions[0][5], BG_AB_DoorPositions[0][6], BG_AB_DoorPositions[0][7], 100, 1)) return false; m_bgobjects[BG_AB_OBJECT_GATE_H] = new GameObject(NULL);+ m_bgobjects[BG_AB_OBJECT_GATE_H]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[BG_AB_OBJECT_GATE_H]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_GATE_H, GetMapId(), BG_AB_DoorPositions[1][0], BG_AB_DoorPositions[1][1], BG_AB_DoorPositions[1][2], BG_AB_DoorPositions[1][3], BG_AB_DoorPositions[1][4], BG_AB_DoorPositions[1][5], BG_AB_DoorPositions[1][6], BG_AB_DoorPositions[1][7], 100, 1)) return false; @@ -757,3 +802,7 @@ ++++Index: src/game/BattleGroundAB.h===================================================================--- src/game/BattleGroundAB.h (revision 5306)+++ src/game/BattleGroundAB.h (working copy)@@ -222,7 +222,7 @@ ~BattleGroundAB(); void Update(time_t diff);- void AddPlayer(Player *plr);+ void AddPlayer(Player *plr, uint32 team = 0); void RemovePlayer(Player *plr,uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); virtual bool SetupBattleGround();Index: src/game/BattleGroundAV.cpp===================================================================--- src/game/BattleGroundAV.cpp (revision 5306)+++ src/game/BattleGroundAV.cpp (working copy)@@ -39,9 +39,9 @@ BattleGround::Update(diff); } -void BattleGroundAV::AddPlayer(Player *plr)+void BattleGroundAV::AddPlayer(Player *plr, uint32 team) {- BattleGround::AddPlayer(plr);+ BattleGround::AddPlayer(plr, team); //create score and add it to map, default values are set in constructor BattleGroundAVScore* sc = new BattleGroundAVScore; Index: src/game/BattleGroundAV.h===================================================================--- src/game/BattleGroundAV.h (revision 5306)+++ src/game/BattleGroundAV.h (working copy)@@ -45,7 +45,7 @@ void Update(time_t diff); /* inherited from BattlegroundClass */- virtual void AddPlayer(Player *plr);+ virtual void AddPlayer(Player *plr, uint32 team = 0); void RemovePlayer(Player *plr,uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger);Index: src/game/BattleGroundBE.cpp===================================================================--- src/game/BattleGroundBE.cpp (revision 5306)+++ src/game/BattleGroundBE.cpp (working copy)@@ -89,6 +89,11 @@ if(plr) plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); }++ if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+ EndBattleGround(HORDE);+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))+ EndBattleGround(ALLIANCE); } } @@ -98,9 +103,9 @@ }*/ } -void BattleGroundBE::AddPlayer(Player *plr)+void BattleGroundBE::AddPlayer(Player *plr, uint32 team) {- BattleGround::AddPlayer(plr);+ BattleGround::AddPlayer(plr, team); //create score and add it to map, default values are set in constructor BattleGroundBEScore* sc = new BattleGroundBEScore; @@ -109,7 +114,13 @@ void BattleGroundBE::RemovePlayer(Player *plr, uint64 guid) {+ if(GetStatus() == STATUS_WAIT_LEAVE)+ return; + if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+ EndBattleGround(HORDE);+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))+ EndBattleGround(ALLIANCE); } void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer)@@ -123,15 +134,16 @@ return; } - uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());-- m_TeamKills[killer_team_index]++; // add kills to killer's team-- if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))+ if(!GetAlivePlayersCountByTeam(ALLIANCE)) { // all opponents killed- EndBattleGround(killer->GetTeam());+ EndBattleGround(HORDE); }+ else if(!GetAlivePlayersCountByTeam(HORDE))+ {+ // all opponents killed+ EndBattleGround(ALLIANCE);+ } } void BattleGroundBE::HandleAreaTrigger(Player *Source, uint32 Trigger)@@ -141,14 +153,14 @@ return; uint32 SpellId = 0;- uint64 buff_guid = 0;+ GameObject* obj = 0; switch(Trigger) { case 4538: // buff trigger?- buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_1];+ obj = m_BgObjects[BG_BE_OBJECT_BUFF_1]; break; case 4539: // buff trigger?- buff_guid = m_BgObjects[BG_BE_OBJECT_BUFF_2];+ obj = m_BgObjects[BG_BE_OBJECT_BUFF_2]; break; default: sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);@@ -156,11 +168,8 @@ break; } - if(buff_guid)+ if(obj) {- GameObject *obj = HashMapHolder<GameObject>::Find(buff_guid);- if(obj)- { if(!obj->isSpawned()) return; // buff not spawned yet obj->SetRespawnTime(BUFF_RESPAWN_TIME);@@ -168,14 +177,12 @@ SpellId = obj->GetGOInfo()->data3; if(SpellId) Source->CastSpell(Source, SpellId, true);- } } } void BattleGroundBE::ResetBGSubclass() {- m_TeamKills[BG_TEAM_ALLIANCE] = 0;- m_TeamKills[BG_TEAM_HORDE] = 0;+ } bool BattleGroundBE::SetupBattleGround()Index: src/game/BattleGroundBE.h===================================================================--- src/game/BattleGroundBE.h (revision 5306)+++ src/game/BattleGroundBE.h (working copy)@@ -58,7 +58,7 @@ void Update(time_t diff); /* inherited from BattlegroundClass */- virtual void AddPlayer(Player *plr);+ virtual void AddPlayer(Player *plr, uint32 team = 0); void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger);@@ -68,8 +68,5 @@ /* Scorekeeping */ void UpdatePlayerScore(Player *Source, uint32 type, uint32 value);-- private:- uint32 m_TeamKills[2]; // count of kills for each team }; #endifIndex: src/game/BattleGroundEY.cpp===================================================================--- src/game/BattleGroundEY.cpp (revision 5306)+++ src/game/BattleGroundEY.cpp (working copy)@@ -39,9 +39,9 @@ BattleGround::Update(diff); } -void BattleGroundEY::AddPlayer(Player *plr)+void BattleGroundEY::AddPlayer(Player *plr, uint32 team) {- BattleGround::AddPlayer(plr);+ BattleGround::AddPlayer(plr, team); //create score and add it to map BattleGroundEYScore* sc = new BattleGroundEYScore; Index: src/game/BattleGroundEY.h===================================================================--- src/game/BattleGroundEY.h (revision 5306)+++ src/game/BattleGroundEY.h (working copy)@@ -39,7 +39,7 @@ void Update(time_t diff); /* inherited from BattlegroundClass */- virtual void AddPlayer(Player *plr);+ virtual void AddPlayer(Player *plr, uint32 team = 0); void RemovePlayer(Player *plr,uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger);Index: src/game/BattleGroundHandler.cpp===================================================================--- src/game/BattleGroundHandler.cpp (revision 5306)+++ src/game/BattleGroundHandler.cpp (working copy)@@ -26,9 +26,12 @@ #include "MapManager.h" #include "ObjectAccessor.h" #include "Object.h"+#include "Chat.h"+#include "Language.h" #include "BattleGroundMgr.h" #include "BattleGroundWS.h" #include "BattleGround.h"+#include "ArenaTeam.h" void WorldSession::HandleBattleGroundHelloOpcode( WorldPacket & recv_data ) {@@ -78,8 +81,17 @@ recv_data >> instanceId; // instance id, 0 if First Available selected recv_data >> joinAsGroup; // join as group + if(bgTypeId >= MAX_BATTLEGROUND_TYPES)+ {+ sLog.outError("bgport: invalid bgtype received. possible cheater? player guid %u",_player->GetGUIDLow());+ return;+ }+ sLog.outDebug( "WORLD: Recvd CMSG_BATTLEMASTER_JOIN Message from: " I64FMT, guid); + // can do this, since it's battleground, not arena+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, 0);+ // ignore if we already in BG or BG queue if(_player->InBattleGround()) return;@@ -100,19 +112,39 @@ return; } - // check existence- BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);- if(!bg)+ // get bg instance or bg template if instance not found+ BattleGround * bg = 0;+ if(instanceId)+ BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);++ if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))+ {+ sLog.outError("Battleground: no available bg / template found"); return;+ } if(joinAsGroup && _player->GetGroup()) { Group *grp = _player->GetGroup();+ if(grp->GetMembersCount() > bg->GetMaxPlayersPerTeam())+ {+ WorldPacket data;+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_BG_GROUP_TOO_LARGE), NULL);+ SendPacket(&data);+ return;+ }+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0); for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player *member = itr->getSource(); if(!member) continue; + if( member->GetBattleGroundQueueIdFromLevel() != _player->GetBattleGroundQueueIdFromLevel() )+ continue;++ if( member->GetTeam() != _player->GetTeam() )+ continue;+ if( !member->CanJoinToBattleground() ) { WorldPacket data(SMSG_GROUP_JOINED_BATTLEGROUND, 4);@@ -120,12 +152,12 @@ _player->GetSession()->SendPacket(&data); continue; }- if (member->GetBattleGroundQueueIndex(bgTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+ if (member->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) //player is already in this queue continue; WorldPacket data;- uint32 queueSlot = member->AddBattleGroundQueueId(bgTypeId); // add to queue+ uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId); // add to queue if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES) { // fill data packet@@ -134,22 +166,23 @@ } // store entry point coords (same as leader entry point)- member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());+ member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0); member->GetSession()->SendPacket(&data); sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); member->GetSession()->SendPacket(&data);- sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(member, bgTypeId);+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo); }+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); } else {- if (_player->GetBattleGroundQueueIndex(bgTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+ if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES) //player is already in this queue return;- uint32 queueSlot = _player->AddBattleGroundQueueId(bgTypeId);+ uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES) { WorldPacket data;@@ -159,13 +192,16 @@ } // store entry point coords- _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());+ _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); WorldPacket data; // send status packet (in queue) sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0); SendPacket(&data);- sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(_player, bgTypeId);++ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, 0, false, 0);+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); } } @@ -247,6 +283,12 @@ uint32 bgTypeId; recv_data >> bgTypeId; // id from DBC + if(bgTypeId >= MAX_BATTLEGROUND_TYPES)+ {+ sLog.outError("Battleground: invalid bgtype received.");+ return;+ }+ BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if(!bl)@@ -263,39 +305,151 @@ sLog.outDebug( "WORLD: Recvd CMSG_BATTLEFIELD_PORT Message"); - uint8 unk1;+ uint8 type; // arenatype if arena uint8 unk2; // unk, can be 0x0 (may be if was invited?) and 0x1+ uint32 instanceId; uint32 bgTypeId; // type id from dbc uint16 unk; // 0x1F90 constant? uint8 action; // enter battle 0x1, leave queue 0x0 - recv_data >> unk1 >> unk2 >> bgTypeId >> unk >> action;+ recv_data >> type >> unk2 >> bgTypeId >> unk >> action; - BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);+ if(bgTypeId >= MAX_BATTLEGROUND_TYPES)+ {+ sLog.outError("Battleground: invalid bgtype received.");+ // update battleground slots for the player to fix his UI and sent data.+ // this is a HACK, I don't know why the client starts sending invalid packets in the first place.+ // it usually happens with extremely high latency (if debugging / stepping in the code for example)+ if(_player->InBattleGroundQueue())+ {+ // update all queues, send invitation info if player is invited, queue info if queued+ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)+ {+ uint32 queue_id = _player->GetBattleGroundQueueId(i);+ if(!queue_id)+ continue;+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());+ // if the player is not in queue, contine+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())+ continue;++ // no group information, this should never happen+ if(!itrPlayerStatus->second.GroupInfo)+ continue;++ BattleGround * bg = NULL;++ // get possibly needed data from groupinfo+ bgTypeId = itrPlayerStatus->second.GroupInfo->BgTypeId;+ uint8 arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;+ uint8 israted = itrPlayerStatus->second.GroupInfo->IsRated;+ uint8 status = 0;++ + if(!itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID)+ {+ // not invited to bg, get template+ bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);+ status = STATUS_WAIT_QUEUE;+ }+ else+ {+ // get the bg we're invited to+ BattleGround * bg = sBattleGroundMgr.GetBattleGround(itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID);+ status = STATUS_WAIT_JOIN;+ }++ // if bg not found, then continue+ if(!bg)+ continue;++ // don't invite if already in the instance+ if(_player->InBattleGround() && _player->GetBattleGround() && _player->GetBattleGround()->GetInstanceID() == bg->GetInstanceID())+ continue;++ // re - invite player with proper data+ WorldPacket data;+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, itrPlayerStatus->second.GroupInfo->Team?itrPlayerStatus->second.GroupInfo->Team:_player->GetTeam(), i, status, INVITE_ACCEPT_WAIT_TIME, 0, arenatype, israted);+ SendPacket(&data);+ }+ }+ return;+ }++ uint32 bgQueueTypeId = 0;+ // get the bg what we were invited to + BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus;+ bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId,type);+ itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());++ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())+ {+ sLog.outError("Battleground: itrplayerstatus not found.");+ return;+ }+ instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;++ // if action == 1, then instanceId is _required_+ if(!instanceId && action == 1)+ {+ sLog.outError("Battleground: instance not found.");+ return;+ }++ BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);++ // bg template might and must be used in case of leaving queue, when instance is not created yet+ if(!bg && action == 0)+ bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);++ if(!bg)+ {+ sLog.outError("Battleground: bg not found.");+ return;+ }++ bgTypeId = bg->GetTypeID(); if(bg) { if(_player->InBattleGroundQueue()) { uint32 queueSlot = 0;+ uint32 team = 0;+ uint32 arenatype = 0;+ uint32 israted = 0;+ // get the team info from the queue+ BattleGroundQueue::QueuedPlayersMap::iterator pitr = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());+ if(pitr !=sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end()+ && pitr->second.GroupInfo )+ {+ team = pitr->second.GroupInfo->Team;+ arenatype = pitr->second.GroupInfo->ArenaType;+ israted = pitr->second.GroupInfo->IsRated;+ }+ else+ {+ sLog.outError("Battleground: Invalid player queue info!");+ return;+ } WorldPacket data; switch(action) { case 1: // port to battleground _player->RemoveFromGroup();- queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);+ queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime()); _player->GetSession()->SendPacket(&data); // remove battleground queue status from BGmgr- sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), false);- // check if player is not deserter- if( !_player->CanJoinToBattleground() )+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), false);+ // check if player is not deserter -- check in signup, not here!+ /*if( !_player->CanJoinToBattleground() ) { WorldPacket data2; data2.Initialize(SMSG_GROUP_JOINED_BATTLEGROUND, 4); data2 << (uint32) 0xFFFFFFFE; SendPacket(&data2); return;- }+ }*/ // if player is in battleground already, remove him and port him to new battleground if ( _player->InBattleGround() ) {@@ -303,15 +457,15 @@ if (currentBg) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); }- _player->SetBattleGroundId(bg->GetTypeID());- sBattleGroundMgr.SendToBattleGround(_player, bgTypeId);- bg->AddPlayer(_player);+ _player->SetBattleGroundId(bg->GetInstanceID());+ sBattleGroundMgr.SendToBattleGround(_player, instanceId, team);+ bg->AddPlayer(_player,team); break; case 0: // leave queue- queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);- _player->RemoveBattleGroundQueueId(bgTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs+ queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId);+ _player->RemoveBattleGroundQueueId(bgQueueTypeId); // must be called this way, because if you move this call to queue->removeplayer, it causes bugs sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_NONE, 0, 0);- sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].RemovePlayer(_player->GetGUID(), true);+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(_player->GetGUID(), true); SendPacket(&data); break; default:@@ -350,7 +504,8 @@ BattleGround *bg = _player->GetBattleGround(); if(bg) {- uint32 queueSlot = _player->GetBattleGroundQueueIndex(bg->GetTypeID());+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+ uint32 queueSlot = _player->GetBattleGroundQueueIndex(bgQueueTypeId); if((bg->GetStatus() <= STATUS_IN_PROGRESS)) { sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_IN_PROGRESS, 0, bg->GetStartTime());@@ -358,15 +513,25 @@ } for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) {- uint32 queue_id = _player->GetBattleGroundQueueId(i);- if (i == queueSlot || !queue_id)+ uint32 queue_id = _player->GetBattleGroundQueueId(i); // battlegroundqueueid stores the type id, not the instance id, so this is definitely wrong+ uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);+ uint8 isRated = 0;+ if (i == queueSlot || !queue_id) // we need to get the instance ids continue;- BattleGround *bg2 = sBattleGroundMgr.GetBattleGround(queue_id);+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())+ continue;+ if(itrPlayerStatus->second.GroupInfo)+ {+ arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;+ isRated = itrPlayerStatus->second.GroupInfo->IsRated;+ }+ BattleGround *bg2 = sBattleGroundMgr.GetBattleGroundTemplate(sBattleGroundMgr.BGTemplateId(queue_id)); // try this if(bg2) { //in this call is small bug, this call should be filled by player's waiting time in queue //this call nulls all timers for client :- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0,arenatype,isRated); SendPacket(&data); } }@@ -378,18 +543,34 @@ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) { uint32 queue_id = _player->GetBattleGroundQueueId(i);- BattleGround *bg = sBattleGroundMgr.GetBattleGround(queue_id);+ if(!queue_id)+ continue;+ uint32 bgTypeId = sBattleGroundMgr.BGTemplateId(queue_id);+ uint8 arenatype = sBattleGroundMgr.BGArenaType(queue_id);+ uint8 isRated = 0;+ BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[queue_id].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())+ continue;+ if(itrPlayerStatus->second.GroupInfo)+ {+ arenatype = itrPlayerStatus->second.GroupInfo->ArenaType;+ isRated = itrPlayerStatus->second.GroupInfo->IsRated;+ } if(bg && queue_id) {- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); SendPacket(&data); } } }- /*else // not sure if it needed...+/* else // not sure if it needed... {- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(), STATUS_NONE, 0, 0);- SendPacket(&data);+ for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++)+ {+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, NULL, _player->GetTeam(),i , STATUS_NONE, 0, 0);+ SendPacket(&data);+ } }*/ } @@ -453,7 +634,7 @@ recv_data.hexlike(); // ignore if we already in BG or BG queue- if(_player->InBattleGround() || _player->InBattleGroundQueue())+ if(_player->InBattleGround()) return; uint64 guid; // arena Battlemaster guid@@ -470,6 +651,7 @@ return; uint8 arenatype = 0;+ uint32 arenaRating = 0; switch(type) {@@ -487,23 +669,72 @@ break; } - if(isRated && !_player->GetArenaTeamId(type)) // player not in arena team of that size+ if(isRated) // player not in arena team of that size {- _player->GetSession()->SendNotInArenaTeamPacket(arenatype);- return;+ uint32 ateamId = _player->GetArenaTeamId(type);+ if(!ateamId)+ {+ _player->GetSession()->SendNotInArenaTeamPacket(arenatype);+ return;+ }+ ArenaTeam * at = objmgr.GetArenaTeamById(ateamId);+ if(!at)+ {+ _player->GetSession()->SendNotInArenaTeamPacket(arenatype);+ return;+ }+ arenaRating = at->GetRating();+ Group *grp = _player->GetGroup();+ if(grp)+ {+ for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next())+ {+ Player *member = itr->getSource();++ // offline member or not in team -> err+ if(!member || member->GetArenaTeamId(type) != ateamId)+ {+ WorldPacket data;+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_ARENA_YOUR_TEAM_ONLY), NULL);+ SendPacket(&data);+ return;+ }+ }+ if(grp->GetMembersCount() < arenatype)+ {+ WorldPacket data;+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_ARENA_NOT_ENOUGH_PLAYERS), NULL);+ SendPacket(&data);+ return;+ }+ } } if(asGroup && !_player->GetGroup()) // player not in group return; - // check existence- BattleGround *bg = sBattleGroundMgr.GetBattleGround(BATTLEGROUND_AA);- if(!bg)+ //check existance+ BattleGround* bg = NULL;+ if( !(bg = sBattleGroundMgr.GetBattleGroundTemplate(BATTLEGROUND_AA)) )+ {+ sLog.outError("Battleground: template bg (all arenas) not found"); return;+ } + uint8 bgTypeId = bg->GetTypeID();+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);+ if(asGroup && _player->GetGroup()) { Group *grp = _player->GetGroup();+ if(grp->GetMembersCount() > arenatype)+ {+ WorldPacket data;+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, objmgr.GetMangosString(LANG_ARENA_GROUP_TOO_LARGE), NULL);+ SendPacket(&data);+ return;+ }+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating); for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player *member = itr->getSource();@@ -513,11 +744,19 @@ //player has deserter aura .. do nothing */ - if (member->GetBattleGroundQueueIndex(BATTLEGROUND_AA) < PLAYER_MAX_BATTLEGROUND_QUEUES)+ if( member->GetBattleGroundQueueIdFromLevel() != _player->GetBattleGroundQueueIdFromLevel() )+ continue;++ if( member->GetTeam() != _player->GetTeam() )+ continue;++ if (member->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+ { //player is already in this queue continue;+ } - uint32 queueSlot = member->AddBattleGroundQueueId(BATTLEGROUND_AA);// add to queue+ uint32 queueSlot = member->AddBattleGroundQueueId(bgQueueTypeId);// add to queue if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES) { WorldPacket data;@@ -527,16 +766,17 @@ } // store entry point coords (same as leader entry point)- member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());+ member->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); WorldPacket data; // send status packet (in queue)- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, member->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); member->GetSession()->SendPacket(&data);- sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, BATTLEGROUND_AA);+ sBattleGroundMgr.BuildGroupJoinedBattlegroundPacket(&data, bgTypeId); member->GetSession()->SendPacket(&data);- sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(member, BATTLEGROUND_AA);+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(member, ginfo); }+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating); } else {@@ -544,11 +784,13 @@ //player has deserter aura .. do nothing */ - if (_player->GetBattleGroundQueueIndex(BATTLEGROUND_AA) < PLAYER_MAX_BATTLEGROUND_QUEUES)+ if (_player->GetBattleGroundQueueIndex(bgQueueTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+ { //player is already in this queue return;+ } - uint32 queueSlot = _player->AddBattleGroundQueueId(BATTLEGROUND_AA);+ uint32 queueSlot = _player->AddBattleGroundQueueId(bgQueueTypeId); if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES) { WorldPacket data;@@ -558,12 +800,14 @@ } // store entry point coords- _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation());+ _player->SetBattleGroundEntryPoint(_player->GetMapId(),_player->GetInstanceId(),_player->GetPositionX(),_player->GetPositionY(),_player->GetPositionZ(),_player->GetOrientation()); WorldPacket data; // send status packet (in queue)- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0);+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), queueSlot, STATUS_WAIT_QUEUE, 0, 0, arenatype, isRated); SendPacket(&data);- sBattleGroundMgr.m_BattleGroundQueues[BATTLEGROUND_AA].AddPlayer(_player, BATTLEGROUND_AA);+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddGroup(_player, bgTypeId, arenatype, isRated, arenaRating);+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].AddPlayer(_player, ginfo);+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated, arenaRating); } }Index: src/game/BattleGroundMgr.cpp===================================================================--- src/game/BattleGroundMgr.cpp (revision 5306)+++ src/game/BattleGroundMgr.cpp (working copy)@@ -30,9 +30,12 @@ #include "SharedDefines.h" #include "Policies/SingletonImp.h" #include "MapManager.h"+#include "Map.h"+#include "MapInstanced.h" #include "ObjectMgr.h" #include "ProgressBar.h" #include "World.h"+#include "ArenaTeam.h" INSTANTIATE_SINGLETON_1( BattleGroundMgr ); @@ -43,12 +46,12 @@ BattleGroundQueue::BattleGroundQueue() { //queues are empty, we don't have to call clear()- for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++)+/* for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++) {- m_QueuedPlayers[i].Horde = 0;- m_QueuedPlayers[i].Alliance = 0;+ //m_QueuedPlayers[i].Horde = 0;+ //m_QueuedPlayers[i].Alliance = 0; //m_QueuedPlayers[i].AverageTime = 0;- }+ }*/ } BattleGroundQueue::~BattleGroundQueue()@@ -56,35 +59,187 @@ for (int i = 0; i < MAX_BATTLEGROUND_QUEUES; i++) { m_QueuedPlayers[i].clear();+ for(QueuedGroupsList::iterator itr = m_QueuedGroups[i].begin(); itr!= m_QueuedGroups[i].end(); ++itr)+ {+ delete (*itr);+ }+ m_QueuedGroups[i].clear(); } } -void BattleGroundQueue::AddPlayer(Player *plr, uint32 bgTypeId)+// initialize eligible groups from the given source matching the given specifications+void BattleGroundQueue::EligibleGroups::Init(BattleGroundQueue::QueuedGroupsList *source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime) {+ // clear from prev initialization+ clear();+ BattleGroundQueue::QueuedGroupsList::iterator itr, next;+ // iterate through the source+ for(itr = source->begin(); itr!= source->end(); itr = next)+ {+ next = itr;+ ++next;+ if( (*itr)->BgTypeId == BgTypeId &&+ (*itr)->ArenaType == ArenaType &&+ (*itr)->IsRated == IsRated &&+ (*itr)->IsInvitedToBGInstanceGUID == 0 &&+ (*itr)->Team == side &&+ (*itr)->Players.size() <= MaxPlayers &&+ ((*itr)->JoinTime <= DisregardTime // pass if disregard time is greater than join time+ || (*itr)->ArenaTeamRating == 0 // pass if no rating info+ || ((*itr)->ArenaTeamRating >= MinRating + && ((*itr)->ArenaTeamRating <= MaxRating))) ) // pass if matches the rating range+ {+ // the group matches the conditions+ // insert it in order of groupsize, and join time+ uint32 size = (*itr)->Players.size();+ uint32 jointime = (*itr)->JoinTime;+ bool inserted = false;++ for(std::list<GroupQueueInfo *>::iterator elig_itr = begin(); elig_itr != end(); ++elig_itr)+ {+ // if the next one's size is smaller, then insert+ // also insert if the next one's size is equal, but it joined the queue later+ if( ((*elig_itr)->Players.size()<size) ||+ ((*elig_itr)->Players.size() == size && (*elig_itr)->JoinTime > jointime) )+ {+ insert(elig_itr,(*itr));+ inserted = true;+ break;+ }+ }+ // if not inserted -> this is the smallest group -> push_back+ if(!inserted)+ {+ push_back((*itr));+ }+ }+ }+}++// remove group from eligible groups+// used when building selection pools+void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo)+{+ for(std::list<GroupQueueInfo *>::iterator itr = begin(); itr != end(); ++itr)+ {+ if((*itr)==ginfo)+ {+ erase(itr);+ return;+ }+ }+}++// selection pool initialization, used to clean up from prev selection+void BattleGroundQueue::SelectionPool::Init()+{+ SelectedGroups.clear();+ MaxGroup = 0;+ PlayerCount = 0;+}++// get the maximal group from the selection pool+// used when building the pool, and have to remove the largest+GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup()+{+ if(SelectedGroups.empty())+ {+ sLog.outError("Getting max group when selection pool is empty, this should never happen.");+ MaxGroup = NULL;+ return 0;+ }+ // actually select the max group if it's not set+ if(MaxGroup==0 && !SelectedGroups.empty())+ {+ uint32 max_size = 0;+ for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)+ {+ if(max_size<(*itr)->Players.size())+ {+ MaxGroup =(*itr);+ max_size = MaxGroup->Players.size();+ }+ }+ }+ return MaxGroup;+}++// remove group info from selection pool+// used when building selection pools and have to remove maximal group+void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)+{+ // uninitiate max group info if needed+ if(MaxGroup == ginfo)+ MaxGroup = 0;+ // find what to remove+ for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)+ {+ if((*itr)==ginfo)+ {+ SelectedGroups.erase(itr);+ // decrease selected players count+ PlayerCount -= ginfo->Players.size();+ return;+ }+ }+}++// add group to selection+// used when building selection pools+void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)+{+ SelectedGroups.push_back(ginfo);+ // increase selected players count+ PlayerCount+=ginfo->Players.size();+ if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size())+ {+ // update max group info if needed+ MaxGroup = ginfo;+ }+}++// add group to bg queue with the given leader and bg specifications+GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 arenaRating)+{+ uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();++ // create new ginfo+ // cannot use the method like in addplayer, because that could modify an in-queue group's stats+ // (e.g. leader leaving queue then joining as individual again)+ GroupQueueInfo* ginfo = new GroupQueueInfo;+ ginfo->BgTypeId = BgTypeId;+ ginfo->ArenaType = ArenaType;+ ginfo->IsRated = isRated;+ ginfo->IsInvitedToBGInstanceGUID = 0; // maybe this should be modifiable by function arguments to enable selection of running instances?+ ginfo->JoinTime = getMSTime();+ ginfo->Team = leader->GetTeam();++ if(sBattleGroundMgr.GetMaxRatingDifference()) // if max difference is set, then store rating info for queue+ ginfo->ArenaTeamRating = arenaRating;+ else+ ginfo->ArenaTeamRating = 0; // don't if it doesn't matter++ ginfo->Players.clear();++ m_QueuedGroups[queue_id].push_back(ginfo);++ // return ginfo, because it is needed to add players to this group info+ return ginfo;+}++void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)+{ uint32 queue_id = plr->GetBattleGroundQueueIdFromLevel(); //if player isn't in queue, he is added, if already is, then values are overwritten, no memory leak PlayerQueueInfo& info = m_QueuedPlayers[queue_id][plr->GetGUID()]; info.InviteTime = 0;- info.IsInvitedToBGInstanceGUID = 0; info.LastInviteTime = 0; info.LastOnlineTime = getMSTime();- info.Team = plr->GetTeam();+ info.GroupInfo = ginfo; - //add player to waiting order queue- m_PlayersSortedByWaitTime[queue_id].push_back(plr->GetGUID());-- if(plr->GetTeam() == ALLIANCE)- m_QueuedPlayers[queue_id].Alliance++;- else- m_QueuedPlayers[queue_id].Horde++;-- /* temporary BG queue status message- std::ostringstream str;- str << "Battleground queue invited status: horde: " << m_QueuedPlayers[queue_id].Horde << ", aliance: " << m_QueuedPlayers[queue_id].Alliance;- plr->Say(str.str(), LANG_UNIVERSAL);*/-- this->Update(bgTypeId, queue_id);+ // add the pinfo to ginfo's list+ ginfo->Players[plr->GetGUID()] = &info; } void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount)@@ -93,11 +248,22 @@ uint32 queue_id = 0; QueuedPlayersMap::iterator itr;+ GroupQueueInfo * group;+ QueuedGroupsList::iterator group_itr; bool IsSet = false;- if(!plr)- { //player is offline, we need to find him somewhere in queues- /// there is something wrong if this code is run, because we have in queue only online players!- sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash");+ if(plr)+ {+ queue_id = plr->GetBattleGroundQueueIdFromLevel();++ itr = m_QueuedPlayers[queue_id].find(guid);+ if(itr != m_QueuedPlayers[queue_id].end())+ IsSet = true;+ }++ if(!IsSet)+ { + // either player is offline, or he levelled up to another queue category+ // sLog.outError("Battleground: removing offline player from BG queue - this might not happen, but it should not cause crash"); for (uint32 i = 0; i < MAX_BATTLEGROUND_QUEUES; i++) { itr = m_QueuedPlayers[i].find(guid);@@ -109,44 +275,228 @@ } } }- else- { //player is online, we have his level, so we can find exact queue from his level- queue_id = plr->GetBattleGroundQueueIdFromLevel();- itr = m_QueuedPlayers[queue_id].find(guid);- IsSet = true;++ // couldn't find the player in bg queue, return+ if(!IsSet)+ {+ sLog.outError("Battleground: couldn't find player to remove.");+ return; } - //all variables are set, so remove player- //remove player from time queue- m_PlayersSortedByWaitTime[queue_id].remove(guid);+ group = itr->second.GroupInfo; - if (IsSet && itr != m_QueuedPlayers[queue_id].end())+ for(group_itr=m_QueuedGroups[queue_id].begin(); group_itr != m_QueuedGroups[queue_id].end(); ++group_itr) {- if (!itr->second.IsInvitedToBGInstanceGUID)+ if(group == (GroupQueueInfo*)(*group_itr))+ break;+ }++ // variables are set (what about leveling up when in queue????)+ // remove player from group+ // if only player there, remove group++ // remove player queue info from group queue info+ std::map<uint64, PlayerQueueInfo*>::iterator pitr = group->Players.find(guid);++ if(pitr != group->Players.end())+ group->Players.erase(pitr);++ // check for iterator correctness+ if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())+ {+ // used when player left the queue, NOT used when porting to bg+ if (decreaseInvitedCount) {- if(itr->second.Team == ALLIANCE)- m_QueuedPlayers[queue_id].Alliance--;- else- m_QueuedPlayers[queue_id].Horde--;- }- else- {- if (decreaseInvitedCount)+ // if invited to bg, and should decrease invited count, then do it+ if(group->IsInvitedToBGInstanceGUID) {- BattleGround* bg = sBattleGroundMgr.GetBattleGround(itr->second.IsInvitedToBGInstanceGUID);+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID); if (bg)- bg->DecreaseInvitedCount(itr->second.Team);+ bg->DecreaseInvitedCount(group->Team);+ if (!bg->GetPlayersSize() && !bg->GetInvitedCount(ALLIANCE) && !bg->GetInvitedCount(HORDE))+ {+ // no more players on battleground, set delete it+ bg->SetDeleteThis();+ } }+ // update the join queue, maybe now the player's group fits in a queue!+ // not yet implemented (should store bgTypeId in group queue info?) }+ // remove player queue info m_QueuedPlayers[queue_id].erase(itr);+ // remove group queue info if needed+ if(group->Players.empty())+ {+ m_QueuedGroups[queue_id].erase(group_itr);+ delete group;+ } } } +bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)+{+ // set side if needed+ if(side)+ ginfo->Team = side;++ if(!ginfo->IsInvitedToBGInstanceGUID)+ {+ // not yet invited+ // set invitation+ ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+ // loop through the players+ for(std::map<uint64,PlayerQueueInfo*>::iterator itr = ginfo->Players.begin(); itr != ginfo->Players.end(); ++itr)+ {+ // set status+ itr->second->InviteTime = getMSTime();+ itr->second->LastInviteTime = getMSTime();++ // get the player+ Player* plr = objmgr.GetPlayer(itr->first);+ // if offline, skip him+ if(!plr)+ continue;++ // invite the player+ sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID(),ginfo->Team);++ WorldPacket data;++ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);++ sLog.outDebug("Battleground: invite plr %u queueindex %u bgtype %u",plr->GetGUIDLow(),queueSlot,bg->GetTypeID());++ // send status packet+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, side?side:plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);+ plr->GetSession()->SendPacket(&data);+ }+ return true;+ }++ return false;+}++// this function is responsible for the selection of queued groups when trying to create new battlegrounds+bool BattleGroundQueue::BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated, uint32 MinRating, uint32 MaxRating, uint32 DisregardTime)+{+ uint32 side;+ switch(mode)+ {+ case NORMAL_ALLIANCE:+ case ONESIDE_ALLIANCE_TEAM1:+ case ONESIDE_ALLIANCE_TEAM2:+ side = ALLIANCE;+ break;+ case NORMAL_HORDE:+ case ONESIDE_HORDE_TEAM1:+ case ONESIDE_HORDE_TEAM2:+ side = HORDE;+ break;+ default:+ //unknown mode, return false+ sLog.outDebug("Battleground: unknown selection pool build mode, returning...");+ return false;+ break;+ }++ // inititate the groups eligible to create the bg+ m_EligibleGroups.Init(&(m_QueuedGroups[queue_id]), bgTypeId, side, MaxPlayers, ArenaType, isRated, MinRating, MaxRating, DisregardTime);+ // init the selected groups (clear)+ m_SelectionPools[mode].Init();+ while(!(m_EligibleGroups.empty()))+ {+ sLog.outDebug("m_EligibleGroups is not empty, continue building selection pool");+ // in decreasing group size, add groups to join if they fit in the MaxPlayersPerTeam players+ for(EligibleGroups::iterator itr= m_EligibleGroups.begin(); itr!=m_EligibleGroups.end(); ++itr)+ {+ // get the maximal not yet checked group+ GroupQueueInfo * MaxGroup = (*itr);+ // if it fits in the maxplayer size, add it+ if( (m_SelectionPools[mode].GetPlayerCount() + MaxGroup->Players.size()) <= MaxPlayers )+ {+ m_SelectionPools[mode].AddGroup(MaxGroup);+ }+ }+ if(m_SelectionPools[mode].GetPlayerCount()>=MinPlayers)+ {+ // the selection pool is set, return+ sLog.outDebug("pool build succeeded, return true");+ return true;+ }+ // if the selection pool's not set, then remove the group with the highest player count, and try again with the rest.+ GroupQueueInfo * MaxGroup = m_SelectionPools[mode].GetMaximalGroup();+ m_EligibleGroups.RemoveGroup(MaxGroup);+ m_SelectionPools[mode].RemoveGroup(MaxGroup);+ }+ // failed to build a selection pool matching the given values+ return false;+}++// used to remove the Enter Battle window if the battle has already, but someone still has it+// (this can happen in arenas mainly, since the preparation is shorter than the timer for the bgqueueremove event+void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)+{+ uint32 queue_id = bg->GetQueueType();+ uint32 bgInstanceId = bg->GetInstanceID();+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+ QueuedGroupsList::iterator itr, next;+ for(itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); itr = next)+ {+ // must do this way, because the groupinfo will be deleted when all playerinfos are removed+ GroupQueueInfo * ginfo = (*itr);+ next = itr;+ ++next;+ // if group was invited to this bg instance, then remove all references+ if(ginfo->IsInvitedToBGInstanceGUID == bgInstanceId)+ {+ // after removing this much playerinfos, the ginfo will be deleted, so we'll use a for loop+ uint32 to_remove = ginfo->Players.size();+ uint32 team = ginfo->Team;+ for(int i = 0; i < to_remove; ++i)+ {+ // always remove the first one in the group+ std::map<uint64, PlayerQueueInfo * >::iterator itr2 = ginfo->Players.begin();+ if(itr2 == ginfo->Players.end())+ {+ sLog.outError("Empty Players in ginfo, this should never happen!");+ return;+ }++ // get the player+ Player * plr = objmgr.GetPlayer(itr2->first);+ if(!plr)+ {+ sLog.outError("Player offline when trying to remove from GroupQueueInfo, this should never happen.");+ continue;+ }++ // get the queueslot+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId);+ if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue+ {+ plr->RemoveBattleGroundQueueId(bgQueueTypeId);+ // remove player from queue, this might delete the ginfo as well! don't use that pointer after this!+ RemovePlayer(itr2->first, true);+ // this is probably unneeded, since this player was already invited -> does not fit when initing eligible groups+ // but updateing the queue can't hurt+ Update(bgQueueTypeId, bg->GetQueueType());+ // send info to client+ WorldPacket data;+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, team, queueSlot, STATUS_NONE, 0, 0);+ plr->GetSession()->SendPacket(&data);+ }+ }+ }+ }+}+ /*-this method is called when player is inserted, or removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue-add method calls this by itself, the remove method could works in other way, so you have to call this method from other code after calling remove method+this method is called when group is inserted, or player / group is removed from BG Queue - there is only one player's status changed, so we don't use while(true) cycles to invite whole queue+it must be called after fully adding the members of a group to ensure group joining+should be called after removeplayer functions in some cases */-void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id)+void BattleGroundQueue::Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype, bool isRated, uint32 arenaRating) { if (queue_id >= MAX_BATTLEGROUND_QUEUES) {@@ -156,158 +506,300 @@ } //if no players in queue ... do nothing- if (this->m_QueuedPlayers[queue_id].Alliance == 0 && this->m_QueuedPlayers[queue_id].Horde == 0)+ if (this->m_QueuedGroups[queue_id].size() == 0) return; + uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId, arenatype);+ //battleground with free slot for player should be always the last in this queue- BGFreeSlotQueueType::iterator itr;- for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); ++itr)+ BGFreeSlotQueueType::iterator itr, next;+ for (itr = sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[bgTypeId].end(); itr = next) {+ next = itr;+ ++next; // battleground is running, so if: // DO NOT allow queue manager to invite new player to running arena- if ((*itr)->isBattleGround() && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE)+ if ((*itr)->isBattleGround() && (*itr)->GetTypeID() == bgTypeId && (*itr)->GetQueueType() == queue_id && (*itr)->GetStatus() > STATUS_WAIT_QUEUE && (*itr)->GetStatus() < STATUS_WAIT_LEAVE) { //we must check both teams BattleGround* bg = *itr; //we have to store battleground pointer here, because when battleground is full, it is removed from free queue (not yet implemented!!) // and iterator is invalid - //check if there are some players in queue- if (m_QueuedPlayers[queue_id].Alliance > 0 || m_QueuedPlayers[queue_id].Horde > 0)+ for(QueuedGroupsList::iterator itr = m_QueuedGroups[queue_id].begin(); itr != m_QueuedGroups[queue_id].end(); ++itr) {- for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)+ // did the group join for this bg type?+ if((*itr)->BgTypeId != bgTypeId)+ continue;+ // if so, check if fits in+ if(bg->GetFreeSlotsForTeam((*itr)->Team) >= (*itr)->Players.size()) {- Player* plr = objmgr.GetPlayer(*itr2);- if (!plr)- {- //something is wrong!, kick player from queue- sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");- uint64 oldval = *itr2;- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);- this->RemovePlayer(oldval, true);- continue;- }+ // if group fits in, invite it+ InviteGroupToBG((*itr),bg,(*itr)->Team);+ }+ } - // player will be invited, if in bg there is a free slot for him- if (bg->HasFreeSlotsForTeam(plr->GetTeam()))- {- // iterator to player's queue status- QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);+ if (!bg->HasFreeSlots())+ {+ //remove BG from BGFreeSlotQueue+ bg->RemoveFromBGFreeSlotQueue();+ }+ }+ } - // remove him from time queue- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);+ // finished iterating through the bgs with free slots, maybe we need to create a new bg - // only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and pls report it)- if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())- continue;+ BattleGround * bg_template = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);+ if(!bg_template)+ {+ sLog.outError("Battleground: Update: bg template not found for %u", bgTypeId);+ return;+ } - // check if player is not already invited- if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)- {- itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg->GetInstanceID();- itrPlayerStatus->second.InviteTime = getMSTime();- itrPlayerStatus->second.LastInviteTime = getMSTime();- if(itrPlayerStatus->second.Team == ALLIANCE)- m_QueuedPlayers[queue_id].Alliance--;- else- m_QueuedPlayers[queue_id].Horde--;- sBattleGroundMgr.InvitePlayer(plr, bg->GetInstanceID());+ // get the min. players per team, properly for larger arenas as well. (must have full teams for arena matches!)+ uint32 MinPlayersPerTeam = bg_template->GetMinPlayersPerTeam();+ uint32 MaxPlayersPerTeam = bg_template->GetMaxPlayersPerTeam();+ if(bg_template->isArena())+ {+ switch(arenatype)+ {+ case ARENA_TYPE_2v2:+ MaxPlayersPerTeam = 2;+ MinPlayersPerTeam = 2;+ break;+ case ARENA_TYPE_3v3:+ MaxPlayersPerTeam = 3;+ MinPlayersPerTeam = 3;+ break;+ case ARENA_TYPE_5v5:+ MaxPlayersPerTeam = 5;+ MinPlayersPerTeam = 5;+ break;+ }+ } - WorldPacket data;- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);- plr->GetSession()->SendPacket(&data);- }- }- else- ++itr2;+ uint32 arenaMinRating = (arenaRating <= sBattleGroundMgr.GetMaxRatingDifference()) ? 0 : arenaRating - sBattleGroundMgr.GetMaxRatingDifference();+ uint32 arenaMaxRating = (arenaRating == 0)? 0 : arenaRating + sBattleGroundMgr.GetMaxRatingDifference();+ uint32 discardTime = 0;+ if(sBattleGroundMgr.GetMaxRatingDifference() && getMSTime() >= sBattleGroundMgr.GetRatingDiscardTimer())+ discardTime = getMSTime() - sBattleGroundMgr.GetRatingDiscardTimer(); - //if battleground is FULL, then it is removed from free slot queue - not yet implemented!- if (!bg->HasFreeSlots())- {- //if bg is full, there is no need to invite other players, so break- break;- //remove BG from BGFreeSlotQueue - not used now, in this system we don't remove BGs from free queue- //bg->RemoveFromBGFreeSlotQueue() --- do not uncomment this - not yet implemented- }- }+ // try to build the selection pools+ bool bAllyOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);+ if(bAllyOK)+ sLog.outDebug("Battleground: ally pool succesfully build");+ else+ sLog.outDebug("Battleground: ally pool wasn't created");+ bool bHordeOK = BuildSelectionPool(bgTypeId, queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);+ if(bHordeOK)+ sLog.outDebug("Battleground: horde pool succesfully built");+ else+ sLog.outDebug("Battleground: horde pool wasn't created");++ // if selection pools are ready, create the new bg+ if (bAllyOK && bHordeOK)+ {+ BattleGround * bg2 = 0;+ // special handling for arenas+ if(bg_template->isArena())+ {+ // Find a random arena, that can be created+ uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};+ uint32 arena_num = urand(0,2);+ if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&+ !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&+ !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) )+ {+ sLog.outError("Battleground: couldn't create arena");+ return; }++ // set the MaxPlayersPerTeam values based on arenatype+ // setting the min player values isn't needed, since we won't be using that value later on.+ switch(arenatype)+ {+ case ARENA_TYPE_2v2:+ bg2->SetMaxPlayersPerTeam(2);+ bg2->SetMaxPlayers(4);+ break;+ case ARENA_TYPE_3v3:+ bg2->SetMaxPlayersPerTeam(3);+ bg2->SetMaxPlayers(6);+ break;+ case ARENA_TYPE_5v5:+ bg2->SetMaxPlayersPerTeam(5);+ bg2->SetMaxPlayers(10);+ break;+ default:+ break;+ } }- }+ else+ {+ // create new battleground+ bg2 = sBattleGroundMgr.CreateNewBattleGround(bgTypeId);+ } - /* THIS IS A CASE THAT IN QUEUE THERE IS ENOUGHT PLAYERS TO START NEW BG */- //itr->end is the last BG - template, which is not already started!+ if(!bg2)+ {+ sLog.outError("Battleground: couldn't create bg %u",bgTypeId);+ return;+ } - /* here will be a most of change, when we create battlegrounds instanciated */- /* if (there is enought players to start new BG)- Battleground* newbg = sBattleGroundMgr.CreateNewBattleGround(bgTypeId)- - that function will use the COPY constructor on BattleGround class ( in bg manager we should have one battleground as a template- (battleground template will be used only to create new BGs, it will be an instance of BG class, but it won't ever start) */-- /* folowing code is working with current Battleground system and it should be removed, when BGs will work like instances */- BattleGround* bg2 = sBattleGroundMgr.GetBattleGround(bgTypeId);- if (bg2->GetQueueType() != MAX_BATTLEGROUND_QUEUES || bg2->GetStatus() != STATUS_WAIT_QUEUE)- return;- if (m_QueuedPlayers[queue_id].Alliance >= bg2->GetMinPlayersPerTeam() && m_QueuedPlayers[queue_id].Horde >= bg2->GetMinPlayersPerTeam())- {+ // start the joining of the bg bg2->SetStatus(STATUS_WAIT_JOIN); bg2->SetQueueType(queue_id);+ // initialize arena / rating info+ bg2->SetArenaType(arenatype);+ // set rating+ bg2->SetRated(isRated); - for (PlayerGuidsSortedByTimeQueue::iterator itr2 = m_PlayersSortedByWaitTime[queue_id].begin(); itr2 != m_PlayersSortedByWaitTime[queue_id].end();)+ std::list<GroupQueueInfo* >::iterator itr;++ // invite groups from horde selection pool+ for(itr = m_SelectionPools[NORMAL_HORDE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_HORDE].SelectedGroups.end(); ++itr) {- Player* plr = objmgr.GetPlayer(*itr2);- if (!plr)+ InviteGroupToBG((*itr),bg2,HORDE);+ }++ // invite groups from ally selection pools+ for(itr = m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.begin(); itr != m_SelectionPools[NORMAL_ALLIANCE].SelectedGroups.end(); ++itr)+ {+ InviteGroupToBG((*itr),bg2,ALLIANCE);+ }++ // start the battleground+ bg2->StartBattleGround(0);+ }++ // there weren't enough players for a "normal" match+ // if arena, enable horde versus horde or alliance versus alliance teams here++ else if(bg_template->isArena())+ {+ bool bOneSideHordeTeam1 = false, bOneSideHordeTeam2 = false;+ bool bOneSideAllyTeam1 = false, bOneSideAllyTeam2 = false;+ bOneSideHordeTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);+ if(bOneSideHordeTeam1)+ {+ // one team has been selected, find out if other can be selected too+ std::list<GroupQueueInfo* >::iterator itr;+ // temporarily change the team side to enable building the next pool excluding the already selected groups+ for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)+ (*itr)->Team=ALLIANCE;++ bOneSideHordeTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);++ // change back the team to horde+ for(itr = m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_HORDE_TEAM1].SelectedGroups.end(); ++itr)+ (*itr)->Team=HORDE;++ if(!bOneSideHordeTeam2)+ bOneSideHordeTeam1 = false;+ }+ if(!bOneSideHordeTeam1)+ {+ // check for one sided ally+ bOneSideAllyTeam1 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);+ if(bOneSideAllyTeam1) {- //something is wrong!, kick player from queue- sLog.outError("BATTLEGROUND: problem with inviting offline player to Battleground queue .... pls report bug");- uint64 oldval = *itr2;- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);- this->RemovePlayer(oldval, true);- continue;+ // one team has been selected, find out if other can be selected too+ std::list<GroupQueueInfo* >::iterator itr;+ // temporarily change the team side to enable building the next pool excluding the already selected groups+ for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)+ (*itr)->Team=HORDE;++ bOneSideAllyTeam2 = BuildSelectionPool(bgTypeId, queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated, arenaMinRating, arenaMaxRating, discardTime);++ // change back the team to ally+ for(itr = m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.begin(); itr != m_SelectionPools[ONESIDE_ALLIANCE_TEAM1].SelectedGroups.end(); ++itr)+ (*itr)->Team=ALLIANCE; } - /* TODO: (i'm not sure this code will be useful:- here should be some condition like if (bg2->isArena() && bg2->isRated())+ if(!bOneSideAllyTeam2)+ bOneSideAllyTeam1 = false;+ }+ // 1-sided BuildSelectionPool() will work, because the MinPlayersPerTeam == MaxPlayersPerTeam in every arena!!!!+ if( (bOneSideHordeTeam1 && bOneSideHordeTeam2) ||+ (bOneSideAllyTeam1 && bOneSideAllyTeam2) )+ {+ // create random arena+ uint8 arenas[] = {BATTLEGROUND_NA, BATTLEGROUND_BE, BATTLEGROUND_RL};+ uint32 arena_num = urand(0,2);+ BattleGround* bg2 = NULL;+ if( !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[arena_num%3])) &&+ !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+1)%3])) &&+ !(bg2 = sBattleGroundMgr.CreateNewBattleGround(arenas[(arena_num+2)%3])) ) {- invite players from 1 certain group on each faction to play arena match- } else if ....and existing code- */- // player will be invited, if in bg there is a free slot for him- if (bg2->HasFreeSlotsForTeam(plr->GetTeam()))+ sLog.outError("Could not create arena.");+ return;+ }++ sLog.outDebug("Arena created.");+ // init stats+ switch(arenatype) {- // iterator to player's queue status- QueuedPlayersMap::iterator itrPlayerStatus = m_QueuedPlayers[queue_id].find(*itr2);+ case ARENA_TYPE_2v2:+ bg2->SetMaxPlayersPerTeam(2);+ bg2->SetMaxPlayers(4);+ break;+ case ARENA_TYPE_3v3:+ bg2->SetMaxPlayersPerTeam(3);+ bg2->SetMaxPlayers(6);+ break;+ case ARENA_TYPE_5v5:+ bg2->SetMaxPlayersPerTeam(5);+ bg2->SetMaxPlayers(10);+ break;+ default:+ break;+ } - // remove him from time queue- itr2 = m_PlayersSortedByWaitTime[queue_id].erase(itr2);+ bg2->SetRated(isRated);+ // which side has enough players?+ uint32 side = 0;+ SelectionPoolBuildMode mode1, mode2;+ // find out what pools are we using+ if(bOneSideAllyTeam1 && bOneSideAllyTeam2)+ {+ side = ALLIANCE;+ mode1 = ONESIDE_ALLIANCE_TEAM1;+ mode2 = ONESIDE_ALLIANCE_TEAM2;+ }+ else+ {+ side = HORDE;+ mode1 = ONESIDE_HORDE_TEAM1;+ mode2 = ONESIDE_HORDE_TEAM2;+ }+ // assigned team of the other group+ uint32 other_side;+ if(side == ALLIANCE)+ other_side = HORDE;+ else+ other_side = ALLIANCE; - // only check to be sure ... but this condition shouldn't be true (if it is true, then there is a bug somewhere and report it)- if (itrPlayerStatus == m_QueuedPlayers[queue_id].end())- continue;+ // start the joining of the bg+ bg2->SetStatus(STATUS_WAIT_JOIN);+ bg2->SetQueueType(queue_id);+ // initialize arena / rating info+ bg2->SetArenaType(arenatype); - //check if player is not already invited- if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)- {- itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg2->GetInstanceID();- itrPlayerStatus->second.InviteTime = getMSTime();- itrPlayerStatus->second.LastInviteTime = getMSTime();+ std::list<GroupQueueInfo* >::iterator itr; - if(itrPlayerStatus->second.Team == ALLIANCE)- m_QueuedPlayers[queue_id].Alliance--;- else- m_QueuedPlayers[queue_id].Horde--;+ // invite players from the first group as horde players (actually green team)+ for(itr = m_SelectionPools[mode1].SelectedGroups.begin(); itr != m_SelectionPools[mode1].SelectedGroups.end(); ++itr)+ {+ InviteGroupToBG((*itr),bg2,HORDE);+ } - sBattleGroundMgr.InvitePlayer(plr, bg2->GetInstanceID());+ // invite players from the second group as ally players (actually gold team)+ for(itr = m_SelectionPools[mode2].SelectedGroups.begin(); itr != m_SelectionPools[mode2].SelectedGroups.end(); ++itr)+ {+ InviteGroupToBG((*itr),bg2,ALLIANCE);+ } - WorldPacket data;- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgTypeId);- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg2, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, INVITE_ACCEPT_WAIT_TIME, 0);- plr->GetSession()->SendPacket(&data);- }- }- else- ++itr2;+ bg2->StartBattleGround(0); }- bg2->StartBattleGround(0); } } @@ -330,16 +822,17 @@ BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID); if (bg) {- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue { // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems- BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()];+ BattleGroundQueue::QueuedPlayersMap const& qpMap = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()]; BattleGroundQueue::QueuedPlayersMap::const_iterator qItr = qpMap.find(m_PlayerGuid);- if (qItr != qpMap.end() && qItr->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)+ if (qItr != qpMap.end() && qItr->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID) { WorldPacket data;- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_WAIT_JOIN, BG_REMIND_INVITE_TIME, 0);+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, qItr->second.GroupInfo->Team, queueSlot, STATUS_WAIT_JOIN, BG_REMIND_INVITE_TIME, 0); plr->GetSession()->SendPacket(&data); } }@@ -366,17 +859,18 @@ BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID); if (bg) {- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID(), bg->GetArenaType());+ uint32 queueSlot = plr->GetBattleGroundQueueIndex(bgQueueTypeId); if (queueSlot < PLAYER_MAX_BATTLEGROUND_QUEUES) // player is in queue { // check if player is invited to this bg ... this check must be here, because when player leaves queue and joins another, it would cause a problems- if (sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid)->second.IsInvitedToBGInstanceGUID == m_BgInstanceGUID)+ if (sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[plr->GetBattleGroundQueueIdFromLevel()].find(m_PlayerGuid)->second.GroupInfo->IsInvitedToBGInstanceGUID == m_BgInstanceGUID) {- plr->RemoveBattleGroundQueueId(bg->GetTypeID());- sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].RemovePlayer(m_PlayerGuid, true);- sBattleGroundMgr.m_BattleGroundQueues[bg->GetTypeID()].Update(bg->GetTypeID(), bg->GetQueueType());+ plr->RemoveBattleGroundQueueId(bgQueueTypeId);+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].RemovePlayer(m_PlayerGuid, true);+ sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgQueueTypeId, bg->GetQueueType()); WorldPacket data;- sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, plr->GetTeam(), queueSlot, STATUS_NONE, 0, 0);+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, m_PlayersTeam, queueSlot, STATUS_NONE, 0, 0); plr->GetSession()->SendPacket(&data); } }@@ -398,22 +892,78 @@ BattleGroundMgr::BattleGroundMgr() { m_BattleGrounds.clear();+ m_AutoDistributePoints = (bool)sWorld.getConfig(CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS);+ m_MaxRatingDifference = sWorld.getConfig(CONFIG_ARENA_MAX_RATING_DIFFERENCE);+ m_RatingDiscardTimer = sWorld.getConfig(CONFIG_ARENA_RATING_DISCARD_TIMER);+ m_NextRatingDiscardUpdate = m_RatingDiscardTimer;+ m_AutoDistributionTimeChecker = 0; } BattleGroundMgr::~BattleGroundMgr() {- for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)- delete itr->second;+ BattleGroundSet::iterator itr, next;+ for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)+ {+ next = itr;+ ++next;+ BattleGround * bg = itr->second;+ m_BattleGrounds.erase(itr);+ delete bg;+ } m_BattleGrounds.clear(); } +// used to update running battlegrounds, and delete finished ones void BattleGroundMgr::Update(time_t diff) {- for(BattleGroundSet::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)+ BattleGroundSet::iterator itr, next;+ for(itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); itr = next)+ {+ next = itr;+ ++next; itr->second->Update(diff);+ // use the SetDeleteThis variable+ // direct deletion caused crashes+ if(itr->second->m_SetDeleteThis)+ {+ BattleGround * bg = itr->second;+ m_BattleGrounds.erase(itr);+ delete bg;+ }+ }+ // if rating difference counts, maybe force-update queues+ if(m_MaxRatingDifference)+ {+ // it's time to force update+ if(m_NextRatingDiscardUpdate < diff)+ {+ // forced update for level 70 rated arenas+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_2v2].Update(BATTLEGROUND_AA,6,ARENA_TYPE_2v2,true,0);+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_3v3].Update(BATTLEGROUND_AA,6,ARENA_TYPE_3v3,true,0);+ m_BattleGroundQueues[BATTLEGROUND_QUEUE_5v5].Update(BATTLEGROUND_AA,6,ARENA_TYPE_5v5,true,0);+ m_NextRatingDiscardUpdate = m_RatingDiscardTimer;+ } + else + m_NextRatingDiscardUpdate -= diff;+ }+ if(m_AutoDistributePoints)+ {+ if(m_AutoDistributionTimeChecker < diff)+ {+ if(time(NULL) > m_NextAutoDistributionTime)+ {+ DistributeArenaPoints();+ m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_WEEK;+ CharacterDatabase.PExecute("UPDATE `saved_variables` SET `NextArenaPointDistributionTime` = FROM_UNIXTIME('"I64FMTD"')",(uint64)m_NextAutoDistributionTime);+ }+ m_AutoDistributionTimeChecker = 600000; // check 10 minutes+ }+ else+ m_AutoDistributionTimeChecker -= diff;+ } } -void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2)+void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype, uint8 israted) { // we can be in 3 queues in same time... if(StatusID == 0)@@ -427,7 +977,7 @@ data->Initialize(SMSG_BATTLEFIELD_STATUS, (4+1+1+4+2+4+1+4+4+4)); *data << uint32(QueueSlot); // queue id (0...2) - player can be in 3 queues in time- *data << uint8(bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas+ *data << uint8(arenatype ? arenatype : bg->GetArenaType()); // team type (0=BG, 2=2x2, 3=3x3, 5=5x5), for arenas // NOT PROPER VALUE IF ARENA ISN'T RUNNING YET!!!! switch(bg->GetTypeID()) // value depends on bg id { case BATTLEGROUND_AV:@@ -460,9 +1010,9 @@ } if(bg->isArena() && (StatusID == STATUS_WAIT_QUEUE))- *data << uint32(BATTLEGROUND_AA); // all arenas+ *data << uint32(BATTLEGROUND_AA); // all arenas I don't think so. else- *data << uint32(bg->GetTypeID()); // BG id from DBC+ *data << uint32(bg->GetTypeID()); // BG id from DBC *data << uint16(0x1F90); // unk value 8080 *data << uint32(bg->GetInstanceID()); // instance id@@ -470,7 +1020,7 @@ if(bg->isBattleGround()) *data << uint8(bg->GetTeamIndexByTeamId(team)); // team else- *data << uint8(bg->isRated()); // is rated battle+ *data << uint8(israted?israted:bg->isRated()); // is rated battle *data << uint32(StatusID); // status switch(StatusID)@@ -505,7 +1055,7 @@ { for(uint8 i = 0; i < 2; i++) {- *data << uint32(3000+1+i); // rating change: showed value - 3000+ *data << uint32(3000+bg->m_ArenaTeamRatingChanges[i]); // rating change: showed value - 3000 *data << uint8(0); // string } }@@ -536,11 +1086,13 @@ { // that part probably wrong Player *plr = objmgr.GetPlayer(itr->first);+ uint32 team = bg->GetPlayerTeam(plr->GetGUID());+ if(!team) team = plr->GetTeam(); if(plr) {- if(plr->GetTeam() == HORDE)+ if(team == HORDE) *data << uint8(0);- else if(plr->GetTeam() == ALLIANCE)+ else if(team == ALLIANCE) *data << uint8(1); else *data << uint8(0);@@ -624,20 +1176,133 @@ *data << uint64(plr->GetGUID()); } -void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID)+void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team) { // set invited player counters: BattleGround* bg = this->GetBattleGround(bgInstanceGUID);- bg->IncreaseInvitedCount(plr->GetTeam());+ bg->IncreaseInvitedCount(team); + // set the arena teams for rated matches+ if(bg->isArena() && bg->isRated())+ {+ switch(bg->GetArenaType())+ {+ case ARENA_TYPE_2v2:+ bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(0));+ break;+ case ARENA_TYPE_3v3:+ bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(1));+ break;+ case ARENA_TYPE_5v5:+ bg->SetArenaTeamIdForTeam(team, plr->GetArenaTeamId(2));+ break;+ default:+ break;+ }+ }+ // create invite events: //add events to player's counters ---- this is not good way - there should be something like global event processor, where we should add those events BGQueueInviteEvent* inviteEvent = new BGQueueInviteEvent(plr->GetGUID(), bgInstanceGUID); plr->m_Events.AddEvent(inviteEvent, plr->m_Events.CalculateTime(BG_REMIND_INVITE_TIME));- BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, plr->GetTeam());+ BGQueueRemoveEvent* removeEvent = new BGQueueRemoveEvent(plr->GetGUID(), bgInstanceGUID, team); plr->m_Events.AddEvent(removeEvent, plr->m_Events.CalculateTime(2*BG_REMIND_INVITE_TIME)); } +BattleGround * BattleGroundMgr::GetBattleGroundTemplate(uint32 bgTypeId)+{+ return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();+}++// create a new battleground that will really be used to play+BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)+{+ BattleGround *bg = NULL;++ // get the template BG+ BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);++ if(!bg_template)+ {+ sLog.outError("BattleGround: CreateNewBattleGround - bg template not found for %u", bgTypeId);+ return 0;+ }+ + // create a copy of the BG template+ switch(bgTypeId)+ {+ case BATTLEGROUND_AV: + bg = new BattleGroundAV(*(BattleGroundAV*)bg_template); + break;+ case BATTLEGROUND_WS: + bg = new BattleGroundWS(*(BattleGroundWS*)bg_template); + break;+ case BATTLEGROUND_AB: + bg = new BattleGroundAB(*(BattleGroundAB*)bg_template); + break;+ case BATTLEGROUND_NA: + bg = new BattleGroundNA(*(BattleGroundNA*)bg_template); + break;+ case BATTLEGROUND_BE: + bg = new BattleGroundBE(*(BattleGroundBE*)bg_template); + break;+ case BATTLEGROUND_AA: + bg = new BattleGroundAA(*(BattleGroundAA*)bg_template); + break;+ case BATTLEGROUND_EY: + bg = new BattleGroundEY(*(BattleGroundEY*)bg_template); + break;+ case BATTLEGROUND_RL: + bg = new BattleGroundRL(*(BattleGroundRL*)bg_template); + break;+ default:+ //bg = new BattleGround; + return 0;+ break; // placeholder for non implemented BG+ }++ // generate a new instance id+ bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id++/* UNCOMMENT THIS IF MAP SYSTEM IS UPDATED+ // get the map+ Map * m = MapManager::Instance().GetMap(bg->GetMapId(),NULL);+ if(!m)+ {+ // no map found, delete bg and return null+ delete bg;+ return 0;+ }++ // create new instance if the map is instanceable+ if(m->Instanceable())+ {+ // generate a new instance id+ bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id+ ((MapInstanced*)m)->CreateInstance(bg->GetInstanceID(),m);+ }+*/++ // reset the new bg (set status to status_wait_queue from status_none)+ bg->Reset();++ if(!(bg->SetupBattleGround()))+ {+ sLog.outError("BattleGround: CreateNewBattleGround: SetupBattleGround failed for bg %u", bgTypeId);+ delete bg;+ return 0;+ }++ // add BG to free slot queue+ bg->AddToBGFreeSlotQueue();++ // add bg to update list+ AddBattleGround(bg->GetInstanceID(), bg);++ return bg;+}++// used to create the BG templates uint32 BattleGroundMgr::CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO) { // Create the BG@@ -657,12 +1322,12 @@ } bg->SetMapId(MapID);++ // set unloadflag to false+ Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(MapID));+ if(map) map->SetUnloadMap(false);+ bg->Reset();- if(!bg->SetupBattleGround())- {- delete bg;- return 0;- } BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId); //in previous method is checked if exists entry in sBattlemasterListStore, so no check needed@@ -672,7 +1337,7 @@ } bg->SetTypeID(bgTypeId);- bg->SetInstanceID(bgTypeId); // temporary+ bg->SetInstanceID(0); // template bg, instance id is 0 bg->SetMinPlayersPerTeam(MinPlayersPerTeam); bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam); bg->SetMinPlayers(MinPlayersPerTeam*2);@@ -681,12 +1346,14 @@ bg->SetTeamStartLoc(ALLIANCE, Team1StartLocX, Team1StartLocY, Team1StartLocZ, Team1StartLocO); bg->SetTeamStartLoc(HORDE, Team2StartLocX, Team2StartLocY, Team2StartLocZ, Team2StartLocO); bg->SetLevelRange(LevelMin, LevelMax);- //add BaggleGround instance to FreeSlotQueue++ //add BattleGround instance to FreeSlotQueue (.back() will return the template!) bg->AddToBGFreeSlotQueue(); - AddBattleGround(bg->GetInstanceID(), bg);- //sLog.outDetail("BattleGroundMgr: Created new battleground: %u %s (Map %u, %u players per team, Levels %u-%u)", bg_TypeID, bg->m_Name, bg->m_MapId, bg->m_MaxPlayersPerTeam, bg->m_LevelMin, bg->m_LevelMax);- return bg->GetInstanceID();+ // do NOT add to update list, since this is a template battleground!++ // return some not-null value, bgTypeId is good enough for me+ return bgTypeId; } void BattleGroundMgr::CreateInitialBattleGrounds()@@ -806,6 +1473,86 @@ sLog.outString( ">> Loaded %u battlegrounds", count ); } +void BattleGroundMgr::InitAutomaticArenaPointDistribution()+{+ if(m_AutoDistributePoints)+ {+ sLog.outDebug("Initializing Automatic Arena Point Distribution");+ QueryResult * result = CharacterDatabase.Query("SELECT UNIX_TIMESTAMP(`NextArenaPointDistributionTime`) FROM `saved_variables`");+ if(!result)+ {+ sLog.outDebug("Battleground: Next arena point distribution time not found in SavedVariables, reseting it now."); + m_NextAutoDistributionTime = time(NULL) + BATTLEGROUND_ARENA_POINT_DISTRIBUTION_WEEK;+ CharacterDatabase.PExecute("INSERT INTO `saved_variables` (`NextArenaPointDistributionTime`) VALUES ( FROM_UNIXTIME('"I64FMTD"') )",(uint64)m_NextAutoDistributionTime);+ }+ else+ {+ m_NextAutoDistributionTime = (*result)[0].GetUInt64();+ delete result;+ }+ sLog.outDebug("Automatic Arena Point Distribution initialized.");+ }+}++void BattleGroundMgr::DistributeArenaPoints()+{+ // used to distribute arena points based on last week's stats+ sWorld.SendWorldText("Flushing Arena points based on team ratings, this may take a few minutes. Please stand by...", NULL);++ sWorld.SendWorldText("Distributing arena points to online players...", NULL);++ //TODO: Guard Player map+ HashMapHolder<Player>::MapType& m = ObjectAccessor::Instance().GetPlayers();+ for(HashMapHolder<Player>::MapType::iterator itr = m.begin(); itr != m.end(); ++itr)+ {+ uint64 guid = itr->second->GetGUID();+ Player * pl = itr->second;+ if(!pl)+ continue;+ uint32 mod = 0;+ for(int i=0; i<3; ++i)+ {+ ArenaTeam * at = objmgr.GetArenaTeamById(pl->GetArenaTeamId(i));+ if(at && mod < at->GetMemberPoints(guid))+ mod = at->GetMemberPoints(guid);+ // reset weekly played match count for team+ if(at)+ pl->SetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * at->GetSlot() + 2, 0);++ }+ mod += pl->GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY);+ if(mod > 5000)+ mod = 5000;++ pl->SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, mod);++ CharacterDatabase.PExecute("UPDATE `arena_team_member` SET `points_to_add` = '0' WHERE `guid` = '%u'",guid);+ }++ sWorld.SendWorldText("Finished distributing arena points to online players. Now saving... ", NULL);++ ObjectAccessor::Instance().SaveAllPlayers();++ sWorld.SendWorldText("Online players saved.", NULL);++ sWorld.SendWorldText("Distributing arena points to offline players...", NULL);++ CharacterDatabase.BeginTransaction();+ CharacterDatabase.PExecute("UPDATE `character` b, `arena_team_member` a SET b.`data` = CONCAT( SUBSTRING_INDEX(b.`data`, ' ', '%u'),' ', CAST( IF ( ((CAST( SUBSTRING( b.`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) + 2) FOR (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - 1) ) AS UNSIGNED) + (SELECT MAX(c.`points_to_add`) FROM `arena_team_member` c WHERE c.`guid` = b.`guid` GROUP BY c.`guid`) ) < '5000'), CAST(SUBSTRING(b.`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) + 2) FOR (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) - 1) ) AS UNSIGNED) + (SELECT MAX(d.`points_to_add`) FROM `arena_team_member` d WHERE d.`guid` = b.`guid` GROUP BY d.`guid`), '5000') AS CHAR),' ',SUBSTRING(b.`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(b.`data`,' ','%u')) + 2))) WHERE b.`guid` = a.`guid`",PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1, PLAYER_FIELD_ARENA_CURRENCY, PLAYER_FIELD_ARENA_CURRENCY+1);+ for(int i=0; i<3; ++i)+ {+ // reset weekly played matches+ uint32 position = PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + 6 * i + 2;+ CharacterDatabase.PExecute("UPDATE `character` SET `data` = CONCAT( SUBSTRING_INDEX(`data`,' ','%u'),' ','0',' ',SUBSTRING(`data` FROM (CHAR_LENGTH(SUBSTRING_INDEX(`data`,' ','%u')) + 2)))",position, position + 1);+ }+ CharacterDatabase.Execute("UPDATE `arena_team_member` SET `points_to_add` = '0', `played_week` = '0', `wons_week` = '0'");+ CharacterDatabase.Execute("UPDATE `arena_team_stats` SET `games` = '0', `wins` = '0'");+ CharacterDatabase.CommitTransaction();++ sWorld.SendWorldText("Finished distributing arena points to offline players.", NULL);+ sWorld.SendWorldText("Done flushing Arena points.", NULL);+}+ void BattleGroundMgr::BuildBattleGroundListPacket(WorldPacket *data, uint64 guid, Player* plr, uint32 bgTypeId) { uint32 PlayerLevel = 10;@@ -841,18 +1588,27 @@ } } -void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 bgTypeId)+void BattleGroundMgr::SendToBattleGround(Player *pl, uint32 instanceId, uint32 team) {- BattleGround *bg = GetBattleGround(bgTypeId);+ BattleGround *bg = GetBattleGround(instanceId); if(bg) { uint32 mapid = bg->GetMapId(); float x, y, z, O;- bg->GetTeamStartLoc(pl->GetTeam(), x, y, z, O);+ if(team==0)+ team = pl->GetTeam();+ bg->GetTeamStartLoc(team, x, y, z, O); sLog.outDetail("BATTLEGROUND: Sending %s to map %u, X %f, Y %f, Z %f, O %f", pl->GetName(), mapid, x, y, z, O);- pl->TeleportTo(mapid, x, y, z, O);+ pl->SetInstanceId(instanceId); + pl->m_BoundInstances[mapid]=std::pair<uint32,uint32>(instanceId, pl->GetGUIDLow());+ // teleport as gm command+ pl->TeleportTo(mapid, x, y, z, O, true, true, false, true); }+ else+ {+ sLog.outError("player %u trying to port to non-existent bg instance %u",pl->GetGUIDLow(), instanceId);+ } } void BattleGroundMgr::SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid)@@ -864,3 +1620,91 @@ data << guid << time_; pl->GetSession()->SendPacket(&data); }++void BattleGroundMgr::RemoveBattleGround(uint32 instanceID)+{+ BattleGroundSet::iterator itr = m_BattleGrounds.find(instanceID);+ if(itr!=m_BattleGrounds.end())+ m_BattleGrounds.erase(itr);+}++bool BattleGroundMgr::IsArenaType(uint32 bgTypeId) const+{+ return ( bgTypeId == BATTLEGROUND_AA ||+ bgTypeId == BATTLEGROUND_BE ||+ bgTypeId == BATTLEGROUND_NA ||+ bgTypeId == BATTLEGROUND_RL );+}++bool BattleGroundMgr::IsBattleGroundType(uint32 bgTypeId) const+{+ return !IsArenaType(bgTypeId);+}++uint32 BattleGroundMgr::BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const+{+ switch(bgTypeId)+ {+ case BATTLEGROUND_WS:+ return BATTLEGROUND_QUEUE_WS;+ case BATTLEGROUND_AB:+ return BATTLEGROUND_QUEUE_AB;+ case BATTLEGROUND_AV:+ return BATTLEGROUND_QUEUE_AV;+ case BATTLEGROUND_EY:+ return BATTLEGROUND_QUEUE_EY;+ case BATTLEGROUND_AA:+ case BATTLEGROUND_NA:+ case BATTLEGROUND_RL:+ case BATTLEGROUND_BE:+ switch(arenaType)+ {+ case ARENA_TYPE_2v2:+ return BATTLEGROUND_QUEUE_2v2;+ case ARENA_TYPE_3v3:+ return BATTLEGROUND_QUEUE_3v3;+ case ARENA_TYPE_5v5:+ return BATTLEGROUND_QUEUE_5v5;+ default:+ return 0;+ }+ default:+ return 0;+ }+}++uint32 BattleGroundMgr::BGTemplateId(uint32 bgQueueTypeId) const+{+ switch(bgQueueTypeId)+ {+ case BATTLEGROUND_QUEUE_WS:+ return BATTLEGROUND_WS;+ case BATTLEGROUND_QUEUE_AB:+ return BATTLEGROUND_AB;+ case BATTLEGROUND_QUEUE_AV:+ return BATTLEGROUND_AV;+ case BATTLEGROUND_QUEUE_EY:+ return BATTLEGROUND_EY;+ case BATTLEGROUND_QUEUE_2v2:+ case BATTLEGROUND_QUEUE_3v3:+ case BATTLEGROUND_QUEUE_5v5:+ return BATTLEGROUND_AA;+ default:+ return 0;+ }+}++uint8 BattleGroundMgr::BGArenaType(uint32 bgQueueTypeId) const+{+ switch(bgQueueTypeId)+ {+ case BATTLEGROUND_QUEUE_2v2:+ return ARENA_TYPE_2v2;+ case BATTLEGROUND_QUEUE_3v3:+ return ARENA_TYPE_3v3;+ case BATTLEGROUND_QUEUE_5v5:+ return ARENA_TYPE_5v5;+ default:+ return 0;+ }+}Index: src/game/BattleGroundMgr.h===================================================================--- src/game/BattleGroundMgr.h (revision 5306)+++ src/game/BattleGroundMgr.h (working copy)@@ -34,53 +34,99 @@ #define MAX_BATTLEGROUND_TYPES 9 // each BG type will be in array +#define MAX_BATTLEGROUND_QUEUE_TYPES 8+ #define BG_REMIND_INVITE_TIME 60000 // when this time pass, player get invitation request again -struct PlayerQueueInfo+#define BATTLEGROUND_ARENA_POINT_DISTRIBUTION_WEEK 604800 // seconds in a week++struct GroupQueueInfo; // type predefinition+struct PlayerQueueInfo // stores information for players in queue { uint32 InviteTime; // first invite time uint32 LastInviteTime; // last invite time- uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG uint32 LastOnlineTime; // for tracking and removing offline players from queue after 5 minutes- uint32 Team; // Player team (ALLIANCE/HORDE)- bool IsRated;- bool AsGroup; // uint32 GroupId;- uint8 ArenaType;+ GroupQueueInfo * GroupInfo; // pointer to the associated groupqueueinfo }; -struct PlayersCount+struct GroupQueueInfo // stores information about the group in queue (also used when joined as solo!) {- uint32 Alliance;- uint32 Horde;+ std::map<uint64, PlayerQueueInfo*> Players; // player queue info map+ uint32 Team; // Player team (ALLIANCE/HORDE)+ bool IsRated; // rated+ uint32 BgTypeId; // battleground type id+ uint8 ArenaType; // 2v2, 3v3, 5v5 or 0 when BG+ uint32 JoinTime; // time when group was added+ uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG+ uint32 ArenaTeamRating; // if rated match, inited to the rating of the team }; -template<class _Kty, class _Ty> class bgqueue: public std::map<_Kty, _Ty>-{- public:- uint32 Alliance;- uint32 Horde;- //bool Ready; // not used now- //uint32 AverageTime; //not already implemented (it should be average time in queue for last 10 players)-};-+class BattleGround; class BattleGroundQueue { public: BattleGroundQueue(); ~BattleGroundQueue();-/*- uint32 GetType();- void SetType(uint32 type);*/ - void Update(uint32 bgTypeId, uint32 queue_id);+ void Update(uint32 bgTypeId, uint32 queue_id, uint8 arenatype = 0, bool isRated = false, uint32 minRating = 0); - void AddPlayer(Player *plr, uint32 bgTypeId);+ GroupQueueInfo * AddGroup(Player * leader, uint32 BgTypeId, uint8 ArenaType, bool isRated, uint32 ArenaRating);+ void AddPlayer(Player *plr, GroupQueueInfo * ginfo); void RemovePlayer(uint64 guid, bool decreaseInvitedCount);+ void DecreaseGroupLength(uint32 queueId, uint32 AsGroup);+ void BGEndedRemoveInvites(BattleGround * bg); - typedef bgqueue<uint64, PlayerQueueInfo> QueuedPlayersMap;+ typedef std::map<uint64, PlayerQueueInfo> QueuedPlayersMap; QueuedPlayersMap m_QueuedPlayers[MAX_BATTLEGROUND_QUEUES];- typedef std::list<uint64> PlayerGuidsSortedByTimeQueue;- PlayerGuidsSortedByTimeQueue m_PlayersSortedByWaitTime[MAX_BATTLEGROUND_QUEUES];++ typedef std::list<GroupQueueInfo*> QueuedGroupsList;+ QueuedGroupsList m_QueuedGroups[MAX_BATTLEGROUND_QUEUES];++ // class to hold pointers to the groups eligible for a specific selection pool building mode+ class EligibleGroups : public std::list<GroupQueueInfo *>+ {+ public:+ void Init(QueuedGroupsList * source, uint32 BgTypeId, uint32 side, uint32 MaxPlayers, uint8 ArenaType = 0, bool IsRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0);+ void RemoveGroup(GroupQueueInfo * ginfo);+ };++ EligibleGroups m_EligibleGroups;++ // class to select and invite groups to bg+ class SelectionPool+ {+ public:+ void Init();+ void AddGroup(GroupQueueInfo * group);+ GroupQueueInfo * GetMaximalGroup();+ void RemoveGroup(GroupQueueInfo * group);+ uint32 GetPlayerCount() const {return PlayerCount;}+ public:+ std::list<GroupQueueInfo *> SelectedGroups;+ private:+ uint32 PlayerCount;+ GroupQueueInfo * MaxGroup;+ };++ enum SelectionPoolBuildMode+ {+ NORMAL_ALLIANCE,+ NORMAL_HORDE,+ ONESIDE_ALLIANCE_TEAM1,+ ONESIDE_ALLIANCE_TEAM2,+ ONESIDE_HORDE_TEAM1,+ ONESIDE_HORDE_TEAM2,++ NUM_SELECTION_POOL_TYPES+ };++ SelectionPool m_SelectionPools[NUM_SELECTION_POOL_TYPES];++ bool BuildSelectionPool(uint32 bgTypeId, uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType = 0, bool isRated = false, uint32 MinRating = 0, uint32 MaxRating = 0, uint32 DisregardTime = 0);++ private:++ bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side); }; /*@@ -98,7 +144,6 @@ private: uint64 m_PlayerGuid; uint32 m_BgInstanceGUID;- }; /*@@ -118,7 +163,6 @@ uint32 m_PlayersTeam; }; - class BattleGroundMgr { public:@@ -134,18 +178,18 @@ void BuildGroupJoinedBattlegroundPacket(WorldPacket *data, uint32 bgTypeId); void BuildUpdateWorldStatePacket(WorldPacket *data, uint32 field, uint32 value); void BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg);- void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2);+ void BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2, uint32 arenatype = 0, uint8 israted = 0); void BuildPlaySoundPacket(WorldPacket *data, uint32 soundid); /* Player invitation */ // called from Queue update, or from Addplayer to queue- void InvitePlayer(Player* plr, uint32 bgInstanceGUID);+ void InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team); /* Battlegrounds */ BattleGroundSet::iterator GetBattleGroundsBegin() { return m_BattleGrounds.begin(); }; BattleGroundSet::iterator GetBattleGroundsEnd() { return m_BattleGrounds.end(); }; - BattleGround* GetBattleGround(uint8 ID)+ BattleGround* GetBattleGround(uint32 ID) { BattleGroundSet::iterator i = m_BattleGrounds.find(ID); if(i != m_BattleGrounds.end())@@ -154,26 +198,48 @@ return NULL; }; + BattleGround * GetBattleGroundTemplate(uint32 bgTypeId);+ BattleGround * CreateNewBattleGround(uint32 bgTypeId);+ uint32 CreateBattleGround(uint32 bgTypeId, uint32 MinPlayersPerTeam, uint32 MaxPlayersPerTeam, uint32 LevelMin, uint32 LevelMax, char* BattleGroundName, uint32 MapID, float Team1StartLocX, float Team1StartLocY, float Team1StartLocZ, float Team1StartLocO, float Team2StartLocX, float Team2StartLocY, float Team2StartLocZ, float Team2StartLocO); inline void AddBattleGround(uint32 ID, BattleGround* BG) { m_BattleGrounds[ID] = BG; };+ void RemoveBattleGround(uint32 instanceID); void CreateInitialBattleGrounds(); - void SendToBattleGround(Player *pl, uint32 bgTypeId);+ void SendToBattleGround(Player *pl, uint32 bgTypeId, uint32 team = 0); /* Battleground queues */ //these queues are instantiated when creating BattlegroundMrg- BattleGroundQueue m_BattleGroundQueues[MAX_BATTLEGROUND_TYPES]; // public, because we need to access them in BG handler code+ BattleGroundQueue m_BattleGroundQueues[MAX_BATTLEGROUND_QUEUE_TYPES]; // public, because we need to access them in BG handler code BGFreeSlotQueueType BGFreeSlotQueue[MAX_BATTLEGROUND_TYPES]; void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid); + bool IsArenaType(uint32 bgTypeId) const;+ bool IsBattleGroundType(uint32 bgTypeId) const;+ uint32 BGQueueTypeId(uint32 bgTypeId, uint8 arenaType) const;+ uint32 BGTemplateId(uint32 bgQueueTypeId) const;+ uint8 BGArenaType(uint32 bgQueueTypeId) const;++ uint32 GetMaxRatingDifference() const {return m_MaxRatingDifference;}+ uint32 GetRatingDiscardTimer() const {return m_RatingDiscardTimer;}++ void InitAutomaticArenaPointDistribution();+ void DistributeArenaPoints();+ private: /* Battlegrounds */ BattleGroundSet m_BattleGrounds;+ uint32 m_MaxRatingDifference;+ uint32 m_RatingDiscardTimer;+ uint32 m_NextRatingDiscardUpdate;+ bool m_AutoDistributePoints;+ uint64 m_NextAutoDistributionTime;+ uint32 m_AutoDistributionTimeChecker; }; #define sBattleGroundMgr MaNGOS::Singleton<BattleGroundMgr>::Instance()Index: src/game/BattleGroundNA.cpp===================================================================--- src/game/BattleGroundNA.cpp (revision 5306)+++ src/game/BattleGroundNA.cpp (working copy)@@ -73,6 +73,9 @@ for(uint32 i = BG_NA_OBJECT_DOOR_1; i <= BG_NA_OBJECT_DOOR_2; i++) DoorOpen(i); + for(uint32 i = BG_NA_OBJECT_BUFF_1; i <= BG_NA_OBJECT_BUFF_2; i++)+ SpawnBGObject(i, 60);+ SendMessageToAll(LANG_ARENA_BEGUN); SetStatus(STATUS_IN_PROGRESS); SetStartDelayTime(0);@@ -83,6 +86,11 @@ if(plr) plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); }++ if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+ EndBattleGround(HORDE);+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))+ EndBattleGround(ALLIANCE); } } @@ -92,9 +100,9 @@ }*/ } -void BattleGroundNA::AddPlayer(Player *plr)+void BattleGroundNA::AddPlayer(Player *plr, uint32 team) {- BattleGround::AddPlayer(plr);+ BattleGround::AddPlayer(plr, team); //create score and add it to map, default values are set in constructor BattleGroundNAScore* sc = new BattleGroundNAScore; @@ -103,7 +111,13 @@ void BattleGroundNA::RemovePlayer(Player *plr, uint64 guid) {+ if(GetStatus() == STATUS_WAIT_LEAVE)+ return; + if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+ EndBattleGround(HORDE);+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))+ EndBattleGround(ALLIANCE); } void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer)@@ -117,15 +131,16 @@ return; } - uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());-- m_TeamKills[killer_team_index]++; // add kills to killer's team-- if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))+ if(!GetAlivePlayersCountByTeam(ALLIANCE)) { // all opponents killed- EndBattleGround(killer->GetTeam());+ EndBattleGround(HORDE); }+ else if(!GetAlivePlayersCountByTeam(HORDE))+ {+ // all opponents killed+ EndBattleGround(ALLIANCE);+ } } void BattleGroundNA::HandleAreaTrigger(Player *Source, uint32 Trigger)@@ -134,11 +149,14 @@ return; uint32 SpellId = 0;- uint64 buff_guid = 0;+ GameObject* obj = 0; switch(Trigger) { case 4536: // buff trigger?+ obj = m_BgObjects[BG_NA_OBJECT_BUFF_1];+ break; case 4537: // buff trigger?+ obj = m_BgObjects[BG_NA_OBJECT_BUFF_2]; break; default: sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);@@ -146,11 +164,8 @@ break; } - if(buff_guid)+ if(obj) {- GameObject *obj = HashMapHolder<GameObject>::Find(buff_guid);- if(obj)- { if(!obj->isSpawned()) return; // buff not spawned yet obj->SetRespawnTime(BUFF_RESPAWN_TIME);@@ -158,14 +173,12 @@ SpellId = obj->GetGOInfo()->data3; if(SpellId) Source->CastSpell(Source, SpellId, true);- } } } void BattleGroundNA::ResetBGSubclass() {- m_TeamKills[BG_TEAM_ALLIANCE] = 0;- m_TeamKills[BG_TEAM_HORDE] = 0;+ } bool BattleGroundNA::SetupBattleGround()@@ -174,7 +187,10 @@ if( !AddObject(BG_NA_OBJECT_DOOR_1, BG_NA_OBJECT_TYPE_DOOR_1, 4031.854, 2966.833, 12.6462, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY) || !AddObject(BG_NA_OBJECT_DOOR_2, BG_NA_OBJECT_TYPE_DOOR_2, 4081.179, 2874.97, 12.39171, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY) || !AddObject(BG_NA_OBJECT_DOOR_3, BG_NA_OBJECT_TYPE_DOOR_3, 4023.709, 2981.777, 10.70117, -2.648788, 0, 0, 0.9697962, -0.2439165, RESPAWN_IMMEDIATELY)- || !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY))+ || !AddObject(BG_NA_OBJECT_DOOR_4, BG_NA_OBJECT_TYPE_DOOR_4, 4090.064, 2858.438, 10.23631, 0.4928045, 0, 0, 0.2439165, 0.9697962, RESPAWN_IMMEDIATELY)+ // buffs+ || !AddObject(BG_NA_OBJECT_BUFF_1, BG_NA_OBJECT_TYPE_BUFF_1, 4009.189941, 2895.250000, 13.052700, -1.448624, 0, 0, 0.6626201, -0.7489557, 120)+ || !AddObject(BG_NA_OBJECT_BUFF_2, BG_NA_OBJECT_TYPE_BUFF_2, 4103.330078, 2946.350098, 13.051300, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120)) { sLog.outErrorDb("BatteGroundNA: Failed to spawn some object!"); return false;Index: src/game/BattleGroundNA.h===================================================================--- src/game/BattleGroundNA.h (revision 5306)+++ src/game/BattleGroundNA.h (working copy)@@ -26,7 +26,9 @@ BG_NA_OBJECT_DOOR_2 = 1, BG_NA_OBJECT_DOOR_3 = 2, BG_NA_OBJECT_DOOR_4 = 3,- BG_NA_OBJECT_MAX = 4+ BG_NA_OBJECT_BUFF_1 = 4,+ BG_NA_OBJECT_BUFF_2 = 5,+ BG_NA_OBJECT_MAX = 6 }; enum BattleGroundNAObjects@@ -34,7 +36,9 @@ BG_NA_OBJECT_TYPE_DOOR_1 = 183978, BG_NA_OBJECT_TYPE_DOOR_2 = 183980, BG_NA_OBJECT_TYPE_DOOR_3 = 183977,- BG_NA_OBJECT_TYPE_DOOR_4 = 183979+ BG_NA_OBJECT_TYPE_DOOR_4 = 183979,+ BG_NA_OBJECT_TYPE_BUFF_1 = 184663,+ BG_NA_OBJECT_TYPE_BUFF_2 = 184664 }; class BattleGroundNAScore : public BattleGroundScore@@ -55,15 +59,12 @@ void Update(time_t diff); /* inherited from BattlegroundClass */- virtual void AddPlayer(Player *plr);+ virtual void AddPlayer(Player *plr, uint32 team = 0); void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); bool SetupBattleGround(); virtual void ResetBGSubclass(); void HandleKillPlayer(Player* player, Player *killer);-- private:- uint32 m_TeamKills[2]; // count of kills for each team }; #endifIndex: src/game/BattleGroundRL.cpp===================================================================--- src/game/BattleGroundRL.cpp (revision 5306)+++ src/game/BattleGroundRL.cpp (working copy)@@ -74,6 +74,9 @@ for(uint32 i = BG_RL_OBJECT_DOOR_1; i <= BG_RL_OBJECT_DOOR_2; i++) DoorOpen(i); + for(uint32 i = BG_RL_OBJECT_BUFF_1; i <= BG_RL_OBJECT_BUFF_2; i++)+ SpawnBGObject(i, 60);+ SendMessageToAll(LANG_ARENA_BEGUN); SetStatus(STATUS_IN_PROGRESS); SetStartDelayTime(0);@@ -84,6 +87,11 @@ if(plr) plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION); }++ if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+ EndBattleGround(HORDE);+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))+ EndBattleGround(ALLIANCE); } } @@ -93,9 +101,9 @@ }*/ } -void BattleGroundRL::AddPlayer(Player *plr)+void BattleGroundRL::AddPlayer(Player *plr, uint32 team) {- BattleGround::AddPlayer(plr);+ BattleGround::AddPlayer(plr, team); //create score and add it to map, default values are set in constructor BattleGroundRLScore* sc = new BattleGroundRLScore; @@ -104,7 +112,13 @@ void BattleGroundRL::RemovePlayer(Player *plr, uint64 guid) {+ if(GetStatus() == STATUS_WAIT_LEAVE)+ return; + if(!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+ EndBattleGround(HORDE);+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))+ EndBattleGround(ALLIANCE); } void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer)@@ -118,15 +132,16 @@ return; } - uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());-- m_TeamKills[killer_team_index]++; // add kills to killer's team-- if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))+ if(!GetAlivePlayersCountByTeam(ALLIANCE)) { // all opponents killed- EndBattleGround(killer->GetTeam());+ EndBattleGround(HORDE); }+ else if(!GetAlivePlayersCountByTeam(HORDE))+ {+ // all opponents killed+ EndBattleGround(ALLIANCE);+ } } void BattleGroundRL::HandleAreaTrigger(Player *Source, uint32 Trigger)@@ -136,11 +151,14 @@ return; uint32 SpellId = 0;- uint64 buff_guid = 0;+ GameObject* obj = 0; switch(Trigger) { case 4696: // buff trigger?+ obj = m_BgObjects[BG_RL_OBJECT_BUFF_1];+ break; case 4697: // buff trigger?+ obj = m_BgObjects[BG_RL_OBJECT_BUFF_2]; break; default: sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger);@@ -148,11 +166,8 @@ break; } - if(buff_guid)+ if(obj) {- GameObject *obj = HashMapHolder<GameObject>::Find(buff_guid);- if(obj)- { if(!obj->isSpawned()) return; // buff not spawned yet obj->SetRespawnTime(BUFF_RESPAWN_TIME);@@ -160,21 +175,22 @@ SpellId = obj->GetGOInfo()->data3; if(SpellId) Source->CastSpell(Source, SpellId, true);- } } } void BattleGroundRL::ResetBGSubclass() {- m_TeamKills[BG_TEAM_ALLIANCE] = 0;- m_TeamKills[BG_TEAM_HORDE] = 0;+ } bool BattleGroundRL::SetupBattleGround() { // gates if( !AddObject(BG_RL_OBJECT_DOOR_1, BG_RL_OBJECT_TYPE_DOOR_1, 1293.561, 1601.938, 31.60557, -1.457349, 0, 0, -0.6658813, 0.7460576, RESPAWN_IMMEDIATELY)- || !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY))+ || !AddObject(BG_RL_OBJECT_DOOR_2, BG_RL_OBJECT_TYPE_DOOR_2, 1278.648, 1730.557, 31.60557, 1.684245, 0, 0, 0.7460582, 0.6658807, RESPAWN_IMMEDIATELY)+ // buffs+ || !AddObject(BG_RL_OBJECT_BUFF_1, BG_RL_OBJECT_TYPE_BUFF_1, 1328.719971, 1632.719971, 36.730400, -1.448624, 0, 0, 0.6626201, -0.7489557, 120)+ || !AddObject(BG_RL_OBJECT_BUFF_2, BG_RL_OBJECT_TYPE_BUFF_2, 1243.300049, 1699.170044, 34.872601, -0.06981307, 0, 0, 0.03489945, -0.9993908, 120)) { sLog.outErrorDb("BatteGroundRL: Failed to spawn some object!"); return false;Index: src/game/BattleGroundRL.h===================================================================--- src/game/BattleGroundRL.h (revision 5306)+++ src/game/BattleGroundRL.h (working copy)@@ -24,13 +24,17 @@ { BG_RL_OBJECT_DOOR_1 = 0, BG_RL_OBJECT_DOOR_2 = 1,- BG_RL_OBJECT_MAX = 2+ BG_RL_OBJECT_BUFF_1 = 2,+ BG_RL_OBJECT_BUFF_2 = 3,+ BG_RL_OBJECT_MAX = 4 }; enum BattleGroundRLObjects { BG_RL_OBJECT_TYPE_DOOR_1 = 185918,- BG_RL_OBJECT_TYPE_DOOR_2 = 185917+ BG_RL_OBJECT_TYPE_DOOR_2 = 185917,+ BG_RL_OBJECT_TYPE_BUFF_1 = 184663,+ BG_RL_OBJECT_TYPE_BUFF_2 = 184664 }; class BattleGroundRLScore : public BattleGroundScore@@ -51,15 +55,12 @@ void Update(time_t diff); /* inherited from BattlegroundClass */- virtual void AddPlayer(Player *plr);+ virtual void AddPlayer(Player *plr, uint32 team = 0); void RemovePlayer(Player *plr, uint64 guid); void HandleAreaTrigger(Player *Source, uint32 Trigger); bool SetupBattleGround(); virtual void ResetBGSubclass(); void HandleKillPlayer(Player* player, Player *killer);-- private:- uint32 m_TeamKills[2]; // count of kills for each team }; #endifIndex: src/game/BattleGroundWS.cpp===================================================================--- src/game/BattleGroundWS.cpp (revision 5306)+++ src/game/BattleGroundWS.cpp (working copy)@@ -50,6 +50,9 @@ { m_Events |= 0x01; + for(uint32 i = WS_SPIRIT_MAIN_ALLIANCE; i <= WS_SPIRIT_MAIN_HORDE; i++)+ SpawnBGCreature(i, RESPAWN_IMMEDIATELY);+ for(uint32 i = BG_WS_OBJECT_DOOR_A_1; i <= BG_WS_OBJECT_DOOR_H_4; i++) SpawnBGObject(i, RESPAWN_IMMEDIATELY); @@ -111,9 +114,9 @@ } } -void BattleGroundWS::AddPlayer(Player *plr)+void BattleGroundWS::AddPlayer(Player *plr, uint32 team) {- BattleGround::AddPlayer(plr);+ BattleGround::AddPlayer(plr, team); //create score and add it to map, default values are set in constructor BattleGroundWGScore* sc = new BattleGroundWGScore; @@ -388,7 +391,7 @@ return; uint32 SpellId = 0;- uint64 buff_guid = 0;+ GameObject* buff_guid = 0; switch(Trigger) { case 3686: // Alliance elixir of speed spawn. Trigger not working, because located inside other areatrigger, can be replaced by IsWithinDist(object, dist) in BattleGround::Update().@@ -432,7 +435,7 @@ if(buff_guid) {- GameObject *obj = HashMapHolder<GameObject>::Find(buff_guid);+ GameObject *obj = buff_guid; if(obj) { if(!obj->isSpawned())@@ -504,11 +507,13 @@ m_TeamScores[BG_TEAM_ALLIANCE] = 0; m_TeamScores[BG_TEAM_HORDE] = 0; +/* do not do this here, useless anyway if(m_BgCreatures[WS_SPIRIT_MAIN_ALLIANCE]) DelCreature(WS_SPIRIT_MAIN_ALLIANCE); if(m_BgCreatures[WS_SPIRIT_MAIN_HORDE]) DelCreature(WS_SPIRIT_MAIN_HORDE);+*/ } void BattleGroundWS::HandleKillPlayer(Player *player, Player *killer)Index: src/game/BattleGroundWS.h===================================================================--- src/game/BattleGroundWS.h (revision 5306)+++ src/game/BattleGroundWS.h (working copy)@@ -122,7 +122,7 @@ void Update(time_t diff); /* inherited from BattlegroundClass */- virtual void AddPlayer(Player *plr);+ virtual void AddPlayer(Player *plr, uint32 team = 0); /* BG Flags */ uint64 GetAllianceFlagPickerGUID() const { return m_FlagKeepers[BG_TEAM_ALLIANCE]; }Index: src/game/Chat.cpp===================================================================--- src/game/Chat.cpp (revision 5306)+++ src/game/Chat.cpp (working copy)@@ -387,6 +387,7 @@ { "cast", SEC_ADMINISTRATOR, &ChatHandler::HandleCastCommand, "", NULL }, { "castback", SEC_ADMINISTRATOR, &ChatHandler::HandleCastBackCommand, "", NULL }, { "casttarget", SEC_ADMINISTRATOR, &ChatHandler::HandleCastTargetCommand, "", NULL },+ { "flusharenapoints", SEC_ADMINISTRATOR, &ChatHandler::HandleFlushArenaPointsCommand, "", NULL }, //! Development Commands { "setvalue", SEC_ADMINISTRATOR, &ChatHandler::HandleSetValue, "", NULL },Index: src/game/Chat.h===================================================================--- src/game/Chat.h (revision 5306)+++ src/game/Chat.h (working copy)@@ -329,6 +329,7 @@ bool HandleCastCommand(const char *args); bool HandleCastBackCommand(const char *args); bool HandleCastTargetCommand(const char *args);+ bool HandleFlushArenaPointsCommand(const char *args); //! Development Commands bool HandleSetValue(const char* args);Index: src/game/ItemPrototype.h===================================================================--- src/game/ItemPrototype.h (revision 5306)+++ src/game/ItemPrototype.h (working copy)@@ -536,7 +536,7 @@ uint32 socketBonus; // id from SpellItemEnchantment.dbc uint32 GemProperties; // id from GemProperties.dbc uint32 ExtendedCost; // id from ItemExtendedCost.dbc- uint32 RequiredArenaRank;+ uint32 RequiredArenaRank; // id from ItemCondExtCosts.dbc // note: this field should be renamed accordingly uint32 RequiredDisenchantSkill; float ArmorDamageModifier; char* ScriptName;Index: src/game/Language.h===================================================================--- src/game/Language.h (revision 5306)+++ src/game/Language.h (working copy)@@ -528,6 +528,13 @@ LANG_PLAYER_AFK = 708, LANG_PLAYER_DND_DEFAULT = 709, LANG_PLAYER_AFK_DEFAULT = 710,++ LANG_BG_GROUP_TOO_LARGE = 7007, // "Your group is too large for this battleground. Please regroup to join."+ LANG_ARENA_GROUP_TOO_LARGE = 7008, // "Your group is too large for this arena. Please regroup to join."+ LANG_ARENA_YOUR_TEAM_ONLY = 7009, // "Your group has members not in your arena team. Please regroup to join."+ LANG_ARENA_NOT_ENOUGH_PLAYERS = 7010, // "Your group does not have enough players to join this match."+ LANG_ARENA_GOLD_WINS = 7011, // "The Gold Team wins!"+ LANG_ARENA_GREEN_WINS = 7012 // "The Green Team wins!" }; /* NOT USED VALUESIndex: src/game/Level3.cpp===================================================================--- src/game/Level3.cpp (revision 5306)+++ src/game/Level3.cpp (working copy)@@ -42,6 +42,7 @@ #include "SkillExtraItems.h" #include "SystemConfig.h" #include "Config/ConfigEnv.h"+#include "BattleGroundMgr.h" //reload commands bool ChatHandler::HandleReloadCommand(const char* arg)@@ -4673,3 +4674,9 @@ return true; }++bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/)+{+ sBattleGroundMgr.DistributeArenaPoints();+ return true;+}Index: src/game/Map.cpp===================================================================--- src/game/Map.cpp (revision 5306)+++ src/game/Map.cpp (working copy)@@ -271,6 +271,10 @@ else i_data = NULL; + // flags if gridunloading is enabled / disabled on this map+ // needed, because bg objects aren't in the db, but added in runtime, and unloading the grids would destroy them+ i_unloadmap = sWorld.getConfig(CONFIG_GRID_UNLOAD);+ i_Players.clear(); } @@ -393,7 +397,7 @@ Guard guard(*this); if(!getNGrid(p.x_coord, p.y_coord)) {- setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, sWorld.getConfig(CONFIG_GRID_UNLOAD)),+ setNGrid(new NGridType(p.x_coord*MAX_NUMBER_OF_GRIDS + p.y_coord, p.x_coord, p.y_coord, i_gridExpiry, i_unloadmap), p.x_coord, p.y_coord); // build a linkage between this map and NGridType@@ -725,8 +729,9 @@ { // Don't unload grids if it's battleground, since we may have manually added GOs,creatures, those doesn't load from DB at grid re-load ! // This isn't really bother us, since as soon as we have instanced BG-s, the whole map unloads as the BG gets ended- if ((i_id == 489) || (i_id == 529)) // WS, AB- return;+ // no longer needed, the unloadmap flag will prevent unloading bg map grids+ // if ((i_id == 489) || (i_id == 529)) // WS, AB+ // return; for (GridRefManager<NGridType>::iterator i = GridRefManager<NGridType>::begin(); i != GridRefManager<NGridType>::end(); ) {Index: src/game/Map.h===================================================================--- src/game/Map.h (revision 5306)+++ src/game/Map.h (working copy)@@ -149,6 +149,8 @@ bool GetUnloadFlag(const GridPair &p) const { return getNGrid(p.x_coord, p.y_coord)->getUnloadFlag(); } void SetUnloadFlag(const GridPair &p, bool unload) { getNGrid(p.x_coord, p.y_coord)->setUnloadFlag(unload); }+ void SetUnloadMap(bool unload){ i_unloadmap = unload; }+ bool GetUnloadMap() const { return i_unloadmap; } void LoadGrid(const Cell& cell, bool no_unload = false); bool UnloadGrid(const uint32 &x, const uint32 &y, bool pForce); virtual void UnloadAll(bool pForce);@@ -207,7 +209,7 @@ bool CanEnter(Player* player) const; const char* GetMapName() const; - bool Instanceable() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID))); }+ bool Instanceable() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID) || (i_mapEntry->map_type == MAP_BATTLEGROUND) || (i_mapEntry->map_type == MAP_ARENA))); } // NOTE: this duplicate of Instanceable(), but Instanceable() can be changed when BG also will be instanceable bool IsDungeon() const { return(i_mapEntry && ((i_mapEntry->map_type == MAP_INSTANCE) || (i_mapEntry->map_type == MAP_RAID))); } bool IsRaid() const { return(i_mapEntry && (i_mapEntry->map_type == MAP_RAID)); }@@ -295,6 +297,7 @@ uint32 i_resetDelayTime; uint32 i_InstanceId; uint32 i_maxPlayers;+ bool i_unloadmap; InstanceData* i_data; std::string i_script; Index: src/game/MapInstanced.cpp===================================================================--- src/game/MapInstanced.cpp (revision 5306)+++ src/game/MapInstanced.cpp (working copy)@@ -44,6 +44,7 @@ { if (i->second->GetPlayersCount() == 0) {+ DEBUG_LOG("reseting instance in update for instance id = %u and map id = %u named %s",this->GetInstanceId(),this->GetId(),this->GetMapName()); i->second->Reset(); // avoid doing ++ on invalid data InstancedMaps::iterator i_old = i;@@ -187,7 +188,7 @@ if (!instantiator && instantiator_online) {- sLog.outDebug("MAPINSTANCED: Player '%s' is not in group, instantiating map for player", player->GetName());+ sLog.outDebug("MAPINSTANCED: Player '%s' is not in group, instantiating map %u for player", player->GetName(), GetId()); instantiator = player; } @@ -230,11 +231,13 @@ // check, if we have to generate new instance if (!instantiator_bound || (InstanceId == 0)) {+ sLog.outDebug("MAPINSTANCED: Generating new instance id"); // yes, new instance id has to be generated InstanceId = MapManager::Instance().GenerateInstanceId(); } else {+ sLog.outDebug("MAPINSTANCED: Instantiator bound, finding map..."); // find map of the designated instance and verify it map = _FindMap(InstanceId); }@@ -242,7 +245,7 @@ // now create the instance CreateInstance(InstanceId, map);-+ sLog.outDebug("MAPINSTANCED::GetInstance() Instance Created"); // we do need to bind instance, if the instance we use is valid, not temporary if (player->m_InstanceValid) {@@ -304,6 +307,7 @@ // map for the instance is present, but the instance itself is no more valid, destroy map Guard guard(*this); + DEBUG_LOG("reseting instance in createinstance for instance id = %u and map id = %u named %s",this->GetInstanceId(),this->GetId(),this->GetMapName()); map->Reset(); m_InstancedMaps.erase(InstanceId); delete map;@@ -314,10 +318,13 @@ // verify, if we have the map created, and create it if needed if (!map) {+ sLog.outDebug("MAPINSTANCED: CreateInstance, map not found, creating it"); // map does not exist, create it Guard guard(*this); map = new Map(GetId(), GetGridExpiry(), InstanceId);+ // set the unload map flag according to the base map's flag+ map->SetUnloadMap(GetUnloadMap()); m_InstancedMaps[InstanceId] = map; } }Index: src/game/MapManager.cpp===================================================================--- src/game/MapManager.cpp (revision 5306)+++ src/game/MapManager.cpp (working copy)@@ -104,7 +104,7 @@ Guard guard(*this); const MapEntry* entry = sMapStore.LookupEntry(id);- if (entry && ((entry->map_type == MAP_INSTANCE) || (entry->map_type == MAP_RAID)))+ if (entry && ((entry->map_type == MAP_INSTANCE) || (entry->map_type == MAP_RAID) || (entry->map_type == MAP_BATTLEGROUND) || (entry->map_type == MAP_ARENA))) { m = new MapInstanced(id, i_gridCleanUpDelay, 0); }Index: src/game/MovementHandler.cpp===================================================================--- src/game/MovementHandler.cpp (revision 5306)+++ src/game/MovementHandler.cpp (working copy)@@ -93,17 +93,21 @@ { if(bg->GetMapId() == _player->GetMapId()) // we teleported to bg {- if(!bg->GetBgRaid(_player->GetTeam())) // first player joined+ // get the team this way, because arenas might 'override' the teams.+ uint32 team = bg->GetPlayerTeam(_player->GetGUID());+ if(!team)+ team = _player->GetTeam();+ if(!bg->GetBgRaid(team)) // first player joined { Group *group = new Group;- bg->SetBgRaid(_player->GetTeam(), group);+ bg->SetBgRaid(team, group); group->ConvertToRaid(); group->AddMember(_player->GetGUID(), _player->GetName()); group->ChangeLeader(_player->GetGUID()); } else // raid already exist {- bg->GetBgRaid(_player->GetTeam())->AddMember(_player->GetGUID(), _player->GetName());+ bg->GetBgRaid(team)->AddMember(_player->GetGUID(), _player->GetName()); } } }@@ -504,3 +508,11 @@ _player->SummonIfPossible(); } ++++++++Index: src/game/ObjectMgr.cpp===================================================================--- src/game/ObjectMgr.cpp (revision 5306)+++ src/game/ObjectMgr.cpp (working copy)@@ -1340,6 +1340,10 @@ if(proto->ExtendedCost && !sItemExtendedCostStore.LookupEntry(proto->ExtendedCost)) sLog.outErrorDb("Item (Entry: %u) has wrong ExtendedCost (%u)",i,proto->ExtendedCost); + // check if the extended cost and the required arena rank pair is valid (does it have entry in ItemCondExtCosts.dbc?)+ if(proto->ExtendedCost && proto->RequiredArenaRank && !GetItemCondExtCostsMask(proto->RequiredArenaRank, proto->ExtendedCost))+ sLog.outErrorDb("Item (Entry: %u) has wrong ExtendedCost - RequiredArenaRank pair (%u, %u)",i,proto->ExtendedCost,proto->RequiredArenaRank);+ if(proto->FoodType >= MAX_PET_DIET) { sLog.outErrorDb("Item (Entry: %u) has wrong FoodType value (%u)",i,proto->FoodType);Index: src/game/PetitionsHandler.cpp===================================================================--- src/game/PetitionsHandler.cpp (revision 5306)+++ src/game/PetitionsHandler.cpp (working copy)@@ -49,9 +49,6 @@ { CHECK_PACKET_SIZE(recv_data, 8+8+4+1+5*8+2+1+4+4); - if(_player->GetGuildId())- return;- sLog.outDebug("Received opcode CMSG_PETITION_BUY"); //recv_data.hexlike(); @@ -95,6 +92,11 @@ uint32 type = 0; if(pCreature->isTabardDesigner()) {+ // if tabard designer, then trying to buy a guild charter.+ // do not let if already in guild.+ if(_player->GetGuildId())+ return;+ charterid = GUILD_CHARTER; cost = GUILD_CHARTER_COST; type = 9;@@ -102,7 +104,7 @@ else { // TODO: find correct opcode- if(_player->getLevel() != 70)+ if(_player->getLevel() < 70) { SendNotification(objmgr.GetMangosString(LANG_ARENA_ONE_TOOLOW, GetSessionLocaleIndex()), 70); return;@@ -188,10 +190,31 @@ charter->SetState(ITEM_CHANGED, _player); _player->SendNewItem(charter, 1, true, false); + // a petition is invalid, if both the owner and the type matches+ QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE ownerguid = '%u' AND type = '%u'", _player->GetGUIDLow(), type);++ std::ostringstream ssInvalidPetitionGUIDs;++ if (result)+ {++ do+ {+ Field *fields = result->Fetch();+ ssInvalidPetitionGUIDs << "'" << fields[0].GetUInt32() << "' , ";+ } while (result->NextRow());++ delete result;+ }++ // delete petitions with the same guid as this one+ ssInvalidPetitionGUIDs << "'" << charter->GetGUIDLow() << "'";++ sLog.outDebug("Invalid petition GUIDs: %s", ssInvalidPetitionGUIDs.str().c_str()); CharacterDatabase.escape_string(name); CharacterDatabase.BeginTransaction();- CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u' OR petitionguid = '%u' and type = '%u'", _player->GetGUIDLow(), charter->GetGUIDLow(),type);- CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u' or petitionguid = '%u'", _player->GetGUIDLow(), charter->GetGUIDLow());+ CharacterDatabase.PExecute("DELETE FROM petition WHERE petitionguid IN ( %s )", ssInvalidPetitionGUIDs.str().c_str());+ CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE petitionguid IN ( %s )", ssInvalidPetitionGUIDs.str().c_str()); CharacterDatabase.PExecute("INSERT INTO petition (ownerguid, petitionguid, name, type) VALUES ('%u', '%u', '%s', '%u')", _player->GetGUIDLow(), charter->GetGUIDLow(), name.c_str(), type); CharacterDatabase.CommitTransaction();@@ -205,9 +228,6 @@ sLog.outDebug("Received opcode CMSG_PETITION_SHOW_SIGNATURES"); //recv_data.hexlike(); - if(_player->GetGuildId())- return;- uint8 signs = 0; uint64 petitionguid; recv_data >> petitionguid; // petition guid@@ -215,14 +235,18 @@ // solve (possible) some strange compile problems with explicit use GUID_LOPART(petitionguid) at some GCC versions (wrong code optimization in compiler?) uint32 petitionguid_low = GUID_LOPART(petitionguid); - QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid FROM petition WHERE petitionguid = '%u'", petitionguid_low);+ QueryResult *result = CharacterDatabase.PQuery("SELECT petitionguid, type FROM petition WHERE petitionguid = '%u'", petitionguid_low); if(!result) { sLog.outError("any petition on server..."); return; }-+ Field *fields = result->Fetch();+ uint32 type = fields[1].GetUInt32(); delete result;+ // if guild petition and has guild => error, return;+ if(type==9 && _player->GetGuildId())+ return; result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE petitionguid = '%u'", petitionguid_low); @@ -317,13 +341,14 @@ { data << uint32(9); data << uint32(9);+ data << uint32(0); // bypass client - side limitation, a different value is needed here for each petition } else { data << type-1; data << type-1;+ data << type; // bypass client - side limitation, a different value is needed here for each petition }- data << uint32(0); // 4 data << uint32(0); // 5 data << uint32(0); // 6 data << uint32(0); // 7@@ -457,13 +482,20 @@ return; } + if(type != 9 && _player->getLevel() < 70)+ {+ // player is too low level to join an arena team+ SendNotification("You must be level 70 to join an arena team!");+ return;+ }+ signs += 1; if(signs > type) // client signs maximum return; //client doesn't allow to sign petition two times by one character, but not check sign by another character from same account //not allow sign another player from already sign player account- result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u'", GetAccountId());+ result = CharacterDatabase.PQuery("SELECT playerguid FROM petition_sign WHERE player_account = '%u' AND petitionguid = '%u'", GetAccountId(), GUID_LOPART(petitionguid)); if(result) {@@ -638,16 +670,29 @@ } else {- for(uint8 i = 0; i < 3; i++)+ uint32 type_slot;+ switch(type) {- if(_player->GetArenaTeamId(i))- {+ case ARENA_TEAM_2v2:+ type_slot = 0;+ break;+ case ARENA_TEAM_3v3:+ type_slot = 1;+ break;+ case ARENA_TEAM_5v5:+ type_slot = 2;+ break;+ default:+ type_slot = 0;+ break;+ }+ if(_player->GetArenaTeamId(type_slot))+ { //data.Initialize(SMSG_TURN_IN_PETITION_RESULTS, 4); //data << (uint32)PETITION_TURN_ALREADY_IN_GUILD; // already in guild //_player->GetSession()->SendPacket(&data); SendArenaTeamCommandResult(ERR_ARENA_TEAM_CREATE_S, name, "", ERR_ALREADY_IN_ARENA_TEAM); return;- } } } @@ -735,6 +780,7 @@ ArenaTeam* at = new ArenaTeam; if(!at->create(_player->GetGUID(), type, name)) {+ sLog.outError("PetitionsHandler: arena team create failed."); delete at; delete result; return;@@ -748,11 +794,13 @@ // register team and add captain objmgr.AddArenaTeam(at);+ sLog.outDebug("PetitonsHandler: arena team added to objmrg"); // add members for(uint8 i = 0; i < signs; ++i) { Field* fields = result->Fetch();+ sLog.outDebug("PetitionsHandler: adding arena member %u", fields[0].GetUInt64()); at->AddMember(fields[0].GetUInt64()); result->NextRow(); }@@ -820,21 +868,21 @@ data << uint32(ARENA_TEAM_CHARTER_2v2); // charter entry data << uint32(16161); // charter display id data << uint32(ARENA_TEAM_CHARTER_2v2_COST); // charter cost- data << uint32(0); // unknown+ data << uint32(2); // unknown data << uint32(2); // required signs? // 3v3 data << uint32(2); // index data << uint32(ARENA_TEAM_CHARTER_3v3); // charter entry data << uint32(16161); // charter display id data << uint32(ARENA_TEAM_CHARTER_3v3_COST); // charter cost- data << uint32(0); // unknown+ data << uint32(3); // unknown data << uint32(3); // required signs? // 5v5 data << uint32(3); // index data << uint32(ARENA_TEAM_CHARTER_5v5); // charter entry data << uint32(16161); // charter display id data << uint32(ARENA_TEAM_CHARTER_5v5_COST); // charter cost- data << uint32(0); // unknown+ data << uint32(5); // unknown data << uint32(5); // required signs? } //for(uint8 i = 0; i < count; i++)Index: src/game/Player.cpp===================================================================--- src/game/Player.cpp (revision 5306)+++ src/game/Player.cpp (working copy)@@ -1252,8 +1252,8 @@ bool state = HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); - // afk player not allowed in battleground- if(state && InBattleGround())+ // afk player not allowed in battleground ( do net check this in arena )+ if(state && InBattleGround() && GetBattleGround() && GetBattleGround()->isBattleGround()) LeaveBattleground(); return state;@@ -1436,7 +1436,7 @@ sLog.outDebug( "WORLD: Sent (SMSG_IGNORE_LIST)" ); } -void Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange, bool ignore_transport, bool is_gm_command)+void Player::TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange, bool ignore_transport, bool is_gm_command, bool battleground_port) { // preparing unsummon pet if lost (we must get pet before teleportation or will not find it later) Pet* pet = GetPet();@@ -1596,7 +1596,8 @@ Map* map = MapManager::Instance().GetMap(mapid, this); // verify, if it does want to homebind us (but only if we are not in GM state, // GMs are allowed to teleport everywhere they want to be)- if (!m_InstanceValid && (!isGameMaster() || !is_gm_command))+ // battlegrounds do NOT homebind+ if (!m_InstanceValid && (!isGameMaster() || !is_gm_command) && !battleground_port) { // yes, we are going to be homebind, avoid this action :) SetInstanceId(0); // reset instance id@@ -2727,6 +2728,32 @@ removeSpell(itr->second.spell); } +void Player::RemoveArenaSpellCooldowns()+{+ // remove cooldowns on spells that has < 15 min CD+ SpellCooldowns::iterator itr, next;+ // iterate spell cooldowns+ for(itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); itr = next)+ {+ next = itr;+ ++next;+ SpellEntry const * entry = sSpellStore.LookupEntry(itr->first);+ // check if spellentry is present and if the cooldown is less than 15 mins+ if( entry && + (entry->RecoveryTime <= 15 * 60000) &&+ (entry->CategoryRecoveryTime <= 15 * 60000))+ {+ // notify player+ WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8+4));+ data << uint32(itr->first);+ data << GetGUID();+ GetSession()->SendPacket(&data);+ // remove cooldown+ m_spellCooldowns.erase(itr);+ }+ }+}+ void Player::RemoveAllSpellCooldown() { if(!m_spellCooldowns.empty())@@ -5538,6 +5565,10 @@ uint32 now = time(NULL); UpdateHonorFields(); + // do not reward honor in arenas+ if(InBattleGround() && GetBattleGround() && GetBattleGround()->isArena())+ return false;+ if(honor <= 0) { if(!uVictim || uVictim == this || uVictim->GetAura(2479, 0))@@ -5659,27 +5690,33 @@ return 0; } -uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 slot)+uint32 Player::GetArenaTeamIdFromDB(uint64 guid, uint8 type) { // need fix it! QueryResult *result = CharacterDatabase.PQuery("SELECT arenateamid FROM arena_team_member WHERE guid='%u'", GUID_LOPART(guid)); if(result) {- uint32 id = (*result)[0].GetUInt32();+ // init id to 0, check the arena type before assigning a value to id+ uint32 id = 0; do { QueryResult *result2 = CharacterDatabase.PQuery("SELECT type FROM arena_team WHERE arenateamid='%u'", id); if(result2) {- uint8 dbslot = (*result2)[0].GetUInt32();+ uint8 dbtype = (*result2)[0].GetUInt32(); delete result2;- if(dbslot == slot)+ if(dbtype == type)+ {+ // if the type matches, we've found the id+ id = (*result)[0].GetUInt32(); break;+ } } } while(result->NextRow()); delete result; return id; }+ // no arenateam for the specified guid, return 0 return 0; } @@ -8725,6 +8762,13 @@ pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC) return EQUIP_ERR_NOT_IN_COMBAT; + // do not allow gear change during in-progress arena matches, only weapons / offhands / relics / ammo+ if( InBattleGround() && GetBattleGround() && GetBattleGround()->isArena() && + (GetBattleGround()->GetStatus() == STATUS_IN_PROGRESS) &&+ (pProto->Class != ITEM_CLASS_WEAPON) && (pProto->Class != ITEM_CLASS_PROJECTILE) &&+ (pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD) && (pProto->InventoryType != INVTYPE_RELIC))+ return EQUIP_ERR_NOT_DURING_ARENA_MATCH;+ if(isInCombat()&& pProto->Class == ITEM_CLASS_WEAPON && m_weaponChangeTimer != 0) return EQUIP_ERR_CANT_DO_RIGHT_NOW; // maybe exist better err @@ -8853,6 +8897,13 @@ pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC ) return EQUIP_ERR_NOT_IN_COMBAT; + // do not allow unequipping gear in in-progress arenas, except weapons, offhands, projectiles, relics+ if( InBattleGround() && GetBattleGround() && GetBattleGround()->isArena() && + (GetBattleGround()->GetStatus() == STATUS_IN_PROGRESS) &&+ (pProto->Class != ITEM_CLASS_WEAPON) && (pProto->Class != ITEM_CLASS_PROJECTILE) &&+ (pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD) && (pProto->InventoryType != INVTYPE_RELIC))+ return EQUIP_ERR_NOT_DURING_ARENA_MATCH;+ if(!swap && pItem->IsBag() && !((Bag*)pItem)->IsEmpty()) return EQUIP_ERR_CAN_ONLY_DO_WITH_EMPTY_BAGS; @@ -9887,6 +9938,54 @@ } } +void Player::DestroyConjuredItems( bool update )+{+ // used when entering arena+ // distroys all conjured items+ sLog.outDebug( "STORAGE: DestroyConjuredItems" );++ // in inventory+ for(int i = INVENTORY_SLOT_ITEM_START; i < INVENTORY_SLOT_ITEM_END; i++)+ {+ Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );+ if( pItem && pItem->GetProto() &&+ (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && + (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);+ }++ // in inventory bags+ for(int i = INVENTORY_SLOT_BAG_START; i < INVENTORY_SLOT_BAG_END; i++)+ {+ Bag* pBag = (Bag*)GetItemByPos( INVENTORY_SLOT_BAG_0, i );+ if( pBag )+ {+ ItemPrototype const *pBagProto = pBag->GetProto();+ if( pBagProto )+ {+ for(uint32 j = 0; j < pBagProto->ContainerSlots; j++)+ {+ Item* pItem = pBag->GetItemByPos(j);+ if( pItem && pItem->GetProto() &&+ (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && + (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )+ DestroyItem( i, j, update);+ }+ }+ }+ }++ // in equipment and bag list+ for(int i = EQUIPMENT_SLOT_START; i < INVENTORY_SLOT_BAG_END; i++)+ {+ Item* pItem = GetItemByPos( INVENTORY_SLOT_BAG_0, i );+ if( pItem && pItem->GetProto() &&+ (pItem->GetProto()->Class == ITEM_CLASS_CONSUMABLE) && + (pItem->GetProto()->Flags & ITEM_FLAGS_CONJURED) )+ DestroyItem( INVENTORY_SLOT_BAG_0, i, update);+ }+}+ void Player::DestroyItemCount( Item* pItem, uint32 &count, bool update ) { if(!pItem)@@ -14894,11 +14993,15 @@ void Player::RemovePetitionsAndSigns(uint64 guid, uint32 type) {- QueryResult *result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid));+ QueryResult *result = NULL;+ if(type==10)+ result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid));+ else+ result = CharacterDatabase.PQuery("SELECT ownerguid,petitionguid FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); if(result) {- do- {+ do // this part effectively does nothing, since the deletion / modification only takes place _after_ the PetitionQuery. Though I don't know if the result remains intact if I execute the delete query beforehand.+ { // and SendPetitionQueryOpcode reads data from the DB Field *fields = result->Fetch(); uint64 ownerguid = MAKE_GUID(fields[0].GetUInt32(), HIGHGUID_PLAYER); uint64 petitionguid = MAKE_GUID(fields[1].GetUInt32(), HIGHGUID_ITEM);@@ -14912,15 +15015,23 @@ delete result; - CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid));+ if(type==10)+ CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u'", GUID_LOPART(guid));+ else+ CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE playerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type); } CharacterDatabase.BeginTransaction(); if(type == 10)+ { CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u'", GUID_LOPART(guid));+ CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u'", GUID_LOPART(guid));+ } else+ { CharacterDatabase.PExecute("DELETE FROM petition WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type);- CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u'", GUID_LOPART(guid));+ CharacterDatabase.PExecute("DELETE FROM petition_sign WHERE ownerguid = '%u' AND type = '%u'", GUID_LOPART(guid), type);+ } CharacterDatabase.CommitTransaction(); } @@ -15280,6 +15391,9 @@ if(pProto->ExtendedCost) { ItemExtendedCostEntry const* iece = sItemExtendedCostStore.LookupEntry(pProto->ExtendedCost);+ uint32 mask = 0;+ if(pProto->RequiredArenaRank)+ mask = GetItemCondExtCostsMask(pProto->RequiredArenaRank, pProto->ExtendedCost); if(iece) { if(GetHonorPoints() < (iece->reqhonorpoints * count))@@ -15299,6 +15413,13 @@ SendEquipError(EQUIP_ERR_VENDOR_MISSING_TURNINS, NULL, NULL); return false; }+ // check for personal arena rating requirement+ if( (mask & (1<<3)) && (GetMaxPersonalArenaRatingRequirement() < iece->reqpersonalarenarating) )+ {+ // probably not the proper equip err+ SendEquipError(EQUIP_ERR_CANT_EQUIP_RANK,NULL,NULL);+ return false;+ } } else {@@ -15434,6 +15555,26 @@ return false; } +uint32 Player::GetMaxPersonalArenaRatingRequirement()+{+ // returns the maximal personal arena rating that can be used to purchase items requiring this condition+ // the personal rating of the arena team must match the required limit as well+ // so return max[in arenateams](min(personalrating[teamtype], teamrating[teamtype]))+ uint32 max_personal_rating = 0;+ for(int i = 0; i < 3; ++i)+ {+ if(ArenaTeam * at = objmgr.GetArenaTeamById(GetArenaTeamId(i)))+ {+ uint32 p_rating = GetUInt32Value(PLAYER_FIELD_ARENA_TEAM_INFO_1_1 + (i * 6) + 5);+ uint32 t_rating = at->GetRating();+ p_rating = p_rating<t_rating? p_rating : t_rating;+ if(max_personal_rating < p_rating)+ max_personal_rating = p_rating;+ }+ }+ return max_personal_rating;+}+ void Player::_SaveBoundInstances() { CharacterDatabase.PExecute("DELETE FROM character_instance WHERE (guid = '%u')", GetGUIDLow());@@ -16163,7 +16304,8 @@ bool Player::GetBGAccessByLevel(uint32 bgTypeId) const {- BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);+ // get a template bg instead of running one+ BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); if(!bg) return false; Index: src/game/Player.h===================================================================--- src/game/Player.h (revision 5306)+++ src/game/Player.h (working copy)@@ -860,7 +860,7 @@ void AddToWorld(); void RemoveFromWorld(); - void TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange = true, bool ignore_transport = true, bool is_gm_command = false);+ void TeleportTo(uint32 mapid, float x, float y, float z, float orientation, bool outofrange = true, bool ignore_transport = true, bool is_gm_command = false, bool battleground_port = false); void SetSummonPoint(uint32 mapid, float x, float y, float z) {@@ -1039,6 +1039,7 @@ void DestroyItem( uint8 bag, uint8 slot, bool update ); void DestroyItemCount( uint32 item, uint32 count, bool update, bool unequip_check = false); void DestroyItemCount( Item* item, uint32& count, bool update );+ void DestroyConjuredItems( bool update ); void DestroyZoneLimitedItem( bool update, uint32 new_zone ); void SplitItem( uint16 src, uint16 dst, uint32 count ); void SwapItem( uint16 src, uint16 dst );@@ -1350,6 +1351,7 @@ void AddSpellCooldown(uint32 spell_id, uint32 itemid, time_t end_time); void ProhibitSpellScholl(SpellSchools idSchool, uint32 unTimeMs ); void RemoveSpellCooldown(uint32 spell_id) { m_spellCooldowns.erase(spell_id); }+ void RemoveArenaSpellCooldowns(); void RemoveAllSpellCooldown(); void _LoadSpellCooldowns(QueryResult *result); void _SaveSpellCooldowns();@@ -1598,6 +1600,7 @@ bool RewardHonor(Unit *pVictim, uint32 groupsize, float honor = -1); uint32 GetHonorPoints() { return GetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY); } uint32 GetArenaPoints() { return GetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY); }+ uint32 GetMaxPersonalArenaRatingRequirement(); void SetHonorPoints(uint32 val) { SetUInt32Value(PLAYER_FIELD_HONOR_CURRENCY, val); } void SetArenaPoints(uint32 val) { SetUInt32Value(PLAYER_FIELD_ARENA_CURRENCY, val); } void SetFlushKills(bool value) { m_flushKills = value; }@@ -1715,9 +1718,11 @@ float GetBattleGroundEntryPointY() const { return m_bgEntryPointY; } float GetBattleGroundEntryPointZ() const { return m_bgEntryPointZ; } float GetBattleGroundEntryPointO() const { return m_bgEntryPointO; }- void SetBattleGroundEntryPoint(uint32 Map, float PosX, float PosY, float PosZ, float PosO )+ uint32 GetBattleGroundEntryPointInstanceId() const { return m_bgEntryPointInstanceId; }+ void SetBattleGroundEntryPoint(uint32 Map, uint32 InstanceId, float PosX, float PosY, float PosZ, float PosO ) { m_bgEntryPointMap = Map;+ m_bgEntryPointInstanceId = InstanceId; m_bgEntryPointX = PosX; m_bgEntryPointY = PosY; m_bgEntryPointZ = PosZ;@@ -1864,6 +1869,7 @@ */ uint32 m_bgBattleGroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES]; uint32 m_bgEntryPointMap;+ uint32 m_bgEntryPointInstanceId; float m_bgEntryPointX; float m_bgEntryPointY; float m_bgEntryPointZ;Index: src/game/Spell.cpp===================================================================--- src/game/Spell.cpp (revision 5306)+++ src/game/Spell.cpp (working copy)@@ -2454,12 +2454,20 @@ Player* p_caster = (Player*)m_caster; + // if arena preparation is on, don't take soul shards+ bool bArenaPrep = p_caster->HasAura(SPELL_ARENA_PREPARATION, 0);+ for(uint32 x=0;x<8;x++) { if(m_spellInfo->Reagent[x] <= 0) continue; uint32 itemid = m_spellInfo->Reagent[x];++ // don't take soul shards if arena prep is on+ if(bArenaPrep && (itemid == 6265))+ continue;+ uint32 itemcount = m_spellInfo->ReagentCount[x]; // if CastItem is also spell reagent@@ -2675,6 +2683,15 @@ if((m_spellInfo->AttributesEx3 & 0x800) != 0) return SPELL_FAILED_ONLY_BATTLEGROUNDS; + // do not allow spells with greater than 15 min CD to be cast in arenas+ if( m_caster->GetTypeId() == TYPEID_PLAYER && + ((Player*)m_caster)->InBattleGround() && + ((Player*)m_caster)->GetBattleGround() && + ((Player*)m_caster)->GetBattleGround()->isArena() &&+ (m_spellInfo->RecoveryTime > 15 * 60000 ||+ m_spellInfo->CategoryRecoveryTime > 15 * 60000) )+ return SPELL_FAILED_NOT_IN_ARENA;+ // zone check uint32 zone_id = m_caster->GetZoneId(); @@ -3626,6 +3643,9 @@ focusObject = ok; // game object found in range } + // check if arena prep is up+ bool bArenaPrep = p_caster->HasAura(SPELL_ARENA_PREPARATION, 0);+ for(uint32 i=0;i<8;i++) { if(m_spellInfo->Reagent[i] <= 0)@@ -3633,26 +3653,36 @@ itemid = m_spellInfo->Reagent[i]; itemcount = m_spellInfo->ReagentCount[i];- - // if CastItem is also spell reagent- if( m_CastItem && m_CastItem->GetEntry() == itemid )++ if( m_CastItem ) {- ItemPrototype const *proto = m_CastItem->GetProto();- if(!proto)- return SPELL_FAILED_ITEM_NOT_READY;- for(int s=0;s<5;s++)+ // if CastItem is also spell reagent+ if( m_CastItem->GetEntry() == itemid ) {- // CastItem will be used up and does not count as reagent- int32 charges = m_CastItem->GetSpellCharges(s);- if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)+ ItemPrototype const *proto = m_CastItem->GetProto();+ if(!proto)+ return SPELL_FAILED_ITEM_NOT_READY;+ for(int s=0;s<5;s++) {- itemcount++;- break;+ // CastItem will be used up and does not count as reagent+ int32 charges = m_CastItem->GetSpellCharges(s);+ if (proto->Spells[s].SpellCharges < 0 && abs(charges) < 2)+ {+ itemcount++;+ break;+ } } }+ if( !p_caster->HasItemCount(itemid,itemcount) )+ return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54 }- if( !p_caster->HasItemCount(itemid,itemcount) )- return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54+ // if arena preparation is up, don't take soul shards, but take other reagents+ // this cannot happen in case of a m_CastItem, so it's enough to check here+ else if (!bArenaPrep || itemid != 6265)+ {+ if( !p_caster->HasItemCount(itemid,itemcount) )+ return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54+ } } uint32 totems = 2;Index: src/game/SpellHandler.cpp===================================================================--- src/game/SpellHandler.cpp (revision 5306)+++ src/game/SpellHandler.cpp (working copy)@@ -66,6 +66,15 @@ return; } + // only allow conjured consumable, bandage+ if ( pUser->InBattleGround() && pUser->GetBattleGround() && pUser->GetBattleGround()->isArena()+ && (proto->Class == ITEM_CLASS_CONSUMABLE) && !(proto->Flags & ITEM_FLAGS_CONJURED) && !(proto->SubClass == ITEM_SUBCLASS_BANDAGE))+ {+ //send use error: not in arena+ pUser->SendEquipError(EQUIP_ERR_NOT_DURING_ARENA_MATCH,pItem,NULL);+ return;+ }+ if (pUser->isInCombat()) { for(int i = 0; i < 5; ++i)@@ -468,7 +477,8 @@ if(((BattleGroundWS*)bg)->GetFlagState(ALLIANCE) != BG_WS_FLAG_STATE_ON_BASE) return; // check if it's correct flag- if(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_A_FLAG] != obj->GetGUID())+ if(!(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_A_FLAG]) ||+ (((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_A_FLAG]->GetGUID() != obj->GetGUID())) return; // check player team if(_player->GetTeam() == ALLIANCE)@@ -483,7 +493,8 @@ if(((BattleGroundWS*)bg)->GetFlagState(HORDE) != BG_WS_FLAG_STATE_ON_BASE) return; // check if it's correct flag- if(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_H_FLAG] != obj->GetGUID())+ if(!(((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_H_FLAG]) ||+ (((BattleGroundWS*)bg)->m_BgObjects[BG_WS_OBJECT_H_FLAG]->GetGUID() != obj->GetGUID())) return; // check player team if(_player->GetTeam() == HORDE)Index: src/game/Unit.cpp===================================================================--- src/game/Unit.cpp (revision 5306)+++ src/game/Unit.cpp (working copy)@@ -566,36 +566,6 @@ if (health <= damage) {- // battleground things- if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))- {- Player *killed = ((Player*)pVictim);- Player *killer = NULL;- if(GetTypeId() == TYPEID_PLAYER)- killer = ((Player*)this);- else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())- {- Unit *owner = GetOwner();- if(owner && owner->GetTypeId() == TYPEID_PLAYER)- killer = ((Player*)owner);- }-- if(killer)- {- if(BattleGround *bg = killed->GetBattleGround())- {- bg->HandleKillPlayer(killed, killer); // drop flags and etc- // add +1 deaths- bg->UpdatePlayerScore(killed, SCORE_DEATHS, 1);- if(killer)- // add +1 kills- bg->UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);- // to be able to remove insignia- killed->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );- }- }- }- DEBUG_LOG("DealDamage: victim just died"); DEBUG_LOG("DealDamageAttackStop");@@ -839,6 +809,39 @@ he->DuelComplete(DUEL_INTERUPTED); }++ // battleground things (do this at the end, so the death state flag will be properly set to handle in the bg->handlekill)+ if(pVictim->GetTypeId() == TYPEID_PLAYER && (((Player*)pVictim)->InBattleGround()))+ {+ Player *killed = ((Player*)pVictim);+ Player *killer = NULL;+ if(GetTypeId() == TYPEID_PLAYER)+ killer = ((Player*)this);+ else if(GetTypeId() == TYPEID_UNIT && ((Creature*)this)->isPet())+ {+ Unit *owner = GetOwner();+ if(owner && owner->GetTypeId() == TYPEID_PLAYER)+ killer = ((Player*)owner);+ }++ if(killer)+ {+ if(BattleGround *bg = killed->GetBattleGround())+ {+ bg->HandleKillPlayer(killed, killer); // drop flags and etc+ // add +1 deaths+ bg->UpdatePlayerScore(killed, SCORE_DEATHS, 1);+ if(killer)+ {+ // add +1 kills+ bg->UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);+ bg->UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);+ }+ // to be able to remove insignia+ killed->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );+ }+ }+ } } else // if (health <= damage) {@@ -3900,6 +3903,19 @@ } } +void Unit::RemoveArenaAuras(bool onleave)+{+ // in join, remove positive buffs, on end, remove negative+ // used to remove positive visible auras in arenas+ for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();)+ {+ if (!iter->second->IsPassive() && (iter->second->IsPositive() ^ onleave))+ RemoveAura(iter, true);+ else+ ++iter;+ }+}+ void Unit::RemoveAllAurasOnDeath() { // used just after dieing to remove all visible aurasIndex: src/game/Unit.h===================================================================--- src/game/Unit.h (revision 5306)+++ src/game/Unit.h (working copy)@@ -819,6 +819,7 @@ void RemoveAreaAurasByOthers(uint64 guid = 0); void RemoveAllAuras();+ void RemoveArenaAuras(bool onleave = false); void RemoveAllAurasOnDeath(); void DelayAura(uint32 spellId, uint32 effindex, int32 delaytime); bool SetAurDuration(uint32 spellId, uint32 effindex, uint32 duration);Index: src/game/World.cpp===================================================================--- src/game/World.cpp (revision 5306)+++ src/game/World.cpp (working copy)@@ -491,6 +491,10 @@ m_configs[CONFIG_TALENTS_INSPECTING] = sConfig.GetBoolDefault("TalentsInspecting", true); m_configs[CONFIG_CHAT_FAKE_MESSAGE_PREVENTING] = sConfig.GetBoolDefault("ChatFakeMessagePreventing", false); + m_configs[CONFIG_ARENA_MAX_RATING_DIFFERENCE] = sConfig.GetIntDefault("Arena.MaxRatingDifference", 0);+ m_configs[CONFIG_ARENA_RATING_DISCARD_TIMER] = sConfig.GetIntDefault("Arena.RatingDiscardTimer",300000);+ m_configs[CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS] = sConfig.GetBoolDefault("Arena.AutoDistributePoints", false);+ m_VisibleUnitGreyDistance = sConfig.GetFloatDefault("Visibility.Distance.Grey.Unit", 1); if(m_VisibleUnitGreyDistance > MAX_VISIBILITY_DISTANCE) {@@ -827,6 +831,7 @@ ///- Initialize Battlegrounds sLog.outString( "Starting BattleGround System" ); sBattleGroundMgr.CreateInitialBattleGrounds();+ sBattleGroundMgr.InitAutomaticArenaPointDistribution(); //Not sure if this can be moved up in the sequence (with static data loading) as it uses MapManager sLog.outString( "Loading Transports..." );Index: src/game/World.h===================================================================--- src/game/World.h (revision 5306)+++ src/game/World.h (working copy)@@ -118,6 +118,9 @@ CONFIG_TALENTS_INSPECTING, CONFIG_CHAT_FAKE_MESSAGE_PREVENTING, CONFIG_TCP_NO_DELAY,+ CONFIG_ARENA_MAX_RATING_DIFFERENCE,+ CONFIG_ARENA_RATING_DISCARD_TIMER,+ CONFIG_ARENA_AUTO_DISTRIBUTE_POINTS, CONFIG_VALUE_COUNT }; Index: src/mangosd/mangosd.conf.in===================================================================--- src/mangosd/mangosd.conf.in (revision 5306)+++ src/mangosd/mangosd.conf.in (working copy)@@ -538,3 +538,16 @@ # Default: 0 (false) # 1 (true) Event.Announce = 0++# Rated arena matches config+# MaxRatingDifference: the maximum rating difference between two groups in rated matches+# Default: 0 (disable, rating difference is discarded) +# RatingDiscardTimer: after the specified milliseconds has passed, rating information will be discarded when selecting teams for matches+# also initiates an update by this timer+# Default: 60000+# AutoDistributePoints: set if arena points should be distributed weekly automatically, or by GM command+# Default: 0 (disable) (recommended): use gm command or sql query to distribute the points+# 1 (enable): arena points are distributed automatically+Arena.MaxRatingDifference = 0+Arena.RatingDiscardTimer = 60000+Arena.AutoDistributePoints = 0Index: src/shared/Database/DBCfmt.cpp===================================================================--- src/shared/Database/DBCfmt.cpp (revision 5306)+++ src/shared/Database/DBCfmt.cpp (working copy)@@ -42,7 +42,8 @@ const char GtRegenHPPerSptfmt[]="f"; const char GtRegenMPPerSptfmt[]="f"; const char ItemDisplayTemplateEntryfmt[]="nxxxxxxxxxxixxxxxxxxxxx";-const char ItemExtendedCostEntryfmt[]="niiiiixxiiixxx";+const char ItemCondExtCostsEntryfmt[]="xiii";+const char ItemExtendedCostEntryfmt[]="niiiiixxiiixxi"; const char ItemRandomPropertiesfmt[]="nxiiixxxxxxxxxxxxxxxxxxx"; const char ItemRandomSuffixfmt[]="nxxxxxxxxxxxxxxxxxxiiiiii"; const char ItemSetEntryfmt[]="dssssssssssssssssxxxxxxxxxxxxxxxxxxiiiiiiiiiiiiiiiiii";Index: src/shared/Database/DBCStores.cpp===================================================================--- src/shared/Database/DBCStores.cpp (revision 5306)+++ src/shared/Database/DBCStores.cpp (working copy)@@ -66,6 +66,7 @@ DBCStorage <ItemSetEntry> sItemSetStore(ItemSetEntryfmt); //DBCStorage <ItemDisplayInfoEntry> sItemDisplayInfoStore(ItemDisplayTemplateEntryfmt); -- not used currently+DBCStorage <ItemCondExtCostsEntry> sItemCondExtCostsStore(ItemCondExtCostsEntryfmt); DBCStorage <ItemExtendedCostEntry> sItemExtendedCostStore(ItemExtendedCostEntryfmt); DBCStorage <ItemRandomPropertiesEntry> sItemRandomPropertiesStore(ItemRandomPropertiesfmt); DBCStorage <ItemRandomSuffixEntry> sItemRandomSuffixStore(ItemRandomSuffixfmt);@@ -170,7 +171,7 @@ { std::string tmpPath=""; - const uint32 DBCFilesCount = 48;+ const uint32 DBCFilesCount = 49; barGoLink bar( DBCFilesCount ); @@ -230,6 +231,7 @@ LoadDBC(bar,bad_dbc_files,sGtRegenMPPerSptStore, dataPath+"dbc/gtRegenMPPerSpt.dbc"); //LoadDBC(bar,bad_dbc_files,sItemDisplayInfoStore, dataPath+"dbc/ItemDisplayInfo.dbc"); -- not used currently+ LoadDBC(bar,bad_dbc_files,sItemCondExtCostsStore, dataPath+"dbc/ItemCondExtCosts.dbc"); LoadDBC(bar,bad_dbc_files,sItemExtendedCostStore, dataPath+"dbc/ItemExtendedCost.dbc"); LoadDBC(bar,bad_dbc_files,sItemRandomPropertiesStore,dataPath+"dbc/ItemRandomProperties.dbc"); LoadDBC(bar,bad_dbc_files,sItemRandomSuffixStore, dataPath+"dbc/ItemRandomSuffix.dbc");@@ -542,6 +544,19 @@ return sTalentTabPages[cls]; } +uint32 GetItemCondExtCostsMask(uint32 requiredarenarank, uint32 itemextendedcost)+{+ // create and return mask for (RequiredArenaRank, ItemExtendedCost) pair+ uint32 mask = 0;+ for(uint32 i = 0; i < sItemCondExtCostsStore.nCount; ++i)+ {+ ItemCondExtCostsEntry const* icece = sItemCondExtCostsStore.LookupEntry(i);+ if(icece && icece->requiredarenarank == requiredarenarank && icece->itemextendedcostentry == itemextendedcost)+ mask |= (1 << icece->requirementtype);+ }+ return mask;+}+ // script support functions MANGOS_DLL_SPEC DBCStorage <SpellEntry> const* GetSpellStore() { return &sSpellStore; } MANGOS_DLL_SPEC DBCStorage <SpellRangeEntry> const* GetSpellRangeStore() { return &sSpellRangeStore; }Index: src/shared/Database/DBCStores.h===================================================================--- src/shared/Database/DBCStores.h (revision 5306)+++ src/shared/Database/DBCStores.h (working copy)@@ -44,6 +44,7 @@ uint32 GetTalentInspectBitPosInTab(uint32 talentId); uint32 GetTalentTabInspectBitSize(uint32 talentTabId); uint32 const* /*[3]*/ GetTalentTabPages(uint32 cls);+uint32 GetItemCondExtCostsMask(uint32 requiredarenarank, uint32 itemextendedcost); template<class T> class DBCStorageIndex: src/shared/Database/DBCStructure.h===================================================================--- src/shared/Database/DBCStructure.h (revision 5306)+++ src/shared/Database/DBCStructure.h (working copy)@@ -283,6 +283,16 @@ uint32 randomPropertyChance; }; +struct ItemCondExtCostsEntry+{+ // uint32 ID;+ uint32 requiredarenarank; // ItemPrototype::RequiredArenaRank+ uint32 itemextendedcostentry; // ItemPrototype::ExtendedCost+ uint32 requirementtype; // 1 - honor and/or arena point from itemextendedcost+ // 2 - required item(s) from itemextendedcost+ // 3 - required personal arena rating from itemextendedcost+};+ struct ItemExtendedCostEntry { uint32 ID; // 0 extended-cost entry id@@ -296,7 +306,7 @@ uint32 reqitemcount2; // 9 required count of 2st item uint32 reqitemcount3; // 10 required count of 3st item // 11-12 not used, always 0 (4-5 item count?)- // 13 not used+ uint32 reqpersonalarenarating; // 13 required personal arena rating }; struct ItemRandomPropertiesEntry