Merge branch 'master' of github.com:TrinityCore/TrinityCore into 4.3.4
Conflicts: src/server/game/Entities/Item/Item.cpp src/server/game/Entities/Pet/Pet.cpp src/server/game/Entities/Player/Player.cpp src/server/game/Entities/Player/Player.h src/server/game/Handlers/MiscHandler.cpp src/server/game/Miscellaneous/SharedDefines.h src/server/game/Reputation/ReputationMgr.cpp src/server/game/Server/Protocol/Opcodes.h src/server/game/Server/WorldSession.cpp src/server/game/Server/WorldSession.h src/server/game/Spells/SpellEffects.cpp src/server/game/Weather/Weather.cpp src/server/game/Weather/WeatherMgr.cpp src/server/scripts/EasternKingdoms/ScarletEnclave/zone_the_scarlet_enclave.cpp src/server/scripts/Spells/spell_hunter.cpp
This commit is contained in:
@@ -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');
|
||||
@@ -0,0 +1,3 @@
|
||||
DELETE FROM `trinity_string` WHERE `entry`=11008;
|
||||
INSERT INTO `trinity_string` (`entry`, `content_default`) VALUES
|
||||
(11008, 'InhabitType: %u');
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
#include "Common.h"
|
||||
|
||||
#include "Opcodes.h"
|
||||
#include "WorldSession.h"
|
||||
#include "WorldPacket.h"
|
||||
|
||||
class Player;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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, ...)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
// 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());
|
||||
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());
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
? ""
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user