8587 | | |
8588 | | // player visible for other player if not logout and at same transport |
8589 | | // including case when player is out of world |
8590 | | bool at_same_transport = |
8591 | | GetTypeId() == TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER && |
8592 | | !((Player*)this)->GetSession()->PlayerLogout() && !((Player*)u)->GetSession()->PlayerLogout() && |
8593 | | !((Player*)this)->GetSession()->PlayerLoading() && !((Player*)u)->GetSession()->PlayerLoading() && |
8594 | | ((Player*)this)->GetTransport() && ((Player*)this)->GetTransport() == ((Player*)u)->GetTransport(); |
8595 | | |
8596 | | // not in world |
8597 | | if(!at_same_transport && (!IsInWorld() || !u->IsInWorld())) |
8598 | | return false; |
8599 | | |
8600 | | // forbidden to seen (at GM respawn command) |
8601 | | if(m_Visibility==VISIBILITY_RESPAWN) |
8602 | | return false; |
8603 | | |
8604 | | // always seen by owner |
8605 | | if(GetCharmerOrOwnerGUID()==u->GetGUID()) |
8606 | | return true; |
8607 | | |
8608 | | // Grid dead/alive checks |
8609 | | if( u->GetTypeId()==TYPEID_PLAYER) |
8610 | | { |
8611 | | // non visible at grid for any stealth state |
8612 | | if(!IsVisibleInGridForPlayer((Player *)u)) |
8613 | | return false; |
8614 | | |
8615 | | // if player is dead then he can't detect anyone in anycases |
8616 | | if(!u->isAlive()) |
8617 | | detect = false; |
8618 | | } |
8619 | | else |
8620 | | { |
8621 | | // all dead creatures/players not visible for any creatures |
8622 | | if(!u->isAlive() || !isAlive()) |
8623 | | return false; |
8624 | | } |
8625 | | |
8626 | | // If the player is currently possessing, update visibility from the possessed unit's location |
8627 | | const Unit* target = u->GetTypeId() == TYPEID_PLAYER && u->isPossessing() ? u->GetCharm() : u; |
8628 | | |
8629 | | // different visible distance checks |
8630 | | if(u->isInFlight()) // what see player in flight |
8631 | | { |
8632 | | // use object grey distance for all (only see objects any way) |
8633 | | if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceInFlight()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) |
8634 | | return false; |
8635 | | } |
8636 | | else if(!isAlive()) // distance for show body |
8637 | | { |
8638 | | if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceForObject()+(inVisibleList ? World::GetVisibleObjectGreyDistance() : 0.0f))) |
8639 | | return false; |
8640 | | } |
8641 | | else if(GetTypeId()==TYPEID_PLAYER) // distance for show player |
8642 | | { |
8643 | | if(u->GetTypeId()==TYPEID_PLAYER) |
8644 | | { |
8645 | | // Players far than max visible distance for player or not in our map are not visible too |
8646 | | if (!at_same_transport && !IsWithinDistInMap(target,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) |
8647 | | return false; |
8648 | | } |
8649 | | else |
8650 | | { |
8651 | | // Units far than max visible distance for creature or not in our map are not visible too |
8652 | | // Active unit should always be visibile |
8653 | | if (!IsWithinDistInMap(target, target->isActive() |
8654 | | ? (MAX_VISIBILITY_DISTANCE - (inVisibleList ? 0.0f : World::GetVisibleUnitGreyDistance())) |
8655 | | : (World::GetMaxVisibleDistanceForCreature() + (inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f)))) |
8656 | | return false; |
8657 | | } |
8658 | | } |
8659 | | else if(GetCharmerOrOwnerGUID()) // distance for show pet/charmed |
8660 | | { |
8661 | | // Pet/charmed far than max visible distance for player or not in our map are not visible too |
8662 | | if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceForPlayer()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) |
8663 | | return false; |
8664 | | } |
8665 | | else // distance for show creature |
8666 | | { |
8667 | | // Units far than max visible distance for creature or not in our map are not visible too |
8668 | | if (!IsWithinDistInMap(target,World::GetMaxVisibleDistanceForCreature()+(inVisibleList ? World::GetVisibleUnitGreyDistance() : 0.0f))) |
8669 | | return false; |
8670 | | } |
8671 | | |
8672 | | // Visible units, always are visible for all units, except for units under invisibility |
8673 | | if (m_Visibility == VISIBILITY_ON && u->m_invisibilityMask==0) |
8674 | | return true; |
8675 | | |
8676 | | // GMs see any players, not higher GMs and all units |
8677 | | if (u->GetTypeId() == TYPEID_PLAYER && ((Player *)u)->isGameMaster()) |
8678 | | { |
8679 | | if(GetTypeId() == TYPEID_PLAYER) |
8680 | | return ((Player *)this)->GetSession()->GetSecurity() <= ((Player *)u)->GetSession()->GetSecurity(); |
8681 | | else |
| 8592 | AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); // Hunter mark |
| 8593 | for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) |
| 8594 | if((*iter)->GetCasterGUID()==u->GetGUID()) |
8683 | | } |
8684 | | |
8685 | | // non faction visibility non-breakable for non-GMs |
8686 | | if (m_Visibility == VISIBILITY_OFF) |
8687 | | return false; |
8688 | | |
8689 | | // raw invisibility |
8690 | | bool invisible = (m_invisibilityMask != 0 || u->m_invisibilityMask !=0); |
8691 | | |
8692 | | // detectable invisibility case |
8693 | | if( invisible && ( |
8694 | | // Invisible units, always are visible for units under same invisibility type |
8695 | | (m_invisibilityMask & u->m_invisibilityMask)!=0 || |
8696 | | // Invisible units, always are visible for unit that can detect this invisibility (have appropriate level for detect) |
8697 | | u->canDetectInvisibilityOf(this) || |
8698 | | // Units that can detect invisibility always are visible for units that can be detected |
8699 | | canDetectInvisibilityOf(u) )) |
8700 | | { |
8701 | | invisible = false; |
8702 | | } |
8703 | | |
8704 | | // special cases for always overwrite invisibility/stealth |
8705 | | if(invisible || m_Visibility == VISIBILITY_GROUP_STEALTH) |
8706 | | { |
8707 | | // non-hostile case |
8708 | | if (!u->IsHostileTo(this)) |
8709 | | { |
8710 | | // 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) |
8711 | | if(GetTypeId()==TYPEID_PLAYER && u->GetTypeId()==TYPEID_PLAYER) |
8712 | | { |
8713 | | if(((Player*)this)->IsGroupVisibleFor(((Player*)u))) |
8714 | | return true; |
8715 | | |
8716 | | // else apply same rules as for hostile case (detecting check for stealth) |
8717 | | } |
8718 | | } |
8719 | | // hostile case |
8720 | | else |
8721 | | { |
8722 | | // Hunter mark functionality |
8723 | | AuraList const& auras = GetAurasByType(SPELL_AURA_MOD_STALKED); |
8724 | | for(AuraList::const_iterator iter = auras.begin(); iter != auras.end(); ++iter) |
8725 | | if((*iter)->GetCasterGUID()==u->GetGUID()) |
8726 | | return true; |
8727 | | |
8728 | | // else apply detecting check for stealth |
8729 | | } |
8730 | | |
8731 | | // none other cases for detect invisibility, so invisible |
8732 | | if(invisible) |
8733 | | return false; |
8734 | | |
8735 | | // else apply stealth detecting check |
8736 | | } |
8737 | | |
8738 | | // unit got in stealth in this moment and must ignore old detected state |
8739 | | if (m_Visibility == VISIBILITY_GROUP_NO_DETECT) |
8740 | | return false; |
8741 | | |
8742 | | // GM invisibility checks early, invisibility if any detectable, so if not stealth then visible |
8743 | | if (m_Visibility != VISIBILITY_GROUP_STEALTH) |
8744 | | return true; |
8745 | | |
8746 | | // NOW ONLY STEALTH CASE |
8747 | | |
8748 | | // stealth and detected and visible for some seconds |
8749 | | if (u->GetTypeId() == TYPEID_PLAYER && ((Player*)u)->m_DetectInvTimer > 300 && ((Player*)u)->HaveAtClient(this)) |
8750 | | return true; |
8751 | | |
8752 | | //if in non-detect mode then invisible for unit |
8753 | | if (!detect) |
8754 | | return false; |
8755 | | |
8756 | | // Special cases |
8757 | | |
8758 | | // If is attacked then stealth is lost, some creature can use stealth too |
8759 | | if( !getAttackers().empty() ) |
8760 | | return true; |
8761 | | |
8762 | | // If there is collision rogue is seen regardless of level difference |
8763 | | // TODO: check sizes in DB |
8764 | | float distance = GetDistance(u); |
8765 | | if (distance < 0.24f) |
8766 | | return true; |
8767 | | |
8768 | | //If a mob or player is stunned he will not be able to detect stealth |
8769 | | if (u->hasUnitState(UNIT_STAT_STUNNED) && (u != this)) |
8770 | | return false; |
8771 | | |
8772 | | // Creature can detect target only in aggro radius |
8773 | | if(u->GetTypeId() != TYPEID_PLAYER) |
8774 | | { |
8775 | | //Always invisible from back and out of aggro range |
8776 | | bool isInFront = u->isInFront(this,((Creature const*)u)->GetAttackDistance(this)); |
8777 | | if(!isInFront) |
8778 | | return false; |
8779 | | } |
8780 | | else |
8781 | | { |
8782 | | //Always invisible from back |
8783 | | bool isInFront = u->isInFront(this,(GetTypeId()==TYPEID_PLAYER || GetCharmerOrOwnerGUID()) ? World::GetMaxVisibleDistanceForPlayer() : World::GetMaxVisibleDistanceForCreature()); |
8784 | | if(!isInFront) |
8785 | | return false; |
8786 | | } |
8787 | | |
8788 | | // if doesn't have stealth detection (Shadow Sight), then check how stealthy the unit is, otherwise just check los |
8789 | | if(!u->HasAuraType(SPELL_AURA_DETECT_STEALTH)) |
8790 | | { |
8791 | | //Calculation if target is in front |
8792 | | |
8793 | | //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) |
8794 | | float visibleDistance = 10.5f - (GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH)/100.0f); |
8795 | | |
8796 | | //Visible distance is modified by |
8797 | | //-Level Diff (every level diff = 1.0f in visible distance) |
8798 | | visibleDistance += int32(u->getLevelForTarget(this)) - int32(this->getLevelForTarget(u)); |
8799 | | |
8800 | | //This allows to check talent tree and will add addition stealth dependent on used points) |
8801 | | int32 stealthMod = GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL); |
8802 | | if(stealthMod < 0) |
8803 | | stealthMod = 0; |
8804 | | |
8805 | | //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) |
8806 | | //based on wowwiki every 5 mod we have 1 more level diff in calculation |
8807 | | visibleDistance += (int32(u->GetTotalAuraModifier(SPELL_AURA_MOD_DETECT)) - stealthMod)/5.0f; |
8808 | | |
8809 | | if(distance > visibleDistance) |
8810 | | return false; |
8811 | | } |
8812 | | |
8813 | | // Now check is target visible with LoS |
8814 | | float ox,oy,oz; |
8815 | | u->GetPosition(ox,oy,oz); |
8816 | | return IsWithinLOS(ox,oy,oz); |
8817 | | } |
8818 | | |
8819 | | void Unit::SetVisibility(UnitVisibility x) |
8820 | | { |
8821 | | m_Visibility = x; |
8822 | | |
8823 | | if(IsInWorld()) |
8824 | | { |
8825 | | Map *m = MapManager::Instance().GetMap(GetMapId(), this); |
8826 | | |
8827 | | if(GetTypeId()==TYPEID_PLAYER) |
8828 | | m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); |
8829 | | else |
8830 | | m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); |
8831 | | } |
8832 | | } |
8833 | | |
8834 | | bool Unit::canDetectInvisibilityOf(Unit const* u) const |
8835 | | { |
| 8596 | |
| 8631 | } |
| 8632 | |
| 8633 | bool Unit::canDetectStealthOf(Unit const* target, float distance) const |
| 8634 | { |
| 8635 | if(hasUnitState(UNIT_STAT_STUNNED)) |
| 8636 | return false; |
| 8637 | if(distance < 0.24f) //collision |
| 8638 | return true; |
| 8639 | if(!HasInArc(M_PI, target)) //behind |
| 8640 | return false; |
| 8641 | if(HasAuraType(SPELL_AURA_DETECT_STEALTH)) |
| 8642 | return true; |
| 8643 | |
| 8644 | //Visible distance based on stealth value (stealth rank 4 300MOD, 10.5 - 3 = 7.5) |
| 8645 | float visibleDistance = 10.5f - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH) / 100.0f; |
| 8646 | //Visible distance is modified by -Level Diff (every level diff = 1.0f in visible distance) |
| 8647 | visibleDistance += int32(getLevelForTarget(target)) - int32(target->getLevelForTarget(this)); |
| 8648 | //-Stealth Mod(positive like Master of Deception) and Stealth Detection(negative like paranoia) |
| 8649 | //based on wowwiki every 5 mod we have 1 more level diff in calculation |
| 8650 | visibleDistance += (float)(GetTotalAuraModifier(SPELL_AURA_MOD_DETECT) - target->GetTotalAuraModifier(SPELL_AURA_MOD_STEALTH_LEVEL)) / 5.0f; |
| 8651 | |
| 8652 | return distance < visibleDistance; |
| 8653 | } |
| 8654 | |
| 8655 | void Unit::SetVisibility(UnitVisibility x) |
| 8656 | { |
| 8657 | m_Visibility = x; |
| 8658 | |
| 8659 | if(IsInWorld()) |
| 8660 | { |
| 8661 | Map *m = MapManager::Instance().GetMap(GetMapId(), this); |
| 8662 | |
| 8663 | if(GetTypeId()==TYPEID_PLAYER) |
| 8664 | m->PlayerRelocation((Player*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); |
| 8665 | else |
| 8666 | m->CreatureRelocation((Creature*)this,GetPositionX(),GetPositionY(),GetPositionZ(),GetOrientation()); |
| 8667 | } |