bucur35

Untitled

Nov 2nd, 2012
135
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 75.31 KB | None | 0 0
  1. /*
  2. * Copyright (C) 2011-2012 Project SkyFire <http://www.projectskyfire.org/>
  3. * Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
  4. * Copyright (C) 2005-2012 MaNGOS <http://getmangos.com/>
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 3 of the License, or (at your
  9. * option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  14. * more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19.  
  20. #include "Player.h"
  21. #include "ObjectMgr.h"
  22. #include "ArenaTeamMgr.h"
  23. #include "World.h"
  24. #include "WorldPacket.h"
  25. #include "ArenaTeam.h"
  26. #include "Battleground.h"
  27. #include "BattlegroundMgr.h"
  28. #include "Creature.h"
  29. #include "Formulas.h"
  30. #include "GridNotifiersImpl.h"
  31. #include "Group.h"
  32. #include "Language.h"
  33. #include "MapManager.h"
  34. #include "Object.h"
  35. #include "SpellAuras.h"
  36. #include "SpellAuraEffects.h"
  37. #include "Util.h"
  38.  
  39. namespace SkyFire
  40. {
  41.     class BattlegroundChatBuilder
  42.     {
  43.         public:
  44.             BattlegroundChatBuilder(ChatMsg msgtype, int32 textId, Player const* source, va_list* args = NULL) : _msgtype(msgtype), _textId(textId), _source(source), _args(args) { }
  45.  
  46.             void operator()(WorldPacket& data, LocaleConstant loc_idx)
  47.             {
  48.                 char const* text = sObjectMgr->GetSkyFireString(_textId, loc_idx);
  49.                 if (_args)
  50.                 {
  51.                     // we need copy va_list before use or original va_list will corrupted
  52.                     va_list ap;
  53.                     va_copy(ap, *_args);
  54.  
  55.                     char str[2048];
  56.                     vsnprintf(str, 2048, text, ap);
  57.                     va_end(ap);
  58.  
  59.                     do_helper(data, &str[0]);
  60.                 }
  61.                 else
  62.                     do_helper(data, text);
  63.             }
  64.  
  65.         private:
  66.             void do_helper(WorldPacket& data, char const* text)
  67.             {
  68.                 uint64 target_guid = _source ? _source->GetGUID() : 0;
  69.  
  70.                 data << uint8 (_msgtype);
  71.                 data << uint32(LANG_UNIVERSAL);
  72.                 data << uint64(target_guid); // there 0 for BG messages
  73.                 data << uint32(0); // can be chat msg group or something
  74.                 data << uint64(target_guid);
  75.                 data << uint32(strlen(text) + 1);
  76.                 data << text;
  77.                 data << uint8 (_source ? _source->GetChatTag() : 0);
  78.             }
  79.  
  80.             ChatMsg _msgtype;
  81.             int32 _textId;
  82.             Player const* _source;
  83.             va_list* _args;
  84.     };
  85.  
  86.     class Battleground2ChatBuilder
  87.     {
  88.         public:
  89.             Battleground2ChatBuilder(ChatMsg msgtype, int32 textId, Player const* source, int32 arg1, int32 arg2) : _msgtype(msgtype), _textId(textId), _source(source), _arg1(arg1), _arg2(arg2) {}
  90.  
  91.             void operator()(WorldPacket& data, LocaleConstant loc_idx)
  92.             {
  93.                 char const* text = sObjectMgr->GetSkyFireString(_textId, loc_idx);
  94.                 char const* arg1str = _arg1 ? sObjectMgr->GetSkyFireString(_arg1, loc_idx) : "";
  95.                 char const* arg2str = _arg2 ? sObjectMgr->GetSkyFireString(_arg2, loc_idx) : "";
  96.  
  97.                 char str[2048];
  98.                 snprintf(str, 2048, text, arg1str, arg2str);
  99.  
  100.                 uint64 target_guid = _source ? _source->GetGUID() : 0;
  101.  
  102.                 data << uint8 (_msgtype);
  103.                 data << uint32(LANG_UNIVERSAL);
  104.                 data << uint64(target_guid); // there 0 for BG messages
  105.                 data << uint32(0); // can be chat msg group or something
  106.                 data << uint64(target_guid);
  107.                 data << uint32(strlen(str) + 1);
  108.                 data << str;
  109.                 data << uint8 (_source ? _source->GetChatTag() : uint8(0));
  110.             }
  111.  
  112.         private:
  113.             ChatMsg _msgtype;
  114.             int32 _textId;
  115.             Player const* _source;
  116.             int32 _arg1;
  117.             int32 _arg2;
  118.     };
  119. } // namespace SkyFire
  120.  
  121. template<class Do>
  122. void Battleground::BroadcastWorker(Do& _do)
  123. {
  124.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  125.         if (Player* player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)))
  126.             _do(player);
  127. }
  128.  
  129. Battleground::Battleground()
  130. {
  131.     _TypeID = BATTLEGROUND_TYPE_NONE;
  132.     _RandomTypeID = BATTLEGROUND_TYPE_NONE;
  133.     _InstanceID = 0;
  134.     _Status = STATUS_NONE;
  135.     _ClientInstanceID = 0;
  136.     _EndTime = 0;
  137.     _LastResurrectTime = 0;
  138.     _BracketId = BG_BRACKET_ID_FIRST;
  139.     _InvitedAlliance = 0;
  140.     _InvitedHorde = 0;
  141.     _ArenaType = 0;
  142.     _IsArena = false;
  143.     _Winner = 2;
  144.     _StartTime = 0;
  145.     _ResetStatTimer = 0;
  146.     _ValidStartPositionTimer = 0;
  147.     _Events = 0;
  148.     _IsRated = false;
  149.     _BuffChange = false;
  150.     _IsRandom = false;
  151.     _Name = "";
  152.     _LevelMin = 0;
  153.     _LevelMax = 0;
  154.     _InBGFreeSlotQueue = false;
  155.     _SetDeleteThis = false;
  156.  
  157.     _MaxPlayersPerTeam = 0;
  158.     _MaxPlayers = 0;
  159.     _MinPlayersPerTeam = 0;
  160.     _MinPlayers = 0;
  161.  
  162.     _MapId = 0;
  163.     _Map = NULL;
  164.  
  165.     _TeamStartLocX[BG_TEAM_ALLIANCE] = 0;
  166.     _TeamStartLocX[BG_TEAM_HORDE] = 0;
  167.  
  168.     _TeamStartLocY[BG_TEAM_ALLIANCE] = 0;
  169.     _TeamStartLocY[BG_TEAM_HORDE] = 0;
  170.  
  171.     _TeamStartLocZ[BG_TEAM_ALLIANCE] = 0;
  172.     _TeamStartLocZ[BG_TEAM_HORDE] = 0;
  173.  
  174.     _TeamStartLocO[BG_TEAM_ALLIANCE] = 0;
  175.     _TeamStartLocO[BG_TEAM_HORDE] = 0;
  176.  
  177.     _ArenaTeamIds[BG_TEAM_ALLIANCE] = 0;
  178.     _ArenaTeamIds[BG_TEAM_HORDE] = 0;
  179.  
  180.     _StartMaxDist = 0.0f;
  181.  
  182.     _ArenaTeamRatingChanges[BG_TEAM_ALLIANCE] = 0;
  183.     _ArenaTeamRatingChanges[BG_TEAM_HORDE] = 0;
  184.  
  185.     _BgRaids[BG_TEAM_ALLIANCE] = NULL;
  186.     _BgRaids[BG_TEAM_HORDE] = NULL;
  187.  
  188.     _PlayersCount[BG_TEAM_ALLIANCE] = 0;
  189.     _PlayersCount[BG_TEAM_HORDE] = 0;
  190.  
  191.     _TeamScores[BG_TEAM_ALLIANCE] = 0;
  192.     _TeamScores[BG_TEAM_HORDE] = 0;
  193.  
  194.     _TeamScores[BG_TEAM_ALLIANCE] = 0;
  195.     _TeamScores[BG_TEAM_HORDE] = 0;
  196.  
  197.     _PrematureCountDown = false;
  198.  
  199.     _HonorMode = BG_NORMAL;
  200.  
  201.     StartDelayTimes[BG_STARTING_EVENT_FIRST] = BG_START_DELAY_2M;
  202.     StartDelayTimes[BG_STARTING_EVENT_SECOND] = BG_START_DELAY_1M;
  203.     StartDelayTimes[BG_STARTING_EVENT_THIRD] = BG_START_DELAY_30S;
  204.     StartDelayTimes[BG_STARTING_EVENT_FOURTH] = BG_START_DELAY_NONE;
  205.     //we must set to some default existing values
  206.     StartMessageIds[BG_STARTING_EVENT_FIRST] = LANG_BG_WS_START_TWO_MINUTES;
  207.     StartMessageIds[BG_STARTING_EVENT_SECOND] = LANG_BG_WS_START_ONE_MINUTE;
  208.     StartMessageIds[BG_STARTING_EVENT_THIRD] = LANG_BG_WS_START_HALF_MINUTE;
  209.     StartMessageIds[BG_STARTING_EVENT_FOURTH] = LANG_BG_WS_HAS_BEGUN;
  210. }
  211.  
  212. Battleground::~Battleground()
  213. {
  214.     // remove objects and creatures
  215.     // (this is done automatically in mapmanager update, when the instance is reset after the reset time)
  216.     uint32 size = uint32(BgCreatures.size());
  217.     for (uint32 i = 0; i < size; ++i)
  218.         DelCreature(i);
  219.  
  220.     size = uint32(BgObjects.size());
  221.     for (uint32 i = 0; i < size; ++i)
  222.         DelObject(i);
  223.  
  224.     sBattlegroundMgr->RemoveBattleground(GetInstanceID(), GetTypeID());
  225.     // unload map
  226.     if (_Map)
  227.     {
  228.         _Map->SetUnload();
  229.         //unlink to prevent crash, always unlink all pointer reference before destruction
  230.         _Map->SetBG(NULL);
  231.         _Map = NULL;
  232.     }
  233.     // remove from bg free slot queue
  234.     RemoveFromBGFreeSlotQueue();
  235.  
  236.     for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
  237.         delete itr->second;
  238. }
  239.  
  240. void Battleground::Update(uint32 diff)
  241. {
  242.     if (!PreUpdateImpl(diff))
  243.         return;
  244.  
  245.     if (!GetPlayersSize())
  246.     {
  247.         //BG is empty
  248.         // if there are no players invited, delete BG
  249.         // this will delete arena or bg object, where any player entered
  250.         // [[ but if you use battleground object again (more battles possible to be played on 1 instance)
  251.         // then this condition should be removed and code:
  252.         // if (!GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
  253.         // this->AddToFreeBGObjectsQueue(); // not yet implemented
  254.         // should be used instead of current
  255.         // ]]
  256.         // Battleground Template instance cannot be updated, because it would be deleted
  257.         if (!GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
  258.             _SetDeleteThis = true;
  259.         return;
  260.     }
  261.  
  262.     switch (GetStatus())
  263.     {
  264.         case STATUS_WAIT_JOIN:
  265.             if (GetPlayersSize())
  266.                 _ProcessJoin(diff);
  267.             break;
  268.         case STATUS_IN_PROGRESS:
  269.             _ProcessOfflineQueue();
  270.             // after 47 minutes without one team losing, the arena closes with no winner and no rating change
  271.             if (isArena())
  272.             {
  273.                 if (GetStartTime() >= 47*MINUTE*IN_MILLISECONDS)
  274.                 {
  275.                     UpdateArenaWorldState();
  276.                     CheckArenaAfterTimerConditions();
  277.                     return;
  278.                 }
  279.             }
  280.             else
  281.             {
  282.                 _ProcessRessurect(diff);
  283.                 if (sBattlegroundMgr->GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
  284.                     _ProcessProgress(diff);
  285.                 else if (_PrematureCountDown)
  286.                     _PrematureCountDown = false;
  287.             }
  288.             break;
  289.         case STATUS_WAIT_LEAVE:
  290.             _ProcessLeave(diff);
  291.             break;
  292.         default:
  293.             break;
  294.     }
  295.  
  296.     // Update start time and reset stats timer
  297.     _StartTime += diff;
  298.     _ResetStatTimer += diff;
  299.     _ValidStartPositionTimer += diff;
  300.  
  301.     PostUpdateImpl(diff);
  302. }
  303.  
  304. inline void Battleground::_ProcessOfflineQueue()
  305. {
  306.     // remove offline players from bg after 5 minutes
  307.     if (!_OfflineQueue.empty())
  308.     {
  309.         BattlegroundPlayerMap::iterator itr = _Players.find(*(_OfflineQueue.begin()));
  310.         if (itr != _Players.end())
  311.         {
  312.             if (itr->second.OfflineRemoveTime <= sWorld->GetGameTime())
  313.             {
  314.                 RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
  315.                 _OfflineQueue.pop_front(); // remove from offline queue
  316.                 //do not use itr for anything, because it is erased in RemovePlayerAtLeave()
  317.             }
  318.         }
  319.     }
  320. }
  321.  
  322. inline void Battleground::_ProcessRessurect(uint32 diff)
  323. {
  324.     // *********************************************************
  325.     // *** BATTLEGROUND RESSURECTION SYSTEM ***
  326.     // *********************************************************
  327.     // this should be handled by spell system
  328.     _LastResurrectTime += diff;
  329.     if (_LastResurrectTime >= RESURRECTION_INTERVAL)
  330.     {
  331.         if (GetReviveQueueSize())
  332.         {
  333.             for (std::map<uint64, std::vector<uint64> >::iterator itr = _ReviveQueue.begin(); itr != _ReviveQueue.end(); ++itr)
  334.             {
  335.                 Creature* sh = NULL;
  336.                 for (std::vector<uint64>::const_iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
  337.                 {
  338.                     Player* player = ObjectAccessor::FindPlayer(*itr2);
  339.                     if (!player)
  340.                         continue;
  341.  
  342.                     if (!sh && player->IsInWorld())
  343.                     {
  344.                         sh = player->GetMap()->GetCreature(itr->first);
  345.                         // only for visual effect
  346.                         if (sh)
  347.                             // Spirit Heal, effect 117
  348.                             sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true);
  349.                     }
  350.  
  351.                     // Resurrection visual
  352.                     player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true);
  353.                     _ResurrectQueue.push_back(*itr2);
  354.                 }
  355.                 (itr->second).clear();
  356.             }
  357.  
  358.             _ReviveQueue.clear();
  359.             _LastResurrectTime = 0;
  360.         }
  361.         else
  362.             // queue is clear and time passed, just update last resurrection time
  363.             _LastResurrectTime = 0;
  364.     }
  365.     else if (_LastResurrectTime > 500) // Resurrect players only half a second later, to see spirit heal effect on NPC
  366.     {
  367.         for (std::vector<uint64>::const_iterator itr = _ResurrectQueue.begin(); itr != _ResurrectQueue.end(); ++itr)
  368.         {
  369.             Player* player = ObjectAccessor::FindPlayer(*itr);
  370.             if (!player)
  371.                 continue;
  372.             player->ResurrectPlayer(1.0f);
  373.             player->CastSpell(player, 6962, true);
  374.             player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
  375.             sObjectAccessor->ConvertCorpseForPlayer(*itr);
  376.         }
  377.         _ResurrectQueue.clear();
  378.     }
  379. }
  380.  
  381. inline void Battleground::_ProcessProgress(uint32 diff)
  382. {
  383.     // *********************************************************
  384.     // *** BATTLEGROUND BALLANCE SYSTEM ***
  385.     // *********************************************************
  386.     // if less then minimum players are in on one side, then start premature finish timer
  387.     if (!_PrematureCountDown)
  388.     {
  389.         _PrematureCountDown = true;
  390.         _PrematureCountDownTimer = sBattlegroundMgr->GetPrematureFinishTime();
  391.     }
  392.     else if (_PrematureCountDownTimer < diff)
  393.     {
  394.         // time's up!
  395.         uint32 winner = 0;
  396.         if (GetPlayersCountByTeam(ALLIANCE) >= GetMinPlayersPerTeam())
  397.             winner = ALLIANCE;
  398.         else if (GetPlayersCountByTeam(HORDE) >= GetMinPlayersPerTeam())
  399.             winner = HORDE;
  400.  
  401.         EndBattleground(winner);
  402.         _PrematureCountDown = false;
  403.     }
  404.     else if (!sBattlegroundMgr->isTesting())
  405.     {
  406.         uint32 newtime = _PrematureCountDownTimer - diff;
  407.         // announce every minute
  408.         if (newtime > (MINUTE * IN_MILLISECONDS))
  409.         {
  410.             if (newtime / (MINUTE * IN_MILLISECONDS) != _PrematureCountDownTimer / (MINUTE * IN_MILLISECONDS))
  411.                 PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING, CHAT_MSG_SYSTEM, NULL, (uint32)(_PrematureCountDownTimer / (MINUTE * IN_MILLISECONDS)));
  412.         }
  413.         else
  414.         {
  415.             //announce every 15 seconds
  416.             if (newtime / (15 * IN_MILLISECONDS) != _PrematureCountDownTimer / (15 * IN_MILLISECONDS))
  417.                 PSendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS, CHAT_MSG_SYSTEM, NULL, (uint32)(_PrematureCountDownTimer / IN_MILLISECONDS));
  418.         }
  419.         _PrematureCountDownTimer = newtime;
  420.     }
  421. }
  422.  
  423. inline void Battleground::_ProcessJoin(uint32 diff)
  424. {
  425.     // *********************************************************
  426.     // *** BATTLEGROUND STARTING SYSTEM ***
  427.     // *********************************************************
  428.     ModifyStartDelayTime(diff);
  429.  
  430.     if (_ResetStatTimer > 5000)
  431.     {
  432.         _ResetStatTimer = 0;
  433.         for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
  434.             if (Player* player = ObjectAccessor::FindPlayer(itr->first))
  435.                 player->ResetAllPowers();
  436.     }
  437.  
  438.     if (!(_Events & BG_STARTING_EVENT_1))
  439.     {
  440.         _Events |= BG_STARTING_EVENT_1;
  441.  
  442.         if (!FindBgMap())
  443.         {
  444.             sLog->outError("Battleground::_ProcessJoin: map (map id: %u, instance id: %u) is not created!", _MapId, _InstanceID);
  445.             EndNow();
  446.             return;
  447.         }
  448.  
  449.         // Setup here, only when at least one player has ported to the map
  450.         if (!SetupBattleground())
  451.         {
  452.             EndNow();
  453.             return;
  454.         }
  455.  
  456.         StartingEventCloseDoors();
  457.         SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FIRST]);
  458.         // First start warning - 2 or 1 minute
  459.         SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_FIRST], CHAT_MSG_BG_SYSTEM_NEUTRAL);
  460.     }
  461.     // After 1 minute or 30 seconds, warning is signalled
  462.     else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_SECOND] && !(_Events & BG_STARTING_EVENT_2))
  463.     {
  464.         _Events |= BG_STARTING_EVENT_2;
  465.         SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_SECOND], CHAT_MSG_BG_SYSTEM_NEUTRAL);
  466.     }
  467.     // After 30 or 15 seconds, warning is signalled
  468.     else if (GetStartDelayTime() <= StartDelayTimes[BG_STARTING_EVENT_THIRD] && !(_Events & BG_STARTING_EVENT_3))
  469.     {
  470.         _Events |= BG_STARTING_EVENT_3;
  471.         SendMessageToAll(StartMessageIds[BG_STARTING_EVENT_THIRD], CHAT_MSG_BG_SYSTEM_NEUTRAL);
  472.     }
  473.     // Delay expired (after 2 or 1 minute)
  474.     else if (GetStartDelayTime() <= 0 && !(_Events & BG_STARTING_EVENT_4))
  475.     {
  476.         _Events |= BG_STARTING_EVENT_4;
  477.  
  478.         StartingEventOpenDoors();
  479.  
  480.         SendWarningToAll(StartMessageIds[BG_STARTING_EVENT_FOURTH]);
  481.         SetStatus(STATUS_IN_PROGRESS);
  482.         SetStartDelayTime(StartDelayTimes[BG_STARTING_EVENT_FOURTH]);
  483.  
  484.         // Remove preparation
  485.         if (isArena())
  486.         {
  487.             // TODO : add arena sound PlaySoundToAll(SOUND_ARENA_START);
  488.             for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
  489.                 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
  490.                 {
  491.                     // BG Status packet
  492.                     WorldPacket status;
  493.                     BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(_TypeID, GetArenaType());
  494.                     uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId);
  495.                     sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, queueSlot, STATUS_IN_PROGRESS, 0, GetStartTime(), GetArenaType());
  496.                     player->GetSession()->SendPacket(&status);
  497.  
  498.                     player->RemoveAurasDueToSpell(SPELL_ARENA_PREPARATION);
  499.                     player->ResetAllPowers();
  500.                     // remove auras with duration lower than 30s
  501.                     Unit::AuraApplicationMap & auraMap = player->GetAppliedAuras();
  502.                     for (Unit::AuraApplicationMap::iterator iter = auraMap.begin(); iter != auraMap.end();)
  503.                     {
  504.                         AuraApplication * aurApp = iter->second;
  505.                         Aura* aura = aurApp->GetBase();
  506.                         if (!aura->IsPermanent()
  507.                             && aura->GetDuration() <= 30*IN_MILLISECONDS
  508.                             && aurApp->IsPositive()
  509.                             && (!(aura->GetSpellInfo()->Attributes & SPELL_ATTR0_UNAFFECTED_BY_INVULNERABILITY))
  510.                             && (!aura->HasEffectType(SPELL_AURA_MOD_INVISIBILITY)))
  511.                             player->RemoveAura(iter);
  512.                         else
  513.                             ++iter;
  514.                     }
  515.                 }
  516.  
  517.             CheckArenaWinConditions();
  518.         }
  519.         else
  520.         {
  521.             PlaySoundToAll(SOUND_BG_START);
  522.  
  523.             for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
  524.                 if (Player* player = ObjectAccessor::FindPlayer(itr->first))
  525.                 {
  526.                     player->RemoveAurasDueToSpell(SPELL_PREPARATION);
  527.                     player->ResetAllPowers();
  528.                 }
  529.             // Announce BG starting
  530.             if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE))
  531.                 sWorld->SendWorldText(LANG_BG_STARTED_ANNOUNCE_WORLD, GetName(), GetMinLevel(), GetMaxLevel());
  532.         }
  533.     }
  534.  
  535.     // Find if the player left our start zone; if so, teleport it back
  536.     if (_ValidStartPositionTimer > 1000)
  537.     {
  538.         _ValidStartPositionTimer = 0;
  539.         float maxDist = GetStartMaxDist();
  540.         if (maxDist > 0.0f)
  541.         {
  542.             for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
  543.             {
  544.                 if (Player *player = ObjectAccessor::FindPlayer(itr->first))
  545.                 {
  546.                     float x, y, z, o;
  547.                     uint32 team = player->GetBGTeam();
  548.                     GetTeamStartLoc(team, x, y, z, o);
  549.  
  550.                     float dist = player->GetDistance(x, y, z);
  551.  
  552.                     if (dist >= maxDist)
  553.                     {
  554.                         sLog->outError("BATTLEGROUND: Sending %s back to start location (map: %u) (possible exploit)", player->GetName(), GetMapId());
  555.                         player->TeleportTo(GetMapId(), x, y, z, o);
  556.                     }
  557.                 }
  558.             }
  559.         }
  560.     }
  561. }
  562.  
  563. inline void Battleground::_ProcessLeave(uint32 diff)
  564. {
  565.     // *********************************************************
  566.     // *** BATTLEGROUND ENDING SYSTEM ***
  567.     // *********************************************************
  568.     // remove all players from battleground after 2 minutes
  569.     _EndTime -= diff;
  570.     if (_EndTime <= 0)
  571.     {
  572.         _EndTime = 0;
  573.         BattlegroundPlayerMap::iterator itr, next;
  574.         for (itr = _Players.begin(); itr != _Players.end(); itr = next)
  575.         {
  576.             next = itr;
  577.             ++next;
  578.             //itr is erased here!
  579.             RemovePlayerAtLeave(itr->first, true, true);// remove player from BG
  580.             // do not change any battleground's private variables
  581.         }
  582.     }
  583. }
  584.  
  585. inline Player* Battleground::_GetPlayer(uint64 guid, bool offlineRemove, const char* context) const
  586. {
  587.     Player* player = NULL;
  588.     if (!offlineRemove)
  589.     {
  590.         player = ObjectAccessor::FindPlayer(guid);
  591.         if (!player)
  592.             sLog->outError("Battleground::%s: player (GUID: %u) not found for BG (map: %u, instance id: %u)!",
  593.                 context, GUID_LOPART(guid), _MapId, _InstanceID);
  594.     }
  595.     return player;
  596. }
  597.  
  598. inline Player* Battleground::_GetPlayer(BattlegroundPlayerMap::iterator itr, const char* context)
  599. {
  600.     return _GetPlayer(itr->first, itr->second.OfflineRemoveTime, context);
  601. }
  602.  
  603. inline Player* Battleground::_GetPlayer(BattlegroundPlayerMap::const_iterator itr, const char* context) const
  604. {
  605.     return _GetPlayer(itr->first, itr->second.OfflineRemoveTime, context);
  606. }
  607.  
  608. inline Player* Battleground::_GetPlayerForTeam(uint32 teamId, BattlegroundPlayerMap::const_iterator itr, const char* context) const
  609. {
  610.     Player* player = _GetPlayer(itr, context);
  611.     if (player)
  612.     {
  613.         uint32 team = itr->second.Team;
  614.         if (!team)
  615.             team = player->GetTeam();
  616.         if (team != teamId)
  617.             player = NULL;
  618.     }
  619.     return player;
  620. }
  621.  
  622. void Battleground::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
  623. {
  624.     BattlegroundTeamId idx = GetTeamIndexByTeamId(TeamID);
  625.     _TeamStartLocX[idx] = X;
  626.     _TeamStartLocY[idx] = Y;
  627.     _TeamStartLocZ[idx] = Z;
  628.     _TeamStartLocO[idx] = O;
  629. }
  630.  
  631. void Battleground::SendPacketToAll(WorldPacket* packet)
  632. {
  633.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  634.         if (Player* player = _GetPlayer(itr, "SendPacketToAll"))
  635.             player->GetSession()->SendPacket(packet);
  636. }
  637.  
  638. void Battleground::SendPacketToTeam(uint32 TeamID, WorldPacket* packet, Player* sender, bool self)
  639. {
  640.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  641.         if (Player* player = _GetPlayerForTeam(TeamID, itr, "SendPacketToTeam"))
  642.             if (self || sender != player)
  643.                 player->GetSession()->SendPacket(packet);
  644. }
  645.  
  646. void Battleground::PlaySoundToAll(uint32 SoundID)
  647. {
  648.     WorldPacket data;
  649.     sBattlegroundMgr->BuildPlaySoundPacket(&data, SoundID);
  650.     SendPacketToAll(&data);
  651. }
  652.  
  653. void Battleground::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
  654. {
  655.     WorldPacket data;
  656.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  657.         if (Player* player = _GetPlayerForTeam(TeamID, itr, "PlaySoundToTeam"))
  658.         {
  659.             sBattlegroundMgr->BuildPlaySoundPacket(&data, SoundID);
  660.             player->GetSession()->SendPacket(&data);
  661.         }
  662. }
  663.  
  664. void Battleground::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
  665. {
  666.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  667.         if (Player* player = _GetPlayerForTeam(TeamID, itr, "CastSpellOnTeam"))
  668.             player->CastSpell(player, SpellID, true);
  669. }
  670.  
  671. void Battleground::RemoveAuraOnTeam(uint32 SpellID, uint32 TeamID)
  672. {
  673.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  674.         if (Player* player = _GetPlayerForTeam(TeamID, itr, "RemoveAuraOnTeam"))
  675.             player->RemoveAura(SpellID);
  676. }
  677.  
  678. void Battleground::YellToAll(Creature* creature, const char* text, uint32 language)
  679. {
  680.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  681.         if (Player* player = _GetPlayer(itr, "YellToAll"))
  682.         {
  683.             WorldPacket data(SMSG_MESSAGECHAT, 200);
  684.             creature->BuildMonsterChat(&data, CHAT_MSG_MONSTER_YELL, text, language, creature->GetName(), itr->first);
  685.             player->GetSession()->SendPacket(&data);
  686.         }
  687. }
  688.  
  689. void Battleground::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
  690. {
  691.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  692.         if (Player* player = _GetPlayerForTeam(TeamID, itr, "RewardHonorToTeam"))
  693.             UpdatePlayerScore(player, SCORE_BONUS_HONOR, Honor);
  694. }
  695.  
  696. void Battleground::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
  697. {
  698.     if (FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id))
  699.         for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  700.             if (Player* player = _GetPlayerForTeam(TeamID, itr, "RewardReputationToTeam"))
  701.                 player->GetReputationMgr().ModifyReputation(factionEntry, Reputation);
  702. }
  703.  
  704. void Battleground::UpdateWorldState(uint32 Field, uint32 Value)
  705. {
  706.     WorldPacket data;
  707.     sBattlegroundMgr->BuildUpdateWorldStatePacket(&data, Field, Value);
  708.     SendPacketToAll(&data);
  709. }
  710.  
  711. void Battleground::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player* Source)
  712. {
  713.     WorldPacket data;
  714.     sBattlegroundMgr->BuildUpdateWorldStatePacket(&data, Field, Value);
  715.     Source->GetSession()->SendPacket(&data);
  716. }
  717.  
  718. void Battleground::EndBattleground(uint32 winner)
  719. {
  720.     RemoveFromBGFreeSlotQueue();
  721.  
  722.     ArenaTeam* winner_arena_team = NULL;
  723.     ArenaTeam* loser_arena_team = NULL;
  724.     uint32 loser_team_rating = 0;
  725.     uint32 loser_matchmaker_rating = 0;
  726.     int32 loser_change = 0;
  727.     int32 loser_matchmaker_change = 0;
  728.     uint32 winner_team_rating = 0;
  729.     uint32 winner_matchmaker_rating = 0;
  730.     int32 winner_change = 0;
  731.     int32 winner_matchmaker_change = 0;
  732.     WorldPacket data;
  733.     int32 winmsg_id = 0;
  734.  
  735.     if (winner == ALLIANCE)
  736.     {
  737.         winmsg_id = isBattleground() ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS;
  738.  
  739.         PlaySoundToAll(SOUND_ALLIANCE_WINS); // alliance wins sound
  740.  
  741.         SetWinner(WINNER_ALLIANCE);
  742.     }
  743.     else if (winner == HORDE)
  744.     {
  745.         winmsg_id = isBattleground() ? LANG_BG_H_WINS : LANG_ARENA_GREEN_WINS;
  746.  
  747.         PlaySoundToAll(SOUND_HORDE_WINS); // horde wins sound
  748.  
  749.         SetWinner(WINNER_HORDE);
  750.     }
  751.     else
  752.     {
  753.         SetWinner(3);
  754.     }
  755.  
  756.     SetStatus(STATUS_WAIT_LEAVE);
  757.     //we must set it this way, because end time is sent in packet!
  758.     _EndTime = TIME_TO_AUTOREMOVE;
  759.  
  760.     // arena rating calculation
  761.     if (isArena() && isRated())
  762.     {
  763.         winner_arena_team = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(winner));
  764.         loser_arena_team = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(winner)));
  765.         if (winner_arena_team && loser_arena_team && winner_arena_team != loser_arena_team)
  766.         {
  767.             if (winner != WINNER_NONE)
  768.             {
  769.                 loser_team_rating = loser_arena_team->GetRating();
  770.                 loser_matchmaker_rating = GetArenaMatchmakerRating(GetOtherTeam(winner));
  771.                 winner_team_rating = winner_arena_team->GetRating();
  772.                 winner_matchmaker_rating = GetArenaMatchmakerRating(winner);
  773.                 winner_matchmaker_change = winner_arena_team->WonAgainst(winner_matchmaker_rating, loser_matchmaker_rating, winner_change);
  774.                 loser_matchmaker_change = loser_arena_team->LostAgainst(loser_matchmaker_rating, winner_matchmaker_rating, loser_change);
  775.                 sLog->outArena("match Type: %u --- Winner: old rating: %u, rating gain: %d, old MMR: %u, MMR gain: %d --- Loser: old rating: %u, rating loss: %d, old MMR: %u, MMR loss: %d ---", _ArenaType, winner_team_rating, winner_change, winner_matchmaker_rating,
  776.                     winner_matchmaker_change, loser_team_rating, loser_change, loser_matchmaker_rating, loser_matchmaker_change);
  777.                 SetArenaMatchmakerRating(winner, winner_matchmaker_rating + winner_matchmaker_change);
  778.                 SetArenaMatchmakerRating(GetOtherTeam(winner), loser_matchmaker_rating + loser_matchmaker_change);
  779.                 SetArenaTeamRatingChangeForTeam(winner, winner_change);
  780.                 SetArenaTeamRatingChangeForTeam(GetOtherTeam(winner), loser_change);
  781.                 sLog->outArena("Arena match Type: %u for Team1Id: %u - Team2Id: %u ended. WinnerTeamId: %u. Winner rating: +%d, Loser rating: %d", _ArenaType, _ArenaTeamIds[BG_TEAM_ALLIANCE], _ArenaTeamIds[BG_TEAM_HORDE], winner_arena_team->GetId(), winner_change, loser_change);
  782.                 if (sWorld->getBoolConfig(CONFIG_ARENA_LOG_EXTENDED_INFO))
  783.                     for (Battleground::BattlegroundScoreMap::const_iterator itr = GetPlayerScoresBegin(); itr != GetPlayerScoresEnd(); ++itr)
  784.                         if (Player* player = ObjectAccessor::FindPlayer(itr->first))
  785.                             sLog->outArena("Statistics match Type: %u for %s (GUID: " UI64FMTD ", Team: %d, IP: %s): %u damage, %u healing, %u killing blows", _ArenaType, player->GetName(), itr->first, player->GetArenaTeamId(_ArenaType == 5 ? 2 : _ArenaType == 3), player->GetSession()->GetRemoteAddress().c_str(), itr->second->DamageDone, itr->second->HealingDone, itr->second->KillingBlows);
  786.             }
  787.             // Deduct 16 points from each teams arena-rating if there are no winners after 45+2 minutes
  788.             else
  789.             {
  790.                 SetArenaTeamRatingChangeForTeam(ALLIANCE, ARENA_TIMELIMIT_POINTS_LOSS);
  791.                 SetArenaTeamRatingChangeForTeam(HORDE, ARENA_TIMELIMIT_POINTS_LOSS);
  792.                 winner_arena_team->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS);
  793.                 loser_arena_team->FinishGame(ARENA_TIMELIMIT_POINTS_LOSS);
  794.             }
  795.         }
  796.         else
  797.         {
  798.             SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
  799.             SetArenaTeamRatingChangeForTeam(HORDE, 0);
  800.         }
  801.     }
  802.  
  803.     uint8 aliveWinners = GetAlivePlayersCountByTeam(winner);
  804.     for (BattlegroundPlayerMap::iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  805.     {
  806.         uint32 team = itr->second.Team;
  807.  
  808.         if (itr->second.OfflineRemoveTime)
  809.         {
  810.             //if rated arena match - make member lost!
  811.             if (isArena() && isRated() && winner_arena_team && loser_arena_team && winner_arena_team != loser_arena_team)
  812.             {
  813.                 if (team == winner)
  814.                     winner_arena_team->OfflineMemberLost(itr->first, loser_matchmaker_rating, winner_matchmaker_change);
  815.                 else
  816.                     loser_arena_team->OfflineMemberLost(itr->first, winner_matchmaker_rating, loser_matchmaker_change);
  817.             }
  818.             continue;
  819.         }
  820.  
  821.         Player* player = _GetPlayer(itr, "EndBattleground");
  822.         if (!player)
  823.             continue;
  824.  
  825.         // should remove spirit of redemption
  826.         if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
  827.             player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
  828.  
  829.         // Last standing - Rated 5v5 arena & be solely alive player
  830.         if (team == winner && isArena() && isRated() && GetArenaType() == ARENA_TYPE_5v5 && aliveWinners == 1 && player->isAlive())
  831.             player->CastSpell(player, SPELL_THE_LAST_STANDING, true);
  832.  
  833.         if (!player->isAlive())
  834.         {
  835.             player->ResurrectPlayer(1.0f);
  836.             player->SpawnCorpseBones();
  837.         }
  838.         else
  839.         {
  840.             //needed cause else in av some creatures will kill the players at the end
  841.             player->CombatStop();
  842.             player->getHostileRefManager().deleteReferences();
  843.         }
  844.  
  845.         //this line is obsolete - team is set ALWAYS
  846.         //if (!team) team = player->GetTeam();
  847.  
  848.         // per player calculation
  849.         if (isArena() && isRated() && winner_arena_team && loser_arena_team && winner_arena_team != loser_arena_team)
  850.         {
  851.             if (team == winner)
  852.             {
  853.                 // update achievement BEFORE personal rating update
  854.                 ArenaTeamMember* member = winner_arena_team->GetMember(player->GetGUID());
  855.                 if (member)
  856.                     player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, 1);
  857.  
  858.                 winner_arena_team->MemberWon(player, loser_matchmaker_rating, winner_matchmaker_change);
  859.  
  860.                 player->ModifyCurrency(CURRENCY_TYPE_CONQUEST_POINTS, sWorld->getIntConfig(CONFIG_ARENA_CONQUEST_POINTS_REWARD) * PLAYER_CURRENCY_PRECISION);
  861.                 player->UpdateMaxWeekRating(CP_SOURCE_ARENA, winner_arena_team->GetSlot());
  862.             }
  863.             else
  864.             {
  865.                 loser_arena_team->MemberLost(player, winner_matchmaker_rating, loser_matchmaker_change);
  866.  
  867.                 // Arena lost => reset the win_rated_arena having the "no_lose" condition
  868.                 player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA, player, ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE);
  869.             }
  870.         }
  871.  
  872.         uint32 winner_kills = player->GetRandomWinner() ? BG_REWARD_WINNER_HONOR_LAST : BG_REWARD_WINNER_HONOR_FIRST;
  873.         uint32 loser_kills = player->GetRandomWinner() ? BG_REWARD_LOSER_HONOR_LAST : BG_REWARD_LOSER_HONOR_FIRST;
  874.         uint32 winner_arena = player->GetRandomWinner() ? BG_REWARD_WINNER_ARENA_LAST : BG_REWARD_WINNER_ARENA_FIRST;
  875.  
  876.         // Reward winner team
  877.         if (team == winner)
  878.         {
  879.             if (IsRandom() || BattlegroundMgr::IsBGWeekend(GetTypeID()))
  880.             {
  881.                 UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(winner_kills));
  882.  
  883.                 if (!player->GetRandomWinner())
  884.                 {
  885.                     player->ModifyCurrency(CURRENCY_TYPE_CONQUEST_POINTS, 25 * PLAYER_CURRENCY_PRECISION);
  886.                     player->SetRandomWinner(true);
  887.                 }
  888.             }
  889.  
  890.             player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, 1);
  891.         }
  892.         else
  893.         {
  894.             if (IsRandom() || BattlegroundMgr::IsBGWeekend(GetTypeID()))
  895.                 UpdatePlayerScore(player, SCORE_BONUS_HONOR, GetBonusHonorFromKill(loser_kills));
  896.         }
  897.  
  898.         player->ResetAllPowers();
  899.         player->CombatStopWithPets(true);
  900.  
  901.         BlockMovement(player);
  902.  
  903.         sBattlegroundMgr->BuildPvpLogDataPacket(&data, this);
  904.         player->GetSession()->SendPacket(&data);
  905.  
  906.         BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
  907.         sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime(), GetArenaType());
  908.         player->GetSession()->SendPacket(&data);
  909.         player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND, 1);
  910.     }
  911.  
  912.     if (isArena() && isRated() && winner_arena_team && loser_arena_team && winner_arena_team != loser_arena_team)
  913.     {
  914.         // update arena points only after increasing the player's match count!
  915.         //obsolete: winner_arena_team->UpdateArenaPointsHelper();
  916.         //obsolete: loser_arena_team->UpdateArenaPointsHelper();
  917.         // save the stat changes
  918.         winner_arena_team->SaveToDB();
  919.         loser_arena_team->SaveToDB();
  920.         // send updated arena team stats to players
  921.         // this way all arena team members will get notified, not only the ones who participated in this match
  922.         winner_arena_team->NotifyStatsChanged();
  923.         loser_arena_team->NotifyStatsChanged();
  924.     }
  925.  
  926.     if (winmsg_id)
  927.         SendMessageToAll(winmsg_id, CHAT_MSG_BG_SYSTEM_NEUTRAL);
  928. }
  929.  
  930. uint32 Battleground::GetBonusHonorFromKill(uint32 kills) const
  931. {
  932.     //variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
  933.     uint32 maxLevel = std::min(GetMaxLevel(), 80U);
  934.     return SkyFire::Honor::hk_honor_at_level(maxLevel, float(kills));
  935. }
  936.  
  937. void Battleground::BlockMovement(Player* player)
  938. {
  939.     player->SetClientControl(player, 0); // movement disabled NOTE: the effect will be automatically removed by client when the player is teleported from the battleground, so no need to send with uint8(1) in RemovePlayerAtLeave()
  940. }
  941.  
  942. void Battleground::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
  943. {
  944.     uint32 team = GetPlayerTeam(guid);
  945.     bool participant = false;
  946.     // Remove from lists/maps
  947.     BattlegroundPlayerMap::iterator itr = _Players.find(guid);
  948.     if (itr != _Players.end())
  949.     {
  950.         UpdatePlayersCountByTeam(team, true); // -1 player
  951.         _Players.erase(itr);
  952.         // check if the player was a participant of the match, or only entered through gm command (goname)
  953.         participant = true;
  954.     }
  955.  
  956.     BattlegroundScoreMap::iterator itr2 = PlayerScores.find(guid);
  957.     if (itr2 != PlayerScores.end())
  958.     {
  959.         delete itr2->second; // delete player's score
  960.         PlayerScores.erase(itr2);
  961.     }
  962.  
  963.     RemovePlayerFromResurrectQueue(guid);
  964.  
  965.     Player* player = ObjectAccessor::FindPlayer(guid);
  966.  
  967.     // should remove spirit of redemption
  968.     if (player)
  969.     {
  970.         if (player->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
  971.             player->RemoveAurasByType(SPELL_AURA_MOD_SHAPESHIFT);
  972.  
  973.         if (!player->isAlive()) // resurrect on exit
  974.         {
  975.             player->ResurrectPlayer(1.0f);
  976.             player->SpawnCorpseBones();
  977.         }
  978.     }
  979.  
  980.     RemovePlayer(player, guid, team); // BG subclass specific code
  981.  
  982.     if (participant) // if the player was a match participant, remove auras, calc rating, update queue
  983.     {
  984.         BattlegroundTypeId bgTypeId = GetTypeID();
  985.         BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
  986.         if (player)
  987.         {
  988.             player->ClearAfkReports();
  989.  
  990.             if (!team) team = player->GetTeam();
  991.  
  992.             // if arena, remove the specific arena auras
  993.             if (isArena())
  994.             {
  995.                 bgTypeId=BATTLEGROUND_AA; // set the bg type to all arenas (it will be used for queue refreshing)
  996.  
  997.                 // unsummon current and summon old pet if there was one and there isn't a current pet
  998.                 player->RemovePet(NULL, PET_SAVE_AS_CURRENT);
  999.                 player->ResummonPetTemporaryUnSummonedIfAny();
  1000.  
  1001.                 if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
  1002.                 {
  1003.                     //left a rated match while the encounter was in progress, consider as loser
  1004.                     ArenaTeam* winner_arena_team = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team)));
  1005.                     ArenaTeam* loser_arena_team = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(team));
  1006.                     if (winner_arena_team && loser_arena_team && winner_arena_team != loser_arena_team)
  1007.                         loser_arena_team->MemberLost(player, GetArenaMatchmakerRating(GetOtherTeam(team)));
  1008.                 }
  1009.             }
  1010.             if (SendPacket)
  1011.             {
  1012.                 WorldPacket data;
  1013.                 sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0, 0);
  1014.                 player->GetSession()->SendPacket(&data);
  1015.             }
  1016.  
  1017.             // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
  1018.             player->RemoveBattlegroundQueueId(bgQueueTypeId);
  1019.         }
  1020.         else
  1021.         // removing offline participant
  1022.         {
  1023.             if (isRated() && GetStatus() == STATUS_IN_PROGRESS)
  1024.             {
  1025.                 //left a rated match while the encounter was in progress, consider as loser
  1026.                 ArenaTeam* others_arena_team = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(GetOtherTeam(team)));
  1027.                 ArenaTeam* players_arena_team = sArenaTeamMgr->GetArenaTeamById(GetArenaTeamIdForTeam(team));
  1028.                 if (others_arena_team && players_arena_team)
  1029.                     players_arena_team->OfflineMemberLost(guid, GetArenaMatchmakerRating(GetOtherTeam(team)));
  1030.             }
  1031.         }
  1032.  
  1033.         // remove from raid group if player is member
  1034.         if (Group* group = GetBgRaid(team))
  1035.         {
  1036.             if (!group->RemoveMember(guid)) // group was disbanded
  1037.             {
  1038.                 SetBgRaid(team, NULL);
  1039.             }
  1040.         }
  1041.         DecreaseInvitedCount(team);
  1042.         //we should update battleground queue, but only if bg isn't ending
  1043.         if (isBattleground() && GetStatus() < STATUS_WAIT_LEAVE)
  1044.         {
  1045.             // a player has left the battleground, so there are free slots -> add to queue
  1046.             AddToBGFreeSlotQueue();
  1047.             sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, GetBracketId());
  1048.         }
  1049.         // Let others know
  1050.         WorldPacket data;
  1051.         sBattlegroundMgr->BuildPlayerLeftBattlegroundPacket(&data, guid);
  1052.         SendPacketToTeam(team, &data, player, false);
  1053.     }
  1054.  
  1055.     if (player)
  1056.     {
  1057.         // Do next only if found in battleground
  1058.         player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE); // We're not in BG.
  1059.         // reset destination bg team
  1060.         player->SetBGTeam(0);
  1061.  
  1062.         if (Transport)
  1063.             player->TeleportToBGEntryPoint();
  1064.  
  1065.         sLog->outDetail("BATTLEGROUND: Removed player %s from Battleground.", player->GetName());
  1066.     }
  1067.  
  1068.     //battleground object will be deleted next Battleground::Update() call
  1069. }
  1070.  
  1071. // this method is called when no players remains in battleground
  1072. void Battleground::Reset()
  1073. {
  1074.     SetWinner(WINNER_NONE);
  1075.     SetStatus(STATUS_WAIT_QUEUE);
  1076.     SetStartTime(0);
  1077.     SetEndTime(0);
  1078.     SetLastResurrectTime(0);
  1079.     SetArenaType(0);
  1080.     SetRated(false);
  1081.  
  1082.     _Events = 0;
  1083.  
  1084.     if (_InvitedAlliance > 0 || _InvitedHorde > 0)
  1085.         sLog->outError("Battleground::Reset: one of the counters is not 0 (alliance: %u, horde: %u) for BG (map: %u, instance id: %u)!",
  1086.             _InvitedAlliance, _InvitedHorde, _MapId, _InstanceID);
  1087.  
  1088.     _InvitedAlliance = 0;
  1089.     _InvitedHorde = 0;
  1090.     _InBGFreeSlotQueue = false;
  1091.  
  1092.     _Players.clear();
  1093.  
  1094.     for (BattlegroundScoreMap::const_iterator itr = PlayerScores.begin(); itr != PlayerScores.end(); ++itr)
  1095.         delete itr->second;
  1096.     PlayerScores.clear();
  1097.  
  1098.     ResetBGSubclass();
  1099. }
  1100.  
  1101. void Battleground::StartBattleground()
  1102. {
  1103.     SetStartTime(0);
  1104.     SetLastResurrectTime(0);
  1105.     // add BG to free slot queue
  1106.     AddToBGFreeSlotQueue();
  1107.  
  1108.     // add bg to update list
  1109.     // This must be done here, because we need to have already invited some players when first BG::Update() method is executed
  1110.     // and it doesn't matter if we call StartBattleground() more times, because m_Battlegrounds is a map and instance id never changes
  1111.     sBattlegroundMgr->AddBattleground(GetInstanceID(), GetTypeID(), this);
  1112.     if (_IsRated)
  1113.         sLog->outArena("Arena match type: %u for Team1Id: %u - Team2Id: %u started.", _ArenaType, _ArenaTeamIds[BG_TEAM_ALLIANCE], _ArenaTeamIds[BG_TEAM_HORDE]);
  1114. }
  1115.  
  1116. void Battleground::AddPlayer(Player* player)
  1117. {
  1118.     // remove afk from player
  1119.     if (player->HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK))
  1120.         player->ToggleAFK();
  1121.  
  1122.     // score struct must be created in inherited class
  1123.  
  1124.     uint64 guid = player->GetGUID();
  1125.     uint32 team = player->GetBGTeam();
  1126.  
  1127.     BattlegroundPlayer bp;
  1128.     bp.OfflineRemoveTime = 0;
  1129.     bp.Team = team;
  1130.  
  1131.     // Add to list/maps
  1132.     _Players[guid] = bp;
  1133.  
  1134.     UpdatePlayersCountByTeam(team, false); // +1 player
  1135.  
  1136.     WorldPacket data;
  1137.     sBattlegroundMgr->BuildPlayerJoinedBattlegroundPacket(&data, player);
  1138.     SendPacketToTeam(team, &data, player, false);
  1139.  
  1140.     // BG Status packet
  1141.     WorldPacket status;
  1142.     BattlegroundQueueTypeId bgQueueTypeId = sBattlegroundMgr->BGQueueTypeId(_TypeID, GetArenaType());
  1143.     uint32 queueSlot = player->GetBattlegroundQueueIndex(bgQueueTypeId);
  1144.     sBattlegroundMgr->BuildBattlegroundStatusPacket(&status, this, queueSlot, STATUS_IN_PROGRESS, 0, GetStartTime(), GetArenaType(), isArena() ? 0 : 1);
  1145.     player->GetSession()->SendPacket(&status);
  1146.  
  1147.     player->RemoveAurasByType(SPELL_AURA_MOUNTED);
  1148.  
  1149.     // add arena specific auras
  1150.     if (isArena())
  1151.     {
  1152.         player->ResummonPetTemporaryUnSummonedIfAny();
  1153.  
  1154.         // Removing pet's buffs and debuffs which are not permanent on Arena enter
  1155.         if (Pet* pet = player->GetPet())
  1156.         {
  1157.             pet->SetHealth(pet->GetMaxHealth());
  1158.  
  1159.             Unit::AuraApplicationMap& appliedAuras = pet->GetAppliedAuras();
  1160.             for (Unit::AuraApplicationMap::iterator itr = appliedAuras.begin(); itr != appliedAuras.end(); ++itr)
  1161.                 if (AuraApplication* aurApp = itr->second)
  1162.                     if (Aura* aura = aurApp->GetBase())
  1163.                         if (!aura->IsPermanent())
  1164.                             pet->RemoveAura(itr);
  1165.         }
  1166.  
  1167.         player->RemoveArenaEnchantments(TEMP_ENCHANTMENT_SLOT);
  1168.         if (team == ALLIANCE) // gold
  1169.         {
  1170.             if (player->GetTeam() == HORDE)
  1171.                 player->CastSpell(player, SPELL_HORDE_GOLD_FLAG, true);
  1172.             else
  1173.                 player->CastSpell(player, SPELL_ALLIANCE_GOLD_FLAG, true);
  1174.         }
  1175.         else // green
  1176.         {
  1177.             if (player->GetTeam() == HORDE)
  1178.                 player->CastSpell(player, SPELL_HORDE_GREEN_FLAG, true);
  1179.             else
  1180.                 player->CastSpell(player, SPELL_ALLIANCE_GREEN_FLAG, true);
  1181.         }
  1182.  
  1183.         player->DestroyConjuredItems(true);
  1184.         player->UnsummonPetTemporaryIfAny();
  1185.  
  1186.         if (GetStatus() == STATUS_WAIT_JOIN) // not started yet
  1187.         {
  1188.             player->CastSpell(player, SPELL_ARENA_PREPARATION, true);
  1189.             player->ResetAllPowers();
  1190.         }
  1191.         WorldPacket teammate;
  1192.         teammate.Initialize(SMSG_ARENA_OPPONENT_UPDATE, 8);
  1193.         teammate << uint64(player->GetGUID());
  1194.         SendPacketToTeam(team, &teammate, player, false);
  1195.     }
  1196.     else
  1197.     {
  1198.         if (GetStatus() == STATUS_WAIT_JOIN) // not started yet
  1199.             player->CastSpell(player, SPELL_PREPARATION, true); // reduces all mana cost of spells.
  1200.     }
  1201.  
  1202.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1203.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_WIN_BG, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1204.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1205.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1206.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1207.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1208.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1209.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1210.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1211.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1212.     player->GetAchievementMgr().ResetAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL, player, ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP, GetMapId(), true);
  1213.  
  1214.     // setup BG group membership
  1215.     PlayerAddedToBGCheckIfBGIsRunning(player);
  1216.     AddOrSetPlayerToCorrectBgGroup(player, team);
  1217.  
  1218.     // Log
  1219.     sLog->outDetail("BATTLEGROUND: Player %s joined the battle.", player->GetName());
  1220. }
  1221.  
  1222. // this method adds player to his team's bg group, or sets his correct group if player is already in bg group
  1223. void Battleground::AddOrSetPlayerToCorrectBgGroup(Player* player, uint32 team)
  1224. {
  1225.     uint64 playerGuid = player->GetGUID();
  1226.     Group* group = GetBgRaid(team);
  1227.     if (!group) // first player joined
  1228.     {
  1229.         group = new Group;
  1230.         SetBgRaid(team, group);
  1231.         group->Create(player);
  1232.     }
  1233.     else // raid already exist
  1234.     {
  1235.         if (group->IsMember(playerGuid))
  1236.         {
  1237.             uint8 subgroup = group->GetMemberGroup(playerGuid);
  1238.             player->SetBattlegroundOrBattlefieldRaid(group, subgroup);
  1239.         }
  1240.         else
  1241.         {
  1242.             group->AddMember(player);
  1243.             if (Group* originalGroup = player->GetOriginalGroup())
  1244.                 if (originalGroup->IsLeader(playerGuid))
  1245.                 {
  1246.                     group->ChangeLeader(playerGuid);
  1247.                     group->SendUpdate();
  1248.                 }
  1249.         }
  1250.     }
  1251. }
  1252.  
  1253. // This method should be called when player logs into running battleground
  1254. void Battleground::EventPlayerLoggedIn(Player* player)
  1255. {
  1256.     uint64 guid = player->GetGUID();
  1257.     // player is correct pointer
  1258.     for (std::deque<uint64>::iterator itr = _OfflineQueue.begin(); itr != _OfflineQueue.end(); ++itr)
  1259.     {
  1260.         if (*itr == guid)
  1261.         {
  1262.             _OfflineQueue.erase(itr);
  1263.             break;
  1264.         }
  1265.     }
  1266.     _Players[guid].OfflineRemoveTime = 0;
  1267.     PlayerAddedToBGCheckIfBGIsRunning(player);
  1268.     // if battleground is starting, then add preparation aura
  1269.     // we don't have to do that, because preparation aura isn't removed when player logs out
  1270. }
  1271.  
  1272. // This method should be called when player logs out from running battleground
  1273. void Battleground::EventPlayerLoggedOut(Player* player)
  1274. {
  1275.     uint64 guid = player->GetGUID();
  1276.     // player is correct pointer, it is checked in WorldSession::LogoutPlayer()
  1277.     _OfflineQueue.push_back(player->GetGUID());
  1278.     _Players[guid].OfflineRemoveTime = sWorld->GetGameTime() + MAX_OFFLINE_TIME;
  1279.     if (GetStatus() == STATUS_IN_PROGRESS)
  1280.     {
  1281.         // drop flag and handle other cleanups
  1282.         RemovePlayer(player, guid, GetPlayerTeam(guid));
  1283.  
  1284.         // 1 player is logging out, if it is the last, then end arena!
  1285.         if (isArena())
  1286.             if (GetAlivePlayersCountByTeam(player->GetTeam()) <= 1 && GetPlayersCountByTeam(GetOtherTeam(player->GetTeam())))
  1287.                 EndBattleground(GetOtherTeam(player->GetTeam()));
  1288.     }
  1289. }
  1290.  
  1291. // This method should be called only once ... it adds pointer to queue
  1292. void Battleground::AddToBGFreeSlotQueue()
  1293. {
  1294.     // make sure to add only once
  1295.     if (!_InBGFreeSlotQueue && isBattleground())
  1296.     {
  1297.         sBattlegroundMgr->BGFreeSlotQueue[_TypeID].push_front(this);
  1298.         _InBGFreeSlotQueue = true;
  1299.     }
  1300. }
  1301.  
  1302. // This method removes this battleground from free queue - it must be called when deleting battleground - not used now
  1303. void Battleground::RemoveFromBGFreeSlotQueue()
  1304. {
  1305.     // set to be able to re-add if needed
  1306.     _InBGFreeSlotQueue = false;
  1307.     // uncomment this code when battlegrounds will work like instances
  1308.     for (BGFreeSlotQueueType::iterator itr = sBattlegroundMgr->BGFreeSlotQueue[_TypeID].begin(); itr != sBattlegroundMgr->BGFreeSlotQueue[_TypeID].end(); ++itr)
  1309.     {
  1310.         if ((*itr)->GetInstanceID() == _InstanceID)
  1311.         {
  1312.             sBattlegroundMgr->BGFreeSlotQueue[_TypeID].erase(itr);
  1313.             return;
  1314.         }
  1315.     }
  1316. }
  1317.  
  1318. // get the number of free slots for team
  1319. // returns the number how many players can join battleground to MaxPlayersPerTeam
  1320. uint32 Battleground::GetFreeSlotsForTeam(uint32 Team) const
  1321. {
  1322.     // if BG is starting ... invite anyone
  1323.     if (GetStatus() == STATUS_WAIT_JOIN)
  1324.         return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
  1325.     // if BG is already started .. do not allow to join too much players of one faction
  1326.     uint32 otherTeam;
  1327.     uint32 otherIn;
  1328.     if (Team == ALLIANCE)
  1329.     {
  1330.         otherTeam = GetInvitedCount(HORDE);
  1331.         otherIn = GetPlayersCountByTeam(HORDE);
  1332.     }
  1333.     else
  1334.     {
  1335.         otherTeam = GetInvitedCount(ALLIANCE);
  1336.         otherIn = GetPlayersCountByTeam(ALLIANCE);
  1337.     }
  1338.     if (GetStatus() == STATUS_IN_PROGRESS)
  1339.     {
  1340.         // difference based on ppl invited (not necessarily entered battle)
  1341.         // default: allow 0
  1342.         uint32 diff = 0;
  1343.         // allow join one person if the sides are equal (to fill up bg to minplayersperteam)
  1344.         if (otherTeam == GetInvitedCount(Team))
  1345.             diff = 1;
  1346.         // allow join more ppl if the other side has more players
  1347.         else if (otherTeam > GetInvitedCount(Team))
  1348.             diff = otherTeam - GetInvitedCount(Team);
  1349.  
  1350.         // difference based on max players per team (don't allow inviting more)
  1351.         uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
  1352.         // difference based on players who already entered
  1353.         // default: allow 0
  1354.         uint32 diff3 = 0;
  1355.         // allow join one person if the sides are equal (to fill up bg minplayersperteam)
  1356.         if (otherIn == GetPlayersCountByTeam(Team))
  1357.             diff3 = 1;
  1358.         // allow join more ppl if the other side has more players
  1359.         else if (otherIn > GetPlayersCountByTeam(Team))
  1360.             diff3 = otherIn - GetPlayersCountByTeam(Team);
  1361.         // or other side has less than minPlayersPerTeam
  1362.         else if (GetInvitedCount(Team) <= GetMinPlayersPerTeam())
  1363.             diff3 = GetMinPlayersPerTeam() - GetInvitedCount(Team) + 1;
  1364.  
  1365.         // return the minimum of the 3 differences
  1366.  
  1367.         // min of diff and diff 2
  1368.         diff = std::min(diff, diff2);
  1369.         // min of diff, diff2 and diff3
  1370.         return std::min(diff, diff3);
  1371.     }
  1372.     return 0;
  1373. }
  1374.  
  1375. bool Battleground::HasFreeSlots() const
  1376. {
  1377.     return GetPlayersSize() < GetMaxPlayers();
  1378. }
  1379.  
  1380. void Battleground::UpdatePlayerScore(Player* Source, uint32 type, uint32 value, bool doAddHonor)
  1381. {
  1382.     //this procedure is called from virtual function implemented in bg subclass
  1383.     BattlegroundScoreMap::const_iterator itr = PlayerScores.find(Source->GetGUID());
  1384.     if (itr == PlayerScores.end()) // player not found...
  1385.         return;
  1386.  
  1387.     switch (type)
  1388.     {
  1389.         case SCORE_KILLING_BLOWS: // Killing blows
  1390.             itr->second->KillingBlows += value;
  1391.             break;
  1392.         case SCORE_DEATHS: // Deaths
  1393.             itr->second->Deaths += value;
  1394.             break;
  1395.         case SCORE_HONORABLE_KILLS: // Honorable kills
  1396.             itr->second->HonorableKills += value;
  1397.             break;
  1398.         case SCORE_BONUS_HONOR: // Honor bonus
  1399.             // do not add honor in arenas
  1400.             if (isBattleground())
  1401.             {
  1402.                 // reward honor instantly
  1403.                 if (doAddHonor)
  1404.                     Source->RewardHonor(NULL, 1, value); // RewardHonor calls UpdatePlayerScore with doAddHonor = false
  1405.                 else
  1406.                     itr->second->BonusHonor += value;
  1407.             }
  1408.             break;
  1409.             // used only in EY, but in MSG_PVP_LOG_DATA opcode
  1410.         case SCORE_DAMAGE_DONE: // Damage Done
  1411.             itr->second->DamageDone += value;
  1412.             break;
  1413.         case SCORE_HEALING_DONE: // Healing Done
  1414.             itr->second->HealingDone += value;
  1415.             break;
  1416.         default:
  1417.             sLog->outError("Battleground::UpdatePlayerScore: unknown score type (%u) for BG (map: %u, instance id: %u)!",
  1418.                 type, _MapId, _InstanceID);
  1419.             break;
  1420.     }
  1421. }
  1422.  
  1423. void Battleground::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
  1424. {
  1425.     _ReviveQueue[npc_guid].push_back(player_guid);
  1426.  
  1427.     Player* player = ObjectAccessor::FindPlayer(player_guid);
  1428.     if (!player)
  1429.         return;
  1430.  
  1431.     player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
  1432. }
  1433.  
  1434. void Battleground::RemovePlayerFromResurrectQueue(uint64 player_guid)
  1435. {
  1436.     for (std::map<uint64, std::vector<uint64> >::iterator itr = _ReviveQueue.begin(); itr != _ReviveQueue.end(); ++itr)
  1437.     {
  1438.         for (std::vector<uint64>::iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
  1439.         {
  1440.             if (*itr2 == player_guid)
  1441.             {
  1442.                 (itr->second).erase(itr2);
  1443.                 if (Player* player = ObjectAccessor::FindPlayer(player_guid))
  1444.                     player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
  1445.                 return;
  1446.             }
  1447.         }
  1448.     }
  1449. }
  1450.  
  1451. bool Battleground::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 /*respawnTime*/)
  1452. {
  1453.     // If the assert is called, means that _BgObjects must be resized!
  1454.     ASSERT(type < BgObjects.size());
  1455.  
  1456.     Map* map = FindBgMap();
  1457.     if (!map)
  1458.         return false;
  1459.     // Must be created this way, adding to godatamap would add it to the base map of the instance
  1460.     // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
  1461.     // So we must create it specific for this instance
  1462.     GameObject* go = new GameObject;
  1463.     if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, GetBgMap(),
  1464.         PHASEMASK_NORMAL, x, y, z, o, rotation0, rotation1, rotation2, rotation3, 100, GO_STATE_READY))
  1465.     {
  1466.         sLog->outErrorDb("Battleground::AddObject: cannot create gameobject (entry: %u) for BG (map: %u, instance id: %u)!",
  1467.                 entry, _MapId, _InstanceID);
  1468.         sLog->outError("Battleground::AddObject: cannot create gameobject (entry: %u) for BG (map: %u, instance id: %u)!",
  1469.                 entry, _MapId, _InstanceID);
  1470.         delete go;
  1471.         return false;
  1472.     }
  1473. /*
  1474. uint32 guid = go->GetGUIDLow();
  1475.  
  1476. // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
  1477. // iirc that was changed, so adding to go data map is no longer required if that was the only function using godata from GameObject without checking if it existed
  1478. GameObjectData& data = sObjectMgr->NewGOData(guid);
  1479.  
  1480. data.id = entry;
  1481. data.mapid = GetMapId();
  1482. data.posX = x;
  1483. data.posY = y;
  1484. data.posZ = z;
  1485. data.orientation = o;
  1486. data.rotation0 = rotation0;
  1487. data.rotation1 = rotation1;
  1488. data.rotation2 = rotation2;
  1489. data.rotation3 = rotation3;
  1490. data.spawntimesecs = respawnTime;
  1491. data.spawnMask = 1;
  1492. data.animprogress = 100;
  1493. data.go_state = 1;
  1494. */
  1495.     // Add to world, so it can be later looked up from HashMapHolder
  1496.     if (!map->AddToMap(go))
  1497.     {
  1498.         delete go;
  1499.         return false;
  1500.     }
  1501.     BgObjects[type] = go->GetGUID();
  1502.     return true;
  1503. }
  1504.  
  1505. // Some doors aren't despawned so we cannot handle their closing in gameobject::update()
  1506. // It would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
  1507. void Battleground::DoorClose(uint32 type)
  1508. {
  1509.     if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
  1510.     {
  1511.         // If doors are open, close it
  1512.         if (obj->getLootState() == GO_ACTIVATED && obj->GetGoState() != GO_STATE_READY)
  1513.         {
  1514.             // Change state to allow door to be closed
  1515.             obj->SetLootState(GO_READY);
  1516.             obj->SetGoState(GO_STATE_READY);
  1517.         }
  1518.     }
  1519.     else
  1520.         sLog->outError("Battleground::DoorClose: door gameobject (type: %u, GUID: %u) not found for BG (map: %u, instance id: %u)!",
  1521.             type, GUID_LOPART(BgObjects[type]), _MapId, _InstanceID);
  1522. }
  1523.  
  1524. void Battleground::DoorOpen(uint32 type)
  1525. {
  1526.     if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
  1527.     {
  1528.         // Change state to be sure they will be opened
  1529.         obj->SetLootState(GO_ACTIVATED);
  1530.         obj->SetGoState(GO_STATE_ACTIVE);
  1531.     }
  1532.     else
  1533.         sLog->outError("Battleground::DoorOpen: door gameobject (type: %u, GUID: %u) not found for BG (map: %u, instance id: %u)!",
  1534.             type, GUID_LOPART(BgObjects[type]), _MapId, _InstanceID);
  1535. }
  1536.  
  1537. GameObject* Battleground::GetBGObject(uint32 type)
  1538. {
  1539.     GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]);
  1540.     if (!obj)
  1541.         sLog->outError("Battleground::GetBGObject: gameobject (type: %u, GUID: %u) not found for BG (map: %u, instance id: %u)!",
  1542.             type, GUID_LOPART(BgObjects[type]), _MapId, _InstanceID);
  1543.     return obj;
  1544. }
  1545.  
  1546. Creature* Battleground::GetBGCreature(uint32 type)
  1547. {
  1548.     Creature* creature = GetBgMap()->GetCreature(BgCreatures[type]);
  1549.     if (!creature)
  1550.         sLog->outError("Battleground::GetBGCreature: creature (type: %u, GUID: %u) not found for BG (map: %u, instance id: %u)!",
  1551.             type, GUID_LOPART(BgCreatures[type]), _MapId, _InstanceID);
  1552.     return creature;
  1553. }
  1554.  
  1555. void Battleground::SpawnBGObject(uint32 type, uint32 respawntime)
  1556. {
  1557.     if (Map* map = FindBgMap())
  1558.         if (GameObject* obj = map->GetGameObject(BgObjects[type]))
  1559.         {
  1560.             if (respawntime)
  1561.                 obj->SetLootState(GO_JUST_DEACTIVATED);
  1562.             else
  1563.                 if (obj->getLootState() == GO_JUST_DEACTIVATED)
  1564.                     // Change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
  1565.                     obj->SetLootState(GO_READY);
  1566.             obj->SetRespawnTime(respawntime);
  1567.             map->AddToMap(obj);
  1568.         }
  1569. }
  1570.  
  1571. Creature* Battleground::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
  1572. {
  1573.     // If the assert is called, means that BgCreatures must be resized!
  1574.     ASSERT(type < BgCreatures.size());
  1575.  
  1576.     Map* map = FindBgMap();
  1577.     if (!map)
  1578.         return NULL;
  1579.  
  1580.     Creature* creature = new Creature;
  1581.     if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, PHASEMASK_NORMAL, entry, 0, teamval, x, y, z, o))
  1582.     {
  1583.         sLog->outError("Battleground::AddCreature: cannot create creature (entry: %u) for BG (map: %u, instance id: %u)!",
  1584.             entry, _MapId, _InstanceID);
  1585.         delete creature;
  1586.         return NULL;
  1587.     }
  1588.  
  1589.     creature->SetHomePosition(x, y, z, o);
  1590.  
  1591.     CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry);
  1592.     if (!cinfo)
  1593.     {
  1594.         sLog->outError("Battleground::AddCreature: creature template (entry: %u) does not exist for BG (map: %u, instance id: %u)!",
  1595.             entry, _MapId, _InstanceID);
  1596.         delete creature;
  1597.         return NULL;
  1598.     }
  1599.     // Force using DB speeds
  1600.     creature->SetSpeed(MOVE_WALK, cinfo->speed_walk);
  1601.     creature->SetSpeed(MOVE_RUN, cinfo->speed_run);
  1602.  
  1603.     if (!map->AddToMap(creature))
  1604.     {
  1605.         delete creature;
  1606.         return NULL;
  1607.     }
  1608.  
  1609.     BgCreatures[type] = creature->GetGUID();
  1610.  
  1611.     if (respawntime)
  1612.         creature->SetRespawnDelay(respawntime);
  1613.  
  1614.     return creature;
  1615. }
  1616.  
  1617. bool Battleground::DelCreature(uint32 type)
  1618. {
  1619.     if (!BgCreatures[type])
  1620.         return true;
  1621.  
  1622.     if (Creature* creature = GetBgMap()->GetCreature(BgCreatures[type]))
  1623.     {
  1624.         creature->AddObjectToRemoveList();
  1625.         BgCreatures[type] = 0;
  1626.         return true;
  1627.     }
  1628.  
  1629.     sLog->outError("Battleground::DelCreature: creature (type: %u, GUID: %u) not found for BG (map: %u, instance id: %u)!",
  1630.         type, GUID_LOPART(BgCreatures[type]), _MapId, _InstanceID);
  1631.     BgCreatures[type] = 0;
  1632.     return false;
  1633. }
  1634.  
  1635. bool Battleground::DelObject(uint32 type)
  1636. {
  1637.     if (!BgObjects[type])
  1638.         return true;
  1639.  
  1640.     if (GameObject* obj = GetBgMap()->GetGameObject(BgObjects[type]))
  1641.     {
  1642.         obj->SetRespawnTime(0); // not save respawn time
  1643.         obj->Delete();
  1644.         BgObjects[type] = 0;
  1645.         return true;
  1646.     }
  1647.     sLog->outError("Battleground::DelObject: gameobject (type: %u, GUID: %u) not found for BG (map: %u, instance id: %u)!",
  1648.         type, GUID_LOPART(BgObjects[type]), _MapId, _InstanceID);
  1649.     BgObjects[type] = 0;
  1650.     return false;
  1651. }
  1652.  
  1653. bool Battleground::AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
  1654. {
  1655.     uint32 entry = (team == ALLIANCE) ?
  1656.         BG_CREATURE_ENTRY_A_SPIRITGUIDE :
  1657.         BG_CREATURE_ENTRY_H_SPIRITGUIDE;
  1658.  
  1659.     if (Creature* creature = AddCreature(entry, type, team, x, y, z, o))
  1660.     {
  1661.         creature->setDeathState(DEAD);
  1662.         creature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, creature->GetGUID());
  1663.         // aura
  1664.         // TODO: Fix display here
  1665.         // creature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL);
  1666.         // casting visual effect
  1667.         creature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
  1668.         // correct cast speed
  1669.         creature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
  1670.         //creature->CastSpell(creature, SPELL_SPIRIT_HEAL_CHANNEL, true);
  1671.         return true;
  1672.     }
  1673.     sLog->outError("Battleground::AddSpiritGuide: cannot create spirit guide (type: %u, entry: %u) for BG (map: %u, instance id: %u)!",
  1674.         type, entry, _MapId, _InstanceID);
  1675.     EndNow();
  1676.     return false;
  1677. }
  1678.  
  1679. void Battleground::SendMessageToAll(int32 entry, ChatMsg type, Player const* source)
  1680. {
  1681.     if (!entry)
  1682.         return;
  1683.  
  1684.     SkyFire::BattlegroundChatBuilder bg_builder(type, entry, source);
  1685.     SkyFire::LocalizedPacketDo<SkyFire::BattlegroundChatBuilder> bg_do(bg_builder);
  1686.     BroadcastWorker(bg_do);
  1687. }
  1688.  
  1689. void Battleground::PSendMessageToAll(int32 entry, ChatMsg type, Player const* source, ...)
  1690. {
  1691.     if (!entry)
  1692.         return;
  1693.  
  1694.     va_list ap;
  1695.     va_start(ap, source);
  1696.  
  1697.     SkyFire::BattlegroundChatBuilder bg_builder(type, entry, source, &ap);
  1698.     SkyFire::LocalizedPacketDo<SkyFire::BattlegroundChatBuilder> bg_do(bg_builder);
  1699.     BroadcastWorker(bg_do);
  1700.  
  1701.     va_end(ap);
  1702. }
  1703.  
  1704. void Battleground::SendWarningToAll(int32 entry, ...)
  1705. {
  1706.     if (!entry)
  1707.         return;
  1708.  
  1709.     const char *format = sObjectMgr->GetSkyFireStringForDBCLocale(entry);
  1710.  
  1711.     char str[1024];
  1712.     va_list ap;
  1713.     va_start(ap, entry);
  1714.     vsnprintf(str, 1024, format, ap);
  1715.     va_end(ap);
  1716.     std::string msg(str);
  1717.  
  1718.     WorldPacket data(SMSG_MESSAGECHAT, 200);
  1719.  
  1720.     data << (uint8)CHAT_MSG_RAID_BOSS_EMOTE;
  1721.     data << (uint32)LANG_UNIVERSAL;
  1722.     data << (uint64)0;
  1723.     data << (uint32)0; // 2.1.0
  1724.     data << (uint32)1;
  1725.     data << (uint8)0;
  1726.     data << (uint64)0;
  1727.     data << (uint32)(msg.length() + 1);
  1728.     data << msg.c_str();
  1729.     data << (uint8)0;
  1730.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  1731.         if (Player* player = ObjectAccessor::FindPlayer(MAKE_NEW_GUID(itr->first, 0, HIGHGUID_PLAYER)))
  1732.             if (player->GetSession())
  1733.                 player->GetSession()->SendPacket(&data);
  1734. }
  1735.  
  1736. void Battleground::SendMessage2ToAll(int32 entry, ChatMsg type, Player const* source, int32 arg1, int32 arg2)
  1737. {
  1738.     SkyFire::Battleground2ChatBuilder bg_builder(type, entry, source, arg1, arg2);
  1739.     SkyFire::LocalizedPacketDo<SkyFire::Battleground2ChatBuilder> bg_do(bg_builder);
  1740.     BroadcastWorker(bg_do);
  1741. }
  1742.  
  1743. void Battleground::EndNow()
  1744. {
  1745.     RemoveFromBGFreeSlotQueue();
  1746.     SetStatus(STATUS_WAIT_LEAVE);
  1747.     SetEndTime(0);
  1748. }
  1749.  
  1750. // To be removed
  1751. const char* Battleground::GetSkyFireString(int32 entry)
  1752. {
  1753.     // FIXME: now we have different DBC locales and need localized message for each target client
  1754.     return sObjectMgr->GetSkyFireStringForDBCLocale(entry);
  1755. }
  1756.  
  1757. // IMPORTANT NOTICE:
  1758. // buffs aren't spawned/despawned when players captures anything
  1759. // buffs are in their positions when battleground starts
  1760. void Battleground::HandleTriggerBuff(uint64 go_guid)
  1761. {
  1762.     GameObject* obj = GetBgMap()->GetGameObject(go_guid);
  1763.     if (!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
  1764.         return;
  1765.  
  1766.     // Change buff type, when buff is used:
  1767.     int32 index = BgObjects.size() - 1;
  1768.     while (index >= 0 && BgObjects[index] != go_guid)
  1769.         index--;
  1770.     if (index < 0)
  1771.     {
  1772.         sLog->outError("Battleground::HandleTriggerBuff: cannot find buff gameobject (GUID: %u, entry: %u, type: %u) in internal data for BG (map: %u, instance id: %u)!",
  1773.             GUID_LOPART(go_guid), obj->GetEntry(), obj->GetGoType(), _MapId, _InstanceID);
  1774.         return;
  1775.     }
  1776.  
  1777.     // Randomly select new buff
  1778.     uint8 buff = urand(0, 2);
  1779.     uint32 entry = obj->GetEntry();
  1780.     if (_BuffChange && entry != Buff_Entries[buff])
  1781.     {
  1782.         // Despawn current buff
  1783.         SpawnBGObject(index, RESPAWN_ONE_DAY);
  1784.         // Set index for new one
  1785.         for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
  1786.             if (entry == Buff_Entries[currBuffTypeIndex])
  1787.             {
  1788.                 index -= currBuffTypeIndex;
  1789.                 index += buff;
  1790.             }
  1791.     }
  1792.  
  1793.     SpawnBGObject(index, BUFF_RESPAWN_TIME);
  1794. }
  1795.  
  1796. void Battleground::HandleKillPlayer(Player* player, Player* killer)
  1797. {
  1798.     // Keep in mind that for arena this will have to be changed a bit
  1799.  
  1800.     // Add +1 deaths
  1801.     UpdatePlayerScore(player, SCORE_DEATHS, 1);
  1802.     // Add +1 kills to group and +1 killing_blows to killer
  1803.     if (killer)
  1804.     {
  1805.         UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
  1806.         UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
  1807.  
  1808.         for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  1809.         {
  1810.             Player* creditedPlayer = ObjectAccessor::FindPlayer(itr->first);
  1811.             if (!creditedPlayer || creditedPlayer == killer)
  1812.                 continue;
  1813.  
  1814.             if (creditedPlayer->GetTeam() == killer->GetTeam() && creditedPlayer->IsAtGroupRewardDistance(player))
  1815.                 UpdatePlayerScore(creditedPlayer, SCORE_HONORABLE_KILLS, 1);
  1816.         }
  1817.     }
  1818.  
  1819.     if (!isArena())
  1820.     {
  1821.         // To be able to remove insignia -- ONLY IN Battlegrounds
  1822.         player->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE);
  1823.         RewardXPAtKill(killer, player);
  1824.     }
  1825. }
  1826.  
  1827. // Return the player's team based on battlegroundplayer info
  1828. // Used in same faction arena matches mainly
  1829. uint32 Battleground::GetPlayerTeam(uint64 guid) const
  1830. {
  1831.     BattlegroundPlayerMap::const_iterator itr = _Players.find(guid);
  1832.     if (itr != _Players.end())
  1833.         return itr->second.Team;
  1834.     return 0;
  1835. }
  1836.  
  1837. uint32 Battleground::GetOtherTeam(uint32 teamId) const
  1838. {
  1839.     return teamId ? ((teamId == ALLIANCE) ? HORDE : ALLIANCE) : 0;
  1840. }
  1841.  
  1842. bool Battleground::IsPlayerInBattleground(uint64 guid) const
  1843. {
  1844.     BattlegroundPlayerMap::const_iterator itr = _Players.find(guid);
  1845.     if (itr != _Players.end())
  1846.         return true;
  1847.     return false;
  1848. }
  1849.  
  1850. void Battleground::PlayerAddedToBGCheckIfBGIsRunning(Player* player)
  1851. {
  1852.     if (GetStatus() != STATUS_WAIT_LEAVE)
  1853.         return;
  1854.  
  1855.     WorldPacket data;
  1856.     BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId(GetTypeID(), GetArenaType());
  1857.  
  1858.     BlockMovement(player);
  1859.  
  1860.     sBattlegroundMgr->BuildPvpLogDataPacket(&data, this);
  1861.     player->GetSession()->SendPacket(&data);
  1862.  
  1863.     sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, this, player->GetBattlegroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, GetEndTime(), GetStartTime(), GetArenaType());
  1864.     player->GetSession()->SendPacket(&data);
  1865. }
  1866.  
  1867. uint32 Battleground::GetAlivePlayersCountByTeam(uint32 Team) const
  1868. {
  1869.     int count = 0;
  1870.     for (BattlegroundPlayerMap::const_iterator itr = _Players.begin(); itr != _Players.end(); ++itr)
  1871.     {
  1872.         if (itr->second.Team == Team)
  1873.         {
  1874.             Player* player = ObjectAccessor::FindPlayer(itr->first);
  1875.             if (player && player->isAlive() && !player->HasByteFlag(UNIT_FIELD_BYTES_2, 3, FORM_SPIRITOFREDEMPTION))
  1876.                 ++count;
  1877.         }
  1878.     }
  1879.     return count;
  1880. }
  1881.  
  1882. void Battleground::SetHoliday(bool is_holiday)
  1883. {
  1884.     _HonorMode = is_holiday ? BG_HOLIDAY : BG_NORMAL;
  1885. }
  1886.  
  1887. int32 Battleground::GetObjectType(uint64 guid)
  1888. {
  1889.     for (uint32 i = 0; i < BgObjects.size(); ++i)
  1890.         if (BgObjects[i] == guid)
  1891.             return i;
  1892.     sLog->outError("Battleground::GetObjectType: player used gameobject (GUID: %u) which is not in internal data for BG (map: %u, instance id: %u), cheating?",
  1893.         GUID_LOPART(guid), _MapId, _InstanceID);
  1894.     return -1;
  1895. }
  1896.  
  1897. void Battleground::HandleKillUnit(Creature* /*creature*/, Player* /*killer*/)
  1898. {
  1899. }
  1900.  
  1901. void Battleground::CheckArenaAfterTimerConditions()
  1902. {
  1903.     EndBattleground(WINNER_NONE);
  1904. }
  1905.  
  1906. void Battleground::CheckArenaWinConditions()
  1907. {
  1908.     if (!GetAlivePlayersCountByTeam(ALLIANCE) && GetPlayersCountByTeam(HORDE))
  1909.         EndBattleground(HORDE);
  1910.     else if (GetPlayersCountByTeam(ALLIANCE) && !GetAlivePlayersCountByTeam(HORDE))
  1911.         EndBattleground(ALLIANCE);
  1912. }
  1913.  
  1914. void Battleground::UpdateArenaWorldState()
  1915. {
  1916.     UpdateWorldState(0xe10, GetAlivePlayersCountByTeam(HORDE));
  1917.     UpdateWorldState(0xe11, GetAlivePlayersCountByTeam(ALLIANCE));
  1918. }
  1919.  
  1920. void Battleground::SetBgRaid(uint32 TeamID, Group* bg_raid)
  1921. {
  1922.     Group*& old_raid = TeamID == ALLIANCE ? _BgRaids[BG_TEAM_ALLIANCE] : _BgRaids[BG_TEAM_HORDE];
  1923.     if (old_raid)
  1924.         old_raid->SetBattlegroundGroup(NULL);
  1925.     if (bg_raid)
  1926.         bg_raid->SetBattlegroundGroup(this);
  1927.     old_raid = bg_raid;
  1928. }
  1929.  
  1930. WorldSafeLocsEntry const* Battleground::GetClosestGraveYard(Player* player)
  1931. {
  1932.     return sObjectMgr->GetClosestGraveYard(player->GetPositionX(), player->GetPositionY(), player->GetPositionZ(), player->GetMapId(), player->GetTeam());
  1933. }
  1934.  
  1935. bool Battleground::IsTeamScoreInRange(uint32 team, uint32 minScore, uint32 maxScore) const
  1936. {
  1937.     BattlegroundTeamId teamIndex = GetTeamIndexByTeamId(team);
  1938.     uint32 score = std::max(_TeamScores[teamIndex], 0);
  1939.     return score >= minScore && score <= maxScore;
  1940. }
  1941.  
  1942. void Battleground::StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry)
  1943. {
  1944.     for (BattlegroundPlayerMap::const_iterator itr = GetPlayers().begin(); itr != GetPlayers().end(); ++itr)
  1945.         if (Player* player = ObjectAccessor::FindPlayer(itr->first))
  1946.             player->GetAchievementMgr().StartTimedAchievement(type, entry);
  1947. }
  1948.  
  1949. void Battleground::SetBracket(PvPDifficultyEntry const* bracketEntry)
  1950. {
  1951.     _BracketId = bracketEntry->GetBracketId();
  1952.     SetLevelRange(bracketEntry->minLevel, bracketEntry->maxLevel);
  1953. }
  1954.  
  1955. void Battleground::RewardXPAtKill(Player* killer, Player* victim)
  1956. {
  1957.     if (sWorld->getBoolConfig(CONFIG_BG_XP_FOR_KILL) && killer && victim)
  1958.         killer->RewardPlayerAndGroupAtKill(victim, true);
  1959. }
Add Comment
Please, Sign In to add comment