diff options
31 files changed, 437 insertions, 82 deletions
diff --git a/sql/updates/world/2014_05_23_00_world_spell_script_names.sql b/sql/updates/world/2014_05_23_00_world_spell_script_names.sql new file mode 100644 index 00000000000..22d792e6f72 --- /dev/null +++ b/sql/updates/world/2014_05_23_00_world_spell_script_names.sql @@ -0,0 +1,3 @@ +DELETE FROM `spell_script_names` WHERE `spell_id`=69232; +INSERT INTO `spell_script_names` (`spell_id`,`ScriptName`) VALUES +(69232,'spell_tyrannus_rimefang_icy_blast'); diff --git a/sql/updates/world/2014_05_23_01_world_trinity_string.sql b/sql/updates/world/2014_05_23_01_world_trinity_string.sql new file mode 100644 index 00000000000..e05d36f601c --- /dev/null +++ b/sql/updates/world/2014_05_23_01_world_trinity_string.sql @@ -0,0 +1,3 @@ +DELETE FROM `trinity_string` WHERE `entry`=11008; +INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES +(11008, 'InhabitType: %u'); diff --git a/src/server/collision/Maps/MapTree.cpp b/src/server/collision/Maps/MapTree.cpp index bb57079c389..d592d795125 100644 --- a/src/server/collision/Maps/MapTree.cpp +++ b/src/server/collision/Maps/MapTree.cpp @@ -157,8 +157,7 @@ namespace VMAP { float maxDist = (pos2 - pos1).magnitude(); // return false if distance is over max float, in case of cheater teleporting to the end of the universe - if (maxDist == std::numeric_limits<float>::max() || - maxDist == std::numeric_limits<float>::infinity()) + if (maxDist == std::numeric_limits<float>::max() || !std::isfinite(maxDist)) return false; // valid map coords should *never ever* produce float overflow, but this would produce NaNs too diff --git a/src/server/collision/Models/GameObjectModel.cpp b/src/server/collision/Models/GameObjectModel.cpp index 1b99e282132..de97943bb37 100644 --- a/src/server/collision/Models/GameObjectModel.cpp +++ b/src/server/collision/Models/GameObjectModel.cpp @@ -140,6 +140,7 @@ bool GameObjectModel::initialize(const GameObject& go, const GameObjectDisplayIn } #endif + owner = &go; return true; } @@ -161,7 +162,7 @@ GameObjectModel* GameObjectModel::Create(const GameObject& go) bool GameObjectModel::intersectRay(const G3D::Ray& ray, float& MaxDist, bool StopAtFirstHit, uint32 ph_mask) const { - if (!(phasemask & ph_mask)) + if (!(phasemask & ph_mask) || !owner->isSpawned()) return false; float time = ray.intersectionTime(iBound); diff --git a/src/server/collision/Models/GameObjectModel.h b/src/server/collision/Models/GameObjectModel.h index 6088b924343..99c9b1337b3 100644 --- a/src/server/collision/Models/GameObjectModel.h +++ b/src/server/collision/Models/GameObjectModel.h @@ -44,8 +44,9 @@ class GameObjectModel /*, public Intersectable*/ float iInvScale; float iScale; VMAP::WorldModel* iModel; + GameObject const* owner; - GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(NULL) { } + GameObjectModel() : phasemask(0), iInvScale(0), iScale(0), iModel(NULL), owner(NULL) { } bool initialize(const GameObject& go, const GameObjectDisplayInfoEntry& info); public: diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 5957eeefd7e..97fe3b80f10 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -3461,16 +3461,10 @@ void SmartScript::OnInitialize(WorldObject* obj, AreaTriggerEntry const* at) void SmartScript::OnMoveInLineOfSight(Unit* who) { - ProcessEventsFor(SMART_EVENT_OOC_LOS, who); - if (!me) return; - if (me->GetVictim()) - return; - - ProcessEventsFor(SMART_EVENT_IC_LOS, who); - + ProcessEventsFor(me->IsInCombat() ? SMART_EVENT_IC_LOS : SMART_EVENT_OOC_LOS, who); } /* diff --git a/src/server/game/Battlefield/Battlefield.cpp b/src/server/game/Battlefield/Battlefield.cpp index a136ed8a438..a797f6109ca 100644 --- a/src/server/game/Battlefield/Battlefield.cpp +++ b/src/server/game/Battlefield/Battlefield.cpp @@ -55,7 +55,7 @@ Battlefield::Battlefield() m_uiKickAfkPlayersTimer = 1000; - m_LastResurectTimer = 30 * IN_MILLISECONDS; + m_LastResurrectTimer = 30 * IN_MILLISECONDS; m_StartGroupingTimer = 0; m_StartGrouping = false; StalkerGuid = 0; @@ -185,15 +185,15 @@ bool Battlefield::Update(uint32 diff) } - if (m_LastResurectTimer <= diff) + if (m_LastResurrectTimer <= diff) { for (uint8 i = 0; i < m_GraveyardList.size(); i++) if (GetGraveyardById(i)) m_GraveyardList[i]->Resurrect(); - m_LastResurectTimer = RESURRECTION_INTERVAL; + m_LastResurrectTimer = RESURRECTION_INTERVAL; } else - m_LastResurectTimer -= diff; + m_LastResurrectTimer -= diff; return objective_changed; } @@ -634,7 +634,7 @@ void Battlefield::RemovePlayerFromResurrectQueue(uint64 playerGuid) void Battlefield::SendAreaSpiritHealerQueryOpcode(Player* player, uint64 guid) { WorldPacket data(SMSG_AREA_SPIRIT_HEALER_TIME, 12); - uint32 time = m_LastResurectTimer; // resurrect every 30 seconds + uint32 time = m_LastResurrectTimer; // resurrect every 30 seconds data << guid << time; ASSERT(player && player->GetSession()); @@ -713,7 +713,7 @@ void BfGraveyard::Resurrect() if (Creature* spirit = m_Bf->GetCreature(m_SpiritGuide[m_ControlTeam])) spirit->CastSpell(spirit, SPELL_SPIRIT_HEAL, true); - // Resurect player + // Resurrect player player->CastSpell(player, SPELL_RESURRECTION_VISUAL, true); player->ResurrectPlayer(1.0f); player->CastSpell(player, 6962, true); diff --git a/src/server/game/Battlefield/Battlefield.h b/src/server/game/Battlefield/Battlefield.h index 4e2e28f124c..1b142d1c89f 100644 --- a/src/server/game/Battlefield/Battlefield.h +++ b/src/server/game/Battlefield/Battlefield.h @@ -174,7 +174,7 @@ class BfGraveyard // Check if this graveyard has a spirit guide bool HasNpc(uint64 guid); - // Check if a player is in this graveyard's ressurect queue + // Check if a player is in this graveyard's resurrect queue bool HasPlayer(uint64 guid) { return m_ResurrectQueue.find(guid) != m_ResurrectQueue.end(); } // Get the graveyard's ID. @@ -387,7 +387,7 @@ class Battlefield : public ZoneScript // Graveyard variables GraveyardVect m_GraveyardList; // Vector witch contain the different GY of the battle - uint32 m_LastResurectTimer; // Timer for resurect player every 30 sec + uint32 m_LastResurrectTimer; // Timer for resurrect player every 30 sec uint32 m_StartGroupingTimer; // Timer for invite players in area 15 minute before start battle bool m_StartGrouping; // bool for know if all players in area has been invited diff --git a/src/server/game/Battlegrounds/Battleground.cpp b/src/server/game/Battlegrounds/Battleground.cpp index 24e01cf5b37..dff99280e73 100644 --- a/src/server/game/Battlegrounds/Battleground.cpp +++ b/src/server/game/Battlegrounds/Battleground.cpp @@ -273,7 +273,7 @@ void Battleground::Update(uint32 diff) } else { - _ProcessRessurect(diff); + _ProcessResurrect(diff); if (sBattlegroundMgr->GetPrematureFinishTime() && (GetPlayersCountByTeam(ALLIANCE) < GetMinPlayersPerTeam() || GetPlayersCountByTeam(HORDE) < GetMinPlayersPerTeam())) _ProcessProgress(diff); else if (m_PrematureCountDown) @@ -342,10 +342,10 @@ inline void Battleground::_ProcessOfflineQueue() } } -inline void Battleground::_ProcessRessurect(uint32 diff) +inline void Battleground::_ProcessResurrect(uint32 diff) { // ********************************************************* - // *** BATTLEGROUND RESSURECTION SYSTEM *** + // *** BATTLEGROUND RESURRECTION SYSTEM *** // ********************************************************* // this should be handled by spell system m_LastResurrectTime += diff; diff --git a/src/server/game/Battlegrounds/Battleground.h b/src/server/game/Battlegrounds/Battleground.h index 2feb15e2ee6..205d03c1e61 100644 --- a/src/server/game/Battlegrounds/Battleground.h +++ b/src/server/game/Battlegrounds/Battleground.h @@ -561,7 +561,7 @@ class Battleground Player* _GetPlayerForTeam(uint32 teamId, BattlegroundPlayerMap::const_iterator itr, const char* context) const; void _ProcessOfflineQueue(); - void _ProcessRessurect(uint32 diff); + void _ProcessResurrect(uint32 diff); void _ProcessProgress(uint32 diff); void _ProcessLeave(uint32 diff); void _ProcessJoin(uint32 diff); diff --git a/src/server/game/Chat/Channels/Channel.h b/src/server/game/Chat/Channels/Channel.h index 9ad6877d929..115e340762e 100644 --- a/src/server/game/Chat/Channels/Channel.h +++ b/src/server/game/Chat/Channels/Channel.h @@ -25,7 +25,7 @@ #include "Common.h" -#include "Opcodes.h" +#include "WorldSession.h" #include "WorldPacket.h" class Player; diff --git a/src/server/game/Entities/GameObject/GameObject.cpp b/src/server/game/Entities/GameObject/GameObject.cpp index d9304752e73..d6a029d29bf 100644 --- a/src/server/game/Entities/GameObject/GameObject.cpp +++ b/src/server/game/Entities/GameObject/GameObject.cpp @@ -2014,6 +2014,10 @@ void GameObject::SetLootState(LootState state, Unit* unit) m_lootStateUnitGUID = unit ? unit->GetGUID() : 0; AI()->OnStateChanged(state, unit); sScriptMgr->OnGameObjectLootStateChanged(this, state, unit); + + if (GetGoType() == GAMEOBJECT_TYPE_DOOR) // only set collision for doors on SetGoState + return; + if (m_model) { bool collision = false; diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a8434bb515e..f5c6d12a341 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -7804,6 +7804,19 @@ void Player::UpdateArea(uint32 newArea) else RemoveByteFlag(UNIT_FIELD_BYTES_2, 1, UNIT_BYTE2_FLAG_SANCTUARY); + uint32 const areaRestFlag = (GetTeam() == ALLIANCE) ? AREA_FLAG_REST_ZONE_ALLIANCE : AREA_FLAG_REST_ZONE_HORDE; + if (area && area->flags & areaRestFlag) + { + SetFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + SetRestType(REST_TYPE_IN_FACTION_AREA); + InnEnter(time(0), GetMapId(), 0, 0, 0); + } + else if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING) && GetRestType() == REST_TYPE_IN_FACTION_AREA) + { + RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); + SetRestType(REST_TYPE_NO); + } + phaseMgr.RemoveUpdateFlag(PHASE_UPDATE_FLAG_AREA_UPDATE); } @@ -7892,8 +7905,9 @@ void Player::UpdateZone(uint32 newZone, uint32 newArea) SetRestType(REST_TYPE_NO); } } - else // Recently left a capital city + else if (GetRestType() != REST_TYPE_IN_FACTION_AREA) // handled in UpdateArea { + // Recently left a capital city RemoveFlag(PLAYER_FLAGS, PLAYER_FLAGS_RESTING); SetRestType(REST_TYPE_NO); } @@ -8490,7 +8504,12 @@ void Player::_ApplyWeaponDependentAuraDamageMod(Item* item, WeaponAttackType att { HandleStatModifier(unitMod, unitModType, float(aura->GetAmount()), apply); if (unitModType == TOTAL_VALUE) - ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply); + { + if (aura->GetAmount() > 0) + ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS, aura->GetAmount(), apply); + else + ApplyModUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG, aura->GetAmount(), apply); + } } } @@ -22684,7 +22703,7 @@ void Player::UpdatePotionCooldown(Spell* spell) void Player::SetResurrectRequestData(Unit* caster, uint32 health, uint32 mana, uint32 appliedAura) { - ASSERT(!IsRessurectRequested()); + ASSERT(!IsResurrectRequested()); _resurrectionData = new ResurrectionData(); _resurrectionData->GUID = caster->GetGUID(); _resurrectionData->Location.WorldRelocate(*caster); @@ -24520,7 +24539,7 @@ bool Player::IsAtRecruitAFriendDistance(WorldObject const* pOther) const return pOther->GetDistance(player) <= sWorld->getFloatConfig(CONFIG_MAX_RECRUIT_A_FRIEND_DISTANCE); } -void Player::ResurectUsingRequestData() +void Player::ResurrectUsingRequestData() { /// Teleport before resurrecting by player, otherwise the player might get attacked from creatures near his corpse float x, y, z, o; diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 2f210b5f9f8..dccbc550a1e 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -802,9 +802,10 @@ class InstanceSave; enum RestType { - REST_TYPE_NO = 0, - REST_TYPE_IN_TAVERN = 1, - REST_TYPE_IN_CITY = 2 + REST_TYPE_NO = 0, + REST_TYPE_IN_TAVERN = 1, + REST_TYPE_IN_CITY = 2, + REST_TYPE_IN_FACTION_AREA = 3 // used with AREA_FLAG_REST_ZONE_* }; enum TeleportToOptions @@ -1869,16 +1870,16 @@ class Player : public Unit, public GridObject<Player> _resurrectionData = NULL; } - bool IsRessurectRequestedBy(uint64 guid) const + bool IsResurrectRequestedBy(uint64 guid) const { - if (!IsRessurectRequested()) + if (!IsResurrectRequested()) return false; return _resurrectionData->GUID == guid; } - bool IsRessurectRequested() const { return _resurrectionData != NULL; } - void ResurectUsingRequestData(); + bool IsResurrectRequested() const { return _resurrectionData != NULL; } + void ResurrectUsingRequestData(); uint8 getCinematic() { return m_cinematic; } void setCinematic(uint8 cine) { m_cinematic = cine; } diff --git a/src/server/game/Entities/Player/SocialMgr.cpp b/src/server/game/Entities/Player/SocialMgr.cpp index f505c8dd64d..6e593951f2c 100644 --- a/src/server/game/Entities/Player/SocialMgr.cpp +++ b/src/server/game/Entities/Player/SocialMgr.cpp @@ -19,7 +19,7 @@ #include "SocialMgr.h" #include "DatabaseEnv.h" -#include "Opcodes.h" +#include "WorldSession.h" #include "WorldPacket.h" #include "Player.h" #include "ObjectMgr.h" diff --git a/src/server/game/Handlers/MiscHandler.cpp b/src/server/game/Handlers/MiscHandler.cpp index 866a99bcfb7..e57c748b540 100644 --- a/src/server/game/Handlers/MiscHandler.cpp +++ b/src/server/game/Handlers/MiscHandler.cpp @@ -187,11 +187,6 @@ void WorldSession::HandleWhoOpcode(WorldPacket& recvData) { TC_LOG_DEBUG("network", "WORLD: Recvd CMSG_WHO Message"); - time_t now = time(NULL); - if (now - timeLastWhoCommand < 5) - return; - else timeLastWhoCommand = now; - uint32 matchcount = 0; uint32 level_min, level_max, racemask, classmask, zones_count, str_count; @@ -795,10 +790,10 @@ void WorldSession::HandleResurrectResponseOpcode(WorldPacket& recvData) return; } - if (!GetPlayer()->IsRessurectRequestedBy(guid)) + if (!GetPlayer()->IsResurrectRequestedBy(guid)) return; - GetPlayer()->ResurectUsingRequestData(); + GetPlayer()->ResurrectUsingRequestData(); } void WorldSession::SendAreaTriggerMessage(const char* Text, ...) diff --git a/src/server/game/Miscellaneous/Language.h b/src/server/game/Miscellaneous/Language.h index cbb76ba4612..97834d3e444 100644 --- a/src/server/game/Miscellaneous/Language.h +++ b/src/server/game/Miscellaneous/Language.h @@ -1232,6 +1232,8 @@ enum TrinityStrings LANG_BAN_ACCOUNT_YOUBANNEDMESSAGE_WORLD = 11006, LANG_BAN_ACCOUNT_YOUPERMBANNEDMESSAGE_WORLD = 11007, + LANG_NPCINFO_INHABIT_TYPE = 11008 + // NOT RESERVED IDS 12000-1999999999 // `db_script_string` table index 2000000000-2000009999 (MIN_DB_SCRIPT_STRING_ID-MAX_DB_SCRIPT_STRING_ID) // For other tables maybe 2000010000-2147483647 (max index) diff --git a/src/server/game/Miscellaneous/SharedDefines.h b/src/server/game/Miscellaneous/SharedDefines.h index cd57789ed60..89ddb6697e3 100644 --- a/src/server/game/Miscellaneous/SharedDefines.h +++ b/src/server/game/Miscellaneous/SharedDefines.h @@ -1282,7 +1282,7 @@ enum SpellCustomErrors SPELL_CUSTOM_ERROR_REQUIRES_CONTROL_FIREWORKS = 95, // Requires Remote Control Fireworks. Return to Hobart Grapplehammer to get more. SPELL_CUSTOM_ERROR_MAX_NUMBER_OF_RECRUITS = 96, // You already have the max number of recruits. SPELL_CUSTOM_ERROR_MAX_NUMBER_OF_VOLUNTEERS = 97, // You already have the max number of volunteers. - SPELL_CUSTOM_ERROR_FROSTMOURNE_RENDERED_RESSURECT = 98, // Frostmourne has rendered you unable to ressurect. + SPELL_CUSTOM_ERROR_FROSTMOURNE_RENDERED_RESURRECT = 98, // Frostmourne has rendered you unable to resurrect. SPELL_CUSTOM_ERROR_CANT_MOUNT_WITH_SHAPESHIFT = 99, // You can't mount while affected by that shapeshift. SPELL_CUSTOM_ERROR_FAWNS_ALREADY_FOLLOWING = 100, // Three fawns are already following you! SPELL_CUSTOM_ERROR_ALREADY_HAVE_RIVER_BOAT = 101, // You already have a River Boat. diff --git a/src/server/game/Server/Protocol/Opcodes.h b/src/server/game/Server/Protocol/Opcodes.h index 8f77f09ba2d..94bfc8e1305 100644 --- a/src/server/game/Server/Protocol/Opcodes.h +++ b/src/server/game/Server/Protocol/Opcodes.h @@ -1395,11 +1395,18 @@ enum PacketProcessing PROCESS_THREADSAFE //packet is thread-safe - process it in Map::Update() }; +class WorldSession; class WorldPacket; class WorldSession; typedef void(WorldSession::*pOpcodeHandler)(WorldPacket& recvPacket); +#if defined(__GNUC__) +#pragma pack(1) +#else +#pragma pack(push, 1) +#endif + struct OpcodeHandler { OpcodeHandler() {} @@ -1446,6 +1453,12 @@ class OpcodeTable extern OpcodeTable opcodeTable; +#if defined(__GNUC__) +#pragma pack() +#else +#pragma pack(pop) +#endif + void InitOpcodes(); /// Lookup opcode name for human understandable logging diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index a99695206ad..a16af561125 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -124,7 +124,6 @@ WorldSession::WorldSession(uint32 id, WorldSocket* sock, AccountTypes sec, uint8 _filterAddonMessages(false), recruiterId(recruiter), isRecruiter(isARecruiter), - timeLastWhoCommand(0), _RBACData(NULL) { memset(m_Tutorials, 0, sizeof(m_Tutorials)); @@ -317,12 +316,13 @@ bool WorldSession::Update(uint32 diff, PacketFilter& updater) //! loop caused by re-enqueueing the same packets over and over again, we stop updating this session //! and continue updating others. The re-enqueued packets will be handled in the next Update call for this session. uint32 processedPackets = 0; + time_t currentTime = time(NULL); while (m_Socket && !m_Socket->IsClosed() && !_recvQueue.empty() && _recvQueue.peek(true) != firstDelayedPacket && _recvQueue.next(packet, updater)) { - if (!AntiDOS.EvaluateOpcode(*packet)) + if (!AntiDOS.EvaluateOpcode(*packet, currentTime)) KickPlayer(); OpcodeHandler const* opHandle = opcodeTable[packet->GetOpcode()]; @@ -1176,14 +1176,38 @@ void WorldSession::InvalidateRBACData() _RBACData = NULL; } -bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p) const +bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p, time_t time) const { - if (IsOpcodeAllowed(p.GetOpcode())) - return true; + PacketCounter& packetCounter = _PacketThrottlingMap[p.GetOpcode()]; + if (packetCounter.lastReceiveTime != time) + { + packetCounter.lastReceiveTime = time; + packetCounter.amountCounter = 0; + } + + uint32 maxPacketCounterAllowed = GetMaxPacketCounterAllowed(p.GetOpcode()); + + bool dosTriggered = false; + // Check if player is flooding some packets + if (++packetCounter.amountCounter > maxPacketCounterAllowed) + { + dosTriggered = true; + TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, flooding packet (opc: %s, count: %u)", + Session->GetAccountId(), Session->GetRemoteAddress().c_str(), p.GetOpcode(), packetCounter.amountCounter); + } + + // Then check if player is sending packets not allowed + if (!IsOpcodeAllowed(p.GetOpcode())) + { + dosTriggered = true; + // Opcode not allowed, let the punishment begin + TC_LOG_WARN("network", "AntiDOS: Account %u, IP: %s, sent unacceptable packet (opc: %u, size: %u)", + Session->GetAccountId(), Session->GetRemoteAddress().c_str(), p.GetOpcode(), (uint32)p.size()); + } - // Opcode not allowed, let the punishment begin - TC_LOG_INFO("network", "AntiDOS: Account %u, IP: %s, sent unacceptable packet (opc: %u, size: %u)", - Session->GetAccountId(), Session->GetRemoteAddress().c_str(), p.GetOpcode(), (uint32)p.size()); + // Return true if everything is fine, otherwise apply the configured policy + if (!dosTriggered) + return true; switch (_policy) { @@ -1212,3 +1236,234 @@ bool WorldSession::DosProtection::EvaluateOpcode(WorldPacket& p) const return true; } } + + +uint32 WorldSession::DosProtection::GetMaxPacketCounterAllowed(uint16 opcode) const +{ + uint32 maxPacketCounterAllowed; + switch (opcode) + { + case CMSG_MESSAGECHAT_ADDON_BATTLEGROUND: + case CMSG_MESSAGECHAT_ADDON_GUILD: + case CMSG_MESSAGECHAT_ADDON_OFFICER: + case CMSG_MESSAGECHAT_ADDON_PARTY: + case CMSG_MESSAGECHAT_ADDON_RAID: + case CMSG_MESSAGECHAT_ADDON_WHISPER: + case CMSG_MESSAGECHAT_AFK: + case CMSG_MESSAGECHAT_BATTLEGROUND: + case CMSG_MESSAGECHAT_CHANNEL: + case CMSG_MESSAGECHAT_DND: + case CMSG_MESSAGECHAT_EMOTE: + case CMSG_MESSAGECHAT_GUILD: + case CMSG_MESSAGECHAT_OFFICER: + case CMSG_MESSAGECHAT_PARTY: + case CMSG_MESSAGECHAT_RAID: + case CMSG_MESSAGECHAT_RAID_WARNING: + case CMSG_MESSAGECHAT_SAY: + case CMSG_MESSAGECHAT_WHISPER: + case CMSG_MESSAGECHAT_YELL: + { + maxPacketCounterAllowed = 500; + break; + } + + case CMSG_ATTACKSTOP: + case CMSG_GUILD_QUERY: + case CMSG_NAME_QUERY: + case CMSG_PET_NAME_QUERY: + case CMSG_GAMEOBJECT_QUERY: + case CMSG_CREATURE_QUERY: + case CMSG_NPC_TEXT_QUERY: + case CMSG_ARENA_TEAM_QUERY: + case CMSG_TAXINODE_STATUS_QUERY: + case CMSG_TAXIQUERYAVAILABLENODES: + case CMSG_QUESTGIVER_QUERY_QUEST: + case CMSG_QUEST_QUERY: + case CMSG_QUESTGIVER_STATUS_MULTIPLE_QUERY: + case CMSG_QUERY_QUESTS_COMPLETED: + case CMSG_QUEST_POI_QUERY: + case CMSG_QUERY_TIME: + case CMSG_PAGE_TEXT_QUERY: + case CMSG_PETITION_QUERY: + case CMSG_QUERY_INSPECT_ACHIEVEMENTS: + case CMSG_AREA_SPIRIT_HEALER_QUERY: + case CMSG_CORPSE_MAP_POSITION_QUERY: + case CMSG_MOVE_TIME_SKIPPED: + case CMSG_GUILD_BANK_QUERY_TAB: + case CMSG_GUILD_BANK_LOG_QUERY: + case CMSG_GUILD_EVENT_LOG_QUERY: + case MSG_CORPSE_QUERY: + case MSG_QUERY_NEXT_MAIL_TIME: + case MSG_MOVE_SET_FACING: + { + maxPacketCounterAllowed = 200; + break; + } + + case CMSG_REQUEST_PARTY_MEMBER_STATS: + case CMSG_WHO: + { + maxPacketCounterAllowed = 50; + break; + } + + case CMSG_SETSHEATHED: + case CMSG_CONTACT_LIST: + { + maxPacketCounterAllowed = 10; + break; + } + + case CMSG_GAMEOBJ_USE: + case CMSG_GAMEOBJ_REPORT_USE: + case CMSG_SPELLCLICK: + case CMSG_PLAYER_LOGOUT: + case CMSG_LOGOUT_REQUEST: + case CMSG_LOGOUT_CANCEL: + case CMSG_CHANGE_SEATS_ON_CONTROLLED_VEHICLE: + case CMSG_REQUEST_VEHICLE_PREV_SEAT: + case CMSG_REQUEST_VEHICLE_NEXT_SEAT: + case CMSG_REQUEST_VEHICLE_SWITCH_SEAT: + case CMSG_TOGGLE_PVP: + case CMSG_ADD_FRIEND: + case CMSG_DEL_FRIEND: + case CMSG_SET_CONTACT_NOTES: + case CMSG_RESET_INSTANCES: + case CMSG_HEARTH_AND_RESURRECT: + case CMSG_CHAR_CREATE: + case CMSG_READY_FOR_ACCOUNT_DATA_TIMES: + case CMSG_CHAR_ENUM: + case CMSG_REALM_SPLIT: + case CMSG_CHAR_DELETE: + case CMSG_PLAYER_LOGIN: + case CMSG_PET_ABANDON: + case CMSG_PET_RENAME: + case CMSG_CHAR_RENAME: + case CMSG_CHAR_CUSTOMIZE: + case CMSG_CHAR_RACE_CHANGE: + case CMSG_CHAR_FACTION_CHANGE: + case CMSG_GMTICKET_CREATE: + case CMSG_GMTICKET_UPDATETEXT: + case CMSG_GMTICKET_DELETETICKET: + case CMSG_GMSURVEY_SUBMIT: + case CMSG_GM_REPORT_LAG: + case CMSG_BUG: + case CMSG_GMRESPONSE_RESOLVE: + case CMSG_ACTIVATETAXIEXPRESS: + case CMSG_ACTIVATETAXI: + case CMSG_SELF_RES: + case CMSG_INITIATE_TRADE: + case CMSG_BEGIN_TRADE: + case CMSG_UNLEARN_SKILL: + case CMSG_DISMISS_CONTROLLED_VEHICLE: + case CMSG_REQUEST_VEHICLE_EXIT: + case CMSG_LEARN_PREVIEW_TALENTS: + case CMSG_LEARN_PREVIEW_TALENTS_PET: + case CMSG_PLAYER_VEHICLE_ENTER: + case CMSG_EJECT_PASSENGER: + case CMSG_EQUIPMENT_SET_SAVE: + case CMSG_EQUIPMENT_SET_DELETE: + case CMSG_ALTER_APPEARANCE: + case CMSG_QUESTGIVER_ACCEPT_QUEST: + case CMSG_QUESTGIVER_CHOOSE_REWARD: + case CMSG_QUESTGIVER_REQUEST_REWARD: + //case CMSG_QUESTGIVER_CANCEL: + case CMSG_QUESTLOG_REMOVE_QUEST: + case CMSG_QUEST_CONFIRM_ACCEPT: + case CMSG_QUESTGIVER_COMPLETE_QUEST: + case CMSG_DISMISS_CRITTER: + case CMSG_REPOP_REQUEST: + case CMSG_PETITION_BUY: + case CMSG_PETITION_SIGN: + case CMSG_TURN_IN_PETITION: + case CMSG_COMPLETE_CINEMATIC: + case CMSG_ITEM_REFUND: + case CMSG_SOCKET_GEMS: + case CMSG_WRAP_ITEM: + case CMSG_BUY_BANK_SLOT: + case CMSG_GROUP_INVITE_RESPONSE: + //case CMSG_GROUP_UNINVITE: + case CMSG_GROUP_UNINVITE_GUID: + case CMSG_GROUP_SET_LEADER: + case CMSG_GROUP_DISBAND: + case CMSG_GROUP_RAID_CONVERT: + case CMSG_GROUP_CHANGE_SUB_GROUP: + case CMSG_GROUP_ASSISTANT_LEADER: + case CMSG_OPT_OUT_OF_LOOT: + case CMSG_BATTLEMASTER_JOIN_ARENA: + case CMSG_BATTLEFIELD_LEAVE: + case CMSG_REPORT_PVP_AFK: + case CMSG_DUEL_ACCEPTED: + case CMSG_DUEL_CANCELLED: + case CMSG_CALENDAR_GET_CALENDAR: + case CMSG_CALENDAR_ADD_EVENT: + case CMSG_CALENDAR_UPDATE_EVENT: + case CMSG_CALENDAR_REMOVE_EVENT: + case CMSG_CALENDAR_COPY_EVENT: + case CMSG_CALENDAR_EVENT_INVITE: + case CMSG_CALENDAR_EVENT_SIGNUP: + case CMSG_CALENDAR_EVENT_RSVP: + case CMSG_CALENDAR_EVENT_REMOVE_INVITE: + case CMSG_CALENDAR_EVENT_MODERATOR_STATUS: + case CMSG_CALENDAR_COMPLAIN: + case CMSG_ARENA_TEAM_INVITE: + case CMSG_ARENA_TEAM_ACCEPT: + case CMSG_ARENA_TEAM_DECLINE: + case CMSG_ARENA_TEAM_LEAVE: + case CMSG_ARENA_TEAM_DISBAND: + case CMSG_ARENA_TEAM_REMOVE: + case CMSG_ARENA_TEAM_LEADER: + case CMSG_LOOT_METHOD: + case CMSG_GUILD_INVITE: + case CMSG_GUILD_ACCEPT: + case CMSG_GUILD_DECLINE: + case CMSG_GUILD_LEAVE: + case CMSG_GUILD_DISBAND: + case CMSG_GUILD_SET_GUILD_MASTER: + case CMSG_GUILD_MOTD: + case SMSG_GUILD_NEWS_UPDATE: + case CMSG_GUILD_QUERY_RANKS: + case CMSG_GUILD_ADD_RANK: + case CMSG_GUILD_DEL_RANK: + case CMSG_GUILD_INFO_TEXT: + case CMSG_GUILD_BANK_DEPOSIT_MONEY: + case CMSG_GUILD_BANK_WITHDRAW_MONEY: + case CMSG_GUILD_BANK_BUY_TAB: + case CMSG_GUILD_BANK_UPDATE_TAB: + case CMSG_SET_GUILD_BANK_TEXT: + case MSG_SAVE_GUILD_EMBLEM: + case MSG_PETITION_RENAME: + case MSG_PETITION_DECLINE: + case MSG_TALENT_WIPE_CONFIRM: + case MSG_SET_DUNGEON_DIFFICULTY: + case MSG_SET_RAID_DIFFICULTY: + case MSG_RANDOM_ROLL: + case MSG_RAID_TARGET_UPDATE: + case MSG_PARTY_ASSIGNMENT: + case MSG_RAID_READY_CHECK: + { + maxPacketCounterAllowed = 3; + break; + } + + case CMSG_SET_ACTION_BUTTON: + { + maxPacketCounterAllowed = MAX_ACTION_BUTTONS; + break; + } + + case CMSG_ITEM_REFUND_INFO: + { + maxPacketCounterAllowed = PLAYER_SLOTS_COUNT; + break; + } + + default: + { + maxPacketCounterAllowed = 100; + break; + } + } + + return maxPacketCounterAllowed; +} diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 2453104c80e..3a3a2730c2d 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -28,6 +28,7 @@ #include "AddonMgr.h" #include "DatabaseEnv.h" #include "World.h" +#include "Opcodes.h" #include "WorldPacket.h" #include "Cryptography/BigNumber.h" #include "Opcodes.h" @@ -203,6 +204,12 @@ class CharacterCreateInfo uint8 CharCount; }; +struct PacketCounter +{ + time_t lastReceiveTime; + uint32 amountCounter; +}; + /// Player session in the World class WorldSession { @@ -985,7 +992,7 @@ class WorldSession friend class World; public: DosProtection(WorldSession* s) : Session(s), _policy((Policy)sWorld->getIntConfig(CONFIG_PACKET_SPOOF_POLICY)) { } - bool EvaluateOpcode(WorldPacket& p) const; + bool EvaluateOpcode(WorldPacket& p, time_t time) const; void AllowOpcode(uint16 opcode, bool allow) { _isOpcodeAllowed[opcode] = allow; } protected: enum Policy @@ -1004,12 +1011,17 @@ class WorldSession return itr->second; } + uint32 GetMaxPacketCounterAllowed(uint16 opcode) const; + WorldSession* Session; private: typedef std::unordered_map<uint16, bool> OpcodeStatusMap; OpcodeStatusMap _isOpcodeAllowed; // could be bool array, but wouldn't be practical for game versions with non-linear opcodes Policy _policy; + typedef std::unordered_map<uint16, PacketCounter> PacketThrottlingMap; + // mark this member as "mutable" so it can be modified even in const functions + mutable PacketThrottlingMap _PacketThrottlingMap; DosProtection(DosProtection const& right) = delete; DosProtection& operator=(DosProtection const& right) = delete; @@ -1066,7 +1078,6 @@ class WorldSession uint32 recruiterId; bool isRecruiter; ACE_Based::LockedQueue<WorldPacket*, ACE_Thread_Mutex> _recvQueue; - time_t timeLastWhoCommand; z_stream_s* _compressionStream; rbac::RBACData* _RBACData; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index c2876a2536e..661c1ec340a 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -4223,7 +4223,7 @@ void Spell::SendChannelStart(uint32 duration) void Spell::SendResurrectRequest(Player* target) { - // get ressurector name for creature resurrections, otherwise packet will be not accepted + // get resurrector name for creature resurrections, otherwise packet will be not accepted // for player resurrections the name is looked up by guid std::string const sentName(m_caster->GetTypeId() == TYPEID_PLAYER ? "" diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index 9c6b69ef7d7..8dfa017467a 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -280,7 +280,7 @@ void Spell::EffectResurrectNew(SpellEffIndex effIndex) Player* target = unitTarget->ToPlayer(); - if (target->IsRessurectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = damage; @@ -4254,7 +4254,7 @@ void Spell::EffectResurrect(SpellEffIndex effIndex) Player* target = unitTarget->ToPlayer(); - if (target->IsRessurectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = target->CountPctFromMaxHealth(damage); @@ -5713,7 +5713,7 @@ void Spell::EffectResurrectWithAura(SpellEffIndex effIndex) if (unitTarget->IsAlive()) return; - if (target->IsRessurectRequested()) // already have one active request + if (target->IsResurrectRequested()) // already have one active request return; uint32 health = target->CountPctFromMaxHealth(damage); diff --git a/src/server/game/Spells/SpellInfo.cpp b/src/server/game/Spells/SpellInfo.cpp index ef9e6d5aa21..7491920c36a 100644 --- a/src/server/game/Spells/SpellInfo.cpp +++ b/src/server/game/Spells/SpellInfo.cpp @@ -24,6 +24,7 @@ #include "Player.h" #include "Battleground.h" #include "Vehicle.h" +#include "Pet.h" uint32 GetTargetFlagMask(SpellTargetObjectTypes objType) { @@ -1678,8 +1679,16 @@ SpellCastResult SpellInfo::CheckTarget(Unit const* caster, WorldObject const* ta // creature/player specific target checks if (unitTarget) { - if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT && unitTarget->IsInCombat()) - return SPELL_FAILED_TARGET_AFFECTING_COMBAT; + if (AttributesEx & SPELL_ATTR1_CANT_TARGET_IN_COMBAT) + { + if (unitTarget->IsInCombat()) + return SPELL_FAILED_TARGET_AFFECTING_COMBAT; + // player with active pet counts as a player in combat + else if (Player const* player = unitTarget->ToPlayer()) + if (Pet* pet = player->GetPet()) + if (pet->GetVictim() && !pet->HasUnitState(UNIT_STATE_CONTROLLED)) + return SPELL_FAILED_TARGET_AFFECTING_COMBAT; + } // only spells with SPELL_ATTR3_ONLY_TARGET_GHOSTS can target ghosts if (((AttributesEx3 & SPELL_ATTR3_ONLY_TARGET_GHOSTS) != 0) != unitTarget->HasAuraType(SPELL_AURA_GHOST)) diff --git a/src/server/scripts/Commands/cs_npc.cpp b/src/server/scripts/Commands/cs_npc.cpp index e7aeb289833..fb465aaca16 100644 --- a/src/server/scripts/Commands/cs_npc.cpp +++ b/src/server/scripts/Commands/cs_npc.cpp @@ -720,6 +720,7 @@ public: handler->PSendSysMessage(LANG_NPCINFO_LEVEL, target->getLevel()); handler->PSendSysMessage(LANG_NPCINFO_EQUIPMENT, target->GetCurrentEquipmentId(), target->GetOriginalEquipmentId()); handler->PSendSysMessage(LANG_NPCINFO_HEALTH, target->GetCreateHealth(), target->GetMaxHealth(), target->GetHealth()); + handler->PSendSysMessage(LANG_NPCINFO_INHABIT_TYPE, cInfo->InhabitType); handler->PSendSysMessage(LANG_NPCINFO_UNIT_FIELD_FLAGS, target->GetUInt32Value(UNIT_FIELD_FLAGS)); for (uint8 i = 0; i < MAX_UNIT_FLAGS; ++i) diff --git a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp index f47a3bc3a86..cad51dd55e0 100644 --- a/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp @@ -99,7 +99,7 @@ public: FlyBackTimer = 4500; break; case 2: - if (!player->IsRessurectRequested()) + if (!player->IsResurrectRequested()) { me->HandleEmoteCommand(EMOTE_ONESHOT_CUSTOM_SPELL_01); DoCast(player, SPELL_REVIVE, true); diff --git a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp index 5891de9acf9..25bb08620a1 100644 --- a/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp +++ b/src/server/scripts/EasternKingdoms/ScarletMonastery/boss_mograine_and_whitemane.cpp @@ -33,12 +33,12 @@ enum Says //Mograine says SAY_MO_AGGRO = 0, SAY_MO_KILL = 1, - SAY_MO_RESSURECTED = 2, + SAY_MO_RESURRECTED = 2, //Whitemane says SAY_WH_INTRO = 0, SAY_WH_KILL = 1, - SAY_WH_RESSURECT = 2, + SAY_WH_RESURRECT = 2, }; enum Spells @@ -157,10 +157,10 @@ public: void SpellHit(Unit* /*who*/, const SpellInfo* spell) override { - //When hit with ressurection say text + //When hit with resurrection say text if (spell->Id == SPELL_SCARLETRESURRECTION) { - Talk(SAY_MO_RESSURECTED); + Talk(SAY_MO_RESURRECTED); _bFakeDeath = false; instance->SetData(TYPE_MOGRAINE_AND_WHITE_EVENT, SPECIAL); @@ -174,7 +174,7 @@ public: if (_bHasDied && !_bHeal && instance->GetData(TYPE_MOGRAINE_AND_WHITE_EVENT) == SPECIAL) { - //On ressurection, stop fake death and heal whitemane and resume fight + //On resurrection, stop fake death and heal whitemane and resume fight if (Unit* Whitemane = ObjectAccessor::GetUnit(*me, instance->GetData64(DATA_WHITEMANE))) { me->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); @@ -294,7 +294,7 @@ public: if (Creature* mograine = ObjectAccessor::GetCreature(*me, instance->GetData64(DATA_MOGRAINE))) { DoCast(mograine, SPELL_SCARLETRESURRECTION); - Talk(SAY_WH_RESSURECT); + Talk(SAY_WH_RESURRECT); _bCanResurrect = false; } } diff --git a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp index f581f96e562..c4f46136bd9 100644 --- a/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp +++ b/src/server/scripts/Northrend/FrozenHalls/PitOfSaron/boss_scourgelord_tyrannus.cpp @@ -25,12 +25,12 @@ enum Yells { - //Gorkun + // Gorkun SAY_GORKUN_INTRO_2 = 0, SAY_GORKUN_OUTRO_1 = 1, SAY_GORKUN_OUTRO_2 = 2, - //Tyrannus + // Tyrannus SAY_AMBUSH_1 = 3, SAY_AMBUSH_2 = 4, SAY_GAUNTLET_START = 5, @@ -44,12 +44,12 @@ enum Yells SAY_DARK_MIGHT_1 = 13, SAY_DARK_MIGHT_2 = 14, - //Jaina + // Jaina SAY_JAYNA_OUTRO_3 = 3, SAY_JAYNA_OUTRO_4 = 4, SAY_JAYNA_OUTRO_5 = 5, - //Sylvanas + // Sylvanas SAY_SYLVANAS_OUTRO_3 = 3, SAY_SYLVANAS_OUTRO_4 = 4 }; @@ -121,7 +121,7 @@ static const Position rimefangPos[10] = {1012.601f, 142.4965f, 665.0453f, 0.000000f}, }; -static const Position miscPos = {1018.376f, 167.2495f, 628.2811f, 0.000000f}; //tyrannus combat start position +static Position const miscPos = { 1018.376f, 167.2495f, 628.2811f, 0.000000f }; // tyrannus combat start position class boss_tyrannus : public CreatureScript { @@ -490,6 +490,43 @@ class spell_tyrannus_mark_of_rimefang : public SpellScriptLoader } }; +// 69232 - Icy Blast +class spell_tyrannus_rimefang_icy_blast : public SpellScriptLoader +{ + public: + spell_tyrannus_rimefang_icy_blast() : SpellScriptLoader("spell_tyrannus_rimefang_icy_blast") { } + + class spell_tyrannus_rimefang_icy_blast_SpellScript : public SpellScript + { + PrepareSpellScript(spell_tyrannus_rimefang_icy_blast_SpellScript); + + bool Validate(SpellInfo const* /*spellInfo*/) override + { + if (!sSpellMgr->GetSpellInfo(SPELL_ICY_BLAST_AURA)) + return false; + return true; + } + + void HandleTriggerMissile(SpellEffIndex effIndex) + { + PreventHitDefaultEffect(effIndex); + if (Position const* pos = GetHitDest()) + if (TempSummon* summon = GetCaster()->SummonCreature(NPC_ICY_BLAST, *pos, TEMPSUMMON_TIMED_DESPAWN, 60000)) + summon->CastSpell(summon, SPELL_ICY_BLAST_AURA, true); + } + + void Register() override + { + OnEffectHit += SpellEffectFn(spell_tyrannus_rimefang_icy_blast_SpellScript::HandleTriggerMissile, EFFECT_1, SPELL_EFFECT_TRIGGER_MISSILE); + } + }; + + SpellScript* GetSpellScript() const override + { + return new spell_tyrannus_rimefang_icy_blast_SpellScript(); + } +}; + class at_tyrannus_event_starter : public AreaTriggerScript { public: @@ -518,5 +555,6 @@ void AddSC_boss_tyrannus() new boss_rimefang(); new spell_tyrannus_overlord_brand(); new spell_tyrannus_mark_of_rimefang(); + new spell_tyrannus_rimefang_icy_blast(); new at_tyrannus_event_starter(); } diff --git a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp index a261d2f860a..011d1844adf 100644 --- a/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp +++ b/src/server/scripts/Northrend/Ulduar/Ulduar/boss_general_vezax.cpp @@ -494,13 +494,13 @@ class spell_general_vezax_mark_of_the_faceless_leech : public SpellScriptLoader FinishCast(SPELL_FAILED_NO_VALID_TARGETS); } - void Register() + void Register() override { OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_general_vezax_mark_of_the_faceless_leech_SpellScript::FilterTargets, EFFECT_1, TARGET_UNIT_DEST_AREA_ENEMY); } }; - SpellScript* GetSpellScript() const + SpellScript* GetSpellScript() const override { return new spell_general_vezax_mark_of_the_faceless_leech_SpellScript(); } diff --git a/src/server/scripts/Spells/spell_hunter.cpp b/src/server/scripts/Spells/spell_hunter.cpp index e780b88c6be..eb03b47e6fe 100644 --- a/src/server/scripts/Spells/spell_hunter.cpp +++ b/src/server/scripts/Spells/spell_hunter.cpp @@ -842,15 +842,16 @@ class spell_hun_sniper_training : public SpellScriptLoader PreventDefaultAction(); if (aurEff->GetAmount() <= 0) { - Unit* caster = GetCaster(); + Unit* target = GetTarget(); uint32 spellId = SPELL_HUNTER_SNIPER_TRAINING_BUFF_R1 + GetId() - SPELL_HUNTER_SNIPER_TRAINING_R1; - if (Unit* target = GetTarget()) - if (!target->HasAura(spellId)) - { - SpellInfo const* triggeredSpellInfo = sSpellMgr->GetSpellInfo(spellId); - Unit* triggerCaster = triggeredSpellInfo->NeedsToBeTriggeredByCaster(GetSpellInfo()) ? caster : target; - triggerCaster->CastSpell(target, triggeredSpellInfo, true, 0, aurEff); - } + + target->CastSpell(target, spellId, true, 0, aurEff); + if (Player* playerTarget = GetUnitOwner()->ToPlayer()) + { + int32 baseAmount = aurEff->GetBaseAmount(); + int32 amount = playerTarget->CalculateSpellDamage(playerTarget, GetSpellInfo(), aurEff->GetEffIndex(), &baseAmount); + GetEffect(EFFECT_0)->SetAmount(amount); + } } } diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index e1ff495a50b..2638224acff 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -31,6 +31,7 @@ #include <vector> #include <cstring> #include <time.h> +#include <math.h> // Root of ByteBuffer exception hierarchy class ByteBufferException : public std::exception @@ -340,12 +341,16 @@ class ByteBuffer ByteBuffer &operator>>(float &value) { value = read<float>(); + if (!std::isfinite(value)) + throw ByteBufferException(); return *this; } ByteBuffer &operator>>(double &value) { value = read<double>(); + if (!std::isfinite(value)) + throw ByteBufferException(); return *this; } |