rendered paste bodyIndex: src/game/ArenaTeam.cpp===================================================================--- src/game/ArenaTeam.cpp (revision 5116)+++ src/game/ArenaTeam.cpp (working copy)@@ -34,7 +34,7 @@ stats.games = 0; stats.played = 0; stats.rank = 0;- stats.rating = 0;+ stats.rating = 1500; stats.wins = 0; stats.wins2 = 0; }@@ -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;@@ -74,7 +74,7 @@ CharacterDatabase.PExecute("INSERT INTO `arena_team` (`arenateamid`,`name`,`captainguid`,`type`,`EmblemStyle`,`EmblemColor`,`BorderStyle`,`BorderColor`,`BackgroundColor`) " "VALUES('%u','%s','%u','%u','%u','%u','%u','%u','%u')", Id, ArenaTeamName.c_str(), GUID_LOPART(CaptainGuid), Type, EmblemStyle, EmblemColor, BorderStyle, BorderColor, BackgroundColor);- CharacterDatabase.PExecute("INSERT INTO `arena_team_stats` (`arenateamid`, `rating`, `games`, `wins`, `played`, `wins2`, `rank`) VALUES ('%u', '0', '0', '0', '0', '0', '0')", Id);+ CharacterDatabase.PExecute("INSERT INTO `arena_team_stats` (`arenateamid`, `rating`, `games`, `wins`, `played`, `wins2`, `rank`) VALUES ('%u', '1500', '0', '0', '0', '0', '0')", Id); CharacterDatabase.CommitTransaction(); AddMember(CaptainGuid);@@ -89,8 +89,11 @@ 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@@ -118,6 +121,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));@@ -195,7 +199,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; @@ -209,6 +213,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;@@ -329,6 +334,7 @@ data << itr->wons_week; // wins this week data << itr->played_season; // played this season data << itr->wons_season; // wins this season+ data << uint32(0); // unknown } else {@@ -342,6 +348,7 @@ data << itr->wons_week; // wins this week data << itr->played_season; // played this season data << itr->wons_season; // wins this season+ data << uint32(0); // unknown } } session->SendPacket(&data);@@ -365,7 +372,7 @@ void ArenaTeam::Stats(WorldSession *session) {- WorldPacket data(SMSG_ARENA_TEAM_STATS, 4*7);+ WorldPacket data(SMSG_ARENA_TEAM_STATS, 4*9); data << GetId(); // arena team id data << stats.rating; // rating data << stats.games; // games@@ -373,6 +380,19 @@ data << stats.played; // played data << stats.wins2; // wins(again o_O) data << stats.rank; // rank+ uint64 guid = session->GetPlayer()->GetGUID();+ float played_percent = 0;+ for(MemberList::const_iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ if(itr->guid == guid)+ {+ if(stats.games)+ played_percent = itr->played_week / stats.games;+ break;+ }+ }+ data << played_percent; // played % per player+ data << played_percent; session->SendPacket(&data); } @@ -463,6 +483,145 @@ } } +uint32 ArenaTeam::GetPoints()+{+ 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));+ }++ 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)+{+ return 1.0f/(1.0f+exp(log(10.0f)*(float)(stats.rating - rating)/400.0f));+}++int32 ArenaTeam::WonAgainstChance(float chance)+{+ int32 mod = (int32)(32.0f * (1.0f - chance));+ stats.rating += mod;+ stats.games += 1;+ stats.wins += 1;+ stats.played += 1;+ stats.wins2 += 1;+// SetStats(STAT_TYPE_RATING, stats.rating + mod);+// SetStats(STAT_TYPE_GAMES, stats.games+1);+// SetStats(STAT_TYPE_WINS, stats.wins+1);+// SetStats(STAT_TYPE_PLAYED, stats.played+1);+// SetStats(STAT_TYPE_WINS2, stats.wins2+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;+ }+// SetStats(STAT_TYPE_RATING, higher_rating + 1);+ stats.rank = higher_rank + 1;+ return mod;+}++int32 ArenaTeam::LostAgainstChance(float chance)+{+ int32 mod = (int32)(32.0f * (0.0f - chance));+ stats.rating += mod;+ stats.games += 1;+ stats.played += 1;+// SetStats(STAT_TYPE_RATING, stats.rating + mod);+// SetStats(STAT_TYPE_GAMES, stats.games+1);+// SetStats(STAT_TYPE_PLAYED, 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;+ }+// SetStats(STAT_TYPE_RATING, higher_rating + 1);+ stats.rank = higher_rank + 1;+ return mod;+}++void ArenaTeam::MemberLost(uint64 guid)+{+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ if(itr->guid == guid)+ {+ itr->played_week +=1;+ itr->played_season +=1;+ return;+ }+ }+}++void ArenaTeam::MemberWon(uint64 guid)+{+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ if(itr->guid == guid)+ {+ itr->played_week +=1;+ itr->played_season +=1;+ itr->wons_season += 1;+ itr->wons_week += 1;+ return;+ }+ }+}++uint32 ArenaTeam::GetMemberPoints(uint64 guid)+{+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ if(itr->guid == guid)+ {+ return itr->points_to_add;+ }+ }+ return 0;+}++void ArenaTeam::UpdateArenaPointsHelper()+{+ if(stats.games < 10)+ return;+ uint32 min_plays = stats.games * 0.3;+ for(MemberList::iterator itr = members.begin(); itr != members.end(); ++itr)+ {+ if(itr->played_week >= min_plays)+ {+ 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);+ }+ else+ {+ itr->points_to_add = 0;+ }+ }+}++void ArenaTeam::SaveToDB()+{+ 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.1.0 client): 1405 - arena team id 2v2Index: src/game/ArenaTeam.h===================================================================--- src/game/ArenaTeam.h (revision 5116)+++ 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@@ -144,6 +145,8 @@ void LoadStatsFromDB(uint32 ArenaTeamId); void LoadPlayerStats(ArenaTeamMember* member); + void SaveToDB();+ void BroadcastPacket(WorldPacket *packet); void Roster(WorldSession *session);@@ -151,6 +154,16 @@ void Stats(WorldSession *session); void InspectStats(WorldSession *session); + uint32 GetPoints();+ float GetChanceAgainst(uint32 rating);+ int32 WonAgainstChance(float chance);+ void MemberWon(uint64 guid);+ int32 LostAgainstChance(float chance);+ void MemberLost(uint64 guid);++ void UpdateArenaPointsHelper();+ uint32 GetMemberPoints(uint64 guid);+ protected: uint32 Id;Index: src/game/ArenaTeamHandler.cpp===================================================================--- src/game/ArenaTeamHandler.cpp (revision 5116)+++ src/game/ArenaTeamHandler.cpp (working copy)@@ -141,6 +141,7 @@ if(player->GetArenaTeamId(team_slot)) {+ sLog.outDebug("ALREADY IN ARENA TEAM OF THAT SIZE!!!!! team id %u for team slot %u", player->GetArenaTeamId(team_slot), team_slot); SendArenaTeamCommandResult(ERR_ARENA_TEAM_INVITE_SS, player->GetName(), "", ERR_ALREADY_IN_ARENA_TEAM_S); return; }Index: src/game/BattleGround.cpp===================================================================--- src/game/BattleGround.cpp (revision 5116)+++ src/game/BattleGround.cpp (working copy)@@ -25,11 +25,13 @@ #include "Language.h" // for chat messages #include "Chat.h" #include "SpellAuras.h"+#include "ArenaTeam.h" #include "World.h" BattleGround::BattleGround() { m_TypeID = 0;+ m_TeamType = 0; m_InstanceID = 0; m_Status = 0; m_EndTime = 0;@@ -46,6 +48,8 @@ m_Name = ""; m_LevelMin = 0; m_LevelMax = 0;+ m_InBGFreeSlotQueue = false;+ m_SetDeleteThis = false; m_MaxPlayersPerTeam = 0; m_MaxPlayers = 0;@@ -66,6 +70,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; @@ -75,7 +85,28 @@ BattleGround::~BattleGround() {+ // remove objects and creatures+/* for(BGObjects::iterator itr = m_BgObjects.begin(); itr != m_BgObjects.end(); ++itr)+ {+ if(*itr) (*itr)->RemoveFromWorld();+ } + for(BGCreatures::iterator itr = m_BgCreatures.begin(); itr != m_BgCreatures.end(); ++itr)+ {+ if(*itr) (*itr)->RemoveFromWorld();+ }+*/+ // 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)@@ -237,7 +268,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); } }@@ -263,7 +297,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);@@ -283,7 +320,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); } }@@ -300,7 +340,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); } }@@ -322,7 +365,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); } }@@ -336,13 +382,20 @@ void BattleGround::EndBattleGround(uint32 winner) {+ this->RemoveFromBGFreeSlotQueue();++ ArenaTeam * winner_arena_team = NULL;+ ArenaTeam * loser_arena_team = NULL; WorldPacket data; Player *Source = NULL; const char *winmsg = ""; if(winner == ALLIANCE) {- winmsg = LANG_BG_A_WINS;+ if(isBattleGround())+ winmsg = LANG_BG_A_WINS;+ else+ winmsg = LANG_ARENA_GOLD_WINS; PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound @@ -350,13 +403,56 @@ } else {- winmsg = LANG_BG_H_WINS;+ if(isBattleGround())+ winmsg = LANG_BG_H_WINS;+ else+ winmsg = LANG_ARENA_GREEN_WINS; PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound SetWinner(WINNER_HORDE); } + 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)+ {+ uint32 loser_rating = loser_arena_team->GetStats().rating;+ uint32 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);+ }+ }+ SetStatus(STATUS_WAIT_LEAVE); m_EndTime = 0; @@ -371,14 +467,35 @@ 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();++ if(isArena() && isRated() && winner_arena_team && loser_arena_team) {+ if(team == winner)+ {+ winner_arena_team->MemberWon(itr->first);+ winner_arena_team->Stats(plr->GetSession());+ }+ else+ {+ loser_arena_team->MemberLost(itr->first);+ loser_arena_team->Stats(plr->GetSession());+ }+ }++ if(team == winner)+ { if(!Source) Source = plr; switch(GetTypeID())@@ -429,10 +546,21 @@ 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 bgTypeId = sBattleGroundMgr.BGQueueTypeId(m_TypeID);+ sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime()); plr->GetSession()->SendPacket(&data); } + if(isArena() && isRated() && winner_arena_team && loser_arena_team)+ {+ winner_arena_team->SaveToDB();+ loser_arena_team->SaveToDB();+ }++ // inform invited players about the removal+ sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].BGEndedRemoveInvites(this);++ if(Source) { ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_GLOBAL, Source->GetGUID(), winmsg);@@ -449,11 +577,13 @@ void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket) {+ sLog.outDebug("BG:Removing player at leave");+ 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); } @@ -468,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);@@ -478,41 +612,78 @@ if(plr) {+ if(!team) team = plr->GetTeam();++ uint32 bgTypeId = GetTypeID(); if(isArena()) {- if(!sWorld.IsFFAPvPRealm())- plr->RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);+ plr->RemoveArenaAuras(true);+ 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; - plr->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);+ Pet* NewPet = new Pet(plr);+ if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetOldPetNumber(), true))+ delete NewPet;++ (plr)->SetOldPetNumber(0); } 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(bgTypeId), 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(bgTypeId); - 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[bgTypeId].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();+ 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 *group = new Group;+ SetBgRaid(team, group);+ group->ConvertToRaid();+ group->AddMember(grpGuy->GetGUID(), grpGuy->GetName());+ group->ChangeLeader(grpGuy->GetGUID());+ } } } @@ -521,11 +692,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); } @@ -533,13 +705,32 @@ 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()) {- Reset();+ // // no one left, cleanup and reinit instance+ // Reset();+ // if(!SetupBattleGround())+ // {+ // // setup failed, remove battleground.+ m_SetDeleteThis = true;+ 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@@ -551,6 +742,9 @@ SetStartTime(0); SetEndTime(0); SetLastResurrectTime(0);+ SetTeamType(BG_TEAM_TYPE_NORMAL);+ SetArenaType(0);+ SetRated(false); m_Events = 0; @@ -559,6 +753,7 @@ m_InvitedAlliance = 0; m_InvitedHorde = 0;+ m_InBGFreeSlotQueue = false; m_Players.clear(); m_PlayerScores.clear();@@ -576,52 +771,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) {+ sLog.outDebug("BGAddPlayer %u",plr->GetGUIDLow()); // 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); 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@@ -631,13 +838,18 @@ /* This method should be called only once ... it adds pointer to queue */ void BattleGround::AddToBGFreeSlotQueue() {- sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);+ 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+ 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)@@ -645,7 +857,7 @@ sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr); return; }- }*/+ } } /*@@ -668,6 +880,30 @@ return false; } +// get the number of free slots for team+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 {@@ -748,7 +984,7 @@ 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);+/* GameObjectInfo const* goinfo = objmgr.GetGameObjectInfo(entry); if(!goinfo) { sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);@@ -772,21 +1008,40 @@ data.spawntimesecs = spawntime; data.animprogress = 100; data.go_state = 1;- objmgr.AddGameobjectToGrid(guid, &data); +// objmgr.AddGameobjectToGrid(guid, &data);+ m_BgObjects[type] = MAKE_GUID(guid, HIGHGUID_GAMEOBJECT); +/* GameObject * go = ObjectAccessor::Instance().GetObjectInWorld(m_BgObjects[type], (GameObject*)NULL);+ go->SetInstanceId(GetInstanceID());//*/++ 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("Cannot create gameobject template %u! BattleGround not created!", entry);+ delete go;+ return false;+ }++// objmgr.SaveGORespawnTime(go->GetGUIDLow(),go->GetInstanceId(),spawntime);+// MapManager::Instance().GetMap(go->GetMapId(), go)->Add(go);++ m_BgObjects[type] = go;//*/+ sLog.outDebug("GO created in bg type %u, insta %u, go entry %u",GetTypeID(), GetInstanceID(), entry); 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);+ sLog.outDebug("BG Door opened"); } else {@@ -798,32 +1053,37 @@ { 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);+ sLog.outDebug("BG Object spawned"); }- else- objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, 0);+// else+// objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), GetInstanceID(), 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);+ sLog.outDebug("BG Object spawned 2"); }- else- objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), 0, time(NULL) + respawntime);+// else+// objmgr.SaveGORespawnTime(GUID_LOPART(m_BgObjects[type]), GetInstanceID(), 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);@@ -834,17 +1094,50 @@ pCreature->AIM_Initialize(); //pCreature->SetDungeonDifficulty(0);- MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature);- m_BgCreatures[type] = pCreature->GetGUID();+// objmgr.SaveCreatureRespawnTime(pCreature->GetGUIDLow(), pCreature->GetInstanceId(), respawntime);+// MapManager::Instance().GetMap(pCreature->GetMapId(), pCreature)->Add(pCreature);+ m_BgCreatures[type] = pCreature;+ sLog.outDebug("BG Creature created in bg type %u, insta %u, go entry %u",GetTypeID(), GetInstanceID(), entry); 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);+ sLog.outDebug("BG Creature spawned");+ }+ // else+ // objmgr.SaveCreatureRespawnTime(GUID_LOPART(m_BgCreatures[type]), GetInstanceID(), 0);+ }+ else+ {+ Creature *obj = m_BgCreatures[type];+ if(obj)+ {+ obj->setDeathState(DEAD);+ obj->SetRespawnTime(respawntime);+ MapManager::Instance().GetMap(obj->GetMapId(), obj)->Add(obj);+ sLog.outDebug("BG Creature spawned 2");+ }+ // else+ // objmgr.SaveCreatureRespawnTime(GUID_LOPART(m_BgCreatures[type]), GetInstanceID(), time(NULL) + respawntime);+ }+}+ 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();@@ -855,10 +1148,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@@ -914,3 +1207,11 @@ SetStatus(STATUS_WAIT_LEAVE); SetEndTime(TIME_TO_AUTOREMOVE); }++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;+}Index: src/game/BattleGround.h===================================================================--- src/game/BattleGround.h (revision 5116)+++ src/game/BattleGround.h (working copy)@@ -50,7 +50,11 @@ SPELL_SPIRIT_HEAL_CHANNEL = 22011, SPELL_SPIRIT_HEAL = 22012, SPELL_RESURRECTION_VISUAL = 24171,- SPELL_ARENA_PREPARATION = 32727+ SPELL_ARENA_PREPARATION = 32727,+ SPELL_ALLIANCE_GOLD_FLAG = 32724,+ SPELL_ALLIANCE_GREEN_FLAG = 32725,+ SPELL_HORDE_GOLD_FLAG = 35774,+ SPELL_HORDE_GREEN_FLAG = 35775 }; enum BattleGroundTimeIntervals@@ -61,9 +65,9 @@ TIME_TO_AUTOREMOVE = 120000, // ms MAX_OFFLINE_TIME = 300000, // ms START_DELAY0 = 120000, // ms- START_DELAY1 = 60000, // ms- START_DELAY2 = 30000, // ms- START_DELAY3 = 15000, // ms used only in arena+ START_DELAY1 = 10000, // ms+ START_DELAY2 = 5000, // ms+ START_DELAY3 = 1000, // ms used only in arena RESPAWN_ONE_DAY = 86400, // secs RESPAWN_IMMEDIATELY = 0, // secs BUFF_RESPAWN_TIME = 180 // secs@@ -166,6 +170,13 @@ BG_TEAM_HORDE = 1 }; +enum BattleGroundTeamType+{+ BG_TEAM_TYPE_NORMAL = 0, // one side is ally, other is horde+ BG_TEAM_TYPE_ALLIANCE_ONLY = 1, // both sides are alliance+ BG_TEAM_TYPE_HORDE_ONLY = 2 // both sides are horde+};+ class BattleGroundScore { public:@@ -193,6 +204,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@@ -262,6 +274,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; }@@ -334,6 +347,11 @@ m_PlayersCount[GetTeamIndexByTeamId(Team)]++; } + 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*/) {}@@ -342,24 +360,30 @@ // 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); void DoorOpen(uint32 type); + uint32 GetPlayerTeam(uint64 guid);++ uint8 GetTeamType() const {return m_TeamType;}+ void SetTeamType(uint8 type){m_TeamType=type;}+ protected: //this method is called, when BG cannot spawn its own spirit guide, or something is wrong, It correctly ends BattleGround void EndNow();@@ -387,6 +411,9 @@ uint32 m_LastResurrectTime; uint32 m_Queue_type; uint8 m_ArenaType; // 2=2v2, 3=3v3, 5=5v5+ uint8 m_TeamType;+ bool m_InBGFreeSlotQueue;+ bool m_SetDeleteThis; // 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@@ -412,6 +439,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 5116)+++ 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 5116)+++ 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 5116)+++ src/game/BattleGroundAB.cpp (working copy)@@ -237,9 +237,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; @@ -342,6 +342,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]); @@ -463,6 +464,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);@@ -626,6 +628,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 +637,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; @@ -755,3 +763,6 @@ } +++Index: src/game/BattleGroundAB.h===================================================================--- src/game/BattleGroundAB.h (revision 5116)+++ 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 5116)+++ 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 5116)+++ 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 5116)+++ src/game/BattleGroundBE.cpp (working copy)@@ -98,9 +98,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 +109,13 @@ void BattleGroundBE::RemovePlayer(Player *plr, uint64 guid) {+ if(GetStatus() == STATUS_WAIT_LEAVE)+ return; + if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+ EndBattleGround(HORDE);+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))+ EndBattleGround(ALLIANCE); } void BattleGroundBE::HandleKillPlayer(Player *player, Player *killer)@@ -123,14 +129,20 @@ return; } - uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());+ uint32 killer_team = GetPlayerTeam(killer->GetGUID());+ if(!killer_team) killer_team = killer->GetTeam(); + uint32 killer_team_index = GetTeamIndexByTeamId(killer_team);+ m_TeamKills[killer_team_index]++; // add kills to killer's team - if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))+ uint32 team = GetPlayerTeam(player->GetGUID());+ if(!team) team = player->GetTeam();++ if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(team)) { // all opponents killed- EndBattleGround(killer->GetTeam());+ EndBattleGround(killer_team); } } @@ -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,7 +177,6 @@ SpellId = obj->GetGOInfo()->data3; if(SpellId) Source->CastSpell(Source, SpellId, true);- } } } Index: src/game/BattleGroundBE.h===================================================================--- src/game/BattleGroundBE.h (revision 5116)+++ 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);Index: src/game/BattleGroundEY.cpp===================================================================--- src/game/BattleGroundEY.cpp (revision 5116)+++ 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 5116)+++ 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 5116)+++ src/game/BattleGroundHandler.cpp (working copy)@@ -26,6 +26,8 @@ #include "MapManager.h" #include "ObjectAccessor.h" #include "Object.h"+#include "Chat.h"+#include "Language.h" #include "BattleGroundMgr.h" #include "BattleGroundWS.h" #include "BattleGround.h"@@ -78,6 +80,12 @@ 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); // ignore if we already in BG or BG queue@@ -100,19 +108,38 @@ return; } - // check existence- BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);- if(!bg)+ BattleGround * bg = 0;+ if(instanceId)+ BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);++ if(!bg && !(bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId)))+ {+ sLog.outDebug("bgjoin: 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, LANG_BG_GROUP_TOO_LARGE, NULL);+ SendPacket(&data);+ return;+ }+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddGroup(_player, 0, false); 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);@@ -134,15 +161,16 @@ } // 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[bgTypeId].AddPlayer(member, ginfo); }+ sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); } else {@@ -159,13 +187,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[bgTypeId].AddGroup(_player, 0, false);+ sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(_player, ginfo);+ sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel()); } } @@ -247,6 +278,12 @@ uint32 bgTypeId; recv_data >> bgTypeId; // id from DBC + if(bgTypeId >= MAX_BATTLEGROUND_TYPES)+ {+ sLog.outError("bgport: invalid bgtype received. possible cheater? player guid %u",_player->GetGUIDLow());+ return;+ }+ BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if(!bl)@@ -265,37 +302,83 @@ uint8 unk1; 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; - BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);+ if(bgTypeId >= MAX_BATTLEGROUND_TYPES)+ {+ sLog.outError("bgport: invalid bgtype received. possible cheater? player guid %u",_player->GetGUIDLow());+ return;+ }++ // get the bg what we were invited to + uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bgTypeId);+ BattleGroundQueue::QueuedPlayersMap::iterator itrPlayerStatus = sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].find(_player->GetGUID());+ if(itrPlayerStatus == sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].m_QueuedPlayers[_player->GetBattleGroundQueueIdFromLevel()].end())+ {+ sLog.outDebug("bgport: itrplayerstatus not found.");+ return;+ }+ instanceId = itrPlayerStatus->second.GroupInfo->IsInvitedToBGInstanceGUID;//*/++ if(!instanceId && action == 1)+ {+ sLog.outDebug("bgport: instance not found.");+ return;+ }++ BattleGround *bg = sBattleGroundMgr.GetBattleGround(instanceId);++ if(!bg && action == 0)+ bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId);++ if(!bg)+ {+ sLog.outDebug("bgport: 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;+ } WorldPacket data; switch(action) { case 1: // port to battleground- _player->RemoveFromGroup();- queueSlot = _player->GetBattleGroundQueueIndex(bgTypeId);+ //_player->RemoveFromGroup();+ 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 +386,16 @@ if (currentBg) currentBg->RemovePlayerAtLeave(_player->GetGUID(), false, true); }- _player->SetBattleGroundId(bg->GetTypeID());- sBattleGroundMgr.SendToBattleGround(_player, bgTypeId);- bg->AddPlayer(_player);+ _player->SetBattleGroundId(bg->GetInstanceID()); // really bg type, or rather instance id?+ // for now, it works with typeid, but should be instance id. + 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 +434,8 @@ BattleGround *bg = _player->GetBattleGround(); if(bg) {- uint32 queueSlot = _player->GetBattleGroundQueueIndex(bg->GetTypeID());+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID());+ 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,10 +443,10 @@ } 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+ if (i == queueSlot || !queue_id) // we need to get the instance ids continue;- BattleGround *bg2 = sBattleGroundMgr.GetBattleGround(queue_id);+ BattleGround *bg2 = sBattleGroundMgr.GetBattleGroundTemplate(queue_id); // try this if(bg2) { //in this call is small bug, this call should be filled by player's waiting time in queue@@ -377,8 +462,8 @@ // we should update all queues? .. i'm not sure if this code is correct for (uint32 i = 0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) {- uint32 queue_id = _player->GetBattleGroundQueueId(i);- BattleGround *bg = sBattleGroundMgr.GetBattleGround(queue_id);+ uint32 queue_id = sBattleGroundMgr.BGQueueTypeId(_player->GetBattleGroundQueueId(i));+ BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(queue_id); if(bg && queue_id) { sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, bg, _player->GetTeam(), i, STATUS_WAIT_QUEUE, 0, 0);@@ -453,7 +538,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@@ -487,23 +572,57 @@ 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;+ }+ 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, LANG_ARENA_YOUR_TEAM_ONLY, 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.outDebug("arena_join template bg (all arenas) not found"); return;+ } + uint8 bgTypeId = bg->GetTypeID();+ 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, LANG_ARENA_GROUP_TOO_LARGE, NULL);+ SendPacket(&data);+ return;+ }+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddGroup(_player, arenatype, isRated); for(GroupReference *itr = grp->GetFirstMember(); itr != NULL; itr = itr->next()) { Player *member = itr->getSource();@@ -513,13 +632,23 @@ //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(bgTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+ {+ sLog.outDebug("all arenas: player is already in this queue"); //player is already in this queue continue;+ } - uint32 queueSlot = member->AddBattleGroundQueueId(BATTLEGROUND_AA);// add to queue+ uint32 queueSlot = member->AddBattleGroundQueueId(bgTypeId);// add to queue if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES) {+ sLog.outDebug("arena_join player max bg queues are filled. error"); WorldPacket data; //fill data //member->GetSession()->SendPacket(data);@@ -527,16 +656,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); 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[bgTypeId].AddPlayer(member, ginfo); }+ sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated); } else {@@ -544,13 +674,17 @@ //player has deserter aura .. do nothing */ - if (_player->GetBattleGroundQueueIndex(BATTLEGROUND_AA) < PLAYER_MAX_BATTLEGROUND_QUEUES)+ if (_player->GetBattleGroundQueueIndex(bgTypeId) < PLAYER_MAX_BATTLEGROUND_QUEUES)+ {+ sLog.outDebug("player is already in all_arenas queue"); //player is already in this queue return;+ } - uint32 queueSlot = _player->AddBattleGroundQueueId(BATTLEGROUND_AA);+ uint32 queueSlot = _player->AddBattleGroundQueueId(bgTypeId); if (queueSlot == PLAYER_MAX_BATTLEGROUND_QUEUES) {+ sLog.outDebug("arenajoin player queues are already full"); WorldPacket data; //fill data (player is in 3 queues already) //SendPacket(data);@@ -558,12 +692,15 @@ } // 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[BATTLEGROUND_AA].AddPlayer(_player, BATTLEGROUND_AA);+ GroupQueueInfo * ginfo = sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddGroup(_player,arenatype,isRated);+ sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(_player, ginfo);+ sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].Update(bgTypeId, _player->GetBattleGroundQueueIdFromLevel(), arenatype, isRated);+// sBattleGroundMgr.m_BattleGroundQueues[bgTypeId].AddPlayer(_player, bgTypeId, 0, 0, arenatype, isRated); } }Index: src/game/BattleGroundMgr.cpp===================================================================--- src/game/BattleGroundMgr.cpp (revision 5116)+++ src/game/BattleGroundMgr.cpp (working copy)@@ -42,112 +42,456 @@ BattleGroundQueue::BattleGroundQueue() {+ sLog.outDebug("Creating battleground queue"); //queues are empty, we don't have to call clear() 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() {+ sLog.outDebug("Destroying battleground queue"); 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)+void BattleGroundQueue::EligibleGroups::Init(BattleGroundQueue::QueuedGroupsList *source, uint32 side, uint32 MaxPlayers, uint8 ArenaType, bool IsRated) {+ sLog.outDebug("initializing eligible groups for side %u, maxplayers %u, arenatype %u, rated %u",side,MaxPlayers,ArenaType,IsRated);+ clear();+ BattleGroundQueue::QueuedGroupsList::iterator itr, next;+ for(itr = source->begin(); itr!= source->end(); itr = next)+ {+ next = itr;+ ++next;+ if( (*itr)->ArenaType == ArenaType &&+ (*itr)->IsRated == IsRated &&+ (*itr)->IsInvitedToBGInstanceGUID == 0 &&+ (*itr)->Team == side &&+ (*itr)->Players.size() <= MaxPlayers )+ {+ sLog.outDebug("Found an eligible group. Inserting it.");+ // the group matches the conditions+ // insert it in order of groupsize+ 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) )+ {+ sLog.outDebug("inserting inside list");+ insert(elig_itr,(*itr));+ inserted = true;+ break;+ }+ }+ // if not inserted -> this is the smallest group -> push_back+ if(!inserted)+ {+ sLog.outDebug("inserting at end of list");+ push_back((*itr));+ }+ }+ }+}++void BattleGroundQueue::EligibleGroups::RemoveGroup(GroupQueueInfo * ginfo)+{+ sLog.outDebug("EligibleGroups::RemoveGroup");+ for(std::list<GroupQueueInfo *>::iterator itr = begin(); itr != end(); ++itr)+ {+ if((*itr)=ginfo)+ {+ sLog.outDebug("Group found, erase");+ erase(itr);+ return;+ }+ }+}++void BattleGroundQueue::SelectionPool::Init()+{+ sLog.outDebug("Initializing selection pool");+ SelectedGroups.clear();+ MaxGroup = 0;+ PlayerCount = 0;+}++GroupQueueInfo * BattleGroundQueue::SelectionPool::GetMaximalGroup()+{+ sLog.outDebug("Getting maximal group from SelectionPool");+ if(SelectedGroups.empty())+ {+ sLog.outError("Getting max group when selection pool is empty, this should never happen.");+ MaxGroup = NULL;+ return 0;+ }+ 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;+}++void BattleGroundQueue::SelectionPool::RemoveGroup(GroupQueueInfo *ginfo)+{+ sLog.outDebug("Removing group from SelectionPool");+ if(MaxGroup == ginfo)+ MaxGroup = 0;+ for(std::list<GroupQueueInfo *>::iterator itr = SelectedGroups.begin(); itr != SelectedGroups.end(); ++itr)+ {+ if((*itr)=ginfo)+ {+ SelectedGroups.erase(itr);+ PlayerCount -= ginfo->Players.size();+ return;+ }+ }+}++void BattleGroundQueue::SelectionPool::AddGroup(GroupQueueInfo * ginfo)+{+ sLog.outDebug("Adding group to SelectionPool");+ SelectedGroups.push_back(ginfo);+ PlayerCount+=ginfo->Players.size();+ if(!MaxGroup || ginfo->Players.size() > MaxGroup->Players.size())+ {+ sLog.outDebug("Setting the newly added group as MaxGroup");+ MaxGroup = ginfo;+ }+}+++GroupQueueInfo * BattleGroundQueue::AddGroup(Player *leader, uint8 ArenaType, bool isRated)+{+ sLog.outDebug("Adding Group to BGQueue with leader %u",leader->GetGUIDLow());+ uint32 queue_id = leader->GetBattleGroundQueueIdFromLevel();++ GroupQueueInfo* ginfo = new GroupQueueInfo;+ ginfo->ArenaType = ArenaType;+ ginfo->IsRated = isRated;+ ginfo->IsInvitedToBGInstanceGUID = 0;+ ginfo->JoinTime = getMSTime();+ ginfo->Team = leader->GetTeam();++ ginfo->Players.clear();++ m_QueuedGroups[queue_id].push_back(ginfo);++ return ginfo;+}++void BattleGroundQueue::AddPlayer(Player *plr, GroupQueueInfo *ginfo)+{+ sLog.outDebug("Adding player %u to BGGroup in queue", plr->GetGUIDLow()); 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);+ ginfo->Players[plr->GetGUID()] = &info; } void BattleGroundQueue::RemovePlayer(uint64 guid, bool decreaseInvitedCount) {+ sLog.outDebug("removing player guid %u", guid); Player *plr = objmgr.GetPlayer(guid); 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)+ {+ sLog.outDebug("plr found");+ 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); if(itr != m_QueuedPlayers[i].end()) {+ sLog.outDebug("player itr found."); queue_id = i; IsSet = true; break; } } }- 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())+ {+ sLog.outDebug("player found, now remove");+ group->Players.erase(pitr);+ }++ if(group->Players.empty())+ {+ // player group is empty, remove group from wait queue+ // not yet implemented, probably won't ever be :(+ }++ if (group_itr != m_QueuedGroups[queue_id].end() && itr != m_QueuedPlayers[queue_id].end())+ {+ if (!group->IsInvitedToBGInstanceGUID) {+/* // do nothing for now if(itr->second.Team == ALLIANCE) m_QueuedPlayers[queue_id].Alliance--; else- m_QueuedPlayers[queue_id].Horde--;+ m_QueuedPlayers[queue_id].Horde--;*/ } else { if (decreaseInvitedCount) {- BattleGround* bg = sBattleGroundMgr.GetBattleGround(itr->second.IsInvitedToBGInstanceGUID);+ sLog.outDebug("BGQueue - decreasing invited count");+ BattleGround* bg = sBattleGroundMgr.GetBattleGround(group->IsInvitedToBGInstanceGUID); if (bg)- bg->DecreaseInvitedCount(itr->second.Team);+ bg->DecreaseInvitedCount(group->Team);+ // update the join queue, maybe now the player's group fits in a queue! } }+ // remove player queue info m_QueuedPlayers[queue_id].erase(itr);+ // remove group queue info if needed+ if(group->Players.empty())+ {+ sLog.outDebug("BGQueue:RemovePlayer:deleting group");+ m_QueuedGroups[queue_id].erase(group_itr);+ delete group;+ } } } +bool BattleGroundQueue::InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side)+{+ sLog.outDebug("Inviting group to bg, groupsize %u, bgtype %u, instance %u, as side %u",ginfo->Players.size(), bg->GetTypeID(), bg->GetInstanceID(), side);+ // set side if needed+ if(side)+ ginfo->Team = side;++ if(!ginfo->IsInvitedToBGInstanceGUID)+ {+ // not yet invited+ // set invitation+ ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();+ // 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 = 0;+ if(bg->isArena())+ queueSlot = plr->GetBattleGroundQueueIndex(BATTLEGROUND_AA);+ else+ queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());++ 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;+ }++ sLog.outDebug("Group already invited to bg, doing nothing");+ return false;+}++// this function is responsible for the selection of queued groups when trying to create new battlegrounds+bool BattleGroundQueue::BuildSelectionPool(uint32 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType, bool isRated)+{+ sLog.outDebug("Building selection pool, mode %u", mode);+ 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]), side, MaxPlayers, ArenaType, isRated);+ // 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;+}++void BattleGroundQueue::BGEndedRemoveInvites(BattleGround *bg)+{+ sLog.outDebug("BG Ended, removing invited groups");+ uint32 queue_id = bg->GetQueueType();+ uint32 bgInstanceId = bg->GetInstanceID();+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID());+ 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);+ Update(bgQueueTypeId, bg->GetQueueType());+ 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) {+ sLog.outDebug("Battleground: Update with bgtype %u, queueid %u", bgTypeId, queue_id); if (queue_id >= MAX_BATTLEGROUND_QUEUES) { //this is error, that caused crashes (not in , but now it shouldn't)@@ -156,158 +500,310 @@ } //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; //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) // iterate only till .back(), not .end()! {+ sLog.outDebug("Iterating BGFreeSlotQueue");+ 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) {+ sLog.outDebug("proper bg with free slots found"); //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();)+ sLog.outDebug("Iterating through queued groups");+ 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;- }+ sLog.outDebug("group fits in, inviting");+ 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())+ {+ sLog.outDebug("bg type %u, instance %u is full, removing from free slot queue", bg->GetTypeID(), bg->GetInstanceID());+ //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+ //if bg is full, there is no need to invite other players, so break+// break;+ }+ }+ } - // 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;+ }+ sLog.outDebug("BG Template found"); - // 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 rated 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;+ // try to build the selection pools+ bool bAllyOK = BuildSelectionPool(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_ALLIANCE, arenatype, isRated);+ if(bAllyOK)+ sLog.outDebug("Battleground: ally pool succesfully build");+ else+ sLog.outDebug("Battleground: ally pool wasn't created");+ bool bHordeOK = BuildSelectionPool(queue_id, MinPlayersPerTeam, MaxPlayersPerTeam, NORMAL_HORDE, arenatype, isRated);+ if(bHordeOK)+ sLog.outDebug("Battleground: horde pool succesfully built");+ else+ sLog.outDebug("Battleground: horde pool wasn't created"); - //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- }- }+ // 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) */+ sLog.outDebug("BG Created."); - /* 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);+ }++ sLog.outDebug("Starting bg.");+ // start the battleground+ bg2->StartBattleGround(0);+ sLog.outDebug("BG Started.");+ }++ // 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(queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM1,arenatype, isRated);+ if(bOneSideHordeTeam1)+ {+ sLog.outDebug("one side horde team1 alright");+ // 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(queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_HORDE_TEAM2,arenatype, isRated);++ // 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;+ else+ sLog.outDebug("one side horde team2 alright");+ }+ if(!bOneSideHordeTeam1)+ {+ // check for one sided ally+ bOneSideAllyTeam1 = BuildSelectionPool(queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM1,arenatype, isRated);+ 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(queue_id,MaxPlayersPerTeam,MaxPlayersPerTeam,ONESIDE_ALLIANCE_TEAM2,arenatype, isRated);++ // 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;+ // set the team type of the arena+ if(side == ALLIANCE)+ bg2->SetTeamType(BG_TEAM_TYPE_ALLIANCE_ONLY);+ else+ bg2->SetTeamType(BG_TEAM_TYPE_HORDE_ONLY); - //check if player is not already invited- if (!itrPlayerStatus->second.IsInvitedToBGInstanceGUID)- {- itrPlayerStatus->second.IsInvitedToBGInstanceGUID = bg2->GetInstanceID();- itrPlayerStatus->second.InviteTime = getMSTime();- itrPlayerStatus->second.LastInviteTime = getMSTime();+ // start the joining of the bg+ bg2->SetStatus(STATUS_WAIT_JOIN);+ bg2->SetQueueType(queue_id);+ // initialize arena / rating info+ bg2->SetArenaType(arenatype); - if(itrPlayerStatus->second.Team == ALLIANCE)- m_QueuedPlayers[queue_id].Alliance--;- else- m_QueuedPlayers[queue_id].Horde--;+ std::list<GroupQueueInfo* >::iterator itr; - sBattleGroundMgr.InvitePlayer(plr, bg2->GetInstanceID());+ // 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);+ } - 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);- }+ // 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); }- else- ++itr2;++ sLog.outDebug("Starting arena");+ bg2->StartBattleGround(0);+ sLog.outDebug("Arena started"); }- bg2->StartBattleGround(0); } } @@ -317,6 +813,7 @@ bool BGQueueInviteEvent::Execute(uint64 /*e_time*/, uint32 p_time) {+ sLog.outDebug("Executing BGInvite event"); Player* plr = objmgr.GetPlayer( m_PlayerGuid ); // player logged off (we should do nothing, he is correctly removed from queue in another procedure)@@ -330,16 +827,17 @@ BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID); if (bg) {- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID());+ 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); } }@@ -355,6 +853,7 @@ bool BGQueueRemoveEvent::Execute(uint64 /*e_time*/, uint32 /*p_time*/) {+ sLog.outDebug("Executing BGRemove Event"); Player* plr = objmgr.GetPlayer( m_PlayerGuid ); if (!plr) // player logged off (we should do nothing, he is correctly removed from queue in another procedure)@@ -366,17 +865,18 @@ BattleGround* bg = sBattleGroundMgr.GetBattleGround(m_BgInstanceGUID); if (bg) {- uint32 queueSlot = plr->GetBattleGroundQueueIndex(bg->GetTypeID());+ uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(bg->GetTypeID());+ 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); } }@@ -397,24 +897,46 @@ BattleGroundMgr::BattleGroundMgr() {+ sLog.outDebug("Creating BattleGroundMgr"); m_BattleGrounds.clear(); } BattleGroundMgr::~BattleGroundMgr() {- for(std::map<uint32, BattleGround*>::iterator itr = m_BattleGrounds.begin(); itr != m_BattleGrounds.end(); ++itr)- delete itr->second;+ sLog.outDebug("Destroying BattleGRoundMgr");+ 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(); } 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);+ if(itr->second->m_SetDeleteThis)+ {+ BattleGround * bg = itr->second;+ sLog.outDebug("deleting bg insta %u", bg->GetInstanceID());+ m_BattleGrounds.erase(itr);+ delete bg;+ }+ } } void BattleGroundMgr::BuildBattleGroundStatusPacket(WorldPacket *data, BattleGround *bg, uint32 team, uint8 QueueSlot, uint8 StatusID, uint32 Time1, uint32 Time2) {+ sLog.outDebug("Building BGStatusPacket"); // we can be in 3 queues in same time... if(StatusID == 0) {@@ -427,7 +949,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(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 +982,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@@ -497,6 +1019,7 @@ void BattleGroundMgr::BuildPvpLogDataPacket(WorldPacket *data, BattleGround *bg) {+ sLog.outDebug("Building PvpLogPacket"); uint8 type = (bg->isArena() ? 1 : 0); // checked on 2.1.3 data->Initialize(MSG_PVP_LOG_DATA, (1+1+4+40*bg->GetPlayerScoresSize()));@@ -505,7 +1028,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 +1059,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 +1149,109 @@ *data << uint64(plr->GetGUID()); } -void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID)+void BattleGroundMgr::InvitePlayer(Player* plr, uint32 bgInstanceGUID, uint32 team) {+ sLog.outDebug("bgmgr::inviteplayer %u to %u", plr->GetGUIDLow(), bgInstanceGUID); // set invited player counters: BattleGround* bg = this->GetBattleGround(bgInstanceGUID);- bg->IncreaseInvitedCount(plr->GetTeam());+ bg->IncreaseInvitedCount(team); + 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)+{+ sLog.outDebug("Getting bg template for %u", bgTypeId);+ return BGFreeSlotQueue[bgTypeId].empty() ? NULL : BGFreeSlotQueue[bgTypeId].back();+}++BattleGround * BattleGroundMgr::CreateNewBattleGround(uint32 bgTypeId)+{+ sLog.outDebug("creating new bg %u", bgTypeId);+ // Create the BG+ BattleGround *bg = NULL;++ BattleGround *bg_template = GetBattleGroundTemplate(bgTypeId);++ if(!bg_template)+ {+ sLog.outDebug("CreateNewBG - bg template not found for %u", bgTypeId);+ return 0;+ }+ + 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+ }+ sLog.outDebug("generating instance id");+ bg->SetInstanceID(MapManager::Instance().GenerateInstanceId()); // set instance id+ sLog.outDebug("id generated: %u",bg->GetInstanceID());+ bg->Reset();+ sLog.outDebug("bg reseted");+ if(!(bg->SetupBattleGround())) // setup the battleground in its update function to ensure that a player is present in the instance. Otherwise the objects won't be spawned :(+ {+ sLog.outDebug("CreateNewBattleGround - SetupBattleGround failed for bg %u", bgTypeId);+ delete bg;+ return 0;+ }+ sLog.outDebug("bg is set up");+ bg->AddToBGFreeSlotQueue();++ AddBattleGround(bg->GetInstanceID(), bg);+ sLog.outDebug("bg added to queue and update list");+ return bg;+}+ 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,13 +1271,19 @@ } bg->SetMapId(MapID);++ // set unloadflag to false+ Map* map = const_cast<Map*>(MapManager::Instance().GetBaseMap(MapID));+// Map * map = MapManager::Instance().GetMap(GetMapId(), m_bgobjects[BG_AB_OBJECT_GATE_H]);+ if(map) map->SetUnloadMap(false);+ bg->Reset();- if(!bg->SetupBattleGround())+/* if(!bg->SetupBattleGround()) do not setup for template bgs! { delete bg; return 0; }-+*/ BattlemasterListEntry const *bl = sBattlemasterListStore.LookupEntry(bgTypeId); //in previous method is checked if exists entry in sBattlemasterListStore, so no check needed if (bl)@@ -672,7 +1292,8 @@ } bg->SetTypeID(bgTypeId);- bg->SetInstanceID(bgTypeId); // temporary+// bg->SetInstanceID(bgTypeId); // temporary+ bg->SetInstanceID(0); // template bg, instance id is 0 bg->SetMinPlayersPerTeam(MinPlayersPerTeam); bg->SetMaxPlayersPerTeam(MaxPlayersPerTeam); bg->SetMinPlayers(MinPlayersPerTeam*2);@@ -684,9 +1305,9 @@ //add BaggleGround instance to FreeSlotQueue bg->AddToBGFreeSlotQueue(); - AddBattleGround(bg->GetInstanceID(), bg);+// AddBattleGround(bg->GetInstanceID(), bg); // do not! we're instantiating! only working ones need to be added, but not the templates! //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();+ return bgTypeId; //bg->GetInstanceID(); } void BattleGroundMgr::CreateInitialBattleGrounds()@@ -841,18 +1462,28 @@ } } -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 %f, %f, %f, %f", pl->GetName(), x, y, z, O);- pl->TeleportTo(mapid, x, y, z, O);+ // pl->SetInstanceId(instanceId); DO NOT DO THIS!!!! EVER!!!! (well, not here anyway)+ // actually, thinking a bit more, this wasn't used at all.+ pl->m_BoundInstances[mapid]=std::pair<uint32,uint32>(instanceId, pl->GetGUIDLow());+ // teleport as gm command+ pl->TeleportTo(mapid, x, y, z, O, true, true, 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 +1495,28 @@ 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) const+{+ return IsArenaType(bgTypeId)?BATTLEGROUND_AA:bgTypeId;+}Index: src/game/BattleGroundMgr.h===================================================================--- src/game/BattleGroundMgr.h (revision 5116)+++ src/game/BattleGroundMgr.h (working copy)@@ -36,16 +36,23 @@ #define BG_REMIND_INVITE_TIME 60000 // when this time pass, player get invitation request again +struct GroupQueueInfo; struct PlayerQueueInfo { 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+ GroupQueueInfo * GroupInfo;+};++struct GroupQueueInfo+{+ std::map<uint64, PlayerQueueInfo*> Players; uint32 Team; // Player team (ALLIANCE/HORDE)- bool IsRated;- bool AsGroup; // uint32 GroupId;- uint8 ArenaType;+ bool IsRated;+ uint8 ArenaType;+ uint32 JoinTime;+ uint32 IsInvitedToBGInstanceGUID; // was invited to certain BG }; struct PlayersCount@@ -63,6 +70,7 @@ //uint32 AverageTime; //not already implemented (it should be average time in queue for last 10 players) }; +class BattleGround; class BattleGroundQueue { public:@@ -72,15 +80,69 @@ uint32 GetType(); void SetType(uint32 type);*/ - void Update(uint32 bgTypeId, uint32 queue_id);+ void Update(uint32 bgTypeId, uint32 queue_id, uint8 arenateam = 0, bool isRated = false); - void AddPlayer(Player *plr, uint32 bgTypeId);+ GroupQueueInfo * AddGroup(Player * leader, uint8 ArenaType, bool isRated);+ 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;+// uint32 GetPlayerCount(uint32 queueId, uint32 team, uint8 arenatype, bool isRated, uint32 instanceGUID = 0);++ 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];++ typedef std::list<uint64> GroupIdsSortedByTimeQueue;+ GroupIdsSortedByTimeQueue m_GroupIdsSortedByWaitTime[MAX_BATTLEGROUND_QUEUES];++ class EligibleGroups : public std::list<GroupQueueInfo *>+ {+ public:+ void Init(QueuedGroupsList * source, uint32 side, uint32 MaxPlayers, uint8 ArenaType = 0, bool IsRated = false);+ void RemoveGroup(GroupQueueInfo * ginfo);+ };++ EligibleGroups m_EligibleGroups;++ 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 queue_id, uint32 MinPlayers, uint32 MaxPlayers, SelectionPoolBuildMode mode, uint8 ArenaType = 0, bool isRated = false);++ private:++ bool InviteGroupToBG(GroupQueueInfo * ginfo, BattleGround * bg, uint32 side);+// bool InvitePlayerToBG(PlayerGuidsSortedByTimeQueue::iterator &itr, Player * plr, BattleGround * bg, uint32 side); }; /*@@ -139,13 +201,13 @@ /* 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,13 +216,17 @@ 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@@ -170,6 +236,10 @@ void SendAreaSpiritHealerQueryOpcode(Player *pl, BattleGround *bg, uint64 guid); + bool IsArenaType(uint32 bgTypeId) const;+ bool IsBattleGroundType(uint32 bgTypeId) const;+ uint32 BGQueueTypeId(uint32 bgTypeId) const;+ private: /* Battlegrounds */Index: src/game/BattleGroundNA.cpp===================================================================--- src/game/BattleGroundNA.cpp (revision 5116)+++ src/game/BattleGroundNA.cpp (working copy)@@ -92,9 +92,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 +103,13 @@ void BattleGroundNA::RemovePlayer(Player *plr, uint64 guid) {+ if(GetStatus() == STATUS_WAIT_LEAVE)+ return; + if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+ EndBattleGround(HORDE);+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))+ EndBattleGround(ALLIANCE); } void BattleGroundNA::HandleKillPlayer(Player *player, Player *killer)@@ -117,14 +123,20 @@ return; } - uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());+ uint32 killer_team = GetPlayerTeam(killer->GetGUID());+ if(!killer_team) killer_team = killer->GetTeam(); + uint32 killer_team_index = GetTeamIndexByTeamId(killer_team);+ m_TeamKills[killer_team_index]++; // add kills to killer's team - if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))+ uint32 team = GetPlayerTeam(player->GetGUID());+ if(!team) team = player->GetTeam();++ if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(team)) { // all opponents killed- EndBattleGround(killer->GetTeam());+ EndBattleGround(killer_team); } } Index: src/game/BattleGroundNA.h===================================================================--- src/game/BattleGroundNA.h (revision 5116)+++ src/game/BattleGroundNA.h (working copy)@@ -55,7 +55,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/BattleGroundRL.cpp===================================================================--- src/game/BattleGroundRL.cpp (revision 5116)+++ src/game/BattleGroundRL.cpp (working copy)@@ -93,9 +93,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 +104,13 @@ void BattleGroundRL::RemovePlayer(Player *plr, uint64 guid) {+ if(GetStatus() == STATUS_WAIT_LEAVE)+ return; + if(!GetPlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))+ EndBattleGround(HORDE);+ else if(GetPlayersCountByTeam(ALLIANCE) && !GetPlayersCountByTeam(HORDE))+ EndBattleGround(ALLIANCE); } void BattleGroundRL::HandleKillPlayer(Player *player, Player *killer)@@ -118,14 +124,20 @@ return; } - uint32 killer_team_index = GetTeamIndexByTeamId(killer->GetTeam());+ uint32 killer_team = GetPlayerTeam(killer->GetGUID());+ if(!killer_team) killer_team = killer->GetTeam(); + uint32 killer_team_index = GetTeamIndexByTeamId(killer_team);+ m_TeamKills[killer_team_index]++; // add kills to killer's team - if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(player->GetTeam()))+ uint32 team = GetPlayerTeam(player->GetGUID());+ if(!team) team = player->GetTeam();++ if(m_TeamKills[killer_team_index] >= GetPlayersCountByTeam(team)) { // all opponents killed- EndBattleGround(killer->GetTeam());+ EndBattleGround(killer_team); } } Index: src/game/BattleGroundRL.h===================================================================--- src/game/BattleGroundRL.h (revision 5116)+++ src/game/BattleGroundRL.h (working copy)@@ -51,7 +51,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/BattleGroundWS.cpp===================================================================--- src/game/BattleGroundWS.cpp (revision 5116)+++ 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())@@ -503,12 +506,13 @@ m_FlagState[BG_TEAM_HORDE] = BG_WS_FLAG_STATE_ON_BASE; m_TeamScores[BG_TEAM_ALLIANCE] = 0; m_TeamScores[BG_TEAM_HORDE] = 0;-+/* currently crashes the server, must find out the problem, till then, let the instance unloading solve this 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 5116)+++ src/game/BattleGroundWS.h (working copy)@@ -97,7 +97,7 @@ BG_WS_FLAG_STATE_ON_GROUND = 3 }; -enum BattleGroundGaveyardsWS+enum BattleGroundGraveyardsWS { WS_GRAVEYARD_MAIN_ALLIANCE = 771, WS_GRAVEYARD_MAIN_HORDE = 772@@ -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 5116)+++ src/game/Chat.cpp (working copy)@@ -385,6 +385,7 @@ { "movegens", SEC_ADMINISTRATOR, &ChatHandler::HandleMovegensCommand, "", NULL }, { "cast", SEC_ADMINISTRATOR, &ChatHandler::HandleCastCommand, "", NULL }, { "castback", SEC_ADMINISTRATOR, &ChatHandler::HandleCastBackCommand, "", 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 5116)+++ src/game/Chat.h (working copy)@@ -322,6 +322,7 @@ bool HandleWritePDumpCommand(const char *args); bool HandleCastCommand(const char *args); bool HandleCastBackCommand(const char *args);+ bool HandleFlushArenaPointsCommand(const char *args); //! Development Commands bool HandleSetValue(const char* args);Index: src/game/GroupHandler.cpp===================================================================--- src/game/GroupHandler.cpp (revision 5116)+++ src/game/GroupHandler.cpp (working copy)@@ -26,6 +26,8 @@ #include "ObjectMgr.h" #include "Player.h" #include "Group.h"+#include "Chat.h"+#include "Language.h" #include "ObjectAccessor.h" /* differeces from off:@@ -257,6 +259,15 @@ SendPartyResult(PARTY_OP_LEAVE, name, PARTY_RESULT_NOT_IN_YOUR_PARTY); return; }++ if(player && player->InBattleGround())+ {+ WorldPacket data;+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, LANG_BG_CANNOT_IN_BG, NULL);+ SendPacket(&data);+ + return;+ } /********************/ // everything's fine, do it@@ -295,7 +306,15 @@ /** error handling **/ /********************/+ if(GetPlayer() && GetPlayer()->InBattleGround())+ {+ WorldPacket data;+ ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, LANG_BG_CANNOT_IN_BG, NULL);+ SendPacket(&data); + return;+ }+ // everything's fine, do it SendPartyResult(PARTY_OP_LEAVE, GetPlayer()->GetName(), PARTY_RESULT_OK); Index: src/game/Language.h===================================================================--- src/game/Language.h (revision 5116)+++ src/game/Language.h (working copy)@@ -535,6 +535,11 @@ #define LANG_INVISIBLE_INVISIBLE "You are now invisible." #define LANG_INVISIBLE_VISIBLE "You are now visible." +#define LANG_BG_CANNOT_IN_BG "You can't do that right now."+#define LANG_BG_GROUP_TOO_LARGE "Your group is too large for this battleground. Please regroup to join."+#define LANG_ARENA_GROUP_TOO_LARGE "Your group is too large for this arena. Please regroup to join."+#define LANG_ARENA_YOUR_TEAM_ONLY "Your group has members not in your arena team. Please regroup to join."+ #define LANG_BG_A_WINS "The Alliance wins!" #define LANG_BG_H_WINS "The Horde wins!" #define LANG_BG_WS_ONE_MINUTE "The battle for Warsong Gulch begins in 1 minute."@@ -568,6 +573,8 @@ #define LANG_BG_AB_A_NEAR_VICTORY "The Alliance has gathered $1776W resources, and is near victory!" #define LANG_BG_AB_H_NEAR_VICTORY "The Horde has gathered $1777W resources, and is near victory!" +#define LANG_ARENA_GOLD_WINS "The Gold Team wins!"+#define LANG_ARENA_GREEN_WINS "The Green Team wins!" #define LANG_ARENA_ONE_TOOLOW "You must be level %u to form an arena team" #define LANG_ARENA_ONE_MINUTE "One minute until the Arena battle begins!" #define LANG_ARENA_THIRTY_SECONDS "Thirty seconds until the Arena battle begins!"Index: src/game/Level3.cpp===================================================================--- src/game/Level3.cpp (revision 5116)+++ src/game/Level3.cpp (working copy)@@ -42,6 +42,7 @@ #include "SkillExtraItems.h" #include "SystemConfig.h" #include "Config/ConfigEnv.h"+#include "ArenaTeam.h" //reload commands bool ChatHandler::HandleReloadCommand(const char* arg)@@ -4616,3 +4617,52 @@ return true; }++bool ChatHandler::HandleFlushArenaPointsCommand(const char * /*args*/)+{+ 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);+ }+ 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(a.`points_to_add`) FROM `arena_team_member` WHERE a.`guid` = b.`guid` GROUP BY a.`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(a.`points_to_add`) FROM `arena_team_member` WHERE a.`guid` = b.`guid` GROUP BY a.`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);+ 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);+ return true;+}Index: src/game/Map.cpp===================================================================--- src/game/Map.cpp (revision 5116)+++ src/game/Map.cpp (working copy)@@ -270,6 +270,8 @@ else i_data = NULL; + i_unloadmap = sWorld.getConfig(CONFIG_GRID_UNLOAD);+ i_Players.clear(); } @@ -392,7 +394,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 NGridTypeIndex: src/game/Map.h===================================================================--- src/game/Map.h (revision 5116)+++ src/game/Map.h (working copy)@@ -148,6 +148,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); virtual void UnloadAll();@@ -206,7 +208,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)); }@@ -294,6 +296,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 5116)+++ 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,12 @@ // 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);+ map->SetUnloadMap(GetUnloadMap()); m_InstancedMaps[InstanceId] = map; } }Index: src/game/MapManager.cpp===================================================================--- src/game/MapManager.cpp (revision 5116)+++ 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 5116)+++ src/game/MovementHandler.cpp (working copy)@@ -79,17 +79,21 @@ { if(bg->GetMapId() == _player->GetMapId()) // we teleported to bg {- if(!bg->GetBgRaid(_player->GetTeam())) // first player joined+ uint32 team = bg->GetPlayerTeam(_player->GetGUID());+ if(!team)+ team = _player->GetTeam();+ _player->RemoveFromGroup();+ 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()); } } }@@ -485,3 +489,5 @@ _player->SummonIfPossible(); } ++Index: src/game/PetitionsHandler.cpp===================================================================--- src/game/PetitionsHandler.cpp (revision 5116)+++ 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,9 @@ uint32 type = 0; if(pCreature->isTabardDesigner()) {+ if(_player->GetGuildId())+ return;+ charterid = GUILD_CHARTER; cost = GUILD_CHARTER_COST; type = 9;@@ -188,10 +188,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 +226,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 +233,17 @@ // 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(type==9 && _player->GetGuildId())+ return; result = CharacterDatabase.PQuery("SELECT `playerguid` FROM `petition_sign` WHERE `petitionguid` = '%u'", petitionguid_low); @@ -317,13 +338,14 @@ { data << uint32(9); data << uint32(9);+ data << uint32(0); } else { data << type-1; data << type-1;+ data << type; }- data << uint32(0); // 4 data << uint32(0); // 5 data << uint32(0); // 6 data << uint32(0); // 7@@ -463,7 +485,7 @@ //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 +660,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 +770,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 +784,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 +858,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 5116)+++ src/game/Player.cpp (working copy)@@ -104,6 +104,9 @@ m_zoneUpdateId = 0; m_zoneUpdateTimer = 0; + m_areaUpdateId = 0;+ m_areaUpdateTimer = 0;+ m_dismountCost = 0; m_nextSave = sWorld.getConfig(CONFIG_INTERVAL_SAVE);@@ -937,6 +940,20 @@ m_zoneUpdateTimer -= p_time; } + if (m_areaUpdateTimer > 0)+ {+ if(p_time >= m_areaUpdateTimer)+ {+ uint32 newarea = GetAreaId();+ if( m_areaUpdateId != newarea )+ UpdateArea(newarea);+ else+ m_areaUpdateTimer = ZONE_UPDATE_INTERVAL;+ }+ else+ m_areaUpdateTimer -= p_time;+ }+ if (isAlive()) { RegenerateAll();@@ -2726,6 +2743,27 @@ removeSpell(itr->second.spell); } +void Player::RemoveArenaSpellCooldowns()+{+ SpellCooldowns::iterator itr, next;+ for(itr = m_spellCooldowns.begin();itr != m_spellCooldowns.end(); itr = next)+ {+ next = itr;+ ++next;+ SpellEntry const * entry = sSpellStore.LookupEntry(itr->first);+ if( entry && + (entry->RecoveryTime <= 15 * 60000) &&+ (entry->CategoryRecoveryTime <= 15 * 60000))+ {+ WorldPacket data(SMSG_CLEAR_COOLDOWN, (4+8+4));+ data << uint32(itr->first);+ data << GetGUID();+ GetSession()->SendPacket(&data);+ m_spellCooldowns.erase(itr);+ }+ }+}+ void Player::RemoveAllSpellCooldown() { if(!m_spellCooldowns.empty())@@ -5665,8 +5703,27 @@ return zone; } +void Player::UpdateArea(uint32 newArea)+{+ m_areaUpdateId = newArea;+ m_areaUpdateTimer = ZONE_UPDATE_INTERVAL;++ AreaTableEntry const* area = GetAreaEntryByAreaID(newArea);++ if(area && (area->flags & 0x80))+ {+ SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);+ }+ else+ {+ if(HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP) && !sWorld.IsFFAPvPRealm())+ RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_FFA_PVP);+ }+}+ void Player::UpdateZone(uint32 newZone) {+ UpdateArea(GetAreaId()); m_zoneUpdateId = newZone; m_zoneUpdateTimer = ZONE_UPDATE_INTERVAL; @@ -8627,6 +8684,12 @@ pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC) return EQUIP_ERR_NOT_IN_COMBAT; + 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 @@ -8760,6 +8823,12 @@ pProto->SubClass != ITEM_SUBCLASS_ARMOR_SHIELD && pProto->InventoryType != INVTYPE_RELIC ) return EQUIP_ERR_NOT_IN_COMBAT; + 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; @@ -9842,6 +9911,52 @@ } } +void Player::DestroyConjuredItems( bool update )+{+ 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)@@ -14688,10 +14803,14 @@ 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. { Field *fields = result->Fetch(); uint64 ownerguid = MAKE_GUID(fields[0].GetUInt32(), HIGHGUID_PLAYER);@@ -14706,15 +14825,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(); } @@ -15970,7 +16097,7 @@ bool Player::GetBGAccessByLevel(uint32 bgTypeId) const {- BattleGround *bg = sBattleGroundMgr.GetBattleGround(bgTypeId);+ BattleGround *bg = sBattleGroundMgr.GetBattleGroundTemplate(bgTypeId); if(!bg) return false; Index: src/game/Player.h===================================================================--- src/game/Player.h (revision 5116)+++ src/game/Player.h (working copy)@@ -1023,6 +1023,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 );@@ -1332,6 +1333,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();@@ -1362,6 +1364,7 @@ PvPInfo pvpInfo; void UpdatePvP(bool state, bool ovrride=false); void UpdateZone(uint32 newZone);+ void UpdateArea(uint32 newArea); void UpdatePvPFlag(time_t currTime); /** todo: -maybe move UpdateDuelFlag+DuelComplete to independent DuelHandler.. **/@@ -1683,9 +1686,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;@@ -1830,6 +1835,7 @@ */ uint32 m_bgBattleGroundQueueID[PLAYER_MAX_BATTLEGROUND_QUEUES]; uint32 m_bgEntryPointMap;+ uint32 m_bgEntryPointInstanceId; float m_bgEntryPointX; float m_bgEntryPointY; float m_bgEntryPointZ;@@ -1995,6 +2001,9 @@ uint32 m_zoneUpdateId; uint32 m_zoneUpdateTimer; + uint32 m_areaUpdateId;+ uint32 m_areaUpdateTimer;+ uint32 m_deathTimer; time_t m_resurrectingSicknessExpire; Index: src/game/Spell.cpp===================================================================--- src/game/Spell.cpp (revision 5116)+++ src/game/Spell.cpp (working copy)@@ -2667,6 +2667,14 @@ if((m_spellInfo->AttributesEx3 & 0x800) != 0) return SPELL_FAILED_ONLY_BATTLEGROUNDS; + 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->GetAreaId(); Index: src/game/SpellHandler.cpp===================================================================--- src/game/SpellHandler.cpp (revision 5116)+++ src/game/SpellHandler.cpp (working copy)@@ -66,6 +66,14 @@ return; } + 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)@@ -466,7 +474,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)@@ -481,7 +490,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 5116)+++ src/game/Unit.cpp (working copy)@@ -591,8 +591,11 @@ // 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 ); }@@ -3799,6 +3802,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 5116)+++ src/game/Unit.h (working copy)@@ -825,6 +825,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/WorldSession.cpp===================================================================--- src/game/WorldSession.cpp (revision 5116)+++ src/game/WorldSession.cpp (working copy)@@ -656,7 +656,7 @@ { for (int i=0; i < PLAYER_MAX_BATTLEGROUND_QUEUES; i++) {- int32 bgTypeId = _player->GetBattleGroundQueueId(i);+ int32 bgTypeId = sBattleGroundMgr.BGQueueTypeId(_player->GetBattleGroundQueueId(i)); if (bgTypeId != 0) { _player->RemoveBattleGroundQueueId(bgTypeId);