root/trunk/src/game/BattleGround.cpp @ 230

Revision 230, 49.7 kB (checked in by yumileroy, 17 years ago)

[svn] *** Source: MaNGOS ***
* Implement localization of creature/gameobject name that say/yell. Author: evilstar (rewrited by: Vladimir)
* Fix auth login queue. Author: Derex
* Allowed switching INVTYPE_HOLDABLE items during combat, used correct spells for triggering global cooldown at weapon switch. Author: mobel/simak
* Fixed some format arg type/value pairs. Other warnings. Author: Vladimir
* [238_world.sql] Allow have team dependent graveyards at entrance map for instances. Author: Vladimir

NOTE:
Entrance map graveyards selected by same way as local (by distance from entrance) Until DB support will work in old way base at current DB data.

Original author: visagalis
Date: 2008-11-14 17:03:03-06:00

RevLine 
[2]1/*
[102]2 * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/>
3 *
[44]4 * Copyright (C) 2008 Trinity <http://www.trinitycore.org/>
[2]5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
[44]13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
[2]14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
[44]18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
[2]19 */
20
21#include "Object.h"
22#include "Player.h"
23#include "BattleGround.h"
24#include "Creature.h"
25#include "MapManager.h"
26#include "Language.h"
27#include "Chat.h"
28#include "SpellAuras.h"
[9]29#include "ArenaTeam.h"
[2]30#include "World.h"
31#include "Util.h"
32
33BattleGround::BattleGround()
34{
35    m_TypeID            = 0;
36    m_InstanceID        = 0;
37    m_Status            = 0;
38    m_EndTime           = 0;
39    m_LastResurrectTime = 0;
40    m_Queue_type        = MAX_BATTLEGROUND_QUEUES;
41    m_InvitedAlliance   = 0;
42    m_InvitedHorde      = 0;
43    m_ArenaType         = 0;
44    m_IsArena           = false;
45    m_Winner            = 2;
46    m_StartTime         = 0;
47    m_Events            = 0;
48    m_IsRated           = false;
49    m_BuffChange        = false;
50    m_Name              = "";
51    m_LevelMin          = 0;
52    m_LevelMax          = 0;
[9]53    m_InBGFreeSlotQueue = false;
54    m_SetDeleteThis     = false;
[2]55
56    m_MaxPlayersPerTeam = 0;
57    m_MaxPlayers        = 0;
58    m_MinPlayersPerTeam = 0;
59    m_MinPlayers        = 0;
60
61    m_MapId             = 0;
62
63    m_TeamStartLocX[BG_TEAM_ALLIANCE]   = 0;
64    m_TeamStartLocX[BG_TEAM_HORDE]      = 0;
65
66    m_TeamStartLocY[BG_TEAM_ALLIANCE]   = 0;
67    m_TeamStartLocY[BG_TEAM_HORDE]      = 0;
68
69    m_TeamStartLocZ[BG_TEAM_ALLIANCE]   = 0;
70    m_TeamStartLocZ[BG_TEAM_HORDE]      = 0;
71
72    m_TeamStartLocO[BG_TEAM_ALLIANCE]   = 0;
73    m_TeamStartLocO[BG_TEAM_HORDE]      = 0;
74
[9]75    m_ArenaTeamIds[BG_TEAM_ALLIANCE]   = 0;
76    m_ArenaTeamIds[BG_TEAM_HORDE]      = 0;
77
78    m_ArenaTeamRatingChanges[BG_TEAM_ALLIANCE]   = 0;
79    m_ArenaTeamRatingChanges[BG_TEAM_HORDE]      = 0;
80
[2]81    m_BgRaids[BG_TEAM_ALLIANCE]         = NULL;
82    m_BgRaids[BG_TEAM_HORDE]            = NULL;
83
84    m_PlayersCount[BG_TEAM_ALLIANCE]    = 0;
85    m_PlayersCount[BG_TEAM_HORDE]       = 0;
[9]86
87    m_PrematureCountDown = false;
88    m_PrematureCountDown = 0;
[50]89    m_HonorMode = BG_NORMAL;
[2]90}
91
92BattleGround::~BattleGround()
93{
[9]94    // remove objects and creatures
95    // (this is done automatically in mapmanager update, when the instance is reset after the reset time)   
96    int size = m_BgCreatures.size();
97    for(int i = 0; i < size; ++i)
98    {
99        DelCreature(i);
100    }
101    size = m_BgObjects.size();
102    for(int i = 0; i < size; ++i)
103    {
104        DelObject(i);
105    }
[2]106
[9]107    // delete creature and go respawn times
108    WorldDatabase.PExecute("DELETE FROM creature_respawn WHERE instance = '%u'",GetInstanceID());
109    WorldDatabase.PExecute("DELETE FROM gameobject_respawn WHERE instance = '%u'",GetInstanceID());
110    // delete instance from db
111    CharacterDatabase.PExecute("DELETE FROM instance WHERE id = '%u'",GetInstanceID());
112    // remove from battlegrounds
113    sBattleGroundMgr.RemoveBattleGround(GetInstanceID());
114    // unload map
115    if(Map * map = MapManager::Instance().FindMap(GetMapId(), GetInstanceID()))
116        if(map->IsBattleGroundOrArena())
117            ((BattleGroundMap*)map)->SetUnload();
118    // remove from bg free slot queue
119    this->RemoveFromBGFreeSlotQueue();
[2]120}
121
122void BattleGround::Update(time_t diff)
123{
124    if(!GetPlayersSize() && !GetRemovedPlayersSize() && !GetReviveQueueSize())
125        //BG is empty
126        return;
127
128    WorldPacket data;
129
130    if(GetRemovedPlayersSize())
131    {
132        for(std::map<uint64, uint8>::iterator itr = m_RemovedPlayers.begin(); itr != m_RemovedPlayers.end(); ++itr)
133        {
134            Player *plr = objmgr.GetPlayer(itr->first);
135            switch(itr->second)
136            {
137                //following code is handled by event:
138                /*case 0:
139                    sBattleGroundMgr.m_BattleGroundQueues[GetTypeID()].RemovePlayer(itr->first);
140                    //RemovePlayerFromQueue(itr->first);
141                    if(plr)
142                    {
143                        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(m_TypeID), STATUS_NONE, 0, 0);
144                        plr->GetSession()->SendPacket(&data);
145                    }
146                    break;*/
147                case 1:                                     // currently in bg and was removed from bg
148                    if(plr)
149                        RemovePlayerAtLeave(itr->first, true, true);
150                    else
151                        RemovePlayerAtLeave(itr->first, false, false);
152                    break;
153                case 2:                                     // revive queue
154                    RemovePlayerFromResurrectQueue(itr->first);
155                    break;
156                default:
157                    sLog.outError("BattleGround: Unknown remove player case!");
158            }
159        }
160        m_RemovedPlayers.clear();
161    }
162
163    // this code isn't efficient and its idea isn't implemented yet
164    /* offline players are removed from battleground in worldsession::LogoutPlayer()
165    // remove offline players from bg after ~5 minutes
166    if(GetPlayersSize())
167    {
168        for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
169        {
170            Player *plr = objmgr.GetPlayer(itr->first);
171            itr->second.LastOnlineTime += diff;
172
173            if(plr)
174                itr->second.LastOnlineTime = 0;   // update last online time
175            else
176                if(itr->second.LastOnlineTime >= MAX_OFFLINE_TIME)                   // 5 minutes
177                    m_RemovedPlayers[itr->first] = 1;       // add to remove list (BG)
178        }
179    }*/
180
181    m_LastResurrectTime += diff;
182    if (m_LastResurrectTime >= RESURRECTION_INTERVAL)
183    {
184        if(GetReviveQueueSize())
185        {
186            for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
187            {
188                Creature *sh = NULL;
189                for(std::vector<uint64>::iterator itr2 = (itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
190                {
191                    Player *plr = objmgr.GetPlayer(*itr2);
192                    if(!plr)
193                        continue;
194
195                    if (!sh)
196                    {
197                        sh = ObjectAccessor::GetCreature(*plr, itr->first);
198                        // only for visual effect
199                        if (sh)
200                            sh->CastSpell(sh, SPELL_SPIRIT_HEAL, true);   // Spirit Heal, effect 117
201                    }
202
203                    plr->CastSpell(plr, SPELL_RESURRECTION_VISUAL, true);   // Resurrection visual
204                    m_ResurrectQueue.push_back(*itr2);
205                }
206                (itr->second).clear();
207            }
208
209            m_ReviveQueue.clear();
210            m_LastResurrectTime = 0;
211        }
212        else
213            // queue is clear and time passed, just update last resurrection time
214            m_LastResurrectTime = 0;
215    }
216    else if (m_LastResurrectTime > 500)    // Resurrect players only half a second later, to see spirit heal effect on NPC
217    {
218        for(std::vector<uint64>::iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
219        {
220            Player *plr = objmgr.GetPlayer(*itr);
221            if(!plr)
222                continue;
223            plr->ResurrectPlayer(1.0f);
224            plr->CastSpell(plr, SPELL_SPIRIT_HEAL_MANA, true);
225            ObjectAccessor::Instance().ConvertCorpseForPlayer(*itr);
226        }
227        m_ResurrectQueue.clear();
228    }
229
[9]230    // if less then minimum players are in on one side, then start premature finish timer
231    if(GetStatus() == STATUS_IN_PROGRESS && !isArena() && sBattleGroundMgr.GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam()))
232    {
233        if(!m_PrematureCountDown)
234        {
235            m_PrematureCountDown = true;
236            m_PrematureCountDownTimer = sBattleGroundMgr.GetPrematureFinishTime();
237            SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
238        }
239        else if(m_PrematureCountDownTimer < diff)
240        {
241            // time's up!
242            EndBattleGround(0); // noone wins
243            m_PrematureCountDown = false;
244        } 
245        else 
246        {
247            uint32 newtime = m_PrematureCountDownTimer - diff;
248            // announce every minute
249            if(m_PrematureCountDownTimer != sBattleGroundMgr.GetPrematureFinishTime() && newtime / 60000 != m_PrematureCountDownTimer / 60000)
250                SendMessageToAll(LANG_BATTLEGROUND_PREMATURE_FINISH_WARNING);
251            m_PrematureCountDownTimer = newtime;
252        }
253    }
254    else if (m_PrematureCountDown)
255        m_PrematureCountDown = false;
256
[2]257    if(GetStatus() == STATUS_WAIT_LEAVE)
258    {
259        // remove all players from battleground after 2 minutes
260        m_EndTime += diff;
261        if(m_EndTime >= TIME_TO_AUTOREMOVE)                 // 2 minutes
262        {
263            for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
264            {
265                m_RemovedPlayers[itr->first] = 1;           // add to remove list (BG)
266            }
267            // do not change any battleground's private variables
268        }
269    }
270}
271
272void BattleGround::SetTeamStartLoc(uint32 TeamID, float X, float Y, float Z, float O)
273{
274    uint8 idx = GetTeamIndexByTeamId(TeamID);
275    m_TeamStartLocX[idx] = X;
276    m_TeamStartLocY[idx] = Y;
277    m_TeamStartLocZ[idx] = Z;
278    m_TeamStartLocO[idx] = O;
279}
280
281void BattleGround::SendPacketToAll(WorldPacket *packet)
282{
283    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
284    {
285        Player *plr = objmgr.GetPlayer(itr->first);
286        if(plr)
287            plr->GetSession()->SendPacket(packet);
288        else
289            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
290    }
291}
292
293void BattleGround::SendPacketToTeam(uint32 TeamID, WorldPacket *packet, Player *sender, bool self)
294{
295    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
296    {
297        Player *plr = objmgr.GetPlayer(itr->first);
298
299        if(!plr)
300        {
301            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
302            continue;
303        }
304
305        if(!self && sender == plr)
306            continue;
307
[9]308        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
309
310        if(team == TeamID)
[2]311            plr->GetSession()->SendPacket(packet);
312    }
313}
314
315void BattleGround::PlaySoundToAll(uint32 SoundID)
316{
317    WorldPacket data;
318    sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
319    SendPacketToAll(&data);
320}
321
322void BattleGround::PlaySoundToTeam(uint32 SoundID, uint32 TeamID)
323{
324    WorldPacket data;
325
326    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
327    {
328        Player *plr = objmgr.GetPlayer(itr->first);
329
330        if(!plr)
331        {
332            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
333            continue;
334        }
335
[9]336        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
337
338        if(team == TeamID)
[2]339        {
340            sBattleGroundMgr.BuildPlaySoundPacket(&data, SoundID);
341            plr->GetSession()->SendPacket(&data);
342        }
343    }
344}
345
346void BattleGround::CastSpellOnTeam(uint32 SpellID, uint32 TeamID)
347{
348    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
349    {
350        Player *plr = objmgr.GetPlayer(itr->first);
351
352        if(!plr)
353        {
354            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
355            continue;
356        }
357
[9]358        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
359       
360        if(team == TeamID)
[2]361            plr->CastSpell(plr, SpellID, true);
362    }
363}
364
365void BattleGround::RewardHonorToTeam(uint32 Honor, uint32 TeamID)
366{
367    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
368    {
369        Player *plr = objmgr.GetPlayer(itr->first);
370
371        if(!plr)
372        {
373            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
374            continue;
375        }
376
[9]377        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
378
379        if(team == TeamID)
[2]380            UpdatePlayerScore(plr, SCORE_BONUS_HONOR, Honor);
381    }
382}
383
384void BattleGround::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID)
385{
386    FactionEntry const* factionEntry = sFactionStore.LookupEntry(faction_id);
387
388    if(!factionEntry)
389        return;
390
391    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
392    {
393        Player *plr = objmgr.GetPlayer(itr->first);
394
395        if(!plr)
396        {
397            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
398            continue;
399        }
400
[9]401        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
402
403        if(team == TeamID)
[2]404            plr->ModifyFactionReputation(factionEntry, Reputation);
405    }
406}
407
408void BattleGround::UpdateWorldState(uint32 Field, uint32 Value)
409{
410    WorldPacket data;
411    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
412    SendPacketToAll(&data);
413}
414
415void BattleGround::UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player *Source)
416{
417    WorldPacket data;
418    sBattleGroundMgr.BuildUpdateWorldStatePacket(&data, Field, Value);
419    Source->GetSession()->SendPacket(&data);
420}
421
422void BattleGround::EndBattleGround(uint32 winner)
423{
[9]424    // battleground finished, remove from the running bg's list
425    this->RemoveFromBGFreeSlotQueue();
426
427    ArenaTeam * winner_arena_team = NULL;
428    ArenaTeam * loser_arena_team = NULL;
429    uint32 loser_rating = 0;
430    uint32 winner_rating = 0;
[2]431    WorldPacket data;
432    Player *Source = NULL;
433    const char *winmsg = "";
434
435    if(winner == ALLIANCE)
436    {
[9]437        if(isBattleGround())
[44]438            winmsg = GetTrinityString(LANG_BG_A_WINS);
[9]439        else
[44]440            winmsg = GetTrinityString(LANG_ARENA_GOLD_WINS);
[2]441
442        PlaySoundToAll(SOUND_ALLIANCE_WINS);                // alliance wins sound
443
444        SetWinner(WINNER_ALLIANCE);
445    }
[9]446    else if(winner == HORDE)
[2]447    {
[9]448        if(isBattleGround())
[44]449            winmsg = GetTrinityString(LANG_BG_H_WINS);
[9]450        else
[44]451            winmsg = GetTrinityString(LANG_ARENA_GREEN_WINS);
[2]452
453        PlaySoundToAll(SOUND_HORDE_WINS);                   // horde wins sound
454
455        SetWinner(WINNER_HORDE);
456    }
[9]457    else
458    {
459        SetWinner(3);
460    }
[2]461
462    SetStatus(STATUS_WAIT_LEAVE);
463    m_EndTime = 0;
464
[9]465    // arena rating calculation
466    if(isArena() && isRated())
467    {
468        if(winner == ALLIANCE)
469        {
470            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
471            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
472        }
473        else if(winner == HORDE)
474        {
475            winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
476            loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
477        }
478        if(winner_arena_team && loser_arena_team)
479        {
480            loser_rating = loser_arena_team->GetStats().rating;
481            winner_rating = winner_arena_team->GetStats().rating;
482            float winner_chance = winner_arena_team->GetChanceAgainst(loser_rating);
483            float loser_chance = loser_arena_team->GetChanceAgainst(winner_rating);
484            int32 winner_change = winner_arena_team->WonAgainstChance(winner_chance);
485            int32 loser_change = loser_arena_team->LostAgainstChance(loser_chance);
486            sLog.outDebug("--- %u ; %u ; %d ; %d ; %u ; %u ---",winner_rating,loser_rating,winner_chance,loser_chance,winner_change,loser_change);
487            if(winner == ALLIANCE)
488            {
489                SetArenaTeamRatingChangeForTeam(ALLIANCE, winner_change);
490                SetArenaTeamRatingChangeForTeam(HORDE, loser_change);
491            }
492            else
493            {
494                SetArenaTeamRatingChangeForTeam(HORDE, winner_change);
495                SetArenaTeamRatingChangeForTeam(ALLIANCE, loser_change);
496            }
497        }
498        else
499        {
500            SetArenaTeamRatingChangeForTeam(ALLIANCE, 0);
501            SetArenaTeamRatingChangeForTeam(HORDE, 0);
502        }
503    }
504
[2]505    for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
506    {
507        Player *plr = objmgr.GetPlayer(itr->first);
508        if(!plr)
509        {
510            sLog.outError("BattleGround: Player " I64FMTD " not found!", itr->first);
511            continue;
512        }
513
[9]514        // should remove spirit of redemption
515        if(plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
516            plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
517
[2]518        if(!plr->isAlive())
519        {
520            plr->ResurrectPlayer(1.0f);
521            plr->SpawnCorpseBones();
522        }
523
[9]524        uint32 team = itr->second.Team;//GetPlayerTeam(plr->GetGUID());
525        if(!team) team = plr->GetTeam();
526
527        // per player calculation
528        if(isArena() && isRated() && winner_arena_team && loser_arena_team)
[2]529        {
[9]530            if(team == winner)
531                winner_arena_team->MemberWon(plr,loser_rating);
532            else
533                loser_arena_team->MemberLost(plr,winner_rating);
534        }
535
536        if(team == winner)
537        {
[2]538            if(!Source)
539                Source = plr;
540            RewardMark(plr,ITEM_WINNER_COUNT);
541            RewardQuest(plr);
542        }
543        else
544        {
545            RewardMark(plr,ITEM_LOSER_COUNT);
546        }
547
548        plr->CombatStopWithPets(true);
549
550        BlockMovement(plr);
551
552        sBattleGroundMgr.BuildPvpLogDataPacket(&data, this);
553        plr->GetSession()->SendPacket(&data);
554
[9]555        uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
556        sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, plr->GetTeam(), plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_IN_PROGRESS, TIME_TO_AUTOREMOVE, GetStartTime());
[2]557        plr->GetSession()->SendPacket(&data);
558    }
559
[9]560    if(isArena() && isRated() && winner_arena_team && loser_arena_team)
561    {
562        // update arena points only after increasing the player's match count!
563        winner_arena_team->UpdateArenaPointsHelper();
564        loser_arena_team->UpdateArenaPointsHelper();
565        // save the stat changes
566        winner_arena_team->SaveToDB();
567        loser_arena_team->SaveToDB();
568        // send updated arena team stats to players
569        // this way all arena team members will get notified, not only the ones who participated in this match
570        winner_arena_team->NotifyStatsChanged();
571        loser_arena_team->NotifyStatsChanged();
572    }
573
574    // inform invited players about the removal
575    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
576
[2]577    if(Source)
578    {
579        ChatHandler(Source).FillMessageData(&data, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, Source->GetGUID(), winmsg);
580        SendPacketToAll(&data);
581    }
582}
583
584uint32 BattleGround::GetBattlemasterEntry() const
585{
586    switch(GetTypeID())
587    {
588        case BATTLEGROUND_AV: return 15972;
589        case BATTLEGROUND_WS: return 14623;
590        case BATTLEGROUND_AB: return 14879;
591        case BATTLEGROUND_EY: return 22516;
592        case BATTLEGROUND_NA: return 20200;
593        default:              return 0;
594    }
595}
596
597void BattleGround::RewardMark(Player *plr,uint32 count)
598{
599    // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
600    if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
601        return;
602
603    BattleGroundMarks mark;
604    bool IsSpell;
605    switch(GetTypeID())
606    {
607        case BATTLEGROUND_AV:
608            IsSpell = true;
609            if(count == ITEM_WINNER_COUNT)
610                mark = SPELL_AV_MARK_WINNER;
611            else
612                mark = SPELL_AV_MARK_LOSER;
613            break;
614        case BATTLEGROUND_WS:
615            IsSpell = true;
616            if(count == ITEM_WINNER_COUNT)
617                mark = SPELL_WS_MARK_WINNER;
618            else
619                mark = SPELL_WS_MARK_LOSER;
620            break;
621        case BATTLEGROUND_AB:
622            IsSpell = true;
623            if(count == ITEM_WINNER_COUNT)
624                mark = SPELL_AB_MARK_WINNER;
625            else
626                mark = SPELL_AB_MARK_LOSER;
627            break;
628        case BATTLEGROUND_EY:
629            IsSpell = false;
630            mark = ITEM_EY_MARK_OF_HONOR;
631            break;
632        default:
633            return;
634    }
635
636    if(IsSpell)
637        plr->CastSpell(plr, mark, true);
638    else if ( objmgr.GetItemPrototype( mark ) )
639    {
640        ItemPosCountVec dest;
641        uint32 no_space_count = 0;
642        uint8 msg = plr->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, mark, count, &no_space_count );
643        if( msg != EQUIP_ERR_OK )                       // convert to possible store amount
644            count -= no_space_count;
645
646        if( count != 0 && !dest.empty())                // can add some
647            if(Item* item = plr->StoreNewItem( dest, mark, true, 0))
648                plr->SendNewItem(item,count,false,true);
649
650        if(no_space_count > 0)
651            SendRewardMarkByMail(plr,mark,no_space_count);
652    }
653}
654
655void BattleGround::SendRewardMarkByMail(Player *plr,uint32 mark, uint32 count)
656{
657    uint32 bmEntry = GetBattlemasterEntry();
658    if(!bmEntry)
659        return;
660
661    ItemPrototype const* markProto = objmgr.GetItemPrototype(mark);
662    if(!markProto)
663        return;
664
665    if(Item* markItem = Item::CreateItem(mark,count,plr))
666    {
667        // save new item before send
668        markItem->SaveToDB();                               // save for prevent lost at next mail load, if send fail then item will deleted
669
670        // item
671        MailItemsInfo mi;
672        mi.AddItem(markItem->GetGUIDLow(), markItem->GetEntry(), markItem);
673
674        // subject: item name
675        std::string subject = markProto->Name1;
676        int loc_idx = plr->GetSession()->GetSessionDbLocaleIndex();
677        if ( loc_idx >= 0 )
678            if(ItemLocale const *il = objmgr.GetItemLocale(markProto->ItemId))
679                if (il->Name.size() > loc_idx && !il->Name[loc_idx].empty())
680                    subject = il->Name[loc_idx];
681
682        // text
[44]683        std::string textFormat = plr->GetSession()->GetTrinityString(LANG_BG_MARK_BY_MAIL);
[2]684        char textBuf[300];
685        snprintf(textBuf,300,textFormat.c_str(),GetName(),GetName());
686        uint32 itemTextId = objmgr.CreateItemText( textBuf );
687
688        WorldSession::SendMailTo(plr, MAIL_CREATURE, MAIL_STATIONERY_NORMAL, bmEntry, plr->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
689    }
690}
691
692void BattleGround::RewardQuest(Player *plr)
693{
694    // 'Inactive' this aura prevents the player from gaining honor points and battleground tokens
695    if(plr->GetDummyAura(SPELL_AURA_PLAYER_INACTIVE))
696        return;
697
698    uint32 quest;
699    switch(GetTypeID())
700    {
701        case BATTLEGROUND_AV:
702            quest = SPELL_AV_QUEST_REWARD;
703            break;
704        case BATTLEGROUND_WS:
705            quest = SPELL_WS_QUEST_REWARD;
706            break;
707        case BATTLEGROUND_AB:
708            quest = SPELL_AB_QUEST_REWARD;
709            break;
710        case BATTLEGROUND_EY:
711            quest = SPELL_EY_QUEST_REWARD;
712            break;
713        default:
714            return;
715    }
716
717    plr->CastSpell(plr, quest, true);
718}
719
720void BattleGround::BlockMovement(Player *plr)
721{
722    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()
723}
724
725void BattleGround::RemovePlayerAtLeave(uint64 guid, bool Transport, bool SendPacket)
726{
[9]727    uint32 team = GetPlayerTeam(guid);
728    bool participant = false;
[2]729    // Remove from lists/maps
730    std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.find(guid);
731    if(itr != m_Players.end())
732    {
[9]733        UpdatePlayersCountByTeam(team, true);   // -1 player
[2]734        m_Players.erase(itr);
[9]735        // check if the player was a participant of the match, or only entered through gm command (goname)
736        participant = true;
[2]737    }
738
739    std::map<uint64, BattleGroundScore*>::iterator itr2 = m_PlayerScores.find(guid);
740    if(itr2 != m_PlayerScores.end())
741    {
742        delete itr2->second;                                // delete player's score
743        m_PlayerScores.erase(itr2);
744    }
745
746    RemovePlayerFromResurrectQueue(guid);
747
748    Player *plr = objmgr.GetPlayer(guid);
749
[9]750    // should remove spirit of redemption
751    if(plr && plr->HasAuraType(SPELL_AURA_SPIRIT_OF_REDEMPTION))
752        plr->RemoveSpellsCausingAura(SPELL_AURA_MOD_SHAPESHIFT);
753
[2]754    if(plr && !plr->isAlive())                              // resurrect on exit
755    {
756        plr->ResurrectPlayer(1.0f);
757        plr->SpawnCorpseBones();
758    }
759
760    RemovePlayer(plr, guid);                                // BG subclass specific code
761
762    if(plr)
763    {
764        plr->ClearAfkReports();
765
[9]766        if(participant) // if the player was a match participant, remove auras, calc rating, update queue
[2]767        {
[9]768            if(!team) team = plr->GetTeam();
[2]769
[9]770            uint32 bgTypeId = GetTypeID();
771            uint32 bgQueueTypeId = sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType());
772            // if arena, remove the specific arena auras
773            if(isArena())
774            {
775                plr->RemoveArenaAuras(true);    // removes debuffs / dots etc., we don't want the player to die after porting out
776                bgTypeId=BATTLEGROUND_AA;       // set the bg type to all arenas (it will be used for queue refreshing)
[2]777
[9]778                // summon old pet if there was one and there isn't a current pet
779                if(!plr->GetPet() && plr->GetTemporaryUnsummonedPetNumber())
780                {
781                    Pet* NewPet = new Pet;
782                    if(!NewPet->LoadPetFromDB(plr, 0, (plr)->GetTemporaryUnsummonedPetNumber(), true))
783                        delete NewPet;
[2]784
[9]785                    (plr)->SetTemporaryUnsummonedPetNumber(0);
786                }
[2]787
[9]788                if(isRated() && GetStatus() == STATUS_IN_PROGRESS)
789                {
790                    //left a rated match while the encounter was in progress, consider as loser
791                    ArenaTeam * winner_arena_team = 0;
792                    ArenaTeam * loser_arena_team = 0;
793                    if(team == HORDE)
794                    {
795                        winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
796                        loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
797                    }
798                    else
799                    {
800                        winner_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(HORDE));
801                        loser_arena_team = objmgr.GetArenaTeamById(GetArenaTeamIdForTeam(ALLIANCE));
802                    }
803                    if(winner_arena_team && loser_arena_team)
804                    {
805                        loser_arena_team->MemberLost(plr,winner_arena_team->GetRating());
806                    }
807                }
808            }
[2]809
[9]810            WorldPacket data;
811            if(SendPacket)
812            {
813                sBattleGroundMgr.BuildBattleGroundStatusPacket(&data, this, team, plr->GetBattleGroundQueueIndex(bgQueueTypeId), STATUS_NONE, 0, 0);
814                plr->GetSession()->SendPacket(&data);
815            }
[2]816
[9]817            // this call is important, because player, when joins to battleground, this method is not called, so it must be called when leaving bg
818            plr->RemoveBattleGroundQueueId(bgQueueTypeId);
819
820            DecreaseInvitedCount(team);
821            //we should update battleground queue, but only if bg isn't ending
822            if (GetQueueType() < MAX_BATTLEGROUND_QUEUES)
823                sBattleGroundMgr.m_BattleGroundQueues[bgQueueTypeId].Update(bgTypeId, GetQueueType());
824
825            Group * group = plr->GetGroup();
826            // remove from raid group if exist
827            if(group && group == GetBgRaid(team))
[2]828            {
[9]829                if(!group->RemoveMember(guid, 0))               // group was disbanded
830                {
831                    SetBgRaid(team, NULL);
832                    delete group;
833                }
[2]834            }
[9]835
836            // Let others know
837            sBattleGroundMgr.BuildPlayerLeftBattleGroundPacket(&data, plr);
838            SendPacketToTeam(team, &data, plr, false);
[2]839        }
840
841        // Do next only if found in battleground
842        plr->SetBattleGroundId(0);                          // We're not in BG.
[9]843        // reset destination bg team
844        plr->SetBGTeam(0);
[2]845
846        if(Transport)
847        {
848            plr->TeleportTo(plr->GetBattleGroundEntryPointMap(), plr->GetBattleGroundEntryPointX(), plr->GetBattleGroundEntryPointY(), plr->GetBattleGroundEntryPointZ(), plr->GetBattleGroundEntryPointO());
849        }
850
851        // Log
852        sLog.outDetail("BATTLEGROUND: Removed player %s from BattleGround.", plr->GetName());
853    }
854
[9]855    if(!GetPlayersSize() && !GetInvitedCount(HORDE) && !GetInvitedCount(ALLIANCE))
[2]856    {
[9]857        // if no players left AND no invitees left, set this bg to delete in next update
858        // direct deletion could cause crashes
859        m_SetDeleteThis = true;
860        // return to prevent addition to freeslotqueue
861        return;
[2]862    }
[9]863
864    // a player exited the battleground, so there are free slots. add to queue
865    this->AddToBGFreeSlotQueue();
[2]866}
867
868// this method is called when no players remains in battleground
869void BattleGround::Reset()
870{
871    SetQueueType(MAX_BATTLEGROUND_QUEUES);
872    SetWinner(WINNER_NONE);
873    SetStatus(STATUS_WAIT_QUEUE);
874    SetStartTime(0);
875    SetEndTime(0);
876    SetLastResurrectTime(0);
[9]877    SetArenaType(0);
878    SetRated(false);
[2]879
880    m_Events = 0;
881
882    if (m_InvitedAlliance > 0 || m_InvitedHorde > 0)
883        sLog.outError("BattleGround system ERROR: bad counter, m_InvitedAlliance: %d, m_InvitedHorde: %d", m_InvitedAlliance, m_InvitedHorde);
884
885    m_InvitedAlliance = 0;
886    m_InvitedHorde = 0;
[9]887    m_InBGFreeSlotQueue = false;
[2]888
889    m_Players.clear();
890    m_PlayerScores.clear();
891
[9]892    // reset BGSubclass (this cleans up creatures and gos as well)
[2]893    this->ResetBGSubclass();
894}
895
896void BattleGround::StartBattleGround()
897{
898    ///this method should spawn spirit guides and so on
899    SetStartTime(0);
900
901    SetLastResurrectTime(0);
902}
903
904void BattleGround::AddPlayer(Player *plr)
905{
906    // score struct must be created in inherited class
907
908    uint64 guid = plr->GetGUID();
909    uint32 team = plr->GetBGTeam();
910
911    BattleGroundPlayer bp;
912    bp.LastOnlineTime = 0;
913    bp.Team = team;
914
915    // Add to list/maps
916    m_Players[guid] = bp;
917
[9]918    UpdatePlayersCountByTeam(team, false);        // +1 player
[2]919
920    WorldPacket data;
921    sBattleGroundMgr.BuildPlayerJoinedBattleGroundPacket(&data, plr);
922    SendPacketToTeam(team, &data, plr, false);
923
[9]924    // add arena specific auras
[2]925    if(isArena())
926    {
[9]927        // remove auras first, only then reset spell cooldowns
928        // this is to prevent bugging amp. curse, combustion, etc. like spells
929        plr->RemoveArenaAuras();
[2]930        plr->RemoveArenaSpellCooldowns();
931        plr->RemoveAllEnchantments(TEMP_ENCHANTMENT_SLOT);
932        if(team == ALLIANCE && plr->GetTeam() == ALLIANCE)
933            plr->CastSpell(plr,SPELL_ALLIANCE_GOLD_FLAG,true);
934        else if(team == HORDE && plr->GetTeam() == ALLIANCE)
935            plr->CastSpell(plr,SPELL_ALLIANCE_GREEN_FLAG,true);
936        else if(team == ALLIANCE && plr->GetTeam() == HORDE)
937            plr->CastSpell(plr,SPELL_HORDE_GOLD_FLAG,true);
938        else
939            plr->CastSpell(plr,SPELL_HORDE_GREEN_FLAG,true);
940        plr->DestroyConjuredItems(true);
941
[9]942        Pet* pet = plr->GetPet();
943        if(pet)
944        {
945            if(pet->getPetType() == SUMMON_PET || pet->getPetType() == HUNTER_PET)
946            {
947                (plr)->SetTemporaryUnsummonedPetNumber(pet->GetCharmInfo()->GetPetNumber());
948                (plr)->SetOldPetSpell(pet->GetUInt32Value(UNIT_CREATED_BY_SPELL));
949            }
950            (plr)->RemovePet(NULL,PET_SAVE_NOT_IN_SLOT);
951        }
952
[2]953        if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet
954        {
955            plr->CastSpell(plr, SPELL_ARENA_PREPARATION, true);
956
957            plr->SetHealth(plr->GetMaxHealth());
958            plr->SetPower(POWER_MANA, plr->GetMaxPower(POWER_MANA));
959        }
960    }
961    else
962    {
963        if(GetStatus() == STATUS_WAIT_JOIN)                 // not started yet
964            plr->CastSpell(plr, SPELL_PREPARATION, true);   // reduces all mana cost of spells.
965    }
966
967    // Log
968    sLog.outDetail("BATTLEGROUND: Player %s joined the battle.", plr->GetName());
969}
970
971/* This method should be called only once ... it adds pointer to queue */
972void BattleGround::AddToBGFreeSlotQueue()
973{
[9]974    // make sure to add only once
975    if(!m_InBGFreeSlotQueue)
976    {
977        sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].push_front(this);
978        m_InBGFreeSlotQueue = true;
979    }
[2]980}
981
982/* This method removes this battleground from free queue - it must be called when deleting battleground - not used now*/
983void BattleGround::RemoveFromBGFreeSlotQueue()
984{
[9]985    // set to be able to re-add if needed
986    m_InBGFreeSlotQueue = false;
987    // uncomment this code when battlegrounds will work like instances
[2]988    for (std::deque<BattleGround*>::iterator itr = sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].begin(); itr != sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].end(); ++itr)
989    {
990        if ((*itr)->GetInstanceID() == m_InstanceID)
991        {
992            sBattleGroundMgr.BGFreeSlotQueue[m_TypeID].erase(itr);
993            return;
994        }
[9]995    }
[2]996}
997
[9]998// get the number of free slots for team
999// works in similar way that HasFreeSlotsForTeam did, but this is needed for join as group
1000uint32 BattleGround::GetFreeSlotsForTeam(uint32 Team) const
[2]1001{
1002    //if BG is starting ... invite anyone:
1003    if (GetStatus() == STATUS_WAIT_JOIN)
[9]1004        return (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
[2]1005    //if BG is already started .. do not allow to join too much players of one faction
1006    uint32 otherTeam;
[9]1007    uint32 otherIn;
[2]1008    if (Team == ALLIANCE)
[9]1009    {
[2]1010        otherTeam = GetInvitedCount(HORDE);
[9]1011        otherIn = GetPlayersCountByTeam(HORDE);
1012    }
[2]1013    else
[9]1014    {
[2]1015        otherTeam = GetInvitedCount(ALLIANCE);
[9]1016        otherIn = GetPlayersCountByTeam(ALLIANCE);
1017    }
[2]1018    if (GetStatus() == STATUS_IN_PROGRESS)
[9]1019    {
1020        // difference based on ppl invited (not necessarily entered battle)
1021        // default: allow 0
1022        uint32 diff = 0;
1023        // allow join one person if the sides are equal (to fill up bg to minplayersperteam)
1024        if (otherTeam == GetInvitedCount(Team)) 
1025            diff = 1;
1026        // allow join more ppl if the other side has more players
1027        else if(otherTeam > GetInvitedCount(Team))
1028            diff = otherTeam - GetInvitedCount(Team);
[2]1029
[9]1030        // difference based on max players per team (don't allow inviting more)
1031        uint32 diff2 = (GetInvitedCount(Team) < GetMaxPlayersPerTeam()) ? GetMaxPlayersPerTeam() - GetInvitedCount(Team) : 0;
1032
1033        // difference based on players who already entered
1034        // default: allow 0
1035        uint32 diff3 = 0;
1036        // allow join one person if the sides are equal (to fill up bg minplayersperteam)
1037        if (otherIn == GetPlayersCountByTeam(Team))
1038            diff3 = 1;
1039        // allow join more ppl if the other side has more players
1040        else if (otherIn > GetPlayersCountByTeam(Team))
1041            diff3 = otherIn - GetPlayersCountByTeam(Team);
1042
1043        // return the minimum of the 3 differences
1044
1045        // min of diff and diff 2
1046        diff = diff < diff2 ? diff : diff2;
1047
1048        // min of diff, diff2 and diff3
1049        return diff < diff3 ? diff : diff3 ;
1050    }
1051
1052    return 0;
[2]1053}
1054
1055bool BattleGround::HasFreeSlots() const
1056{
1057    return GetPlayersSize() < GetMaxPlayers();
1058}
1059
1060void BattleGround::UpdatePlayerScore(Player *Source, uint32 type, uint32 value)
1061{
1062    //this procedure is called from virtual function implemented in bg subclass
1063    std::map<uint64, BattleGroundScore*>::iterator itr = m_PlayerScores.find(Source->GetGUID());
1064
1065    if(itr == m_PlayerScores.end())                         // player not found...
1066        return;
1067
1068    switch(type)
1069    {
1070        case SCORE_KILLING_BLOWS:                           // Killing blows
1071            itr->second->KillingBlows += value;
1072            break;
1073        case SCORE_DEATHS:                                  // Deaths
1074            itr->second->Deaths += value;
1075            break;
1076        case SCORE_HONORABLE_KILLS:                         // Honorable kills
1077            itr->second->HonorableKills += value;
1078            break;
1079        case SCORE_BONUS_HONOR:                             // Honor bonus
[9]1080            // do not add honor in arenas
1081            if(isBattleGround())
1082            {
1083                // reward honor instantly
1084                if(Source->RewardHonor(NULL, 1, value))
1085                    itr->second->BonusHonor += value;
1086            }
[2]1087            break;
1088            //used only in EY, but in MSG_PVP_LOG_DATA opcode
1089        case SCORE_DAMAGE_DONE:                             // Damage Done
1090            itr->second->DamageDone += value;
1091            break;
1092        case SCORE_HEALING_DONE:                            // Healing Done
1093            itr->second->HealingDone += value;
1094            break;
1095        default:
1096            sLog.outError("BattleGround: Unknown player score type %u", type);
1097            break;
1098    }
1099}
1100
1101void BattleGround::AddPlayerToResurrectQueue(uint64 npc_guid, uint64 player_guid)
1102{
1103    m_ReviveQueue[npc_guid].push_back(player_guid);
1104
1105    Player *plr = objmgr.GetPlayer(player_guid);
1106    if(!plr)
1107        return;
1108
1109    plr->CastSpell(plr, SPELL_WAITING_FOR_RESURRECT, true);
1110    SpellEntry const *spellInfo = sSpellStore.LookupEntry( SPELL_WAITING_FOR_RESURRECT );
1111    if(spellInfo)
1112    {
1113        Aura *Aur = CreateAura(spellInfo, 0, NULL, plr);
1114        plr->AddAura(Aur);
1115    }
1116}
1117
1118void BattleGround::RemovePlayerFromResurrectQueue(uint64 player_guid)
1119{
1120    for(std::map<uint64, std::vector<uint64> >::iterator itr = m_ReviveQueue.begin(); itr != m_ReviveQueue.end(); ++itr)
1121    {
1122        for(std::vector<uint64>::iterator itr2 =(itr->second).begin(); itr2 != (itr->second).end(); ++itr2)
1123        {
1124            if(*itr2 == player_guid)
1125            {
1126                (itr->second).erase(itr2);
1127
1128                Player *plr = objmgr.GetPlayer(player_guid);
1129                if(!plr)
1130                    return;
1131
1132                plr->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
1133
1134                return;
1135            }
1136        }
1137    }
1138}
1139
1140bool BattleGround::AddObject(uint32 type, uint32 entry, float x, float y, float z, float o, float rotation0, float rotation1, float rotation2, float rotation3, uint32 respawnTime)
1141{
[9]1142    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1143    if(!map)
1144        return false;
1145
1146    // must be created this way, adding to godatamap would add it to the base map of the instance
1147    // and when loading it (in go::LoadFromDB()), a new guid would be assigned to the object, and a new object would be created
1148    // so we must create it specific for this instance
1149    GameObject * go = new GameObject;
1150    if(!go->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT),entry, map,x,y,z,o,rotation0,rotation1,rotation2,rotation3,100,1))
[2]1151    {
1152        sLog.outErrorDb("Gameobject template %u not found in database! BattleGround not created!", entry);
[9]1153        sLog.outError("Cannot create gameobject template %u! BattleGround not created!", entry);
1154        delete go;
[2]1155        return false;
1156    }
[9]1157/*
1158    uint32 guid = go->GetGUIDLow();
[2]1159
[9]1160    // without this, UseButtonOrDoor caused the crash, since it tried to get go info from godata
1161    // 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
[2]1162    GameObjectData& data = objmgr.NewGOData(guid);
1163
1164    data.id             = entry;
1165    data.mapid          = GetMapId();
1166    data.posX           = x;
1167    data.posY           = y;
1168    data.posZ           = z;
1169    data.orientation    = o;
1170    data.rotation0      = rotation0;
1171    data.rotation1      = rotation1;
1172    data.rotation2      = rotation2;
1173    data.rotation3      = rotation3;
1174    data.spawntimesecs  = respawnTime;
[9]1175    data.spawnMask      = 1;
[2]1176    data.animprogress   = 100;
1177    data.go_state       = 1;
[9]1178*/
1179    // add to world, so it can be later looked up from HashMapHolder
1180    go->AddToWorld();
1181    m_BgObjects[type] = go->GetGUID();
[2]1182    return true;
1183}
1184
1185//some doors aren't despawned so we cannot handle their closing in gameobject::update()
1186//it would be nice to correctly implement GO_ACTIVATED state and open/close doors in gameobject code
1187void BattleGround::DoorClose(uint32 type)
1188{
1189    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1190    if(obj)
1191    {
1192        //if doors are open, close it
1193        if( obj->getLootState() == GO_ACTIVATED && !obj->GetGoState() )
1194        {
1195            //change state to allow door to be closed
1196            obj->SetLootState(GO_READY);
1197            obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1198        }
1199    }
1200    else
1201    {
1202        sLog.outError("BattleGround: Door object not found (cannot close doors)");
1203    }
1204}
1205
1206void BattleGround::DoorOpen(uint32 type)
1207{
1208    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1209    if(obj)
1210    {
1211        //change state to be sure they will be opened
1212        obj->SetLootState(GO_READY);
1213        obj->UseDoorOrButton(RESPAWN_ONE_DAY);
1214    }
1215    else
1216    {
1217        sLog.outError("BattleGround: Door object not found! - doors will be closed.");
1218    }
1219}
1220
1221void BattleGround::SpawnBGObject(uint32 type, uint32 respawntime)
1222{
[9]1223    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1224    if(!map)
1225        return;
[2]1226    if( respawntime == 0 )
1227    {
1228        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1229        if(obj)
1230        {
1231            //we need to change state from GO_JUST_DEACTIVATED to GO_READY in case battleground is starting again
1232            if( obj->getLootState() == GO_JUST_DEACTIVATED )
1233                obj->SetLootState(GO_READY);
[9]1234            obj->SetRespawnTime(0);
1235            map->Add(obj);
[2]1236        }
1237    }
1238    else
1239    {
1240        GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1241        if(obj)
1242        {
[9]1243            map->Add(obj);
[2]1244            obj->SetRespawnTime(respawntime);
1245            obj->SetLootState(GO_JUST_DEACTIVATED);
1246        }
1247    }
1248}
1249
[9]1250Creature* BattleGround::AddCreature(uint32 entry, uint32 type, uint32 teamval, float x, float y, float z, float o, uint32 respawntime)
[2]1251{
[9]1252    Map * map = MapManager::Instance().FindMap(GetMapId(),GetInstanceID());
1253    if(!map)
1254        return NULL;
[2]1255
1256    Creature* pCreature = new Creature;
1257    if (!pCreature->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), map, entry, teamval))
1258    {
1259        sLog.outError("Can't create creature entry: %u",entry);
1260        delete pCreature;
1261        return NULL;
1262    }
1263
1264    pCreature->Relocate(x, y, z, o);
1265
1266    if(!pCreature->IsPositionValid())
1267    {
1268        sLog.outError("ERROR: Creature (guidlow %d, entry %d) not added to battleground. Suggested coordinates isn't valid (X: %f Y: %f)",pCreature->GetGUIDLow(),pCreature->GetEntry(),pCreature->GetPositionX(),pCreature->GetPositionY());
1269        return NULL;
1270    }
1271
1272    pCreature->AIM_Initialize();
1273
1274    //pCreature->SetDungeonDifficulty(0);
1275
1276    map->Add(pCreature);
1277    m_BgCreatures[type] = pCreature->GetGUID();
[9]1278
[2]1279    return  pCreature;
1280}
1281
1282bool BattleGround::DelCreature(uint32 type)
1283{
1284    Creature *cr = HashMapHolder<Creature>::Find(m_BgCreatures[type]);
1285    if(!cr)
1286    {
[230]1287        sLog.outError("Can't find creature guid: %u",GUID_LOPART(m_BgCreatures[type]));
[2]1288        return false;
1289    }
1290    cr->CleanupsBeforeDelete();
1291    cr->AddObjectToRemoveList();
1292    m_BgCreatures[type] = 0;
1293    return true;
1294}
1295
1296bool BattleGround::DelObject(uint32 type)
1297{
1298    GameObject *obj = HashMapHolder<GameObject>::Find(m_BgObjects[type]);
1299    if(!obj)
1300    {
[230]1301        sLog.outError("Can't find gobject guid: %u",GUID_LOPART(m_BgObjects[type]));
[2]1302        return false;
1303    }
1304    obj->SetRespawnTime(0);                                 // not save respawn time
1305    obj->Delete();
1306    m_BgObjects[type] = 0;
1307    return true;
1308}
1309
1310bool BattleGround::AddSpiritGuide(uint32 type, float x, float y, float z, float o, uint32 team)
1311{
1312    uint32 entry = 0;
1313
1314    if(team == ALLIANCE)
1315        entry = 13116;
1316    else
1317        entry = 13117;
1318
1319    Creature* pCreature = AddCreature(entry,type,team,x,y,z,o);
1320    if(!pCreature)
1321    {
1322        sLog.outError("Can't create Spirit guide. BattleGround not created!");
1323        this->EndNow();
1324        return false;
1325    }
1326
1327    pCreature->setDeathState(DEAD);
1328
1329    pCreature->SetUInt64Value(UNIT_FIELD_CHANNEL_OBJECT, pCreature->GetGUID());
1330    // aura
1331    pCreature->SetUInt32Value(UNIT_FIELD_AURA, SPELL_SPIRIT_HEAL_CHANNEL);
1332    pCreature->SetUInt32Value(UNIT_FIELD_AURAFLAGS, 0x00000009);
1333    pCreature->SetUInt32Value(UNIT_FIELD_AURALEVELS, 0x0000003C);
1334    pCreature->SetUInt32Value(UNIT_FIELD_AURAAPPLICATIONS, 0x000000FF);
1335    // casting visual effect
1336    pCreature->SetUInt32Value(UNIT_CHANNEL_SPELL, SPELL_SPIRIT_HEAL_CHANNEL);
1337    // correct cast speed
1338    pCreature->SetFloatValue(UNIT_MOD_CAST_SPEED, 1.0f);
1339
1340    //pCreature->CastSpell(pCreature, SPELL_SPIRIT_HEAL_CHANNEL, true);
1341
1342    return true;
1343}
1344
1345void BattleGround::SendMessageToAll(char const* text)
1346{
1347    WorldPacket data;
1348    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1349    SendPacketToAll(&data);
1350}
1351
1352void BattleGround::SendMessageToAll(int32 entry)
1353{
[44]1354    char const* text = GetTrinityString(entry);
[2]1355    WorldPacket data;
1356    ChatHandler::FillMessageData(&data, NULL, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_UNIVERSAL, NULL, 0, text, NULL);
1357    SendPacketToAll(&data);
1358}
1359
1360void BattleGround::EndNow()
1361{
[9]1362    RemoveFromBGFreeSlotQueue();
[2]1363    SetStatus(STATUS_WAIT_LEAVE);
1364    SetEndTime(TIME_TO_AUTOREMOVE);
[9]1365    // inform invited players about the removal
1366    sBattleGroundMgr.m_BattleGroundQueues[sBattleGroundMgr.BGQueueTypeId(GetTypeID(), GetArenaType())].BGEndedRemoveInvites(this);
[2]1367}
1368
1369// Battleground messages are localized using the dbc lang, they are not client language dependent
[44]1370const char *BattleGround::GetTrinityString(int32 entry)
[2]1371{
1372    // FIXME: now we have different DBC locales and need localized message for each target client
[44]1373    return objmgr.GetTrinityStringForDBCLocale(entry);
[2]1374}
1375
1376/*
1377important notice:
1378buffs aren't spawned/despawned when players captures anything
1379buffs are in their positions when battleground starts
1380*/
1381void BattleGround::HandleTriggerBuff(uint64 const& go_guid)
1382{
1383    GameObject *obj = HashMapHolder<GameObject>::Find(go_guid);
1384    if(!obj || obj->GetGoType() != GAMEOBJECT_TYPE_TRAP || !obj->isSpawned())
1385        return;
1386
1387    //change buff type, when buff is used:
1388    int32 index = m_BgObjects.size() - 1;
1389    while (index >= 0 && m_BgObjects[index] != go_guid)
1390        index--;
1391    if (index < 0)
1392    {
1393        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());
1394        return;
1395    }
1396
1397    //randomly select new buff
1398    uint8 buff = urand(0, 2);
1399    uint32 entry = obj->GetEntry();
1400    if( m_BuffChange && entry != Buff_Entries[buff] )
1401    {
1402        //despawn current buff
1403        SpawnBGObject(index, RESPAWN_ONE_DAY);
1404        //set index for new one
1405        for (uint8 currBuffTypeIndex = 0; currBuffTypeIndex < 3; ++currBuffTypeIndex)
1406            if( entry == Buff_Entries[currBuffTypeIndex] )
1407            {
1408                index -= currBuffTypeIndex;
1409                index += buff;
1410            }
1411    }
1412
1413    SpawnBGObject(index, BUFF_RESPAWN_TIME);
1414}
1415
1416void BattleGround::HandleKillPlayer( Player *player, Player *killer )
1417{
1418    //keep in mind that for arena this will have to be changed a bit
1419
1420    // add +1 deaths
1421    UpdatePlayerScore(player, SCORE_DEATHS, 1);
1422
1423    // add +1 kills to group and +1 killing_blows to killer
1424    if( killer )
1425    {
1426        UpdatePlayerScore(killer, SCORE_HONORABLE_KILLS, 1);
1427        UpdatePlayerScore(killer, SCORE_KILLING_BLOWS, 1);
1428
1429        for(std::map<uint64, BattleGroundPlayer>::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1430        {
1431            Player *plr = objmgr.GetPlayer(itr->first);
1432
1433            if(!plr || plr == killer)
1434                continue;
1435
1436            if( plr->GetTeam() == killer->GetTeam() && plr->IsAtGroupRewardDistance(player) )
1437                UpdatePlayerScore(plr, SCORE_HONORABLE_KILLS, 1);
1438        }
1439    }
1440
1441    // to be able to remove insignia
1442    player->SetFlag( UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE );
1443}
[9]1444
1445// return the player's team based on battlegroundplayer info
1446// used in same faction arena matches mainly
1447uint32 BattleGround::GetPlayerTeam(uint64 guid)
1448{
1449    std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.find(guid);
1450    if(itr!=m_Players.end())
1451        return itr->second.Team;
1452    return 0;
1453}
1454
1455uint32 BattleGround::GetAlivePlayersCountByTeam(uint32 Team) const
1456{
1457    int count = 0;
1458    for(std::map<uint64, BattleGroundPlayer>::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
1459    {
1460        if(itr->second.Team == Team)
1461        {
1462            Player * pl = objmgr.GetPlayer(itr->first);
1463            if(pl && pl->isAlive())
1464                ++count;
1465        }
1466    }
1467    return count;
1468}
[50]1469
1470void BattleGround::SetHoliday(bool is_holiday)
1471{
1472    if(is_holiday)
1473        m_HonorMode = BG_HOLIDAY;
1474    else
1475        m_HonorMode = BG_NORMAL;
1476}
Note: See TracBrowser for help on using the browser.