diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server/game/Entities/Object/Object.cpp | 46 | ||||
-rw-r--r-- | src/server/game/Entities/Object/Object.h | 4 | ||||
-rw-r--r-- | src/server/game/Maps/Map.cpp | 11 | ||||
-rw-r--r-- | src/server/game/Maps/Map.h | 10 | ||||
-rw-r--r-- | src/server/game/Spells/Spell.cpp | 18 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 3 | ||||
-rw-r--r-- | src/server/game/World/World.h | 1 | ||||
-rw-r--r-- | src/server/scripts/Commands/cs_debug.cpp | 11 | ||||
-rw-r--r-- | src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp | 77 | ||||
-rw-r--r-- | src/server/worldserver/worldserver.conf.dist | 9 |
10 files changed, 72 insertions, 118 deletions
diff --git a/src/server/game/Entities/Object/Object.cpp b/src/server/game/Entities/Object/Object.cpp index 8eb18694c84..51c7273de96 100644 --- a/src/server/game/Entities/Object/Object.cpp +++ b/src/server/game/Entities/Object/Object.cpp @@ -1142,20 +1142,6 @@ bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool return thisOrTransport->IsInDist2d(objOrObjTransport, maxdist); } -bool WorldObject::IsWithinLOSInMap(const WorldObject* obj, VMAP::ModelIgnoreFlags ignoreFlags) const -{ - if (!IsInMap(obj)) - return false; - - float x, y, z; - if (obj->GetTypeId() == TYPEID_PLAYER) - obj->GetPosition(x, y, z); - else - obj->GetHitSpherePointFor(GetPosition(), x, y, z); - - return IsWithinLOS(x, y, z, ignoreFlags); -} - float WorldObject::GetDistance(const WorldObject* obj) const { float d = GetExactDist(obj) - GetCombatReach() - obj->GetCombatReach(); @@ -1230,12 +1216,17 @@ bool WorldObject::IsWithinDistInMap(WorldObject const* obj, float dist2compare, return obj && IsInMap(obj) && InSamePhase(obj) && _IsWithinDist(obj, dist2compare, is3D, incOwnRadius, incTargetRadius); } -bool WorldObject::IsWithinLOS(float ox, float oy, float oz, VMAP::ModelIgnoreFlags ignoreFlags) const +Position WorldObject::GetHitSpherePointFor(Position const& dest) const +{ + G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ()); + G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ()); + G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(GetPosition()), GetCombatReach()); + + return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAngle(contactPoint.x, contactPoint.y)); +} + +bool WorldObject::IsWithinLOS(float ox, float oy, float oz, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const { - /*float x, y, z; - GetPosition(x, y, z); - VMAP::IVMapManager* vMapManager = VMAP::VMapFactory::createOrGetVMapManager(); - return vMapManager->isInLineOfSight(GetMapId(), x, y, z+2.0f, ox, oy, oz+2.0f);*/ if (IsInWorld()) { float x, y, z; @@ -1244,19 +1235,24 @@ bool WorldObject::IsWithinLOS(float ox, float oy, float oz, VMAP::ModelIgnoreFla else GetHitSpherePointFor({ ox, oy, oz }, x, y, z); - return GetMap()->isInLineOfSight(x, y, z + 2.0f, ox, oy, oz + 2.0f, GetPhaseMask(), ignoreFlags); + return GetMap()->isInLineOfSight(x, y, z + 2.0f, ox, oy, oz + 2.0f, GetPhaseMask(), checks, ignoreFlags); } return true; } -Position WorldObject::GetHitSpherePointFor(Position const& dest) const +bool WorldObject::IsWithinLOSInMap(const WorldObject* obj, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const { - G3D::Vector3 vThis(GetPositionX(), GetPositionY(), GetPositionZ()); - G3D::Vector3 vObj(dest.GetPositionX(), dest.GetPositionY(), dest.GetPositionZ()); - G3D::Vector3 contactPoint = vThis + (vObj - vThis).directionOrZero() * std::min(dest.GetExactDist(GetPosition()), GetCombatReach()); + if (!IsInMap(obj)) + return false; - return Position(contactPoint.x, contactPoint.y, contactPoint.z, GetAngle(contactPoint.x, contactPoint.y)); + float x, y, z; + if (obj->GetTypeId() == TYPEID_PLAYER) + obj->GetPosition(x, y, z); + else + obj->GetHitSpherePointFor(GetPosition(), x, y, z); + + return IsWithinLOS(x, y, z, checks, ignoreFlags); } void WorldObject::GetHitSpherePointFor(Position const& dest, float& x, float& y, float& z) const diff --git a/src/server/game/Entities/Object/Object.h b/src/server/game/Entities/Object/Object.h index 56842bd6d1e..c949d1fd524 100644 --- a/src/server/game/Entities/Object/Object.h +++ b/src/server/game/Entities/Object/Object.h @@ -490,8 +490,8 @@ class TC_GAME_API WorldObject : public Object, public WorldLocation // use only if you will sure about placing both object at same map bool IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true) const; bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true, bool incOwnRadius = true, bool incTargetRadius = true) const; - bool IsWithinLOS(float x, float y, float z, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing) const; - bool IsWithinLOSInMap(WorldObject const* obj, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing) const; + bool IsWithinLOS(float x, float y, float z, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing) const; + bool IsWithinLOSInMap(WorldObject const* obj, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags ignoreFlags = VMAP::ModelIgnoreFlags::Nothing) const; 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; diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 41e8129889f..2e956616e09 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -2713,10 +2713,15 @@ 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, VMAP::ModelIgnoreFlags ignoreFlags) const +bool Map::isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const { - return VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2, ignoreFlags) - && _dynamicTree.isInLineOfSight(x1, y1, z1, x2, y2, z2, phasemask); + if ((checks & LINEOFSIGHT_CHECK_VMAP) + && !VMAP::VMapFactory::createOrGetVMapManager()->isInLineOfSight(GetId(), x1, y1, z1, x2, y2, z2, 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; } bool Map::getObjectHitPos(uint32 phasemask, float x1, float y1, float z1, float x2, float y2, float z2, float& rx, float& ry, float& rz, float modifyDist) diff --git a/src/server/game/Maps/Map.h b/src/server/game/Maps/Map.h index ec7f1cc8752..5f55fc4f8f4 100644 --- a/src/server/game/Maps/Map.h +++ b/src/server/game/Maps/Map.h @@ -176,6 +176,14 @@ struct PositionFullTerrainStatus Optional<LiquidData> liquidInfo; }; +enum LineOfSightChecks +{ + LINEOFSIGHT_CHECK_VMAP = 0x1, // check static floor layout data + LINEOFSIGHT_CHECK_GOBJECT = 0x2, // check dynamic game object data + + LINEOFSIGHT_ALL_CHECKS = (LINEOFSIGHT_CHECK_VMAP | LINEOFSIGHT_CHECK_GOBJECT) +}; + class TC_GAME_API GridMap { uint32 _flags; @@ -519,7 +527,7 @@ class TC_GAME_API Map : public GridRefManager<NGridType> float GetWaterOrGroundLevel(uint32 phasemask, float x, float y, float z, float* ground = NULL, bool swim = false) const; float GetHeight(uint32 phasemask, float x, float y, float z, bool vmap = true, float maxSearchDist = DEFAULT_HEIGHT_SEARCH) const; - bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, VMAP::ModelIgnoreFlags ignoreFlags) const; + bool isInLineOfSight(float x1, float y1, float z1, float x2, float y2, float z2, uint32 phasemask, LineOfSightChecks checks, VMAP::ModelIgnoreFlags ignoreFlags) const; void Balance() { _dynamicTree.balance(); } void RemoveGameObjectModel(const GameObjectModel& model) { _dynamicTree.remove(model); } void InsertGameObjectModel(const GameObjectModel& model) { _dynamicTree.insert(model); } diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index 7b88ff487fd..1b16666eb92 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -1852,7 +1852,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, VMAP::ModelIgnoreFlags::M2)) + if ((deficit > maxHPDeficit || foundItr == tempTargets.end()) && target->IsWithinDist(unit, jumpRadius) && target->IsWithinLOSInMap(unit, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2)) { foundItr = itr; maxHPDeficit = deficit; @@ -1867,10 +1867,10 @@ void Spell::SearchChainTargets(std::list<WorldObject*>& targets, uint32 chainTar { if (foundItr == tempTargets.end()) { - if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr, VMAP::ModelIgnoreFlags::M2)) + if ((!isBouncingFar || target->IsWithinDist(*itr, jumpRadius)) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2)) foundItr = itr; } - else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr, VMAP::ModelIgnoreFlags::M2)) + else if (target->GetDistanceOrder(*itr, *foundItr) && target->IsWithinLOSInMap(*itr, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2)) foundItr = itr; } } @@ -4998,7 +4998,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint if (DynamicObject* dynObj = m_caster->GetDynObject(m_triggeredByAuraSpell->Id)) losTarget = dynObj; - if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget, VMAP::ModelIgnoreFlags::M2)) + if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !target->IsWithinLOSInMap(losTarget, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2)) return SPELL_FAILED_LINE_OF_SIGHT; } } @@ -5010,7 +5010,7 @@ SpellCastResult Spell::CheckCast(bool strict, uint32* param1 /*= nullptr*/, uint float x, y, z; m_targets.GetDstPos()->GetPosition(x, y, z); - if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z, VMAP::ModelIgnoreFlags::M2)) + if (!m_spellInfo->HasAttribute(SPELL_ATTR2_CAN_TARGET_NOT_IN_LOS) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_SPELL, m_spellInfo->Id, NULL, SPELL_DISABLE_LOS) && !m_caster->IsWithinLOS(x, y, z, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2)) return SPELL_FAILED_LINE_OF_SIGHT; } @@ -6891,7 +6891,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo { if (!m_targets.GetCorpseTargetGUID()) { - if (target->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE)) + if (target->IsWithinLOSInMap(m_caster, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2) && target->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_SKINNABLE)) return true; return false; @@ -6907,7 +6907,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo if (!corpse->HasFlag(CORPSE_FIELD_FLAGS, CORPSE_FLAG_LOOTABLE)) return false; - if (!corpse->IsWithinLOSInMap(m_caster, VMAP::ModelIgnoreFlags::M2)) + if (!corpse->IsWithinLOSInMap(m_caster, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2)) return false; break; @@ -6915,7 +6915,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo default: // normal case { if (losPosition) - return target->IsWithinLOS(losPosition->GetPositionX(), losPosition->GetPositionY(), losPosition->GetPositionZ(), VMAP::ModelIgnoreFlags::M2); + return target->IsWithinLOS(losPosition->GetPositionX(), losPosition->GetPositionY(), losPosition->GetPositionZ(), LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2); else { // Get GO cast coordinates if original caster -> GO @@ -6924,7 +6924,7 @@ bool Spell::CheckEffectTarget(Unit const* target, uint32 eff, Position const* lo caster = m_caster->GetMap()->GetGameObject(m_originalCasterGUID); if (!caster) caster = m_caster; - if (target != m_caster && !target->IsWithinLOSInMap(caster, VMAP::ModelIgnoreFlags::M2)) + if (target != m_caster && !target->IsWithinLOSInMap(caster, LINEOFSIGHT_ALL_CHECKS, VMAP::ModelIgnoreFlags::M2)) return false; } break; diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index a3eae2f7679..2f09d03893f 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1346,6 +1346,9 @@ void World::LoadConfigSettings(bool reload) // Allow to cache data queries m_bool_configs[CONFIG_CACHE_DATA_QUERIES] = sConfigMgr->GetBoolDefault("CacheDataQueries", true); + // Whether to use LoS from game objects + m_bool_configs[CONFIG_CHECK_GOBJECT_LOS] = sConfigMgr->GetBoolDefault("CheckGameObjectLoS", true); + // call ScriptMgr if we're reloading the configuration if (reload) sScriptMgr->OnConfigLoad(reload); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 1eec3d45f53..a976ba5bd7b 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -178,6 +178,7 @@ enum WorldBoolConfigs CONFIG_HOTSWAP_PREFIX_CORRECTION_ENABLED, CONFIG_PREVENT_RENAME_CUSTOMIZATION, CONFIG_CACHE_DATA_QUERIES, + CONFIG_CHECK_GOBJECT_LOS, BOOL_CONFIG_VALUE_COUNT }; diff --git a/src/server/scripts/Commands/cs_debug.cpp b/src/server/scripts/Commands/cs_debug.cpp index 8406139d018..2adab479d44 100644 --- a/src/server/scripts/Commands/cs_debug.cpp +++ b/src/server/scripts/Commands/cs_debug.cpp @@ -1100,8 +1100,15 @@ public: static bool HandleDebugLoSCommand(ChatHandler* handler, char const* /*args*/) { if (Unit* unit = handler->getSelectedUnit()) - handler->PSendSysMessage("Unit %s (GuidLow: %u) is %sin LoS", unit->GetName().c_str(), unit->GetGUID().GetCounter(), handler->GetSession()->GetPlayer()->IsWithinLOSInMap(unit) ? "" : "not "); - return true; + { + 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("%s is %sin line of sight of %s.", unit->GetName().c_str(), (player->IsWithinLOSInMap(unit) ? "" : "not "), player->GetName().c_str()); + return true; + } + return false; } static bool HandleDebugSetAuraStateCommand(ChatHandler* handler, char const* args) diff --git a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp index f0490e7d1d4..29e0d9f1555 100644 --- a/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp +++ b/src/server/scripts/Northrend/Naxxramas/boss_sapphiron.cpp @@ -340,6 +340,7 @@ class boss_sapphiron : public CreatureScript case EVENT_EXPLOSION: DoCastAOE(SPELL_FROST_BREATH); DoCastAOE(SPELL_FROST_BREATH_ANTICHEAT); + instance->DoRemoveAurasDueToSpellOnPlayers(SPELL_ICEBOLT); events.ScheduleEvent(EVENT_LAND, Seconds(3) + Milliseconds(500), 0, PHASE_FLIGHT); return; case EVENT_LAND: @@ -505,81 +506,6 @@ class spell_sapphiron_icebolt : public SpellScriptLoader } }; -// @hack Hello, developer from the future! How has your day been? -// Anyway, this is, as you can undoubtedly see, a hack to emulate line of sight checks on a spell that abides line of sight anyway. -// In the current core, line of sight is not properly checked for people standing behind an ice block. This is not a good thing and kills people. -// Thus, we have this hack to check for ice block LoS in a "safe" way. Kind of. It's inaccurate, but in a good way (tends to save people when it shouldn't in edge cases). -// If LoS handling is better in whatever the current revision is when you read this, please get rid of the hack. Thanks! -class spell_sapphiron_frost_breath : public SpellScriptLoader -{ - public: - spell_sapphiron_frost_breath() : SpellScriptLoader("spell_sapphiron_frost_breath") { } - - class spell_sapphiron_frost_breath_SpellScript : public SpellScript - { - PrepareSpellScript(spell_sapphiron_frost_breath_SpellScript); - - bool Validate(SpellInfo const* /*spell*/) override - { - return !!sSpellMgr->GetSpellInfo(SPELL_FROST_BREATH); - } - - void HandleTargets(std::list<WorldObject*>& targetList) - { - std::list<GameObject*> blocks; - if (GetCaster()) - GetCaster()->GetGameObjectListWithEntryInGrid(blocks, GO_ICEBLOCK, 200.0f); - - std::vector<Unit*> toRemove; - toRemove.reserve(3); - std::list<WorldObject*>::iterator it = targetList.begin(); - while (it != targetList.end()) - { - Unit* target = (*it)->ToUnit(); - if (!target) - { - it = targetList.erase(it); - continue; - } - - if (target->HasAura(SPELL_ICEBOLT)) - { - it = targetList.erase(it); - toRemove.push_back(target); - continue; - } - - bool found = false; - for (GameObject* block : blocks) - if (block->IsInBetween(GetCaster(), target, 2.0f) && GetCaster()->GetExactDist2d(block) + 5 >= GetCaster()->GetExactDist2d(target)) - { - found = true; - break; - } - if (found) - { - it = targetList.erase(it); - continue; - } - ++it; - } - - for (Unit* block : toRemove) - block->RemoveAura(SPELL_ICEBOLT); - } - - void Register() override - { - OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(spell_sapphiron_frost_breath_SpellScript::HandleTargets, EFFECT_0, TARGET_UNIT_DEST_AREA_ENEMY); - } - }; - - SpellScript* GetSpellScript() const override - { - return new spell_sapphiron_frost_breath_SpellScript(); - } -}; - class spell_sapphiron_summon_blizzard : public SpellScriptLoader { public: @@ -641,7 +567,6 @@ void AddSC_boss_sapphiron() new go_sapphiron_birth(); new spell_sapphiron_change_blizzard_target(); new spell_sapphiron_icebolt(); - new spell_sapphiron_frost_breath(); new spell_sapphiron_summon_blizzard(); new achievement_the_hundred_club(); } diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index ec4d6ac83ad..a4943047a97 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -400,6 +400,15 @@ vmap.enableIndoorCheck = 1 DetectPosCollision = 1 # +# CheckGameObjectLoS +# Description: Include dynamic game objects (doors, chests etc.) in line of sight checks. +# This increases CPU usage somewhat. +# Default: 1 - (Enabled) +# 0 - (Disabled, may break some boss encounters) + +CheckGameObjectLoS = 1 + +# # TargetPosRecalculateRange # Description: Max distance from movement target point (+moving unit size) and targeted # object (+size) after that new target movement point calculated. |