2008-10-02 16:23:55 -05:00
/*
2009-02-04 12:42:26 +01:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
2008-10-14 11:57:03 -05:00
*
2009-02-04 12:04:12 +01:00
* Copyright (C) 2008-2009 Trinity <http://www.trinitycore.org/>
2008-10-02 16:23:55 -05:00
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
2008-12-19 16:05:13 -06:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2008-10-02 16:23:55 -05:00
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
2008-12-19 16:05:13 -06:00
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2008-10-02 16:23:55 -05:00
*/
#include "Object.h"
#include "Player.h"
#include "BattleGround.h"
2009-02-09 22:08:06 -06:00
#include "BattleGroundMgr.h"
2008-10-02 16:23:55 -05:00
#include "Creature.h"
#include "MapManager.h"
#include "Language.h"
#include "SpellAuras.h"
2008-10-05 08:48:32 -05:00
#include "ArenaTeam.h"
2008-10-02 16:23:55 -05:00
#include "World.h"
2009-02-09 22:08:06 -06:00
#include "Group.h"
#include "ObjectMgr.h"
#include "WorldPacket.h"
2008-10-02 16:23:55 -05:00
#include "Util.h"
2009-03-09 18:14:06 -06:00
#include "Formulas.h"
2009-03-09 17:00:31 -06:00
#include "GridNotifiersImpl.h"
namespace MaNGOS
{
class BattleGroundChatBuilder
{
public :
BattleGroundChatBuilder ( ChatMsg msgtype , int32 textId , Player const * source , va_list * args = NULL )
: i_msgtype ( msgtype ), i_textId ( textId ), i_source ( source ), i_args ( args ) {}
void operator ()( WorldPacket & data , int32 loc_idx )
{
char const * text = objmgr . GetMangosString ( i_textId , loc_idx );
2009-04-08 16:33:46 -05:00
if ( i_args )
2009-03-09 17:00:31 -06:00
{
// we need copy va_list before use or original va_list will corrupted
va_list ap ;
va_copy ( ap , * i_args );
char str [ 2048 ];
vsnprintf ( str , 2048 , text , ap );
va_end ( ap );
do_helper ( data , & str [ 0 ]);
}
else
do_helper ( data , text );
}
private :
void do_helper ( WorldPacket & data , char const * text )
{
uint64 target_guid = i_source ? i_source -> GetGUID () : 0 ;
data << uint8 ( i_msgtype );
data << uint32 ( LANG_UNIVERSAL );
data << uint64 ( target_guid ); // there 0 for BG messages
data << uint32 ( 0 ); // can be chat msg group or something
data << uint64 ( target_guid );
data << uint32 ( strlen ( text ) + 1 );
data << text ;
data << uint8 ( i_source ? i_source -> chatTag () : uint8 ( 0 ));
}
ChatMsg i_msgtype ;
int32 i_textId ;
Player const * i_source ;
va_list * i_args ;
};
2009-03-09 17:06:13 -06:00
class BattleGround2ChatBuilder
{
public :
BattleGround2ChatBuilder ( ChatMsg msgtype , int32 textId , Player const * source , int32 arg1 , int32 arg2 )
: i_msgtype ( msgtype ), i_textId ( textId ), i_source ( source ), i_arg1 ( arg1 ), i_arg2 ( arg2 ) {}
void operator ()( WorldPacket & data , int32 loc_idx )
{
char const * text = objmgr . GetMangosString ( i_textId , loc_idx );
char const * arg1str = i_arg1 ? objmgr . GetMangosString ( i_arg1 , loc_idx ) : "" ;
char const * arg2str = i_arg2 ? objmgr . GetMangosString ( i_arg2 , loc_idx ) : "" ;
char str [ 2048 ];
snprintf ( str , 2048 , text , arg1str , arg2str );
uint64 target_guid = i_source ? i_source -> GetGUID () : 0 ;
data << uint8 ( i_msgtype );
data << uint32 ( LANG_UNIVERSAL );
data << uint64 ( target_guid ); // there 0 for BG messages
data << uint32 ( 0 ); // can be chat msg group or something
data << uint64 ( target_guid );
data << uint32 ( strlen ( str ) + 1 );
data << str ;
data << uint8 ( i_source ? i_source -> chatTag () : uint8 ( 0 ));
}
private :
ChatMsg i_msgtype ;
int32 i_textId ;
Player const * i_source ;
int32 i_arg1 ;
int32 i_arg2 ;
};
2009-03-09 17:00:31 -06:00
} // namespace MaNGOS
2008-10-02 16:23:55 -05:00
2009-03-09 17:06:13 -06:00
template < class Do >
void BattleGround :: BroadcastWorker ( Do & _do )
{
2009-04-29 00:26:07 -05:00
for ( BattleGroundPlayerMap :: const_iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2009-04-08 16:33:46 -05:00
if ( Player * plr = ObjectAccessor :: FindPlayer ( MAKE_NEW_GUID ( itr -> first , 0 , HIGHGUID_PLAYER )))
2009-03-09 17:06:13 -06:00
_do ( plr );
}
2008-10-02 16:23:55 -05:00
BattleGround :: BattleGround ()
{
2009-02-09 22:08:06 -06:00
m_TypeID = BattleGroundTypeId ( 0 );
2008-10-02 16:23:55 -05:00
m_InstanceID = 0 ;
2009-03-05 19:02:08 -06:00
m_Status = STATUS_NONE ;
2009-03-10 15:30:44 -06:00
m_ClientInstanceID = 0 ;
2008-10-02 16:23:55 -05:00
m_EndTime = 0 ;
m_LastResurrectTime = 0 ;
2009-02-27 12:13:59 -06:00
m_QueueId = QUEUE_ID_MAX_LEVEL_19 ;
2008-10-02 16:23:55 -05:00
m_InvitedAlliance = 0 ;
m_InvitedHorde = 0 ;
m_ArenaType = 0 ;
m_IsArena = false ;
m_Winner = 2 ;
m_StartTime = 0 ;
m_Events = 0 ;
m_IsRated = false ;
m_BuffChange = false ;
m_Name = "" ;
m_LevelMin = 0 ;
m_LevelMax = 0 ;
2008-10-05 08:48:32 -05:00
m_InBGFreeSlotQueue = false ;
m_SetDeleteThis = false ;
2008-10-02 16:23:55 -05:00
m_MaxPlayersPerTeam = 0 ;
m_MaxPlayers = 0 ;
m_MinPlayersPerTeam = 0 ;
m_MinPlayers = 0 ;
m_MapId = 0 ;
m_TeamStartLocX [ BG_TEAM_ALLIANCE ] = 0 ;
m_TeamStartLocX [ BG_TEAM_HORDE ] = 0 ;
m_TeamStartLocY [ BG_TEAM_ALLIANCE ] = 0 ;
m_TeamStartLocY [ BG_TEAM_HORDE ] = 0 ;
m_TeamStartLocZ [ BG_TEAM_ALLIANCE ] = 0 ;
m_TeamStartLocZ [ BG_TEAM_HORDE ] = 0 ;
m_TeamStartLocO [ BG_TEAM_ALLIANCE ] = 0 ;
m_TeamStartLocO [ BG_TEAM_HORDE ] = 0 ;
2008-10-05 08:48:32 -05:00
m_ArenaTeamIds [ BG_TEAM_ALLIANCE ] = 0 ;
m_ArenaTeamIds [ BG_TEAM_HORDE ] = 0 ;
m_ArenaTeamRatingChanges [ BG_TEAM_ALLIANCE ] = 0 ;
m_ArenaTeamRatingChanges [ BG_TEAM_HORDE ] = 0 ;
2008-10-02 16:23:55 -05:00
m_BgRaids [ BG_TEAM_ALLIANCE ] = NULL ;
m_BgRaids [ BG_TEAM_HORDE ] = NULL ;
m_PlayersCount [ BG_TEAM_ALLIANCE ] = 0 ;
m_PlayersCount [ BG_TEAM_HORDE ] = 0 ;
2008-10-05 08:48:32 -05:00
m_PrematureCountDown = false ;
m_PrematureCountDown = 0 ;
2008-12-19 16:05:13 -06:00
2008-10-17 16:36:07 -05:00
m_HonorMode = BG_NORMAL ;
2009-03-07 12:05:30 -06:00
m_StartDelayTimes [ BG_STARTING_EVENT_FIRST ] = BG_START_DELAY_2M ;
m_StartDelayTimes [ BG_STARTING_EVENT_SECOND ] = BG_START_DELAY_1M ;
m_StartDelayTimes [ BG_STARTING_EVENT_THIRD ] = BG_START_DELAY_30S ;
m_StartDelayTimes [ BG_STARTING_EVENT_FOURTH ] = BG_START_DELAY_NONE ;
//we must set to some default existing values
m_StartMessageIds [ BG_STARTING_EVENT_FIRST ] = LANG_BG_WS_START_TWO_MINUTES ;
m_StartMessageIds [ BG_STARTING_EVENT_SECOND ] = LANG_BG_WS_START_ONE_MINUTE ;
m_StartMessageIds [ BG_STARTING_EVENT_THIRD ] = LANG_BG_WS_START_HALF_MINUTE ;
m_StartMessageIds [ BG_STARTING_EVENT_FOURTH ] = LANG_BG_WS_HAS_BEGUN ;
2008-10-02 16:23:55 -05:00
}
BattleGround ::~ BattleGround ()
{
2008-10-05 08:48:32 -05:00
// remove objects and creatures
2008-12-19 16:05:13 -06:00
// (this is done automatically in mapmanager update, when the instance is reset after the reset time)
2008-10-05 08:48:32 -05:00
int size = m_BgCreatures . size ();
for ( int i = 0 ; i < size ; ++ i )
{
DelCreature ( i );
}
size = m_BgObjects . size ();
for ( int i = 0 ; i < size ; ++ i )
{
DelObject ( i );
}
2008-10-02 16:23:55 -05:00
2009-02-17 17:40:38 -06:00
if ( GetInstanceID ()) // not spam by useless queries in case BG templates
{
// 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
}
2009-02-27 12:57:33 -06:00
sBattleGroundMgr . RemoveBattleGround ( GetInstanceID (), GetTypeID ());
2008-10-05 08:48:32 -05:00
// unload map
2009-04-08 16:33:46 -05:00
if ( Map * map = MapManager :: Instance (). FindMap ( GetMapId (), GetInstanceID ()))
if ( map -> IsBattleGroundOrArena ())
2008-10-05 08:48:32 -05:00
(( BattleGroundMap * ) map ) -> SetUnload ();
// remove from bg free slot queue
this -> RemoveFromBGFreeSlotQueue ();
2008-10-02 16:23:55 -05:00
}
2009-01-21 16:18:57 -06:00
void BattleGround :: Update ( uint32 diff )
2008-10-02 16:23:55 -05:00
{
2009-04-08 16:33:46 -05:00
if ( ! GetPlayersSize () && ! GetReviveQueueSize ())
2008-10-02 16:23:55 -05:00
//BG is empty
return ;
2009-03-09 16:36:58 -06:00
// remove offline players from bg after 5 minutes
2009-04-08 16:33:46 -05:00
if ( ! m_OfflineQueue . empty ())
2008-10-02 16:23:55 -05:00
{
2009-03-09 17:07:12 -06:00
BattleGroundPlayerMap :: iterator itr = m_Players . find ( * ( m_OfflineQueue . begin ()));
2009-04-08 16:33:46 -05:00
if ( itr != m_Players . end ())
2008-10-02 16:23:55 -05:00
{
2009-04-08 16:33:46 -05:00
if ( itr -> second . OfflineRemoveTime <= sWorld . GetGameTime ())
2009-03-09 17:07:12 -06:00
{
2009-03-09 17:07:40 -06:00
RemovePlayerAtLeave ( itr -> first , true , true ); // remove player from BG
2009-03-09 17:07:12 -06:00
m_OfflineQueue . pop_front (); // remove from offline queue
2009-03-09 17:58:04 -06:00
//do not use itr for anything, because it is erased in RemovePlayerAtLeave()
2009-03-09 17:07:12 -06:00
}
2008-10-02 16:23:55 -05:00
}
2009-02-10 01:16:16 -06:00
}
2008-10-02 16:23:55 -05:00
2009-03-07 12:05:30 -06:00
/*********************************************************/
/*** BATTLEGROUND RESSURECTION SYSTEM ***/
/*********************************************************/
2009-03-09 16:36:58 -06:00
//this should be handled by spell system
2008-10-02 16:23:55 -05:00
m_LastResurrectTime += diff ;
if ( m_LastResurrectTime >= RESURRECTION_INTERVAL )
{
2009-04-08 16:33:46 -05:00
if ( GetReviveQueueSize ())
2008-10-02 16:23:55 -05:00
{
for ( std :: map < uint64 , std :: vector < uint64 > >:: iterator itr = m_ReviveQueue . begin (); itr != m_ReviveQueue . end (); ++ itr )
{
Creature * sh = NULL ;
2009-04-29 00:26:07 -05:00
for ( std :: vector < uint64 >:: const_iterator itr2 = ( itr -> second ). begin (); itr2 != ( itr -> second ). end (); ++ itr2 )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( * itr2 );
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
continue ;
2009-04-20 20:28:19 -05:00
if ( ! sh && plr -> IsInWorld ())
2008-10-02 16:23:55 -05:00
{
2009-04-20 20:28:19 -05:00
sh = plr -> GetMap () -> GetCreature ( itr -> first );
2008-10-02 16:23:55 -05:00
// only for visual effect
if ( sh )
sh -> CastSpell ( sh , SPELL_SPIRIT_HEAL , true ); // Spirit Heal, effect 117
}
plr -> CastSpell ( plr , SPELL_RESURRECTION_VISUAL , true ); // Resurrection visual
m_ResurrectQueue . push_back ( * itr2 );
}
( itr -> second ). clear ();
}
m_ReviveQueue . clear ();
m_LastResurrectTime = 0 ;
}
else
// queue is clear and time passed, just update last resurrection time
m_LastResurrectTime = 0 ;
}
else if ( m_LastResurrectTime > 500 ) // Resurrect players only half a second later, to see spirit heal effect on NPC
{
2009-04-29 00:26:07 -05:00
for ( std :: vector < uint64 >:: const_iterator itr = m_ResurrectQueue . begin (); itr != m_ResurrectQueue . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( * itr );
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
continue ;
plr -> ResurrectPlayer ( 1.0f );
plr -> CastSpell ( plr , SPELL_SPIRIT_HEAL_MANA , true );
ObjectAccessor :: Instance (). ConvertCorpseForPlayer ( * itr );
}
m_ResurrectQueue . clear ();
}
2009-03-07 12:05:30 -06:00
/*********************************************************/
/*** BATTLEGROUND BALLANCE SYSTEM ***/
/*********************************************************/
2008-10-05 08:48:32 -05:00
// if less then minimum players are in on one side, then start premature finish timer
2009-04-08 16:33:46 -05:00
if ( GetStatus () == STATUS_IN_PROGRESS && ! isArena () && sBattleGroundMgr . GetPrematureFinishTime () && ( GetPlayersCountByTeam ( ALLIANCE ) < GetMinPlayersPerTeam () || GetPlayersCountByTeam ( HORDE ) < GetMinPlayersPerTeam ()))
2008-10-05 08:48:32 -05:00
{
2009-04-08 16:33:46 -05:00
if ( ! m_PrematureCountDown )
2008-10-05 08:48:32 -05:00
{
m_PrematureCountDown = true ;
m_PrematureCountDownTimer = sBattleGroundMgr . GetPrematureFinishTime ();
}
2009-04-08 16:33:46 -05:00
else if ( m_PrematureCountDownTimer < diff )
2008-10-05 08:48:32 -05:00
{
// time's up!
2009-03-09 18:14:06 -06:00
uint32 winner = 0 ;
2009-04-08 16:33:46 -05:00
if ( GetPlayersCountByTeam ( ALLIANCE ) >= GetMinPlayersPerTeam ())
2009-03-09 18:14:06 -06:00
winner = ALLIANCE ;
2009-04-08 16:33:46 -05:00
else if ( GetPlayersCountByTeam ( HORDE ) >= GetMinPlayersPerTeam ())
2009-03-09 18:14:06 -06:00
winner = HORDE ;
EndBattleGround ( winner );
2008-10-05 08:48:32 -05:00
m_PrematureCountDown = false ;
2008-12-19 16:05:13 -06:00
}
else
2008-10-05 08:48:32 -05:00
{
uint32 newtime = m_PrematureCountDownTimer - diff ;
// announce every minute
2009-04-08 16:33:46 -05:00
if ( newtime > ( MINUTE * IN_MILISECONDS ))
2009-03-06 15:25:20 -06:00
{
2009-04-08 16:33:46 -05:00
if ( newtime / ( MINUTE * IN_MILISECONDS ) != m_PrematureCountDownTimer / ( MINUTE * IN_MILISECONDS ))
2009-03-09 17:00:31 -06:00
PSendMessageToAll ( LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING , CHAT_MSG_SYSTEM , NULL , ( uint32 )( m_PrematureCountDownTimer / ( MINUTE * IN_MILISECONDS )));
2009-03-06 15:25:20 -06:00
}
else
{
//announce every 15 seconds
2009-04-08 16:33:46 -05:00
if ( newtime / ( 15 * IN_MILISECONDS ) != m_PrematureCountDownTimer / ( 15 * IN_MILISECONDS ))
2009-03-09 17:00:31 -06:00
PSendMessageToAll ( LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING_SECS , CHAT_MSG_SYSTEM , NULL , ( uint32 )( m_PrematureCountDownTimer / IN_MILISECONDS ));
2009-03-06 15:25:20 -06:00
}
2008-10-05 08:48:32 -05:00
m_PrematureCountDownTimer = newtime ;
}
}
else if ( m_PrematureCountDown )
m_PrematureCountDown = false ;
2009-03-07 12:05:30 -06:00
/*********************************************************/
/*** BATTLEGROUND STARTING SYSTEM ***/
/*********************************************************/
if ( GetStatus () == STATUS_WAIT_JOIN && GetPlayersSize ())
{
ModifyStartDelayTime ( diff );
if ( ! ( m_Events & BG_STARTING_EVENT_1 ))
{
m_Events |= BG_STARTING_EVENT_1 ;
// setup here, only when at least one player has ported to the map
2009-04-08 16:33:46 -05:00
if ( ! SetupBattleGround ())
2009-03-07 12:05:30 -06:00
{
EndNow ();
return ;
}
StartingEventCloseDoors ();
SetStartDelayTime ( m_StartDelayTimes [ BG_STARTING_EVENT_FIRST ]);
//first start warning - 2 or 1 minute
SendMessageToAll ( m_StartMessageIds [ BG_STARTING_EVENT_FIRST ], CHAT_MSG_BG_SYSTEM_NEUTRAL );
}
// After 1 minute or 30 seconds, warning is signalled
else if ( GetStartDelayTime () <= m_StartDelayTimes [ BG_STARTING_EVENT_SECOND ] && ! ( m_Events & BG_STARTING_EVENT_2 ))
{
m_Events |= BG_STARTING_EVENT_2 ;
SendMessageToAll ( m_StartMessageIds [ BG_STARTING_EVENT_SECOND ], CHAT_MSG_BG_SYSTEM_NEUTRAL );
}
// After 30 or 15 seconds, warning is signalled
else if ( GetStartDelayTime () <= m_StartDelayTimes [ BG_STARTING_EVENT_THIRD ] && ! ( m_Events & BG_STARTING_EVENT_3 ))
{
m_Events |= BG_STARTING_EVENT_3 ;
SendMessageToAll ( m_StartMessageIds [ BG_STARTING_EVENT_THIRD ], CHAT_MSG_BG_SYSTEM_NEUTRAL );
}
// delay expired (atfer 2 or 1 minute)
else if ( GetStartDelayTime () <= 0 && ! ( m_Events & BG_STARTING_EVENT_4 ))
{
m_Events |= BG_STARTING_EVENT_4 ;
StartingEventOpenDoors ();
SendMessageToAll ( m_StartMessageIds [ BG_STARTING_EVENT_FOURTH ], CHAT_MSG_BG_SYSTEM_NEUTRAL );
SetStatus ( STATUS_IN_PROGRESS );
SetStartDelayTime ( m_StartDelayTimes [ BG_STARTING_EVENT_FOURTH ]);
//remove preparation
2009-04-08 16:33:46 -05:00
if ( isArena ())
2009-03-07 12:05:30 -06:00
{
2009-03-09 16:36:58 -06:00
//TODO : add arena sound PlaySoundToAll(SOUND_ARENA_START);
2009-03-07 12:05:30 -06:00
for ( BattleGroundPlayerMap :: const_iterator itr = GetPlayers (). begin (); itr != GetPlayers (). end (); ++ itr )
2009-04-08 16:33:46 -05:00
if ( Player * plr = objmgr . GetPlayer ( itr -> first ))
2009-05-24 22:54:13 +02:00
{
2009-03-07 12:05:30 -06:00
plr -> RemoveAurasDueToSpell ( SPELL_ARENA_PREPARATION );
2009-05-24 22:54:13 +02:00
// remove auras with duration lower than 30s
Unit :: AuraMap & aurMap = plr -> GetAuras ();
for ( Unit :: AuraMap :: iterator iter = aurMap . begin (); iter != aurMap . end ();)
{
2009-05-25 17:04:52 +02:00
if ( ! iter -> second -> IsPermanent ()
&& iter -> second -> GetAuraDuration () <= 30 * IN_MILISECONDS
&& iter -> second -> IsPositive ()
&& ( ! ( iter -> second -> GetSpellProto () -> Attributes & SPELL_ATTR_UNAFFECTED_BY_INVULNERABILITY ))
&& ( ! iter -> second -> IsAuraType ( SPELL_AURA_MOD_INVISIBILITY )))
2009-05-24 22:54:13 +02:00
{
plr -> RemoveAura ( iter );
}
else
++ iter ;
}
}
2009-03-07 12:05:30 -06:00
2009-03-09 16:36:58 -06:00
CheckArenaWinConditions ();
2009-03-07 12:05:30 -06:00
}
else
{
PlaySoundToAll ( SOUND_BG_START );
for ( BattleGroundPlayerMap :: const_iterator itr = GetPlayers (). begin (); itr != GetPlayers (). end (); ++ itr )
2009-04-08 16:33:46 -05:00
if ( Player * plr = objmgr . GetPlayer ( itr -> first ))
2009-03-07 12:05:30 -06:00
plr -> RemoveAurasDueToSpell ( SPELL_PREPARATION );
2009-03-09 16:36:58 -06:00
//Announce BG starting
2009-04-08 16:33:46 -05:00
if ( sWorld . getConfig ( CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_ENABLE ))
2009-03-07 12:05:30 -06:00
{
sWorld . SendWorldText ( LANG_BG_STARTED_ANNOUNCE_WORLD , GetName (), GetMinLevel (), GetMaxLevel ());
}
}
}
}
/*********************************************************/
/*** BATTLEGROUND ENDING SYSTEM ***/
/*********************************************************/
2009-04-08 16:33:46 -05:00
if ( GetStatus () == STATUS_WAIT_LEAVE )
2008-10-02 16:23:55 -05:00
{
// remove all players from battleground after 2 minutes
2009-03-13 18:06:36 -06:00
m_EndTime -= diff ;
2009-04-08 16:33:46 -05:00
if ( m_EndTime <= 0 )
2008-10-02 16:23:55 -05:00
{
2009-03-13 18:06:36 -06:00
m_EndTime = 0 ;
2009-03-09 17:58:04 -06:00
BattleGroundPlayerMap :: iterator itr , next ;
for ( itr = m_Players . begin (); itr != m_Players . end (); itr = next )
{
next = itr ;
++ next ;
//itr is erased here!
2009-03-09 17:07:40 -06:00
RemovePlayerAtLeave ( itr -> first , true , true ); // remove player from BG
2009-03-09 17:58:04 -06:00
// do not change any battleground's private variables
}
2008-10-02 16:23:55 -05:00
}
}
2009-03-07 12:05:30 -06:00
2009-03-13 18:06:36 -06:00
//update start time
m_StartTime += diff ;
2008-10-02 16:23:55 -05:00
}
void BattleGround :: SetTeamStartLoc ( uint32 TeamID , float X , float Y , float Z , float O )
{
uint8 idx = GetTeamIndexByTeamId ( TeamID );
m_TeamStartLocX [ idx ] = X ;
m_TeamStartLocY [ idx ] = Y ;
m_TeamStartLocZ [ idx ] = Z ;
m_TeamStartLocO [ idx ] = O ;
}
void BattleGround :: SendPacketToAll ( WorldPacket * packet )
{
2009-04-29 00:26:07 -05:00
for ( BattleGroundPlayerMap :: const_iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( itr -> first );
2009-04-08 16:33:46 -05:00
if ( plr )
2008-10-02 16:23:55 -05:00
plr -> GetSession () -> SendPacket ( packet );
else
sLog . outError ( "BattleGround: Player " I64FMTD " not found!" , itr -> first );
}
}
void BattleGround :: SendPacketToTeam ( uint32 TeamID , WorldPacket * packet , Player * sender , bool self )
{
2009-04-29 00:26:07 -05:00
for ( BattleGroundPlayerMap :: const_iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( itr -> first );
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
{
sLog . outError ( "BattleGround: Player " I64FMTD " not found!" , itr -> first );
continue ;
}
2009-04-08 16:33:46 -05:00
if ( ! self && sender == plr )
2008-10-02 16:23:55 -05:00
continue ;
2009-02-13 20:10:14 -06:00
uint32 team = itr -> second . Team ;
2008-12-19 16:05:13 -06:00
if ( ! team ) team = plr -> GetTeam ();
2008-10-05 08:48:32 -05:00
2009-04-08 16:33:46 -05:00
if ( team == TeamID )
2008-10-02 16:23:55 -05:00
plr -> GetSession () -> SendPacket ( packet );
}
}
void BattleGround :: PlaySoundToAll ( uint32 SoundID )
{
WorldPacket data ;
sBattleGroundMgr . BuildPlaySoundPacket ( & data , SoundID );
SendPacketToAll ( & data );
}
void BattleGround :: PlaySoundToTeam ( uint32 SoundID , uint32 TeamID )
{
WorldPacket data ;
2009-04-29 00:26:07 -05:00
for ( BattleGroundPlayerMap :: const_iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( itr -> first );
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
{
sLog . outError ( "BattleGround: Player " I64FMTD " not found!" , itr -> first );
continue ;
}
2009-02-13 20:10:14 -06:00
uint32 team = itr -> second . Team ;
2008-12-19 16:05:13 -06:00
if ( ! team ) team = plr -> GetTeam ();
2008-10-05 08:48:32 -05:00
2009-04-08 16:33:46 -05:00
if ( team == TeamID )
2008-10-02 16:23:55 -05:00
{
sBattleGroundMgr . BuildPlaySoundPacket ( & data , SoundID );
plr -> GetSession () -> SendPacket ( & data );
}
}
}
void BattleGround :: CastSpellOnTeam ( uint32 SpellID , uint32 TeamID )
{
2009-04-29 00:26:07 -05:00
for ( BattleGroundPlayerMap :: const_iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( itr -> first );
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
{
sLog . outError ( "BattleGround: Player " I64FMTD " not found!" , itr -> first );
continue ;
}
2009-02-13 20:10:14 -06:00
uint32 team = itr -> second . Team ;
2008-12-19 16:05:13 -06:00
if ( ! team ) team = plr -> GetTeam ();
2009-04-08 16:33:46 -05:00
if ( team == TeamID )
2008-10-02 16:23:55 -05:00
plr -> CastSpell ( plr , SpellID , true );
}
}
2008-11-21 19:45:49 -06:00
void BattleGround :: YellToAll ( Creature * creature , const char * text , uint32 language )
{
for ( std :: map < uint64 , BattleGroundPlayer >:: iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
{
WorldPacket data ( SMSG_MESSAGECHAT , 200 );
Player * plr = objmgr . GetPlayer ( itr -> first );
if ( ! plr )
{
sLog . outError ( "BattleGround: Player " I64FMTD " not found!" , itr -> first );
continue ;
}
creature -> BuildMonsterChat ( & data , CHAT_MSG_MONSTER_YELL , text , language , creature -> GetName (), itr -> first );
plr -> GetSession () -> SendPacket ( & data );
}
}
2008-10-02 16:23:55 -05:00
void BattleGround :: RewardHonorToTeam ( uint32 Honor , uint32 TeamID )
{
2009-04-29 00:26:07 -05:00
for ( BattleGroundPlayerMap :: const_iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( itr -> first );
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
{
sLog . outError ( "BattleGround: Player " I64FMTD " not found!" , itr -> first );
continue ;
}
2009-02-13 20:10:14 -06:00
uint32 team = itr -> second . Team ;
2008-12-19 16:05:13 -06:00
if ( ! team ) team = plr -> GetTeam ();
2008-10-05 08:48:32 -05:00
2009-04-08 16:33:46 -05:00
if ( team == TeamID )
2008-10-02 16:23:55 -05:00
UpdatePlayerScore ( plr , SCORE_BONUS_HONOR , Honor );
}
}
void BattleGround :: RewardReputationToTeam ( uint32 faction_id , uint32 Reputation , uint32 TeamID )
{
FactionEntry const * factionEntry = sFactionStore . LookupEntry ( faction_id );
2009-04-08 16:33:46 -05:00
if ( ! factionEntry )
2008-10-02 16:23:55 -05:00
return ;
2009-04-29 00:26:07 -05:00
for ( BattleGroundPlayerMap :: const_iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( itr -> first );
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
{
sLog . outError ( "BattleGround: Player " I64FMTD " not found!" , itr -> first );
continue ;
}
2009-02-13 20:10:14 -06:00
uint32 team = itr -> second . Team ;
2008-12-19 16:05:13 -06:00
if ( ! team ) team = plr -> GetTeam ();
2008-10-05 08:48:32 -05:00
2009-04-08 16:33:46 -05:00
if ( team == TeamID )
2009-03-26 13:53:32 -06:00
plr -> GetReputationMgr (). ModifyReputation ( factionEntry , Reputation );
2008-10-02 16:23:55 -05:00
}
}
void BattleGround :: UpdateWorldState ( uint32 Field , uint32 Value )
{
WorldPacket data ;
sBattleGroundMgr . BuildUpdateWorldStatePacket ( & data , Field , Value );
SendPacketToAll ( & data );
}
void BattleGround :: UpdateWorldStateForPlayer ( uint32 Field , uint32 Value , Player * Source )
{
WorldPacket data ;
sBattleGroundMgr . BuildUpdateWorldStatePacket ( & data , Field , Value );
Source -> GetSession () -> SendPacket ( & data );
}
void BattleGround :: EndBattleGround ( uint32 winner )
{
2008-10-05 08:48:32 -05:00
this -> RemoveFromBGFreeSlotQueue ();
ArenaTeam * winner_arena_team = NULL ;
ArenaTeam * loser_arena_team = NULL ;
uint32 loser_rating = 0 ;
uint32 winner_rating = 0 ;
2008-10-02 16:23:55 -05:00
WorldPacket data ;
2009-03-09 17:00:31 -06:00
int32 winmsg_id = 0 ;
2008-10-02 16:23:55 -05:00
2009-04-08 16:33:46 -05:00
if ( winner == ALLIANCE )
2008-10-02 16:23:55 -05:00
{
2009-03-09 17:00:31 -06:00
winmsg_id = isBattleGround () ? LANG_BG_A_WINS : LANG_ARENA_GOLD_WINS ;
2008-10-02 16:23:55 -05:00
PlaySoundToAll ( SOUND_ALLIANCE_WINS ); // alliance wins sound
SetWinner ( WINNER_ALLIANCE );
}
2009-04-08 16:33:46 -05:00
else if ( winner == HORDE )
2008-10-02 16:23:55 -05:00
{
2009-03-09 17:00:31 -06:00
winmsg_id = isBattleGround () ? LANG_BG_H_WINS : LANG_ARENA_GREEN_WINS ;
2008-10-02 16:23:55 -05:00
PlaySoundToAll ( SOUND_HORDE_WINS ); // horde wins sound
SetWinner ( WINNER_HORDE );
}
2008-10-05 08:48:32 -05:00
else
{
SetWinner ( 3 );
}
2008-10-02 16:23:55 -05:00
SetStatus ( STATUS_WAIT_LEAVE );
2009-03-13 18:06:36 -06:00
//we must set it this way, because end time is sent in packet!
m_EndTime = TIME_TO_AUTOREMOVE ;
2008-10-02 16:23:55 -05:00
2008-10-05 08:48:32 -05:00
// arena rating calculation
2009-04-08 16:33:46 -05:00
if ( isArena () && isRated ())
2008-10-05 08:48:32 -05:00
{
2009-03-09 17:07:40 -06:00
winner_arena_team = objmgr . GetArenaTeamById ( GetArenaTeamIdForTeam ( winner ));
loser_arena_team = objmgr . GetArenaTeamById ( GetArenaTeamIdForTeam ( GetOtherTeam ( winner )));
2009-04-08 16:33:46 -05:00
if ( winner_arena_team && loser_arena_team )
2008-10-05 08:48:32 -05:00
{
loser_rating = loser_arena_team -> GetStats (). rating ;
winner_rating = winner_arena_team -> GetStats (). rating ;
2008-12-19 16:05:13 -06:00
int32 winner_change = winner_arena_team -> WonAgainst ( loser_rating );
int32 loser_change = loser_arena_team -> LostAgainst ( winner_rating );
sLog . outDebug ( "--- Winner rating: %u, Loser rating: %u, Winner change: %u, Losser change: %u ---" , winner_rating , loser_rating , winner_change , loser_change );
2009-03-09 17:07:40 -06:00
SetArenaTeamRatingChangeForTeam ( winner , winner_change );
SetArenaTeamRatingChangeForTeam ( GetOtherTeam ( winner ), loser_change );
2008-10-05 08:48:32 -05:00
}
else
{
SetArenaTeamRatingChangeForTeam ( ALLIANCE , 0 );
SetArenaTeamRatingChangeForTeam ( HORDE , 0 );
}
}
2009-03-09 17:07:12 -06:00
for ( BattleGroundPlayerMap :: iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( itr -> first );
2009-03-09 17:07:40 -06:00
uint32 team = itr -> second . Team ;
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
{
2009-03-09 17:07:40 -06:00
//if rated arena match - make member lost!
2009-04-08 16:33:46 -05:00
if ( isArena () && isRated () && winner_arena_team && loser_arena_team )
2009-03-09 17:07:40 -06:00
{
2009-04-08 16:33:46 -05:00
if ( team == winner )
2009-03-09 17:07:40 -06:00
winner_arena_team -> OfflineMemberLost ( itr -> first , loser_rating );
else
loser_arena_team -> OfflineMemberLost ( itr -> first , winner_rating );
}
2008-10-02 16:23:55 -05:00
sLog . outError ( "BattleGround: Player " I64FMTD " not found!" , itr -> first );
continue ;
}
2008-10-05 08:48:32 -05:00
// should remove spirit of redemption
if ( plr -> HasAuraType ( SPELL_AURA_SPIRIT_OF_REDEMPTION ))
2009-04-06 13:31:14 +02:00
plr -> RemoveAurasByType ( SPELL_AURA_MOD_SHAPESHIFT );
2008-10-05 08:48:32 -05:00
2009-04-08 16:33:46 -05:00
if ( ! plr -> isAlive ())
2008-10-02 16:23:55 -05:00
{
plr -> ResurrectPlayer ( 1.0f );
plr -> SpawnCorpseBones ();
}
2009-03-09 17:07:40 -06:00
//this line is obsolete - team is set ALWAYS
//if(!team) team = plr->GetTeam();
2008-10-05 08:48:32 -05:00
// per player calculation
2009-04-08 16:33:46 -05:00
if ( isArena () && isRated () && winner_arena_team && loser_arena_team )
2008-10-05 08:48:32 -05:00
{
2009-04-08 16:33:46 -05:00
if ( team == winner )
2008-10-05 08:48:32 -05:00
winner_arena_team -> MemberWon ( plr , loser_rating );
else
loser_arena_team -> MemberLost ( plr , winner_rating );
}
2009-04-08 16:33:46 -05:00
if ( team == winner )
2008-10-02 16:23:55 -05:00
{
RewardMark ( plr , ITEM_WINNER_COUNT );
2009-05-10 14:43:29 -05:00
RewardQuestComplete ( plr );
2008-10-02 16:23:55 -05:00
}
2009-05-10 14:43:29 -05:00
else if ( winner )
2008-10-02 16:23:55 -05:00
RewardMark ( plr , ITEM_LOSER_COUNT );
plr -> CombatStopWithPets ( true );
BlockMovement ( plr );
sBattleGroundMgr . BuildPvpLogDataPacket ( & data , this );
plr -> GetSession () -> SendPacket ( & data );
2009-02-13 19:56:22 -06:00
BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr :: BGQueueTypeId ( GetTypeID (), GetArenaType ());
2009-03-13 18:06:36 -06:00
sBattleGroundMgr . BuildBattleGroundStatusPacket ( & data , this , plr -> GetBattleGroundQueueIndex ( bgQueueTypeId ), STATUS_IN_PROGRESS , TIME_TO_AUTOREMOVE , GetStartTime (), GetArenaType ());
2008-10-02 16:23:55 -05:00
plr -> GetSession () -> SendPacket ( & data );
2008-12-24 09:58:26 -06:00
plr -> GetAchievementMgr (). UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND , 1 );
2008-10-02 16:23:55 -05:00
}
2009-04-08 16:33:46 -05:00
if ( isArena () && isRated () && winner_arena_team && loser_arena_team )
2008-10-05 08:48:32 -05:00
{
// update arena points only after increasing the player's match count!
2008-12-19 16:05:13 -06:00
//obsolete: winner_arena_team->UpdateArenaPointsHelper();
//obsolete: loser_arena_team->UpdateArenaPointsHelper();
2008-10-05 08:48:32 -05:00
// save the stat changes
winner_arena_team -> SaveToDB ();
loser_arena_team -> SaveToDB ();
// send updated arena team stats to players
// this way all arena team members will get notified, not only the ones who participated in this match
winner_arena_team -> NotifyStatsChanged ();
loser_arena_team -> NotifyStatsChanged ();
}
2009-04-08 16:33:46 -05:00
if ( winmsg_id )
2009-03-09 18:14:06 -06:00
SendMessageToAll ( winmsg_id , CHAT_MSG_BG_SYSTEM_NEUTRAL );
}
uint32 BattleGround :: GetBonusHonorFromKill ( uint32 kills ) const
{
//variable kills means how many honorable kills you scored (so we need kills * honor_for_one_kill)
return MaNGOS :: Honor :: hk_honor_at_level ( GetMaxLevel (), kills );
2008-10-02 16:23:55 -05:00
}
uint32 BattleGround :: GetBattlemasterEntry () const
{
switch ( GetTypeID ())
{
case BATTLEGROUND_AV : return 15972 ;
case BATTLEGROUND_WS : return 14623 ;
case BATTLEGROUND_AB : return 14879 ;
case BATTLEGROUND_EY : return 22516 ;
case BATTLEGROUND_NA : return 20200 ;
default : return 0 ;
}
}
void BattleGround :: RewardMark ( Player * plr , uint32 count )
{
2009-04-06 21:14:51 +02:00
BattleGroundMarks mark ;
2008-10-02 16:23:55 -05:00
switch ( GetTypeID ())
{
case BATTLEGROUND_AV :
2009-03-07 08:41:31 +01:00
mark = ITEM_AV_MARK_OF_HONOR ;
2008-10-02 16:23:55 -05:00
break ;
case BATTLEGROUND_WS :
2009-03-07 08:41:31 +01:00
mark = ITEM_WS_MARK_OF_HONOR ;
2008-10-02 16:23:55 -05:00
break ;
case BATTLEGROUND_AB :
2009-03-07 08:41:31 +01:00
mark = ITEM_AB_MARK_OF_HONOR ;
2008-10-02 16:23:55 -05:00
break ;
2009-04-06 21:14:51 +02:00
case BATTLEGROUND_EY :
2008-10-02 16:23:55 -05:00
mark = ITEM_EY_MARK_OF_HONOR ;
break ;
default :
return ;
}
2009-05-10 14:43:29 -05:00
//if (IsSpell)
// RewardSpellCast(plr,mark);
//else
RewardItem ( plr , mark , count );
}
void BattleGround :: RewardSpellCast ( Player * plr , uint32 spell_id )
{
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
if ( plr -> GetDummyAura ( SPELL_AURA_PLAYER_INACTIVE ))
return ;
SpellEntry const * spellInfo = sSpellStore . LookupEntry ( spell_id );
if ( ! spellInfo )
2008-10-02 16:23:55 -05:00
{
2009-05-10 14:43:29 -05:00
sLog . outError ( "Battleground reward casting spell %u not exist." , spell_id );
return ;
2008-10-02 16:23:55 -05:00
}
2009-05-10 14:43:29 -05:00
plr -> CastSpell ( plr , spellInfo , true );
}
void BattleGround :: RewardItem ( Player * plr , uint32 item_id , uint32 count )
{
// 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
if ( plr -> GetDummyAura ( SPELL_AURA_PLAYER_INACTIVE ))
return ;
ItemPosCountVec dest ;
uint32 no_space_count = 0 ;
uint8 msg = plr -> CanStoreNewItem ( NULL_BAG , NULL_SLOT , dest , item_id , count , & no_space_count );
if ( msg == EQUIP_ERR_ITEM_NOT_FOUND )
{
sLog . outErrorDb ( "Battleground reward item (Entry %u) not exist in `item_template`." , item_id );
return ;
}
if ( msg != EQUIP_ERR_OK ) // convert to possible store amount
count -= no_space_count ;
if ( count != 0 && ! dest . empty ()) // can add some
if ( Item * item = plr -> StoreNewItem ( dest , item_id , true , 0 ))
plr -> SendNewItem ( item , count , false , true );
if ( no_space_count > 0 )
SendRewardMarkByMail ( plr , item_id , no_space_count );
2008-10-02 16:23:55 -05:00
}
void BattleGround :: SendRewardMarkByMail ( Player * plr , uint32 mark , uint32 count )
{
uint32 bmEntry = GetBattlemasterEntry ();
2009-04-08 16:33:46 -05:00
if ( ! bmEntry )
2008-10-02 16:23:55 -05:00
return ;
ItemPrototype const * markProto = objmgr . GetItemPrototype ( mark );
2009-04-08 16:33:46 -05:00
if ( ! markProto )
2008-10-02 16:23:55 -05:00
return ;
2009-04-08 16:33:46 -05:00
if ( Item * markItem = Item :: CreateItem ( mark , count , plr ))
2008-10-02 16:23:55 -05:00
{
// save new item before send
markItem -> SaveToDB (); // save for prevent lost at next mail load, if send fail then item will deleted
// item
MailItemsInfo mi ;
mi . AddItem ( markItem -> GetGUIDLow (), markItem -> GetEntry (), markItem );
// subject: item name
std :: string subject = markProto -> Name1 ;
int loc_idx = plr -> GetSession () -> GetSessionDbLocaleIndex ();
2009-04-08 16:33:46 -05:00
if ( loc_idx >= 0 )
if ( ItemLocale const * il = objmgr . GetItemLocale ( markProto -> ItemId ))
2008-12-19 16:05:13 -06:00
if ( il -> Name . size () > size_t ( loc_idx ) && ! il -> Name [ loc_idx ]. empty ())
2008-10-02 16:23:55 -05:00
subject = il -> Name [ loc_idx ];
// text
2008-10-14 11:57:03 -05:00
std :: string textFormat = plr -> GetSession () -> GetTrinityString ( LANG_BG_MARK_BY_MAIL );
2008-10-02 16:23:55 -05:00
char textBuf [ 300 ];
snprintf ( textBuf , 300 , textFormat . c_str (), GetName (), GetName ());
uint32 itemTextId = objmgr . CreateItemText ( textBuf );
WorldSession :: SendMailTo ( plr , MAIL_CREATURE , MAIL_STATIONERY_NORMAL , bmEntry , plr -> GetGUIDLow (), subject , itemTextId , & mi , 0 , 0 , MAIL_CHECK_MASK_NONE );
}
}
2009-05-10 14:43:29 -05:00
void BattleGround :: RewardQuestComplete ( Player * plr )
2008-10-02 16:23:55 -05:00
{
uint32 quest ;
switch ( GetTypeID ())
{
case BATTLEGROUND_AV :
quest = SPELL_AV_QUEST_REWARD ;
break ;
case BATTLEGROUND_WS :
quest = SPELL_WS_QUEST_REWARD ;
break ;
case BATTLEGROUND_AB :
quest = SPELL_AB_QUEST_REWARD ;
break ;
case BATTLEGROUND_EY :
quest = SPELL_EY_QUEST_REWARD ;
break ;
default :
return ;
}
2009-05-10 14:43:29 -05:00
RewardSpellCast ( plr , quest );
2008-10-02 16:23:55 -05:00
}
void BattleGround :: BlockMovement ( Player * plr )
{
plr -> SetClientControl ( plr , 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()
}
void BattleGround :: RemovePlayerAtLeave ( uint64 guid , bool Transport , bool SendPacket )
{
2008-10-05 08:48:32 -05:00
uint32 team = GetPlayerTeam ( guid );
bool participant = false ;
2008-10-02 16:23:55 -05:00
// Remove from lists/maps
2009-03-09 17:07:12 -06:00
BattleGroundPlayerMap :: iterator itr = m_Players . find ( guid );
2009-04-08 16:33:46 -05:00
if ( itr != m_Players . end ())
2008-10-02 16:23:55 -05:00
{
2009-03-09 18:14:06 -06:00
UpdatePlayersCountByTeam ( team , true ); // -1 player
2008-10-02 16:23:55 -05:00
m_Players . erase ( itr );
2008-10-05 08:48:32 -05:00
// check if the player was a participant of the match, or only entered through gm command (goname)
participant = true ;
2008-10-02 16:23:55 -05:00
}
std :: map < uint64 , BattleGroundScore *>:: iterator itr2 = m_PlayerScores . find ( guid );
2009-04-08 16:33:46 -05:00
if ( itr2 != m_PlayerScores . end ())
2008-10-02 16:23:55 -05:00
{
delete itr2 -> second ; // delete player's score
m_PlayerScores . erase ( itr2 );
}
RemovePlayerFromResurrectQueue ( guid );
Player * plr = objmgr . GetPlayer ( guid );
2008-10-05 08:48:32 -05:00
// should remove spirit of redemption
if ( plr && plr -> HasAuraType ( SPELL_AURA_SPIRIT_OF_REDEMPTION ))
2009-04-06 13:31:14 +02:00
plr -> RemoveAurasByType ( SPELL_AURA_MOD_SHAPESHIFT );
2008-10-05 08:48:32 -05:00
2008-10-02 16:23:55 -05:00
if ( plr && ! plr -> isAlive ()) // resurrect on exit
{
plr -> ResurrectPlayer ( 1.0f );
plr -> SpawnCorpseBones ();
}
RemovePlayer ( plr , guid ); // BG subclass specific code
2009-03-09 17:07:40 -06:00
if ( participant ) // if the player was a match participant, remove auras, calc rating, update queue
2008-10-02 16:23:55 -05:00
{
2009-03-09 17:07:40 -06:00
BattleGroundTypeId bgTypeId = GetTypeID ();
BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr :: BGQueueTypeId ( GetTypeID (), GetArenaType ());
2009-04-08 16:33:46 -05:00
if ( plr )
2008-10-02 16:23:55 -05:00
{
2009-03-09 17:07:40 -06:00
plr -> ClearAfkReports ();
2008-10-05 08:48:32 -05:00
if ( ! team ) team = plr -> GetTeam ();
2008-10-02 16:23:55 -05:00
2008-10-05 08:48:32 -05:00
// if arena, remove the specific arena auras
2009-04-08 16:33:46 -05:00
if ( isArena ())
2008-10-05 08:48:32 -05:00
{
2009-03-09 18:14:06 -06:00
plr -> RemoveArenaAuras ( true ); // removes debuffs / dots etc., we don't want the player to die after porting out
bgTypeId = BATTLEGROUND_AA ; // set the bg type to all arenas (it will be used for queue refreshing)
2008-10-02 16:23:55 -05:00
2009-04-11 14:47:38 -05:00
// unsummon current and summon old pet if there was one and there isn't a current pet
plr -> RemovePet ( NULL , PET_SAVE_NOT_IN_SLOT );
plr -> ResummonPetTemporaryUnSummonedIfAny ();
2008-10-02 16:23:55 -05:00
2009-04-08 16:33:46 -05:00
if ( isRated () && GetStatus () == STATUS_IN_PROGRESS )
2008-10-05 08:48:32 -05:00
{
//left a rated match while the encounter was in progress, consider as loser
2009-03-09 17:07:40 -06:00
ArenaTeam * winner_arena_team = objmgr . GetArenaTeamById ( GetArenaTeamIdForTeam ( GetOtherTeam ( team )));
ArenaTeam * loser_arena_team = objmgr . GetArenaTeamById ( GetArenaTeamIdForTeam ( team ));
2009-04-08 16:33:46 -05:00
if ( winner_arena_team && loser_arena_team )
2008-10-05 08:48:32 -05:00
loser_arena_team -> MemberLost ( plr , winner_arena_team -> GetRating ());
}
}
2009-04-08 16:33:46 -05:00
if ( SendPacket )
2008-10-05 08:48:32 -05:00
{
2009-03-09 17:07:40 -06:00
WorldPacket data ;
2009-03-13 18:06:36 -06:00
sBattleGroundMgr . BuildBattleGroundStatusPacket ( & data , this , plr -> GetBattleGroundQueueIndex ( bgQueueTypeId ), STATUS_NONE , 0 , 0 , 0 );
2008-10-05 08:48:32 -05:00
plr -> GetSession () -> SendPacket ( & data );
}
2008-10-02 16:23:55 -05:00
2008-10-05 08:48:32 -05:00
// 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 ( bgQueueTypeId );
2009-03-09 17:07:40 -06:00
}
else
// removing offline participant
{
2009-04-08 16:33:46 -05:00
if ( isRated () && GetStatus () == STATUS_IN_PROGRESS )
2008-10-02 16:23:55 -05:00
{
2009-03-09 17:07:40 -06:00
//left a rated match while the encounter was in progress, consider as loser
ArenaTeam * others_arena_team = objmgr . GetArenaTeamById ( GetArenaTeamIdForTeam ( GetOtherTeam ( team )));
ArenaTeam * players_arena_team = objmgr . GetArenaTeamById ( GetArenaTeamIdForTeam ( team ));
2009-04-08 16:33:46 -05:00
if ( others_arena_team && players_arena_team )
2009-03-09 17:07:40 -06:00
players_arena_team -> OfflineMemberLost ( guid , others_arena_team -> GetRating ());
2008-10-02 16:23:55 -05:00
}
2009-03-09 17:07:40 -06:00
}
2008-10-05 08:48:32 -05:00
2009-03-09 17:07:40 -06:00
// remove from raid group if player is member
2009-04-08 16:33:46 -05:00
if ( Group * group = GetBgRaid ( team ))
2009-03-09 17:07:40 -06:00
{
2009-03-09 18:14:06 -06:00
if ( ! group -> RemoveMember ( guid , 0 ) ) // group was disbanded
2009-03-09 17:07:40 -06:00
{
SetBgRaid ( team , NULL );
delete group ;
}
2008-10-02 16:23:55 -05:00
}
2009-03-09 17:07:40 -06:00
DecreaseInvitedCount ( team );
//we should update battleground queue, but only if bg isn't ending
2009-04-08 16:33:46 -05:00
if ( isBattleGround () && GetStatus () < STATUS_WAIT_LEAVE )
2009-03-09 17:07:40 -06:00
sBattleGroundMgr . m_BattleGroundQueues [ bgQueueTypeId ]. Update ( bgTypeId , GetQueueId ());
// Let others know
WorldPacket data ;
sBattleGroundMgr . BuildPlayerLeftBattleGroundPacket ( & data , guid );
SendPacketToTeam ( team , & data , plr , false );
}
2008-10-02 16:23:55 -05:00
2009-04-08 16:33:46 -05:00
if ( plr )
2009-03-09 17:07:40 -06:00
{
2008-10-02 16:23:55 -05:00
// Do next only if found in battleground
2009-03-09 18:14:06 -06:00
plr -> SetBattleGroundId ( 0 , BATTLEGROUND_TYPE_NONE ); // We're not in BG.
2008-10-05 08:48:32 -05:00
// reset destination bg team
plr -> SetBGTeam ( 0 );
2008-10-02 16:23:55 -05:00
2009-04-08 16:33:46 -05:00
if ( Transport )
2009-02-10 01:06:39 -06:00
plr -> TeleportTo ( plr -> GetBattleGroundEntryPoint ());
2008-10-02 16:23:55 -05:00
sLog . outDetail ( "BATTLEGROUND: Removed player %s from BattleGround." , plr -> GetName ());
}
2009-04-08 16:33:46 -05:00
if ( ! GetPlayersSize () && ! GetInvitedCount ( HORDE ) && ! GetInvitedCount ( ALLIANCE ))
2008-10-02 16:23:55 -05:00
{
2008-10-05 08:48:32 -05:00
// if no players left AND no invitees left, set this bg to delete in next update
// direct deletion could cause crashes
m_SetDeleteThis = true ;
// return to prevent addition to freeslotqueue
return ;
2008-10-02 16:23:55 -05:00
}
2008-10-05 08:48:32 -05:00
// a player exited the battleground, so there are free slots. add to queue
this -> AddToBGFreeSlotQueue ();
2008-10-02 16:23:55 -05:00
}
// this method is called when no players remains in battleground
void BattleGround :: Reset ()
{
2009-02-27 12:13:59 -06:00
SetQueueId ( QUEUE_ID_MAX_LEVEL_19 );
2008-10-02 16:23:55 -05:00
SetWinner ( WINNER_NONE );
SetStatus ( STATUS_WAIT_QUEUE );
SetStartTime ( 0 );
SetEndTime ( 0 );
SetLastResurrectTime ( 0 );
2008-10-05 08:48:32 -05:00
SetArenaType ( 0 );
SetRated ( false );
2008-10-02 16:23:55 -05:00
m_Events = 0 ;
if ( m_InvitedAlliance > 0 || m_InvitedHorde > 0 )
2009-03-21 14:28:02 -06:00
sLog . outError ( "BattleGround system: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d" , m_InvitedAlliance , m_InvitedHorde );
2008-10-02 16:23:55 -05:00
m_InvitedAlliance = 0 ;
m_InvitedHorde = 0 ;
2008-10-05 08:48:32 -05:00
m_InBGFreeSlotQueue = false ;
2008-10-02 16:23:55 -05:00
m_Players . clear ();
m_PlayerScores . clear ();
}
void BattleGround :: StartBattleGround ()
{
///this method should spawn spirit guides and so on
SetStartTime ( 0 );
SetLastResurrectTime ( 0 );
}
void BattleGround :: AddPlayer ( Player * plr )
{
// score struct must be created in inherited class
uint64 guid = plr -> GetGUID ();
uint32 team = plr -> GetBGTeam ();
BattleGroundPlayer bp ;
2009-03-09 17:07:12 -06:00
bp . OfflineRemoveTime = 0 ;
2008-10-02 16:23:55 -05:00
bp . Team = team ;
// Add to list/maps
m_Players [ guid ] = bp ;
2008-12-19 16:05:13 -06:00
UpdatePlayersCountByTeam ( team , false ); // +1 player
2008-10-02 16:23:55 -05:00
WorldPacket data ;
sBattleGroundMgr . BuildPlayerJoinedBattleGroundPacket ( & data , plr );
SendPacketToTeam ( team , & data , plr , false );
2008-10-05 08:48:32 -05:00
// add arena specific auras
2009-04-08 16:33:46 -05:00
if ( isArena ())
2008-10-02 16:23:55 -05:00
{
plr -> RemoveArenaSpellCooldowns ();
2008-12-19 16:05:13 -06:00
plr -> RemoveArenaAuras ();
2009-05-24 22:54:13 +02:00
plr -> RemoveArenaEnchantments ( TEMP_ENCHANTMENT_SLOT );
2008-11-30 12:47:26 -06:00
if ( team == ALLIANCE ) // gold
{
2009-04-08 16:33:46 -05:00
if ( plr -> GetTeam () == HORDE )
2008-11-30 12:47:26 -06:00
plr -> CastSpell ( plr , SPELL_HORDE_GOLD_FLAG , true );
else
plr -> CastSpell ( plr , SPELL_ALLIANCE_GOLD_FLAG , true );
}
else // green
{
2009-04-08 16:33:46 -05:00
if ( plr -> GetTeam () == HORDE )
2008-11-30 12:47:26 -06:00
plr -> CastSpell ( plr , SPELL_HORDE_GREEN_FLAG , true );
else
plr -> CastSpell ( plr , SPELL_ALLIANCE_GREEN_FLAG , true );
}
2008-10-02 16:23:55 -05:00
plr -> DestroyConjuredItems ( true );
2009-04-11 14:47:38 -05:00
plr -> UnsummonPetTemporaryIfAny ();
2008-10-05 08:48:32 -05:00
2008-10-02 16:23:55 -05:00
if ( GetStatus () == STATUS_WAIT_JOIN ) // not started yet
{
2009-03-12 13:59:03 +01:00
plr -> CastSpell ( plr , SPELL_ARENA_PREPARATION , true );
2008-10-02 16:23:55 -05:00
plr -> SetHealth ( plr -> GetMaxHealth ());
plr -> SetPower ( POWER_MANA , plr -> GetMaxPower ( POWER_MANA ));
}
}
else
{
if ( GetStatus () == STATUS_WAIT_JOIN ) // not started yet
plr -> CastSpell ( plr , SPELL_PREPARATION , true ); // reduces all mana cost of spells.
}
2009-04-23 22:07:37 -05:00
plr -> GetAchievementMgr (). ResetAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE , ACHIEVEMENT_CRITERIA_CONDITION_MAP , GetMapId ());
plr -> GetAchievementMgr (). ResetAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE , ACHIEVEMENT_CRITERIA_CONDITION_MAP , GetMapId ());
2009-02-13 20:10:14 -06:00
// setup BG group membership
2009-03-09 17:07:12 -06:00
PlayerAddedToBGCheckIfBGIsRunning ( plr );
2009-02-13 20:10:14 -06:00
AddOrSetPlayerToCorrectBgGroup ( plr , guid , team );
2008-10-02 16:23:55 -05:00
// Log
sLog . outDetail ( "BATTLEGROUND: Player %s joined the battle." , plr -> GetName ());
}
2009-02-13 20:10:14 -06:00
/* this method adds player to his team's bg group, or sets his correct group if player is already in bg group */
void BattleGround :: AddOrSetPlayerToCorrectBgGroup ( Player * plr , uint64 plr_guid , uint32 team )
{
Group * group = GetBgRaid ( team );
if ( ! group ) // first player joined
{
group = new Group ;
SetBgRaid ( team , group );
group -> Create ( plr_guid , plr -> GetName ());
}
else // raid already exist
{
2009-04-08 16:33:46 -05:00
if ( group -> IsMember ( plr_guid ))
2009-02-13 20:10:14 -06:00
{
uint8 subgroup = group -> GetMemberGroup ( plr_guid );
2009-03-14 20:00:02 -06:00
plr -> SetBattleGroundRaid ( group , subgroup );
2009-02-13 20:10:14 -06:00
}
else
2009-03-14 20:06:00 -06:00
{
group -> AddMember ( plr_guid , plr -> GetName ());
2009-04-08 16:33:46 -05:00
if ( Group * originalGroup = plr -> GetOriginalGroup ())
if ( originalGroup -> IsLeader ( plr_guid ))
2009-03-14 20:06:00 -06:00
group -> ChangeLeader ( plr_guid );
}
2009-02-13 20:10:14 -06:00
}
}
2009-03-09 17:07:12 -06:00
// This method should be called when player logs into running battleground
void BattleGround :: EventPlayerLoggedIn ( Player * player , uint64 plr_guid )
{
// player is correct pointer
for ( std :: deque < uint64 >:: iterator itr = m_OfflineQueue . begin (); itr != m_OfflineQueue . end (); ++ itr )
{
2009-04-08 16:33:46 -05:00
if ( * itr == plr_guid )
2009-03-09 17:07:12 -06:00
{
m_OfflineQueue . erase ( itr );
break ;
}
}
m_Players [ plr_guid ]. OfflineRemoveTime = 0 ;
PlayerAddedToBGCheckIfBGIsRunning ( player );
2009-03-09 17:07:40 -06:00
// if battleground is starting, then add preparation aura
// we don't have to do that, because preparation aura isn't removed when player logs out
2009-03-09 17:07:12 -06:00
}
2009-03-09 16:36:58 -06:00
// This method should be called when player logs out from running battleground
void BattleGround :: EventPlayerLoggedOut ( Player * player )
{
2009-03-09 17:07:12 -06:00
// player is correct pointer, it is checked in WorldSession::LogoutPlayer()
m_OfflineQueue . push_back ( player -> GetGUID ());
m_Players [ player -> GetGUID ()]. OfflineRemoveTime = sWorld . GetGameTime () + MAX_OFFLINE_TIME ;
2009-04-08 16:33:46 -05:00
if ( GetStatus () == STATUS_IN_PROGRESS )
2009-03-09 16:36:58 -06:00
{
2009-04-08 16:33:46 -05:00
if ( isBattleGround ())
2009-03-09 16:36:58 -06:00
EventPlayerDroppedFlag ( player );
else
2009-03-15 17:16:11 -06:00
{
//1 player is logging out, if it is the last, then end arena!
2009-04-08 16:33:46 -05:00
if ( GetAlivePlayersCountByTeam ( player -> GetTeam ()) <= 1 && GetPlayersCountByTeam ( GetOtherTeam ( player -> GetTeam ())))
2009-03-15 17:16:11 -06:00
EndBattleGround ( GetOtherTeam ( player -> GetTeam ()));
}
2009-03-09 16:36:58 -06:00
}
}
2009-02-13 20:10:14 -06:00
2008-10-02 16:23:55 -05:00
/* This method should be called only once ... it adds pointer to queue */
void BattleGround :: AddToBGFreeSlotQueue ()
{
2008-10-05 08:48:32 -05:00
// make sure to add only once
2009-04-08 16:33:46 -05:00
if ( ! m_InBGFreeSlotQueue && isBattleGround ())
2008-10-05 08:48:32 -05:00
{
sBattleGroundMgr . BGFreeSlotQueue [ m_TypeID ]. push_front ( this );
m_InBGFreeSlotQueue = true ;
}
2008-10-02 16:23:55 -05:00
}
/* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
void BattleGround :: RemoveFromBGFreeSlotQueue ()
{
2008-10-05 08:48:32 -05:00
// set to be able to re-add if needed
m_InBGFreeSlotQueue = false ;
// uncomment this code when battlegrounds will work like instances
2009-02-27 12:57:33 -06:00
for ( BGFreeSlotQueueType :: iterator itr = sBattleGroundMgr . BGFreeSlotQueue [ m_TypeID ]. begin (); itr != sBattleGroundMgr . BGFreeSlotQueue [ m_TypeID ]. end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
if (( * itr ) -> GetInstanceID () == m_InstanceID )
{
sBattleGroundMgr . BGFreeSlotQueue [ m_TypeID ]. erase ( itr );
return ;
}
2008-10-05 08:48:32 -05:00
}
2008-10-02 16:23:55 -05:00
}
2008-10-05 08:48:32 -05:00
// get the number of free slots for team
2009-02-27 12:13:59 -06:00
// returns the number how many players can join battleground to MaxPlayersPerTeam
2008-10-05 08:48:32 -05:00
uint32 BattleGround :: GetFreeSlotsForTeam ( uint32 Team ) const
2008-10-02 16:23:55 -05:00
{
2009-03-06 15:25:20 -06:00
//return free slot count to MaxPlayerPerTeam
2009-02-27 12:13:59 -06:00
if ( GetStatus () == STATUS_WAIT_JOIN || GetStatus () == STATUS_IN_PROGRESS )
2008-10-05 08:48:32 -05:00
return ( GetInvitedCount ( Team ) < GetMaxPlayersPerTeam ()) ? GetMaxPlayersPerTeam () - GetInvitedCount ( Team ) : 0 ;
2008-10-02 16:23:55 -05:00
2008-10-05 08:48:32 -05:00
return 0 ;
2008-10-02 16:23:55 -05:00
}
bool BattleGround :: HasFreeSlots () const
{
return GetPlayersSize () < GetMaxPlayers ();
}
void BattleGround :: UpdatePlayerScore ( Player * Source , uint32 type , uint32 value )
{
//this procedure is called from virtual function implemented in bg subclass
2009-04-29 00:26:07 -05:00
std :: map < uint64 , BattleGroundScore *>:: const_iterator itr = m_PlayerScores . find ( Source -> GetGUID ());
2008-10-02 16:23:55 -05:00
if ( itr == m_PlayerScores . end ()) // player not found...
return ;
switch ( type )
{
case SCORE_KILLING_BLOWS : // Killing blows
itr -> second -> KillingBlows += value ;
break ;
case SCORE_DEATHS : // Deaths
itr -> second -> Deaths += value ;
break ;
case SCORE_HONORABLE_KILLS : // Honorable kills
itr -> second -> HonorableKills += value ;
break ;
case SCORE_BONUS_HONOR : // Honor bonus
2008-10-05 08:48:32 -05:00
// do not add honor in arenas
2009-04-08 16:33:46 -05:00
if ( isBattleGround ())
2008-10-05 08:48:32 -05:00
{
// reward honor instantly
2009-04-08 16:33:46 -05:00
if ( Source -> RewardHonor ( NULL , 1 , value ))
2008-10-05 08:48:32 -05:00
itr -> second -> BonusHonor += value ;
}
2008-10-02 16:23:55 -05:00
break ;
//used only in EY, but in MSG_PVP_LOG_DATA opcode
case SCORE_DAMAGE_DONE : // Damage Done
itr -> second -> DamageDone += value ;
break ;
case SCORE_HEALING_DONE : // Healing Done
itr -> second -> HealingDone += value ;
break ;
default :
sLog . outError ( "BattleGround: Unknown player score type %u" , type );
break ;
}
}
void BattleGround :: AddPlayerToResurrectQueue ( uint64 npc_guid , uint64 player_guid )
{
m_ReviveQueue [ npc_guid ]. push_back ( player_guid );
Player * plr = objmgr . GetPlayer ( player_guid );
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
return ;
SpellEntry const * spellInfo = sSpellStore . LookupEntry ( SPELL_WAITING_FOR_RESURRECT );
2009-04-08 16:33:46 -05:00
if ( spellInfo )
2008-10-02 16:23:55 -05:00
{
2009-04-06 13:31:14 +02:00
Aura * Aur = new Aura ( spellInfo , 1 , NULL , plr );
2008-10-02 16:23:55 -05:00
plr -> AddAura ( Aur );
}
}
void BattleGround :: RemovePlayerFromResurrectQueue ( uint64 player_guid )
{
for ( std :: map < uint64 , std :: vector < uint64 > >:: iterator itr = m_ReviveQueue . begin (); itr != m_ReviveQueue . end (); ++ itr )
{
for ( std :: vector < uint64 >:: iterator itr2 = ( itr -> second ). begin (); itr2 != ( itr -> second ). end (); ++ itr2 )
{
2009-04-08 16:33:46 -05:00
if ( * itr2 == player_guid )
2008-10-02 16:23:55 -05:00
{
( itr -> second ). erase ( itr2 );
Player * plr = objmgr . GetPlayer ( player_guid );
2009-04-08 16:33:46 -05:00
if ( ! plr )
2008-10-02 16:23:55 -05:00
return ;
plr -> RemoveAurasDueToSpell ( SPELL_WAITING_FOR_RESURRECT );
return ;
}
}
}
}
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 )
{
2008-10-05 08:48:32 -05:00
Map * map = MapManager :: Instance (). FindMap ( GetMapId (), GetInstanceID ());
2009-04-08 16:33:46 -05:00
if ( ! map )
2008-10-05 08:48:32 -05:00
return false ;
// must be created this way, adding to godatamap would add it to the base map of the instance
// and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
// so we must create it specific for this instance
GameObject * go = new GameObject ;
2009-01-31 16:38:50 -06:00
if ( ! go -> Create ( objmgr . GenerateLowGuid ( HIGHGUID_GAMEOBJECT ), entry , map ,
2009-04-27 18:36:10 -05:00
PHASEMASK_NORMAL , x , y , z , o , rotation0 , rotation1 , rotation2 , rotation3 , 100 , GO_STATE_READY ))
2008-10-02 16:23:55 -05:00
{
sLog . outErrorDb ( "Gameobject template %u not found in database! BattleGround not created!" , entry );
2008-10-05 08:48:32 -05:00
sLog . outError ( "Cannot create gameobject template %u! BattleGround not created!" , entry );
delete go ;
2008-10-02 16:23:55 -05:00
return false ;
}
2008-10-05 08:48:32 -05:00
/*
uint32 guid = go->GetGUIDLow();
2008-10-02 16:23:55 -05:00
2008-10-05 08:48:32 -05:00
// without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
// 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
2008-10-02 16:23:55 -05:00
GameObjectData& data = objmgr.NewGOData(guid);
data.id = entry;
data.mapid = GetMapId();
data.posX = x;
data.posY = y;
data.posZ = z;
data.orientation = o;
data.rotation0 = rotation0;
data.rotation1 = rotation1;
data.rotation2 = rotation2;
data.rotation3 = rotation3;
data.spawntimesecs = respawnTime;
2008-10-05 08:48:32 -05:00
data.spawnMask = 1;
2008-10-02 16:23:55 -05:00
data.animprogress = 100;
data.go_state = 1;
2008-10-05 08:48:32 -05:00
*/
// add to world, so it can be later looked up from HashMapHolder
2009-04-08 17:23:57 -05:00
map -> Add ( go );
2008-10-05 08:48:32 -05:00
m_BgObjects [ type ] = go -> GetGUID ();
2008-10-02 16:23:55 -05:00
return true ;
}
//some doors aren't despawned so we cannot handle their closing in gameobject::update()
//it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
void BattleGround :: DoorClose ( uint32 type )
{
GameObject * obj = HashMapHolder < GameObject >:: Find ( m_BgObjects [ type ]);
2009-04-08 16:33:46 -05:00
if ( obj )
2008-10-02 16:23:55 -05:00
{
//if doors are open, close it
2009-04-27 18:36:10 -05:00
if ( obj -> getLootState () == GO_ACTIVATED && obj -> GetGoState () != GO_STATE_READY )
2008-10-02 16:23:55 -05:00
{
//change state to allow door to be closed
obj -> SetLootState ( GO_READY );
obj -> UseDoorOrButton ( RESPAWN_ONE_DAY );
}
}
else
{
sLog . outError ( "BattleGround: Door object not found (cannot close doors)" );
}
}
void BattleGround :: DoorOpen ( uint32 type )
{
GameObject * obj = HashMapHolder < GameObject >:: Find ( m_BgObjects [ type ]);
2009-04-08 16:33:46 -05:00
if ( obj )
2008-10-02 16:23:55 -05:00
{
//change state to be sure they will be opened
obj -> SetLootState ( GO_READY );
obj -> UseDoorOrButton ( RESPAWN_ONE_DAY );
}
else
{
sLog . outError ( "BattleGround: Door object not found! - doors will be closed." );
}
}
2008-11-21 19:45:49 -06:00
GameObject * BattleGround :: GetBGObject ( uint32 type )
{
GameObject * obj = HashMapHolder < GameObject >:: Find ( m_BgObjects [ type ]);
if ( ! obj )
sLog . outError ( "couldn't get gameobject %i" , type );
return obj ;
}
Creature * BattleGround :: GetBGCreature ( uint32 type )
{
Creature * creature = HashMapHolder < Creature >:: Find ( m_BgCreatures [ type ]);
if ( ! creature )
sLog . outError ( "couldn't get creature %i" , type );
return creature ;
}
2008-10-02 16:23:55 -05:00
void BattleGround :: SpawnBGObject ( uint32 type , uint32 respawntime )
{
2008-10-05 08:48:32 -05:00
Map * map = MapManager :: Instance (). FindMap ( GetMapId (), GetInstanceID ());
2009-04-08 16:33:46 -05:00
if ( ! map )
2008-10-05 08:48:32 -05:00
return ;
2009-04-08 16:33:46 -05:00
if ( respawntime == 0 )
2008-10-02 16:23:55 -05:00
{
GameObject * obj = HashMapHolder < GameObject >:: Find ( m_BgObjects [ type ]);
2009-04-08 16:33:46 -05:00
if ( obj )
2008-10-02 16:23:55 -05:00
{
//we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
2009-04-08 16:33:46 -05:00
if ( obj -> getLootState () == GO_JUST_DEACTIVATED )
2008-10-02 16:23:55 -05:00
obj -> SetLootState ( GO_READY );
2008-10-05 08:48:32 -05:00
obj -> SetRespawnTime ( 0 );
map -> Add ( obj );
2008-10-02 16:23:55 -05:00
}
}
else
{
GameObject * obj = HashMapHolder < GameObject >:: Find ( m_BgObjects [ type ]);
2009-04-08 16:33:46 -05:00
if ( obj )
2008-10-02 16:23:55 -05:00
{
2008-10-05 08:48:32 -05:00
map -> Add ( obj );
2008-10-02 16:23:55 -05:00
obj -> SetRespawnTime ( respawntime );
obj -> SetLootState ( GO_JUST_DEACTIVATED );
}
}
}
2008-10-05 08:48:32 -05:00
Creature * BattleGround :: AddCreature ( uint32 entry , uint32 type , uint32 teamval , float x , float y , float z , float o , uint32 respawntime )
2008-10-02 16:23:55 -05:00
{
2008-10-05 08:48:32 -05:00
Map * map = MapManager :: Instance (). FindMap ( GetMapId (), GetInstanceID ());
2009-04-08 16:33:46 -05:00
if ( ! map )
2008-10-05 08:48:32 -05:00
return NULL ;
2008-10-02 16:23:55 -05:00
Creature * pCreature = new Creature ;
2009-05-30 22:15:05 -05:00
if ( ! pCreature -> Create ( objmgr . GenerateLowGuid ( HIGHGUID_UNIT ), map , PHASEMASK_NORMAL , entry , teamval , x , y , z , o ))
2008-10-02 16:23:55 -05:00
{
sLog . outError ( "Can't create creature entry: %u" , entry );
delete pCreature ;
return NULL ;
}
2009-03-20 14:05:14 -06:00
pCreature -> SetHomePosition ( x , y , z , o );
2008-10-02 16:23:55 -05:00
//pCreature->SetDungeonDifficulty(0);
map -> Add ( pCreature );
m_BgCreatures [ type ] = pCreature -> GetGUID ();
2008-10-05 08:48:32 -05:00
2008-10-02 16:23:55 -05:00
return pCreature ;
}
2008-12-19 16:05:13 -06:00
/*
void BattleGround::SpawnBGCreature(uint32 type, uint32 respawntime)
{
Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceId());
2009-04-08 16:33:46 -05:00
if (!map)
2008-12-19 16:05:13 -06:00
return false;
2008-10-02 16:23:55 -05:00
2009-04-08 16:33:46 -05:00
if (respawntime == 0)
2008-12-19 16:05:13 -06:00
{
Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
2009-04-08 16:33:46 -05:00
if (obj)
2008-12-19 16:05:13 -06:00
{
//obj->Respawn(); // bugged
obj->SetRespawnTime(0);
objmgr.SaveCreatureRespawnTime(obj->GetGUIDLow(), GetInstanceID(), 0);
map->Add(obj);
}
}
else
{
Creature *obj = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
2009-04-08 16:33:46 -05:00
if (obj)
2008-12-19 16:05:13 -06:00
{
obj->setDeathState(DEAD);
obj->SetRespawnTime(respawntime);
map->Add(obj);
}
}
}
*/
2008-10-02 16:23:55 -05:00
bool BattleGround :: DelCreature ( uint32 type )
{
2009-04-08 16:33:46 -05:00
if ( ! m_BgCreatures [ type ])
2009-02-10 09:55:16 -06:00
return true ;
2008-10-02 16:23:55 -05:00
Creature * cr = HashMapHolder < Creature >:: Find ( m_BgCreatures [ type ]);
2009-04-08 16:33:46 -05:00
if ( ! cr )
2008-10-02 16:23:55 -05:00
{
2008-11-14 17:03:03 -06:00
sLog . outError ( "Can't find creature guid: %u" , GUID_LOPART ( m_BgCreatures [ type ]));
2008-10-02 16:23:55 -05:00
return false ;
}
2008-11-21 19:45:49 -06:00
//TODO: only delete creature after not in combat
2008-10-02 16:23:55 -05:00
cr -> CleanupsBeforeDelete ();
cr -> AddObjectToRemoveList ();
m_BgCreatures [ type ] = 0 ;
return true ;
}
bool BattleGround :: DelObject ( uint32 type )
{
2009-04-08 16:33:46 -05:00
if ( ! m_BgObjects [ type ])
2009-02-10 09:55:16 -06:00
return true ;
2008-10-02 16:23:55 -05:00
GameObject * obj = HashMapHolder < GameObject >:: Find ( m_BgObjects [ type ]);
2009-04-08 16:33:46 -05:00
if ( ! obj )
2008-10-02 16:23:55 -05:00
{
2008-11-14 17:03:03 -06:00
sLog . outError ( "Can't find gobject guid: %u" , GUID_LOPART ( m_BgObjects [ type ]));
2008-10-02 16:23:55 -05:00
return false ;
}
obj -> SetRespawnTime ( 0 ); // not save respawn time
obj -> Delete ();
m_BgObjects [ type ] = 0 ;
return true ;
}
bool BattleGround :: AddSpiritGuide ( uint32 type , float x , float y , float z , float o , uint32 team )
{
uint32 entry = 0 ;
2009-04-08 16:33:46 -05:00
if ( team == ALLIANCE )
2008-10-02 16:23:55 -05:00
entry = 13116 ;
else
entry = 13117 ;
Creature * pCreature = AddCreature ( entry , type , team , x , y , z , o );
2009-04-08 16:33:46 -05:00
if ( ! pCreature )
2008-10-02 16:23:55 -05:00
{
sLog . outError ( "Can't create Spirit guide. BattleGround not created!" );
2008-12-19 16:05:13 -06:00
EndNow ();
2008-10-02 16:23:55 -05:00
return false ;
}
pCreature -> setDeathState ( DEAD );
pCreature -> SetUInt64Value ( UNIT_FIELD_CHANNEL_OBJECT , pCreature -> GetGUID ());
// aura
2009-02-06 19:42:03 +01:00
//TODO: Fix display here
//pCreature->SetVisibleAura(0, SPELL_SPIRIT_HEAL_CHANNEL);
2008-12-24 09:58:26 -06:00
//pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
//pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
//pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
2008-10-02 16:23:55 -05:00
// casting visual effect
pCreature -> SetUInt32Value ( UNIT_CHANNEL_SPELL , SPELL_SPIRIT_HEAL_CHANNEL );
// correct cast speed
pCreature -> SetFloatValue ( UNIT_MOD_CAST_SPEED , 1.0f );
//pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
return true ;
}
2009-03-09 17:00:31 -06:00
void BattleGround :: SendMessageToAll ( int32 entry , ChatMsg type , Player const * source )
2008-10-02 16:23:55 -05:00
{
2009-03-09 17:00:31 -06:00
MaNGOS :: BattleGroundChatBuilder bg_builder ( type , entry , source );
MaNGOS :: LocalizedPacketDo < MaNGOS :: BattleGroundChatBuilder > bg_do ( bg_builder );
BroadcastWorker ( bg_do );
2008-10-02 16:23:55 -05:00
}
2009-03-09 17:00:31 -06:00
void BattleGround :: PSendMessageToAll ( int32 entry , ChatMsg type , Player const * source , ...)
2008-10-02 16:23:55 -05:00
{
2009-03-06 15:25:20 -06:00
va_list ap ;
2009-03-09 17:07:12 -06:00
va_start ( ap , source );
2009-03-09 17:00:31 -06:00
MaNGOS :: BattleGroundChatBuilder bg_builder ( type , entry , source , & ap );
MaNGOS :: LocalizedPacketDo < MaNGOS :: BattleGroundChatBuilder > bg_do ( bg_builder );
BroadcastWorker ( bg_do );
2009-03-06 15:25:20 -06:00
va_end ( ap );
}
2009-03-09 17:06:13 -06:00
void BattleGround :: SendMessage2ToAll ( int32 entry , ChatMsg type , Player const * source , int32 arg1 , int32 arg2 )
{
MaNGOS :: BattleGround2ChatBuilder bg_builder ( type , entry , source , arg1 , arg2 );
MaNGOS :: LocalizedPacketDo < MaNGOS :: BattleGround2ChatBuilder > bg_do ( bg_builder );
BroadcastWorker ( bg_do );
}
2008-10-02 16:23:55 -05:00
void BattleGround :: EndNow ()
{
2008-10-05 08:48:32 -05:00
RemoveFromBGFreeSlotQueue ();
2008-10-02 16:23:55 -05:00
SetStatus ( STATUS_WAIT_LEAVE );
2009-03-13 18:06:36 -06:00
SetEndTime ( 0 );
2008-10-02 16:23:55 -05:00
}
2009-03-09 17:06:13 -06:00
//to be removed
2008-10-14 11:57:03 -05:00
const char * BattleGround :: GetTrinityString ( int32 entry )
2008-10-02 16:23:55 -05:00
{
// FIXME: now we have different DBC locales and need localized message for each target client
2008-10-14 11:57:03 -05:00
return objmgr . GetTrinityStringForDBCLocale ( entry );
2008-10-02 16:23:55 -05:00
}
/*
important notice:
buffs aren't spawned/despawned when players captures anything
buffs are in their positions when battleground starts
*/
void BattleGround :: HandleTriggerBuff ( uint64 const & go_guid )
{
GameObject * obj = HashMapHolder < GameObject >:: Find ( go_guid );
2009-04-08 16:33:46 -05:00
if ( ! obj || obj -> GetGoType () != GAMEOBJECT_TYPE_TRAP || ! obj -> isSpawned ())
2008-10-02 16:23:55 -05:00
return ;
//change buff type, when buff is used:
int32 index = m_BgObjects . size () - 1 ;
while ( index >= 0 && m_BgObjects [ index ] != go_guid )
index -- ;
if ( index < 0 )
{
sLog . outError ( "BattleGround (Type: %u) has buff gameobject (Guid: %u Entry: %u Type:%u) but it hasn't that object in its internal data" , GetTypeID (), GUID_LOPART ( go_guid ), obj -> GetEntry (), obj -> GetGoType ());
return ;
}
//randomly select new buff
uint8 buff = urand ( 0 , 2 );
uint32 entry = obj -> GetEntry ();
2009-04-08 16:33:46 -05:00
if ( m_BuffChange && entry != Buff_Entries [ buff ])
2008-10-02 16:23:55 -05:00
{
//despawn current buff
SpawnBGObject ( index , RESPAWN_ONE_DAY );
//set index for new one
for ( uint8 currBuffTypeIndex = 0 ; currBuffTypeIndex < 3 ; ++ currBuffTypeIndex )
2009-04-08 16:33:46 -05:00
if ( entry == Buff_Entries [ currBuffTypeIndex ])
2008-10-02 16:23:55 -05:00
{
index -= currBuffTypeIndex ;
index += buff ;
}
}
SpawnBGObject ( index , BUFF_RESPAWN_TIME );
}
void BattleGround :: HandleKillPlayer ( Player * player , Player * killer )
{
//keep in mind that for arena this will have to be changed a bit
// add +1 deaths
UpdatePlayerScore ( player , SCORE_DEATHS , 1 );
// add +1 kills to group and +1 killing_blows to killer
2009-04-08 16:33:46 -05:00
if ( killer )
2008-10-02 16:23:55 -05:00
{
UpdatePlayerScore ( killer , SCORE_HONORABLE_KILLS , 1 );
UpdatePlayerScore ( killer , SCORE_KILLING_BLOWS , 1 );
2009-04-29 00:26:07 -05:00
for ( BattleGroundPlayerMap :: const_iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2008-10-02 16:23:55 -05:00
{
Player * plr = objmgr . GetPlayer ( itr -> first );
2009-04-08 16:33:46 -05:00
if ( ! plr || plr == killer )
2008-10-02 16:23:55 -05:00
continue ;
2009-04-08 16:33:46 -05:00
if ( plr -> GetTeam () == killer -> GetTeam () && plr -> IsAtGroupRewardDistance ( player ))
2008-10-02 16:23:55 -05:00
UpdatePlayerScore ( plr , SCORE_HONORABLE_KILLS , 1 );
}
}
2009-03-15 17:16:11 -06:00
// to be able to remove insignia -- ONLY IN BattleGrounds
2009-04-08 16:33:46 -05:00
if ( ! isArena ())
2009-03-15 17:16:11 -06:00
player -> SetFlag ( UNIT_FIELD_FLAGS , UNIT_FLAG_SKINNABLE );
2008-10-02 16:23:55 -05:00
}
2008-10-05 08:48:32 -05:00
// return the player's team based on battlegroundplayer info
// used in same faction arena matches mainly
uint32 BattleGround :: GetPlayerTeam ( uint64 guid )
{
2009-03-09 17:07:12 -06:00
BattleGroundPlayerMap :: const_iterator itr = m_Players . find ( guid );
2009-04-08 16:33:46 -05:00
if ( itr != m_Players . end ())
2008-10-05 08:48:32 -05:00
return itr -> second . Team ;
return 0 ;
}
2009-03-09 17:07:40 -06:00
uint32 BattleGround :: GetOtherTeam ( uint32 teamId )
{
return ( teamId ) ? (( teamId == ALLIANCE ) ? HORDE : ALLIANCE ) : 0 ;
}
2009-02-10 01:16:16 -06:00
bool BattleGround :: IsPlayerInBattleGround ( uint64 guid )
{
2009-03-09 17:07:12 -06:00
BattleGroundPlayerMap :: const_iterator itr = m_Players . find ( guid );
2009-04-08 16:33:46 -05:00
if ( itr != m_Players . end ())
2009-02-10 01:16:16 -06:00
return true ;
return false ;
}
2009-03-09 17:07:12 -06:00
void BattleGround :: PlayerAddedToBGCheckIfBGIsRunning ( Player * plr )
2009-02-10 01:16:16 -06:00
{
2009-04-08 16:33:46 -05:00
if ( GetStatus () != STATUS_WAIT_LEAVE )
2009-02-10 01:16:16 -06:00
return ;
WorldPacket data ;
2009-02-13 19:56:22 -06:00
BattleGroundQueueTypeId bgQueueTypeId = BattleGroundMgr :: BGQueueTypeId ( GetTypeID (), GetArenaType ());
2009-02-10 01:16:16 -06:00
BlockMovement ( plr );
sBattleGroundMgr . BuildPvpLogDataPacket ( & data , this );
plr -> GetSession () -> SendPacket ( & data );
2009-03-13 18:06:36 -06:00
sBattleGroundMgr . BuildBattleGroundStatusPacket ( & data , this , plr -> GetBattleGroundQueueIndex ( bgQueueTypeId ), STATUS_IN_PROGRESS , GetEndTime (), GetStartTime (), GetArenaType ());
2009-02-10 01:16:16 -06:00
plr -> GetSession () -> SendPacket ( & data );
}
2008-10-05 08:48:32 -05:00
uint32 BattleGround :: GetAlivePlayersCountByTeam ( uint32 Team ) const
{
int count = 0 ;
2009-03-09 17:07:12 -06:00
for ( BattleGroundPlayerMap :: const_iterator itr = m_Players . begin (); itr != m_Players . end (); ++ itr )
2008-10-05 08:48:32 -05:00
{
2009-04-08 16:33:46 -05:00
if ( itr -> second . Team == Team )
2008-10-05 08:48:32 -05:00
{
Player * pl = objmgr . GetPlayer ( itr -> first );
2009-05-12 10:01:09 -05:00
if ( pl && pl -> isAlive () && ! pl -> HasByteFlag ( UNIT_FIELD_BYTES_2 , 3 , FORM_SPIRITOFREDEMPTION ))
2008-10-05 08:48:32 -05:00
++ count ;
}
}
return count ;
}
2008-10-17 16:36:07 -05:00
void BattleGround :: SetHoliday ( bool is_holiday )
{
if ( is_holiday )
m_HonorMode = BG_HOLIDAY ;
else
m_HonorMode = BG_NORMAL ;
}
2008-11-21 19:45:49 -06:00
int32 BattleGround :: GetObjectType ( uint64 guid )
{
for ( uint32 i = 0 ; i <= m_BgObjects . size (); i ++ )
if ( m_BgObjects [ i ] == guid )
return i ;
sLog . outError ( "BattleGround: cheating? a player used a gameobject which isnt supposed to be a usable object!" );
return - 1 ;
}
void BattleGround :: HandleKillUnit ( Creature * creature , Player * killer )
{
}
2009-02-09 22:08:06 -06:00
2009-03-09 16:36:58 -06:00
void BattleGround :: CheckArenaWinConditions ()
{
2009-04-08 16:33:46 -05:00
if ( ! GetAlivePlayersCountByTeam ( ALLIANCE ) && GetPlayersCountByTeam ( HORDE ))
2009-03-09 16:36:58 -06:00
EndBattleGround ( HORDE );
2009-04-08 16:33:46 -05:00
else if ( GetPlayersCountByTeam ( ALLIANCE ) && ! GetAlivePlayersCountByTeam ( HORDE ))
2009-03-09 16:36:58 -06:00
EndBattleGround ( ALLIANCE );
}
2009-02-09 22:08:06 -06:00
void BattleGround :: SetBgRaid ( uint32 TeamID , Group * bg_raid )
{
Group * & old_raid = TeamID == ALLIANCE ? m_BgRaids [ BG_TEAM_ALLIANCE ] : m_BgRaids [ BG_TEAM_HORDE ];
if ( old_raid ) old_raid -> SetBattlegroundGroup ( NULL );
if ( bg_raid ) bg_raid -> SetBattlegroundGroup ( this );
old_raid = bg_raid ;
2009-02-18 22:39:00 +01:00
}
2009-03-02 17:13:12 -06:00
WorldSafeLocsEntry const * BattleGround :: GetClosestGraveYard ( Player * player )
{
return objmgr . GetClosestGraveYard ( player -> GetPositionX (), player -> GetPositionY (), player -> GetPositionZ (), player -> GetMapId (), player -> GetTeam () );
2009-03-08 13:05:56 -06:00
}