Files
TCPlayerbotCore/src/server/game/Battlefield/Battlefield.cpp
T
jackpoz 1c0903e286 Core/Misc: Fix some static analysis issues
Fix some static analysis issues about uninitialized values. Most of them are false positives, always initialized before being accessed, while some of them are real issues spotted by valgrind too.
2013-12-14 18:41:26 +01:00

1167 lines
37 KiB
C++

/*
* Copyright (C) 2008-2013 TrinityCore <http://www.trinitycore.org/>
*
* 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 MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the 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, see <http://www.gnu.org/licenses/>.
*/
#include "Battlefield.h"
#include "BattlefieldMgr.h"
#include "ObjectAccessor.h"
#include "ObjectMgr.h"
#include "Map.h"
#include "MapManager.h"
#include "Group.h"
#include "WorldPacket.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "GridNotifiers.h"
#include "GridNotifiersImpl.h"
#include "CellImpl.h"
#include "CreatureTextMgr.h"
#include "GroupMgr.h"
Battlefield::Battlefield()
{
m_Timer = 0;
m_IsEnabled = true;
m_isActive = false;
m_DefenderTeam = TEAM_NEUTRAL;
m_TypeId = 0;
m_BattleId = 0;
m_ZoneId = 0;
m_Map = NULL;
m_MapId = 0;
m_MaxPlayer = 0;
m_MinPlayer = 0;
m_MinLevel = 0;
m_BattleTime = 0;
m_NoWarBattleTime = 0;
m_RestartAfterCrash = 0;
m_TimeForAcceptInvite = 20;
m_uiKickDontAcceptTimer = 1000;
m_uiKickAfkPlayersTimer = 1000;
m_LastResurectTimer = 30 * IN_MILLISECONDS;
m_StartGroupingTimer = 0;
m_StartGrouping = false;
StalkerGuid = 0;
}
Battlefield::~Battlefield()
{
for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
delete itr->second;
for (GraveyardVect::const_iterator itr = m_GraveyardList.begin(); itr != m_GraveyardList.end(); ++itr)
delete *itr;
}
// Called when a player enters the zone
void Battlefield::HandlePlayerEnterZone(Player* player, uint32 /*zone*/)
{
// If battle is started,
// If not full of players > invite player to join the war
// If full of players > announce to player that BF is full and kick him after a few second if he desn't leave
if (IsWarTime())
{
if (m_PlayersInWar[player->GetTeamId()].size() + m_InvitedPlayers[player->GetTeamId()].size() < m_MaxPlayer) // Vacant spaces
InvitePlayerToWar(player);
else // No more vacant places
{
/// @todo Send a packet to announce it to player
m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(NULL) + 10;
InvitePlayerToQueue(player);
}
}
else
{
// If time left is < 15 minutes invite player to join queue
if (m_Timer <= m_StartGroupingTimer)
InvitePlayerToQueue(player);
}
// Add player in the list of player in zone
m_players[player->GetTeamId()].insert(player->GetGUID());
OnPlayerEnterZone(player);
}
// Called when a player leave the zone
void Battlefield::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/)
{
if (IsWarTime())
{
// If the player is participating to the battle
if (m_PlayersInWar[player->GetTeamId()].find(player->GetGUID()) != m_PlayersInWar[player->GetTeamId()].end())
{
m_PlayersInWar[player->GetTeamId()].erase(player->GetGUID());
player->GetSession()->SendBfLeaveMessage(m_BattleId);
if (Group* group = player->GetGroup()) // Remove the player from the raid group
group->RemoveMember(player->GetGUID());
OnPlayerLeaveWar(player);
}
}
for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
itr->second->HandlePlayerLeave(player);
m_InvitedPlayers[player->GetTeamId()].erase(player->GetGUID());
m_PlayersWillBeKick[player->GetTeamId()].erase(player->GetGUID());
m_players[player->GetTeamId()].erase(player->GetGUID());
SendRemoveWorldStates(player);
RemovePlayerFromResurrectQueue(player->GetGUID());
OnPlayerLeaveZone(player);
}
bool Battlefield::Update(uint32 diff)
{
if (m_Timer <= diff)
{
// Battlefield ends on time
if (IsWarTime())
EndBattle(true);
else // Time to start a new battle!
StartBattle();
}
else
m_Timer -= diff;
// Invite players a few minutes before the battle's beginning
if (!IsWarTime() && !m_StartGrouping && m_Timer <= m_StartGroupingTimer)
{
m_StartGrouping = true;
InvitePlayersInZoneToQueue();
OnStartGrouping();
}
bool objective_changed = false;
if (IsWarTime())
{
if (m_uiKickAfkPlayersTimer <= diff)
{
m_uiKickAfkPlayersTimer = 1000;
KickAfkPlayers();
}
else
m_uiKickAfkPlayersTimer -= diff;
// Kick players who chose not to accept invitation to the battle
if (m_uiKickDontAcceptTimer <= diff)
{
time_t now = time(NULL);
for (int team = 0; team < 2; team++)
for (PlayerTimerMap::iterator itr = m_InvitedPlayers[team].begin(); itr != m_InvitedPlayers[team].end(); ++itr)
if (itr->second <= now)
KickPlayerFromBattlefield(itr->first);
InvitePlayersInZoneToWar();
for (int team = 0; team < 2; team++)
for (PlayerTimerMap::iterator itr = m_PlayersWillBeKick[team].begin(); itr != m_PlayersWillBeKick[team].end(); ++itr)
if (itr->second <= now)
KickPlayerFromBattlefield(itr->first);
m_uiKickDontAcceptTimer = 1000;
}
else
m_uiKickDontAcceptTimer -= diff;
for (BfCapturePointMap::iterator itr = m_capturePoints.begin(); itr != m_capturePoints.end(); ++itr)
if (itr->second->Update(diff))
objective_changed = true;
}
if (m_LastResurectTimer <= diff)
{
for (uint8 i = 0; i < m_GraveyardList.size(); i++)
if (GetGraveyardById(i))
m_GraveyardList[i]->Resurrect();
m_LastResurectTimer = RESURRECTION_INTERVAL;
}
else
m_LastResurectTimer -= diff;
return objective_changed;
}
void Battlefield::InvitePlayersInZoneToQueue()
{
for (uint8 team = 0; team < 2; ++team)
for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
InvitePlayerToQueue(player);
}
void Battlefield::InvitePlayerToQueue(Player* player)
{
if (m_PlayersInQueue[player->GetTeamId()].count(player->GetGUID()))
return;
if (m_PlayersInQueue[player->GetTeamId()].size() <= m_MinPlayer || m_PlayersInQueue[GetOtherTeam(player->GetTeamId())].size() >= m_MinPlayer)
player->GetSession()->SendBfInvitePlayerToQueue(m_BattleId);
}
void Battlefield::InvitePlayersInQueueToWar()
{
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team)
{
for (GuidSet::const_iterator itr = m_PlayersInQueue[team].begin(); itr != m_PlayersInQueue[team].end(); ++itr)
{
if (Player* player = sObjectAccessor->FindPlayer(*itr))
{
if (m_PlayersInWar[player->GetTeamId()].size() + m_InvitedPlayers[player->GetTeamId()].size() < m_MaxPlayer)
InvitePlayerToWar(player);
else
{
//Full
}
}
}
m_PlayersInQueue[team].clear();
}
}
void Battlefield::InvitePlayersInZoneToWar()
{
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team)
for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
{
if (Player* player = sObjectAccessor->FindPlayer(*itr))
{
if (m_PlayersInWar[player->GetTeamId()].count(player->GetGUID()) || m_InvitedPlayers[player->GetTeamId()].count(player->GetGUID()))
continue;
if (m_PlayersInWar[player->GetTeamId()].size() + m_InvitedPlayers[player->GetTeamId()].size() < m_MaxPlayer)
InvitePlayerToWar(player);
else // Battlefield is full of players
m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(NULL) + 10;
}
}
}
void Battlefield::InvitePlayerToWar(Player* player)
{
if (!player)
return;
/// @todo needed ?
if (player->IsInFlight())
return;
if (player->InArena() || player->GetBattleground())
{
m_PlayersInQueue[player->GetTeamId()].erase(player->GetGUID());
return;
}
// If the player does not match minimal level requirements for the battlefield, kick him
if (player->getLevel() < m_MinLevel)
{
if (m_PlayersWillBeKick[player->GetTeamId()].count(player->GetGUID()) == 0)
m_PlayersWillBeKick[player->GetTeamId()][player->GetGUID()] = time(NULL) + 10;
return;
}
// Check if player is not already in war
if (m_PlayersInWar[player->GetTeamId()].count(player->GetGUID()) || m_InvitedPlayers[player->GetTeamId()].count(player->GetGUID()))
return;
m_PlayersWillBeKick[player->GetTeamId()].erase(player->GetGUID());
m_InvitedPlayers[player->GetTeamId()][player->GetGUID()] = time(NULL) + m_TimeForAcceptInvite;
player->GetSession()->SendBfInvitePlayerToWar(m_BattleId, m_ZoneId, m_TimeForAcceptInvite);
}
void Battlefield::InitStalker(uint32 entry, float x, float y, float z, float o)
{
if (Creature* creature = SpawnCreature(entry, x, y, z, o, TEAM_NEUTRAL))
StalkerGuid = creature->GetGUID();
else
TC_LOG_ERROR("bg.battlefield", "Battlefield::InitStalker: could not spawn Stalker (Creature entry %u), zone messeges will be un-available", entry);
}
void Battlefield::KickAfkPlayers()
{
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team)
for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
if (player->isAFK())
KickPlayerFromBattlefield(*itr);
}
void Battlefield::KickPlayerFromBattlefield(uint64 guid)
{
if (Player* player = sObjectAccessor->FindPlayer(guid))
if (player->GetZoneId() == GetZoneId())
player->TeleportTo(KickPosition);
}
void Battlefield::StartBattle()
{
if (m_isActive)
return;
for (int team = 0; team < BG_TEAMS_COUNT; team++)
{
m_PlayersInWar[team].clear();
m_Groups[team].clear();
}
m_Timer = m_BattleTime;
m_isActive = true;
InvitePlayersInZoneToWar();
InvitePlayersInQueueToWar();
DoPlaySoundToAll(BF_START);
OnBattleStart();
}
void Battlefield::EndBattle(bool endByTimer)
{
if (!m_isActive)
return;
m_isActive = false;
m_StartGrouping = false;
if (!endByTimer)
SetDefenderTeam(GetAttackerTeam());
if (GetDefenderTeam() == TEAM_ALLIANCE)
DoPlaySoundToAll(BF_ALLIANCE_WINS);
else
DoPlaySoundToAll(BF_HORDE_WINS);
OnBattleEnd(endByTimer);
// Reset battlefield timer
m_Timer = m_NoWarBattleTime;
SendInitWorldStatesToAll();
}
void Battlefield::DoPlaySoundToAll(uint32 SoundID)
{
WorldPacket data;
data.Initialize(SMSG_PLAY_SOUND, 4);
data << uint32(SoundID);
for (int team = 0; team < BG_TEAMS_COUNT; team++)
for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
player->GetSession()->SendPacket(&data);
}
bool Battlefield::HasPlayer(Player* player) const
{
return m_players[player->GetTeamId()].find(player->GetGUID()) != m_players[player->GetTeamId()].end();
}
// Called in WorldSession::HandleBfQueueInviteResponse
void Battlefield::PlayerAcceptInviteToQueue(Player* player)
{
// Add player in queue
m_PlayersInQueue[player->GetTeamId()].insert(player->GetGUID());
// Send notification
player->GetSession()->SendBfQueueInviteResponse(m_BattleId, m_ZoneId);
}
// Called in WorldSession::HandleBfExitRequest
void Battlefield::AskToLeaveQueue(Player* player)
{
// Remove player from queue
m_PlayersInQueue[player->GetTeamId()].erase(player->GetGUID());
}
// Called in WorldSession::HandleBfEntryInviteResponse
void Battlefield::PlayerAcceptInviteToWar(Player* player)
{
if (!IsWarTime())
return;
if (AddOrSetPlayerToCorrectBfGroup(player))
{
player->GetSession()->SendBfEntered(m_BattleId);
m_PlayersInWar[player->GetTeamId()].insert(player->GetGUID());
m_InvitedPlayers[player->GetTeamId()].erase(player->GetGUID());
if (player->isAFK())
player->ToggleAFK();
OnPlayerJoinWar(player); //for scripting
}
}
void Battlefield::TeamCastSpell(TeamId team, int32 spellId)
{
if (spellId > 0)
{
for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
player->CastSpell(player, uint32(spellId), true);
}
else
{
for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
player->RemoveAuraFromStack(uint32(-spellId));
}
}
void Battlefield::BroadcastPacketToZone(WorldPacket& data) const
{
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team)
for (GuidSet::const_iterator itr = m_players[team].begin(); itr != m_players[team].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
player->GetSession()->SendPacket(&data);
}
void Battlefield::BroadcastPacketToQueue(WorldPacket& data) const
{
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team)
for (GuidSet::const_iterator itr = m_PlayersInQueue[team].begin(); itr != m_PlayersInQueue[team].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
player->GetSession()->SendPacket(&data);
}
void Battlefield::BroadcastPacketToWar(WorldPacket& data) const
{
for (uint8 team = 0; team < BG_TEAMS_COUNT; ++team)
for (GuidSet::const_iterator itr = m_PlayersInWar[team].begin(); itr != m_PlayersInWar[team].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
player->GetSession()->SendPacket(&data);
}
WorldPacket Battlefield::BuildWarningAnnPacket(std::string const& msg)
{
WorldPacket data(SMSG_MESSAGECHAT, 200);
data << uint8(CHAT_MSG_RAID_BOSS_EMOTE);
data << uint32(LANG_UNIVERSAL);
data << uint64(0);
data << uint32(0); // 2.1.0
data << uint32(1);
data << uint8(0);
data << uint64(0);
data << uint32(msg.length() + 1);
data << msg;
data << uint8(0);
return data;
}
void Battlefield::SendWarningToAllInZone(uint32 entry)
{
if (Creature* stalker = GetCreature(StalkerGuid))
// FIXME: replaced CHAT_TYPE_END with CHAT_MSG_BG_SYSTEM_NEUTRAL to fix compile, it's a guessed change :/
sCreatureTextMgr->SendChat(stalker, (uint8) entry, 0, CHAT_MSG_BG_SYSTEM_NEUTRAL, LANG_ADDON, TEXT_RANGE_ZONE);
}
/*void Battlefield::SendWarningToAllInWar(int32 entry, ...)
{
const char *format = sObjectMgr->GetTrinityStringForDBCLocale(entry);
va_list ap;
char str [1024];
va_start(ap, entry);
vsnprintf(str, 1024, format, ap);
va_end(ap);
std::string msg = (std::string)str;
WorldPacket data = BuildWarningAnnPacket(msg);
BroadcastPacketWar(data);
}*/
void Battlefield::SendWarningToPlayer(Player* player, uint32 entry)
{
if (player)
if (Creature* stalker = GetCreature(StalkerGuid))
sCreatureTextMgr->SendChat(stalker, (uint8)entry, player->GetGUID());
}
void Battlefield::SendUpdateWorldState(uint32 field, uint32 value)
{
for (uint8 i = 0; i < BG_TEAMS_COUNT; ++i)
for (GuidSet::iterator itr = m_players[i].begin(); itr != m_players[i].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
player->SendUpdateWorldState(field, value);
}
void Battlefield::RegisterZone(uint32 zoneId)
{
sBattlefieldMgr->AddZone(zoneId, this);
}
void Battlefield::HideNpc(Creature* creature)
{
creature->CombatStop();
creature->SetReactState(REACT_PASSIVE);
creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
creature->SetPhaseMask(2, true);
creature->DisappearAndDie();
creature->SetVisible(false);
}
void Battlefield::ShowNpc(Creature* creature, bool aggressive)
{
creature->SetPhaseMask(1, true);
creature->SetVisible(true);
creature->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
if (!creature->IsAlive())
creature->Respawn(true);
if (aggressive)
creature->SetReactState(REACT_AGGRESSIVE);
else
{
creature->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE);
creature->SetReactState(REACT_PASSIVE);
}
}
// ****************************************************
// ******************* Group System *******************
// ****************************************************
Group* Battlefield::GetFreeBfRaid(TeamId TeamId)
{
for (GuidSet::const_iterator itr = m_Groups[TeamId].begin(); itr != m_Groups[TeamId].end(); ++itr)
if (Group* group = sGroupMgr->GetGroupByGUID(*itr))
if (!group->IsFull())
return group;
return NULL;
}
Group* Battlefield::GetGroupPlayer(uint64 guid, TeamId TeamId)
{
for (GuidSet::const_iterator itr = m_Groups[TeamId].begin(); itr != m_Groups[TeamId].end(); ++itr)
if (Group* group = sGroupMgr->GetGroupByGUID(*itr))
if (group->IsMember(guid))
return group;
return NULL;
}
bool Battlefield::AddOrSetPlayerToCorrectBfGroup(Player* player)
{
if (!player->IsInWorld())
return false;
if (Group* group = player->GetGroup())
group->RemoveMember(player->GetGUID());
Group* group = GetFreeBfRaid(player->GetTeamId());
if (!group)
{
group = new Group;
group->SetBattlefieldGroup(this);
group->Create(player);
sGroupMgr->AddGroup(group);
m_Groups[player->GetTeamId()].insert(group->GetGUID());
}
else if (group->IsMember(player->GetGUID()))
{
uint8 subgroup = group->GetMemberGroup(player->GetGUID());
player->SetBattlegroundOrBattlefieldRaid(group, subgroup);
}
else
group->AddMember(player);
return true;
}
//***************End of Group System*******************
//*****************************************************
//***************Spirit Guide System*******************
//*****************************************************
//--------------------
//-Battlefield Method-
//--------------------
BfGraveyard* Battlefield::GetGraveyardById(uint32 id) const
{
if (id < m_GraveyardList.size())
{
if (BfGraveyard* graveyard = m_GraveyardList.at(id))
return graveyard;
else
TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:%u not existed", id);
}
else
TC_LOG_ERROR("bg.battlefield", "Battlefield::GetGraveyardById Id:%u cant be found", id);
return NULL;
}
WorldSafeLocsEntry const* Battlefield::GetClosestGraveYard(Player* player)
{
BfGraveyard* closestGY = NULL;
float maxdist = -1;
for (uint8 i = 0; i < m_GraveyardList.size(); i++)
{
if (m_GraveyardList[i])
{
if (m_GraveyardList[i]->GetControlTeamId() != player->GetTeamId())
continue;
float dist = m_GraveyardList[i]->GetDistance(player);
if (dist < maxdist || maxdist < 0)
{
closestGY = m_GraveyardList[i];
maxdist = dist;
}
}
}
if (closestGY)
return sWorldSafeLocsStore.LookupEntry(closestGY->GetGraveyardId());
return NULL;
}
void Battlefield::AddPlayerToResurrectQueue(uint64 npcGuid, uint64 playerGuid)
{
for (uint8 i = 0; i < m_GraveyardList.size(); i++)
{
if (!m_GraveyardList[i])
continue;
if (m_GraveyardList[i]->HasNpc(npcGuid))
{
m_GraveyardList[i]->AddPlayer(playerGuid);
break;
}
}
}
void Battlefield::RemovePlayerFromResurrectQueue(uint64 playerGuid)
{
for (uint8 i = 0; i < m_GraveyardList.size(); i++)
{
if (!m_GraveyardList[i])
continue;
if (m_GraveyardList[i]->HasPlayer(playerGuid))
{
m_GraveyardList[i]->RemovePlayer(playerGuid);
break;
}
}
}
void Battlefield::SendAreaSpiritHealerQueryOpcode(Player* player, uint64 guid)
{
WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12);
uint32 time = m_LastResurectTimer; // resurrect every 30 seconds
data << guid << time;
ASSERT(player && player->GetSession());
player->GetSession()->SendPacket(&data);
}
// ----------------------
// - BfGraveyard Method -
// ----------------------
BfGraveyard::BfGraveyard(Battlefield* battlefield)
{
m_Bf = battlefield;
m_GraveyardId = 0;
m_ControlTeam = TEAM_NEUTRAL;
m_SpiritGuide[0] = 0;
m_SpiritGuide[1] = 0;
}
void BfGraveyard::Initialize(TeamId startControl, uint32 graveyardId)
{
m_ControlTeam = startControl;
m_GraveyardId = graveyardId;
}
void BfGraveyard::SetSpirit(Creature* spirit, TeamId team)
{
if (!spirit)
{
TC_LOG_ERROR("bg.battlefield", "BfGraveyard::SetSpirit: Invalid Spirit.");
return;
}
m_SpiritGuide[team] = spirit->GetGUID();
spirit->SetReactState(REACT_PASSIVE);
}
float BfGraveyard::GetDistance(Player* player)
{
const WorldSafeLocsEntry* safeLoc = sWorldSafeLocsStore.LookupEntry(m_GraveyardId);
return player->GetDistance2d(safeLoc->x, safeLoc->y);
}
void BfGraveyard::AddPlayer(uint64 playerGuid)
{
if (!m_ResurrectQueue.count(playerGuid))
{
m_ResurrectQueue.insert(playerGuid);
if (Player* player = sObjectAccessor->FindPlayer(playerGuid))
player->CastSpell(player, SPELL_WAITING_FOR_RESURRECT, true);
}
}
void BfGraveyard::RemovePlayer(uint64 playerGuid)
{
m_ResurrectQueue.erase(m_ResurrectQueue.find(playerGuid));
if (Player* player = sObjectAccessor->FindPlayer(playerGuid))
player->RemoveAurasDueToSpell(SPELL_WAITING_FOR_RESURRECT);
}
void BfGraveyard::Resurrect()
{
if (m_ResurrectQueue.empty())
return;
for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
{
// Get player object from his guid
Player* player = sObjectAccessor->FindPlayer(*itr);
if (!player)
continue;
// Check if the player is in world and on the good graveyard
if (player->IsInWorld())
if (Creature* spirit = m_Bf->GetCreature(m_SpiritGuide[m_ControlTeam]))
spirit->CastSpell(spirit, SPELL_SPIRIT_HEAL, true);
// Resurect player
player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true);
player->ResurrectPlayer(1.0f);
player->CastSpell(player, 6962, true);
player->CastSpell(player, SPELL_SPIRIT_HEAL_MANA, true);
sObjectAccessor->ConvertCorpseForPlayer(player->GetGUID());
}
m_ResurrectQueue.clear();
}
// For changing graveyard control
void BfGraveyard::GiveControlTo(TeamId team)
{
// Guide switching
// Note: Visiblity changes are made by phasing
/*if (m_SpiritGuide[1 - team])
m_SpiritGuide[1 - team]->SetVisible(false);
if (m_SpiritGuide[team])
m_SpiritGuide[team]->SetVisible(true);*/
m_ControlTeam = team;
// Teleport to other graveyard, player witch were on this graveyard
RelocateDeadPlayers();
}
void BfGraveyard::RelocateDeadPlayers()
{
WorldSafeLocsEntry const* closestGrave = NULL;
for (GuidSet::const_iterator itr = m_ResurrectQueue.begin(); itr != m_ResurrectQueue.end(); ++itr)
{
Player* player = sObjectAccessor->FindPlayer(*itr);
if (!player)
continue;
if (closestGrave)
player->TeleportTo(player->GetMapId(), closestGrave->x, closestGrave->y, closestGrave->z, player->GetOrientation());
else
{
closestGrave = m_Bf->GetClosestGraveYard(player);
if (closestGrave)
player->TeleportTo(player->GetMapId(), closestGrave->x, closestGrave->y, closestGrave->z, player->GetOrientation());
}
}
}
bool BfGraveyard::HasNpc(uint64 guid)
{
if (!m_SpiritGuide[0] || !m_SpiritGuide[1])
return false;
if (!m_Bf->GetCreature(m_SpiritGuide[0]) ||
!m_Bf->GetCreature(m_SpiritGuide[1]))
return false;
return (m_SpiritGuide[0] == guid || m_SpiritGuide[1] == guid);
}
// *******************************************************
// *************** End Spirit Guide system ***************
// *******************************************************
// ********************** Misc ***************************
// *******************************************************
Creature* Battlefield::SpawnCreature(uint32 entry, const Position& pos, TeamId team)
{
return SpawnCreature(entry, pos.m_positionX, pos.m_positionY, pos.m_positionZ, pos.m_orientation, team);
}
Creature* Battlefield::SpawnCreature(uint32 entry, float x, float y, float z, float o, TeamId team)
{
//Get map object
Map* map = sMapMgr->CreateBaseMap(m_MapId);
if (!map)
{
TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Can't create creature entry: %u map not found", entry);
return 0;
}
Creature* creature = new Creature();
if (!creature->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_UNIT), map, PHASEMASK_NORMAL, entry, 0, team, x, y, z, o))
{
TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: Can't create creature entry: %u", entry);
delete creature;
return NULL;
}
creature->SetHomePosition(x, y, z, o);
CreatureTemplate const* cinfo = sObjectMgr->GetCreatureTemplate(entry);
if (!cinfo)
{
TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnCreature: entry %u does not exist.", entry);
return NULL;
}
// force using DB speeds -- do we really need this?
creature->SetSpeed(MOVE_WALK, cinfo->speed_walk);
creature->SetSpeed(MOVE_RUN, cinfo->speed_run);
// Set creature in world
map->AddToMap(creature);
creature->setActive(true);
return creature;
}
// Method for spawning gameobject on map
GameObject* Battlefield::SpawnGameObject(uint32 entry, float x, float y, float z, float o)
{
// Get map object
Map* map = sMapMgr->CreateBaseMap(571); // *vomits*
if (!map)
return 0;
// Create gameobject
GameObject* go = new GameObject;
if (!go->Create(sObjectMgr->GenerateLowGuid(HIGHGUID_GAMEOBJECT), entry, map, PHASEMASK_NORMAL, x, y, z, o, 0, 0, 0, 0, 100, GO_STATE_READY))
{
TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Gameobject template %u not found in database! Battlefield not created!", entry);
TC_LOG_ERROR("bg.battlefield", "Battlefield::SpawnGameObject: Cannot create gameobject template %u! Battlefield not created!", entry);
delete go;
return NULL;
}
// Add to world
map->AddToMap(go);
go->setActive(true);
return go;
}
Creature* Battlefield::GetCreature(uint64 GUID)
{
if (!m_Map)
return NULL;
return m_Map->GetCreature(GUID);
}
GameObject* Battlefield::GetGameObject(uint64 GUID)
{
if (!m_Map)
return NULL;
return m_Map->GetGameObject(GUID);
}
// *******************************************************
// ******************* CapturePoint **********************
// *******************************************************
BfCapturePoint::BfCapturePoint(Battlefield* battlefield) : m_Bf(battlefield), m_capturePointGUID(0)
{
m_team = TEAM_NEUTRAL;
m_value = 0;
m_minValue = 0.0f;
m_maxValue = 0.0f;
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL;
m_OldState = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL;
m_capturePointEntry = 0;
m_neutralValuePct = 0;
m_maxSpeed = 0;
}
bool BfCapturePoint::HandlePlayerEnter(Player* player)
{
if (m_capturePointGUID)
{
if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
{
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1);
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate2, uint32(ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f)));
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, m_neutralValuePct);
}
}
return m_activePlayers[player->GetTeamId()].insert(player->GetGUID()).second;
}
GuidSet::iterator BfCapturePoint::HandlePlayerLeave(Player* player)
{
if (m_capturePointGUID)
if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
player->SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 0);
GuidSet::iterator current = m_activePlayers[player->GetTeamId()].find(player->GetGUID());
if (current == m_activePlayers[player->GetTeamId()].end())
return current; // return end()
m_activePlayers[player->GetTeamId()].erase(current++);
return current;
}
void BfCapturePoint::SendChangePhase()
{
if (!m_capturePointGUID)
return;
if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
{
// send this too, sometimes the slider disappears, dunno why :(
SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldState1, 1);
// send these updates to only the ones in this objective
SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate2, (uint32) ceil((m_value + m_maxValue) / (2 * m_maxValue) * 100.0f));
// send this too, sometimes it resets :S
SendUpdateWorldState(capturePoint->GetGOInfo()->capturePoint.worldstate3, m_neutralValuePct);
}
}
bool BfCapturePoint::SetCapturePointData(GameObject* capturePoint)
{
ASSERT(capturePoint);
TC_LOG_DEBUG("bg.battlefield", "Creating capture point %u", capturePoint->GetEntry());
m_capturePointGUID = MAKE_NEW_GUID(capturePoint->GetGUIDLow(), capturePoint->GetEntry(), HIGHGUID_GAMEOBJECT);
// check info existence
GameObjectTemplate const* goinfo = capturePoint->GetGOInfo();
if (goinfo->type != GAMEOBJECT_TYPE_CAPTURE_POINT)
{
TC_LOG_ERROR("misc", "OutdoorPvP: GO %u is not capture point!", capturePoint->GetEntry());
return false;
}
// get the needed values from goinfo
m_maxValue = goinfo->capturePoint.maxTime;
m_maxSpeed = m_maxValue / (goinfo->capturePoint.minTime ? goinfo->capturePoint.minTime : 60);
m_neutralValuePct = goinfo->capturePoint.neutralPercent;
m_minValue = m_maxValue * goinfo->capturePoint.neutralPercent / 100;
m_capturePointEntry = capturePoint->GetEntry();
if (m_team == TEAM_ALLIANCE)
{
m_value = m_maxValue;
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE;
}
else
{
m_value = -m_maxValue;
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE;
}
return true;
}
GameObject* BfCapturePoint::GetCapturePointGo()
{
return m_Bf->GetGameObject(m_capturePointGUID);
}
bool BfCapturePoint::DelCapturePoint()
{
if (m_capturePointGUID)
{
if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
{
capturePoint->SetRespawnTime(0); // not save respawn time
capturePoint->Delete();
capturePoint = NULL;
}
m_capturePointGUID = 0;
}
return true;
}
bool BfCapturePoint::Update(uint32 diff)
{
if (!m_capturePointGUID)
return false;
if (GameObject* capturePoint = m_Bf->GetGameObject(m_capturePointGUID))
{
float radius = capturePoint->GetGOInfo()->capturePoint.radius;
for (uint8 team = 0; team < 2; ++team)
{
for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end();)
{
if (Player* player = sObjectAccessor->FindPlayer(*itr))
{
if (!capturePoint->IsWithinDistInMap(player, radius) || !player->IsOutdoorPvPActive())
itr = HandlePlayerLeave(player);
else
++itr;
}
else
++itr;
}
}
std::list<Player*> players;
Trinity::AnyPlayerInObjectRangeCheck checker(capturePoint, radius);
Trinity::PlayerListSearcher<Trinity::AnyPlayerInObjectRangeCheck> searcher(capturePoint, players, checker);
capturePoint->VisitNearbyWorldObject(radius, searcher);
for (std::list<Player*>::iterator itr = players.begin(); itr != players.end(); ++itr)
if ((*itr)->IsOutdoorPvPActive())
if (m_activePlayers[(*itr)->GetTeamId()].insert((*itr)->GetGUID()).second)
HandlePlayerEnter(*itr);
}
// get the difference of numbers
float fact_diff = ((float) m_activePlayers[0].size() - (float) m_activePlayers[1].size()) * diff / BATTLEFIELD_OBJECTIVE_UPDATE_INTERVAL;
if (G3D::fuzzyEq(fact_diff, 0.0f))
return false;
uint32 Challenger = 0;
float maxDiff = m_maxSpeed * diff;
if (fact_diff < 0)
{
// horde is in majority, but it's already horde-controlled -> no change
if (m_State == BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE && m_value <= -m_maxValue)
return false;
if (fact_diff < -maxDiff)
fact_diff = -maxDiff;
Challenger = HORDE;
}
else
{
// ally is in majority, but it's already ally-controlled -> no change
if (m_State == BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE && m_value >= m_maxValue)
return false;
if (fact_diff > maxDiff)
fact_diff = maxDiff;
Challenger = ALLIANCE;
}
float oldValue = m_value;
TeamId oldTeam = m_team;
m_OldState = m_State;
m_value += fact_diff;
if (m_value < -m_minValue) // red
{
if (m_value < -m_maxValue)
m_value = -m_maxValue;
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE;
m_team = TEAM_HORDE;
}
else if (m_value > m_minValue) // blue
{
if (m_value > m_maxValue)
m_value = m_maxValue;
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE;
m_team = TEAM_ALLIANCE;
}
else if (oldValue * m_value <= 0) // grey, go through mid point
{
// if challenger is ally, then n->a challenge
if (Challenger == ALLIANCE)
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE;
// if challenger is horde, then n->h challenge
else if (Challenger == HORDE)
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE;
m_team = TEAM_NEUTRAL;
}
else // grey, did not go through mid point
{
// old phase and current are on the same side, so one team challenges the other
if (Challenger == ALLIANCE && (m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE || m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_HORDE_CHALLENGE))
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE_ALLIANCE_CHALLENGE;
else if (Challenger == HORDE && (m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE || m_OldState == BF_CAPTUREPOINT_OBJECTIVESTATE_NEUTRAL_ALLIANCE_CHALLENGE))
m_State = BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE_HORDE_CHALLENGE;
m_team = TEAM_NEUTRAL;
}
if (G3D::fuzzyNe(m_value, oldValue))
SendChangePhase();
if (m_OldState != m_State)
{
//TC_LOG_ERROR("bg.battlefield", "%u->%u", m_OldState, m_State);
if (oldTeam != m_team)
ChangeTeam(oldTeam);
return true;
}
return false;
}
void BfCapturePoint::SendUpdateWorldState(uint32 field, uint32 value)
{
for (uint8 team = 0; team < 2; ++team)
for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr) // send to all players present in the area
if (Player* player = sObjectAccessor->FindPlayer(*itr))
player->SendUpdateWorldState(field, value);
}
void BfCapturePoint::SendObjectiveComplete(uint32 id, uint64 guid)
{
uint8 team;
switch (m_State)
{
case BF_CAPTUREPOINT_OBJECTIVESTATE_ALLIANCE:
team = 0;
break;
case BF_CAPTUREPOINT_OBJECTIVESTATE_HORDE:
team = 1;
break;
default:
return;
}
// send to all players present in the area
for (GuidSet::iterator itr = m_activePlayers[team].begin(); itr != m_activePlayers[team].end(); ++itr)
if (Player* player = sObjectAccessor->FindPlayer(*itr))
player->KilledMonsterCredit(id, guid);
}
bool BfCapturePoint::IsInsideObjective(Player* player) const
{
return m_activePlayers[player->GetTeamId()].find(player->GetGUID()) != m_activePlayers[player->GetTeamId()].end();
}