Merge branch 'azerothcore:master' into Playerbot

This commit is contained in:
ZhengPeiRu21
2022-04-11 08:40:56 -06:00
committed by GitHub
51 changed files with 3015 additions and 145 deletions

View File

@@ -647,6 +647,25 @@ struct GameObjectTemplate
{
return IsForQuests;
}
[[nodiscard]] bool IsIgnoringLOSChecks() const
{
switch (type)
{
case GAMEOBJECT_TYPE_BUTTON:
return button.losOK == 0;
case GAMEOBJECT_TYPE_QUESTGIVER:
return questgiver.losOK == 0;
case GAMEOBJECT_TYPE_CHEST:
return chest.losOK == 0;
case GAMEOBJECT_TYPE_GOOBER:
return goober.losOK == 0;
case GAMEOBJECT_TYPE_FLAGSTAND:
return flagstand.losOK == 0;
default:
return false;
}
}
};
// From `gameobject_template_addon`

View File

@@ -1320,7 +1320,7 @@ bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare,
return obj && IsInMap(obj) && InSamePhase(obj) && _IsWithinDist(obj, dist2compare, is3D, useBoundingRadius);
}
bool WorldObject::IsWithinLOS(float ox, float oy, float oz, LineOfSightChecks checks) const
bool WorldObject::IsWithinLOS(float ox, float oy, float oz, VMAP::ModelIgnoreFlags ignoreFlags, LineOfSightChecks checks) const
{
if (IsInWorld())
{
@@ -1336,12 +1336,12 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz, LineOfSightChecks ch
GetHitSpherePointFor({ ox, oy, oz }, x, y, z);
}
return GetMap()->isInLineOfSight(x, y, z, ox, oy, oz, GetPhaseMask(), checks);
return GetMap()->isInLineOfSight(x, y, z, ox, oy, oz, GetPhaseMask(), checks, ignoreFlags);
}
return true;
}
bool WorldObject::IsWithinLOSInMap(WorldObject const* obj, LineOfSightChecks checks) const
bool WorldObject::IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlags ignoreFlags, LineOfSightChecks checks) const
{
if (!IsInMap(obj))
return false;
@@ -1364,7 +1364,7 @@ bool WorldObject::IsWithinLOSInMap(WorldObject const* obj, LineOfSightChecks che
else
GetHitSpherePointFor({ obj->GetPositionX(), obj->GetPositionY(), obj->GetPositionZ() + obj->GetCollisionHeight() }, x, y, z);
return GetMap()->isInLineOfSight(x, y, z, ox, oy, oz, GetPhaseMask(), checks);
return GetMap()->isInLineOfSight(x, y, z, ox, oy, oz, GetPhaseMask(), checks, ignoreFlags);
}
void WorldObject::GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const

View File

@@ -24,6 +24,7 @@
#include "GridDefines.h"
#include "GridReference.h"
#include "Map.h"
#include "ModelIgnoreFlags.h"
#include "ObjectDefines.h"
#include "ObjectGuid.h"
#include "Optional.h"
@@ -455,8 +456,8 @@ public:
// use only if you will sure about placing both object at same map
bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true, bool useBoundingRadius = true) const;
bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true, bool useBoundingRadius = true) const;
[[nodiscard]] bool IsWithinLOS(float x, float y, float z, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS) const;
bool IsWithinLOSInMap(WorldObject const* obj, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS) const;
[[nodiscard]] bool IsWithinLOS(float x, float y, float z, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS) const;
[[nodiscard]] bool IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS) const;
[[nodiscard]] Position GetHitSpherePointFor(Position const& dest) const;
void GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const;
bool GetDistanceOrder(WorldObject const* obj1, WorldObject const* obj2, bool is3D = true) const;

View File

@@ -1693,8 +1693,7 @@ void Player::UpdateTriggerVisibility()
// units (values dependent on GM state)
if (!creature || (!creature->IsTrigger() &&
!creature->HasAuraType(SPELL_AURA_TRANSFORM) &&
!creature->HasFlag(UNIT_FIELD_FLAGS,
UNIT_FLAG_NOT_SELECTABLE)))
!creature->HasUnitFlag(UNIT_FLAG_NOT_SELECTABLE)))
continue;
creature->SetFieldNotifyFlag(UF_FLAG_PUBLIC);

View File

@@ -1871,7 +1871,7 @@ void Group::UpdateLooterGuid(WorldObject* pLootedObject, bool ifneed)
}
}
GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* bgTemplate, BattlegroundQueueTypeId /*bgQueueTypeId*/, uint32 MinPlayerCount, uint32 /*MaxPlayerCount*/, bool isRated, uint32 arenaSlot)
GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const* bgTemplate, BattlegroundQueueTypeId bgQueueTypeId, uint32 MinPlayerCount, uint32 /*MaxPlayerCount*/, bool isRated, uint32 arenaSlot)
{
// check if this group is LFG group
if (isLFGGroup())
@@ -1944,6 +1944,12 @@ GroupJoinBattlegroundResult Group::CanJoinBattlegroundQueue(Battleground const*
if (!member->HasFreeBattlegroundQueueId())
return ERR_BATTLEGROUND_TOO_MANY_QUEUES;
// don't let join if someone from the group is already in that bg queue
if (member->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeId))
{
return ERR_BATTLEGROUND_JOIN_FAILED;
}
// don't let join if someone from the group is in bg queue random
if (member->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeIdRandom))
return ERR_IN_RANDOM_BG;

View File

@@ -211,46 +211,65 @@ void WorldSession::HandleBattlemasterJoinOpcode(WorldPacket& recvData)
else
{
Group* grp = _player->GetGroup();
// no group or not a leader
if (!grp || grp->GetLeaderGUID() != _player->GetGUID())
return;
if (_player->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeIdRandom)) // queued for random bg, so can't queue for anything else
err = ERR_IN_RANDOM_BG;
else if (_player->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) // already in queue, so can't queue for random
err = ERR_IN_NON_RANDOM_BG;
else if (_player->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_2v2) ||
_player->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_3v3) ||
_player->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_5v5)) // can't be already queued for arenas
err = ERR_BATTLEGROUND_QUEUED_FOR_RATED;
grp->DoForAllMembers([&err, bgQueueTypeId, bgQueueTypeIdRandom, bgTypeId](Player* member)
{
if (member->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeIdRandom)) // queued for random bg, so can't queue for anything else
{
err = ERR_IN_RANDOM_BG;
}
else if (member->InBattlegroundQueue() && bgTypeId == BATTLEGROUND_RB) // already in queue, so can't queue for random
{
err = ERR_IN_NON_RANDOM_BG;
}
else if (member->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_2v2) ||
member->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_3v3) ||
member->InBattlegroundQueueForBattlegroundQueueType(BATTLEGROUND_QUEUE_5v5)) // can't be already queued for arenas
{
err = ERR_BATTLEGROUND_QUEUED_FOR_RATED;
}
else if (member->InBattlegroundQueueForBattlegroundQueueType(bgQueueTypeId)) // queued for this bg
{
err = ERR_BATTLEGROUND_NONE;
}
if (err > 0)
err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
if (err < 0)
{
return;
}
});
if (err <= 0)
{
grp->DoForAllMembers([err](Player* member)
{
WorldPacket data;
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
member->GetSession()->SendPacket(&data);
});
return;
}
ASSERT(err > 0);
err = grp->CanJoinBattlegroundQueue(bg, bgQueueTypeId, 0, bg->GetMaxPlayersPerTeam(), false, 0);
isPremade = (grp->GetMembersCount() >= bg->GetMinPlayersPerTeam() && bgTypeId != BATTLEGROUND_RB);
uint32 avgWaitTime = 0;
if (err > 0)
{
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
}
GroupQueueInfo* ginfo = bgQueue.AddGroup(_player, grp, bgTypeId, bracketEntry, 0, false, isPremade, 0, 0);
avgWaitTime = bgQueue.GetAverageQueueWaitTime(ginfo);
grp->DoForAllMembers([bg, err, bgQueueTypeId, avgWaitTime](Player* member)
{
WorldPacket data;
if (err <= 0)
{
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);
member->GetSession()->SendPacket(&data);
return;
}
uint32 queueSlot = member->AddBattlegroundQueueId(bgQueueTypeId);
// send status packet
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, member->AddBattlegroundQueueId(bgQueueTypeId), STATUS_WAIT_QUEUE, avgWaitTime, 0, 0, TEAM_NEUTRAL);
member->GetSession()->SendPacket(&data);
sBattlegroundMgr->BuildGroupJoinedBattlegroundPacket(&data, err);

View File

@@ -2023,7 +2023,7 @@ Transport* Map::GetTransportForPos(uint32 phase, float x, float y, float z, Worl
if ((*itr)->IsInWorld() && (*itr)->GetExactDistSq(x, y, z) < 75.0f * 75.0f && (*itr)->m_model)
{
float dist = 30.0f;
bool hit = (*itr)->m_model->intersectRay(r, dist, false, phase);
bool hit = (*itr)->m_model->intersectRay(r, dist, false, phase, VMAP::ModelIgnoreFlags::Nothing);
if (hit)
return *itr;
}
@@ -2033,7 +2033,7 @@ Transport* Map::GetTransportForPos(uint32 phase, float x, float y, float z, Worl
if (staticTrans->m_model)
{
float dist = 10.0f;
bool hit = staticTrans->m_model->intersectRay(r, dist, false, phase);
bool hit = staticTrans->m_model->intersectRay(r, dist, false, phase, VMAP::ModelIgnoreFlags::Nothing);
if (hit)
if (GetHeight(phase, x, y, z, true, 30.0f) < (v.z - dist + 1.0f))
return staticTrans->ToTransport();
@@ -2440,14 +2440,27 @@ float Map::GetWaterLevel(float x, float y) const
return 0;
}
bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks) const
bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const
{
if ((checks & LINEOFSIGHT_CHECK_VMAP) && !VMAP::VMapFactory::createOrGetVMapMgr()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2))
if ((checks & LINEOFSIGHT_CHECK_VMAP) && !VMAP::VMapFactory::createOrGetVMapMgr()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2, ignoreFlags))
{
return false;
}
if (sWorld->getBoolConfig(CONFIG_CHECK_GOBJECT_LOS) && (checks & LINEOFSIGHT_CHECK_GOBJECT_ALL))
{
ignoreFlags = VMAP::ModelIgnoreFlags::Nothing;
if (!(checks & LINEOFSIGHT_CHECK_GOBJECT_M2))
{
ignoreFlags = VMAP::ModelIgnoreFlags::M2;
}
if (!_dynamicTree.isInLineOfSight(x1, y1, z1, x2, y2, z2, phasemask, ignoreFlags))
{
return false;
}
}
if (sWorld->getBoolConfig(CONFIG_CHECK_GOBJECT_LOS) && (checks & LINEOFSIGHT_CHECK_GOBJECT)
&& !_dynamicTree.isInLineOfSight(x1, y1, z1, x2, y2, z2, phasemask))
return false;
return true;
}

View File

@@ -63,6 +63,11 @@ class PathGenerator;
enum WeatherState : uint32;
namespace VMAP
{
enum class ModelIgnoreFlags : uint32;
}
namespace Acore
{
struct ObjectUpdater;
@@ -183,10 +188,13 @@ struct PositionFullTerrainStatus
enum LineOfSightChecks
{
LINEOFSIGHT_CHECK_VMAP = 0x1, // check static floor layout data
LINEOFSIGHT_CHECK_GOBJECT = 0x2, // check dynamic game object data
LINEOFSIGHT_CHECK_VMAP = 0x1, // check static floor layout data
LINEOFSIGHT_CHECK_GOBJECT_WMO = 0x2, // check dynamic game object data (wmo models)
LINEOFSIGHT_CHECK_GOBJECT_M2 = 0x4, // check dynamic game object data (m2 models)
LINEOFSIGHT_ALL_CHECKS = (LINEOFSIGHT_CHECK_VMAP | LINEOFSIGHT_CHECK_GOBJECT)
LINEOFSIGHT_CHECK_GOBJECT_ALL = LINEOFSIGHT_CHECK_GOBJECT_WMO | LINEOFSIGHT_CHECK_GOBJECT_M2,
LINEOFSIGHT_ALL_CHECKS = LINEOFSIGHT_CHECK_VMAP | LINEOFSIGHT_CHECK_GOBJECT_ALL
};
class GridMap
@@ -539,7 +547,7 @@ public:
float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground = nullptr, bool swim = false, float collisionHeight = DEFAULT_COLLISION_HEIGHT) const;
[[nodiscard]] float GetHeight(uint32 phasemask, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const;
[[nodiscard]] bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks) const;
[[nodiscard]] bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const;
bool CanReachPositionAndGetValidCoords(WorldObject const* source, PathGenerator *path, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
bool CanReachPositionAndGetValidCoords(WorldObject const* source, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;
bool CanReachPositionAndGetValidCoords(WorldObject const* source, float startX, float startY, float startZ, float &destX, float &destY, float &destZ, bool failOnCollision = true, bool failOnSlopes = true) const;

View File

@@ -1052,12 +1052,10 @@ void PathGenerator::ShortenPathUntilDist(G3D::Vector3 const& target, float dist)
// check if the shortened path is still in LoS with the target and it is walkable
_source->GetHitSpherePointFor({ _pathPoints[i - 1].x, _pathPoints[i - 1].y, _pathPoints[i - 1].z + collisionHeight }, x, y, z);
if (!_source->GetMap()->isInLineOfSight(x, y, z, _pathPoints[i - 1].x, _pathPoints[i - 1].y, _pathPoints[i - 1].z + collisionHeight, _source->GetPhaseMask(), LINEOFSIGHT_ALL_CHECKS)
|| (canCheckSlope
&& !IsSwimmableSegment(_source->GetPositionX(), _source->GetPositionY(), _source->GetPositionZ(), _pathPoints[i - 1].x, _pathPoints[i - 1].y, _pathPoints[i - 1].z)
&& !IsWalkableClimb(_source->GetPositionX(), _source->GetPositionY(), _source->GetPositionZ(), _pathPoints[i - 1].x, _pathPoints[i - 1].y, _pathPoints[i - 1].z)
)
)
if (!_source->GetMap()->isInLineOfSight(x, y, z, _pathPoints[i - 1].x, _pathPoints[i - 1].y, _pathPoints[i - 1].z + collisionHeight,
_source->GetPhaseMask(), LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::Nothing) || (canCheckSlope &&
!IsSwimmableSegment(_source->GetPositionX(), _source->GetPositionY(), _source->GetPositionZ(), _pathPoints[i - 1].x, _pathPoints[i - 1].y, _pathPoints[i - 1].z) &&
!IsWalkableClimb(_source->GetPositionX(), _source->GetPositionY(), _source->GetPositionZ(), _pathPoints[i - 1].x, _pathPoints[i - 1].y, _pathPoints[i - 1].z)))
{
// whenver we find a point that is not valid anymore, simply use last valid path
_pathPoints.resize(i + 1);

View File

@@ -165,7 +165,8 @@ void RandomMovementGenerator<Creature>::_setRandomLocation(Creature* creature)
return;
}
if (!map->isInLineOfSight((*itr).x, (*itr).y, (*itr).z + 2.f, (*itrNext).x, (*itrNext).y, (*itrNext).z + 2.f, creature->GetPhaseMask(), LINEOFSIGHT_ALL_CHECKS))
if (!map->isInLineOfSight((*itr).x, (*itr).y, (*itr).z + 2.f, (*itrNext).x, (*itrNext).y, (*itrNext).z + 2.f, creature->GetPhaseMask(),
LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::Nothing))
{
_validPointsVector[_currentPoint].erase(randomIter);
_preComputedPaths.erase(pathIdx);

View File

@@ -2049,7 +2049,7 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
if (Unit* unit = (*itr)->ToUnit())
{
uint32 deficit = unit->GetMaxHealth() - unit->GetHealth();
if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && target->IsWithinDist(unit, jumpRadius) && target->IsWithinLOSInMap(unit, LINEOFSIGHT_ALL_CHECKS))
if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && target->IsWithinDist(unit, jumpRadius) && target->IsWithinLOSInMap(unit, VMAP::ModelIgnoreFlags::M2))
{
foundItr = itr;
maxHPDeficit = deficit;
@@ -2064,10 +2064,10 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar
{
if (foundItr == tempTargets.end())
{
if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS))
if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr, VMAP::ModelIgnoreFlags::M2))
foundItr = itr;
}
else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS))
else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr, VMAP::ModelIgnoreFlags::M2))
foundItr = itr;
}
}
@@ -5617,9 +5617,38 @@ SpellCastResult Spell::CheckCast(bool strict)
if (m_spellInfo->HasAttribute(SPELL_ATTR0_CU_REQ_TARGET_FACING_CASTER) && !target->HasInArc(static_cast<float>(M_PI), m_caster))
return SPELL_FAILED_NOT_INFRONT;
if (m_caster->GetEntry() != WORLD_TRIGGER) // Ignore LOS for gameobjects casts (wrongly casted by a trigger)
if ((!m_caster->IsTotem() || !m_spellInfo->IsPositive()) && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !m_caster->IsWithinLOSInMap(target, LINEOFSIGHT_ALL_CHECKS) && !(m_spellFlags & SPELL_FLAG_REDIRECTED))
if ((!m_caster->IsTotem() || !m_spellInfo->IsPositive()) && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) &&
!m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !(m_spellFlags & SPELL_FLAG_REDIRECTED))
{
WorldObject* losCenter = nullptr;
uint32 losChecks = LINEOFSIGHT_ALL_CHECKS;
if (m_originalCasterGUID.IsGameObject())
{
losCenter = m_caster->GetMap()->GetGameObject(m_originalCasterGUID);
}
else if (m_caster->GetEntry() == WORLD_TRIGGER)
{
if (TempSummon* tempSummon = m_caster->ToTempSummon())
{
losCenter = tempSummon->GetSummonerGameObject();
}
}
if (losCenter)
{
// If spell casted by gameobject then ignore M2 models
losChecks &= ~LINEOFSIGHT_CHECK_GOBJECT_M2;
}
else
{
losCenter = m_caster;
}
if (!losCenter->IsWithinLOSInMap(target, VMAP::ModelIgnoreFlags::M2, LineOfSightChecks(losChecks)))
{
return SPELL_FAILED_LINE_OF_SIGHT;
}
}
}
}
@@ -5629,8 +5658,38 @@ SpellCastResult Spell::CheckCast(bool strict)
float x, y, z;
m_targets.GetDstPos()->GetPosition(x, y, z);
if ((!m_caster->IsTotem() || !m_spellInfo->IsPositive()) && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) && !m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT) && !m_caster->IsWithinLOS(x, y, z, LINEOFSIGHT_ALL_CHECKS))
return SPELL_FAILED_LINE_OF_SIGHT;
if ((!m_caster->IsTotem() || !m_spellInfo->IsPositive()) && !m_spellInfo->HasAttribute(SPELL_ATTR2_IGNORE_LINE_OF_SIGHT) &&
!m_spellInfo->HasAttribute(SPELL_ATTR5_ALWAYS_AOE_LINE_OF_SIGHT))
{
WorldObject* losCenter = nullptr;
uint32 losChecks = LINEOFSIGHT_ALL_CHECKS;
if (m_originalCasterGUID.IsGameObject())
{
losCenter = m_caster->GetMap()->GetGameObject(m_originalCasterGUID);
}
else if (m_caster->GetEntry() == WORLD_TRIGGER)
{
if (TempSummon* tempSummon = m_caster->ToTempSummon())
{
losCenter = tempSummon->GetSummonerGameObject();
}
}
if (losCenter)
{
// If spell casted by gameobject then ignore M2 models
losChecks &= ~LINEOFSIGHT_CHECK_GOBJECT_M2;
}
else
{
losCenter = m_caster;
}
if (!losCenter->IsWithinLOS(x, y, z, VMAP::ModelIgnoreFlags::M2, LineOfSightChecks((losChecks))))
{
return SPELL_FAILED_LINE_OF_SIGHT;
}
}
}
// check pet presence
@@ -7626,7 +7685,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
{
case SPELL_EFFECT_RESURRECT_NEW:
// player far away, maybe his corpse near?
if (target != m_caster && !target->IsWithinLOSInMap(m_caster, LINEOFSIGHT_ALL_CHECKS))
if (target != m_caster && !target->IsWithinLOSInMap(m_caster))
{
if (!m_targets.GetCorpseTargetGUID())
return false;
@@ -7638,7 +7697,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
if (target->GetGUID() != corpse->GetOwnerGUID())
return false;
if (!corpse->IsWithinLOSInMap(m_caster, LINEOFSIGHT_ALL_CHECKS) && !(m_spellFlags & SPELL_FLAG_REDIRECTED))
if (!corpse->IsWithinLOSInMap(m_caster) && !(m_spellFlags & SPELL_FLAG_REDIRECTED))
return false;
}
break;
@@ -7646,7 +7705,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
{
if (!m_targets.GetCorpseTargetGUID())
{
if (target->IsWithinLOSInMap(m_caster, LINEOFSIGHT_ALL_CHECKS) && target->HasUnitFlag(UNIT_FLAG_SKINNABLE))
if (target->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2) && target->HasUnitFlag(UNIT_FLAG_SKINNABLE))
return true;
return false;
@@ -7662,7 +7721,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
if (!corpse->HasFlag(CORPSE_FIELD_FLAGS, CORPSE_FLAG_LOOTABLE))
return false;
if (!corpse->IsWithinLOSInMap(m_caster, LINEOFSIGHT_ALL_CHECKS))
if (!corpse->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2))
return false;
}
break;
@@ -7676,14 +7735,40 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
if (target->ToPlayer()->getLevel() >= sWorld->getIntConfig(CONFIG_MAX_RECRUIT_A_FRIEND_BONUS_PLAYER_LEVEL))
return false;
break;
default: // normal case
// Get GO cast coordinates if original caster -> GO
WorldObject* caster = nullptr;
default: // normal case
{
uint32 losChecks = LINEOFSIGHT_ALL_CHECKS;
GameObject* gobCaster = nullptr;
if (m_originalCasterGUID.IsGameObject())
caster = m_caster->GetMap()->GetGameObject(m_originalCasterGUID);
if (!caster)
{
gobCaster = m_caster->GetMap()->GetGameObject(m_originalCasterGUID);
}
else if (m_caster->GetEntry() == WORLD_TRIGGER)
{
if (TempSummon* tempSummon = m_caster->ToTempSummon())
{
gobCaster = tempSummon->GetSummonerGameObject();
}
}
WorldObject* caster = nullptr;
if (gobCaster)
{
if (gobCaster->GetGOInfo()->IsIgnoringLOSChecks())
{
return true;
}
caster = gobCaster;
// If spell casted by gameobject then ignore M2 models
losChecks &= ~LINEOFSIGHT_CHECK_GOBJECT_M2;
}
else
{
caster = m_caster;
}
if (target != m_caster)
{
if (m_targets.HasDst())
@@ -7692,13 +7777,18 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff) const
float y = m_targets.GetDstPos()->GetPositionY();
float z = m_targets.GetDstPos()->GetPositionZ();
if (!target->IsWithinLOS(x, y, z, LINEOFSIGHT_ALL_CHECKS))
if (!target->IsWithinLOS(x, y, z, VMAP::ModelIgnoreFlags::M2, LineOfSightChecks(losChecks)))
{
return false;
}
}
else if (!target->IsWithinLOSInMap(caster, LINEOFSIGHT_ALL_CHECKS))
else if (!target->IsWithinLOSInMap(caster, VMAP::ModelIgnoreFlags::M2, LineOfSightChecks(losChecks)))
{
return false;
}
}
break;
}
}
return true;

View File

@@ -4160,14 +4160,6 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(152); // 150 yards
});
// Shadowbolt Volley
ApplySpellFix({ 22665 }, [](SpellInfo* spellInfo)
{
spellInfo->RangeEntry = sSpellRangeStore.LookupEntry(152); // 150 yards
spellInfo->Effects[EFFECT_0].RadiusEntry = sSpellRadiusStore.LookupEntry(41); // 150 yards
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
});
ApplySpellFix({ 22247 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesCu |= SPELL_ATTR0_CU_DONT_BREAK_STEALTH;
@@ -4229,12 +4221,6 @@ void SpellMgr::LoadSpellInfoCorrections()
spellInfo->AttributesEx |= SPELL_ATTR1_EXCLUDE_CASTER;
});
// Suppression Aura
ApplySpellFix({ 22247 }, [](SpellInfo* spellInfo)
{
spellInfo->AttributesEx2 |= SPELL_ATTR2_IGNORE_LINE_OF_SIGHT;
});
// Cosmetic - Lightning Beam Channel
ApplySpellFix({ 45537 }, [](SpellInfo* spellInfo)
{

View File

@@ -1000,8 +1000,8 @@ public:
{
Player* player = handler->GetSession()->GetPlayer();
handler->PSendSysMessage("Checking LoS %s -> %s:", player->GetName().c_str(), unit->GetName().c_str());
handler->PSendSysMessage(" VMAP LoS: %s", player->IsWithinLOSInMap(unit, LINEOFSIGHT_CHECK_VMAP) ? "clear" : "obstructed");
handler->PSendSysMessage(" GObj LoS: %s", player->IsWithinLOSInMap(unit, LINEOFSIGHT_CHECK_GOBJECT) ? "clear" : "obstructed");
handler->PSendSysMessage(" VMAP LoS: %s", player->IsWithinLOSInMap(unit, VMAP::ModelIgnoreFlags::Nothing, LINEOFSIGHT_CHECK_VMAP) ? "clear" : "obstructed");
handler->PSendSysMessage(" GObj LoS: %s", player->IsWithinLOSInMap(unit, VMAP::ModelIgnoreFlags::Nothing, LINEOFSIGHT_CHECK_GOBJECT_ALL) ? "clear" : "obstructed");
handler->PSendSysMessage("%s is %sin line of sight of %s.", unit->GetName().c_str(), (player->IsWithinLOSInMap(unit) ? "" : "not "), player->GetName().c_str());
return true;
}

View File

@@ -21,6 +21,7 @@
#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "blackwing_lair.h"
#include "SpellScript.h"
enum Say
{
@@ -247,8 +248,28 @@ class go_suppression_device : public GameObjectScript
}
};
class spell_suppression_aura : public SpellScript
{
PrepareSpellScript(spell_suppression_aura);
void FilterTargets(std::list<WorldObject*>& targets)
{
targets.remove_if([&](WorldObject* target) -> bool
{
Unit* unit = target->ToUnit();
return !unit || unit->HasAuraType(SPELL_AURA_MOD_STEALTH);
});
}
void Register() override
{
OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_suppression_aura::FilterTargets, EFFECT_ALL, TARGET_UNIT_DEST_AREA_ENEMY);
}
};
void AddSC_boss_broodlord()
{
new boss_broodlord();
new go_suppression_device();
RegisterSpellScript(spell_suppression_aura);
}

View File

@@ -256,7 +256,7 @@ public:
me->SetVisible(true);
me->SetPhaseMask(1, true);
me->ReplaceAllNpcFlags(NPCFlags(1));
me->SetNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetFaction(FACTION_FRIENDLY);
me->SetStandState(UNIT_STAND_STATE_SIT_HIGH_CHAIR);
me->RemoveAura(SPELL_NEFARIANS_BARRIER);
@@ -284,6 +284,7 @@ public:
if (action == ACTION_KILLED)
{
summons.DespawnEntry(NPC_BONE_CONSTRUCT);
Unit::Kill(me, me);
}
}
@@ -472,7 +473,7 @@ public:
Talk(SAY_GAMESBEGIN_1);
events.ScheduleEvent(EVENT_START_EVENT, 4000);
me->SetFaction(FACTION_DRAGONFLIGHT_BLACK);
me->ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE);
me->RemoveNpcFlag(UNIT_NPC_FLAG_GOSSIP);
me->SetStandState(UNIT_STAND_STATE_STAND);
me->SetUnitFlag(UNIT_FLAG_IMMUNE_TO_PC | UNIT_FLAG_NOT_SELECTABLE);
// Due to Nefarius despawning himself on Vael, we need to update the guid on instance to prevent unwanted behaviours as encounter not resetting at all.

View File

@@ -306,6 +306,7 @@ public:
razorgore->AI()->DoAction(TALK_EGG_BROKEN_RAND);
egg->SetLootState(GO_READY);
egg->UseDoorOrButton(10000);
egg->SetRespawnTime(WEEK);
}
}
}

View File

@@ -310,6 +310,8 @@ public:
break;
case SPECIAL:
if (EggEvent == NOT_STARTED)
SetData(DATA_EGG_EVENT, IN_PROGRESS);
if (++EggCount >= EggList.size())
{
if (Creature* razor = instance->GetCreature(razorgoreGUID))
@@ -321,8 +323,6 @@ public:
_events.ScheduleEvent(EVENT_RAZOR_PHASE_TWO, 1000);
_events.CancelEvent(EVENT_RAZOR_SPAWN);
}
if (EggEvent == NOT_STARTED)
SetData(DATA_EGG_EVENT, IN_PROGRESS);
break;
}
}
@@ -400,6 +400,7 @@ public:
summon->SetUnitFlag(UNIT_FLAG_NOT_SELECTABLE);
summon->SetReactState(REACT_PASSIVE);
summon->SetStandState(UNIT_STAND_STATE_DEAD);
summon->SetHomePosition(summon->GetPosition());
if (Creature* nefarius = instance->GetCreature(victorNefariusGUID))
{
@@ -447,7 +448,7 @@ public:
}
}
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 12000, 17000);
_events.ScheduleEvent(EVENT_RAZOR_SPAWN, 15000);
}
break;
case EVENT_RAZOR_PHASE_TWO:

View File

@@ -1763,7 +1763,9 @@ public:
{
float destX = summoner->GetPositionX() + cos(angle + a * M_PI) * i * 10.0f;
float destY = summoner->GetPositionY() + std::sin(angle + a * M_PI) * i * 10.0f;
if (summoner->GetMap()->isInLineOfSight(summoner->GetPositionX(), summoner->GetPositionY(), summoner->GetPositionZ() + 10.0f, destX, destY, summoner->GetPositionZ() + 10.0f, summoner->GetPhaseMask(), LINEOFSIGHT_ALL_CHECKS) && destX > 4585.0f && destY > 2716.0f && destY < 2822.0f)
if (summoner->GetMap()->isInLineOfSight(summoner->GetPositionX(), summoner->GetPositionY(), summoner->GetPositionZ() + 10.0f, destX, destY,
summoner->GetPositionZ() + 10.0f, summoner->GetPhaseMask(), LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::Nothing) &&
destX > 4585.0f && destY > 2716.0f && destY < 2822.0f)
{
float destZ = summoner->GetMapHeight(summoner->GetPhaseMask(), destX, destY, summoner->GetPositionZ());
if (std::fabs(destZ - summoner->GetPositionZ()) < 10.0f) // valid z found

View File

@@ -1285,7 +1285,7 @@ public:
float ox, oy, oz;
_caster->GetPosition(ox, oy, oz);
DynamicMapTree const& dTree = unit->GetMap()->GetDynamicMapTree();
return !dTree.isInLineOfSight(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ() + 2.f, ox, oy, oz + 2.f, unit->GetPhaseMask());
return !dTree.isInLineOfSight(unit->GetPositionX(), unit->GetPositionY(), unit->GetPositionZ() + 2.f, ox, oy, oz + 2.f, unit->GetPhaseMask(), VMAP::ModelIgnoreFlags::Nothing);
}
private:

View File

@@ -125,7 +125,8 @@ public:
void MoveInLineOfSight(Unit* who) override
{
if (!activated && who->GetTypeId() == TYPEID_PLAYER)
if (me->GetExactDist2d(who) <= 25.0f && me->GetMap()->isInLineOfSight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5.0f, who->GetPositionX(), who->GetPositionY(), who->GetPositionZ() + 5.0f, 2, LINEOFSIGHT_ALL_CHECKS))
if (me->GetExactDist2d(who) <= 25.0f && me->GetMap()->isInLineOfSight(me->GetPositionX(), me->GetPositionY(), me->GetPositionZ() + 5.0f,
who->GetPositionX(), who->GetPositionY(), who->GetPositionZ() + 5.0f, 2, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::Nothing))
{
activated = true;
me->RemoveAura(64615);

View File

@@ -0,0 +1,74 @@
/*
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by the
* Free Software Foundation; either version 3 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 Affero 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 "SpellInfo.h"
#include "SpellScript.h"
#include "Unit.h"
#include "utgarde_pinnacle.h"
enum UtgardeSpells
{
SPELL_BEAST_MARK_NORMAL = 48876,
SPELL_BEAST_MARK_DAMAGE_N = 48877,
SPELL_BEAST_MARK_DAMAGE_H = 59233
};
// 48876 - Beast's Mark
// 59237 - Beast's Mark
class spell_utgarde_pinnacle_beast_mark : public AuraScript
{
PrepareAuraScript(spell_utgarde_pinnacle_beast_mark);
bool Validate(SpellInfo const* /*spell*/) override
{
return ValidateSpellInfo({ SPELL_BEAST_MARK_DAMAGE_N, SPELL_BEAST_MARK_DAMAGE_H });
}
bool CheckProc(ProcEventInfo& eventInfo)
{
if (DamageInfo* damageInfo = eventInfo.GetDamageInfo())
{
Unit* attacker = damageInfo->GetAttacker();
if (!attacker || !damageInfo->GetDamage())
return false;
return attacker->GetCreatureType() == CREATURE_TYPE_BEAST;
}
return false;
}
void HandleProc(AuraEffect const* aurEff, ProcEventInfo& /*eventInfo*/)
{
PreventDefaultAction();
Unit* target = GetTarget();
uint32 spellId = (m_scriptSpellId == SPELL_BEAST_MARK_NORMAL) ? SPELL_BEAST_MARK_DAMAGE_N : SPELL_BEAST_MARK_DAMAGE_H;
target->CastSpell(target, spellId, aurEff);
}
void Register() override
{
DoCheckProc += AuraCheckProcFn(spell_utgarde_pinnacle_beast_mark::CheckProc);
OnEffectProc += AuraEffectProcFn(spell_utgarde_pinnacle_beast_mark::HandleProc, EFFECT_0, SPELL_AURA_PROC_TRIGGER_SPELL);
}
};
void AddSC_utgarde_pinnacle()
{
RegisterSpellScript(spell_utgarde_pinnacle_beast_mark);
}

View File

@@ -111,6 +111,7 @@ void AddSC_boss_palehoof();
void AddSC_boss_skadi();
void AddSC_boss_ymiron();
void AddSC_instance_utgarde_pinnacle();
void AddSC_utgarde_pinnacle();
void AddSC_utgarde_keep();
void AddSC_boss_archavon(); //Vault of Archavon
void AddSC_boss_emalon();
@@ -276,6 +277,7 @@ void AddNorthrendScripts()
AddSC_boss_skadi();
AddSC_boss_ymiron();
AddSC_instance_utgarde_pinnacle();
AddSC_utgarde_pinnacle();
AddSC_utgarde_keep();
AddSC_boss_archavon(); //Vault of Archavon
AddSC_boss_emalon();

View File

@@ -3493,7 +3493,8 @@ class spell_item_eggnog : public SpellScript
enum GoblinBomb
{
SPELL_SUMMON_GOBLIN_BOMB = 13258,
SPELL_SUMMON_GOBLIN_BOMB = 13258,
SPELL_MALFUNCTION_EXPLOSION = 13261
};
// 23134 - Goblin Bomb
@@ -3503,14 +3504,14 @@ class spell_item_goblin_bomb : public SpellScript
bool Validate(SpellInfo const* /*spellInfo*/) override
{
return ValidateSpellInfo({ SPELL_SUMMON_GOBLIN_BOMB });
return ValidateSpellInfo({ SPELL_SUMMON_GOBLIN_BOMB, SPELL_MALFUNCTION_EXPLOSION });
}
void HandleDummy(SpellEffIndex /*effIndex*/)
{
if (Unit* caster = GetCaster())
{
caster->CastSpell(caster, SPELL_SUMMON_GOBLIN_BOMB, true, GetCastItem());
caster->CastSpell(caster, roll_chance_i(95) ? SPELL_SUMMON_GOBLIN_BOMB : SPELL_MALFUNCTION_EXPLOSION, true, GetCastItem());
}
}