diff options
Diffstat (limited to 'src/game')
| -rw-r--r-- | src/game/Creature.cpp | 47 | ||||
| -rw-r--r-- | src/game/Creature.h | 3 | ||||
| -rw-r--r-- | src/game/Object.cpp | 2 | ||||
| -rw-r--r-- | src/game/OutdoorPvPObjectiveAI.cpp | 6 | ||||
| -rw-r--r-- | src/game/Player.cpp | 108 | ||||
| -rw-r--r-- | src/game/Player.h | 5 | ||||
| -rw-r--r-- | src/game/SpellAuras.cpp | 13 | ||||
| -rw-r--r-- | src/game/SpellEffects.cpp | 7 | ||||
| -rw-r--r-- | src/game/Unit.cpp | 306 | ||||
| -rw-r--r-- | src/game/Unit.h | 8 |
10 files changed, 232 insertions, 273 deletions
diff --git a/src/game/Creature.cpp b/src/game/Creature.cpp index b15010ec67d..0bb7c024c1a 100644 --- a/src/game/Creature.cpp +++ b/src/game/Creature.cpp @@ -319,6 +319,10 @@ bool Creature::UpdateEntry(uint32 Entry, uint32 team, const CreatureData *data ) m_spells[2] = GetCreatureInfo()->spell3; m_spells[3] = GetCreatureInfo()->spell4; + // HACK: trigger creature is always not selectable + if(GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER) + SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE); + return true; } @@ -1487,6 +1491,47 @@ void Creature::DeleteFromDB() WorldDatabase.CommitTransaction(); } +bool Creature::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList) const +{ + // not in world + if(!IsInWorld() || !u->IsInWorld()) + return false; + + // all dead creatures/players not visible for any creatures + if(!u->isAlive() || !isAlive()) + return false; + + // Always can see self + if (u == this) + return true; + + // always seen by owner + if(GetGUID() == u->GetCharmerOrOwnerGUID()) + return true; + + if(u->GetVisibility() == VISIBILITY_OFF) //GM + return false; + + // invisible aura + if((m_invisibilityMask || u->m_invisibilityMask) && !canDetectInvisibilityOf(u)) + return false; + + // unit got in stealth in this moment and must ignore old detected state + //if (m_Visibility == VISIBILITY_GROUP_NO_DETECT) + // return false; + + // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible + if(u->GetVisibility() == VISIBILITY_GROUP_STEALTH) + { + //do not know what is the use of this detect + if(!detect || !canDetectStealthOf(u, GetDistance(u))) + return false; + } + + // Now check is target visible with LoS + return u->IsWithinLOS(GetPositionX(),GetPositionY(),GetPositionZ()); +} + float Creature::GetAttackDistance(Unit const* pl) const { float aggroRate = sWorld.getRate(RATE_CREATURE_AGGRO); @@ -1698,7 +1743,7 @@ SpellEntry const *Creature::reachWithSpellCure(Unit *pVictim) return NULL; } -bool Creature::IsVisibleInGridForPlayer(Player* pl) const +bool Creature::IsVisibleInGridForPlayer(Player const* pl) const { // gamemaster in GM mode see all, including ghosts if(pl->isGameMaster()) diff --git a/src/game/Creature.h b/src/game/Creature.h index 679b17f416f..e65c72465f2 100644 --- a/src/game/Creature.h +++ b/src/game/Creature.h @@ -547,6 +547,7 @@ class TRINITY_DLL_SPEC Creature : public Unit CreatureSpellCooldowns m_CreatureCategoryCooldowns; uint32 m_GlobalCooldown; + bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList) const; float GetAttackDistance(Unit const* pl) const; void CallAssistence(); @@ -560,7 +561,7 @@ class TRINITY_DLL_SPEC Creature : public Unit Cell const& GetCurrentCell() const { return m_currentCell; } void SetCurrentCell(Cell const& cell) { m_currentCell = cell; } - bool IsVisibleInGridForPlayer(Player* pl) const; + bool IsVisibleInGridForPlayer(Player const* pl) const; void RemoveCorpse(); diff --git a/src/game/Object.cpp b/src/game/Object.cpp index 4fbd030217a..568e9a90a31 100644 --- a/src/game/Object.cpp +++ b/src/game/Object.cpp @@ -1486,7 +1486,7 @@ Creature* WorldObject::SummonCreature(uint32 id, float x, float y, float z, floa { if(GetTypeId() == TYPEID_UNIT || GetTypeId() == TYPEID_PLAYER) pCreature->setFaction(((Unit*)this)->getFaction()); - pCreature->CastSpell(pCreature, pCreature->m_spells[0], true, 0, 0, GetGUID()); + pCreature->CastSpell(pCreature, pCreature->m_spells[0], false, 0, 0, GetGUID()); } //return the creature therewith the summoner has access to it diff --git a/src/game/OutdoorPvPObjectiveAI.cpp b/src/game/OutdoorPvPObjectiveAI.cpp index fc762f77e7a..62c4cb96191 100644 --- a/src/game/OutdoorPvPObjectiveAI.cpp +++ b/src/game/OutdoorPvPObjectiveAI.cpp @@ -50,13 +50,13 @@ bool OutdoorPvPObjectiveAI::IsVisible(Unit *pl) const void OutdoorPvPObjectiveAI::AttackStart(Unit *) { - EnterEvadeMode(); + //EnterEvadeMode(); } void OutdoorPvPObjectiveAI::EnterEvadeMode() { - i_creature.DeleteThreatList(); - i_creature.CombatStop(); +// i_creature.DeleteThreatList(); +// i_creature.CombatStop(); } void OutdoorPvPObjectiveAI::UpdateAI(const uint32 diff) diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 7723cb23a3b..e02ac468244 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -2000,8 +2000,8 @@ void Player::SetGMVisible(bool on) // Reapply stealth/invisibility if active or show if not any if(HasAuraType(SPELL_AURA_MOD_STEALTH)) SetVisibility(VISIBILITY_GROUP_STEALTH); - else if(HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) - SetVisibility(VISIBILITY_GROUP_INVISIBILITY); + //else if(HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) + // SetVisibility(VISIBILITY_GROUP_INVISIBILITY); else SetVisibility(VISIBILITY_ON); } @@ -16395,7 +16395,6 @@ void Player::HandleStealthedUnitsDetection() if ((*i)->isVisibleForOrDetect(this,true)) { - (*i)->SendUpdateToPlayer(this); m_clientGUIDs.insert((*i)->GetGUID()); @@ -17188,7 +17187,108 @@ void Player::ReportedAfkBy(Player* reporter) } } -bool Player::IsVisibleInGridForPlayer( Player* pl ) const +bool Player::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList) const +{ + // Always can see self + if (u == this) + return true; + + // player visible for other player if not logout and at same transport + // including case when player is out of world + bool at_same_transport = + GetTransport() && u->GetTypeId() == TYPEID_PLAYER + && !GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() + && !GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() + && GetTransport() == ((Player*)u)->GetTransport(); + + // not in world + if(!at_same_transport && (!IsInWorld() || !u->IsInWorld())) + return false; + + // forbidden to seen (at GM respawn command) + if(u->GetVisibility() == VISIBILITY_RESPAWN) + return false; + + // always seen by owner + if(GetGUID() == u->GetCharmerOrOwnerGUID()) + return true; + + // Grid dead/alive checks + // non visible at grid for any stealth state + if(!u->IsVisibleInGridForPlayer(this)) + return false; + + // If the player is currently possessing, update visibility from the possessed unit's location + const Unit* target = isPossessing() ? GetCharm() : this; + + // different visible distance checks + if(isInFlight()) // what see player in flight + { + if (!target->IsWithinDistInMap(u,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) + return false; + } + else if(!u->isAlive()) // distance for show body + { + if (!target->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) + return false; + } + else if(u->GetTypeId()==TYPEID_PLAYER) // distance for show player + { + // Players far than max visible distance for player or not in our map are not visible too + if (!at_same_transport && !target->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) + return false; + } + else if(u->GetCharmerOrOwnerGUID()) // distance for show pet/charmed + { + // Pet/charmed far than max visible distance for player or not in our map are not visible too + if (!target->IsWithinDistInMap(u,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) + return false; + } + else // distance for show creature + { + // Units far than max visible distance for creature or not in our map are not visible too + if (!target->IsWithinDistInMap(u, target->isActive() + ? (MAX_VISIBILITY_DISTANCE - (inVisibleList ? 0.0f : World::GetVisibleUnitGreyDistance())) + : (World::GetMaxVisibleDistanceForCreature() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))) + return false; + } + + // GMs see any players, not higher GMs and all units + if(isGameMaster()) + { + if(u->GetTypeId() == TYPEID_PLAYER) + return ((Player *)u)->GetSession()->GetSecurity() <= GetSession()->GetSecurity(); + else + return true; + } + + if(u->GetVisibility() == VISIBILITY_OFF) + return false; + + // player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting) + if((m_invisibilityMask || u->m_invisibilityMask) && !canDetectInvisibilityOf(u)) + if(!(u->GetTypeId()==TYPEID_PLAYER && !IsHostileTo(u) && IsGroupVisibleFor(((Player*)u)))) + return false; + + // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible + if(u->GetVisibility() == VISIBILITY_GROUP_STEALTH) + { + // if player is dead then he can't detect anyone in anycases + //do not know what is the use of this detect + // stealth and detected and visible for some seconds + if(!isAlive()) + detect = false; + if(m_DetectInvTimer < 300 || !HaveAtClient(u)) + if(!(u->GetTypeId()==TYPEID_PLAYER && !IsHostileTo(u) && IsGroupVisibleFor(((Player*)u)))) + if(!detect || !canDetectStealthOf(u, GetDistance(u))) + return false; + } + + // Now check is target visible with LoS + return u->IsWithinLOS(GetPositionX(),GetPositionY(),GetPositionZ()); +} + +bool Player::IsVisibleInGridForPlayer( Player const * pl ) const { // gamemaster in GM mode see all, including ghosts if(pl->isGameMaster() && GetSession()->GetSecurity() <= pl->GetSession()->GetSecurity()) diff --git a/src/game/Player.h b/src/game/Player.h index f8865040a9e..2e8de5e5823 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -1992,9 +1992,10 @@ class TRINITY_DLL_SPEC Player : public Unit typedef std::set<uint64> ClientGUIDs; ClientGUIDs m_clientGUIDs; - bool HaveAtClient(WorldObject const* u) { return u==this || m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); } + bool HaveAtClient(WorldObject const* u) const { return u==this || m_clientGUIDs.find(u->GetGUID())!=m_clientGUIDs.end(); } - bool IsVisibleInGridForPlayer(Player* pl) const; + bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList) const; + bool IsVisibleInGridForPlayer(Player const* pl) const; bool IsVisibleGloballyFor(Player* pl) const; void UpdateVisibilityOf(WorldObject* target); diff --git a/src/game/SpellAuras.cpp b/src/game/SpellAuras.cpp index d0a70858b71..1d7df27a76f 100644 --- a/src/game/SpellAuras.cpp +++ b/src/game/SpellAuras.cpp @@ -3230,7 +3230,8 @@ void Aura::HandleModStealth(bool apply, bool Real) // apply only if not in GM invisibility (and overwrite invisibility state) if(m_target->GetVisibility()!=VISIBILITY_OFF) { - m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT); + //m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT); + m_target->SetVisibility(VISIBILITY_OFF); m_target->SetVisibility(VISIBILITY_GROUP_STEALTH); } @@ -3258,8 +3259,9 @@ void Aura::HandleModStealth(bool apply, bool Real) // restore invisibility if any if(m_target->HasAuraType(SPELL_AURA_MOD_INVISIBILITY)) { - m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT); - m_target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY); + //m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT); + //m_target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY); + m_target->SetVisibility(VISIBILITY_ON); } else { @@ -3314,8 +3316,9 @@ void Aura::HandleInvisibility(bool apply, bool Real) if(m_target->GetVisibility()==VISIBILITY_ON) { // Aura not added yet but visibility code expect temporary add aura - m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT); - m_target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY); + //m_target->SetVisibility(VISIBILITY_GROUP_NO_DETECT); + //m_target->SetVisibility(VISIBILITY_GROUP_INVISIBILITY); + m_target->SetVisibility(VISIBILITY_ON); } } else diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index e8060d282e6..eeafd0d024e 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -3576,6 +3576,13 @@ void Spell::EffectSummonGuardian(uint32 i) return; } + // trigger + if(m_spellInfo->Id == 40276) + { + EffectSummonWild(i); + return; + } + // set timer for unsummon int32 duration = GetSpellDuration(m_spellInfo); diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index 0c94c095c3e..00cd8694b35 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -8506,9 +8506,6 @@ bool Unit::isTargetableForAttack() const if(HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE)) return false; - if(GetTypeId()==TYPEID_UNIT && (((Creature *)this)->GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER)) - return false; - return isAlive() && !hasUnitState(UNIT_STAT_DIED)&& !isInFlight() /*&& !isStealth()*/; } @@ -8580,240 +8577,79 @@ bool Unit::isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList) { if(!u) return false; + return u->canSeeOrDetect(this, detect, inVisibleList); +} - // Always can see self - if (u==this) - return true; - - // player visible for other player if not logout and at same transport - // including case when player is out of world - bool at_same_transport = - GetTypeId() == TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER && - !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() && - !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() && - ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport(); - - // not in world - if(!at_same_transport && (!IsInWorld() || !u->IsInWorld())) - return false; - - // forbidden to seen (at GM respawn command) - if(m_Visibility==VISIBILITY_RESPAWN) - return false; +bool Unit::canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList) const +{ + return true; +} - // always seen by owner - if(GetCharmerOrOwnerGUID()==u->GetGUID()) +bool Unit::canDetectInvisibilityOf(Unit const* u) const +{ + if(m_invisibilityMask & u->m_invisibilityMask) // same group return true; + AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); // Hunter mark + for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) + if((*iter)->GetCasterGUID()==u->GetGUID()) + return true; - // Grid dead/alive checks - if( u->GetTypeId()==TYPEID_PLAYER) - { - // non visible at grid for any stealth state - if(!IsVisibleInGridForPlayer((Player *)u)) - return false; - - // if player is dead then he can't detect anyone in anycases - if(!u->isAlive()) - detect = false; - } - else - { - // all dead creatures/players not visible for any creatures - if(!u->isAlive() || !isAlive()) - return false; - } - - // If the player is currently possessing, update visibility from the possessed unit's location - const Unit* target = u->GetTypeId() == TYPEID_PLAYER && u->isPossessing() ? u->GetCharm() : u; - - // different visible distance checks - if(u->isInFlight()) // what see player in flight - { - // use object grey distance for all (only see objects any way) - if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) - return false; - } - else if(!isAlive()) // distance for show body - { - if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) - return false; - } - else if(GetTypeId()==TYPEID_PLAYER) // distance for show player + if(uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask)) { - if(u->GetTypeId()==TYPEID_PLAYER) - { - // Players far than max visible distance for player or not in our map are not visible too - if (!at_same_transport && !IsWithinDistInMap(target,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) - return false; - } - else + for(uint32 i = 0; i < 10; ++i) { - // Units far than max visible distance for creature or not in our map are not visible too - // Active unit should always be visibile - if (!IsWithinDistInMap(target, target->isActive() - ? (MAX_VISIBILITY_DISTANCE - (inVisibleList ? 0.0f : World::GetVisibleUnitGreyDistance())) - : (World::GetMaxVisibleDistanceForCreature() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))) - return false; - } - } - else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed - { - // Pet/charmed far than max visible distance for player or not in our map are not visible too - if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) - return false; - } - else // distance for show creature - { - // Units far than max visible distance for creature or not in our map are not visible too - if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) - return false; - } - - // Visible units, always are visible for all units, except for units under invisibility - if (m_Visibility == VISIBILITY_ON && u->m_invisibilityMask==0) - return true; - - // GMs see any players, not higher GMs and all units - if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster()) - { - if(GetTypeId() == TYPEID_PLAYER) - return ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity(); - else - return true; - } - - // non faction visibility non-breakable for non-GMs - if (m_Visibility == VISIBILITY_OFF) - return false; - - // raw invisibility - bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask !=0); + if(((1 << i) & mask)==0) + continue; - // detectable invisibility case - if( invisible && ( - // Invisible units, always are visible for units under same invisibility type - (m_invisibilityMask & u->m_invisibilityMask)!=0 || - // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect) - u->canDetectInvisibilityOf(this) || - // Units that can detect invisibility always are visible for units that can be detected - canDetectInvisibilityOf(u) )) - { - invisible = false; - } + // find invisibility level + uint32 invLevel = 0; + Unit::AuraList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY); + for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr) + if(((*itr)->GetModifier()->m_miscvalue)==i && invLevel < (*itr)->GetModifier()->m_amount) + invLevel = (*itr)->GetModifier()->m_amount; - // special cases for always overwrite invisibility/stealth - if(invisible || m_Visibility == VISIBILITY_GROUP_STEALTH) - { - // non-hostile case - if (!u->IsHostileTo(this)) - { - // player see other player with stealth/invisibility only if he in same group or raid or same team (raid/team case dependent from conf setting) - if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER) + // find invisibility detect level + uint32 detectLevel = 0; + if(i==6 && GetTypeId()==TYPEID_PLAYER) // special drunk detection case { - if(((Player*)this)->IsGroupVisibleFor(((Player*)u))) - return true; - - // else apply same rules as for hostile case (detecting check for stealth) + detectLevel = ((Player*)this)->GetDrunkValue(); + } + else + { + Unit::AuraList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION); + for(Unit::AuraList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr) + if(((*itr)->GetModifier()->m_miscvalue)==i && detectLevel < (*itr)->GetModifier()->m_amount) + detectLevel = (*itr)->GetModifier()->m_amount; } - } - // hostile case - else - { - // Hunter mark functionality - AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); - for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) - if((*iter)->GetCasterGUID()==u->GetGUID()) - return true; - // else apply detecting check for stealth + if(invLevel <= detectLevel) + return true; } - - // none other cases for detect invisibility, so invisible - if(invisible) - return false; - - // else apply stealth detecting check } - // unit got in stealth in this moment and must ignore old detected state - if (m_Visibility == VISIBILITY_GROUP_NO_DETECT) - return false; - - // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible - if (m_Visibility != VISIBILITY_GROUP_STEALTH) - return true; - - // NOW ONLY STEALTH CASE - - // stealth and detected and visible for some seconds - if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->m_DetectInvTimer > 300 && ((Player*)u)->HaveAtClient(this)) - return true; + return false; +} - //if in non-detect mode then invisible for unit - if (!detect) +bool Unit::canDetectStealthOf(Unit const* target, float distance) const +{ + if(hasUnitState(UNIT_STAT_STUNNED)) return false; - - // Special cases - - // If is attacked then stealth is lost, some creature can use stealth too - if( !getAttackers().empty() ) - return true; - - // If there is collision rogue is seen regardless of level difference - // TODO: check sizes in DB - float distance = GetDistance(u); - if (distance < 0.24f) + if(distance < 0.24f) //collision return true; - - //If a mob or player is stunned he will not be able to detect stealth - if (u->hasUnitState(UNIT_STAT_STUNNED) && (u != this)) + if(!HasInArc(M_PI, target)) //behind return false; + if(HasAuraType(SPELL_AURA_DETECT_STEALTH)) + return true; - // Creature can detect target only in aggro radius - if(u->GetTypeId() != TYPEID_PLAYER) - { - //Always invisible from back and out of aggro range - bool isInFront = u->isInFront(this,((Creature const*)u)->GetAttackDistance(this)); - if(!isInFront) - return false; - } - else - { - //Always invisible from back - bool isInFront = u->isInFront(this,(GetTypeId()==TYPEID_PLAYER || GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature()); - if(!isInFront) - return false; - } - - // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los - if(!u->HasAuraType(SPELL_AURA_DETECT_STEALTH)) - { - //Calculation if target is in front - - //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) - float visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/100.0f); - - //Visible distance is modified by - //-Level Diff (every level diff = 1.0f in visible distance) - visibleDistance += int32(u->getLevelForTarget(this)) - int32(this->getLevelForTarget(u)); - - //This allows to check talent tree and will add addition stealth dependent on used points) - int32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL); - if(stealthMod < 0) - stealthMod = 0; - - //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) - //based on wowwiki every 5 mod we have 1 more level diff in calculation - visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT)) - stealthMod)/5.0f; - - if(distance > visibleDistance) - return false; - } + //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) + float visibleDistance = 10.5f - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH) / 100.0f; + //Visible distance is modified by -Level Diff (every level diff = 1.0f in visible distance) + visibleDistance += int32(getLevelForTarget(target)) - int32(target->getLevelForTarget(this)); + //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) + //based on wowwiki every 5 mod we have 1 more level diff in calculation + visibleDistance += (float)(GetTotalAuraModifier(SPELL_AURA_MOD_DETECT) - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL)) / 5.0f; - // Now check is target visible with LoS - float ox,oy,oz; - u->GetPosition(ox,oy,oz); - return IsWithinLOS(ox,oy,oz); + return distance < visibleDistance; } void Unit::SetVisibility(UnitVisibility x) @@ -8831,42 +8667,6 @@ void Unit::SetVisibility(UnitVisibility x) } } -bool Unit::canDetectInvisibilityOf(Unit const* u) const -{ - if(uint32 mask = (m_detectInvisibilityMask & u->m_invisibilityMask)) - { - for(uint32 i = 0; i < 10; ++i) - { - if(((1 << i) & mask)==0) - continue; - - // find invisibility level - uint32 invLevel = 0; - Unit::AuraList const& iAuras = u->GetAurasByType(SPELL_AURA_MOD_INVISIBILITY); - for(Unit::AuraList::const_iterator itr = iAuras.begin(); itr != iAuras.end(); ++itr) - if(((*itr)->GetModifier()->m_miscvalue)==i && invLevel < (*itr)->GetModifier()->m_amount) - invLevel = (*itr)->GetModifier()->m_amount; - - // find invisibility detect level - uint32 detectLevel = 0; - Unit::AuraList const& dAuras = GetAurasByType(SPELL_AURA_MOD_INVISIBILITY_DETECTION); - for(Unit::AuraList::const_iterator itr = dAuras.begin(); itr != dAuras.end(); ++itr) - if(((*itr)->GetModifier()->m_miscvalue)==i && detectLevel < (*itr)->GetModifier()->m_amount) - detectLevel = (*itr)->GetModifier()->m_amount; - - if(i==6 && GetTypeId()==TYPEID_PLAYER) // special drunk detection case - { - detectLevel = ((Player*)this)->GetDrunkValue(); - } - - if(invLevel <= detectLevel) - return true; - } - } - - return false; -} - void Unit::UpdateSpeed(UnitMoveType mtype, bool forced) { int32 main_speed_mod = 0; diff --git a/src/game/Unit.h b/src/game/Unit.h index 2482648180e..c113587a5ff 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -437,8 +437,8 @@ enum UnitVisibility VISIBILITY_OFF = 0, // absolute, not detectable, GM-like, can see all other VISIBILITY_ON = 1, VISIBILITY_GROUP_STEALTH = 2, // detect chance, seen and can see group members - VISIBILITY_GROUP_INVISIBILITY = 3, // invisibility, can see and can be seen only another invisible unit or invisible detection unit, set only if not stealthed, and in checks not used (mask used instead) - VISIBILITY_GROUP_NO_DETECT = 4, // state just at stealth apply for update Grid state. Don't remove, otherwise stealth spells will break + //VISIBILITY_GROUP_INVISIBILITY = 3, // invisibility, can see and can be seen only another invisible unit or invisible detection unit, set only if not stealthed, and in checks not used (mask used instead) + //VISIBILITY_GROUP_NO_DETECT = 4, // state just at stealth apply for update Grid state. Don't remove, otherwise stealth spells will break VISIBILITY_RESPAWN = 5 // special totally not detectable visibility for force delete object at respawn command }; @@ -1135,13 +1135,15 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void SetVisibility(UnitVisibility x); // common function for visibility checks for player/creatures with detection code + virtual bool canSeeOrDetect(Unit const* u, bool detect, bool inVisibleList) const; bool isVisibleForOrDetect(Unit const* u, bool detect, bool inVisibleList = false) const; bool canDetectInvisibilityOf(Unit const* u) const; + bool canDetectStealthOf(Unit const* u, float distance) const; // virtual functions for all world objects types bool isVisibleForInState(Player const* u, bool inVisibleList) const; // function for low level grid visibility checks in player/creature cases - virtual bool IsVisibleInGridForPlayer(Player* pl) const = 0; + virtual bool IsVisibleInGridForPlayer(Player const* pl) const = 0; bool waterbreath; AuraList & GetSingleCastAuras() { return m_scAuras; } |
