/* * Copyright (C) 2005-2008 MaNGOS * * 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Object.h" #include "Player.h" #include "BattleGround.h" #include "BattleGroundAB.h" #include "Creature.h" #include "Chat.h" #include "ObjectMgr.h" #include "MapManager.h" #include "Language.h" BattleGroundAB::BattleGroundAB() { /* code commented because, it isn't implemented for AB yet m_BgObjects.resize(BG_AB_OBJECT_MAX); //used to store actual spirit guides GUIDs m_BgCreatures.resize(BG_AB_NODES_COUNT+2);*/ } BattleGroundAB::~BattleGroundAB() { // despawn objects / creatures here too, maybe the BG ends when the last not-ported invitee leaves the queue sLog.outDebug("Arathi Basin: BG ended, objects despawning..."); // delete everything (for times, when BG will instanced) for(uint32 i = 0; i < BG_AB_OBJECT_MAX; i++) if (m_bgobjects[i]) { m_bgobjects[i]->SetRespawnTime(0); m_bgobjects[i]->Delete(); m_bgobjects[i] = NULL; } for(uint32 node = 0; node < BG_AB_NODES_COUNT; node++) if (m_bgbuffobjects[node].object) { m_bgbuffobjects[node].object->SetRespawnTime(0); m_bgbuffobjects[node].object->Delete(); m_bgbuffobjects[node].object = NULL; } for(uint32 node = 0; node < 7; node++) if (m_spiritGuides[node]) { m_spiritGuides[node]->CleanupsBeforeDelete(); ObjectAccessor::Instance().AddObjectToRemoveList(m_spiritGuides[node]); m_spiritGuides[node] = NULL; } } void BattleGroundAB::Update(time_t diff) { BattleGround::Update(diff); if (GetStatus() == STATUS_WAIT_JOIN && GetPlayersSize()) { ModifyStartDelayTime(diff); if (!(m_Events & 0x01)) { m_Events |= 0x01; sLog.outDebug("Arathi Basin: entering state STATUS_WAIT_JOIN ..."); // Starting doors MapManager::Instance().GetMap(GetMapId(), m_bgobjects[BG_AB_OBJECT_GATE_A])->Add(m_bgobjects[BG_AB_OBJECT_GATE_A]); MapManager::Instance().GetMap(GetMapId(), m_bgobjects[BG_AB_OBJECT_GATE_H])->Add(m_bgobjects[BG_AB_OBJECT_GATE_H]); // Starting base spirit guides _NodeOccupied(5); _NodeOccupied(6); SetStartDelayTime(START_DELAY0); } // After 1 minute, warning is signalled else if (GetStartDelayTime() <= START_DELAY1 && !(m_Events & 0x04)) { m_Events |= 0x04; SendMessageToAll(GetMangosString(LANG_BG_AB_ONEMINTOSTART)); } // After 1,5 minute, warning is signalled else if (GetStartDelayTime() <= START_DELAY2 && !(m_Events & 0x08)) { m_Events |= 0x08; SendMessageToAll(GetMangosString(LANG_BG_AB_HALFMINTOSTART)); } // After 2 minutes, gates OPEN ! x) else if (GetStartDelayTime() <= 0 && !(m_Events & 0x10)) { m_Events |= 0x10; SendMessageToAll(GetMangosString(LANG_BG_AB_STARTED)); // Neutral banners for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i) MapManager::Instance().GetMap(GetMapId(), m_bgobjects[banner])->Add(m_bgobjects[banner]); m_bgobjects[BG_AB_OBJECT_GATE_A]->SetUInt32Value(GAMEOBJECT_FLAGS,33); m_bgobjects[BG_AB_OBJECT_GATE_A]->SetUInt32Value(GAMEOBJECT_STATE,0); m_bgobjects[BG_AB_OBJECT_GATE_H]->SetUInt32Value(GAMEOBJECT_FLAGS,33); m_bgobjects[BG_AB_OBJECT_GATE_H]->SetUInt32Value(GAMEOBJECT_STATE,0); PlaySoundToAll(SOUND_BG_START); SetStatus(STATUS_IN_PROGRESS); } } else if(GetStatus() == STATUS_IN_PROGRESS) { // 3 sec delay to spawn new banner instead previous despawned one for (int node = 0; node < 5; ++node) if (m_BannerTimers[node].timer) if (m_BannerTimers[node].timer > diff) m_BannerTimers[node].timer -= diff; else { m_BannerTimers[node].timer = 0; _CreateBanner(node, m_BannerTimers[node].type, m_BannerTimers[node].teamIndex, false); } // 1-minute to occupy a node from contested state for (int node = 0; node < 5; ++node) if (m_NodeTimers[node]) if (m_NodeTimers[node] > diff) m_NodeTimers[node] -= diff; else { m_NodeTimers[node] = 0; // Change from contested to occupied ! uint8 teamIndex = m_Nodes[node]-1; m_prevNodes[node] = m_Nodes[node]; m_Nodes[node] += 2; // burn current contested banner _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex); // create new occupied banner _CreateBanner(node, BG_AB_BODE_TYPE_OCCUPIED, teamIndex, true); _SendNodeUpdate(node); _NodeOccupied(node); // Message to chatlog char buf[256]; uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE; sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node)); WorldPacket data; ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL); SendPacketToAll(&data); PlaySoundToAll((teamIndex == 0) ? SOUND_NODE_CAPTURED_ALLIANCE : SOUND_NODE_CAPTURED_HORDE); } // Accumulate points for (int team = 0; team < 2; ++team) { int points = 0; // Go throught all nodes for (int node = 0; node < BG_AB_NODES_COUNT; ++node) if (m_Nodes[node] == team + 3) ++points; if (!points) continue; m_lastTick[team] += diff; if (m_lastTick[team] > BG_AB_TickIntervals[points]) { m_lastTick[team] -= BG_AB_TickIntervals[points]; m_TeamScores[team] += BG_AB_TickPoints[points]; m_HonorScoreTics[team] += BG_AB_TickPoints[points]; m_ReputationScoreTics[team] += BG_AB_TickPoints[points]; if(m_ReputationScoreTics[team] >= 200) { (team == BG_TEAM_ALLIANCE) ? RewardReputationToTeam(509, 10, ALLIANCE) : RewardReputationToTeam(510, 10, HORDE); m_ReputationScoreTics[team] -= 200; } if(m_HonorScoreTics[team] >= 330) { (team == BG_TEAM_ALLIANCE) ? RewardHonorToTeam(20, ALLIANCE) : RewardHonorToTeam(20, HORDE); m_HonorScoreTics[team] -= 330; } if (!m_IsInformedNearVictory && m_TeamScores[team] > 1800) { if(team == BG_TEAM_ALLIANCE) SendMessageToAll(GetMangosString(LANG_BG_AB_A_NEAR_VICTORY)); else SendMessageToAll(GetMangosString(LANG_BG_AB_H_NEAR_VICTORY)); PlaySoundToAll(SOUND_NEAR_VICTORY); m_IsInformedNearVictory = true; } if (m_TeamScores[team] > 2000) m_TeamScores[team] = 2000; if(team == BG_TEAM_ALLIANCE) UpdateWorldState(BG_AB_OP_RESOURCES_ALLY, m_TeamScores[team]); if(team == BG_TEAM_HORDE) UpdateWorldState(BG_AB_OP_RESOURCES_HORDE, m_TeamScores[team]); } } // Test win condition if (m_TeamScores[BG_TEAM_ALLIANCE] >= 2000) EndBattleGround(ALLIANCE); if (m_TeamScores[BG_TEAM_HORDE] >= 2000) EndBattleGround(HORDE); // Buff objects checking m_buffchecktimer += diff; if (m_buffchecktimer > BG_AB_BUFFCHECK_TIME) { for (uint8 node = 0; node < BG_AB_NODES_COUNT; ++node) { // respawn timer caring if (m_bgbuffobjects[node].timer > 0) { if (m_bgbuffobjects[node].timer < m_buffchecktimer) m_bgbuffobjects[node].timer = 0; else m_bgbuffobjects[node].timer -= m_buffchecktimer; // actual respawning } else if (m_Nodes[node] && !m_bgbuffobjects[node].object) // only spawn buff on half- or fully occupied nodes { uint8 buff = urand(0, 2); m_bgbuffobjects[node].object = new GameObject(NULL); m_bgbuffobjects[node].object->SetInstanceId(GetInstanceID()); if (!m_bgbuffobjects[node].object->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_BuffObjects[buff][0], GetMapId(), BG_AB_BuffPositions[node][0], BG_AB_BuffPositions[node][1], BG_AB_BuffPositions[node][2], BG_AB_BuffPositions[node][3], 0, 0, sin(BG_AB_BuffPositions[node][3]/2), cos(BG_AB_BuffPositions[node][3]/2), 0, 0)) ASSERT(0); m_bgbuffobjects[node].spellId = BG_AB_BuffObjects[buff][1]; MapManager::Instance().GetMap(GetMapId(), m_bgbuffobjects[node].object)->Add(m_bgbuffobjects[node].object); // pickup checking } else if (m_bgbuffobjects[node].object) for(std::map::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { Player *plr = objmgr.GetPlayer(itr->first); if(!plr) { sLog.outError("Player " I64FMTD " not found!", itr->first); continue; } if (plr->isAlive() && plr->IsWithinDistInMap(m_bgbuffobjects[node].object , 2)) // 2 yard radius to pick it up { SpellEntry const *spell = sSpellStore.LookupEntry(m_bgbuffobjects[node].spellId); if (spell) plr->CastSpell(plr, spell, true, 0); m_bgbuffobjects[node].timer = BG_AB_BUFF_RESPAWN_TIME; m_bgbuffobjects[node].object->SetRespawnTime(0); m_bgbuffobjects[node].object->Delete(); m_bgbuffobjects[node].object = NULL; break; } } } m_buffchecktimer = 0; } } } void BattleGroundAB::AddPlayer(Player *plr, uint32 team) { BattleGround::AddPlayer(plr, team); //create score and add it to map, default values are set in the constructor BattleGroundABScore* sc = new BattleGroundABScore; m_PlayerScores[plr->GetGUID()] = sc; } void BattleGroundAB::RemovePlayer(Player * /*plr*/, uint64 /*guid*/) { if(GetPlayersSize()==0 && GetInvitedCount(ALLIANCE)==0 && GetInvitedCount(HORDE)==0) { sLog.outDebug("Arathi Basin: BG ended, objects despawning..."); // delete everything (for times, when BG will instanced) for(uint32 i = 0; i < BG_AB_OBJECT_MAX; i++) if (m_bgobjects[i]) { m_bgobjects[i]->SetRespawnTime(0); m_bgobjects[i]->Delete(); m_bgobjects[i] = NULL; } for(uint32 node = 0; node < BG_AB_NODES_COUNT; node++) if (m_bgbuffobjects[node].object) { m_bgbuffobjects[node].object->SetRespawnTime(0); m_bgbuffobjects[node].object->Delete(); m_bgbuffobjects[node].object = NULL; } for(uint32 node = 0; node < 7; node++) if (m_spiritGuides[node]) { m_spiritGuides[node]->CleanupsBeforeDelete(); ObjectAccessor::Instance().AddObjectToRemoveList(m_spiritGuides[node]); m_spiritGuides[node] = NULL; } // no use, the bg will be deleted soonish // re-setup // Reset(); // SetupBattleGround(); // Only change back to STATUS_WAIT_QUEUE if successfully re-setuped } } void BattleGroundAB::HandleAreaTrigger(Player *Source, uint32 Trigger) { if(GetStatus() != STATUS_IN_PROGRESS) return; switch(Trigger) { case 3948: // Arathi Basin Alliance Exit. if(Source->GetTeam() != ALLIANCE) Source->GetSession()->SendAreaTriggerMessage("Only The Alliance can use that portal"); else Source->LeaveBattleground(); break; case 3949: // Arathi Basin Horde Exit. if(Source->GetTeam() != HORDE) Source->GetSession()->SendAreaTriggerMessage("Only The Horde can use that portal"); else Source->LeaveBattleground(); break; case 3866: // Stables case 3869: // Gold Mine case 3867: // Farm case 3868: // Lumber Mill case 3870: // Black Smith case 4020: // Unk1 case 4021: // Unk2 //break; default: //sLog.outError("WARNING: Unhandled AreaTrigger in Battleground: %u", Trigger); //Source->GetSession()->SendAreaTriggerMessage("Warning: Unhandled AreaTrigger in Battleground: %u", Trigger); break; } } /* type: 0-neutral, 1-contested, 3-occupied teamIndex: 0-ally, 1-horde */ void BattleGroundAB::_CreateBanner(uint8 node, uint8 type, uint8 teamIndex, bool delay) { // Just put it into the queue if (delay) { m_BannerTimers[node].timer = 2000; m_BannerTimers[node].type = type; m_BannerTimers[node].teamIndex = teamIndex; return; } uint8 obj = node*8 + type + teamIndex; // create this object uint32 goId; if (type==1) { if (teamIndex==0) goId = BG_AB_OBJECTID_BANNER_CONT_A; else goId = BG_AB_OBJECTID_BANNER_CONT_H; } else if (teamIndex==0) goId = BG_AB_OBJECTID_BANNER_A; else goId = BG_AB_OBJECTID_BANNER_H; m_bgobjects[obj] = new GameObject(NULL); m_bgobjects[obj]->SetInstanceId(GetInstanceID()); m_bgobjects[obj]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), goId, GetMapId(), BG_AB_NodePositions[node][0], BG_AB_NodePositions[node][1], BG_AB_NodePositions[node][2], BG_AB_NodePositions[node][3], 0, 0, sin(BG_AB_NodePositions[node][3]/2), cos(BG_AB_NodePositions[node][3]/2), 100, 1); MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]); // handle aura with banner if (!type) return; obj = node*8 + ((type == 3) ? (5 + teamIndex) : 7); if(m_bgobjects[obj]) MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Add(m_bgobjects[obj]); } void BattleGroundAB::_DelBanner(uint8 node, uint8 type, uint8 teamIndex) { uint8 obj = node*8 + type + teamIndex; if (!m_bgobjects[obj]) return; m_bgobjects[obj]->SetRespawnTime(0); m_bgobjects[obj]->Delete(); m_bgobjects[obj] = NULL; // handle aura with banner if (!type) return; obj = node*8 + ((type == 3) ? (5 + teamIndex) : 7); if(m_bgobjects[obj]) MapManager::Instance().GetMap(GetMapId(), m_bgobjects[obj])->Remove(m_bgobjects[obj], false); } const char* BattleGroundAB::_GetNodeName(uint8 node) { switch (node) { case BG_AB_NODE_STABLES: return GetMangosString(LANG_BG_AB_NODE_STABLES); case BG_AB_NODE_BLACKSMITH: return GetMangosString(LANG_BG_AB_NODE_BLACKSMITH); case BG_AB_NODE_FARM: return GetMangosString(LANG_BG_AB_NODE_FARM); case BG_AB_NODE_LUMBER_MILL: return GetMangosString(LANG_BG_AB_NODE_LUMBER_MILL); case BG_AB_NODE_GOLD_MINE: return GetMangosString(LANG_BG_AB_NODE_GOLD_MINE); default: ASSERT(0); } return ""; } void BattleGroundAB::FillInitialWorldStates(WorldPacket& data) { const uint8 plusArray[] = {0, 2, 3, 0, 1}; /* this values should be already in data variable WorldPacket data(SMSG_INIT_WORLD_STATES, (4+4+4+2+(38*8))); data << uint32(plr->GetMapId()); data << uint32(plr->GetZoneId()); data << uint32(plr->GetAreaId()); data << uint16(38); // count of uint64 blocks data << uint32(0x8d8) << uint32(0x0); // 1 data << uint32(0x8d7) << uint32(0x0); // 2 data << uint32(0x8d6) << uint32(0x0); // 3 data << uint32(0x8d5) << uint32(0x0); // 4 data << uint32(0x8d4) << uint32(0x0); // 5 data << uint32(0x8d3) << uint32(0x0); // 6*/ // Node icons for (uint8 node = 0; node < BG_AB_NODES_COUNT; ++node) data << uint32(BG_AB_OP_NODEICONS[node]) << uint32((m_Nodes[node]==0)?1:0); // Node occupied states for (uint8 node = 0; node < BG_AB_NODES_COUNT; ++node) for (uint8 i = 1; i < BG_AB_NODES_COUNT; ++i) data << uint32(BG_AB_OP_NODESTATES[node] + plusArray[i]) << uint32((m_Nodes[node]==i)?1:0); // How many bases each team owns uint8 ally = 0, horde = 0; for (uint8 node = 0; node < BG_AB_NODES_COUNT; ++node) if (m_Nodes[node] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) ++ally; else if (m_Nodes[node] == BG_AB_NODE_STATUS_HORDE_OCCUPIED) ++horde; data << uint32(BG_AB_OP_OCCUPIED_BASES_ALLY) << uint32(ally); data << uint32(BG_AB_OP_OCCUPIED_BASES_HORDE) << uint32(horde); // Team scores data << uint32(BG_AB_OP_RESOURCES_MAX) << uint32(BG_AB_MAX_TEAM_SCORE); data << uint32(BG_AB_OP_RESOURCES_WARNING) << uint32(BG_AB_WARNING_SCORE); data << uint32(BG_AB_OP_RESOURCES_ALLY) << uint32(m_TeamScores[BG_TEAM_ALLIANCE]); data << uint32(BG_AB_OP_RESOURCES_HORDE) << uint32(m_TeamScores[BG_TEAM_HORDE]); // other unknown data << uint32(0x745) << uint32(0x2); // 37 1861 unk } void BattleGroundAB::_SendNodeUpdate(uint8 node) { // Send node owner state update to refresh map icons on client const uint8 plusArray[] = {0, 2, 3, 0, 1}; if (m_prevNodes[node]) UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_prevNodes[node]], 0); else UpdateWorldState(BG_AB_OP_NODEICONS[node], 0); UpdateWorldState(BG_AB_OP_NODESTATES[node] + plusArray[m_Nodes[node]], 1); // How many bases each team owns uint8 ally = 0, horde = 0; for (uint8 i = 0; i < BG_AB_NODES_COUNT; ++i) if (m_Nodes[i] == BG_AB_NODE_STATUS_ALLY_OCCUPIED) ++ally; else if (m_Nodes[i] == BG_AB_NODE_STATUS_HORDE_OCCUPIED) ++horde; UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_ALLY, ally); UpdateWorldState(BG_AB_OP_OCCUPIED_BASES_HORDE, horde); } void BattleGroundAB::_NodeOccupied(uint8 node) { // spawn spirit guide if (m_spiritGuides[node]) return; m_spiritGuides[node] = new Creature(NULL); m_spiritGuides[node]->SetInstanceId(GetInstanceID()); if (!m_spiritGuides[node]->Create(objmgr.GenerateLowGuid(HIGHGUID_UNIT), 529, BG_AB_SpiritGuidePos[node][0], BG_AB_SpiritGuidePos[node][1], BG_AB_SpiritGuidePos[node][2], BG_AB_SpiritGuidePos[node][3], (node>4)?BG_AB_SpiritGuideId[node-5]:BG_AB_SpiritGuideId[m_Nodes[node]-3], (node>4)?BG_AB_SpiritGuideTeamId[node-5]:BG_AB_SpiritGuideTeamId[m_Nodes[node]-3])) ASSERT(0); m_spiritGuides[node]->setDeathState(DEAD); m_spiritGuides[node]->AIM_Initialize(); MapManager::Instance().GetMap(GetMapId(), m_spiritGuides[node])->Add(m_spiritGuides[node]); m_spiritGuides[node]->CastSpell(m_spiritGuides[node], SPELL_SPIRIT_HEAL_CHANNEL, true); } void BattleGroundAB::_NodeDeOccupied(uint8 node) { if (node >= BG_AB_NODES_COUNT) return; // Those who are waiting to resurrect at this node are taken to the closest own node's graveyard std::vector ghost_list = m_ReviveQueue[m_spiritGuides[node]->GetGUID()]; if (!ghost_list.empty()) { WorldSafeLocsEntry const *ClosestGrave = NULL; Player *plr; for (std::vector::iterator itr = ghost_list.begin(); itr != ghost_list.end(); ++itr) { plr = objmgr.GetPlayer(*ghost_list.begin()); if (!plr) continue; if (!ClosestGrave) ClosestGrave = SelectGraveYard(plr); plr->TeleportTo(GetMapId(), ClosestGrave->x, ClosestGrave->y, ClosestGrave->z, plr->GetOrientation()); } } // despawn spirit guide if (m_spiritGuides[node]) { m_spiritGuides[node]->CleanupsBeforeDelete(); ObjectAccessor::Instance().AddObjectToRemoveList(m_spiritGuides[node]); m_spiritGuides[node] = NULL; } // despawn buff object if ((node < BG_AB_NODES_COUNT) && (m_bgbuffobjects[node].object)) { m_bgbuffobjects[node].object->SetRespawnTime(0); m_bgbuffobjects[node].object->Delete(); m_bgbuffobjects[node].object = NULL; } } /* Invoked if a player used a banner as a gameobject */ void BattleGroundAB::EventPlayerCapturedBanner(Player *source) { if(GetStatus() != STATUS_IN_PROGRESS) return; uint8 node = BG_AB_NODE_STABLES; while ( (node < BG_AB_NODES_COUNT) && !(source->IsWithinDistInMap(m_bgobjects[node*8+7], 10)) ) // player and nodes distance ++node; if (node == BG_AB_NODES_COUNT) { // this means our player isn't close to any of banners - maybe cheater ?? return; } uint8 teamIndex = GetTeamIndexByTeamId(source->GetTeam()); // Message to chatlog char buf[256]; uint8 type = (teamIndex == 0) ? CHAT_MSG_BG_SYSTEM_ALLIANCE : CHAT_MSG_BG_SYSTEM_HORDE; // Check if player really could use this banner, not cheated if ( !(m_Nodes[node] == 0 || teamIndex == m_Nodes[node]%2) ) return; uint32 sound = 0; // If node is neutral, change to contested if (m_Nodes[node] == BG_AB_NODE_TYPE_NEUTRAL) { m_prevNodes[node] = m_Nodes[node]; m_Nodes[node] = teamIndex + 1; // burn current neutral banner _DelBanner(node, BG_AB_NODE_TYPE_NEUTRAL, 0); // create new contested banner _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); _SendNodeUpdate(node); m_NodeTimers[node] = 60000; sprintf(buf, GetMangosString(LANG_BG_AB_NODE_CLAIMED), _GetNodeName(node), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE)); sound = SOUND_NODE_CLAIMED; } // If node is contested else if ((m_Nodes[node] == 1) || (m_Nodes[node] == 2)) { // If last state is NOT occupied, change node to enemy-contested if (m_prevNodes[node] < BG_AB_BODE_TYPE_OCCUPIED) { m_prevNodes[node] = m_Nodes[node]; m_Nodes[node] = teamIndex + 1; // burn current contested banner _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex); // create new contested banner _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); _SendNodeUpdate(node); m_NodeTimers[node] = 60000; sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node)); } // If contested, change back to occupied else { m_prevNodes[node] = m_Nodes[node]; m_Nodes[node] = teamIndex + 3; // burn current contested banner _DelBanner(node, BG_AB_NODE_TYPE_CONTESTED, !teamIndex); // create new occupied banner _CreateBanner(node, BG_AB_BODE_TYPE_OCCUPIED, teamIndex, true); _SendNodeUpdate(node); m_NodeTimers[node] = 0; _NodeOccupied(node); sprintf(buf, GetMangosString(LANG_BG_AB_NODE_DEFENDED), _GetNodeName(node)); } (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE; } // If node is occupied, change to enemy-contested else { m_prevNodes[node] = m_Nodes[node]; m_Nodes[node] = teamIndex + 1; // burn current occupied banner _DelBanner(node, BG_AB_BODE_TYPE_OCCUPIED, !teamIndex); // create new contested banner _CreateBanner(node, BG_AB_NODE_TYPE_CONTESTED, teamIndex, true); _SendNodeUpdate(node); _NodeDeOccupied(node); m_NodeTimers[node] = 60000; sprintf(buf, GetMangosString(LANG_BG_AB_NODE_ASSAULTED), _GetNodeName(node)); (teamIndex == 0) ? SOUND_NODE_ASSAULTED_ALLIANCE : SOUND_NODE_ASSAULTED_HORDE; } UpdatePlayerScore(source, SCORE_HONORABLE_KILLS, 1); UpdatePlayerScore(source, SCORE_BASES_ASSAULTED, 1); WorldPacket data; ChatHandler::FillMessageData(&data, source->GetSession(), type, LANG_UNIVERSAL, NULL, source->GetGUID(), buf, NULL); SendPacketToAll(&data); // If node is occupied again, send "XY has taken the XY" msg. if (m_Nodes[node] > 2) { sprintf(buf, GetMangosString(LANG_BG_AB_NODE_TAKEN), (teamIndex == 0) ? GetMangosString(LANG_BG_AB_ALLY) : GetMangosString(LANG_BG_AB_HORDE), _GetNodeName(node)); ChatHandler::FillMessageData(&data, NULL, type, LANG_UNIVERSAL, NULL, 0, buf, NULL); SendPacketToAll(&data); } PlaySoundToAll(sound); } bool BattleGroundAB::SetupBattleGround() { // Initialize objects table for (uint8 i = 0; i < BG_AB_OBJECT_MAX; ++i) m_bgobjects[i] = NULL; // Create starting objects // neutral banners for (int banner = BG_AB_OBJECT_BANNER_NEUTRAL, i = 0; i < 5; banner += 8, ++i) { m_bgobjects[banner] = new GameObject(NULL); m_bgobjects[banner]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_NODE_BANNER_0+i, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 100, 1)) return false; } // ALL banner auras for (int banner = BG_AB_OBJECT_AURA_ALLY, i = 0; i < 5; banner += 8, ++i) { m_bgobjects[banner] = new GameObject(NULL); m_bgobjects[banner]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_A, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0)) return false; } for (int banner = BG_AB_OBJECT_AURA_HORDE, i = 0; i < 5; banner += 8, ++i) { m_bgobjects[banner] = new GameObject(NULL); m_bgobjects[banner]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_H, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0)) return false; } for (int banner = BG_AB_OBJECT_AURA_CONTESTED, i = 0; i < 5; banner += 8, ++i) { m_bgobjects[banner] = new GameObject(NULL); m_bgobjects[banner]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[banner]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_AURA_C, GetMapId(), BG_AB_NodePositions[i][0], BG_AB_NodePositions[i][1], BG_AB_NodePositions[i][2], BG_AB_NodePositions[i][3], 0, 0, sin(BG_AB_NodePositions[i][3]/2), cos(BG_AB_NodePositions[i][3]/2), 0, 0)) return false; } // Starting gates m_bgobjects[BG_AB_OBJECT_GATE_A] = new GameObject(NULL); m_bgobjects[BG_AB_OBJECT_GATE_A]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[BG_AB_OBJECT_GATE_A]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_GATE_A, GetMapId(), BG_AB_DoorPositions[0][0], BG_AB_DoorPositions[0][1], BG_AB_DoorPositions[0][2], BG_AB_DoorPositions[0][3], BG_AB_DoorPositions[0][4], BG_AB_DoorPositions[0][5], BG_AB_DoorPositions[0][6], BG_AB_DoorPositions[0][7], 100, 1)) return false; m_bgobjects[BG_AB_OBJECT_GATE_H] = new GameObject(NULL); m_bgobjects[BG_AB_OBJECT_GATE_H]->SetInstanceId(GetInstanceID()); if(!m_bgobjects[BG_AB_OBJECT_GATE_H]->Create(objmgr.GenerateLowGuid(HIGHGUID_GAMEOBJECT), BG_AB_OBJECTID_GATE_H, GetMapId(), BG_AB_DoorPositions[1][0], BG_AB_DoorPositions[1][1], BG_AB_DoorPositions[1][2], BG_AB_DoorPositions[1][3], BG_AB_DoorPositions[1][4], BG_AB_DoorPositions[1][5], BG_AB_DoorPositions[1][6], BG_AB_DoorPositions[1][7], 100, 1)) return false; // Initialize pickups table for (uint8 i = 0; i < 5; ++i) { BG_AB_BuffObjectInfo info; info.object = NULL; info.spellId = 0; info.timer = 0; m_bgbuffobjects[i] = info; } // OK return true; } void BattleGroundAB::ResetBGSubclass() { m_TeamScores[BG_TEAM_ALLIANCE] = 0; m_TeamScores[BG_TEAM_HORDE] = 0; m_lastTick[BG_TEAM_ALLIANCE] = 0; m_lastTick[BG_TEAM_HORDE] = 0; m_HonorScoreTics[BG_TEAM_ALLIANCE] = 0; m_HonorScoreTics[BG_TEAM_HORDE] = 0; m_ReputationScoreTics[BG_TEAM_ALLIANCE] = 0; m_ReputationScoreTics[BG_TEAM_HORDE] = 0; m_IsInformedNearVictory = false; for (uint8 i = 0; i < BG_AB_NODES_COUNT; ++i) { m_Nodes[i] = 0; m_prevNodes[i] = 0; m_NodeTimers[i] = 0; m_BannerTimers[i].timer = 0; } for (uint8 i = 0; i < 7; ++i) m_spiritGuides[i] = NULL; m_buffchecktimer = 0; } WorldSafeLocsEntry const* BattleGroundAB::SelectGraveYard(Player* player) { uint8 teamIndex = GetTeamIndexByTeamId(player->GetTeam()); // Is there any occupied node for this team? std::vector nodes; for (uint8 i = 0; i < BG_AB_NODES_COUNT; ++i) if (m_Nodes[i] == teamIndex+3) nodes.push_back(i); WorldSafeLocsEntry const* good_entry = NULL; // If so, select the closest node to place ghost on if (!nodes.empty()) { float x = player->GetPositionX(); float y = player->GetPositionY(); // let alone z coordinate... float mindist = 999999.0f; for (uint8 i = 0; i < nodes.size(); ++i) { WorldSafeLocsEntry const*entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[nodes[i]] ); if(!entry) continue; float dist = (entry->x - x)*(entry->x - x)+(entry->y - y)*(entry->y - y); if (mindist > dist) { mindist = dist; good_entry = entry; } } nodes.clear(); } // If not, place ghost on starting location if(!good_entry) good_entry = sWorldSafeLocsStore.LookupEntry( BG_AB_GraveyardIds[teamIndex+5] ); return good_entry; } void BattleGroundAB::UpdatePlayerScore(Player* Source, uint32 type, uint32 value) { std::map::iterator itr = m_PlayerScores.find(Source->GetGUID()); if(itr == m_PlayerScores.end()) // player not found... return; switch(type) { case SCORE_BASES_ASSAULTED: ((BattleGroundABScore*)itr->second)->BasesAssaulted += value; break; case SCORE_BASES_DEFENDED: ((BattleGroundABScore*)itr->second)->BasesDefended += value; break; default: BattleGround::UpdatePlayerScore(Source,type,value); break; } }