diff options
Diffstat (limited to 'src')
68 files changed, 3981 insertions, 416 deletions
diff --git a/src/server/bnetserver/CMakeLists.txt b/src/server/bnetserver/CMakeLists.txt index 5b854018d47..5d1edef5b81 100644 --- a/src/server/bnetserver/CMakeLists.txt +++ b/src/server/bnetserver/CMakeLists.txt @@ -55,6 +55,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Cryptography/Authentication ${CMAKE_SOURCE_DIR}/src/server/shared/Logging ${CMAKE_SOURCE_DIR}/src/server/shared/Networking + ${CMAKE_SOURCE_DIR}/src/server/shared/Realm ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/ipc diff --git a/src/server/bnetserver/Packets/PacketManager.cpp b/src/server/bnetserver/Packets/PacketManager.cpp index cbfd0c8b2b6..faf38e8a5bc 100644 --- a/src/server/bnetserver/Packets/PacketManager.cpp +++ b/src/server/bnetserver/Packets/PacketManager.cpp @@ -79,7 +79,7 @@ Battlenet::PacketManager::PacketManager() void Battlenet::PacketManager::RegisterAuthenticationPackets() { - REGISTER_CLIENT_PACKET_NAME(PacketHeader(Authentication::CMSG_LOGON_REQUEST, AUTHENTICATION), "Authentication::LogonRequest3"); + REGISTER_CLIENT_PACKET_NAME(PacketHeader(Authentication::CMSG_LOGON_REQUEST, AUTHENTICATION), "Authentication::LogonRequest"); REGISTER_CLIENT_PACKET(PacketHeader(Authentication::CMSG_RESUME_REQUEST, AUTHENTICATION), Authentication::ResumeRequest); REGISTER_CLIENT_PACKET(PacketHeader(Authentication::CMSG_PROOF_RESPONSE, AUTHENTICATION), Authentication::ProofResponse); REGISTER_CLIENT_PACKET(PacketHeader(Authentication::CMSG_LOGON_REQUEST_3, AUTHENTICATION), Authentication::LogonRequest3); diff --git a/src/server/bnetserver/Realms/RealmList.cpp b/src/server/bnetserver/Realms/RealmList.cpp index cc7e1d492a8..a876aa93a07 100644 --- a/src/server/bnetserver/Realms/RealmList.cpp +++ b/src/server/bnetserver/Realms/RealmList.cpp @@ -24,49 +24,6 @@ #include "RealmList.h" #include <boost/asio/ip/tcp.hpp> -Battlenet::RealmId& Battlenet::RealmId::operator=(Battlenet::RealmHandle const& handle) -{ - Region = handle.Region; - Battlegroup = handle.Battlegroup; - Index = handle.Index; - return *this; -} - -ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const -{ - ip::address realmIp; - - // Attempt to send best address for client - if (clientAddr.is_loopback()) - { - // Try guessing if realm is also connected locally - if (LocalAddress.is_loopback() || ExternalAddress.is_loopback()) - realmIp = clientAddr; - else - { - // Assume that user connecting from the machine that bnetserver is located on - // has all realms available in his local network - realmIp = LocalAddress; - } - } - else - { - if (clientAddr.is_v4() && - (clientAddr.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong()) == - (LocalAddress.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong())) - { - realmIp = LocalAddress; - } - else - realmIp = ExternalAddress; - } - - ip::tcp::endpoint endpoint(realmIp, Port); - - // Return external IP - return endpoint; -} - RealmList::RealmList() : _updateInterval(0), _updateTimer(nullptr), _resolver(nullptr), _worldListener(nullptr) { } diff --git a/src/server/bnetserver/Realms/RealmList.h b/src/server/bnetserver/Realms/RealmList.h index dc78a00dfdd..718e26d2564 100644 --- a/src/server/bnetserver/Realms/RealmList.h +++ b/src/server/bnetserver/Realms/RealmList.h @@ -20,6 +20,7 @@ #define _REALMLIST_H #include "Common.h" +#include "Realm.h" #include "WorldListener.h" #include <boost/asio/ip/address.hpp> #include <boost/asio/ip/tcp.hpp> @@ -28,67 +29,6 @@ using namespace boost::asio; -enum RealmFlags -{ - REALM_FLAG_NONE = 0x00, - REALM_FLAG_INVALID = 0x01, - REALM_FLAG_OFFLINE = 0x02, - REALM_FLAG_SPECIFYBUILD = 0x04, - REALM_FLAG_UNK1 = 0x08, - REALM_FLAG_UNK2 = 0x10, - REALM_FLAG_RECOMMENDED = 0x20, - REALM_FLAG_NEW = 0x40, - REALM_FLAG_FULL = 0x80 -}; - -#pragma pack(push, 1) - -namespace Battlenet -{ - struct RealmHandle; - - struct RealmId - { - RealmId() : Region(0), Battlegroup(0), Index(0), Build(0) { } - RealmId(uint8 region, uint8 battlegroup, uint32 index, uint32 build) - : Region(region), Battlegroup(battlegroup), Index(index), Build(build) { } - - uint8 Region; - uint8 Battlegroup; - uint32 Index; - uint32 Build; - - bool operator<(RealmId const& r) const - { - return memcmp(this, &r, sizeof(RealmId) - sizeof(Build)) < 0; - } - - RealmId& operator=(RealmHandle const& handle); - }; -} - -#pragma pack(pop) - -// Storage object for a realm -struct Realm -{ - Battlenet::RealmId Id; - ip::address ExternalAddress; - ip::address LocalAddress; - ip::address LocalSubnetMask; - uint16 Port; - std::string Name; - uint8 Type; - RealmFlags Flags; - uint8 Timezone; - AccountTypes AllowedSecurityLevel; - float PopulationLevel; - bool Updated; - bool Keep; - - ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; -}; - /// Storage object for the list of realms on the server class RealmList { diff --git a/src/server/bnetserver/Realms/WorldListener.cpp b/src/server/bnetserver/Realms/WorldListener.cpp index 30886a67310..9c9f1029e87 100644 --- a/src/server/bnetserver/Realms/WorldListener.cpp +++ b/src/server/bnetserver/Realms/WorldListener.cpp @@ -98,7 +98,9 @@ void WorldListener::HandleToonOnlineStatusChange(Battlenet::RealmHandle const& r if (online) { Battlenet::WoWRealm::ToonReady* toonReady = new Battlenet::WoWRealm::ToonReady(); - toonReady->Realm = realm; + toonReady->Realm.Battlegroup = realm.Battlegroup; + toonReady->Realm.Index = realm.Index; + toonReady->Realm.Region = realm.Region; toonReady->Guid = toonHandle.Guid; toonReady->Name = toonHandle.Name; session->AsyncWrite(toonReady); diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index c06ade69f01..401844b6151 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -29,6 +29,7 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "WorldPacket.h" +#include "WorldStatePackets.h" Battlefield::Battlefield() { @@ -351,7 +352,7 @@ void Battlefield::DoPlaySoundToAll(uint32 SoundID) data << uint32(SoundID); data << uint64(0); - BroadcastPacketToWar(data); + BroadcastPacketToWar(&data); } bool Battlefield::HasPlayer(Player* player) const @@ -410,28 +411,28 @@ void Battlefield::TeamCastSpell(TeamId team, int32 spellId) } } -void Battlefield::BroadcastPacketToZone(WorldPacket& data) const +void Battlefield::BroadcastPacketToZone(WorldPacket const* 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 = ObjectAccessor::FindPlayer(*itr)) - player->SendDirectMessage(&data); + player->SendDirectMessage(data); } -void Battlefield::BroadcastPacketToQueue(WorldPacket& data) const +void Battlefield::BroadcastPacketToQueue(WorldPacket const* 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 = ObjectAccessor::FindConnectedPlayer(*itr)) - player->SendDirectMessage(&data); + player->SendDirectMessage(data); } -void Battlefield::BroadcastPacketToWar(WorldPacket& data) const +void Battlefield::BroadcastPacketToWar(WorldPacket const* 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 = ObjectAccessor::FindPlayer(*itr)) - player->SendDirectMessage(&data); + player->SendDirectMessage(data); } void Battlefield::SendWarning(uint8 id, WorldObject const* target /*= nullptr*/) @@ -440,12 +441,13 @@ void Battlefield::SendWarning(uint8 id, WorldObject const* target /*= nullptr*/) sCreatureTextMgr->SendChat(stalker, id, target); } -void Battlefield::SendUpdateWorldState(uint32 field, uint32 value) +void Battlefield::SendUpdateWorldState(uint32 variable, uint32 value, bool hidden /*= false*/) { - 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 = ObjectAccessor::FindPlayer(*itr)) - player->SendUpdateWorldState(field, value); + WorldPackets::WorldState::UpdateWorldState worldstate; + worldstate.VariableID = variable; + worldstate.Value = value; + worldstate.Hidden = hidden; + BroadcastPacketToZone(worldstate.Write()); } void Battlefield::RegisterZone(uint32 zoneId) diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index 29b8f4a5126..03557779ab1 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -200,7 +200,7 @@ class Battlefield : public ZoneScript virtual bool SetupBattlefield() { return true; } /// Update data of a worldstate to all players present in zone - void SendUpdateWorldState(uint32 field, uint32 value); + void SendUpdateWorldState(uint32 variable, uint32 value, bool hidden = false); /** * \brief Called every time for update bf data and time @@ -397,9 +397,9 @@ class Battlefield : public ZoneScript virtual void SendRemoveWorldStates(Player* /*player*/) { } // use for send a packet for all player list - void BroadcastPacketToZone(WorldPacket& data) const; - void BroadcastPacketToQueue(WorldPacket& data) const; - void BroadcastPacketToWar(WorldPacket& data) const; + void BroadcastPacketToZone(WorldPacket const* data) const; + void BroadcastPacketToQueue(WorldPacket const* data) const; + void BroadcastPacketToWar(WorldPacket const* data) const; // CapturePoint system void AddCapturePoint(BfCapturePoint* cp) { m_capturePoints[cp->GetCapturePointEntry()] = cp; } diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 396b549c0bc..be043aa289a 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -37,6 +37,7 @@ #include "SpellAuras.h" #include "Util.h" #include "WorldPacket.h" +#include "WorldStatePackets.h" #include "Transport.h" namespace Trinity @@ -634,14 +635,14 @@ Position const* Battleground::GetTeamStartPosition(TeamId teamId) const return &StartPosition[teamId]; } -void Battleground::SendPacketToAll(WorldPacket* packet) +void Battleground::SendPacketToAll(WorldPacket const* packet) const { for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) if (Player* player = _GetPlayer(itr, "SendPacketToAll")) player->SendDirectMessage(packet); } -void Battleground::SendPacketToTeam(uint32 TeamID, WorldPacket* packet, Player* sender, bool self) +void Battleground::SendPacketToTeam(uint32 TeamID, WorldPacket const* packet, Player* sender, bool self) const { for (BattlegroundPlayerMap::const_iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr) { @@ -716,18 +717,13 @@ void Battleground::RewardReputationToTeam(uint32 faction_id, uint32 Reputation, } } -void Battleground::UpdateWorldState(uint32 Field, uint32 Value) +void Battleground::UpdateWorldState(uint32 variable, uint32 value, bool hidden /*= false*/) { - WorldPacket data; - sBattlegroundMgr->BuildUpdateWorldStatePacket(&data, Field, Value); - SendPacketToAll(&data); -} - -void Battleground::UpdateWorldStateForPlayer(uint32 field, uint32 value, Player* player) -{ - WorldPacket data; - sBattlegroundMgr->BuildUpdateWorldStatePacket(&data, field, value); - player->SendDirectMessage(&data); + WorldPackets::WorldState::UpdateWorldState worldstate; + worldstate.VariableID = variable; + worldstate.Value = value; + worldstate.Hidden = hidden; + SendPacketToAll(worldstate.Write()); } void Battleground::EndBattleground(uint32 winner) diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index fc52178c52d..aa0bb6fbb4c 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -347,8 +347,8 @@ class Battleground // Packet Transfer // method that should fill worldpacket with actual world states (not yet implemented for all battlegrounds!) virtual void FillInitialWorldStates(WorldPacket& /*data*/) { } - void SendPacketToTeam(uint32 TeamID, WorldPacket* packet, Player* sender = NULL, bool self = true); - void SendPacketToAll(WorldPacket* packet); + void SendPacketToTeam(uint32 TeamID, WorldPacket const* packet, Player* sender = NULL, bool self = true) const; + void SendPacketToAll(WorldPacket const* packet) const; void SendChatMessage(Creature* source, uint8 textId, WorldObject* target = NULL); @@ -361,8 +361,7 @@ class Battleground void RemoveAuraOnTeam(uint32 SpellID, uint32 TeamID); void RewardHonorToTeam(uint32 Honor, uint32 TeamID); void RewardReputationToTeam(uint32 faction_id, uint32 Reputation, uint32 TeamID); - void UpdateWorldState(uint32 Field, uint32 Value); - void UpdateWorldStateForPlayer(uint32 Field, uint32 Value, Player* player); + void UpdateWorldState(uint32 variable, uint32 value, bool hidden = false); virtual void EndBattleground(uint32 winner); void BlockMovement(Player* player); diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.cpp b/src/server/game/Battlegrounds/BattlegroundMgr.cpp index eae6a831290..e1a3a9b065c 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.cpp +++ b/src/server/game/Battlegrounds/BattlegroundMgr.cpp @@ -426,13 +426,6 @@ void BattlegroundMgr::BuildStatusFailedPacket(WorldPacket* data, Battleground* b data->WriteByteSeq(unkGuid3[5]); } -void BattlegroundMgr::BuildUpdateWorldStatePacket(WorldPacket* data, uint32 field, uint32 value) -{ - data->Initialize(SMSG_UPDATE_WORLD_STATE, 4+4); - *data << uint32(field); - *data << uint32(value); -} - void BattlegroundMgr::BuildPlaySoundPacket(WorldPacket* data, uint32 soundid) { data->Initialize(SMSG_PLAY_SOUND, 4 + 8); diff --git a/src/server/game/Battlegrounds/BattlegroundMgr.h b/src/server/game/Battlegrounds/BattlegroundMgr.h index 23689c03fba..9e330373685 100644 --- a/src/server/game/Battlegrounds/BattlegroundMgr.h +++ b/src/server/game/Battlegrounds/BattlegroundMgr.h @@ -74,7 +74,6 @@ class BattlegroundMgr void BuildPlayerLeftBattlegroundPacket(WorldPacket* data, ObjectGuid guid); void BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid guid, Player* player, BattlegroundTypeId bgTypeId); void BuildStatusFailedPacket(WorldPacket* data, Battleground* bg, Player* pPlayer, uint8 QueueSlot, GroupJoinBattlegroundResult result); - void BuildUpdateWorldStatePacket(WorldPacket* data, uint32 field, uint32 value); void BuildBattlegroundStatusPacket(WorldPacket* data, Battleground* bg, Player* player, uint8 queueSlot, uint8 statusId, uint32 time1, uint32 time2, uint8 arenaType); void BuildPlaySoundPacket(WorldPacket* data, uint32 soundId); void SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid); diff --git a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp index 034f7c91999..1663f4da049 100644 --- a/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp +++ b/src/server/game/Battlegrounds/Zones/BattlegroundEY.cpp @@ -179,9 +179,9 @@ void BattlegroundEY::CheckSomeoneJoinedPoint() { //player joined point! //show progress bar - UpdateWorldStateForPlayer(PROGRESS_BAR_PERCENT_GREY, BG_EY_PROGRESS_BAR_PERCENT_GREY, player); - UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, m_PointBarStatus[i], player); - UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_SHOW, player); + player->SendUpdateWorldState(PROGRESS_BAR_PERCENT_GREY, BG_EY_PROGRESS_BAR_PERCENT_GREY); + player->SendUpdateWorldState(PROGRESS_BAR_STATUS, m_PointBarStatus[i]); + player->SendUpdateWorldState(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_SHOW); //add player to point m_PlayersNearPoint[i].push_back(m_PlayersNearPoint[EY_POINTS_MAX][j]); //remove player from "free space" @@ -222,7 +222,7 @@ void BattlegroundEY::CheckSomeoneLeftPoint() { m_PlayersNearPoint[EY_POINTS_MAX].push_back(m_PlayersNearPoint[i][j]); m_PlayersNearPoint[i].erase(m_PlayersNearPoint[i].begin() + j); - this->UpdateWorldStateForPlayer(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_DONT_SHOW, player); + player->SendUpdateWorldState(PROGRESS_BAR_SHOW, BG_EY_PROGRESS_BAR_DONT_SHOW); } else { @@ -265,7 +265,7 @@ void BattlegroundEY::UpdatePointStatuses() Player* player = ObjectAccessor::FindPlayer(m_PlayersNearPoint[point][i]); if (player) { - this->UpdateWorldStateForPlayer(PROGRESS_BAR_STATUS, m_PointBarStatus[point], player); + player->SendUpdateWorldState(PROGRESS_BAR_STATUS, m_PointBarStatus[point]); //if point owner changed we must evoke event! if (pointOwnerTeamId != m_PointOwnedByTeam[point]) { diff --git a/src/server/game/CMakeLists.txt b/src/server/game/CMakeLists.txt index bcf1a33a626..d18fce9b829 100644 --- a/src/server/game/CMakeLists.txt +++ b/src/server/game/CMakeLists.txt @@ -128,6 +128,7 @@ include_directories( ${CMAKE_SOURCE_DIR}/src/server/shared/Logging ${CMAKE_SOURCE_DIR}/src/server/shared/Networking ${CMAKE_SOURCE_DIR}/src/server/shared/Packets + ${CMAKE_SOURCE_DIR}/src/server/shared/Realm ${CMAKE_SOURCE_DIR}/src/server/shared/Threading ${CMAKE_SOURCE_DIR}/src/server/shared/Utilities ${CMAKE_SOURCE_DIR}/src/server/ipc diff --git a/src/server/game/Entities/Object/Updates/UpdateData.cpp b/src/server/game/Entities/Object/Updates/UpdateData.cpp index df7f6fdcc77..74f6b62e398 100644 --- a/src/server/game/Entities/Object/Updates/UpdateData.cpp +++ b/src/server/game/Entities/Object/Updates/UpdateData.cpp @@ -45,11 +45,11 @@ void UpdateData::AddUpdateBlock(const ByteBuffer &block) bool UpdateData::BuildPacket(WorldPacket* packet) { ASSERT(packet->empty()); // shouldn't happen - packet->Initialize(SMSG_UPDATE_OBJECT, 2 + 4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos()); + packet->Initialize(SMSG_UPDATE_OBJECT, 2 + 4 + (m_outOfRangeGUIDs.empty() ? 0 : 1 + 4 + 9 * m_outOfRangeGUIDs.size()) + m_data.wpos(), CONNECTION_TYPE_INSTANCE); *packet << uint32(m_blockCount); *packet << uint16(m_map); - + if (packet->WriteBit(!m_outOfRangeGUIDs.empty())) { *packet << uint16(0); diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 99561741931..1ad85c237ac 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -41,6 +41,7 @@ #include "DisableMgr.h" #include "Formulas.h" #include "GameEventMgr.h" +#include "GameObjectAI.h" #include "GossipDef.h" #include "GridNotifiers.h" #include "GridNotifiersImpl.h" @@ -55,6 +56,7 @@ #include "Log.h" #include "MapInstanced.h" #include "MapManager.h" +#include "MovementStructures.h" #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Opcodes.h" @@ -81,8 +83,7 @@ #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "MovementStructures.h" -#include "GameObjectAI.h" +#include "WorldStatePackets.h" #define ZONE_UPDATE_INTERVAL (1*IN_MILLISECONDS) @@ -6516,7 +6517,7 @@ void Player::SendMessageToSet(WorldPacket* data, Player const* skipped_rcvr) VisitNearbyWorldObject(GetVisibilityRange(), notifier); } -void Player::SendDirectMessage(WorldPacket* data) +void Player::SendDirectMessage(WorldPacket const* data) { m_session->SendPacket(data); } @@ -9084,13 +9085,13 @@ void Player::SendNotifyLootItemRemoved(uint8 lootSlot) GetSession()->SendPacket(&data); } -void Player::SendUpdateWorldState(uint32 Field, uint32 Value) +void Player::SendUpdateWorldState(uint32 variable, uint32 value, bool hidden /*= false*/) { - WorldPacket data(SMSG_UPDATE_WORLD_STATE, 4+4+1); - data << Field; - data << Value; - data << uint8(0); - GetSession()->SendPacket(&data); + WorldPackets::WorldState::UpdateWorldState worldstate; + worldstate.VariableID = variable; + worldstate.Value = value; + worldstate.Hidden = hidden; + SendDirectMessage(worldstate.Write()); } void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) @@ -9110,22 +9111,22 @@ void Player::SendInitWorldStates(uint32 zoneid, uint32 areaid) data << uint32(areaid); // area id, new 2.1.0 size_t countPos = data.wpos(); data << uint16(0); // 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 - // 7 1 - Arena season in progress, 0 - end of season - data << uint32(0xC77) << uint32(sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS)); - // 8 Arena season id - data << uint32(0xF3D) << uint32(sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID)); + data << uint32(2264) << uint32(0); // 1 + data << uint32(2263) << uint32(0); // 2 + data << uint32(2262) << uint32(0); // 3 + data << uint32(2261) << uint32(0); // 4 + data << uint32(2260) << uint32(0); // 5 + data << uint32(2259) << uint32(0); // 6 + + data << uint32(3191) << uint32(sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS) ? sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) : 0); // 7 Current Season - Arena season in progress + // 0 - End of season + data << uint32(3901) << uint32(sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) - sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS)); // 8 PreviousSeason if (mapid == 530) // Outland { - data << uint32(0x9bf) << uint32(0x0); // 7 - data << uint32(0x9bd) << uint32(0xF); // 8 - data << uint32(0x9bb) << uint32(0xF); // 9 + data << uint32(2495) << uint32(0x0); // 7 + data << uint32(2493) << uint32(0xF); // 8 + data << uint32(2491) << uint32(0xF); // 9 } // insert <field> <value> diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e0655a39daa..0f5418e24e7 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2248,8 +2248,8 @@ class Player : public Unit, public GridObject<Player> void DeleteEquipmentSet(uint64 setGuid); void SendInitWorldStates(uint32 zone, uint32 area); - void SendUpdateWorldState(uint32 Field, uint32 Value); - void SendDirectMessage(WorldPacket* data); + void SendUpdateWorldState(uint32 variable, uint32 value, bool hidden = false); + void SendDirectMessage(WorldPacket const* data); void SendBGWeekendWorldStates(); void SendBattlefieldWorldStates(); diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index 780360dc945..cf46272080e 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -19,7 +19,6 @@ #include "GameEventMgr.h" #include "World.h" #include "ObjectMgr.h" -#include "WorldPacket.h" #include "PoolMgr.h" #include "Language.h" #include "Log.h" @@ -29,6 +28,7 @@ #include "BattlegroundMgr.h" #include "UnitAI.h" #include "GameObjectAI.h" +#include "WorldStatePackets.h" bool GameEventMgr::CheckOneGameEvent(uint16 entry) const { @@ -1486,9 +1486,11 @@ void GameEventMgr::UpdateWorldStates(uint16 event_id, bool Activate) BattlemasterListEntry const* bl = sBattlemasterListStore.LookupEntry(bgTypeId); if (bl && bl->HolidayWorldStateId) { - WorldPacket data; - sBattlegroundMgr->BuildUpdateWorldStatePacket(&data, bl->HolidayWorldStateId, Activate ? 1 : 0); - sWorld->SendGlobalMessage(&data); + WorldPackets::WorldState::UpdateWorldState worldstate; + worldstate.VariableID = bl->HolidayWorldStateId; + worldstate.Value = Activate; + //worldstate.Hidden = false; + sWorld->SendGlobalMessage(worldstate.Write()); } } } diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index 13e390bc362..576ebf4f547 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -2678,7 +2678,7 @@ void ObjectMgr::LoadItemTemplates() itemTemplate.ItemId = itemId; itemTemplate.Class = uint32(fields[1].GetUInt8()); itemTemplate.SubClass = uint32(fields[2].GetUInt8()); - itemTemplate.SoundOverrideSubclass = fields[3].GetInt32(); + itemTemplate.SoundOverrideSubclass = fields[3].GetInt8(); itemTemplate.Name1 = fields[4].GetString(); itemTemplate.DisplayInfoID = fields[5].GetUInt32(); itemTemplate.Quality = uint32(fields[6].GetUInt8()); @@ -6365,11 +6365,11 @@ void ObjectMgr::SetHighestGuids() result = WorldDatabase.Query("SELECT MAX(guid) FROM gameobject"); if (result) - _gameObjectGuidGenerator.Set((*result)[0].GetUInt32() + 1); + _gameObjectGuidGenerator.Set((*result)[0].GetUInt64() + 1); result = WorldDatabase.Query("SELECT MAX(guid) FROM transports"); if (result) - _moTransportGuidGenerator.Set((*result)[0].GetUInt32() + 1); + _moTransportGuidGenerator.Set((*result)[0].GetUInt64() + 1); result = CharacterDatabase.Query("SELECT MAX(id) FROM auctionhouse"); if (result) @@ -8832,8 +8832,8 @@ void ObjectMgr::LoadCreatureClassLevelStats() } } - stats.BaseMana = fields[8].GetUInt16(); - stats.BaseArmor = fields[9].GetUInt16(); + stats.BaseMana = fields[8].GetUInt32(); + stats.BaseArmor = fields[9].GetUInt32(); stats.AttackPower = fields[10].GetUInt16(); stats.RangedAttackPower = fields[11].GetUInt16(); diff --git a/src/server/game/Handlers/AuctionHouseHandler.cpp b/src/server/game/Handlers/AuctionHouseHandler.cpp index e35baca3efc..bad38c91e79 100644 --- a/src/server/game/Handlers/AuctionHouseHandler.cpp +++ b/src/server/game/Handlers/AuctionHouseHandler.cpp @@ -65,7 +65,7 @@ void WorldSession::SendAuctionHello(ObjectGuid guid, Creature* unit) if (!ahEntry) return; - WorldPacket data(MSG_AUCTION_HELLO, 12); + WorldPacket data(SMSG_AUCTION_HELLO, 12); data << guid; data << uint32(ahEntry->houseId); data << uint8(1); // 3.3.3: 1 - AH enabled, 0 - AH disabled @@ -74,7 +74,7 @@ void WorldSession::SendAuctionHello(ObjectGuid guid, Creature* unit) void WorldSession::SendAuctionCommandResult(AuctionEntry* auction, uint32 action, uint32 errorCode, uint32 /*bidError = 0*/) { - WorldPackets::AuctionHousePackets::AuctionCommandResult auctionCommandResult; + WorldPackets::AuctionHouse::AuctionCommandResult auctionCommandResult; auctionCommandResult.InitializeAuction(auction); auctionCommandResult.Action = action; auctionCommandResult.ErrorCode = errorCode; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 6845ebb383b..dd6090a0d62 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -19,7 +19,10 @@ #include "AccountMgr.h" #include "ArenaTeam.h" #include "ArenaTeamMgr.h" +#include "AuthenticationPackets.h" #include "Battleground.h" +#include "BattlegroundPackets.h" +#include "BattlenetServerManager.h" #include "CalendarMgr.h" #include "CharacterPackets.h" #include "Chat.h" @@ -50,7 +53,6 @@ #include "World.h" #include "WorldPacket.h" #include "WorldSession.h" -#include "BattlenetServerManager.h" class LoginQueryHolder : public SQLQueryHolder { @@ -761,7 +763,7 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin& TC_LOG_DEBUG("network", "WORLD: Recvd Player Logon Message"); - m_playerLoading = true; + m_playerLoading = playerLogin.Guid; TC_LOG_DEBUG("network", "Character %s logging in", playerLogin.Guid.ToString().c_str()); @@ -772,11 +774,32 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin& return; } - LoginQueryHolder* holder = new LoginQueryHolder(GetAccountId(), playerLogin.Guid); + boost::system::error_code ignored_error; + boost::asio::ip::tcp::endpoint instanceAddress = realm.GetAddressForClient(boost::asio::ip::address::from_string(GetRemoteAddress(), ignored_error)); + instanceAddress.port(sWorld->getIntConfig(CONFIG_PORT_INSTANCE)); + + WorldPackets::Auth::ConnectTo connectTo; + connectTo.Key = MAKE_PAIR64(GetAccountId(), CONNECTION_TYPE_INSTANCE); + connectTo.Serial = 1; + connectTo.Payload.Where = instanceAddress; + connectTo.Con = CONNECTION_TYPE_INSTANCE; + + SendPacket(connectTo.Write()); +} + +void WorldSession::HandleContinuePlayerLogin() +{ + if (!PlayerLoading() || GetPlayer()) + { + KickPlayer(); + return; + } + + LoginQueryHolder* holder = new LoginQueryHolder(GetAccountId(), m_playerLoading); if (!holder->Initialize()) { delete holder; // delete all unprocessed queries - m_playerLoading = false; + m_playerLoading.Clear(); return; } @@ -809,7 +832,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) KickPlayer(); // disconnect client, player no set to session and it will not deleted or saved at kick delete pCurrChar; // delete it manually delete holder; // delete all unprocessed queries - m_playerLoading = false; + m_playerLoading.Clear(); return; } @@ -870,6 +893,20 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) TC_LOG_DEBUG("network", "WORLD: Sent motd (SMSG_MOTD)"); } + SendSetTimeZoneInformation(); + + // Send PVPSeason + { + WorldPackets::Battleground::PVPSeason season; + season.PreviousSeason = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID) - sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS); + + if (sWorld->getBoolConfig(CONFIG_ARENA_SEASON_IN_PROGRESS)) + season.CurrentSeason = sWorld->getIntConfig(CONFIG_ARENA_SEASON_ID); + + SendPacket(season.Write()); + TC_LOG_DEBUG("network", "WORLD: Sent PVPSeason"); + } + // send server info { if (sWorld->getIntConfig(CONFIG_ENABLE_SINFO_LOGIN) == 1) @@ -1049,7 +1086,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder) if (!pCurrChar->IsStandState() && !pCurrChar->HasUnitState(UNIT_STATE_STUNNED)) pCurrChar->SetStandState(UNIT_STAND_STATE_STAND); - m_playerLoading = false; + m_playerLoading.Clear(); // Handle Login-Achievements (should be handled after loading) _player->UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN, 1); diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index 014e9f7b9d6..39e3edb30ed 100644 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -115,7 +115,9 @@ void WorldSession::HandleLfgJoinOpcode(WorldPacket& recvData) { uint32 dungeon; recvData >> dungeon; - newDungeons.insert((dungeon & 0x00FFFFFF)); // remove the type from the dungeon entry + dungeon &= 0x00FFFFFF; // remove the type from the dungeon entry + if (dungeon) + newDungeons.insert(dungeon); } TC_LOG_DEBUG("lfg", "CMSG_LFG_JOIN %s roles: %u, Dungeons: %u, Comment: %s", diff --git a/src/server/game/Scripting/ScriptLoader.cpp b/src/server/game/Scripting/ScriptLoader.cpp index 0e43a63c98e..ad727fc17d2 100644 --- a/src/server/game/Scripting/ScriptLoader.cpp +++ b/src/server/game/Scripting/ScriptLoader.cpp @@ -677,6 +677,12 @@ void AddSC_zangarmarsh(); // Maelstrom void AddSC_kezan(); +void AddSC_instance_stonecore(); // Stonecore +void AddSC_stonecore(); +void AddSC_boss_corborus(); +void AddSC_boss_slabhide(); +void AddSC_boss_ozruk(); +void AddSC_boss_high_priestess_azil(); // Events void AddSC_event_childrens_week(); @@ -1411,6 +1417,12 @@ void AddMaelstromScripts() { #ifdef SCRIPTS AddSC_kezan(); + AddSC_instance_stonecore(); // Stonecore + AddSC_stonecore(); + AddSC_boss_corborus(); + AddSC_boss_slabhide(); + AddSC_boss_ozruk(); + AddSC_boss_high_priestess_azil(); #endif } diff --git a/src/server/game/Server/Packet.cpp b/src/server/game/Server/Packet.cpp index 10b472bee67..ee805c18610 100644 --- a/src/server/game/Server/Packet.cpp +++ b/src/server/game/Server/Packet.cpp @@ -17,6 +17,164 @@ #include "Packet.h" +inline bool IsInstanceOnlyOpcode(uint32 opcode) +{ + // TODO: Use names when known + switch (opcode) + { + case 0x000F: // Client + case 0x0111: // Client + case 0x03E4: // Client + case 0x0549: // Client + case 0x054C: // Client + case 0x055A: // Client + case 0x056C: // Client + case 0x057A: // Client + case 0x057B: // Client + case 0x05CC: // Client + case 0x05EA: // Client + case 0x05EC: // Client + case 0x05F9: // Client + case 0x05FB: // Client + case 0x074C: // Client + case 0x075B: // Client + case 0x076C: // Client + case 0x077B: // Client + case 0x077C: // Client + case 0x07CC: // Client + case 0x07DB: // Client + case 0x07EC: // Client + case 0x07FB: // Client + case 0x07FC: // Client + case 0x0827: // Client + case 0x0935: // Client + case 0x0F0C: // ClientSpell + case 0x0F10: // ClientSpell + case 0x0F1B: // ClientSpell + case 0x0F1C: // ClientSpell + case 0x0F20: // ClientSpell + case 0x0F2C: // ClientSpell + case 0x0F2F: // ClientSpell + case 0x0F3B: // ClientSpell + case 0x0F8B: // ClientSpell + case 0x0F8C: // ClientSpell + case 0x0F90: // ClientSpell + case 0x0F9F: // ClientSpell + case 0x0FA0: // ClientSpell + case SMSG_ATTACKSTOP: // Client + case 0x14C9: // Client + case 0x154A: // Client + case 0x155A: // Client + case 0x155C: // Client + case SMSG_QUESTGIVER_STATUS: // ClientQuest + case 0x156A: // Client + case 0x156B: // Client + case 0x157A: // Client + case 0x157B: // Client + case 0x15DC: // Client + case 0x15EB: // Client + case 0x15FB: // Client + case 0x170C: // ClientSpell + case 0x171C: // ClientSpell + case 0x171F: // ClientSpell + case 0x172C: // ClientSpell + case 0x172F: // ClientSpell + case 0x173C: // ClientSpell + case 0x173F: // ClientSpell + case 0x1740: // ClientSpell + case 0x1790: // ClientSpell + case 0x179B: // ClientSpell + case 0x179F: // ClientSpell + case SMSG_ATTACKSTART: // Client + case 0x1D82: // ClientQuest + case 0x1D83: // ClientQuest + case 0x1D85: // ClientQuest + case 0x1D87: // ClientQuest + case 0x1D93: // ClientQuest + case 0x1D96: // ClientQuest + case 0x1D97: // ClientQuest + case 0x1DA1: // ClientQuest + case 0x1DA2: // ClientQuest + case 0x1DA3: // ClientQuest + case 0x1DA4: // ClientQuest + case 0x1DA5: // ClientQuest + case 0x1DA7: // ClientQuest + case SMSG_QUERY_TIME_RESPONSE: // Client + case 0x1DC2: // ClientQuest + case 0x1DC6: // ClientQuest + case 0x1DC7: // ClientQuest + case 0x1DD2: // ClientQuest + case 0x1DD3: // ClientQuest + case 0x1DD6: // ClientQuest + case 0x1DD7: // ClientQuest + case 0x1DD8: // ClientQuest + case 0x1DE4: // ClientQuest + case 0x1DE5: // ClientQuest + case 0x1DE7: // ClientQuest + case 0x1F02: // ClientQuest + case 0x1F06: // ClientQuest + case 0x1F07: // ClientQuest + case 0x1F0C: // ClientSpell + case 0x1F12: // ClientQuest + case 0x1F13: // ClientQuest + case 0x1F16: // ClientQuest + case 0x1F17: // ClientQuest + case 0x1F18: // ClientQuest + case 0x1F1C: // ClientSpell + case 0x1F1F: // ClientSpell + case 0x1F24: // ClientQuest + case 0x1F25: // ClientQuest + case 0x1F27: // ClientQuest + case 0x1F2C: // ClientSpell + case 0x1F2F: // ClientSpell + case 0x1F3C: // ClientSpell + case 0x1F3F: // ClientSpell + case 0x1F40: // ClientSpell + case 0x1F44: // ClientQuest + case 0x1F48: // ClientQuest + case 0x1F51: // ClientQuest + case 0x1F55: // ClientQuest + case 0x1F57: // ClientQuest + case 0x1F61: // ClientQuest + case 0x1F63: // ClientQuest + case 0x1F64: // ClientQuest + case 0x1F65: // ClientQuest + case 0x1F67: // ClientQuest + case 0x1F85: // ClientQuest + case 0x1F86: // ClientQuest + case 0x1F87: // ClientQuest + case 0x1F90: // ClientSpell + case 0x1F92: // ClientQuest + case 0x1F94: // ClientQuest + case 0x1F96: // ClientQuest + case 0x1F97: // ClientQuest + case 0x1F9B: // ClientSpell + case 0x1F9F: // ClientSpell + case 0x1FA1: // ClientQuest + case 0x1FA2: // ClientQuest + case 0x1FA3: // ClientQuest + case 0x1FA4: // ClientQuest + case 0x1FA5: // ClientQuest + case 0x1FA7: // ClientQuest + case 0x1FC2: // ClientQuest + case 0x1FC6: // ClientQuest + case 0x1FC7: // ClientQuest + case 0x1FD2: // ClientQuest + case 0x1FD3: // ClientQuest + case 0x1FD6: // ClientQuest + case 0x1FD7: // ClientQuest + case 0x1FD8: // ClientQuest + case 0x1FE4: // ClientQuest + case 0x1FE5: // ClientQuest + case 0x1FE7: // ClientQuest + return true; + default: + return false; + } +} + WorldPackets::ServerPacket::ServerPacket(OpcodeServer opcode, size_t initialSize /*= 200*/) : Packet(WorldPacket(opcode, initialSize)) { + if (IsInstanceOnlyOpcode(opcode)) + _connectionIndex = CONNECTION_TYPE_INSTANCE; } diff --git a/src/server/game/Server/Packet.h b/src/server/game/Server/Packet.h index 66061166ede..1a2ba87f90a 100644 --- a/src/server/game/Server/Packet.h +++ b/src/server/game/Server/Packet.h @@ -25,7 +25,11 @@ namespace WorldPackets class Packet { public: - Packet(WorldPacket&& worldPacket) : _worldPacket(std::move(worldPacket)) { } + Packet(WorldPacket&& worldPacket) : _worldPacket(std::move(worldPacket)) + { + _connectionIndex = _worldPacket.GetConnection(); + } + virtual ~Packet() = default; Packet(Packet const& right) = delete; @@ -35,9 +39,11 @@ namespace WorldPackets virtual void Read() = 0; size_t GetSize() const { return _worldPacket.size(); } + ConnectionType GetConnection() const { return _connectionIndex; } protected: WorldPacket _worldPacket; + ConnectionType _connectionIndex; }; class ServerPacket : public Packet diff --git a/src/server/game/Server/Packets/AuctionHousePackets.cpp b/src/server/game/Server/Packets/AuctionHousePackets.cpp index 56fa0ed396b..bb1a10be254 100644 --- a/src/server/game/Server/Packets/AuctionHousePackets.cpp +++ b/src/server/game/Server/Packets/AuctionHousePackets.cpp @@ -19,10 +19,10 @@ #include "AuctionHouseMgr.h" #include "ObjectGuid.h" -WorldPackets::AuctionHousePackets::AuctionCommandResult::AuctionCommandResult() +WorldPackets::AuctionHouse::AuctionCommandResult::AuctionCommandResult() : ServerPacket(SMSG_AUCTION_COMMAND_RESULT, 4 + 4 + 4 + 8 + 4 + 8 + 8 + 8) { } -void WorldPackets::AuctionHousePackets::AuctionCommandResult::InitializeAuction(AuctionEntry* auction) +void WorldPackets::AuctionHouse::AuctionCommandResult::InitializeAuction(AuctionEntry* auction) { if (auction) { @@ -33,7 +33,7 @@ void WorldPackets::AuctionHousePackets::AuctionCommandResult::InitializeAuction( } } -WorldPacket const* WorldPackets::AuctionHousePackets::AuctionCommandResult::Write() +WorldPacket const* WorldPackets::AuctionHouse::AuctionCommandResult::Write() { _worldPacket << uint32(AuctionId); _worldPacket << uint32(Action); diff --git a/src/server/game/Server/Packets/AuctionHousePackets.h b/src/server/game/Server/Packets/AuctionHousePackets.h index bf392246a20..4204c5c6afc 100644 --- a/src/server/game/Server/Packets/AuctionHousePackets.h +++ b/src/server/game/Server/Packets/AuctionHousePackets.h @@ -20,13 +20,11 @@ #include "Packet.h" #include "ObjectGuid.h" -class ObjectGuid; - struct AuctionEntry; namespace WorldPackets { - namespace AuctionHousePackets + namespace AuctionHouse { class AuctionCommandResult final : public ServerPacket { @@ -54,4 +52,5 @@ namespace WorldPackets }; } } -#endif + +#endif // AuctionHousePackets_h__ diff --git a/src/server/game/Server/Packets/AuthenticationPackets.cpp b/src/server/game/Server/Packets/AuthenticationPackets.cpp index a57f5f60244..95f2379e82f 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.cpp +++ b/src/server/game/Server/Packets/AuthenticationPackets.cpp @@ -585,3 +585,10 @@ WorldPacket const* WorldPackets::Auth::ConnectTo::Write() _worldPacket << uint8(Con); return &_worldPacket; } + +void WorldPackets::Auth::AuthContinuedSession::Read() +{ + _worldPacket >> DosResponse; + _worldPacket >> Key; + _worldPacket.read(Digest, SHA_DIGEST_LENGTH); +} diff --git a/src/server/game/Server/Packets/AuthenticationPackets.h b/src/server/game/Server/Packets/AuthenticationPackets.h index 1d194b0b2a9..70aa38cac8e 100644 --- a/src/server/game/Server/Packets/AuthenticationPackets.h +++ b/src/server/game/Server/Packets/AuthenticationPackets.h @@ -168,6 +168,29 @@ namespace WorldPackets BigNumber dmq1; BigNumber iqmp; }; + + class AuthContinuedSession final : public ClientPacket + { + public: + AuthContinuedSession(WorldPacket&& packet) : ClientPacket(std::move(packet)) + { + memset(Digest, 0, SHA_DIGEST_LENGTH); + } + + void Read() override; + + uint64 DosResponse = 0; + uint64 Key = 0; + uint8 Digest[SHA_DIGEST_LENGTH]; + }; + + class ResumeComms final : public ServerPacket + { + public: + ResumeComms() : ServerPacket(SMSG_RESUME_COMMS, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; } } diff --git a/src/server/game/Server/Packets/BattlegroundPackets.cpp b/src/server/game/Server/Packets/BattlegroundPackets.cpp new file mode 100644 index 00000000000..8a1bec1173b --- /dev/null +++ b/src/server/game/Server/Packets/BattlegroundPackets.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2008-2014 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 "BattlegroundPackets.h" + +WorldPacket const* WorldPackets::Battleground::PVPSeason::Write() +{ + _worldPacket << uint32(CurrentSeason); + _worldPacket << uint32(PreviousSeason); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/BattlegroundPackets.h b/src/server/game/Server/Packets/BattlegroundPackets.h new file mode 100644 index 00000000000..77dc8238438 --- /dev/null +++ b/src/server/game/Server/Packets/BattlegroundPackets.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2008-2014 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/>. + */ + +#ifndef BattlegroundPackets_h__ +#define BattlegroundPackets_h__ + +#include "Packet.h" + +namespace WorldPackets +{ + namespace Battleground + { + class PVPSeason final : public ServerPacket + { + public: + PVPSeason() : ServerPacket(SMSG_PVP_SEASON, 8) { } + + WorldPacket const* Write() override; + + uint32 PreviousSeason = 0; + uint32 CurrentSeason = 0; + }; + } +} + +#endif // BattlegroundPackets_h__ diff --git a/src/server/game/Server/Packets/GuildPackets.cpp b/src/server/game/Server/Packets/GuildPackets.cpp index ee864b256bb..b94fb7839bf 100644 --- a/src/server/game/Server/Packets/GuildPackets.cpp +++ b/src/server/game/Server/Packets/GuildPackets.cpp @@ -16,7 +16,6 @@ */ #include "GuildPackets.h" -#include "ObjectGuid.h" WorldPackets::Guild::QueryGuildInfo::QueryGuildInfo(WorldPacket&& packet) : ClientPacket(std::move(packet)) diff --git a/src/server/game/Server/Packets/GuildPackets.h b/src/server/game/Server/Packets/GuildPackets.h index 17159a017e0..479ceba6280 100644 --- a/src/server/game/Server/Packets/GuildPackets.h +++ b/src/server/game/Server/Packets/GuildPackets.h @@ -19,8 +19,7 @@ #define GuildPackets_h__ #include "Packet.h" - -class ObjectGuid; +#include "ObjectGuid.h" namespace WorldPackets { diff --git a/src/server/game/Server/Packets/WorldStatePackets.cpp b/src/server/game/Server/Packets/WorldStatePackets.cpp new file mode 100644 index 00000000000..7d062841003 --- /dev/null +++ b/src/server/game/Server/Packets/WorldStatePackets.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2008-2014 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 "WorldStatePackets.h" + +WorldPackets::WorldState::InitWorldStates::InitWorldStates() + : ServerPacket(SMSG_INIT_WORLD_STATES, 16) { } + +WorldPacket const* WorldPackets::WorldState::InitWorldStates::Write() +{ + _worldPacket.reserve(16 + Worldstates.size() * 8); + + _worldPacket << uint32(AreaID); + _worldPacket << uint32(SubareaID); + _worldPacket << uint32(MapID); + + _worldPacket << uint32(Worldstates.size()); + for (WorldStateInfo const& wsi : Worldstates) + { + _worldPacket << uint32(wsi.VariableID); + _worldPacket << uint32(wsi.Value); + } + + return &_worldPacket; +} + +WorldPackets::WorldState::UpdateWorldState::UpdateWorldState() + : ServerPacket(SMSG_UPDATE_WORLD_STATE, 9) { } + +WorldPacket const* WorldPackets::WorldState::UpdateWorldState::Write() +{ + _worldPacket << uint32(VariableID); + _worldPacket << int32(Value); + _worldPacket.WriteBit(Hidden); + _worldPacket.FlushBits(); + + return &_worldPacket; +} diff --git a/src/server/game/Server/Packets/WorldStatePackets.h b/src/server/game/Server/Packets/WorldStatePackets.h new file mode 100644 index 00000000000..7f9cdfe80de --- /dev/null +++ b/src/server/game/Server/Packets/WorldStatePackets.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2008-2014 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/>. + */ + +#ifndef WorldStatePackets_h__ +#define WorldStatePackets_h__ + +#include "Packet.h" + +namespace WorldPackets +{ + namespace WorldState + { + class InitWorldStates final : public ServerPacket + { + public: + struct WorldStateInfo + { + WorldStateInfo(uint32 variableID, int32 value) + : VariableID(variableID), Value(value) { } + + uint32 VariableID; + int32 Value; + }; + + InitWorldStates(); + + WorldPacket const* Write() override; + + uint32 AreaID = 0; ///< ZoneId + uint32 SubareaID = 0; ///< AreaId + uint32 MapID = 0; ///< MapId + + std::list<WorldStateInfo> Worldstates; + }; + + class UpdateWorldState final : public ServerPacket + { + public: + UpdateWorldState(); + + WorldPacket const* Write() override; + + int32 Value = 0; + bool Hidden = false; ///< @todo: research + uint32 VariableID = 0; + }; + } +} + +#endif // WorldStatePackets_h__ diff --git a/src/server/game/Server/Protocol/Opcodes.cpp b/src/server/game/Server/Protocol/Opcodes.cpp index b22dc575c0c..97fc18a1c2f 100644 --- a/src/server/game/Server/Protocol/Opcodes.cpp +++ b/src/server/game/Server/Protocol/Opcodes.cpp @@ -130,6 +130,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_ARENA_TEAM_ROSTER, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleArenaTeamRosterOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_ATTACKSTOP, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleAttackStopOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_ATTACKSWING, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleAttackSwingOpcode ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_HELLO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionHelloOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_LIST_BIDDER_ITEMS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListBidderItems ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_LIST_ITEMS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListItems ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_LIST_OWNER_ITEMS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionListOwnerItems ); @@ -137,6 +138,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_PLACE_BID, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionPlaceBid ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_REMOVE_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionRemoveItem ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUCTION_SELL_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionSellItem ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTH_CONTINUED_SESSION, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTH_SESSION, STATUS_NEVER, PROCESS_THREADUNSAFE, &WorldSession::Handle_EarlyProccess ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOBANK_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoBankItemOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_AUTOEQUIP_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAutoEquipItemOpcode ); @@ -160,6 +162,8 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLEMASTER_JOIN_ARENA, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBattlemasterJoinArena ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLEMASTER_JOIN_RATED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLE_PAY_GET_PRODUCT_LIST_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLE_PAY_GET_PURCHASE_LIST_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_BATTLE_PET_NAME_QUERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BEGIN_TRADE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBeginTradeOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BINDER_ACTIVATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBinderActivateOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_BUG, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleBugOpcode ); @@ -497,13 +501,13 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_NPC_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestNPCQuery ); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_POI_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestPOIQuery ); DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEST_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleQuestQueryOpcode ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_QUEUED_MESSAGES_END, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_HANDLER(CMSG_RANDOMIZE_CHAR_NAME, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::GenerateRandomCharacterName, &WorldSession::HandleRandomizeCharNameOpcode); DEFINE_OPCODE_HANDLER_OLD(CMSG_READ_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleReadItem ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REALM_SPLIT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRealmSplitOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_RECLAIM_CORPSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleReclaimCorpseOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_REDIRECTION_AUTH_PROOF, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REFORGE_ITEM, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::HandleReforgeItemOpcode ); - DEFINE_HANDLER(CMSG_REORDER_CHARACTERS, STATUS_AUTHED, PROCESS_INPLACE, WorldPackets::Character::ReorderCharacters, &WorldSession::HandleReorderCharacters); + DEFINE_HANDLER(CMSG_REORDER_CHARACTERS, STATUS_AUTHED, PROCESS_THREADUNSAFE, WorldPackets::Character::ReorderCharacters, &WorldSession::HandleReorderCharacters); DEFINE_OPCODE_HANDLER_OLD(CMSG_REPAIR_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRepairItemOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REPOP_REQUEST, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleRepopRequestOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_REPORT_PVP_AFK, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleReportPvPAFK ); @@ -549,6 +553,7 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_FACTION_ATWAR, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetFactionAtWar ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_FACTION_INACTIVE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetFactionInactiveOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_GUILD_BANK_TEXT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetGuildBankTabText ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_LOOT_SPECIALIZATION, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PET_SLOT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PLAYER_DECLINED_NAMES, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSetPlayerDeclinedNames ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SET_PREFERED_CEMETERY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -576,7 +581,8 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_SUBMIT_COMPLAIN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SUGGESTION_SUBMIT, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SUMMON_RESPONSE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSummonResponseOpcode ); - DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_TOKEN, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_COMMS_ACK, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); + DEFINE_OPCODE_HANDLER_OLD(CMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SWAP_INV_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapInvItemOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SWAP_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleSwapItem ); DEFINE_OPCODE_HANDLER_OLD(CMSG_SYNC_DANCE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL ); @@ -622,9 +628,6 @@ void OpcodeTable::Initialize() DEFINE_OPCODE_HANDLER_OLD(CMSG_WORLD_TELEPORT, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleWorldTeleportOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_WRAP_ITEM, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleWrapItemOpcode ); DEFINE_OPCODE_HANDLER_OLD(CMSG_ZONEUPDATE, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleZoneUpdateOpcode ); - DEFINE_OPCODE_HANDLER_OLD(MSG_AUCTION_HELLO, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleAuctionHelloOpcode ); - DEFINE_OPCODE_HANDLER_OLD(MSG_CHANNEL_START, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); - DEFINE_OPCODE_HANDLER_OLD(MSG_CHANNEL_UPDATE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_ServerSide ); DEFINE_OPCODE_HANDLER_OLD(MSG_CORPSE_QUERY, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleCorpseQueryOpcode ); DEFINE_OPCODE_HANDLER_OLD(MSG_INSPECT_ARENA_TEAMS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleInspectArenaTeamsOpcode ); DEFINE_OPCODE_HANDLER_OLD(MSG_LIST_STABLED_PETS, STATUS_UNHANDLED, PROCESS_THREADUNSAFE, &WorldSession::HandleListStabledPetsOpcode ); @@ -679,6 +682,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_DATA_TIMES, STATUS_NEVER); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_INFO_RESPONSE, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_MOUNT_UPDATE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACCOUNT_RESTRICTED_WARNING, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_DELETED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ACHIEVEMENT_EARNED, STATUS_UNHANDLED); @@ -692,7 +696,6 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MESSAGE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AREA_TRIGGER_MOVEMENT_UPDATE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_ERROR, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_SEASON_WORLD_STATE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_UNIT_DESTROYED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_ARENA_TEAM_COMMAND_RESULT, STATUS_UNHANDLED); @@ -711,6 +714,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_LIST_RESULT, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_BIDDER_NOTIFICATION, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_COMMAND_RESULT, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_HELLO, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_LIST_PENDING_SALES, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_LIST_RESULT, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_AUCTION_OWNER_LIST_RESULT, STATUS_UNHANDLED); @@ -745,8 +749,12 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_INFO_THROTTLED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_JOINED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLEGROUND_PLAYER_LEFT, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_GET_DISTRIBUTION_LIST_RESPONSE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_GET_PRODUCT_LIST_RESPONSE, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PAY_GET_PURCHASE_LIST_RESPONSE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_JOURNAL_LOCK_ACQUIRED, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_BATTLE_PET_NAME_QUERY_RESPONSE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDER_CONFIRM, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDPOINTUPDATE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_BINDZONEREPLY, STATUS_UNHANDLED); @@ -782,6 +790,8 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_LIST, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_MEMBER_COUNT, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_NOTIFY, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_START, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHANNEL_UPDATE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHARACTER_LOGIN_FAILED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CREATE, STATUS_NEVER); DEFINE_SERVER_OPCODE_HANDLER(SMSG_CHAR_CUSTOMIZE, STATUS_UNHANDLED); @@ -834,6 +844,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_CUSTOM_LOAD_SCREEN, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DAMAGE_CALC_LOG, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DANCE_QUERY_RESPONSE, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_DANCE_STUDIO_CREATE_RESULT, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DB_REPLY, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DEATH_RELEASE_LOC, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_DEBUG_RUNE_REGEN, STATUS_UNHANDLED); @@ -877,7 +888,6 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCEACTIONSHOW, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCED_DEATH_UPDATE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_ANIM, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_SEND_QUEUED_PACKETS, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORCE_SET_VEHICLE_REC_ID, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FORGE_MASTER_SET, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_FRIEND_STATUS, STATUS_UNHANDLED); @@ -1166,6 +1176,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_CREDIT, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_LOG_DATA, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_OPTIONS_ENABLED, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_PVP_SEASON, STATUS_NEVER); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_QUESTS_COMPLETED_RESPONSE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUERY_TIME_RESPONSE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_QUESTGIVER_OFFER_REWARD, STATUS_UNHANDLED); @@ -1202,7 +1213,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_REALM_SPLIT, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REAL_GROUP_UPDATE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RECEIVED_MAIL, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_REDIRECT_CLIENT, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_REDIRECT_CLIENT, STATUS_NEVER); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_EXPIRED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFER_A_FRIEND_FAILURE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_REFORGE_RESULT, STATUS_UNHANDLED); @@ -1215,6 +1226,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_COMPRESSION_CONTEXT, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESET_FAILED_NOTIFY, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESUME_COMMS, STATUS_NEVER); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_FAILED, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESURRECT_REQUEST, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_RESYNC_RUNES, STATUS_UNHANDLED); @@ -1312,7 +1324,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPERCEDED_SPELL, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUPPRESS_NPC_GREETINGS, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_COMMS, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN_RESPONSE, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_SUSPEND_TOKEN, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_ERROR, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INFO, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_TALENTS_INVOLUNTARILY_RESET, STATUS_UNHANDLED); @@ -1353,7 +1365,7 @@ void OpcodeTable::Initialize() DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_LAST_INSTANCE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_OBJECT, STATUS_NEVER); DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_SERVER_PLAYER_POSITION, STATUS_UNHANDLED); - DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_WORLD_STATE, STATUS_UNHANDLED); + DEFINE_SERVER_OPCODE_HANDLER(SMSG_UPDATE_WORLD_STATE, STATUS_NEVER); DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_ADD, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_REMOVE, STATUS_UNHANDLED); DEFINE_SERVER_OPCODE_HANDLER(SMSG_USERLIST_UPDATE, STATUS_UNHANDLED); diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index d8ac4b68d9e..879554e8bd6 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -26,6 +26,12 @@ #include "Common.h" #include <iomanip> +enum ConnectionType +{ + CONNECTION_TYPE_REALM = 0, + CONNECTION_TYPE_INSTANCE = 1 +}; + enum OpcodeMisc : uint32 { MAX_OPCODE = 0x1FFF, @@ -70,6 +76,7 @@ enum OpcodeClient : uint32 CMSG_AUCTION_PLACE_BID = 0xBADD, CMSG_AUCTION_REMOVE_ITEM = 0xBADD, CMSG_AUCTION_SELL_ITEM = 0xBADD, + CMSG_AUTH_CONTINUED_SESSION = 0x0485, CMSG_AUTH_SESSION = 0x0487, CMSG_AUTOBANK_ITEM = 0xBADD, CMSG_AUTOEQUIP_GROUND_ITEM = 0xBADD, @@ -98,6 +105,8 @@ enum OpcodeClient : uint32 CMSG_BATTLEMASTER_JOIN_RATED = 0xBADD, CMSG_BATTLEMASTER_HELLO = 0xBADD, CMSG_BATTLE_PAY_GET_PRODUCT_LIST_QUERY = 0x1389, + CMSG_BATTLE_PAY_GET_PURCHASE_LIST_QUERY = 0x120C, + CMSG_BATTLE_PET_NAME_QUERY = 0x041C, CMSG_BEGIN_TRADE = 0xBADD, CMSG_BINDER_ACTIVATE = 0xBADD, CMSG_BOT_DETECTED2 = 0xBADD, @@ -123,7 +132,7 @@ enum OpcodeClient : uint32 CMSG_CALENDAR_GUILD_FILTER = 0xBADD, CMSG_CALENDAR_REMOVE_EVENT = 0xBADD, CMSG_CALENDAR_UPDATE_EVENT = 0xBADD, - CMSG_CANCEL_AURA = 0xBADD, + CMSG_CANCEL_AURA = 0x08AE, CMSG_CANCEL_AUTO_REPEAT_SPELL = 0xBADD, CMSG_CANCEL_CAST = 0xBADD, CMSG_CANCEL_CHANNELLING = 0xBADD, @@ -207,7 +216,7 @@ enum OpcodeClient : uint32 CMSG_EQUIPMENT_SET_USE = 0xBADD, CMSG_FACTION_BONUS_INFO = 0x0928, CMSG_FAR_SIGHT = 0xBADD, - CMSG_FORCE_MOVE_ROOT_ACK = 0xBADD, + CMSG_FORCE_MOVE_ROOT_ACK = 0x0B73, CMSG_FORCE_MOVE_UNROOT_ACK = 0xBADD, CMSG_GAMEOBJECT_QUERY = 0x03AE, CMSG_GAMEOBJ_REPORT_USE = 0x082E, @@ -378,7 +387,7 @@ enum OpcodeClient : uint32 CMSG_MOVE_FORCE_SWIM_SPEED_CHANGE_ACK = 0xBADD, CMSG_MOVE_FORCE_TURN_RATE_CHANGE_ACK = 0xBADD, CMSG_MOVE_FORCE_WALK_SPEED_CHANGE_ACK = 0xBADD, - CMSG_MOVE_GRAVITY_DISABLE_ACK = 0xBADD, + CMSG_MOVE_GRAVITY_DISABLE_ACK = 0x0553, CMSG_MOVE_GRAVITY_ENABLE_ACK = 0xBADD, CMSG_MOVE_HEARTBEAT = 0x19C1, CMSG_MOVE_HOVER_ACK = 0xBADD, @@ -389,7 +398,7 @@ enum OpcodeClient : uint32 CMSG_MOVE_SET_CAN_FLY = 0xBADD, CMSG_MOVE_SET_CAN_FLY_ACK = 0xBADD, CMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY_ACK = 0xBADD, - CMSG_MOVE_SET_COLLISION_HEIGHT_ACK = 0xBADD, + CMSG_MOVE_SET_COLLISION_HEIGHT_ACK = 0x0141, CMSG_MOVE_SET_RELATIVE_POSITION = 0xBADD, CMSG_MOVE_SET_VEHICLE_REC_ID_ACK = 0xBADD, CMSG_MOVE_SPLINE_DONE = 0xBADD, @@ -462,11 +471,11 @@ enum OpcodeClient : uint32 CMSG_QUEST_NPC_QUERY = 0x0B81, CMSG_QUEST_POI_QUERY = 0x0BD9, CMSG_QUEST_QUERY = 0x09A6, + CMSG_QUEUED_MESSAGES_END = 0x04DF, CMSG_RANDOMIZE_CHAR_NAME = 0x1981, CMSG_READ_ITEM = 0xBADD, CMSG_REALM_SPLIT = 0xBADD, CMSG_RECLAIM_CORPSE = 0xBADD, - CMSG_REDIRECTION_AUTH_PROOF = 0x0485, CMSG_REFORGE_ITEM = 0xBADD, CMSG_REORDER_CHARACTERS = 0x0DAA, CMSG_REPAIR_ITEM = 0xBADD, @@ -490,7 +499,7 @@ enum OpcodeClient : uint32 CMSG_REQUEST_VEHICLE_NEXT_SEAT = 0xBADD, CMSG_REQUEST_VEHICLE_PREV_SEAT = 0xBADD, CMSG_REQUEST_VEHICLE_SWITCH_SEAT = 0xBADD, - CMSG_RESET_FACTION_CHEAT = 0x0C56, + CMSG_RESET_FACTION_CHEAT = 0xBADD, CMSG_RESET_INSTANCES = 0xBADD, CMSG_RESURRECT_RESPONSE = 0xBADD, CMSG_RETURN_TO_GRAVEYARD = 0xBADD, @@ -522,10 +531,11 @@ enum OpcodeClient : uint32 CMSG_SET_FACTION_INACTIVE = 0xBADD, CMSG_SET_GUILD_BANK_TEXT = 0xBADD, CMSG_SET_LFG_COMMENT = 0xBADD, + CMSG_SET_LOOT_SPECIALIZATION = 0x0226, CMSG_SET_PET_SLOT = 0xBADD, CMSG_SET_PLAYER_DECLINED_NAMES = 0xBADD, CMSG_SET_PREFERED_CEMETERY = 0xBADD, - CMSG_SET_RAID_DIFFICULTY = 0x04DF, + CMSG_SET_RAID_DIFFICULTY = 0xBADD, CMSG_SET_RELATIVE_POSITION = 0xBADD, CMSG_SET_SAVED_INSTANCE_EXTEND = 0xBADD, CMSG_SET_SELECTION = 0x05BD, @@ -541,7 +551,7 @@ enum OpcodeClient : uint32 CMSG_SHOWING_CLOAK = 0x0132, CMSG_SHOWING_HELM = 0x11E1, CMSG_SOCKET_GEMS = 0xBADD, - CMSG_SPELLCLICK = 0xBADD, + CMSG_SPELLCLICK = 0x0BC2, CMSG_SPIRIT_HEALER_ACTIVATE = 0xBADD, CMSG_SPLIT_ITEM = 0xBADD, CMSG_STANDSTATECHANGE = 0xBADD, @@ -552,7 +562,8 @@ enum OpcodeClient : uint32 CMSG_SUBMIT_COMPLAIN = 0xBADD, CMSG_SUGGESTION_SUBMIT = 0xBADD, CMSG_SUMMON_RESPONSE = 0xBADD, - CMSG_SUSPEND_TOKEN = 0x0142, + CMSG_SUSPEND_COMMS_ACK = 0x0C56, + CMSG_SUSPEND_TOKEN_RESPONSE = 0x0142, CMSG_SWAP_INV_ITEM = 0xBADD, CMSG_SWAP_ITEM = 0xBADD, CMSG_SYNC_DANCE = 0xBADD, @@ -570,7 +581,7 @@ enum OpcodeClient : uint32 CMSG_TOTEM_DESTROYED = 0xBADD, CMSG_TRAINER_BUY_SPELL = 0xBADD, CMSG_TRAINER_LIST = 0xBADD, - CMSG_TRANSMOGRIFY_ITEMS = 0xBADD, + CMSG_TRANSMOGRIFY_ITEMS = 0x0A85, CMSG_TRIGGER_CINEMATIC_CHEAT = 0xBADD, CMSG_TURN_IN_PETITION = 0xBADD, CMSG_TUTORIAL_CLEAR = 0xBADD, @@ -590,9 +601,9 @@ enum OpcodeClient : uint32 CMSG_VIOLENCE_LEVEL = 0x098D, CMSG_VOICE_SESSION_ENABLE = 0xBADD, CMSG_VOID_STORAGE_QUERY = 0x019E, - CMSG_VOID_STORAGE_TRANSFER = 0xBADD, + CMSG_VOID_STORAGE_TRANSFER = 0x0463, CMSG_VOID_STORAGE_UNLOCK = 0xBADD, - CMSG_VOID_SWAP_ITEM = 0xBADD, + CMSG_VOID_SWAP_ITEM = 0x0619, CMSG_WARDEN_DATA = 0x0BA1, CMSG_WARGAME_ACCEPT = 0xBADD, CMSG_WARGAME_START = 0xBADD, @@ -602,9 +613,6 @@ enum OpcodeClient : uint32 CMSG_WORLD_TELEPORT = 0xBADD, CMSG_WRAP_ITEM = 0xBADD, CMSG_ZONEUPDATE = 0xBADD, - MSG_AUCTION_HELLO = 0xBADD, - MSG_CHANNEL_START = 0xBADD, // SMSG only? - MSG_CHANNEL_UPDATE = 0xBADD, // SMSG only? MSG_CORPSE_QUERY = 0xBADD, MSG_GM_BIND_OTHER = 0xBADD, MSG_GM_SHOWLABEL = 0xBADD, @@ -674,6 +682,7 @@ enum OpcodeServer : uint32 { SMSG_ACCOUNT_DATA_TIMES = 0x0120, SMSG_ACCOUNT_INFO_RESPONSE = 0xBADD, + SMSG_ACCOUNT_MOUNT_UPDATE = 0x0140, SMSG_ACCOUNT_RESTRICTED_WARNING = 0xBADD, SMSG_ACHIEVEMENT_DELETED = 0xBADD, SMSG_ACHIEVEMENT_EARNED = 0xBADD, @@ -681,7 +690,7 @@ enum OpcodeServer : uint32 SMSG_ACTIVATETAXIREPLY = 0xBADD, SMSG_ADDON_INFO = 0x1D9F, SMSG_ADD_RUNE_POWER = 0xBADD, - SMSG_AI_REACTION = 0xBADD, + SMSG_AI_REACTION = 0x0BA1, SMSG_ALL_ACHIEVEMENT_DATA = 0xBADD, SMSG_ALL_ACHIEVEMENT_DATA_ACCOUNT = 0x0123, SMSG_ALL_ACHIEVEMENT_DATA_PLAYER = 0x0030, @@ -689,7 +698,6 @@ enum OpcodeServer : uint32 SMSG_AREA_TRIGGER_MESSAGE = 0xBADD, SMSG_AREA_TRIGGER_MOVEMENT_UPDATE = 0xBADD, SMSG_ARENA_ERROR = 0xBADD, - SMSG_ARENA_SEASON_WORLD_STATE = 0x09E3, SMSG_ARENA_UNIT_DESTROYED = 0xBADD, SMSG_ARENA_TEAM_CHANGE_FAILED_QUEUED = 0xBADD, SMSG_ARENA_TEAM_COMMAND_RESULT = 0xBADD, @@ -734,7 +742,7 @@ enum OpcodeServer : uint32 SMSG_BATTLEFIELD_MGR_STATE_CHANGE = 0xBADD, SMSG_BATTLEFIELD_PLAYER_POSITIONS = 0xBADD, SMSG_BATTLEFIELD_PORT_DENIED = 0xBADD, - SMSG_BATTLEFIELD_RATED_INFO = 0xBADD, + SMSG_BATTLEFIELD_RATED_INFO = 0x1F0A, SMSG_BATTLEFIELD_STATUS = 0xBADD, SMSG_BATTLEFIELD_STATUS_QUEUED = 0xBADD, SMSG_BATTLEFIELD_STATUS_ACTIVE = 0xBADD, @@ -744,8 +752,12 @@ enum OpcodeServer : uint32 SMSG_BATTLEGROUND_INFO_THROTTLED = 0xBADD, SMSG_BATTLEGROUND_PLAYER_JOINED = 0xBADD, SMSG_BATTLEGROUND_PLAYER_LEFT = 0xBADD, + SMSG_BATTLE_PAY_GET_DISTRIBUTION_LIST_RESPONSE = 0x0F2A, SMSG_BATTLE_PAY_GET_PRODUCT_LIST_RESPONSE = 0x12A4, + SMSG_BATTLE_PAY_GET_PURCHASE_LIST_RESPONSE = 0x168A, SMSG_BATTLE_PET_JOURNAL = 0x19A2, + SMSG_BATTLE_PET_JOURNAL_LOCK_ACQUIRED = 0x01A3, + SMSG_BATTLE_PET_NAME_QUERY_RESPONSE = 0x09EC, SMSG_BINDER_CONFIRM = 0xBADD, SMSG_BINDPOINTUPDATE = 0x0A30, SMSG_BINDZONEREPLY = 0xBADD, @@ -784,6 +796,8 @@ enum OpcodeServer : uint32 SMSG_CHANNEL_MEMBER_COUNT = 0xBADD, SMSG_CHANNEL_NOTIFY = 0x0643, SMSG_CHANNEL_NOTIFY_JOINED = 0x1602, + SMSG_CHANNEL_START = 0x016C, + SMSG_CHANNEL_UPDATE = 0x19DB, SMSG_CHARACTER_LOGIN_FAILED = 0xBADD, SMSG_CHAR_CREATE = 0x0107, SMSG_CHAR_CUSTOMIZE = 0xBADD, @@ -842,6 +856,7 @@ enum OpcodeServer : uint32 SMSG_DAMAGE_CALC_LOG = 0xBADD, SMSG_DAMAGE_DONE_OBSOLETE = 0xBADD, SMSG_DANCE_QUERY_RESPONSE = 0xBADD, + SMSG_DANCE_STUDIO_CREATE_RESULT = 0x178D, SMSG_DB_REPLY = 0x1939, SMSG_DEATH_RELEASE_LOC = 0xBADD, SMSG_DEBUG_RUNE_REGEN = 0xBADD, @@ -887,7 +902,6 @@ enum OpcodeServer : uint32 SMSG_FORCED_DEATH_UPDATE = 0xBADD, SMSG_FORCE_ANIM = 0xBADD, SMSG_FORCE_DISPLAY_UPDATE = 0xBADD, - SMSG_FORCE_SEND_QUEUED_PACKETS = 0xBADD, SMSG_FORCE_SET_VEHICLE_REC_ID = 0xBADD, SMSG_FORGE_MASTER_SET = 0xBADD, SMSG_FRIEND_STATUS = 0xBADD, @@ -931,7 +945,7 @@ enum OpcodeServer : uint32 SMSG_GUILD_ACHIEVEMENT_MEMBERS = 0xBADD, SMSG_GUILD_BANK_LIST = 0xBADD, SMSG_GUILD_BANK_LOG_QUERY_RESULT = 0xBADD, - SMSG_GUILD_BANK_MONEY_WITHDRAWN = 0xBADD, + SMSG_GUILD_BANK_MONEY_WITHDRAWN = 0x1047, SMSG_GUILD_BANK_QUERY_TEXT_RESULT = 0xBADD, SMSG_GUILD_CANCEL = 0xBADD, SMSG_GUILD_CHALLENGE_COMPLETED = 0xBADD, @@ -960,7 +974,7 @@ enum OpcodeServer : uint32 SMSG_GUILD_NEWS_DELETED = 0xBADD, SMSG_GUILD_NEWS_UPDATE = 0xBADD, SMSG_GUILD_PARTY_STATE_RESPONSE = 0x1225, - SMSG_GUILD_PERMISSIONS_QUERY_RESULTS = 0xBADD, + SMSG_GUILD_PERMISSIONS_QUERY_RESULTS = 0x1827, SMSG_GUILD_QUERY_RESPONSE = 0x1046, SMSG_GUILD_RANK = 0x1218, SMSG_GUILD_RANKS_UPDATE = 0xBADD, @@ -1086,16 +1100,16 @@ enum OpcodeServer : uint32 SMSG_MOVE_COLLISION_DISABLE = 0xBADD, SMSG_MOVE_COLLISION_ENABLE = 0xBADD, SMSG_MOVE_FEATHER_FALL = 0xBADD, - SMSG_MOVE_GRAVITY_DISABLE = 0xBADD, + SMSG_MOVE_GRAVITY_DISABLE = 0x02C6, SMSG_MOVE_GRAVITY_ENABLE = 0xBADD, SMSG_MOVE_KNOCK_BACK = 0xBADD, SMSG_MOVE_LAND_WALK = 0xBADD, SMSG_MOVE_NORMAL_FALL = 0xBADD, - SMSG_MOVE_ROOT = 0xBADD, + SMSG_MOVE_ROOT = 0x1B5A, SMSG_MOVE_SET_ACTIVE_MOVER = 0xBADD, SMSG_MOVE_SET_CAN_FLY = 0xBADD, SMSG_MOVE_SET_CAN_TRANSITION_BETWEEN_SWIM_AND_FLY = 0xBADD, - SMSG_MOVE_SET_COLLISION_HEIGHT = 0xBADD, + SMSG_MOVE_SET_COLLISION_HEIGHT = 0x008D, SMSG_MOVE_SET_COMPOUND_STATE = 0xBADD, SMSG_MOVE_SET_FLIGHT_BACK_SPEED = 0xBADD, SMSG_MOVE_SET_FLIGHT_SPEED = 0xBADD, @@ -1123,7 +1137,7 @@ enum OpcodeServer : uint32 SMSG_MOVE_UPDATE_RUN_SPEED = 0xBADD, SMSG_MOVE_UPDATE_SWIM_BACK_SPEED = 0xBADD, SMSG_MOVE_UPDATE_SWIM_SPEED = 0xBADD, - SMSG_MOVE_UPDATE_TELEPORT = 0xBADD, + SMSG_MOVE_UPDATE_TELEPORT = 0x03D5, SMSG_MOVE_UPDATE_TURN_RATE = 0xBADD, SMSG_MOVE_UPDATE_WALK_SPEED = 0xBADD, SMSG_MOVE_WATER_WALK = 0xBADD, @@ -1139,7 +1153,7 @@ enum OpcodeServer : uint32 SMSG_NPC_TEXT_UPDATE = 0x1122, SMSG_NPC_WONT_TALK = 0xBADD, SMSG_OFFER_PETITION_ERROR = 0xBADD, - SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA = 0xBADD, + SMSG_ON_CANCEL_EXPECTED_RIDE_VEHICLE_AURA = 0x053F, SMSG_OPEN_CONTAINER = 0xBADD, SMSG_OPEN_LFG_DUNGEON_FINDER = 0xBADD, SMSG_OVERRIDE_LIGHT = 0xBADD, @@ -1184,7 +1198,7 @@ enum OpcodeServer : uint32 SMSG_PLAY_MUSIC = 0xBADD, SMSG_PLAY_OBJECT_SOUND = 0xBADD, SMSG_PLAY_ONE_SHOT_ANIM_KIT = 0xBADD, - SMSG_PLAY_SOUND = 0xBADD, + SMSG_PLAY_SOUND = 0x02D2, SMSG_PLAY_SPELL_VISUAL = 0xBADD, SMSG_PLAY_SPELL_VISUAL_KIT = 0xBADD, SMSG_PLAY_TIME_WARNING = 0xBADD, @@ -1197,8 +1211,9 @@ enum OpcodeServer : uint32 SMSG_PVP_CREDIT = 0xBADD, SMSG_PVP_LOG_DATA = 0xBADD, SMSG_PVP_OPTIONS_ENABLED = 0xBADD, + SMSG_PVP_SEASON = 0x09E3, SMSG_QUERY_QUESTS_COMPLETED_RESPONSE = 0xBADD, - SMSG_QUERY_TIME_RESPONSE = 0xBADD, + SMSG_QUERY_TIME_RESPONSE = 0x1DB0, SMSG_QUESTGIVER_OFFER_REWARD = 0xBADD, SMSG_QUESTGIVER_QUEST_COMPLETE = 0xBADD, SMSG_QUESTGIVER_QUEST_DETAILS = 0x15B3, @@ -1248,6 +1263,7 @@ enum OpcodeServer : uint32 SMSG_RESET_FAILED_NOTIFY = 0xBADD, SMSG_RESISTLOG = 0xBADD, SMSG_RESPOND_INSPECT_ACHIEVEMENTS = 0xBADD, + SMSG_RESUME_COMMS = 0x07C9, SMSG_RESURRECT_FAILED = 0xBADD, SMSG_RESURRECT_REQUEST = 0xBADD, SMSG_RESYNC_RUNES = 0xBADD, @@ -1268,13 +1284,13 @@ enum OpcodeServer : uint32 SMSG_SET_FACTION_STANDING = 0xBADD, SMSG_SET_FACTION_VISIBLE = 0xBADD, SMSG_SET_FLAT_SPELL_MODIFIER = 0x1884, - SMSG_SET_FORCED_REACTIONS = 0xBADD, + SMSG_SET_FORCED_REACTIONS = 0x09A9, SMSG_SET_MELEE_ANIM_KIT = 0xBADD, SMSG_SET_MOVEMENT_ANIM_KIT = 0xBADD, SMSG_SET_PCT_SPELL_MODIFIER = 0x113C, SMSG_SET_PHASE_SHIFT = 0x00D1, SMSG_SET_PLAYER_DECLINED_NAMES_RESULT = 0xBADD, - SMSG_SET_PLAY_HOVER_ANIM = 0xBADD, + SMSG_SET_PLAY_HOVER_ANIM = 0x02D4, SMSG_SET_PROFICIENCY = 0x00D3, SMSG_SET_PROJECTILE_POSITION = 0xBADD, SMSG_SET_TIME_ZONE_INFORMATION = 0x153E, @@ -1304,11 +1320,11 @@ enum OpcodeServer : uint32 SMSG_SPELL_FAILURE = 0xBADD, SMSG_SPELL_GO = 0x1161, SMSG_SPELL_START = 0x0803, - SMSG_SPELL_UPDATE_CHAIN_TARGETS = 0xBADD, + SMSG_SPELL_UPDATE_CHAIN_TARGETS = 0x0374, SMSG_SPIRIT_HEALER_CONFIRM = 0xBADD, SMSG_SPLINE_MOVE_COLLISION_DISABLE = 0xBADD, SMSG_SPLINE_MOVE_COLLISION_ENABLE = 0xBADD, - SMSG_SPLINE_MOVE_GRAVITY_DISABLE = 0xBADD, + SMSG_SPLINE_MOVE_GRAVITY_DISABLE = 0x03B2, SMSG_SPLINE_MOVE_GRAVITY_ENABLE = 0xBADD, SMSG_SPLINE_MOVE_ROOT = 0xBADD, SMSG_SPLINE_MOVE_SET_ANIM = 0xBADD, @@ -1333,10 +1349,10 @@ enum OpcodeServer : uint32 SMSG_SPLINE_MOVE_STOP_SWIM = 0xBADD, SMSG_SPLINE_MOVE_UNROOT = 0xBADD, SMSG_SPLINE_MOVE_UNSET_FLYING = 0xBADD, - SMSG_SPLINE_MOVE_UNSET_HOVER = 0xBADD, + SMSG_SPLINE_MOVE_UNSET_HOVER = 0x1959, SMSG_SPLINE_MOVE_WATER_WALK = 0xBADD, SMSG_STABLE_RESULT = 0xBADD, - SMSG_STANDSTATE_UPDATE = 0xBADD, + SMSG_STANDSTATE_UPDATE = 0x1311, SMSG_START_MIRROR_TIMER = 0xBADD, SMSG_START_TIMER = 0xBADD, SMSG_STOP_DANCE = 0xBADD, @@ -1347,7 +1363,7 @@ enum OpcodeServer : uint32 SMSG_SUPERCEDED_SPELL = 0xBADD, SMSG_SUPPRESS_NPC_GREETINGS = 0xBADD, SMSG_SUSPEND_COMMS = 0x076A, - SMSG_SUSPEND_TOKEN_RESPONSE = 0x12A2, + SMSG_SUSPEND_TOKEN = 0x12A2, SMSG_TALENTS_ERROR = 0xBADD, SMSG_TALENTS_INFO = 0x012D, SMSG_TALENTS_INVOLUNTARILY_RESET = 0xBADD, @@ -1398,11 +1414,11 @@ enum OpcodeServer : uint32 SMSG_VOICE_SESSION_LEAVE = 0xBADD, SMSG_VOICE_SESSION_ROSTER_UPDATE = 0xBADD, SMSG_VOICE_SET_TALKER_MUTED = 0xBADD, - SMSG_VOID_ITEM_SWAP_RESPONSE = 0xBADD, + SMSG_VOID_ITEM_SWAP_RESPONSE = 0x1131, SMSG_VOID_STORAGE_CONTENTS = 0x0108, SMSG_VOID_STORAGE_FAILED = 0xBADD, - SMSG_VOID_STORAGE_TRANSFER_CHANGES = 0xBADD, - SMSG_VOID_TRANSFER_RESULT = 0xBADD, + SMSG_VOID_STORAGE_TRANSFER_CHANGES = 0x0321, + SMSG_VOID_TRANSFER_RESULT = 0x0539, SMSG_WAIT_QUEUE_FINISH = 0xBADD, SMSG_WAIT_QUEUE_UPDATE = 0xBADD, SMSG_WARDEN_DATA = 0x0BEC, diff --git a/src/server/game/Server/WorldPacket.h b/src/server/game/Server/WorldPacket.h index e7d6d4fb5b1..65b2f6fcae1 100644 --- a/src/server/game/Server/WorldPacket.h +++ b/src/server/game/Server/WorldPacket.h @@ -27,17 +27,18 @@ class WorldPacket : public ByteBuffer { public: // just container for later use - WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE) + WorldPacket() : ByteBuffer(0), m_opcode(UNKNOWN_OPCODE), _connection(CONNECTION_TYPE_REALM) { } - explicit WorldPacket(uint32 opcode, size_t res = 200) : ByteBuffer(res), m_opcode(opcode) { } + WorldPacket(uint32 opcode, size_t res = 200, ConnectionType connection = CONNECTION_TYPE_REALM) : ByteBuffer(res), + m_opcode(opcode), _connection(connection) { } - WorldPacket(WorldPacket&& packet) : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode) + WorldPacket(WorldPacket&& packet) : ByteBuffer(std::move(packet)), m_opcode(packet.m_opcode), _connection(packet._connection) { } - WorldPacket(WorldPacket const& right) : ByteBuffer(right), m_opcode(right.m_opcode) + WorldPacket(WorldPacket const& right) : ByteBuffer(right), m_opcode(right.m_opcode), _connection(right._connection) { } @@ -46,26 +47,31 @@ class WorldPacket : public ByteBuffer if (this != &right) { m_opcode = right.m_opcode; + _connection = right._connection; ByteBuffer::operator =(right); } return *this; } - WorldPacket(uint32 opcode, MessageBuffer&& buffer) : ByteBuffer(std::move(buffer)), m_opcode(opcode) { } + WorldPacket(uint32 opcode, MessageBuffer&& buffer, ConnectionType connection) : ByteBuffer(std::move(buffer)), m_opcode(opcode), _connection(connection) { } - void Initialize(uint32 opcode, size_t newres = 200) + void Initialize(uint32 opcode, size_t newres = 200, ConnectionType connection = CONNECTION_TYPE_REALM) { clear(); _storage.reserve(newres); m_opcode = opcode; + _connection = connection; } uint32 GetOpcode() const { return m_opcode; } void SetOpcode(uint32 opcode) { m_opcode = opcode; } + ConnectionType GetConnection() const { return _connection; } + protected: uint32 m_opcode; + ConnectionType _connection; }; #endif diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 0164ad9a575..f427b91787a 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -106,7 +106,6 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr AntiDOS(this), m_GUIDLow(UI64LIT(0)), _player(NULL), - m_Socket(sock), _security(sec), _accountId(id), _battlenetAccountId(battlenetAccountId), @@ -114,7 +113,6 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr _warden(NULL), _logoutTime(0), m_inQueue(false), - m_playerLoading(false), m_playerLogout(false), m_playerRecentlyLogout(false), m_playerSave(false), @@ -140,17 +138,9 @@ WorldSession::WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = %u;", GetAccountId()); // One-time query } - InitializeQueryCallbackParameters(); + m_Socket[0] = sock; - _compressionStream = new z_stream(); - _compressionStream->zalloc = (alloc_func)NULL; - _compressionStream->zfree = (free_func)NULL; - _compressionStream->opaque = (voidpf)NULL; - _compressionStream->avail_in = 0; - _compressionStream->next_in = NULL; - int32 z_res = deflateInit2(_compressionStream, sWorld->getIntConfig(CONFIG_COMPRESSION), Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); - if (z_res != Z_OK) - TC_LOG_ERROR("network", "Can't initialize packet compression (zlib: deflateInit) Error code: %i (%s)", z_res, zError(z_res)); + InitializeQueryCallbackParameters(); } /// WorldSession destructor @@ -161,10 +151,13 @@ WorldSession::~WorldSession() LogoutPlayer (true); /// - If have unclosed socket, close it - if (m_Socket) + for (uint8 i = 0; i < 2; ++i) { - m_Socket->CloseSocket(); - m_Socket = nullptr; + if (m_Socket[i]) + { + m_Socket[i]->CloseSocket(); + m_Socket[i].reset(); + } } delete _warden; @@ -176,12 +169,6 @@ WorldSession::~WorldSession() delete packet; LoginDatabase.PExecute("UPDATE account SET online = 0 WHERE id = %u;", GetAccountId()); // One-time query - - int32 z_res = deflateEnd(_compressionStream); - if (z_res != Z_OK && z_res != Z_DATA_ERROR) // Z_DATA_ERROR signals that internal state was BUSY - TC_LOG_ERROR("network", "Can't close packet compression stream (zlib: deflateEnd) Error code: %i (%s)", z_res, zError(z_res)); - - delete _compressionStream; } std::string const & WorldSession::GetPlayerName() const @@ -205,7 +192,7 @@ std::string WorldSession::GetPlayerInfo() const /// Send a packet to the client void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/) { - if (!m_Socket) + if (!m_Socket[packet->GetConnection()]) return; if (packet->GetOpcode() == NULL_OPCODE) @@ -265,38 +252,7 @@ void WorldSession::SendPacket(WorldPacket const* packet, bool forced /*= false*/ sScriptMgr->OnPacketSend(this, *packet); - m_Socket->SendPacket(*packet); -} - -uint32 WorldSession::CompressPacket(uint8* buffer, WorldPacket const& packet) -{ - uint32 opcode = packet.GetOpcode(); - uint32 bufferSize = deflateBound(_compressionStream, packet.size() + sizeof(opcode)); - - _compressionStream->next_out = buffer; - _compressionStream->avail_out = bufferSize; - _compressionStream->next_in = (Bytef*)&opcode; - _compressionStream->avail_in = sizeof(uint32); - - int32 z_res = deflate(_compressionStream, Z_BLOCK); - if (z_res != Z_OK) - { - TC_LOG_ERROR("network", "Can't compress packet opcode (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); - return 0; - } - - _compressionStream->next_in = (Bytef*)packet.contents(); - _compressionStream->avail_in = packet.size(); - - z_res = deflate(_compressionStream, Z_SYNC_FLUSH); - if (z_res != Z_OK) - { - TC_LOG_ERROR("network", "Can't compress packet data (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); - return 0; - } - - - return bufferSize - _compressionStream->avail_out; + m_Socket[packet->GetConnection()]->SendPacket(*packet); } /// Add an incoming packet to the queue @@ -332,7 +288,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) ///- Before we process anything: /// If necessary, kick the player from the character select screen if (IsConnectionIdle()) - m_Socket->CloseSocket(); + m_Socket[0]->CloseSocket(); ///- Retrieve packets from the receive queue and call the appropriate handlers /// not process packets if socket already closed @@ -349,7 +305,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) uint32 processedPackets = 0; time_t currentTime = time(NULL); - while (m_Socket && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) + while (m_Socket[0] && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { if (!AntiDOS.EvaluateOpcode(*packet, currentTime)) KickPlayer(); @@ -458,7 +414,7 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) break; } - if (m_Socket && m_Socket->IsOpen() && _warden) + if (m_Socket[0] && m_Socket[0]->IsOpen() && _warden) _warden->Update(); ProcessQueryCallbacks(); @@ -469,23 +425,24 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) { time_t currTime = time(NULL); ///- If necessary, log the player out - if (ShouldLogOut(currTime) && !m_playerLoading) + if (ShouldLogOut(currTime) && m_playerLoading.IsEmpty()) LogoutPlayer(true); - if (m_Socket && GetPlayer() && _warden) + if (m_Socket[0] && GetPlayer() && _warden) _warden->Update(); ///- Cleanup socket pointer if need - if (m_Socket && !m_Socket->IsOpen()) + if ((m_Socket[0] && !m_Socket[0]->IsOpen()) || (m_Socket[1] && !m_Socket[1]->IsOpen())) { expireTime -= expireTime > diff ? diff : expireTime; if (expireTime < diff || forceExit || !GetPlayer()) { - m_Socket = nullptr; + m_Socket[0].reset(); + m_Socket[1].reset(); } } - if (!m_Socket) + if (!m_Socket[0]) return false; //Will remove this session from the world session map } @@ -587,7 +544,7 @@ void WorldSession::LogoutPlayer(bool save) // remove player from the group if he is: // a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) - if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket) + if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && m_Socket[0]) _player->RemoveFromGroup(); //! Send update to group and reset stored max enchanting level @@ -640,10 +597,13 @@ void WorldSession::LogoutPlayer(bool save) /// Kick a player out of the World void WorldSession::KickPlayer() { - if (m_Socket) + for (uint8 i = 0; i < 2; ++i) { - m_Socket->CloseSocket(); - forceExit = true; + if (m_Socket[i]) + { + m_Socket[i]->CloseSocket(); + forceExit = true; + } } } diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index c77ad210ebc..83a746c8f44 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -54,7 +54,6 @@ struct DeclinedName; struct ItemTemplate; struct MovementInfo; struct TradeStatusInfo; -struct z_stream_s; namespace lfg { @@ -228,7 +227,7 @@ class WorldSession WorldSession(uint32 id, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); ~WorldSession(); - bool PlayerLoading() const { return m_playerLoading; } + bool PlayerLoading() const { return !m_playerLoading.IsEmpty(); } bool PlayerLogout() const { return m_playerLogout; } bool PlayerLogoutWithSave() const { return m_playerLogout && m_playerSave; } bool PlayerRecentlyLoggedOut() const { return m_playerRecentlyLogout; } @@ -238,7 +237,7 @@ class WorldSession bool IsAddonRegistered(const std::string& prefix) const; void SendPacket(WorldPacket const* packet, bool forced = false); - uint32 CompressPacket(uint8* buffer, WorldPacket const& packet); + void AddInstanceConnection(std::shared_ptr<WorldSocket> sock) { m_Socket[1] = sock; } void SendNotification(const char *format, ...) ATTR_PRINTF(2, 3); void SendNotification(uint32 string_id, ...); @@ -424,8 +423,6 @@ class WorldSession uint32 GetRecruiterId() const { return recruiterId; } bool IsARecruiter() const { return isRecruiter; } - z_stream_s* GetCompressionStream() { return _compressionStream; } - public: // opcodes handlers void Handle_NULL(WorldPacket& recvPacket); // not used @@ -441,6 +438,7 @@ class WorldSession void HandleCharCreateOpcode(WorldPackets::Character::CharacterCreate& charCreate); void HandleCharCreateCallback(PreparedQueryResult result, WorldPackets::Character::CharacterCreateInfo* createInfo); void HandlePlayerLoginOpcode(WorldPackets::Character::PlayerLogin& playerLogin); + void HandleContinuePlayerLogin(); void HandleLoadScreenOpcode(WorldPacket& recvPacket); void HandlePlayerLogin(LoginQueryHolder * holder); void HandleCharRenameOpcode(WorldPacket& recvData); @@ -1091,7 +1089,7 @@ class WorldSession ObjectGuid::LowType m_GUIDLow; // set logined or recently logout player (while m_playerRecentlyLogout set) Player* _player; - std::shared_ptr<WorldSocket> m_Socket; + std::shared_ptr<WorldSocket> m_Socket[2]; std::string m_Address; // Current Remote Address // std::string m_LAddress; // Last Attempted Remote Adress - we can not set attempted ip for a non-existing session! @@ -1107,7 +1105,7 @@ class WorldSession time_t _logoutTime; bool m_inQueue; // session wait in auth.queue - bool m_playerLoading; // code processed in LoginPlayer + ObjectGuid m_playerLoading; // code processed in LoginPlayer bool m_playerLogout; // code processed in LogoutPlayer bool m_playerRecentlyLogout; bool m_playerSave; @@ -1124,7 +1122,6 @@ class WorldSession uint32 recruiterId; bool isRecruiter; LockedQueue<WorldPacket*> _recvQueue; - z_stream_s* _compressionStream; rbac::RBACData* _RBACData; uint32 expireTime; bool forceExit; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 23bd9a65f88..9cdb05ac79b 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -25,6 +25,7 @@ #include "SHA1.h" #include "PacketLog.h" #include "BattlenetAccountMgr.h" +#include "World.h" #include <zlib.h> #include <memory> @@ -53,12 +54,22 @@ uint32 const SizeOfClientHeader[2][2] = uint32 const SizeOfServerHeader[2] = { sizeof(uint16) + sizeof(uint32), sizeof(uint32) }; -WorldSocket::WorldSocket(tcp::socket&& socket) - : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _initialized(false) +WorldSocket::WorldSocket(tcp::socket&& socket) : Socket(std::move(socket)), + _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), + _initialized(false), _type(CONNECTION_TYPE_REALM) { _headerBuffer.Resize(SizeOfClientHeader[0][0]); } +WorldSocket::~WorldSocket() +{ + if (_compressionStream) + { + deflateEnd(_compressionStream); + delete _compressionStream; + } +} + void WorldSocket::Start() { AsyncRead(); @@ -75,15 +86,13 @@ void WorldSocket::Start() void WorldSocket::HandleSendAuthSession() { - BigNumber seed1; - BigNumber seed2; - seed1.SetRand(16 * 8); - seed2.SetRand(16 * 8); + _encryptSeed.SetRand(16 * 8); + _decryptSeed.SetRand(16 * 8); WorldPackets::Auth::AuthChallenge challenge; challenge.Challenge = _authSeed; - memcpy(&challenge.DosChallenge[0], seed1.AsByteArray(16).get(), 16); - memcpy(&challenge.DosChallenge[4], seed2.AsByteArray(16).get(), 16); + memcpy(&challenge.DosChallenge[0], _encryptSeed.AsByteArray(16).get(), 16); + memcpy(&challenge.DosChallenge[4], _decryptSeed.AsByteArray(16).get(), 16); challenge.DosZeroBits = 1; SendPacket(*challenge.Write()); @@ -204,7 +213,7 @@ bool WorldSocket::ReadDataHandler() std::string opcodeName = GetOpcodeNameForLogging(opcode); - WorldPacket packet(opcode, std::move(_packetBuffer)); + WorldPacket packet(opcode, std::move(_packetBuffer), GetConnectionType()); if (sPacketLog->CanLogPacket()) sPacketLog->LogPacket(packet, CLIENT_TO_SERVER, GetRemoteIpAddress(), GetRemotePort()); @@ -217,15 +226,32 @@ bool WorldSocket::ReadDataHandler() HandlePing(packet); break; case CMSG_AUTH_SESSION: + { if (_worldSession) { TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_SESSION from %s", _worldSession->GetPlayerInfo().c_str()); break; } - HandleAuthSession(packet); + WorldPackets::Auth::AuthSession authSession(std::move(packet)); + authSession.Read(); + HandleAuthSession(authSession); + break; + } + case CMSG_AUTH_CONTINUED_SESSION: + { + if (_worldSession) + { + TC_LOG_ERROR("network", "WorldSocket::ProcessIncoming: received duplicate CMSG_AUTH_CONTINUED_SESSION from %s", _worldSession->GetPlayerInfo().c_str()); + break; + } + + WorldPackets::Auth::AuthContinuedSession authSession(std::move(packet)); + authSession.Read(); + HandleAuthContinuedSession(authSession); break; - /* + } + /* case CMSG_KEEP_ALIVE: TC_LOG_DEBUG("network", "%s", opcodeName.c_str()); sScriptMgr->OnPacketReceive(_worldSession, packet); @@ -286,6 +312,20 @@ bool WorldSocket::ReadDataHandler() return false; } + _compressionStream = new z_stream(); + _compressionStream->zalloc = (alloc_func)NULL; + _compressionStream->zfree = (free_func)NULL; + _compressionStream->opaque = (voidpf)NULL; + _compressionStream->avail_in = 0; + _compressionStream->next_in = NULL; + int32 z_res = deflateInit2(_compressionStream, sWorld->getIntConfig(CONFIG_COMPRESSION), Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + if (z_res != Z_OK) + { + TC_LOG_ERROR("network", "Can't initialize packet compression (zlib: deflateInit) Error code: %i (%s)", z_res, zError(z_res)); + CloseSocket(); + return false; + } + _initialized = true; _headerBuffer.Resize(SizeOfClientHeader[1][0]); _packetBuffer.Reset(); @@ -295,6 +335,35 @@ bool WorldSocket::ReadDataHandler() return true; } +void WorldSocket::SendPacket(WorldPacket const& packet) +{ + if (!IsOpen()) + return; + + if (sPacketLog->CanLogPacket()) + sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort()); + + TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())).c_str()); + + uint32 packetSize = packet.size(); + uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()]; + if (packetSize > 0x400) + packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket); + + std::unique_lock<std::mutex> guard(_writeLock); + +#ifndef TC_SOCKET_USE_IOCP + if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= sizeOfHeader + packetSize) + WritePacketToBuffer(packet, _writeBuffer); + else +#endif + { + MessageBuffer buffer(sizeOfHeader + packetSize); + WritePacketToBuffer(packet, buffer); + QueuePacket(std::move(buffer), guard); + } +} + void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer) { ServerPktHeader header; @@ -306,7 +375,7 @@ void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& uint8* headerPos = buffer.GetWritePointer(); buffer.WriteCompleted(sizeOfHeader); - if (packetSize > 0x400 && _worldSession) + if (packetSize > 0x400) { CompressedWorldPacket cmp; cmp.UncompressedSize = packetSize + 4; @@ -316,7 +385,7 @@ void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& uint8* compressionInfo = buffer.GetWritePointer(); buffer.WriteCompleted(sizeof(CompressedWorldPacket)); - uint32 compressedSize = _worldSession->CompressPacket(buffer.GetWritePointer(), packet); + uint32 compressedSize = CompressPacket(buffer.GetWritePointer(), packet); cmp.CompressedAdler = adler32(0x9827D8F1, buffer.GetWritePointer(), compressedSize); @@ -344,40 +413,39 @@ void WorldSocket::WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& memcpy(headerPos, &header, sizeOfHeader); } -void WorldSocket::SendPacket(WorldPacket const& packet) +uint32 WorldSocket::CompressPacket(uint8* buffer, WorldPacket const& packet) { - if (!IsOpen()) - return; - - if (sPacketLog->CanLogPacket()) - sPacketLog->LogPacket(packet, SERVER_TO_CLIENT, GetRemoteIpAddress(), GetRemotePort()); + uint32 opcode = packet.GetOpcode(); + uint32 bufferSize = deflateBound(_compressionStream, packet.size() + sizeof(opcode)); - TC_LOG_TRACE("network.opcode", "S->C: %s %s", (_worldSession ? _worldSession->GetPlayerInfo() : GetRemoteIpAddress().to_string()).c_str(), GetOpcodeNameForLogging(static_cast<OpcodeServer>(packet.GetOpcode())).c_str()); + _compressionStream->next_out = buffer; + _compressionStream->avail_out = bufferSize; + _compressionStream->next_in = (Bytef*)&opcode; + _compressionStream->avail_in = sizeof(uint32); - uint32 packetSize = packet.size(); - uint32 sizeOfHeader = SizeOfServerHeader[_authCrypt.IsInitialized()]; - if (packetSize > 0x400 && _worldSession) - packetSize = compressBound(packetSize) + sizeof(CompressedWorldPacket); + int32 z_res = deflate(_compressionStream, Z_BLOCK); + if (z_res != Z_OK) + { + TC_LOG_ERROR("network", "Can't compress packet opcode (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); + return 0; + } - std::unique_lock<std::mutex> guard(_writeLock); + _compressionStream->next_in = (Bytef*)packet.contents(); + _compressionStream->avail_in = packet.size(); -#ifndef TC_SOCKET_USE_IOCP - if (_writeQueue.empty() && _writeBuffer.GetRemainingSpace() >= sizeOfHeader + packetSize) - WritePacketToBuffer(packet, _writeBuffer); - else -#endif + z_res = deflate(_compressionStream, Z_SYNC_FLUSH); + if (z_res != Z_OK) { - MessageBuffer buffer(sizeOfHeader + packetSize); - WritePacketToBuffer(packet, buffer); - QueuePacket(std::move(buffer), guard); + TC_LOG_ERROR("network", "Can't compress packet data (zlib: deflate) Error code: %i (%s, msg: %s)", z_res, zError(z_res), _compressionStream->msg); + return 0; } + + + return bufferSize - _compressionStream->avail_out; } -void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) +void WorldSocket::HandleAuthSession(WorldPackets::Auth::AuthSession& authSession) { - WorldPackets::Auth::AuthSession authSession(std::move(recvPacket)); - authSession.Read(); - uint8 security; uint32 id; LocaleConstant locale; @@ -598,6 +666,56 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) sWorld->AddSession(_worldSession); } +void WorldSocket::HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSession& authSession) +{ + uint32 accountId = PAIR64_LOPART(authSession.Key); + _type = ConnectionType(PAIR64_HIPART(authSession.Key)); + QueryResult result = LoginDatabase.PQuery("SELECT username, sessionkey FROM account WHERE id = %u", accountId); + if (!result) + { + SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); + DelayedCloseSocket(); + return; + } + + Field* fields = result->Fetch(); + std::string login = fields[0].GetString(); + BigNumber k; + k.SetHexStr(fields[1].GetCString()); + + _authCrypt.Init(&k, _encryptSeed.AsByteArray().get(), _decryptSeed.AsByteArray().get()); + _headerBuffer.Resize(SizeOfClientHeader[1][1]); + + SHA1Hash sha; + sha.UpdateData(login); + sha.UpdateBigNumbers(&k, NULL); + sha.UpdateData((uint8*)&_authSeed, 4); + sha.Finalize(); + + if (memcmp(sha.GetDigest(), authSession.Digest, sha.GetLength())) + { + SendAuthResponseError(AUTH_UNKNOWN_ACCOUNT); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthContinuedSession: Authentication failed for account: %u ('%s') address: %s", accountId, login.c_str(), GetRemoteIpAddress().to_string().c_str()); + DelayedCloseSocket(); + return; + } + + _worldSession = sWorld->FindSession(accountId); + if (!_worldSession) + { + SendAuthResponseError(AUTH_SESSION_EXPIRED); + TC_LOG_ERROR("network", "WorldSocket::HandleAuthContinuedSession: No active session found for account: %u ('%s') address: %s", accountId, login.c_str(), GetRemoteIpAddress().to_string().c_str()); + DelayedCloseSocket(); + return; + } + + WorldPackets::Auth::ResumeComms resumeComms; + SendPacket(*resumeComms.Write()); + + _worldSession->AddInstanceConnection(shared_from_this()); + _worldSession->HandleContinuePlayerLogin(); +} + void WorldSocket::SendAuthResponseError(uint8 code) { WorldPackets::Auth::AuthResponse response; diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index e0dad0a43a1..16769c68c33 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -31,10 +31,16 @@ #include <boost/asio/buffer.hpp> using boost::asio::ip::tcp; +struct z_stream_s; namespace WorldPackets { class ServerPacket; + namespace Auth + { + class AuthSession; + class AuthContinuedSession; + } } #pragma pack(push, 1) @@ -67,6 +73,7 @@ class WorldSocket : public Socket<WorldSocket> public: WorldSocket(tcp::socket&& socket); + ~WorldSocket(); WorldSocket(WorldSocket const& right) = delete; WorldSocket& operator=(WorldSocket const& right) = delete; @@ -74,7 +81,8 @@ public: void Start() override; void SendPacket(WorldPacket const& packet); - void WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer); + + ConnectionType GetConnectionType() const { return _type; } protected: void ReadHandler() override; @@ -82,16 +90,24 @@ protected: bool ReadDataHandler(); private: + void WritePacketToBuffer(WorldPacket const& packet, MessageBuffer& buffer); + uint32 CompressPacket(uint8* buffer, WorldPacket const& packet); + void HandleSendAuthSession(); - void HandleAuthSession(WorldPacket& recvPacket); + void HandleAuthSession(WorldPackets::Auth::AuthSession& authSession); + void HandleAuthContinuedSession(WorldPackets::Auth::AuthContinuedSession& authSession); void SendAuthResponseError(uint8 code); void HandlePing(WorldPacket& recvPacket); void ExtractOpcodeAndSize(ClientPktHeader const* header, uint32& opcode, uint32& size) const; + ConnectionType _type; + uint32 _authSeed; WorldPacketCrypt _authCrypt; + BigNumber _encryptSeed; + BigNumber _decryptSeed; std::chrono::steady_clock::time_point _LastPingTime; uint32 _OverSpeedPings; @@ -101,6 +117,8 @@ private: MessageBuffer _headerBuffer; MessageBuffer _packetBuffer; + z_stream_s* _compressionStream; + bool _initialized; }; diff --git a/src/server/game/Server/WorldSocketMgr.cpp b/src/server/game/Server/WorldSocketMgr.cpp index 21f62fa265c..5fcd308f376 100644 --- a/src/server/game/Server/WorldSocketMgr.cpp +++ b/src/server/game/Server/WorldSocketMgr.cpp @@ -46,6 +46,11 @@ WorldSocketMgr::WorldSocketMgr() : BaseSocketMgr(), _socketSendBufferSize(-1), m { } +WorldSocketMgr::~WorldSocketMgr() +{ + delete _instanceAcceptor; +} + bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string const& bindIp, uint16 port) { _tcpNoDelay = sConfigMgr->GetBoolDefault("Network.TcpNodelay", true); @@ -64,8 +69,10 @@ bool WorldSocketMgr::StartNetwork(boost::asio::io_service& service, std::string } BaseSocketMgr::StartNetwork(service, bindIp, port); + _instanceAcceptor = new AsyncAcceptor(service, bindIp, uint16(sWorld->getIntConfig(CONFIG_PORT_INSTANCE))); _acceptor->AsyncAcceptManaged(&OnSocketAccept); + _instanceAcceptor->AsyncAcceptManaged(&OnSocketAccept); sScriptMgr->OnNetworkStart(); return true; diff --git a/src/server/game/Server/WorldSocketMgr.h b/src/server/game/Server/WorldSocketMgr.h index 92a28d0c135..389818b2f9b 100644 --- a/src/server/game/Server/WorldSocketMgr.h +++ b/src/server/game/Server/WorldSocketMgr.h @@ -35,6 +35,8 @@ class WorldSocketMgr : public SocketMgr<WorldSocket> typedef SocketMgr<WorldSocket> BaseSocketMgr; public: + ~WorldSocketMgr(); + static WorldSocketMgr& Instance() { static WorldSocketMgr instance; @@ -55,6 +57,7 @@ protected: NetworkThread<WorldSocket>* CreateThreads() const override; private: + AsyncAcceptor* _instanceAcceptor; int32 _socketSendBufferSize; int32 m_SockOutUBuff; bool _tcpNoDelay; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 659e7ad46ef..2dc6aa3f7a7 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4207,7 +4207,7 @@ void Spell::SendChannelUpdate(uint32 time) m_caster->SetUInt32Value(UNIT_CHANNEL_SPELL, 0); } - WorldPacket data(MSG_CHANNEL_UPDATE, 8+4); + WorldPacket data(SMSG_CHANNEL_UPDATE, 8+4); data << m_caster->GetPackGUID(); data << uint32(time); @@ -4221,7 +4221,7 @@ void Spell::SendChannelStart(uint32 duration) if (m_UniqueTargetInfo.size() + m_UniqueGOTargetInfo.size() == 1) // this is for TARGET_SELECT_CATEGORY_NEARBY channelTarget = !m_UniqueTargetInfo.empty() ? m_UniqueTargetInfo.front().targetGUID : m_UniqueGOTargetInfo.front().targetGUID; - WorldPacket data(MSG_CHANNEL_START, (8+4+4)); + WorldPacket data(SMSG_CHANNEL_START, (8+4+4)); data << m_caster->GetPackGUID(); data << uint32(m_spellInfo->Id); data << uint32(duration); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 4900b655766..8bc360abf4d 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -650,9 +650,16 @@ void World::LoadConfigSettings(bool reload) uint32 val = sConfigMgr->GetIntDefault("WorldServerPort", 8085); if (val != m_int_configs[CONFIG_PORT_WORLD]) TC_LOG_ERROR("server.loading", "WorldServerPort option can't be changed at worldserver.conf reload, using current value (%u).", m_int_configs[CONFIG_PORT_WORLD]); + + val = sConfigMgr->GetIntDefault("InstanceServerPort", 8086); + if (val != m_int_configs[CONFIG_PORT_INSTANCE]) + TC_LOG_ERROR("server.loading", "InstanceServerPort option can't be changed at worldserver.conf reload, using current value (%u).", m_int_configs[CONFIG_PORT_INSTANCE]); } else + { m_int_configs[CONFIG_PORT_WORLD] = sConfigMgr->GetIntDefault("WorldServerPort", 8085); + m_int_configs[CONFIG_PORT_INSTANCE] = sConfigMgr->GetIntDefault("InstanceServerPort", 8086); + } m_int_configs[CONFIG_SOCKET_TIMEOUTTIME] = sConfigMgr->GetIntDefault("SocketTimeOutTime", 900000); m_int_configs[CONFIG_SESSION_ADD_DELAY] = sConfigMgr->GetIntDefault("SessionAddDelay", 10000); @@ -1079,11 +1086,11 @@ void World::LoadConfigSettings(bool reload) m_int_configs[CONFIG_ARENA_RATED_UPDATE_TIMER] = sConfigMgr->GetIntDefault ("Arena.RatedUpdateTimer", 5 * IN_MILLISECONDS); m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_ENABLE] = sConfigMgr->GetBoolDefault("Arena.QueueAnnouncer.Enable", false); m_bool_configs[CONFIG_ARENA_QUEUE_ANNOUNCER_PLAYERONLY] = sConfigMgr->GetBoolDefault("Arena.QueueAnnouncer.PlayerOnly", false); - m_int_configs[CONFIG_ARENA_SEASON_ID] = sConfigMgr->GetIntDefault ("Arena.ArenaSeason.ID", 1); + m_int_configs[CONFIG_ARENA_SEASON_ID] = sConfigMgr->GetIntDefault ("Arena.ArenaSeason.ID", 15); m_int_configs[CONFIG_ARENA_START_RATING] = sConfigMgr->GetIntDefault ("Arena.ArenaStartRating", 0); m_int_configs[CONFIG_ARENA_START_PERSONAL_RATING] = sConfigMgr->GetIntDefault ("Arena.ArenaStartPersonalRating", 1000); m_int_configs[CONFIG_ARENA_START_MATCHMAKER_RATING] = sConfigMgr->GetIntDefault ("Arena.ArenaStartMatchmakerRating", 1500); - m_bool_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfigMgr->GetBoolDefault("Arena.ArenaSeason.InProgress", true); + m_bool_configs[CONFIG_ARENA_SEASON_IN_PROGRESS] = sConfigMgr->GetBoolDefault("Arena.ArenaSeason.InProgress", false); m_bool_configs[CONFIG_ARENA_LOG_EXTENDED_INFO] = sConfigMgr->GetBoolDefault("ArenaLog.ExtendedInfo", false); m_bool_configs[CONFIG_OFFHAND_CHECK_AT_SPELL_UNLEARN] = sConfigMgr->GetBoolDefault("OffhandCheckAtSpellUnlearn", true); @@ -2209,7 +2216,7 @@ void World::ForceGameEventUpdate() } /// Send a packet to all players (except self if mentioned) -void World::SendGlobalMessage(WorldPacket* packet, WorldSession* self, uint32 team) +void World::SendGlobalMessage(WorldPacket const* packet, WorldSession* self, uint32 team) { SessionMap::const_iterator itr; for (itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) @@ -2226,7 +2233,7 @@ void World::SendGlobalMessage(WorldPacket* packet, WorldSession* self, uint32 te } /// Send a packet to all GMs (except self if mentioned) -void World::SendGlobalGMMessage(WorldPacket* packet, WorldSession* self, uint32 team) +void World::SendGlobalGMMessage(WorldPacket const* packet, WorldSession* self, uint32 team) { for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) { @@ -2354,7 +2361,7 @@ void World::SendGlobalText(const char* text, WorldSession* self) } /// Send a packet to all players (or players selected team) in the zone (except self if mentioned) -bool World::SendZoneMessage(uint32 zone, WorldPacket* packet, WorldSession* self, uint32 team) +bool World::SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self, uint32 team) { bool foundPlayerToSend = false; SessionMap::const_iterator itr; diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 3c3e40cc76b..7bf8f5b70e7 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -30,6 +30,7 @@ #include "SharedDefines.h" #include "QueryResult.h" #include "Callback.h" +#include "Realm/Realm.h" #include <atomic> #include <map> @@ -204,6 +205,7 @@ enum WorldIntConfigs CONFIG_INTERVAL_CHANGEWEATHER, CONFIG_INTERVAL_DISCONNECT_TOLERANCE, CONFIG_PORT_WORLD, + CONFIG_PORT_INSTANCE, CONFIG_SOCKET_TIMEOUTTIME, CONFIG_SESSION_ADD_DELAY, CONFIG_GAME_TYPE, @@ -660,9 +662,9 @@ class World void SendGlobalText(const char* text, WorldSession* self); void SendGMText(uint32 string_id, ...); void SendServerMessage(ServerMessageType type, const char *text = "", Player* player = NULL); - void SendGlobalMessage(WorldPacket* packet, WorldSession* self = nullptr, uint32 team = 0); - void SendGlobalGMMessage(WorldPacket* packet, WorldSession* self = nullptr, uint32 team = 0); - bool SendZoneMessage(uint32 zone, WorldPacket* packet, WorldSession* self = nullptr, uint32 team = 0); + void SendGlobalMessage(WorldPacket const* packet, WorldSession* self = nullptr, uint32 team = 0); + void SendGlobalGMMessage(WorldPacket const* packet, WorldSession* self = nullptr, uint32 team = 0); + bool SendZoneMessage(uint32 zone, WorldPacket const* packet, WorldSession* self = nullptr, uint32 team = 0); void SendZoneText(uint32 zone, const char *text, WorldSession* self = nullptr, uint32 team = 0); /// Are we in the middle of a shutdown? @@ -887,6 +889,7 @@ class World }; extern Battlenet::RealmHandle realmHandle; +extern Realm realm; uint32 GetVirtualRealmAddress(); #define sWorld World::instance() diff --git a/src/server/scripts/Maelstrom/CMakeLists.txt b/src/server/scripts/Maelstrom/CMakeLists.txt index 79f0789fd3f..8d3f1ee1c69 100644 --- a/src/server/scripts/Maelstrom/CMakeLists.txt +++ b/src/server/scripts/Maelstrom/CMakeLists.txt @@ -9,6 +9,13 @@ set(scripts_STAT_SRCS ${scripts_STAT_SRCS} Maelstrom/kezan.cpp + Maelstrom/Stonecore/instance_stonecore.cpp + Maelstrom/Stonecore/stonecore.cpp + Maelstrom/Stonecore/stonecore.h + Maelstrom/Stonecore/boss_corborus.cpp + Maelstrom/Stonecore/boss_slabhide.cpp + Maelstrom/Stonecore/boss_ozruk.cpp + Maelstrom/Stonecore/boss_high_priestess_azil.cpp ) message(" -> Prepared: The Maelstrom") diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp new file mode 100644 index 00000000000..2d522928fce --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/boss_corborus.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2008-2014 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "CreatureGroups.h" +#include "stonecore.h" + +// TO-DO: +// Find heroic sniffs and script spawning Crystal Shards on heroic mode. + +enum Spells +{ + // Corborus intro + SPELL_TWILIGHT_DOCUMENTS = 93167, + SPELL_RING_WYRM_CHARGE = 81237, + SPELL_DOOR_BREAK = 81232, // cast by World Trigger 22515 + + // Corborus boss + SPELL_DAMPENING_WAVE = 82415, + SPELL_CRYSTAL_BARRAGE = 86881, // 81638 triggers 81637 +// SPELL_CRYSTAL_BARRAGE_SHARD = 92012, // heroic only, summons Crystal Shard (TO-DO!) + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_SUBMERGE = 81629, + SPELL_TRASHING_CHARGE_TELEPORT = 81839, // triggers 81864 +// SPELL_TRASHING_CHARGE_TELEPORT_2= 81838, // dummy, targets all players, threat update packet follows + SPELL_SUMMON_TRASHING_CHARGE = 81816, + SPELL_TRASHING_CHARGE_VISUAL = 81801, // cast time 3.5 sec + SPELL_TRASHING_CHARGE_EFFECT = 81828, // 40 yard radius + SPELL_EMERGE = 81948, + + // Rock Borer npc (43917) + SPELL_ROCK_BORER_EMERGE = 82185, + SPELL_ROCK_BORE = 80028, +}; + +enum NPCs +{ + NPC_TRASHING_CHARGE = 43743, +// NPC_CRYSTAL_SHARD = 49267, // 49473 +}; + +enum Events +{ + EVENT_NONE, + + // Corborus intro + EVENT_CORBORUS_CHARGE, + EVENT_CORBORUS_KNOCKBACK, + EVENT_CORBORUS_FACEPLAYERS, + + // Corborus boss + EVENT_DAMPENING_WAVE, + EVENT_CRYSTAL_BARRAGE, + EVENT_SUBMERGE, + EVENT_TELEPORT, + EVENT_TRASHING_CHARGE, + EVENT_SUMMON_BEETLE, + EVENT_EMERGE, + EVENT_ATTACK, + + // Rock Borer + EVENT_EMERGED, + EVENT_ROCK_BORE, +}; + +class boss_corborus : public CreatureScript +{ + public: + boss_corborus() : CreatureScript("boss_corborus") { } + + struct boss_corborusAI : public BossAI + { + boss_corborusAI(Creature* creature) : BossAI(creature, DATA_CORBORUS) + { + stateIntro = NOT_STARTED; + } + + void Reset() override + { + _Reset(); + countTrashingCharge = 0; + events.ScheduleEvent(EVENT_DAMPENING_WAVE, 10000); + events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 15000); + events.ScheduleEvent(EVENT_SUBMERGE, 36000); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_CORBORUS_INTRO: // Executes Corborus intro event + { + if (stateIntro != NOT_STARTED) + return; + + stateIntro = IN_PROGRESS; + + if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM))) + { + Millhouse->InterruptNonMeleeSpells(true); + Millhouse->RemoveAllAuras(); + Millhouse->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN); + } + + events.ScheduleEvent(EVENT_CORBORUS_CHARGE, 1000); + break; + } + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && stateIntro != IN_PROGRESS) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_CORBORUS_CHARGE: + // Face Millhouse and other mobs + instance->SetData(DATA_MILLHOUSE_EVENT_FACE, 0); + + // Open rock gate and cast visual from nearby worldtrigger + instance->HandleGameObject(instance->GetGuidData(GAMEOBJECT_CORBORUS_ROCKDOOR), true); + if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 60.0f)) + worldtrigger->CastSpell(worldtrigger, SPELL_DOOR_BREAK, true); + + // Make Corborus charge + me->CastSpell(me, SPELL_RING_WYRM_CHARGE, true); + + events.ScheduleEvent(EVENT_CORBORUS_KNOCKBACK, 1000); + break; + case EVENT_CORBORUS_KNOCKBACK: + // Spawn Twilight Documents (quest gameobject) + if (Creature* Millhouse = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_MILLHOUSE_MANASTORM))) + Millhouse->CastSpell(Millhouse, SPELL_TWILIGHT_DOCUMENTS, true); + + // Knockback Millhouse and other mobs + instance->SetData(DATA_MILLHOUSE_EVENT_KNOCKBACK, 0); + + events.ScheduleEvent(EVENT_CORBORUS_FACEPLAYERS, 2000); + break; + case EVENT_CORBORUS_FACEPLAYERS: + // Face Corborus to players and set new home position + me->SetFacingTo(3.176499f); + me->SetHomePosition(1154.55f, 878.843f, 284.963f, 3.176499f); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IMMUNE_TO_PC); + + // Despawn Millhouse and all trash + instance->SetData(DATA_MILLHOUSE_EVENT_DESPAWN, 0); + + stateIntro = DONE; + break; + case EVENT_DAMPENING_WAVE: + DoCastVictim(SPELL_DAMPENING_WAVE); + events.ScheduleEvent(EVENT_DAMPENING_WAVE, 15000); + break; + case EVENT_CRYSTAL_BARRAGE: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_CRYSTAL_BARRAGE); + events.ScheduleEvent(EVENT_CRYSTAL_BARRAGE, 10000); + break; + case EVENT_SUBMERGE: + events.RescheduleEvent(EVENT_DAMPENING_WAVE, 35000); + events.RescheduleEvent(EVENT_CRYSTAL_BARRAGE, 30000); + events.RescheduleEvent(EVENT_SUBMERGE, 100000); + + me->SetReactState(REACT_PASSIVE); + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + me->AttackStop(); + + DoCast(me, SPELL_SUBMERGE); + + countTrashingCharge = 0; + events.ScheduleEvent(EVENT_TELEPORT, 500); + break; + case EVENT_TELEPORT: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_TRASHING_CHARGE_TELEPORT); + countTrashingCharge += 1; + if (countTrashingCharge <= 4) + events.ScheduleEvent(EVENT_TRASHING_CHARGE, 1000); + else + events.ScheduleEvent(EVENT_EMERGE, 2500); + break; + case EVENT_TRASHING_CHARGE: + DoCast(me, SPELL_SUMMON_TRASHING_CHARGE); + DoCast(me, SPELL_TRASHING_CHARGE_VISUAL); + events.ScheduleEvent(EVENT_TELEPORT, 5000); + break; + case EVENT_EMERGE: + me->RemoveAllAuras(); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + DoCast(me, SPELL_EMERGE); + events.ScheduleEvent(EVENT_ATTACK, 2500); + break; + case EVENT_ATTACK: + me->SetReactState(REACT_AGGRESSIVE); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_TRASHING_CHARGE) + return; + + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_TRASHING_CHARGE_EFFECT); + summon->DespawnOrUnsummon(6000); + } + + private: + EncounterState stateIntro; + uint32 countTrashingCharge; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_corborusAI>(creature); + } +}; + +// 43391 - Rock Borer +class npc_rock_borer : public CreatureScript +{ + public: + npc_rock_borer() : CreatureScript("npc_rock_borer") { } + + struct npc_rock_borerAI : public ScriptedAI + { + npc_rock_borerAI(Creature* creature) : ScriptedAI(creature) + { + me->SetDisableGravity(true); + me->SetReactState(REACT_PASSIVE); + events.ScheduleEvent(EVENT_EMERGED, 1200); + events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer + } + + void IsSummonedBy(Unit* summoner) override + { + me->SetInCombatState(false, summoner); + DoCast(SPELL_ROCK_BORER_EMERGE); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim() && me->GetReactState() != REACT_PASSIVE) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_EMERGED: + me->RemoveAurasDueToSpell(SPELL_ROCK_BORER_EMERGE); + me->SetReactState(REACT_AGGRESSIVE); + break; + case EVENT_ROCK_BORE: + DoCast(SPELL_ROCK_BORE); + events.ScheduleEvent(EVENT_ROCK_BORE, urand(15000, 20000)); // Need sniffs for this timer + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_rock_borerAI>(creature); + } +}; + +void AddSC_boss_corborus() +{ + new boss_corborus(); + new npc_rock_borer(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp new file mode 100644 index 00000000000..477d3baf206 --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/boss_high_priestess_azil.cpp @@ -0,0 +1,808 @@ +/* + * Copyright (C) 2008-2014 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "Player.h" +#include "Vehicle.h" +#include "stonecore.h" + +enum Spells +{ + SPELL_ENERGY_SHIELD = 82858, + + SPELL_CURSE_OF_BLOOD = 79345, + SPELL_FORCE_GRIP = 79351, + SPELL_SUMMON_GRAVITY_WELL = 79340, + SPELL_EARTH_FURY_ENERGY_SHIELD = 79050, + + // Gravity Well + SPELL_GRAVITY_WELL_VISUAL = 79245, + SPELL_GRAVITY_WELL_AURA_DAMAGE = 79244, + SPELL_GRAVITY_WELL_AURA_PULL = 79333, + + SPELL_GRAVITY_WELL_DAMAGE = 79249, + SPELL_GRAVITY_WELL_PULL = 79332, + + // Fury of Earth phase + SPELL_EARTH_FURY_CASTING_VISUAL = 79002, + SPELL_SEISMIC_SHARD_SUMMON_1 = 86860, + SPELL_SEISMIC_SHARD_SUMMON_2 = 86858, + SPELL_SEISMIC_SHARD_SUMMON_3 = 86856, + SPELL_SEISMIC_SHARD_VISUAL = 79009, + SPELL_SEISMIC_SHARD_PREPARE = 86862, + SPELL_SEISMIC_SHARD_TARGETING = 80511, + SPELL_SEISMIC_SHARD_LAUNCH = 79015, + SPELL_SEISMIC_SHARD_MISSLE = 79014, + SPELL_EJECT_ALL_PASSENGERS = 68576, + + // Add wave spells + SPELL_SUMMON_WAVE_SOUTH = 79200, + SPELL_SUMMON_WAVE_WEST = 79196, + SPELL_SUMMON_ADD_SOUTH = 79193, + SPELL_SUMMON_ADD_WEST = 79199, +}; + +enum NPCs +{ + NPC_DEVOUT_FOLLOWER = 42428, + NPC_SEISMIC_SHARD = 42355, +}; + +enum Texts +{ + SAY_AGGRO = 0, + SAY_PHASE_TWO = 1, + SAY_DEATH = 2, +}; + +enum Events +{ + EVENT_NONE, + + EVENT_INTRO_MOVE, + + EVENT_CURSE_OF_BLOOD, + EVENT_FORCE_GRIP, + EVENT_SUMMON_GRAVITY_WELL, + EVENT_ENERGY_SHIELD, + EVENT_EARTH_FURY, + + EVENT_SUMMON_WAVE_SOUTH, + EVENT_SUMMON_WAVE_WEST, + + EVENT_GRAVITY_WELL_AURA_DAMAGE, + EVENT_GRAVITY_WELL_AURA_PULL, + + // Phase 2: Fury of Earth + EVENT_EARTH_FURY_FLY_UP, + EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM, + EVENT_EARTH_FURY_CHECK_SEAT0, + EVENT_EARTH_FURY_LAUNCH_SHARD, + EVENT_EARTH_FURY_FLY_DOWN, + EVENT_START_ATTACK, + + EVENT_LAUNCH, + EVENT_SEISMIC_SHARD_MOUNT +}; + +enum EventGroups +{ + EVENT_GROUP_PHASE_ONE, + EVENT_GROUP_ADDS, +}; + +enum Points +{ + POINT_NONE, + + POINT_INTRO_MOVE, + POINT_FLY_UP, + POINT_ABOVE_PLATFORM, + POINT_PLATFORM, + POINT_GROUND, +}; + +Position const GroundPos = { 1331.82f, 980.314f, 207.542f }; +Position const AbovePlatformPos = { 1336.21f, 960.813f, 215.0f }; + +// TO-DO: +// - Find out why NPCs summoned by boss are usually two times bigger than their normal size. +// - Find more sniffs and script Force Grip spell (79351) + +class boss_high_priestess_azil : public CreatureScript +{ + public: + boss_high_priestess_azil() : CreatureScript("boss_high_priestess_azil") { } + + struct boss_high_priestess_azilAI : public BossAI + { + boss_high_priestess_azilAI(Creature* creature) : BossAI(creature, DATA_HIGH_PRIESTESS_AZIL), vehicle(creature->GetVehicleKit()) + { + ASSERT(vehicle); + } + + Vehicle* vehicle; + + void Reset() override + { + _Reset(); + + me->SetCanFly(false); + me->SetDisableGravity(false); + me->SetReactState(REACT_PASSIVE); + + events.ScheduleEvent(EVENT_INTRO_MOVE, 2000); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000,10000), EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_ENERGY_SHIELD, urand(35000,36000)); + events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 0); + events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 40000); + } + + void EnterCombat(Unit* /*victim*/) override + { + _EnterCombat(); + + DoCast(SPELL_ENERGY_SHIELD); + Talk(SAY_AGGRO); + } + + void JustDied(Unit* killer) override + { + me->Say(SAY_DEATH); + } + + /* + void PassengerBoarded(Unit* who, int8 seatId, bool apply) override + { + if (!apply || who->GetEntry() != NPC_SEISMIC_SHARD) + return; + + Movement::MoveSplineInit init(who); + init.DisableTransportPathTransformations(); + if (seatId == 0) + init.MoveTo(12.13748f, 0.0f, 2.442475f); + else if (seatId == 1) + init.MoveTo(12.13748f, 17.5f, 11.19248f); + else + init.MoveTo(12.13748f, -17.5f, 11.19248f); + init.Launch(); + } + */ + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE && id != POINT_INTRO_MOVE) + return; + + switch (id) + { + case POINT_INTRO_MOVE: + me->RemoveAurasDueToSpell(SPELL_ENERGY_SHIELD); + me->SetReactState(REACT_AGGRESSIVE); + break; + case POINT_FLY_UP: + me->SetCanFly(true); + me->SetDisableGravity(true); + events.ScheduleEvent(EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM, 1000); + break; + case POINT_ABOVE_PLATFORM: + me->SetFacingTo(5.218534f); + DoCast(SPELL_EARTH_FURY_CASTING_VISUAL); + DoCast(SPELL_SEISMIC_SHARD_SUMMON_1); + DoCast(SPELL_SEISMIC_SHARD_SUMMON_2); + DoCast(SPELL_SEISMIC_SHARD_SUMMON_3); + events.ScheduleEvent(EVENT_EARTH_FURY_CHECK_SEAT0, 6700); + break; + case POINT_GROUND: + DoCast(SPELL_EJECT_ALL_PASSENGERS); + me->SetCanFly(false); + me->SetDisableGravity(false); + me->SetReactState(REACT_AGGRESSIVE); + // Find more sniffs to correct these timers, this was copied from Reset() void. + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, 6000, EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_FORCE_GRIP, urand(8000, 10000), EVENT_GROUP_PHASE_ONE); + events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, 16000, EVENT_GROUP_PHASE_ONE); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_INTRO_MOVE: + me->GetMotionMaster()->MoveJump(GroundPos, me->GetSpeed(MOVE_FLIGHT), 1.918408f, POINT_INTRO_MOVE); + break; + case EVENT_CURSE_OF_BLOOD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_CURSE_OF_BLOOD); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE); + break; + case EVENT_FORCE_GRIP: + DoCastVictim(SPELL_FORCE_GRIP); + events.ScheduleEvent(EVENT_CURSE_OF_BLOOD, urand(13000, 15000), EVENT_GROUP_PHASE_ONE); + break; + case EVENT_SUMMON_GRAVITY_WELL: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + DoCast(target, SPELL_SUMMON_GRAVITY_WELL); + events.ScheduleEvent(EVENT_SUMMON_GRAVITY_WELL, urand(13000, 15000), EVENT_GROUP_PHASE_ONE); + break; + case EVENT_ENERGY_SHIELD: + events.CancelEventGroup(EVENT_GROUP_PHASE_ONE); + DoCast(SPELL_EARTH_FURY_ENERGY_SHIELD); + events.ScheduleEvent(EVENT_EARTH_FURY, 0); + break; + case EVENT_EARTH_FURY: + countSeismicShard = 3; + me->SetReactState(REACT_PASSIVE); + me->SetFacingTo(5.862942f); + events.ScheduleEvent(EVENT_EARTH_FURY_FLY_UP, 1600); + break; + case EVENT_EARTH_FURY_FLY_UP: + Talk(SAY_PHASE_TWO); + me->GetMotionMaster()->MovePoint(POINT_FLY_UP, me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5); + break; + case EVENT_EARTH_FURY_FLY_ABOVE_PLATFORM: + me->GetMotionMaster()->MovePoint(POINT_ABOVE_PLATFORM, AbovePlatformPos); + break; + case EVENT_EARTH_FURY_CHECK_SEAT0: + if (!vehicle->GetPassenger(0)) + DoCast(SPELL_SEISMIC_SHARD_PREPARE); + events.ScheduleEvent(EVENT_EARTH_FURY_LAUNCH_SHARD, 1800); + break; + case EVENT_EARTH_FURY_LAUNCH_SHARD: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 100.0f, true)) + { + me->SetFacingToObject(target); + DoCast(target, SPELL_SEISMIC_SHARD_TARGETING); + DoCast(SPELL_SEISMIC_SHARD_LAUNCH); + countSeismicShard -= 1; + } + events.ScheduleEvent(countSeismicShard > 0 ? EVENT_EARTH_FURY_CHECK_SEAT0 : EVENT_EARTH_FURY_FLY_DOWN, 4800); + break; + case EVENT_EARTH_FURY_FLY_DOWN: + { + me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_CASTING_VISUAL); + me->RemoveAurasDueToSpell(SPELL_EARTH_FURY_ENERGY_SHIELD); + Position pos = me->GetPosition(); + pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); + me->GetMotionMaster()->MovePoint(POINT_GROUND, pos); + break; + } + case EVENT_SUMMON_WAVE_SOUTH: + if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f)) + worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_SOUTH); + events.ScheduleEvent(EVENT_SUMMON_WAVE_SOUTH, 12000); + break; + case EVENT_SUMMON_WAVE_WEST: + if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f)) + worldtrigger->CastSpell(worldtrigger, SPELL_SUMMON_WAVE_WEST); + events.ScheduleEvent(EVENT_SUMMON_WAVE_WEST, 20000); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + uint8 countSeismicShard; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_high_priestess_azilAI>(creature); + } +}; + +// 42428 - Devout Follower +class npc_devout_follower : public CreatureScript +{ +public: + npc_devout_follower() : CreatureScript("npc_devout_follower") { } + + struct npc_devout_followerAI : public ScriptedAI + { + npc_devout_followerAI(Creature* creature) : ScriptedAI(creature) { } + + void IsSummonedBy(Unit* summoner) override + { + if (summoner->GetEntry() != NPC_WORLDTRIGGER) + return; + + if (Unit* target = me->SelectNearestPlayer(200.0f)) + { + me->AddThreat(target, 0.0f); + me->SetInCombatWith(target); + target->SetInCombatWith(me); + DoStartMovement(target); + me->Attack(target, true); + } + else + me->GetMotionMaster()->MovePoint(POINT_NONE, summoner->GetPosition()); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_devout_followerAI>(creature); + } +}; + +// 42499 - Gravity Well +class npc_gravity_well : public CreatureScript +{ +public: + npc_gravity_well() : CreatureScript("npc_gravity_well") { } + + struct npc_gravity_wellAI : public ScriptedAI + { + npc_gravity_wellAI(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + DoCast(SPELL_GRAVITY_WELL_VISUAL); + events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_DAMAGE, 3200); + events.ScheduleEvent(EVENT_GRAVITY_WELL_AURA_PULL, 4500); + if (!me->GetMap()->IsHeroic()) + me->DespawnOrUnsummon(23200); + } + + void KilledUnit(Unit* victim) override + { + if (victim->GetEntry() != NPC_DEVOUT_FOLLOWER) + return; + + me->SetObjectScale(me->GetObjectScale() - 0.25f); + if (me->GetObjectScale() <= 0.0f) + me->DespawnOrUnsummon(1000); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_GRAVITY_WELL_AURA_DAMAGE: + me->RemoveAurasDueToSpell(SPELL_GRAVITY_WELL_VISUAL); + DoCast(SPELL_GRAVITY_WELL_AURA_DAMAGE); + break; + case EVENT_GRAVITY_WELL_AURA_PULL: + DoCast(SPELL_GRAVITY_WELL_AURA_PULL); + break; + default: + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_gravity_wellAI>(creature); + } +}; + +// 42355 - Seismic Shard +class npc_seismic_shard : public CreatureScript +{ +public: + npc_seismic_shard() : CreatureScript("npc_seismic_shard") { } + + struct npc_seismic_shardAI : public ScriptedAI + { + npc_seismic_shardAI(Creature* creature) : ScriptedAI(creature) + { + instance = creature->GetInstanceScript(); + me->SetDisableGravity(true); + me->SetReactState(REACT_PASSIVE); + DoCast(SPELL_SEISMIC_SHARD_VISUAL); + + Movement::MoveSplineInit init(me); + FillPath(me->GetPosition(), init.Path()); + init.SetFly(); + init.Launch(); + + events.ScheduleEvent(EVENT_SEISMIC_SHARD_MOUNT, 2400); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_SEISMIC_SHARD_MOUNT: + if (Creature* highPriestAzil = ObjectAccessor::GetCreature(*me, instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL))) + if (Vehicle* vehicle = highPriestAzil->GetVehicleKit()) + me->EnterVehicle(highPriestAzil, vehicle->GetNextEmptySeat(0, false)->first); + break; + default: + break; + } + } + + } + + private: + void FillPath(Position const& pos, Movement::PointsArray& path) + { + G3D::Vector3 point; + + point.x = pos.GetPositionX(); + point.y = pos.GetPositionY(); + point.z = pos.GetPositionZ(); + + point.x -= 1.0f; + path.push_back(point); + + point.x += 1.0f; + path.push_back(point); + + point.z += 25.0f; + path.push_back(point); + + path.push_back(point); + } + + InstanceScript* instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_seismic_shardAI>(creature); + } +}; + +// 79200 - Summon Follower +class spell_summon_wave_south : public SpellScriptLoader +{ +public: + spell_summon_wave_south() : SpellScriptLoader("spell_summon_wave_south") { } + + class spell_summon_wave_south_SpellScript : public SpellScript + { + PrepareSpellScript(spell_summon_wave_south_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_SOUTH)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + for (uint8 i = 0; i < 3; i++) + GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_ADD_SOUTH, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_summon_wave_south_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_summon_wave_south_SpellScript(); + } +}; + +// 79196 - Summon Follower +class spell_summon_wave_west : public SpellScriptLoader +{ +public: + spell_summon_wave_west() : SpellScriptLoader("spell_summon_wave_west") { } + + class spell_summon_wave_west_SpellScript : public SpellScript + { + PrepareSpellScript(spell_summon_wave_west_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_SUMMON_ADD_WEST)) + return false; + return true; + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Unit* caster = GetCaster(); + for (uint8 i = 0; i < 10; i++) + GetCaster()->CastSpell(GetCaster(), SPELL_SUMMON_ADD_WEST, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_summon_wave_west_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_summon_wave_west_SpellScript(); + } +}; + +// 79251 - Gravity Well (casts damage spell on units within 10 yards) +class PlayerPetOrDevoutFollowerCheck +{ +public: + bool operator()(WorldObject* object) const + { + // Valid targets are players, pets and Devout Followers + if (Creature* creature = object->ToCreature()) + return (!creature->ToPet() && object->GetEntry() != NPC_DEVOUT_FOLLOWER); + return (!object->ToPlayer()); + } +}; + +class spell_gravity_well_damage_nearby : public SpellScriptLoader +{ +public: + spell_gravity_well_damage_nearby() : SpellScriptLoader("spell_gravity_well_damage_nearby") { } + + class spell_gravity_well_damage_nearby_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gravity_well_damage_nearby_SpellScript); + + void SetRadiusMod() + { + GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3)); + } + + void FilterTargets(std::list<WorldObject*>& unitList) + { + unitList.remove_if(PlayerPetOrDevoutFollowerCheck()); + } + + void HandleScript(SpellEffIndex /*effIndex*/) + { + GetCaster()->CastSpell(GetHitUnit(), SPELL_GRAVITY_WELL_DAMAGE, true); + } + + void Register() override + { + BeforeCast += SpellCastFn(spell_gravity_well_damage_nearby_SpellScript::SetRadiusMod); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_damage_nearby_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_nearby_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gravity_well_damage_nearby_SpellScript(); + } +}; + +// 79249 - Gravity Well (damage) +class spell_gravity_well_damage : public SpellScriptLoader +{ +public: + spell_gravity_well_damage() : SpellScriptLoader("spell_gravity_well_damage") { } + + class spell_gravity_well_damage_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gravity_well_damage_SpellScript); + + void CalculateDamage(SpellEffIndex /*effIndex*/) + { + Unit* target = GetHitUnit(); + if (!target) + return; + + float distance = GetCaster()->GetDistance2d(target); + + if (target->GetEntry() == NPC_DEVOUT_FOLLOWER) + SetHitDamage(int32(200000 - (1000 * distance))); //need more research on this formula, damage values from sniffs: 189264, 190318, 190478, 196134, 197672, 199735 + else + SetHitDamage(int32(4000 - (200 * distance))); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_gravity_well_damage_SpellScript::CalculateDamage, EFFECT_0, SPELL_EFFECT_SCHOOL_DAMAGE); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gravity_well_damage_SpellScript(); + } +}; + +// 79332 - Gravity Well (pull units within 10 yards) +class PulledRecentlyCheck +{ +public: + bool operator()(WorldObject* object) const + { + return (object->ToUnit() && object->ToUnit()->HasAura(SPELL_GRAVITY_WELL_PULL)); + } +}; + +class spell_gravity_well_pull : public SpellScriptLoader +{ +public: + spell_gravity_well_pull() : SpellScriptLoader("spell_gravity_well_pull") { } + + class spell_gravity_well_pull_SpellScript : public SpellScript + { + PrepareSpellScript(spell_gravity_well_pull_SpellScript); + + void SetRadiusMod() + { + GetSpell()->SetSpellValue(SPELLVALUE_RADIUS_MOD, int32(GetCaster()->GetObjectScale() * 10000 * 2 / 3)); + } + + void FilterTargets(std::list<WorldObject*>& unitList) + { + unitList.remove_if(PulledRecentlyCheck()); + } + + void Register() override + { + BeforeCast += SpellCastFn(spell_gravity_well_pull_SpellScript::SetRadiusMod); + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_gravity_well_pull_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_gravity_well_pull_SpellScript(); + } +}; + +// 86862 - Seismic Shard (forces target to cast 86863) +class spell_seismic_shard_prepare : public SpellScriptLoader +{ +public: + spell_seismic_shard_prepare() : SpellScriptLoader("spell_seismic_shard_prepare") { } + + class spell_seismic_shard_prepare_SpellScript : public SpellScript + { + PrepareSpellScript(spell_seismic_shard_prepare_SpellScript); + + void SetTarget(WorldObject*& target) + { + target = GetCaster()->FindNearestCreature(NPC_SEISMIC_SHARD, 50.0f); + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_prepare_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_seismic_shard_prepare_SpellScript(); + } +}; + +// 86863 - Seismic Shard (moves shard to seat 0) +class spell_seismic_shard_change_seat : public SpellScriptLoader +{ +public: + spell_seismic_shard_change_seat() : SpellScriptLoader("spell_seismic_shard_change_seat") { } + + class spell_seismic_shard_change_seat_SpellScript : public SpellScript + { + PrepareSpellScript(spell_seismic_shard_change_seat_SpellScript); + + void SetTarget(WorldObject*& target) + { + if (InstanceScript* instance = GetCaster()->GetInstanceScript()) + target = ObjectAccessor::GetCreature(*GetCaster(), instance->GetGuidData(DATA_HIGH_PRIESTESS_AZIL)); + } + + void ChangeSeat(SpellEffIndex /*effIndex*/) + { + GetCaster()->ExitVehicle(); + if (GetHitUnit()->IsVehicle()) + GetCaster()->EnterVehicle(GetHitUnit(), 0); + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_seismic_shard_change_seat_SpellScript::SetTarget, EFFECT_0, TARGET_UNIT_NEARBY_ENTRY); + OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_change_seat_SpellScript::ChangeSeat, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_seismic_shard_change_seat_SpellScript(); + } +}; + +// 79015 - Seismic Shard (launches shard) +class spell_seismic_shard : public SpellScriptLoader +{ +public: + spell_seismic_shard() : SpellScriptLoader("spell_seismic_shard") { } + + class spell_seismic_shard_SpellScript : public SpellScript + { + PrepareSpellScript(spell_seismic_shard_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + Creature* target = GetHitUnit()->ToCreature(); + if (!target) + return; + + target->ExitVehicle(); + DynamicObject* dynamicObject = GetCaster()->GetDynObject(SPELL_SEISMIC_SHARD_TARGETING); + target->CastSpell(dynamicObject->GetPositionX(), dynamicObject->GetPositionY(), dynamicObject->GetPositionZ(), SPELL_SEISMIC_SHARD_MISSLE, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_seismic_shard_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_seismic_shard_SpellScript(); + } +}; + +void AddSC_boss_high_priestess_azil() +{ + new boss_high_priestess_azil(); + new npc_devout_follower(); + new npc_gravity_well(); + new npc_seismic_shard(); + new spell_summon_wave_south(); + new spell_summon_wave_west(); + new spell_gravity_well_damage_nearby(); + new spell_gravity_well_damage(); + new spell_gravity_well_pull(); + new spell_seismic_shard_prepare(); + new spell_seismic_shard_change_seat(); + new spell_seismic_shard(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp new file mode 100644 index 00000000000..92c9bba4bc1 --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/boss_ozruk.cpp @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2008-2014 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "SpellAuraEffects.h" +#include "Vehicle.h" +#include "stonecore.h" + +enum Spells +{ + SPELL_ELEMENTIUM_BULWARK = 78939, + SPELL_GROUND_SLAM = 78903, + SPELL_ELEMENTIUM_SPIKE_SHIELD = 78835, + SPELL_SHATTER = 78807, + SPELL_ENRAGE = 80467, + + // Rupture Controller and Rupture + SPELL_RUPTURE = 92393, +// SPELL_RUPTURE_SUMMON_CENTER? = 95669, // summons rupture 8 yards front +// SPELL_RUPTURE_SUMMON_LEFT? = 95348, // summons rupture 3 yards left? +// SPELL_RUPTURE_SUMMON_RIGHT? = 92383, // summons rupture 3 yards right? + SPELL_RUPTURE_DAMAGE = 92381, +}; + +enum NPCs +{ + NPC_BOUNCER_SPIKE = 42189, + NPC_RUPTURE_CONTROLLER = 49597, + NPC_RUPTURE = 49576, +}; + +enum Texts +{ + SAY_AGGRO = 0, + SAY_ELEMENTIUM_BULWARK = 1, + SAY_ELEMENTIUM_SPIKE_SHIELD = 2, + SAY_ENRAGE = 3, + SAY_DEATH = 4, +}; + +enum Events +{ + EVENT_NONE, + + EVENT_ELEMENTIUM_BULWARK, + EVENT_GROUND_SLAM, + EVENT_ELEMENTIUM_SPIKE_SHIELD, + EVENT_SHATTER, + EVENT_ENRAGE, + + EVENT_START_ATTACK, +}; + +// TO-DO: +// - Find heroic sniffs and spawn Ruptures using spells commented above. +// - Make Bouncer Spikes enter ozruk without jump animation. + +class boss_ozruk : public CreatureScript +{ + public: + boss_ozruk() : CreatureScript("boss_ozruk") { } + + struct boss_ozrukAI : public BossAI + { + boss_ozrukAI(Creature* creature) : BossAI(creature, DATA_OZRUK) { } + + void Reset() override + { + _Reset(); + + me->SetReactState(REACT_AGGRESSIVE); + + events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, 5000); + events.ScheduleEvent(EVENT_GROUND_SLAM, 10000); + events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, 13000); + + RemoveBouncerSpikes(); + } + + void EnterCombat(Unit* /*victim*/) override + { + _EnterCombat(); + + Talk(SAY_AGGRO); + } + + void JustSummoned(Creature* summon) override + { + if (summon->GetEntry() != NPC_RUPTURE_CONTROLLER) + return; + + summon->SetReactState(REACT_PASSIVE); + summon->CastSpell(summon, SPELL_RUPTURE, true); + summon->DespawnOrUnsummon(10000); + } + + void DamageTaken(Unit* /*attacker*/, uint32 &damage) override + { + if (!me->HealthBelowPctDamaged(25, damage) || me->HasAura(SPELL_ENRAGE)) + return; + + DoCast(me, SPELL_ENRAGE); + me->Say(SAY_ENRAGE); + } + + void JustDied(Unit* killer) override + { + me->Say(SAY_DEATH, killer); // receiver is the killer, sniff source! + + RemoveBouncerSpikes(); + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING) || me->HasAura(SPELL_ELEMENTIUM_SPIKE_SHIELD)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_ELEMENTIUM_BULWARK: + DoCast(me, SPELL_ELEMENTIUM_BULWARK); + Talk(SAY_ELEMENTIUM_BULWARK); + break; + case EVENT_GROUND_SLAM: + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + DoCast(me, SPELL_GROUND_SLAM); + events.ScheduleEvent(EVENT_START_ATTACK, 4600); + break; + case EVENT_ELEMENTIUM_SPIKE_SHIELD: + DoCast(me, SPELL_ELEMENTIUM_SPIKE_SHIELD); + Talk(SAY_ELEMENTIUM_SPIKE_SHIELD); + events.ScheduleEvent(EVENT_SHATTER, 10000); + break; + case EVENT_SHATTER: + RemoveBouncerSpikes(); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + DoCast(me, SPELL_SHATTER); + events.ScheduleEvent(EVENT_START_ATTACK, 4600); + // Spells are cast in same order everytime after Shatter, so we schedule them here + events.ScheduleEvent(EVENT_ELEMENTIUM_BULWARK, urand(3000,4000)); + events.ScheduleEvent(EVENT_GROUND_SLAM, urand(7000,9000)); + events.ScheduleEvent(EVENT_ELEMENTIUM_SPIKE_SHIELD, urand(10000,12000)); + break; + case EVENT_START_ATTACK: + me->SetReactState(REACT_AGGRESSIVE); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + void RemoveBouncerSpikes() + { + Vehicle* vehicle = me->GetVehicleKit(); + if (!vehicle) + return; + + for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++) + if (Unit* passenger = vehicle->GetPassenger(i)) + if (Creature* creature = passenger->ToCreature()) + creature->RemoveFromWorld(); + } + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_ozrukAI>(creature); + } +}; + +// 92393 - Rupture +class spell_rupture : public SpellScriptLoader +{ +public: + spell_rupture() : SpellScriptLoader("spell_rupture") { } + + class spell_rupture_AuraScript : public AuraScript + { + PrepareAuraScript(spell_rupture_AuraScript); + + void HandleEffectPeriodic(AuraEffect const* aurEff) + { + Unit* caster = GetCaster(); + + float dist = aurEff->GetTickNumber() * 8.0f; + + // probably hack, should use spells (see Spells enum above) + Position pos = caster->GetNearPosition(dist, 0.0f); + SummonRupture(caster, pos); + + pos = caster->GetNearPosition(dist, 0.2f); + SummonRupture(caster, pos); + + pos = caster->GetNearPosition(dist, -0.2f); + SummonRupture(caster, pos); + } + + void SummonRupture(Unit* caster, Position pos) + { + Creature* rupture = caster->SummonCreature(NPC_RUPTURE, pos, TEMPSUMMON_TIMED_DESPAWN, 2500); + if (!rupture) + return; + + rupture->SetReactState(REACT_PASSIVE); + rupture->CastSpell(rupture, SPELL_RUPTURE_DAMAGE, true); + } + + void Register() + { + OnEffectPeriodic += AuraEffectPeriodicFn(spell_rupture_AuraScript::HandleEffectPeriodic, EFFECT_0, SPELL_AURA_PERIODIC_TRIGGER_SPELL); + } + }; + + AuraScript* GetAuraScript() const + { + return new spell_rupture_AuraScript(); + } +}; + +// 78835 - Elementium Spike Shield +class spell_elementium_spike_shield : public SpellScriptLoader +{ +public: + spell_elementium_spike_shield() : SpellScriptLoader("spell_elementium_spike_shield") { } + + class spell_elementium_spike_shield_SpellScript : public SpellScript + { + PrepareSpellScript(spell_elementium_spike_shield_SpellScript); + + void HandleBouncerSpikes() + { + Unit* caster = GetCaster(); + Vehicle* vehicle = caster->GetVehicleKit(); + if (!vehicle) + return; + + for (uint8 i = 0; i < vehicle->GetAvailableSeatCount(); i++) + if (Creature* summon = caster->SummonCreature(NPC_BOUNCER_SPIKE, caster->GetPosition(), TEMPSUMMON_TIMED_DESPAWN, 10000)) + summon->EnterVehicle(caster, i); + } + + void Register() override + { + OnCast += SpellCastFn(spell_elementium_spike_shield_SpellScript::HandleBouncerSpikes); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_elementium_spike_shield_SpellScript(); + } +}; + +void AddSC_boss_ozruk() +{ + new boss_ozruk(); + new spell_rupture(); + new spell_elementium_spike_shield(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp new file mode 100644 index 00000000000..6827312deef --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/boss_slabhide.cpp @@ -0,0 +1,599 @@ +/* + * Copyright (C) 2008-2014 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 "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "stonecore.h" + +enum Spells +{ + SPELL_FACE_RANDOM_PLAYER = 82530, + + // Stalactite Trigger - Trash, On Ground + SPELL_STALACTITE_SUMMON_TRIGGER = 81028, + + // Slabhide + SPELL_LAVA_FISSURE = 80803, + SPELL_SAND_BLAST = 80807, + SPELL_STALACTITE_SUMMON = 80656, +// SPELL_COOLDOWN_5S = 95323, Cooldown: Creature Special 1 (5s)? + SPELL_CRYSTAL_STORM = 92305, + SPELL_CRYSTAL_STORM_TRIGGER = 92265, + + // Lava Fissure + SPELL_LAVA_FISSURE_CRACK = 80798, + SPELL_LAVA_FISSURE_ERUPTION = 80800, + + // Stalactite Trigger - Boss + SPELL_STALACTITE_SHADE = 80654, + SPELL_STALACTITE_MISSLE = 80643, + SPELL_STALACTITE_CREATE = 80647, +}; + +enum Entries +{ + NPC_LAVA_FISSURE = 43242, + NPC_STALACTITE_TRIGGER_GROUND = 43357, + NPC_STALACTITE_TRIGGER = 43159, + GO_STALACTITE = 204337, +}; + +enum Actions +{ + ACTION_STALACTITE_MISSLE, +}; + +enum Events +{ + EVENT_NONE, + + // Intro events + EVENT_ROAR_EMOTE, + + // Slabhide combat + EVENT_HANDLE_ROCK_WALLS, + EVENT_LAVA_FISSURE, + EVENT_SAND_BLAST, + EVENT_AIR_PHASE, + EVENT_TAKEOFF, + EVENT_STALACTITE, + EVENT_LAND, + EVENT_ATTACK, + + // Lava Fissure + EVENT_LAVA_FISSURE_ERUPTION, + + // Stalactite Trigger - Boss + EVENT_STALACTITE_MISSLE, +}; + +enum MovementPoints +{ + POINT_NONE, + + POINT_SLABHIDE_INTRO, + POINT_SLABHIDE_INTRO_LAND, + + POINT_SLABHIDE_MIDDLE, + POINT_SLABHIDE_IN_AIR, + POINT_SLABHIDE_LAND, +}; + +Position const SlabhideIntroPos = { 1292.27f, 1226.16f, 265.573f }; +Position const SlabhideIntroLandPos = { 1292.352f, 1226.478f, 247.6368f, 3.630285f }; + +Position const SlabhideMiddlePos = { 1280.73f, 1212.31f, 247.3837f }; +Position const SlabhideInAirPos = { 1280.73f, 1212.31f, 257.3837f }; +Position const SlabhideLandPos = { 1282.7f, 1229.77f, 247.155f, 3.82227f }; + +class boss_slabhide : public CreatureScript +{ + public: + boss_slabhide() : CreatureScript("boss_slabhide") { } + + struct boss_slabhideAI : public BossAI + { + boss_slabhideAI(Creature* creature) : BossAI(creature, DATA_SLABHIDE) + { + me->setActive(true); + me->SetCanFly(true); + me->SetDisableGravity(true); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetReactState(REACT_PASSIVE); + instance->SetData(DATA_SLABHIDE_INTRO, NOT_STARTED); + } + + void Reset() + { + if (instance->GetData(DATA_SLABHIDE_INTRO) == NOT_STARTED) + return; + + _Reset(); + DespawnAll(); + + me->SetCanFly(false); + me->SetDisableGravity(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetReactState(REACT_AGGRESSIVE); + } + + void EnterCombat(Unit* /*victim*/) override + { + _EnterCombat(); + + events.ScheduleEvent(EVENT_HANDLE_ROCK_WALLS, 4000); + events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000)); + events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000)); + events.ScheduleEvent(EVENT_AIR_PHASE, 10000); + } + + void JustDied(Unit* /*killer*/) override + { + _JustDied(); + + // Despawn related npcs and gameobjects + DespawnAll(); + } + + void DoAction(int32 action) override + { + switch (action) + { + case ACTION_SLABHIDE_INTRO: + { + if (instance->GetData(DATA_SLABHIDE_INTRO) != NOT_STARTED) + return; + + instance->SetData(DATA_SLABHIDE_INTRO, IN_PROGRESS); + + // Execute Slabhide intro event + me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_INTRO, SlabhideIntroPos); + break; + } + default: + break; + } + } + + void MovementInform(uint32 type, uint32 id) override + { + if (type != POINT_MOTION_TYPE && type != EFFECT_MOTION_TYPE) + return; + + switch (id) + { + case POINT_SLABHIDE_INTRO: + me->SetFacingTo(SlabhideIntroLandPos.GetOrientation()); + me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_INTRO_LAND, SlabhideIntroLandPos); + break; + case POINT_SLABHIDE_INTRO_LAND: + me->SetCanFly(false); + me->SetDisableGravity(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetHover(false); + me->SetHomePosition(SlabhideIntroLandPos); + me->HandleEmoteCommand(EMOTE_ONESHOT_ROAR); + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + me->SetReactState(REACT_AGGRESSIVE); + instance->SetData(DATA_SLABHIDE_INTRO, DONE); + break; + case POINT_SLABHIDE_MIDDLE: + events.ScheduleEvent(EVENT_TAKEOFF, 100); + break; + case POINT_SLABHIDE_IN_AIR: + events.ScheduleEvent(EVENT_STALACTITE, 400); + break; + case POINT_SLABHIDE_LAND: + //DoCast(SPELL_COOLDOWN_5S); // unknown purpose + events.ScheduleEvent(EVENT_ATTACK, 1200); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + if (!UpdateVictim()) + return; + + events.Update(diff); + + if (me->HasUnitState(UNIT_STATE_CASTING)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_HANDLE_ROCK_WALLS: // Close rock walls + instance->SetData(DATA_SLABHIDE_ROCK_WALL, false); + break; + case EVENT_LAVA_FISSURE: + DoCast(SPELL_LAVA_FISSURE); + events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000)); + break; + case EVENT_SAND_BLAST: + DoCast(SPELL_SAND_BLAST); + events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 11000)); + break; + case EVENT_AIR_PHASE: + events.Reset(); + me->SetReactState(REACT_PASSIVE); + me->AttackStop(); + me->GetMotionMaster()->MovePoint(POINT_SLABHIDE_MIDDLE, SlabhideMiddlePos); + events.ScheduleEvent(EVENT_AIR_PHASE, 60000); + break; + case EVENT_TAKEOFF: + me->GetMotionMaster()->MoveTakeoff(POINT_SLABHIDE_IN_AIR, SlabhideInAirPos); + break; + case EVENT_STALACTITE: + me->SetCanFly(true); + me->SetDisableGravity(true); + me->SetByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetHover(true); + + DoCast(SPELL_STALACTITE_SUMMON); + + events.ScheduleEvent(EVENT_LAND, 8000); + break; + case EVENT_LAND: + { + Position pos = me->GetPosition(); + pos.m_positionZ = me->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ()); + me->GetMotionMaster()->MoveLand(POINT_SLABHIDE_LAND, pos); + break; + } + case EVENT_ATTACK: + me->SetCanFly(false); + me->SetDisableGravity(false); + me->RemoveByteFlag(UNIT_FIELD_BYTES_1, 3, UNIT_BYTE1_FLAG_ALWAYS_STAND | UNIT_BYTE1_FLAG_HOVER); + me->SetHover(false); + + events.ScheduleEvent(EVENT_LAVA_FISSURE, urand(6000, 8000)); + events.ScheduleEvent(EVENT_SAND_BLAST, urand(8000, 10000)); + DoCast(SPELL_CRYSTAL_STORM); + me->SetReactState(REACT_AGGRESSIVE); + break; + default: + break; + } + } + + DoMeleeAttackIfReady(); + } + + private: + void DespawnAll() + { + // Despawn stalactite triggers npcs + std::list<Creature*> listStalactiteTrigger; + me->GetCreatureListWithEntryInGrid(listStalactiteTrigger, NPC_STALACTITE_TRIGGER, 200.0f); + if (!listStalactiteTrigger.empty()) + for (std::list<Creature*>::const_iterator itr = listStalactiteTrigger.begin(); itr != listStalactiteTrigger.end(); ++itr) + (*itr)->DespawnOrUnsummon(); + + // Despawn stalactite objects + std::list<GameObject*> listStalactite; + me->GetGameObjectListWithEntryInGrid(listStalactite, GO_STALACTITE, 200.0f); + if (!listStalactite.empty()) + for (std::list<GameObject*>::const_iterator itr = listStalactite.begin(); itr != listStalactite.end(); ++itr) + (*itr)->Delete(); + } + + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<boss_slabhideAI>(creature); + } +}; + +// 43242 - Lava Fissure +class npc_lava_fissure : public CreatureScript +{ +public: + npc_lava_fissure() : CreatureScript("npc_lava_fissure") { } + + struct npc_lava_fissureAI : public ScriptedAI + { + npc_lava_fissureAI(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + me->CastSpell(me, SPELL_LAVA_FISSURE_CRACK, true); + events.ScheduleEvent(EVENT_LAVA_FISSURE_ERUPTION, 6000); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_LAVA_FISSURE_ERUPTION: + me->RemoveAurasDueToSpell(SPELL_LAVA_FISSURE_CRACK); + me->CastSpell(me, SPELL_LAVA_FISSURE_ERUPTION, true); + me->DespawnOrUnsummon(14000); + break; + default: + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_lava_fissureAI>(creature); + } +}; + +// 43159 - Stalactite Trigger - Boss +class npc_stalactite_trigger : public CreatureScript +{ +public: + npc_stalactite_trigger() : CreatureScript("npc_stalactite_trigger") { } + + struct npc_stalactite_triggerAI : public ScriptedAI + { + npc_stalactite_triggerAI(Creature* creature) : ScriptedAI(creature) + { + me->SetReactState(REACT_PASSIVE); + me->SetDisableGravity(true); + me->CastSpell(me, SPELL_STALACTITE_SHADE, true); + events.ScheduleEvent(EVENT_STALACTITE_MISSLE, 5600); + } + + void UpdateAI(uint32 diff) override + { + events.Update(diff); + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_STALACTITE_MISSLE: + DoCast(SPELL_STALACTITE_MISSLE); + me->DespawnOrUnsummon(11000); + break; + default: + break; + } + } + } + + private: + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_stalactite_triggerAI>(creature); + } +}; + +// 81035 - Stalactite (check if player is near to summon stalactite) +class NotPlayerCheck +{ + public: + bool operator()(WorldObject* object) const + { + return (object->GetTypeId() != TYPEID_PLAYER); + } +}; + +class spell_s81035_stalactite : public SpellScriptLoader +{ +public: + spell_s81035_stalactite() : SpellScriptLoader("spell_s81035_stalactite") { } + + class spell_s81035_stalactite_SpellScript : public SpellScript + { + PrepareSpellScript(spell_s81035_stalactite_SpellScript); + + void FilterTargets(std::list<WorldObject*>& targets) + { + targets.remove_if(NotPlayerCheck()); + } + + void SummonStalactiteTrigger() + { + Unit* caster = GetCaster(); + caster->CastSpell(caster, SPELL_STALACTITE_SUMMON_TRIGGER, true); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s81035_stalactite_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + OnHit += SpellHitFn(spell_s81035_stalactite_SpellScript::SummonStalactiteTrigger); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_s81035_stalactite_SpellScript(); + } +}; + +// 81028 - Stalactite (summons "Stalactite Trigger - Boss", 20 yard radius) +// 80650 - Stalactite (summons "Stalactite Trigger - Boss", 40 yard radius) +class spell_s81028_s80650_stalactite : public SpellScriptLoader +{ +public: + spell_s81028_s80650_stalactite() : SpellScriptLoader("spell_s81028_s80650_stalactite") { } + + class spell_s81028_s80650_stalactite_SpellScript : public SpellScript + { + PrepareSpellScript(spell_s81028_s80650_stalactite_SpellScript); + + void ModDestHeight(SpellDestination& dest) + { + // All stalactite triggers should have Z position 301.3837f, but no way to relocate (not relocateoffset!) height only. + Position offset = { 0.0f, 0.0f, 50.0f, 0.0f }; + dest.RelocateOffset(offset); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_s81028_s80650_stalactite_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER_RANDOM); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_s81028_s80650_stalactite_SpellScript(); + } +}; + +// 80654 - Stalactite (creates visual shade on ground) +// 80643/92653 - Stalactite (launches missle to the ground) +// 80647/92309 - Stalactite (creates stalactite object) +class spell_stalactite_mod_dest_height : public SpellScriptLoader +{ +public: + spell_stalactite_mod_dest_height() : SpellScriptLoader("spell_stalactite_mod_dest_height") { } + + class spell_stalactite_mod_dest_height_SpellScript : public SpellScript + { + PrepareSpellScript(spell_stalactite_mod_dest_height_SpellScript); + + void ModDestHeight(SpellDestination& dest) + { + Unit* caster = GetCaster(); + Position pos = caster->GetPosition(); + pos.m_positionZ = caster->GetMap()->GetHeight(pos.GetPositionX(), pos.GetPositionY(), pos.GetPositionZ(), true, 100.0f); + dest.Relocate(pos); + } + + void Register() override + { + OnDestinationTargetSelect += SpellDestinationTargetSelectFn(spell_stalactite_mod_dest_height_SpellScript::ModDestHeight, EFFECT_0, TARGET_DEST_CASTER); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_stalactite_mod_dest_height_SpellScript(); + } +}; + +// 92306 - Crystal storm (heroic mode check) +class spell_s92306_crystal_storm : public SpellScriptLoader +{ +public: + spell_s92306_crystal_storm() : SpellScriptLoader("spell_s92306_crystal_storm") { } + + class spell_s92306_crystal_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_s92306_crystal_storm_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_CRYSTAL_STORM_TRIGGER)) + return false; + return true; + } + + void HandleDummyEffect(SpellEffIndex /*eff*/) + { + Unit* caster = GetCaster(); + if (caster->GetMap()->IsHeroic()) + caster->CastSpell(caster, SPELL_CRYSTAL_STORM_TRIGGER, true); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_s92306_crystal_storm_SpellScript::HandleDummyEffect, EFFECT_0, SPELL_EFFECT_APPLY_AURA); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_s92306_crystal_storm_SpellScript(); + } +}; + +// 92300 - Crystal Storm (damage) +class BehindObjectCheck +{ + public: + BehindObjectCheck(Unit* caster, std::list<GameObject*> objectList) : caster(caster), objectList(objectList) { } + + bool operator()(WorldObject* unit) + { + for (std::list<GameObject*>::const_iterator itr = objectList.begin(); itr != objectList.end(); ++itr) + if (!(*itr)->IsInvisibleDueToDespawn() && (*itr)->IsInBetween(caster, unit, 1.5f)) + return true; + return false; + } + + private: + Unit* caster; + std::list<GameObject*> objectList; +}; + +class spell_s92300_crystal_storm : public SpellScriptLoader +{ +public: + spell_s92300_crystal_storm() : SpellScriptLoader("spell_s92300_crystal_storm") { } + + class spell_s92300_crystal_storm_SpellScript : public SpellScript + { + PrepareSpellScript(spell_s92300_crystal_storm_SpellScript); + + void FilterTargets(std::list<WorldObject*>& unitList) + { + Unit* caster = GetCaster(); + + std::list<GameObject*> goList; + caster->GetGameObjectListWithEntryInGrid(goList, GO_STALACTITE, 40.0f); + if (goList.empty()) + return; + + unitList.remove_if(BehindObjectCheck(caster, goList)); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_s92300_crystal_storm_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_s92300_crystal_storm_SpellScript(); + } +}; + +void AddSC_boss_slabhide() +{ + new boss_slabhide(); + new npc_lava_fissure(); + new npc_stalactite_trigger(); + new spell_s81035_stalactite(); + new spell_s81028_s80650_stalactite(); + new spell_stalactite_mod_dest_height(); + new spell_s92306_crystal_storm(); + new spell_s92300_crystal_storm(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp b/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp new file mode 100644 index 00000000000..ca5e40ab117 --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/instance_stonecore.cpp @@ -0,0 +1,262 @@ +/* +* Copyright (C) 2008-2014 TrinityCore <http://www.trinitycore.org/> +* Copyright (C) 2006-2009 ScriptDev2 <https://scriptdev2.svn.sourceforge.net/> +* +* 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 "ScriptMgr.h" +#include "Player.h" +#include "CreatureGroups.h" +#include "InstanceScript.h" +#include "stonecore.h" + +#define MAX_ENCOUNTER 4 + +/* Stonecore encounters: +0 - Corborus +1 - Slabhide +2 - Ozruk +3 - High Priestess Azil +*/ + +// TO-DO: +// - Find out spell IDs for both Stonecore Teleporters (spellclick). + +class instance_stonecore : public InstanceMapScript +{ + public: + instance_stonecore() : InstanceMapScript(SCScriptName, 725) { } + + struct instance_stonecore_InstanceScript : public InstanceScript + { + instance_stonecore_InstanceScript(Map* map) : InstanceScript(map) + { + SetHeaders(DataHeader); + SetBossNumber(MAX_ENCOUNTER); + } + + void OnGameObjectCreate(GameObject* go) override + { + switch (go->GetEntry()) + { + case GAMEOBJECT_CORBORUS_ROCKDOOR: + corborusRockDoorGUID = go->GetGUID(); + go->SetGoState(GetBossState(DATA_CORBORUS) != DONE ? GO_STATE_READY : GO_STATE_ACTIVE); + break; + case GAMEOBJECT_SLABHIDE_ROCK_WALL: + slabhideRockWallGUIDs.push_back(go->GetGUID()); + break; + default: + break; + } + } + + void OnCreatureCreate(Creature* creature) override + { + switch (creature->GetEntry()) + { + case NPC_MILLHOUSE_MANASTORM: + millhouseGUID = creature->GetGUID(); + break; + case NPC_CORBORUS: + corobrusGUID = creature->GetGUID(); + break; + case NPC_SLABHIDE: + slabhideGUID = creature->GetGUID(); + break; + case NPC_HIGH_PRIESTESS_AZIL: + highPriestessAzilGUID = creature->GetGUID(); + break; + case NPC_STONECORE_TELEPORTER: + case NPC_STONECORE_TELEPORTER_2: + if (GetBossState(DATA_SLABHIDE) != DONE) + stonecoreTeleporterGUID[creature->GetEntry() - NPC_STONECORE_TELEPORTER] = creature->GetGUID(); + else // If Slabhide is already dead, no need to store teleporter guids + { + creature->CastSpell(creature, SPELL_TELEPORTER_ACTIVE_VISUAL, true); + creature->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + } + break; + default: + break; + } + + // Check if creature is part of Millhouse event + creature->SearchFormation(); + if (CreatureGroup* group = creature->GetFormation()) // TO-DO: Fix formations + { + switch (group->GetId()) + { + case CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH: + millhouseTrashGUIDs.push_back(creature->GetGUID()); + break; + case CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP: + millhouseLastGroupGUIDs.push_back(creature->GetGUID()); + creature->SetReactState(REACT_PASSIVE); + creature->SetMeleeAnimKitId(ANIM_READY2H); + break; + } + } + } + + bool SetBossState(uint32 type, EncounterState state) override + { + switch (type) + { + case DATA_SLABHIDE: + // Open rock walls (Slabhide AI handles closing because it must be delayed) + if (state != IN_PROGRESS) + SetData(DATA_SLABHIDE_ROCK_WALL, true); + + // Activate teleporters + if (state == DONE) + { + for (int8 i = 0; i < MAX_STONECORE_TELEPORTERS; i++) + { + if (Creature* teleporter = instance->GetCreature(stonecoreTeleporterGUID[i])) + { + teleporter->CastSpell(teleporter, SPELL_TELEPORTER_ACTIVE_VISUAL, true); + teleporter->SetFlag(UNIT_NPC_FLAGS, UNIT_NPC_FLAG_SPELLCLICK); + } + } + } + + break; + default: + break; + } + + return InstanceScript::SetBossState(type, state); + } + + uint32 GetData(uint32 type) const override + { + switch (type) + { + case DATA_SLABHIDE_INTRO: + return slabhideIntro; + default: + break; + } + + return 0; + } + + void SetData(uint32 type, uint32 data) override + { + switch (type) + { + case DATA_MILLHOUSE_EVENT_FACE: + MillhouseEvent_Face(); + break; + case DATA_MILLHOUSE_EVENT_KNOCKBACK: + MillhouseEvent_Knockback(); + break; + case DATA_MILLHOUSE_EVENT_DESPAWN: + MillhouseEvent_Despawn(); + break; + case DATA_SLABHIDE_INTRO: + slabhideIntro = EncounterState(data); + break; + case DATA_SLABHIDE_ROCK_WALL: // Handles rock walls + for (std::vector<ObjectGuid>::iterator itr = slabhideRockWallGUIDs.begin(); itr != slabhideRockWallGUIDs.end(); ++itr) + HandleGameObject((*itr), data ? true : false); + break; + default: + break; + } + } + + ObjectGuid GetGuidData(uint32 type) const override + { + switch (type) + { + case DATA_MILLHOUSE_MANASTORM: + return millhouseGUID; + case GAMEOBJECT_CORBORUS_ROCKDOOR: + return corborusRockDoorGUID; + case DATA_CORBORUS: + return corobrusGUID; + case DATA_SLABHIDE: + return slabhideGUID; + case DATA_HIGH_PRIESTESS_AZIL: + return highPriestessAzilGUID; + case NPC_STONECORE_TELEPORTER: + case NPC_STONECORE_TELEPORTER_2: + return stonecoreTeleporterGUID[type - NPC_STONECORE_TELEPORTER]; + default: + break; + } + + return ObjectGuid::Empty; + } + + private: + // Face Millhouse and other nearby mobs to Corborus + void MillhouseEvent_Face() + { + if (Creature* Millhouse = instance->GetCreature(millhouseGUID)) + Millhouse->SetFacingTo(1.570796f); + for (GuidVector::const_iterator i = millhouseLastGroupGUIDs.begin(); i != millhouseLastGroupGUIDs.end(); ++i) + if (Creature* creature = instance->GetCreature(*i)) + creature->SetFacingTo(1.570796f); + } + + // Knock back Millhouse and other mobs + void MillhouseEvent_Knockback() + { + if (Creature* Millhouse = instance->GetCreature(millhouseGUID)) + Millhouse->CastSpell(Millhouse, SPELL_RING_WYRM_KNOCKBACK, true); + for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr) + if (Creature* creature = instance->GetCreature(*itr)) + creature->CastSpell(creature, SPELL_RING_WYRM_KNOCKBACK, true); + } + + // Despawn all mobs + void MillhouseEvent_Despawn() + { + if (Creature* Millhouse = instance->GetCreature(millhouseGUID)) + Millhouse->DespawnOrUnsummon(3000); + for (GuidVector::const_iterator itr = millhouseTrashGUIDs.begin(); itr != millhouseTrashGUIDs.end(); ++itr) + if (Creature* creature = instance->GetCreature(*itr)) + creature->DespawnOrUnsummon(3000); + for (GuidVector::const_iterator itr = millhouseLastGroupGUIDs.begin(); itr != millhouseLastGroupGUIDs.end(); ++itr) + if (Creature* creature = instance->GetCreature(*itr)) + creature->DespawnOrUnsummon(3000); + } + + ObjectGuid millhouseGUID; + GuidVector millhouseTrashGUIDs; + GuidVector millhouseLastGroupGUIDs; + ObjectGuid corborusRockDoorGUID; + ObjectGuid corobrusGUID; + ObjectGuid slabhideGUID; + ObjectGuid highPriestessAzilGUID; + ObjectGuid stonecoreTeleporterGUID[2]; + GuidVector slabhideRockWallGUIDs; + + EncounterState slabhideIntro; + }; + + InstanceScript* GetInstanceScript(InstanceMap* map) const override + { + return new instance_stonecore_InstanceScript(map); + } +}; + +void AddSC_instance_stonecore() +{ + new instance_stonecore(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp b/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp new file mode 100644 index 00000000000..4ed84732eff --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/stonecore.cpp @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2008-2014 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 "ObjectGuid.h" +#include "ObjectMgr.h" +#include "ScriptMgr.h" +#include "ScriptedCreature.h" +#include "SpellScript.h" +#include "Player.h" +#include "stonecore.h" + +enum Texts +{ + // Millhouse Manastorm + SAY_MILLHOUSE_EVENT_1 = 0, + SAY_MILLHOUSE_EVENT_2 = 1, +}; + +enum NPCs +{ + NPC_GENERIC_TRIGGER_LAB = 40350, +}; + +enum Spells +{ + // Millhouse Manastorm + SPELL_SHADOW_BOLT = 81439, + SPELL_FROSTBOLT_VOLLEY = 81440, + SPELL_SHADOWFURY = 81441, + SPELL_FEAR = 81442, +// SPELL_MILLHOUSE_SAFE_CHECK = 81213, // unknown purpose + SPELL_CLEAR_ALL_DEBUFFS = 34098, + SPELL_BLUR = 81216, + SPELL_ANCHOR_HERE = 45313, + SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND = 81220, + SPELL_IMPENDING_DOOM = 86838, + SPELL_IMPENDING_DOOM_CHANNEL = 86830, + +// SPELL_PORTAL_VISUAL = 79754, +}; + +enum Events +{ + EVENT_NONE, + + // Millhouse Manastorm + EVENT_FROSTBOLT_VOLLEY, + EVENT_SHADOWFURY, + EVENT_FEAR, + + EVENT_READY_FOR_COMBAT, + EVENT_CAST_IMPENDING_DOOM, + EVENT_INTERRUPT_IMPENDING_DOOM, +}; + +enum Phase +{ + PHASE_NONE, + + PHASE_MILLHOUSE_GROUP_1, + PHASE_MILLHOUSE_GROUP_2, + PHASE_MILLHOUSE_GROUP_3, + PHASE_MILLHOUSE_GROUP_4, + + PHASE_MASK_MILLHOUSE_GROUP_1 = (1 << (PHASE_MILLHOUSE_GROUP_1 - 1)), + PHASE_MASK_MILLHOUSE_GROUP_2 = (1 << (PHASE_MILLHOUSE_GROUP_2 - 1)), + PHASE_MASK_MILLHOUSE_GROUP_3 = (1 << (PHASE_MILLHOUSE_GROUP_3 - 1)), + PHASE_MASK_MILLHOUSE_GROUP_4 = (1 << (PHASE_MILLHOUSE_GROUP_4 - 1)), +}; + +enum MovementPoints +{ + POINT_NONE, + + POINT_MILLHOUSE_GROUP_2, + POINT_MILLHOUSE_GROUP_3, + POINT_MILLHOUSE_GROUP_4, +}; + +// Millhouse trash groups +Position const MillhousePointGroup2 = { 977.3045f, 895.2347f, 306.3298f }; +Position const MillhousePointGroup3 = { 1049.823f, 871.4349f, 295.006f }; +Position const MillhousePointGroup4 = { 1149.04f, 884.431f, 284.9406f }; + +// 43391 - Millhouse Manastorm +class npc_sc_millhouse_manastorm : public CreatureScript +{ + public: + npc_sc_millhouse_manastorm() : CreatureScript("npc_sc_millhouse_manastorm") { } + + struct npc_sc_millhouse_manastormAI : public ScriptedAI + { + npc_sc_millhouse_manastormAI(Creature* creature) : ScriptedAI(creature), + _instance(creature->GetInstanceScript()) + { + events.SetPhase(PHASE_MILLHOUSE_GROUP_1); + } + + void ScheduleEvents() + { + events.ScheduleEvent(EVENT_SHADOWFURY, 3000); + events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 5000); + events.ScheduleEvent(EVENT_FEAR, 8000); + } + + void DamageTaken(Unit* /*attacker*/, uint32& damage) override + { + if (damage >= me->GetHealth()) + damage = me->GetHealth() - 1; + + if (!HealthBelowPct(50) || me->HasAura(SPELL_BLUR)) + return; + + switch (events.GetPhaseMask()) + { + case PHASE_MASK_MILLHOUSE_GROUP_1: + events.Reset(); + events.SetPhase(PHASE_MILLHOUSE_GROUP_2); + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + DoCast(me, SPELL_BLUR); + Talk(SAY_MILLHOUSE_EVENT_1); + me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_2, MillhousePointGroup2); + break; + case PHASE_MASK_MILLHOUSE_GROUP_2: + events.Reset(); + events.SetPhase(PHASE_MILLHOUSE_GROUP_3); + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + DoCast(me, SPELL_BLUR); + Talk(SAY_MILLHOUSE_EVENT_1); + me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_3, MillhousePointGroup3); + break; + case PHASE_MASK_MILLHOUSE_GROUP_3: + events.Reset(); + events.SetPhase(PHASE_MILLHOUSE_GROUP_4); + me->SetReactState(REACT_PASSIVE); + me->InterruptNonMeleeSpells(true); + DoCast(me, SPELL_CLEAR_ALL_DEBUFFS); + DoCast(me, SPELL_BLUR); + me->GetMotionMaster()->MovePoint(POINT_MILLHOUSE_GROUP_4, MillhousePointGroup4); + break; + default: + break; + } + + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + } + + void MovementInform(uint32 type, uint32 pointId) override + { + if (type != POINT_MOTION_TYPE) + return; + + if (pointId < POINT_MILLHOUSE_GROUP_2 || pointId > POINT_MILLHOUSE_GROUP_4) + return; + + me->RemoveAllAuras(); + me->CombatStop(true); + me->DeleteThreatList(); + + me->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + me->SetReactState(REACT_AGGRESSIVE); + + switch (pointId) + { + case POINT_MILLHOUSE_GROUP_2: + if (Creature* worldtrigger = me->FindNearestCreature(NPC_WORLDTRIGGER, 150.0f)) + me->SetFacingToObject(worldtrigger); // o: 5.497359f (sniff data) + me->CastSpell(me, SPELL_ANCHOR_HERE, true); + me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me); + events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000); + break; + case POINT_MILLHOUSE_GROUP_3: + me->SetFacingTo(5.931499f); + me->CastSpell(me, SPELL_ANCHOR_HERE, true); + me->AddAura(SPELL_TIGULE_AND_FORORS_SPECIAL_BLEND, me); + events.ScheduleEvent(EVENT_READY_FOR_COMBAT, 10000); + break; + case POINT_MILLHOUSE_GROUP_4: + me->SetFacingTo(3.455752f); + me->CastSpell(me, SPELL_ANCHOR_HERE, true); + Talk(SAY_MILLHOUSE_EVENT_2); + events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 1000); + break; + default: + break; + } + } + + void UpdateAI(uint32 diff) override + { + // Only update events if Millhouse is aggressive + if (me->GetReactState() != REACT_AGGRESSIVE) + return; + + events.Update(diff); + + // Impending Doom is exception because it needs to be interrupted. + if (me->HasUnitState(UNIT_STATE_CASTING) && !me->GetCurrentSpell(SPELL_IMPENDING_DOOM)) + return; + + while (uint32 eventId = events.ExecuteEvent()) + { + switch (eventId) + { + case EVENT_FROSTBOLT_VOLLEY: + DoCast(SPELL_FROSTBOLT_VOLLEY); + events.ScheduleEvent(EVENT_FROSTBOLT_VOLLEY, 7000); + break; + case EVENT_SHADOWFURY: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_SHADOWFURY); + events.ScheduleEvent(EVENT_SHADOWFURY, 7000); + break; + case EVENT_FEAR: + if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 0.0f, true)) + DoCast(target, SPELL_FEAR); + events.ScheduleEvent(EVENT_FEAR, 18000); + break; + case EVENT_READY_FOR_COMBAT: + me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_IN_COMBAT); + me->SetReactState(REACT_AGGRESSIVE); + ScheduleEvents(); + break; + case EVENT_CAST_IMPENDING_DOOM: + DoCast(SPELL_IMPENDING_DOOM); + DoCast(SPELL_IMPENDING_DOOM_CHANNEL); + events.ScheduleEvent(EVENT_INTERRUPT_IMPENDING_DOOM, urand(15000,20000)); + break; + case EVENT_INTERRUPT_IMPENDING_DOOM: + me->InterruptNonMeleeSpells(true); + me->RemoveAllAuras(); + me->HandleEmoteCommand(EMOTE_ONESHOT_KNOCKDOWN); + events.ScheduleEvent(EVENT_CAST_IMPENDING_DOOM, 3000); + break; + default: + break; + } + } + + DoSpellAttackIfReady(SPELL_SHADOW_BOLT); + } + + private: + InstanceScript* _instance; + EventMap events; + }; + + CreatureAI* GetAI(Creature* creature) const override + { + return GetInstanceAI<npc_sc_millhouse_manastormAI>(creature); + } +}; + +// 81459 - Force of Earth +class spell_force_of_earth : public SpellScriptLoader +{ + public: + spell_force_of_earth() : SpellScriptLoader("spell_force_of_earth") { } + + class spell_force_of_earth_SpellScript : public SpellScript + { + PrepareSpellScript(spell_force_of_earth_SpellScript); + + void DummyEffect(SpellEffIndex /*effIndex*/) + { + GetCaster()->SetDisplayId(26693); // can be moved to SAI part, need sniffs to see what this dummy does (note: npc 43552) + } + + void Register() + { + OnEffectLaunch += SpellEffectFn(spell_force_of_earth_SpellScript::DummyEffect, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_force_of_earth_SpellScript(); + } +}; + +// 45313 - Anchor Here +class spell_sc_anchor_here : public SpellScriptLoader +{ +public: + spell_sc_anchor_here() : SpellScriptLoader("spell_sc_anchor_here") { } + + class spell_sc_anchor_here_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sc_anchor_here_SpellScript); + + void HandleScript(SpellEffIndex /*effIndex*/) + { + if (Creature* creature = GetHitUnit()->ToCreature()) + creature->SetHomePosition(creature->GetPositionX(), creature->GetPositionY(), creature->GetPositionZ(), creature->GetOrientation()); + } + + void Register() override + { + OnEffectHitTarget += SpellEffectFn(spell_sc_anchor_here_SpellScript::HandleScript, EFFECT_0, SPELL_EFFECT_SCRIPT_EFFECT); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_sc_anchor_here_SpellScript(); + } +}; + +// 93167 - Twilight Documents +class spell_sc_twilight_documents : public SpellScriptLoader +{ + public: + spell_sc_twilight_documents() : SpellScriptLoader("spell_sc_twilight_documents") { } + + class spell_sc_twilight_documents_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sc_twilight_documents_SpellScript); + + bool Validate(SpellInfo const* /*spell*/) override + { + if (!sObjectMgr->GetGameObjectTemplate(GAMEOBJECT_TWILIGHT_DOCUMENTS)) + return false; + return true; + } + + void SetTarget(WorldObject*& target) + { + target = GetCaster()->FindNearestCreature(NPC_GENERIC_TRIGGER_LAB, 100.0f); + } + + void SpawnGameObject(SpellEffIndex /*effIndex*/) + { + if (WorldLocation* loc = GetHitDest()) + GetCaster()->SummonGameObject(GAMEOBJECT_TWILIGHT_DOCUMENTS, loc->GetPositionX(), loc->GetPositionY(), loc->GetPositionZ(), loc->GetOrientation(), 0, 0, 0, 0, 7200); + } + + void Register() override + { + OnObjectTargetSelect += SpellObjectTargetSelectFn(spell_sc_twilight_documents_SpellScript::SetTarget, EFFECT_0, TARGET_DEST_NEARBY_ENTRY); + OnEffectHit += SpellEffectFn(spell_sc_twilight_documents_SpellScript::SpawnGameObject, EFFECT_0, SPELL_EFFECT_DUMMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_sc_twilight_documents_SpellScript(); + } +}; + +// 81008 - Quake +class JumpCheck +{ + public: + bool operator()(WorldObject* object) const + { + Player* player = object->ToPlayer(); + return (player && player->HasUnitState(UNIT_STATE_JUMPING)); + } +}; + +class spell_sc_quake : public SpellScriptLoader +{ + public: + spell_sc_quake() : SpellScriptLoader("spell_sc_quake") { } + + class spell_sc_quake_SpellScript : public SpellScript + { + PrepareSpellScript(spell_sc_quake_SpellScript); + + void FilterTargets(std::list<WorldObject*>& unitList) + { + unitList.remove_if(JumpCheck()); + } + + void Register() override + { + OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sc_quake_SpellScript::FilterTargets, EFFECT_0, TARGET_UNIT_SRC_AREA_ENEMY); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_sc_quake_SpellScript(); + } +}; + +class at_sc_corborus_intro : public AreaTriggerScript +{ +public: + at_sc_corborus_intro() : AreaTriggerScript("at_sc_corborus_intro") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + { + if (InstanceScript* instance = player->GetInstanceScript()) + if (Creature* corborus = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_CORBORUS))) + corborus->AI()->DoAction(ACTION_CORBORUS_INTRO); + return true; + } +}; + +class at_sc_slabhide_intro : public AreaTriggerScript +{ +public: + at_sc_slabhide_intro() : AreaTriggerScript("at_sc_slabhide_intro") { } + + bool OnTrigger(Player* player, AreaTriggerEntry const* /*areaTrigger*/) override + { + if (InstanceScript* instance = player->GetInstanceScript()) + if (Creature* slabhide = ObjectAccessor::GetCreature(*player, instance->GetGuidData(DATA_SLABHIDE))) + slabhide->AI()->DoAction(ACTION_SLABHIDE_INTRO); + return true; + } +}; + +void AddSC_stonecore() +{ + new npc_sc_millhouse_manastorm(); + new spell_force_of_earth(); + new spell_sc_anchor_here(); + new spell_sc_twilight_documents(); + new spell_sc_quake(); + new at_sc_corborus_intro(); + new at_sc_slabhide_intro(); +} diff --git a/src/server/scripts/Maelstrom/Stonecore/stonecore.h b/src/server/scripts/Maelstrom/Stonecore/stonecore.h new file mode 100644 index 00000000000..98a9878e0d3 --- /dev/null +++ b/src/server/scripts/Maelstrom/Stonecore/stonecore.h @@ -0,0 +1,72 @@ +/* +* Copyright (C) 2008-2014 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/>. +*/ + +#ifndef DEF_STONECORE_H +#define DEF_STONECORE_H + +#define SCScriptName "instance_stonecore" +#define DataHeader "SC" + +enum DataTypes +{ + // Encounter States/Boss GUIDs + DATA_CORBORUS, + DATA_SLABHIDE, + DATA_OZRUK, + DATA_HIGH_PRIESTESS_AZIL, + + // Additional Data + DATA_MILLHOUSE_MANASTORM, + DATA_MILLHOUSE_EVENT_FACE, + DATA_MILLHOUSE_EVENT_KNOCKBACK, + DATA_MILLHOUSE_EVENT_DESPAWN, + + DATA_SLABHIDE_INTRO, + DATA_SLABHIDE_ROCK_WALL, +}; + +enum Misc +{ + ACTION_CORBORUS_INTRO, + ACTION_SLABHIDE_INTRO, + + NPC_WORLDTRIGGER = 22515, + NPC_MILLHOUSE_MANASTORM = 43391, + + NPC_CORBORUS = 43438, + NPC_SLABHIDE = 43214, + NPC_OZRUK = 42188, + NPC_HIGH_PRIESTESS_AZIL = 42333, + + // Stonecore Teleporter misc + MAX_STONECORE_TELEPORTERS = 2, + NPC_STONECORE_TELEPORTER = 51396, // Entrance teleporter + NPC_STONECORE_TELEPORTER_2 = 51397, // Slabhide teleporter + SPELL_TELEPORTER_ACTIVE_VISUAL = 95298, + + GAMEOBJECT_TWILIGHT_DOCUMENTS = 207415, + GAMEOBJECT_CORBORUS_ROCKDOOR = 207343, + GAMEOBJECT_SLABHIDE_ROCK_WALL = 204381, + + SPELL_RING_WYRM_KNOCKBACK = 81235, + + // Creature Formation IDs + CREATURE_FORMATION_MILLHOUSE_EVENT_TRASH = 340418, + CREATURE_FORMATION_MILLHOUSE_EVENT_LAST_GROUP = 340492, +}; + +#endif // DEF_STONECORE diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp index 5e8273dce67..cdbbf755390 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/instance_ulduar.cpp @@ -83,6 +83,7 @@ class instance_ulduar : public InstanceMapScript IsDriveMeCrazyEligible = true; _algalonSummoned = false; _summonAlgalon = false; + _CoUAchivePlayerDeathMask = 0; memset(_summonObservationRingKeeper, 0, sizeof(_summonObservationRingKeeper)); memset(_summonYSKeeper, 0, sizeof(_summonYSKeeper)); @@ -592,6 +593,19 @@ class instance_ulduar : public InstanceMapScript void OnUnitDeath(Unit* unit) override { + // Champion/Conqueror of Ulduar + if (unit->GetTypeId() == TYPEID_PLAYER) + { + for (uint8 i = 0; i < BOSS_ALGALON; i++) + { + if (GetBossState(i) == IN_PROGRESS) + { + _CoUAchivePlayerDeathMask |= (1 << i); + SaveToDB(); + } + } + } + Creature* creature = unit->ToCreature(); if (!creature) return; @@ -1007,6 +1021,45 @@ class instance_ulduar : public InstanceMapScript case CRITERIA_ALONE_IN_THE_DARKNESS_10: case CRITERIA_ALONE_IN_THE_DARKNESS_25: return keepersCount == 0; + case CRITERIA_C_O_U_LEVIATHAN_10: + case CRITERIA_C_O_U_LEVIATHAN_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_LEVIATHAN)) == 0; + case CRITERIA_C_O_U_IGNIS_10: + case CRITERIA_C_O_U_IGNIS_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_IGNIS)) == 0; + case CRITERIA_C_O_U_RAZORSCALE_10: + case CRITERIA_C_O_U_RAZORSCALE_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_RAZORSCALE)) == 0; + case CRITERIA_C_O_U_XT002_10: + case CRITERIA_C_O_U_XT002_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_XT002)) == 0; + case CRITERIA_C_O_U_IRON_COUNCIL_10: + case CRITERIA_C_O_U_IRON_COUNCIL_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_ASSEMBLY_OF_IRON)) == 0; + case CRITERIA_C_O_U_KOLOGARN_10: + case CRITERIA_C_O_U_KOLOGARN_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_KOLOGARN)) == 0; + case CRITERIA_C_O_U_AURIAYA_10: + case CRITERIA_C_O_U_AURIAYA_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_AURIAYA)) == 0; + case CRITERIA_C_O_U_HODIR_10: + case CRITERIA_C_O_U_HODIR_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_HODIR)) == 0; + case CRITERIA_C_O_U_THORIM_10: + case CRITERIA_C_O_U_THORIM_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_THORIM)) == 0; + case CRITERIA_C_O_U_FREYA_10: + case CRITERIA_C_O_U_FREYA_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_FREYA)) == 0; + case CRITERIA_C_O_U_MIMIRON_10: + case CRITERIA_C_O_U_MIMIRON_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_MIMIRON)) == 0; + case CRITERIA_C_O_U_VEZAX_10: + case CRITERIA_C_O_U_VEZAX_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_VEZAX)) == 0; + case CRITERIA_C_O_U_YOGG_SARON_10: + case CRITERIA_C_O_U_YOGG_SARON_25: + return (_CoUAchivePlayerDeathMask & (1 << BOSS_YOGG_SARON)) == 0; } return false; @@ -1018,6 +1071,8 @@ class instance_ulduar : public InstanceMapScript for (uint8 i = 0; i < 4; ++i) data << ' ' << uint32(!KeeperGUIDs[i].IsEmpty() ? 1 : 0); + + data << ' ' << _CoUAchivePlayerDeathMask; } void ReadSaveDataMore(std::istringstream& data) override @@ -1056,6 +1111,8 @@ class instance_ulduar : public InstanceMapScript _summonObservationRingKeeper[2] = true; if (GetBossState(BOSS_MIMIRON) == DONE && !_summonYSKeeper[3]) _summonObservationRingKeeper[3] = true; + + data >> _CoUAchivePlayerDeathMask; } void Update(uint32 diff) override @@ -1095,6 +1152,7 @@ class instance_ulduar : public InstanceMapScript bool _summonYSKeeper[4]; uint32 _maxArmorItemLevel; uint32 _maxWeaponItemLevel; + uint32 _CoUAchivePlayerDeathMask; }; InstanceScript* GetInstanceScript(InstanceMap* map) const override diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h index 82c4ef140f1..1b4330b0faf 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/ulduar.h @@ -36,16 +36,16 @@ enum UlduarBosses BOSS_ASSEMBLY_OF_IRON = 4, BOSS_KOLOGARN = 5, BOSS_AURIAYA = 6, - BOSS_MIMIRON = 7, - BOSS_HODIR = 8, - BOSS_THORIM = 9, - BOSS_FREYA = 10, - BOSS_BRIGHTLEAF = 11, - BOSS_IRONBRANCH = 12, - BOSS_STONEBARK = 13, - BOSS_VEZAX = 14, - BOSS_YOGG_SARON = 15, - BOSS_ALGALON = 16, + BOSS_HODIR = 7, + BOSS_THORIM = 8, + BOSS_FREYA = 9, + BOSS_MIMIRON = 10, + BOSS_VEZAX = 11, + BOSS_YOGG_SARON = 12, + BOSS_ALGALON = 13, + BOSS_BRIGHTLEAF = 14, + BOSS_IRONBRANCH = 15, + BOSS_STONEBARK = 16, }; enum UlduarNPCs @@ -295,6 +295,35 @@ enum UlduarAchievementCriteriaIds CRITERIA_ALONE_IN_THE_DARKNESS_10 = 10412, CRITERIA_ALONE_IN_THE_DARKNESS_25 = 10417, CRITERIA_HERALD_OF_TITANS = 10678, + + // Champion of Ulduar + CRITERIA_C_O_U_LEVIATHAN_10 = 10042, + CRITERIA_C_O_U_IGNIS_10 = 10342, + CRITERIA_C_O_U_RAZORSCALE_10 = 10340, + CRITERIA_C_O_U_XT002_10 = 10341, + CRITERIA_C_O_U_IRON_COUNCIL_10 = 10598, + CRITERIA_C_O_U_KOLOGARN_10 = 10348, + CRITERIA_C_O_U_AURIAYA_10 = 10351, + CRITERIA_C_O_U_HODIR_10 = 10439, + CRITERIA_C_O_U_THORIM_10 = 10403, + CRITERIA_C_O_U_FREYA_10 = 10582, + CRITERIA_C_O_U_MIMIRON_10 = 10347, + CRITERIA_C_O_U_VEZAX_10 = 10349, + CRITERIA_C_O_U_YOGG_SARON_10 = 10350, + // Conqueror of Ulduar + CRITERIA_C_O_U_LEVIATHAN_25 = 10352, + CRITERIA_C_O_U_IGNIS_25 = 10355, + CRITERIA_C_O_U_RAZORSCALE_25 = 10353, + CRITERIA_C_O_U_XT002_25 = 10354, + CRITERIA_C_O_U_IRON_COUNCIL_25 = 10599, + CRITERIA_C_O_U_KOLOGARN_25 = 10357, + CRITERIA_C_O_U_AURIAYA_25 = 10363, + CRITERIA_C_O_U_HODIR_25 = 10719, + CRITERIA_C_O_U_THORIM_25 = 10404, + CRITERIA_C_O_U_FREYA_25 = 10583, + CRITERIA_C_O_U_MIMIRON_25 = 10361, + CRITERIA_C_O_U_VEZAX_25 = 10362, + CRITERIA_C_O_U_YOGG_SARON_25 = 10364 }; enum UlduarData diff --git a/src/server/shared/CMakeLists.txt b/src/server/shared/CMakeLists.txt index 7a02e415d69..1ad85acb601 100644 --- a/src/server/shared/CMakeLists.txt +++ b/src/server/shared/CMakeLists.txt @@ -20,6 +20,7 @@ file(GLOB_RECURSE sources_Dynamic Dynamic/*.cpp Dynamic/*.h) file(GLOB_RECURSE sources_Logging Logging/*.cpp Logging/*.h) file(GLOB_RECURSE sources_Networking Networking/*.cpp Networking/*.h) file(GLOB_RECURSE sources_Packets Packets/*.cpp Packets/*.h) +file(GLOB_RECURSE sources_Realm Realm/*.cpp Realm/*.h) file(GLOB_RECURSE sources_Threading Threading/*.cpp Threading/*.h) file(GLOB_RECURSE sources_Utilities Utilities/*.cpp Utilities/*.h) @@ -50,6 +51,7 @@ set(shared_STAT_SRCS ${sources_Logging} ${sources_Networking} ${sources_Packets} + ${sources_Realm} ${sources_Threading} ${sources_Utilities} ${sources_localdir} @@ -72,6 +74,7 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/Logging ${CMAKE_CURRENT_SOURCE_DIR}/Networking ${CMAKE_CURRENT_SOURCE_DIR}/Packets + ${CMAKE_CURRENT_SOURCE_DIR}/Realm ${CMAKE_CURRENT_SOURCE_DIR}/Threading ${CMAKE_CURRENT_SOURCE_DIR}/Utilities ${CMAKE_SOURCE_DIR}/src/server/game/Entities/Object diff --git a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp index 69198c18df0..b84de24741c 100644 --- a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.cpp @@ -29,12 +29,17 @@ WorldPacketCrypt::WorldPacketCrypt() : PacketCrypt(SHA_DIGEST_LENGTH) void WorldPacketCrypt::Init(BigNumber* K) { uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0x08, 0xF1, 0x95, 0x9F, 0x47, 0xE5, 0xD2, 0xDB, 0xA1, 0x3D, 0x77, 0x8F, 0x3F, 0x3E, 0xE7, 0x00 }; - HmacSha1 serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey); - uint8 *encryptHash = serverEncryptHmac.ComputeHash(K); - uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0x40, 0xAA, 0xD3, 0x92, 0x26, 0x71, 0x43, 0x47, 0x3A, 0x31, 0x08, 0xA6, 0xE7, 0xDC, 0x98, 0x2A }; - HmacSha1 clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey); - uint8 *decryptHash = clientDecryptHmac.ComputeHash(K); + Init(K, ServerEncryptionKey, ServerDecryptionKey); +} + +void WorldPacketCrypt::Init(BigNumber* k, uint8 const* serverKey, uint8 const* clientKey) +{ + HmacSha1 serverEncryptHmac(SEED_KEY_SIZE, (uint8*)serverKey); + uint8 *encryptHash = serverEncryptHmac.ComputeHash(k); + + HmacSha1 clientDecryptHmac(SEED_KEY_SIZE, (uint8*)clientKey); + uint8 *decryptHash = clientDecryptHmac.ComputeHash(k); _clientDecrypt.Init(decryptHash); _serverEncrypt.Init(encryptHash); diff --git a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h index 7ccca11f09d..58c4003418e 100644 --- a/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h +++ b/src/server/shared/Cryptography/Authentication/WorldPacketCrypt.h @@ -29,6 +29,7 @@ class WorldPacketCrypt : public PacketCrypt WorldPacketCrypt(); void Init(BigNumber* K) override; + void Init(BigNumber* k, uint8 const* serverKey, uint8 const* clientKey); }; #endif // _WORLDPACKETCRYPT_H diff --git a/src/server/shared/Database/Field.cpp b/src/server/shared/Database/Field.cpp index f1741f98cc3..da547d3a151 100644 --- a/src/server/shared/Database/Field.cpp +++ b/src/server/shared/Database/Field.cpp @@ -46,7 +46,7 @@ void Field::SetByteValue(const void* newValue, const size_t newSize, enum_field_ data.raw = true; } -void Field::SetStructuredValue(char* newValue, enum_field_types newType, uint32 length, bool isBinary) +void Field::SetStructuredValue(char* newValue, enum_field_types newType, uint32 length) { if (data.value) CleanUp(); @@ -54,15 +54,9 @@ void Field::SetStructuredValue(char* newValue, enum_field_types newType, uint32 // This value stores somewhat structured data that needs function style casting if (newValue) { - if (!isBinary) - { - data.value = new char[length + 1]; - *(reinterpret_cast<char*>(data.value) + length) = '\0'; - } - else - data.value = new char[length]; - + data.value = new char[length + 1]; memcpy(data.value, newValue, length); + *(reinterpret_cast<char*>(data.value) + length) = '\0'; data.length = length; } diff --git a/src/server/shared/Database/Field.h b/src/server/shared/Database/Field.h index 99f98572a56..352db10c539 100644 --- a/src/server/shared/Database/Field.h +++ b/src/server/shared/Database/Field.h @@ -239,9 +239,11 @@ class Field { char const* string = GetCString(); if (!string) - string = ""; + return ""; + return std::string(string, data.length); } + return std::string((char*)data.value, data.length); } @@ -284,7 +286,7 @@ class Field #endif void SetByteValue(void const* newValue, size_t const newSize, enum_field_types newType, uint32 length); - void SetStructuredValue(char* newValue, enum_field_types newType, uint32 length, bool isBinary); + void SetStructuredValue(char* newValue, enum_field_types newType, uint32 length); void CleanUp() { diff --git a/src/server/shared/Database/PreparedStatement.cpp b/src/server/shared/Database/PreparedStatement.cpp index 1f036b5bf0a..3ea3c969a4c 100644 --- a/src/server/shared/Database/PreparedStatement.cpp +++ b/src/server/shared/Database/PreparedStatement.cpp @@ -72,6 +72,7 @@ void PreparedStatement::BindParameters() break; case TYPE_BINARY: m_stmt->setBinary(i, statement_data[i].binary, false); + break; case TYPE_NULL: m_stmt->setNull(i); break; @@ -357,7 +358,7 @@ void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint m_paramsSet[index] = true; MYSQL_BIND* param = &m_bind[index]; size_t len = value.size(); - param->buffer_type = MYSQL_TYPE_VAR_STRING; + param->buffer_type = MYSQL_TYPE_BLOB; delete [] static_cast<char *>(param->buffer); param->buffer = new char[len]; param->buffer_length = len; @@ -365,7 +366,10 @@ void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint delete param->length; param->length = new unsigned long(len); if (isString) + { *param->length -= 1; + param->buffer_type = MYSQL_TYPE_VAR_STRING; + } memcpy(param->buffer, value.data(), len); } diff --git a/src/server/shared/Database/QueryResult.cpp b/src/server/shared/Database/QueryResult.cpp index a6d9c64622a..154cf5cda41 100644 --- a/src/server/shared/Database/QueryResult.cpp +++ b/src/server/shared/Database/QueryResult.cpp @@ -172,7 +172,7 @@ bool ResultSet::NextRow() } for (uint32 i = 0; i < _fieldCount; i++) - _currentRow[i].SetStructuredValue(row[i], _fields[i].type, lengths[i], (_fields[i].flags & BINARY_FLAG) != 0); + _currentRow[i].SetStructuredValue(row[i], _fields[i].type, lengths[i]); return true; } diff --git a/src/server/shared/Networking/SocketMgr.h b/src/server/shared/Networking/SocketMgr.h index dbe2b8ec902..92c16d96882 100644 --- a/src/server/shared/Networking/SocketMgr.h +++ b/src/server/shared/Networking/SocketMgr.h @@ -33,6 +33,7 @@ class SocketMgr public: virtual ~SocketMgr() { + delete _acceptor; delete[] _threads; } diff --git a/src/server/shared/Realm/Realm.cpp b/src/server/shared/Realm/Realm.cpp new file mode 100644 index 00000000000..79b10843773 --- /dev/null +++ b/src/server/shared/Realm/Realm.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2008-2014 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 "Realm.h" + +ip::tcp::endpoint Realm::GetAddressForClient(ip::address const& clientAddr) const +{ + ip::address realmIp; + + // Attempt to send best address for client + if (clientAddr.is_loopback()) + { + // Try guessing if realm is also connected locally + if (LocalAddress.is_loopback() || ExternalAddress.is_loopback()) + realmIp = clientAddr; + else + { + // Assume that user connecting from the machine that bnetserver is located on + // has all realms available in his local network + realmIp = LocalAddress; + } + } + else + { + if (clientAddr.is_v4() && + (clientAddr.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong()) == + (LocalAddress.to_v4().to_ulong() & LocalSubnetMask.to_v4().to_ulong())) + { + realmIp = LocalAddress; + } + else + realmIp = ExternalAddress; + } + + ip::tcp::endpoint endpoint(realmIp, Port); + + // Return external IP + return endpoint; +} diff --git a/src/server/shared/Realm/Realm.h b/src/server/shared/Realm/Realm.h new file mode 100644 index 00000000000..9476f137947 --- /dev/null +++ b/src/server/shared/Realm/Realm.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2008-2014 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/>. + */ + +#ifndef Realm_h__ +#define Realm_h__ + +#include "Common.h" +#include <boost/asio/ip/address.hpp> +#include <boost/asio/ip/tcp.hpp> + +using namespace boost::asio; + +enum RealmFlags +{ + REALM_FLAG_NONE = 0x00, + REALM_FLAG_INVALID = 0x01, + REALM_FLAG_OFFLINE = 0x02, + REALM_FLAG_SPECIFYBUILD = 0x04, + REALM_FLAG_UNK1 = 0x08, + REALM_FLAG_UNK2 = 0x10, + REALM_FLAG_RECOMMENDED = 0x20, + REALM_FLAG_NEW = 0x40, + REALM_FLAG_FULL = 0x80 +}; + +#pragma pack(push, 1) + +namespace Battlenet +{ + struct RealmHandle; + + struct RealmId + { + RealmId() : Region(0), Battlegroup(0), Index(0), Build(0) { } + RealmId(uint8 region, uint8 battlegroup, uint32 index, uint32 build) + : Region(region), Battlegroup(battlegroup), Index(index), Build(build) { } + + uint8 Region; + uint8 Battlegroup; + uint32 Index; + uint32 Build; + + bool operator<(RealmId const& r) const + { + return memcmp(this, &r, sizeof(RealmId) - sizeof(Build)) < 0; + } + }; +} + +#pragma pack(pop) + +// Storage object for a realm +struct Realm +{ + Battlenet::RealmId Id; + ip::address ExternalAddress; + ip::address LocalAddress; + ip::address LocalSubnetMask; + uint16 Port; + std::string Name; + uint8 Type; + RealmFlags Flags; + uint8 Timezone; + AccountTypes AllowedSecurityLevel; + float PopulationLevel; + bool Updated; + bool Keep; + + ip::tcp::endpoint GetAddressForClient(ip::address const& clientAddr) const; +}; + +#endif // Realm_h__ diff --git a/src/server/worldserver/Main.cpp b/src/server/worldserver/Main.cpp index c5127b8f3e2..821e1f5bd83 100644 --- a/src/server/worldserver/Main.cpp +++ b/src/server/worldserver/Main.cpp @@ -30,7 +30,6 @@ #include "OpenSSLCrypto.h" #include "ProcessPriority.h" #include "BigNumber.h" -#include "RealmList.h" #include "World.h" #include "MapManager.h" #include "InstanceSaveMgr.h" @@ -44,6 +43,7 @@ #include "WorldSocket.h" #include "WorldSocketMgr.h" #include "BattlenetServerManager.h" +#include "Realm/Realm.h" #include <openssl/opensslv.h> #include <openssl/crypto.h> #include <boost/asio/io_service.hpp> @@ -82,6 +82,7 @@ WorldDatabaseWorkerPool WorldDatabase; ///< Accessor to the CharacterDatabaseWorkerPool CharacterDatabase; ///< Accessor to the character database LoginDatabaseWorkerPool LoginDatabase; ///< Accessor to the realm/login database Battlenet::RealmHandle realmHandle; ///< Id of the realm +Realm realm; void SignalHandler(const boost::system::error_code& error, int signalNumber); void FreezeDetectorHandler(const boost::system::error_code& error); @@ -92,6 +93,7 @@ void WorldUpdateLoop(); void ClearOnlineAccounts(); void ShutdownCLIThread(std::thread* cliThread); void ShutdownThreadPool(std::vector<std::thread>& threadPool); +bool LoadRealmInfo(); variables_map GetConsoleArguments(int argc, char** argv, std::string& cfg_file, std::string& cfg_service); /// Launch the Trinity server @@ -192,6 +194,8 @@ extern int main(int argc, char** argv) // Set server offline (not connectable) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = (flag & ~%u) | %u WHERE id = '%d'", REALM_FLAG_OFFLINE, REALM_FLAG_INVALID, realmHandle.Index); + LoadRealmInfo(); + // Initialize the World sWorld->SetInitialWorldSettings(); @@ -226,6 +230,8 @@ extern int main(int argc, char** argv) // Set server online (allow connecting now) LoginDatabase.DirectPExecute("UPDATE realmlist SET flag = flag & ~%u, population = 0 WHERE id = '%u'", REALM_FLAG_INVALID, realmHandle.Index); + realm.PopulationLevel = 0.0f; + realm.Flags = RealmFlags(realm.Flags & ~uint32(REALM_FLAG_INVALID)); // Start the freeze check callback cycle in 5 seconds (cycle itself is 1 sec) if (int coreStuckTime = sConfigMgr->GetIntDefault("MaxCoreStuckTime", 0)) @@ -452,6 +458,62 @@ AsyncAcceptor* StartRaSocketAcceptor(boost::asio::io_service& ioService) return acceptor; } +bool LoadRealmInfo() +{ + boost::asio::ip::tcp::resolver resolver(_ioService); + boost::asio::ip::tcp::resolver::iterator end; + + QueryResult result = LoginDatabase.PQuery("SELECT id, name, address, localAddress, localSubnetMask, port, icon, flag, timezone, allowedSecurityLevel, population, gamebuild, Region, Battlegroup FROM realmlist WHERE id = %u", realmHandle.Index); + if (!result) + return false; + + Field* fields = result->Fetch(); + realm.Name = fields[1].GetString(); + boost::asio::ip::tcp::resolver::query externalAddressQuery(ip::tcp::v4(), fields[2].GetString(), ""); + + boost::system::error_code ec; + boost::asio::ip::tcp::resolver::iterator endPoint = resolver.resolve(externalAddressQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.worldserver", "Could not resolve address %s", fields[2].GetString().c_str()); + return false; + } + + realm.ExternalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localAddressQuery(ip::tcp::v4(), fields[3].GetString(), ""); + endPoint = resolver.resolve(localAddressQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.worldserver", "Could not resolve address %s", fields[3].GetString().c_str()); + return false; + } + + realm.LocalAddress = (*endPoint).endpoint().address(); + + boost::asio::ip::tcp::resolver::query localSubmaskQuery(ip::tcp::v4(), fields[4].GetString(), ""); + endPoint = resolver.resolve(localSubmaskQuery, ec); + if (endPoint == end || ec) + { + TC_LOG_ERROR("server.worldserver", "Could not resolve address %s", fields[4].GetString().c_str()); + return false; + } + + realm.LocalSubnetMask = (*endPoint).endpoint().address(); + + realm.Port = fields[5].GetUInt16(); + realm.Type = fields[6].GetUInt8(); + realm.Flags = RealmFlags(fields[7].GetUInt8()); + realm.Timezone = fields[8].GetUInt8(); + realm.AllowedSecurityLevel = AccountTypes(fields[9].GetUInt8()); + realm.PopulationLevel = fields[10].GetFloat(); + realm.Id.Index = fields[0].GetUInt32(); + realm.Id.Build = fields[11].GetUInt32(); + realm.Id.Region = fields[12].GetUInt8(); + realm.Id.Battlegroup = fields[13].GetUInt8(); + return true; +} + /// Initialize connection to the databases bool StartDB() { diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 4d40365451e..e4406e7ecce 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -141,6 +141,13 @@ MaxPingTime = 30 WorldServerPort = 8085 # +# InstanceServerPort +# Description: TCP port to for second world connection. +# Default: 8086 + +InstanceServerPort = 8086 + +# # BindIP # Description: Bind world server to IP/hostname. # Default: "0.0.0.0" - (Bind to all IPs on the system) @@ -2258,9 +2265,9 @@ Arena.QueueAnnouncer.Enable = 0 # # Arena.ArenaSeason.ID # Description: Current arena season id shown in clients. -# Default: 8 +# Default: 15 -Arena.ArenaSeason.ID = 8 +Arena.ArenaSeason.ID = 15 # # Arena.ArenaSeason.InProgress |