Index: src/game/Object.cpp =================================================================== --- src/game/Object.cpp (revision 3674) +++ src/game/Object.cpp (working copy) @@ -672,7 +672,8 @@ float dx = GetPositionX() - obj->GetPositionX(); float dy = GetPositionY() - obj->GetPositionY(); float dz = GetPositionZ() - obj->GetPositionZ(); - float sizefactor = GetObjectSize() + obj->GetObjectSize(); + float sizefactor = GetObjectSize() + obj->GetObjectSize()- 2.28; //size factor is too big student1 + if (sizefactor <= 0) sizefactor = 1; //makes sures values are not negative for too little objects student1 float dist = sqrt((dx*dx) + (dy*dy) + (dz*dz)) - sizefactor; return ( dist > 0 ? dist * dist : 0); } Index: src/game/Spell.cpp =================================================================== --- src/game/Spell.cpp (revision 3674) +++ src/game/Spell.cpp (working copy) @@ -43,6 +43,7 @@ #include "SharedDefines.h" #include "Tools.h" + #define SPELL_CHANNEL_UPDATE_INTERVAL 1000 extern pEffect SpellEffects[TOTAL_SPELL_EFFECTS]; @@ -1234,11 +1235,11 @@ if( ((Player*)m_caster)->HasMovementFlags(MOVEMENTFLAG_JUMPING) ) cancel(); - // check for incapacitating player states - if( m_caster->hasUnitState(UNIT_STAT_STUNDED) || + // check for incapacitating player states + if( (( m_caster->hasUnitState(UNIT_STAT_STUNDED) || m_caster->hasUnitState(UNIT_STAT_ROOT) || - m_caster->hasUnitState(UNIT_STAT_CONFUSED) ) - cancel(); + m_caster->hasUnitState(UNIT_STAT_CONFUSED))) && (m_spellInfo->SpellIconID != 252))//Player can use vanish even if he is incapacitated + cancel(); // check if player has turned if flag is set if( m_spellInfo->ChannelInterruptFlags & CHANNEL_FLAG_TURNING && m_castOrientation != m_caster->GetOrientation() ) @@ -1956,6 +1957,12 @@ } } + + // Target must not be in combat from what i know only R0gu3\S4p requires that + // TODO: find a correct mask ? + // if(m_spellInfo->SpellIconID == 249 && m_spellInfo->SpellFamilyName == SPELLFAMILY_ROGUE && target->isInCombat()) + // return SPELL_FAILED_TARGET_IN_COMBAT; + //Must be behind the target. if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) ) { @@ -1979,11 +1986,21 @@ if(m_spellInfo->AreaId && m_spellInfo->AreaId != m_caster->GetAreaId()) return SPELL_FAILED_REQUIRES_AREA; } + //If caster or target is a player that is stunned will not be able to restun that target again (student1) Also caster will not be able to stun a mob 5 levels higher + if (m_caster->hasUnitState(UNIT_STAT_STUNDED)) + return SPELL_FAILED_STUNNED; - if(m_caster->hasUnitState(UNIT_STAT_STUNDED)) + //If already stunned cannot restun player + if (((m_spellInfo->SpellIconID == 249) && (m_targets.getUnitTarget()->hasUnitState(UNIT_STAT_STUNDED)) + && (m_targets.getUnitTarget()->GetTypeId()==TYPEID_PLAYER))) return SPELL_FAILED_STUNNED; - // not let players cast non-triggered spells at mount (and let do it to creatures) + //will not be able to stun a high level player + if((target->getLevel() > m_caster->getLevel() + 10)&&(m_spellInfo->SpellIconID == 249) + && (target->GetTypeId()==TYPEID_PLAYER)) + return SPELL_FAILED_HIGHLEVEL; + + // not let players cast non-triggered spells at mount (and let do it to creatures) if(m_caster->IsMounted() && !m_IsTriggeredSpell && m_caster->GetTypeId()==TYPEID_PLAYER) return SPELL_FAILED_NOT_MOUNTED; @@ -2272,7 +2289,7 @@ //detect if any mod is in x range.if true,can't steath.FIX ME! if(m_spellInfo->Attributes == 169148432 || m_caster->GetTypeId() != TYPEID_PLAYER) break; - + // Find nearby creatures CellPair p(MaNGOS::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); Cell cell = RedZone::GetZone(p); cell.data.Part.reserved = ALL_DISTRICT; @@ -2285,7 +2302,11 @@ CellLock cell_lock(cell, p); cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); - if(found_creature) + + + // If mob found is not stunned or R0gu3\V4nish is not being used, can't stealth + if (((found_creature) && (m_spellInfo->SpellIconID != 252)) && + (!found_creature->hasUnitState(UNIT_STAT_STUNDED))) return SPELL_FAILED_CANT_STEALTH; };break; @@ -2822,3 +2843,7 @@ m_targets.Update(m_caster); } Index: src/game/Spell.h =================================================================== --- src/game/Spell.h (revision 3674) +++ src/game/Spell.h (working copy) @@ -418,6 +418,7 @@ public: void EffectNULL(uint32 ); + void EffectDistract(uint32 i); void EffectSchoolDMG(uint32 i); void EffectInstaKill(uint32 i); void EffectDummy(uint32 i); Index: src/game/SpellAuras.cpp =================================================================== --- src/game/SpellAuras.cpp (revision 3674) +++ src/game/SpellAuras.cpp (working copy) @@ -43,11 +43,14 @@ #include "ConfusedMovementGenerator.h" #include "TargetedMovementGenerator.h" #include "Formulas.h" +#include "CreatureAI.h" #include "BattleGround.h" -#include "CreatureAI.h" + + pAuraHandler AuraHandler[TOTAL_AURAS]= { + &Aura::HandleNULL, // 0 SPELL_AURA_NONE &Aura::HandleBindSight, // 1 SPELL_AURA_BIND_SIGHT &Aura::HandleModPossess, // 2 SPELL_AURA_MOD_POSSESS @@ -202,7 +205,7 @@ &Aura::HandleAuraTrackStealthed, //151 SPELL_AURA_TRACK_STEALTHED &Aura::HandleNULL, //152 SPELL_AURA_MOD_DETECTED_RANGE &Aura::HandleNULL, //153 SPELL_AURA_SPLIT_DAMAGE_FLAT - &Aura::HandleNULL, //154 SPELL_AURA_MOD_STEALTH_LEVEL + &Aura::HandleNoImmediateEffect, //154 SPELL_AURA_MOD_STEALTH_LEVEL &Aura::HandleNULL, //155 SPELL_AURA_MOD_WATER_BREATHING &Aura::HandleNoImmediateEffect, //156 SPELL_AURA_MOD_REPUTATION_GAIN &Aura::HandleNULL, //157 SPELL_AURA_PET_DAMAGE_MULTI @@ -269,6 +272,9 @@ &Aura::HandleNULL, //218 &Aura::HandleNULL, //219 SPELL_AURA_MOD_MANA_REGEN &Aura::HandleNULL, //220 + + + }; Aura::Aura(SpellEntry const* spellproto, uint32 eff, Unit *target, Unit *caster, Item* castItem) : @@ -1584,7 +1590,6 @@ //TODO: add stealthed tracking effect } - void Aura::HandleAuraModScale(bool apply, bool Real) { m_target->ApplyPercentModFloatValue(OBJECT_FIELD_SCALE_X,m_modifier.m_amount,apply); @@ -1744,15 +1749,21 @@ void Aura::HandleModConfuse(bool apply, bool Real) { + Unit* caster = GetCaster(); + uint32 apply_stat = UNIT_STAT_CONFUSED; - uint32 apply_stat = UNIT_STAT_CONFUSED; if( apply ) { m_target->addUnitState(UNIT_STAT_CONFUSED); // probably wrong m_target->SetFlag(UNIT_FIELD_FLAGS,(apply_stat<<16)); + // R0gu3/Bl1nd ability stops attack + // TODO: does all confuses ? + if ( caster && (GetSpellProto()->Mechanic == MECHANIC_CONFUSED) && (GetSpellProto()->SpellFamilyName == SPELLFAMILY_ROGUE)) + caster->AttackStop(); + // only at real add aura if(Real) { @@ -1897,6 +1908,11 @@ m_target->SetUInt64Value (UNIT_FIELD_TARGET, 0); m_target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_ROTATE); + // Stop attack if spell has knockout effect + if (caster && (GetSpellProto()->Mechanic == MECHANIC_KNOCKOUT)) + caster->AttackStop(); + + // only at real add aura if(Real) { @@ -1913,20 +1929,24 @@ m_target->SetOrientation(m_target->GetAngle(caster)); } + // Creature specific if(m_target->GetTypeId() != TYPEID_PLAYER) { ((Creature *)m_target)->StopMoving(); + //Removes threat and stops combat state so from player so he can re-stealth if( GetSpellProto()->SpellFamilyName == SPELLFAMILY_ROGUE && (GetSpellProto()->SpellIconID == 249) ) { //Unit will not attack player if out of range ((Creature *)m_target)->CombatStop(); + caster->RemoveFromInHateListOf(((Creature *)m_target)); ((Creature *)m_target)->DeleteThreatList(); } } WorldPacket data(SMSG_FORCE_MOVE_ROOT, 8); + data.append(m_target->GetPackGUID()); data << uint32(0); m_target->SendMessageToSet(&data,true); @@ -1948,6 +1968,7 @@ data << uint32(0); m_target->SendMessageToSet(&data,true); + //If sap is used then threat is removed and mob goes back to normal waypoint if( m_target->GetTypeId() != TYPEID_PLAYER && GetSpellProto()->SpellFamilyName == SPELLFAMILY_ROGUE && (GetSpellProto()->SpellIconID == 249)) { @@ -1958,6 +1979,18 @@ if (GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->SpellIconID == 1721) { + // Unit will not attack player if out of range + if(caster) + caster->RemoveFromInHateListOf(((Creature *)m_target)); + + ((Creature *)m_target)->CombatStop(); + ((Creature *)m_target)->AI()->EnterEvadeMode(); + ((Creature *)m_target)->DeleteThreatList(); + ((Creature *)m_target)->RemoveAllAuras(); + } + + if ((GetSpellProto()->SpellFamilyName == SPELLFAMILY_HUNTER && GetSpellProto()->SpellIconID == 1721)) + { if( !caster || caster->GetTypeId()!=TYPEID_PLAYER ) return; @@ -1989,7 +2022,8 @@ void Aura::HandleModStealth(bool apply, bool Real) { - if(apply) + Unit* caster = GetCaster(); + if(apply) { m_target->m_stealthvalue = CalculateDamage(); m_target->SetFlag(UNIT_FIELD_BYTES_1, PLAYER_STATE_FLAG_STEALTH); @@ -2008,17 +2042,22 @@ m_target->CastSpell(m_target, 21009, true, NULL, this); m_target->ApplyStats(false); } - } + } } else { m_target->m_stealthvalue = 0; m_target->RemoveFlag(UNIT_FIELD_BYTES_1, PLAYER_STATE_FLAG_STEALTH); - // only at real aura remove if(Real) { + // Caster comes back to normal state after vanish is finished. + if (caster->hasUnitState(UNIT_STAT_VANISHED)) + caster->clearUnitState(UNIT_STAT_VANISHED); + + // Make target visible m_target->SetVisibility(VISIBILITY_ON); + if(m_target->GetTypeId() == TYPEID_PLAYER) m_target->SendUpdateToPlayer((Player*)m_target); Index: src/game/SpellAuras.h =================================================================== --- src/game/SpellAuras.h (revision 3674) +++ src/game/SpellAuras.h (working copy) @@ -162,7 +162,7 @@ void HandleModShieldBlockPCT(bool Apply, bool Real); void HandleAuraTrackStealthed(bool Apply, bool Real); void HandleModShieldBlock(bool Apply, bool Real); - void HandleForceReaction(bool Apply, bool Real); + void HandleForceReaction(bool Apply, bool Real); void HandleAuraModRangedHaste(bool Apply, bool Real); void HandleRangedAmmoHaste(bool Apply, bool Real); void HandleModHealingDone(bool Apply, bool Real); Index: src/game/SpellEffects.cpp =================================================================== --- src/game/SpellEffects.cpp (revision 3674) +++ src/game/SpellEffects.cpp (working copy) @@ -50,6 +50,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]= { + &Spell::EffectNULL, // 0 &Spell::EffectInstaKill, // 1 SPELL_EFFECT_INSTAKILL &Spell::EffectSchoolDMG, // 2 SPELL_EFFECT_SCHOOL_DAMAGE @@ -119,7 +120,7 @@ &Spell::EffectNULL, // 66 SPELL_EFFECT_POWER_FUNNEL unused &Spell::EffectHealMaxHealth, // 67 SPELL_EFFECT_HEAL_MAX_HEALTH &Spell::EffectInterruptCast, // 68 SPELL_EFFECT_INTERRUPT_CAST - &Spell::EffectNULL, // 69 SPELL_EFFECT_DISTRACT + &Spell::EffectDistract, // 69 SPELL_EFFECT_DISTRACT &Spell::EffectNULL, // 70 SPELL_EFFECT_PULL one spell: Distract Move &Spell::EffectPickPocket, // 71 SPELL_EFFECT_PICKPOCKET &Spell::EffectAddFarsight, // 72 SPELL_EFFECT_ADD_FARSIGHT @@ -186,6 +187,7 @@ &Spell::EffectNULL, //133 SPELL_EFFECT_133 one spell: Forget &Spell::EffectNULL, //134 SPELL_EFFECT_134 &Spell::EffectNULL, //135 SPELL_EFFECT_135 pet related + }; void Spell::EffectNULL(uint32 i) @@ -352,8 +354,8 @@ } return; } - - // Cold Snap - immediately finishes the cooldown on Frost spells + + // Cold Snap - immediately finishes the cooldown on Frost spells if(m_spellInfo->Id == 12472) { if(m_caster->GetTypeId()!=TYPEID_PLAYER) @@ -1494,31 +1496,77 @@ ((Player*)unitTarget)->SetCanDualWield(true); } +void Spell::EffectDistract(uint32 i) +{ + // Check for possible target this line crashed server so removed + // if (!unitTarget) + // return; + + int32 levelDiff = m_caster->getLevel() - unitTarget->getLevel(); + + //If there is a victim to distract + if ((levelDiff > -5) && unitTarget->IsHostileTo(m_caster)) + { + // Gets angle of distract epicenter / target + float angle = unitTarget->GetAngle(m_targets.m_destX, m_targets.m_destY); + + //Set proper orientation + unitTarget->SetOrientation(angle); + + // Update animation if target is creature + if(unitTarget->GetTypeId() != TYPEID_PLAYER) + { + + Creature& pUnit = *((Creature *)unitTarget); + + // Creature movement notifier + CellPair cPair = MaNGOS::ComputeCellPair(pUnit.GetPositionX(), pUnit.GetPositionY()); + Cell cell = RedZone::GetZone(cPair); + cell.data.Part.reserved = ALL_DISTRICT; + MaNGOS::CreatureVisibleMovementNotifier notifier(pUnit); + TypeContainerVisitor player_notifier(notifier); + CellLock cell_lock(cell, cPair); + cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(pUnit.GetMapId(), &pUnit)); + + // Stop moving + ((Creature *)unitTarget)->StopMoving(); + + // TODO: set time to distract center and resume walking with the pull fct + + } + } +} + void Spell::EffectPickPocket(uint32 i) { + // Only players can pickpocket if( m_caster->GetTypeId() != TYPEID_PLAYER ) return; - //victim must be creature and attackable + // Victim must be creature and not friendly if( !unitTarget || unitTarget->GetTypeId() != TYPEID_UNIT || m_caster->IsFriendlyTo(unitTarget) ) return; - //victim have to be alive and humanoid or undead - if( unitTarget->isAlive() && - (((Creature*)unitTarget)->GetCreatureInfo()->type == CREATURE_TYPE_HUMANOID || - ((Creature*)unitTarget)->GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD)) + // Victim have to be alive and humanoid or undead + // TODO: should be checked in Spell::CanCast() Spell.cpp:1826 + if( unitTarget->isAlive() && ( + ((Creature*)unitTarget)->GetCreatureInfo()->type == CREATURE_TYPE_HUMANOID || + ((Creature*)unitTarget)->GetCreatureInfo()->type == CREATURE_TYPE_UNDEAD + )) { - int32 chance = 10 + m_caster->getLevel() - unitTarget->getLevel(); - + // TODO: check wowwiki.com formula + int32 chance = 15 + m_caster->getLevel() - unitTarget->getLevel(); if (chance > irand(0, 19)) { //Stealing successful + //sLog.outDebug("Sending loot from pickpocket"); ((Player*)m_caster)->SendLoot(unitTarget->GetGUID(),LOOT_PICKPOCKETING); + } else { - //Reveal action + get attack + // Reveal caster m_caster->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH); if (((Creature*)unitTarget)->AI()) ((Creature*)unitTarget)->AI()->AttackStart(m_caster); @@ -2333,6 +2381,24 @@ if(!unitTarget) return; unitTarget->CombatStop(); + + //Vanish allows to remove all treat and cast regular stealth so other spells can be used + if (m_spellInfo->SpellIconID == 252) + { + m_caster->AttackStop(); + ((Player *)m_caster)->addUnitState(UNIT_STAT_VANISHED); + } + + + //If player is rooted player looses root with vanish + if ((m_caster->hasUnitState(UNIT_STAT_ROOT)&& (m_spellInfo->SpellIconID == 252))) + { + + ((Player *)m_caster)->RemoveSpellsCausingAura(SPELL_AURA_MOD_ROOT); + ((Player *)m_caster)->ApplySpellImmune(339,IMMUNITY_MECHANIC,8,true); + + } + } void Spell::EffectAddComboPoints(uint32 i) Index: src/game/Unit.cpp =================================================================== --- src/game/Unit.cpp (revision 3674) +++ src/game/Unit.cpp (working copy) @@ -39,6 +39,11 @@ #include "Totem.h" #include "TemporarySummon.h" +// TODO: check if those are needed +#include "RedZoneDistrict.h" +#include "CellImpl.h" +#include "GridNotifiersImpl.h" +#include "MapManager.h" #include float baseMoveSpeed[MAX_MOVE_TYPE] = @@ -4594,17 +4599,16 @@ return gain; } + bool Unit::isVisibleFor(Unit* u, bool detect) { - if(!u) - return false; - - // Visible units, always are visible for all pjs + + // Visible units, always are visible for all pjs if (m_Visibility == VISIBILITY_ON) return true; // Always can see self - if (u==this) + if (u == this) return true; // GMs are visible for higher gms (or players are visible for gms) @@ -4634,35 +4638,203 @@ return true; } - // if in non-detect mode then invisible for unit - if(!detect) - return false; + + //if in non-detect mode then invisible for unit + if ((!detect) && (!u->IsHostileTo(this))) + return false; + + + // Special cases bool IsVisible = true; - bool notInFront = u->isInFront(this, MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT) ? 0 : 1; - float Distance = sqrt(GetDistanceSq(u)); + bool isNotFront = u->isInFront(this, MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT)? 0 : 1; + float distance = sqrt(GetDistanceSq(u)); + + // If is attacked then stealth is lost, some creature can use stealth too + if (this->isAttacked()) + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + + // If there is collision rogue is seen regardless of level difference + // TODO: check sizes in DB + if (distance < 0.5f) + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + + //If a mob or player is stunned he will not be able to detect stealth + if ((u->hasUnitState(UNIT_STAT_STUNDED)) && (u != this)) + { + IsVisible = false; + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + } + + // Cases based on level difference and position + int32 levelDiff = u->getLevel() - this->getLevel(); + + // If victim has more than 5 lvls above caster + if ((this->GetTypeId() == TYPEID_UNIT)&& ( levelDiff > 5 )) + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + + // If caster has more than 5 levels above victim + if ((this->GetTypeId() == TYPEID_UNIT)&& ( levelDiff < -5 )) + { + IsVisible = false; + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + } + float prob = 0; + float modifier = 1; // 100 pct + float pvpMultiplier = 0; + float distanceFormula = 0; + int32 rank = 0; + //This allows to check talent tree and will add addition stealth dependant on used points) + uint32 stealthMod = 0; + AuraList& mStealthMod = GetAurasByType(SPELL_AURA_MOD_STEALTH_LEVEL); + for(AuraList::iterator i = mStealthMod.begin();i != mStealthMod.end(); ++i) + stealthMod += (*i)->GetModifier()->m_amount; + //******************************************************************************** ******** + int32 x = (((u->m_detectStealth+1) / 5) - (((m_stealthvalue+1) / 5) + (stealthMod/5) + 59)); // Stealth detection calculation + + if (x<0) x = 1; + // Check rank if mob is not a player otherwise rank = 1 and there is no modifier when in pvp + if (u->GetTypeId() != TYPEID_PLAYER) + rank = ((Creature const*)u)->GetCreatureInfo()->rank; - // Function for detection (can be improved) - // Take into account that this function is executed every x secs, so prob must be low for right working + // Probabilty of being seen + if (levelDiff < 0) + distanceFormula = ((sWorld.getRate(RATE_CREATURE_AGGRO) * 16) / (abs(levelDiff) + 1.5)) * 2; + if (levelDiff >= 0) + distanceFormula = (((sWorld.getRate(RATE_CREATURE_AGGRO) * 16)) / 2) * (levelDiff + 1); - int32 x = u->getLevel() + (u->m_detectStealth / 5) - (m_stealthvalue / 5) + 59; - if (x<0) x = 0; - float AverageDist = 1 - 0.11016949*x + 0.00301637*x*x; //at this distance, the detector has to be a 15% prob of detect - if (AverageDist < 1) AverageDist = 1; - if (Distance > AverageDist) - //prob between 10% and 0% - prob = (AverageDist-200+9*Distance)/(AverageDist-20); + // Original probability values + // removed level of mob in calculation as it should not affect the detection, it is mainly dependant on level difference + float averageDist = 1 - 0.11016949 * x + 0.00301637 * x * x; //at this distance, the detector has to be a 15% prob of detect + if (averageDist < 1) averageDist = 1; + + if (distance > averageDist) + prob = (averageDist - 200 + 9 * distance) / (averageDist - 20); //prob between 10% and 0% else - prob = 75 - (60/AverageDist)*Distance; //prob between 15% and 75% (75% max prob) - if (notInFront) - prob = prob/100; + prob = 75 - (60 / averageDist) * distance; //prob between 15% and 75% (75% max prob) + + // If is not in front, probability floor + if (isNotFront) + prob = prob / 100; if (prob < 0.1) - prob = 0.1; //min prob of detect is 0.1 + prob = 0.1; - IsVisible = roll_chance_f(prob); + + // Mob rank affects modifier + modifier = rank <= 4 ? 1 + rank * 0.2f : 1; - return IsVisible && ( Distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + + // PVP distance assigned depending on level + if (this->GetTypeId() == TYPEID_PLAYER) + { + // Level diff floor/ceiling <-5,5> + pvpMultiplier = levelDiff > 5 ? 12 : levelDiff < 5 ? 2 : 7 + levelDiff; + pvpMultiplier = pvpMultiplier - (x / 100); + } + + // PVP stealth handler + if (this->GetTypeId() == TYPEID_PLAYER) + { + // Do not loose stealth when coming from back unless mob is more than 10 levels higher than rogue + if ((isNotFront) && (levelDiff > -10 )) + { + IsVisible = false; + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + } + + // If comes in front + if (!isNotFront && (distance >= pvpMultiplier)) + { + IsVisible = false; + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + } + + if (!isNotFront && (distance < pvpMultiplier)) + { + IsVisible = true; + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + } + } + else + { + // PVE stealth handler + + + // Distance of approch player stays stealth 100% is dependant of level. No probabiliy or detection is rolled + // This establishes a buffer zone in between mob start to see you and mob start to roll probabilities or detect you + if ((distance < 100) && (distance > ((distanceFormula * 2) * modifier)) && (distance > 0.24f)) + { + IsVisible = false; + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + + } + + //If victim is level lower or more probability of detection drops + if ((levelDiff < 0) && (distance > 0.24f)) + { + if (abs(levelDiff ) > 4) + IsVisible = false; + else + { + if (rand_chance() > ( prob * modifier / (30 + levelDiff * 5))) + IsVisible = false; + } + + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + } + + //If mob is a higher level but is approached from behind, mob will turn towards the player and attack if closer than 7 feet + if ( ( levelDiff >= 5) && (distance > 0.24f) ) + { + // Cast unit to creature + Creature& pUnit = *(Creature *)u; + + // Creature turns to look at caster + ((Creature* )u)->SetInFront(this); + + CellPair cPair = MaNGOS::ComputeCellPair(pUnit.GetPositionX(), pUnit.GetPositionY()); + Cell cell = RedZone::GetZone(cPair); + cell.data.Part.reserved = ALL_DISTRICT; + MaNGOS::CreatureVisibleMovementNotifier notifier(pUnit); + TypeContainerVisitor player_notifier(notifier); + CellLock cell_lock(cell, cPair); + cell_lock->Visit(cell_lock, player_notifier, *MapManager::Instance().GetMap(pUnit.GetMapId(), &pUnit)); + ((Creature *)u)->StopMoving(); + + //If player comes close to mob he gets detected ( Formula is based on agro and level difference between mob and player + //Formula used is (((aggro * 16)/5) * level difference between mob and player) Will give you the level of detection + //At agro 0.4 and at a difference of 5 levels you can approach until 6.4 feet. At a level diff of 6 you are detected at 7.68 feet or closer etc + if (distance <= ((distanceFormula) * modifier)) + { + //Puts mob back to threat to normal value TODO: ? + IsVisible = true; + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + } + else + { + IsVisible = false; + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + } + } + + // Level detection based on level, the higher the mob level the higher the chance of detection. + if ((distance > 0.24f) && (levelDiff < 5) && (levelDiff >= 0)) + { + if (rand_chance() > ((prob * modifier) / (30 - levelDiff * 5) )) + IsVisible = false; + else + IsVisible = true; + + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); + } + } + + // Didn't match any criteria ? + DEBUG_LOG("Unit::isVisibleForFor unhandled result, dist %f levelDiff %i target_type %u prob %u modifier %u",distance,levelDiff,u->GetTypeId(),prob, modifier); + + // Safety return + return IsVisible && ( distance <= MAX_DIST_INVISIBLE_UNIT * MAX_DIST_INVISIBLE_UNIT); } void Unit::SetVisibility(UnitVisibility x) @@ -5472,4 +5644,4 @@ Unit* Unit::GetUnit(WorldObject& object, uint64 guid) { return ObjectAccessor::Instance().GetUnit(object,guid); -} \ No newline at end of file +} Index: src/game/Unit.h =================================================================== --- src/game/Unit.h (revision 3674) +++ src/game/Unit.h (working copy) @@ -171,6 +171,7 @@ { UNIT_STAT_STOPPED = 0, UNIT_STAT_DIED = 1, + UNIT_STAT_VANISHED = 1, // TODO: stat similar to died, are there any differences? UNIT_STAT_ATTACKING = 2, // player is attacking someone UNIT_STAT_ATTACK_BY = 4, // player is attack by someone // player is in combat mode