This seems to work pretty well, but there are some bugs to iron out with line of sight, etc. I'm also not totally happy with the passive stealth which seems a little too powerful (e.g. you can stand still right in front of an npc without being detected). This should, hopefully, be a case of fine-tuning some of the spell variables.
// Real Stealthbool WorldObject::CanDetectStealthOf(WorldObject const* obj, bool checkAlert) const{ float distance = GetExactDist(obj); float combatReach = 0.0f; float v_intellect = 100.0f; float o_agility = 100.0f; float viewarc = (float(M_PI) * 1.25); float radiusinner = 0.0f; float radiusmiddle = 10.0f; float radiusouter = 20.0f; Unit const* v_unit = ToUnit(); Player const* v_player = ToPlayer(); Unit const* o_unit = obj->ToUnit(); Player const* o_player = obj->ToPlayer(); int32 sneakbonus = 100; float sneakscale = 1.0f; // if object is not a player and has no stealth return true (visible at all times) // do this now to prevent running through the entire function for no good reason if (!(o_unit->GetTypeId() == TYPEID_PLAYER) && !(o_player) && !(obj->m_stealth.GetFlags())) return true; if (v_unit) { combatReach = v_unit->GetCombatReach(); if ((v_unit->GetTypeId() == TYPEID_PLAYER) && (v_player)) v_intellect = v_player->GetStat(STAT_INTELLECT); } if ((o_unit->GetTypeId() == TYPEID_PLAYER) && (o_player)) o_agility = o_player->GetStat(STAT_AGILITY); if (v_intellect < 1.0f) v_intellect = 1.0f; if (o_agility < 1.0f) o_agility = 1.0f; if (v_intellect > 200.0f) v_intellect = 200.0f; if (o_agility > 200.0f) o_agility = 200.0f; viewarc = viewarc * (v_intellect / o_agility); if (viewarc > (float(M_PI) * 1.5f)) viewarc = (float(M_PI) * 1.5f); if (viewarc < (float(M_PI) / 2.0f)) viewarc = (float(M_PI) / 2.0f); for (uint32 i = 0; i < TOTAL_STEALTH_TYPES; ++i) { if (!(obj->m_stealth.GetFlags() & (1 << i))) continue; if (v_unit && v_unit->HasAuraTypeWithMiscvalue(SPELL_AURA_DETECT_STEALTH, i)) return true; sneakbonus -= m_stealthDetect.GetValue(StealthType(i)); sneakbonus += obj->m_stealth.GetValue(StealthType(i)); } if (sneakbonus < 0) sneakbonus = 0; if (sneakbonus > 100) sneakbonus = 100; sneakscale = ((float(sneakbonus) / 100.f) * (o_agility / v_intellect)); radiusinner = combatReach; radiusmiddle = radiusinner + 15.0f - (5.0f * sneakscale); radiusouter = radiusmiddle * 2.0f; if (radiusmiddle < radiusinner) radiusmiddle = radiusinner + 1.0f; if (radiusouter < radiusmiddle) radiusouter = radiusmiddle + 2.0f; if (checkAlert) radiusinner += (radiusinner * 0.08f) + 1.5f; if (checkAlert) radiusmiddle += (radiusmiddle * 0.04f) + 1.0f; if (checkAlert) radiusouter += (radiusouter * 0.02f) + 0.5f; // always detect things in combat reach if (distance < radiusinner) return true; // always detect things within the front middle arc if ((distance < radiusmiddle) && (HasInArc(viewarc, obj))) return true; // always detect unstealthed things within the rear middle arc if ((distance < radiusmiddle) && !(HasInArc(viewarc, obj)) && !(obj->m_stealth.GetFlags())) return true; // always detect unstealthed things within the front outer arc if ((distance < radiusouter) && (HasInArc(viewarc, obj)) && !(obj->m_stealth.GetFlags())) return true; // otherwise thing is not detected return false;}
float v_intellect = YOUR INT BASE AS A FLOAT; float o_agility = YOUR AGI BASE AS A FLOAT;
if (v_intellect < 1.0f) v_intellect = 1.0f; if (o_agility < 1.0f) o_agility = 1.0f; if (v_intellect > YOUR INT CAP AS A FLOAT) v_intellect = YOUR INT CAP AS A FLOAT; if (o_agility > YOUR AGI CAP AS A FLOAT) o_agility = YOUR AGI CAP AS A FLOAT;
int32 sneakbonus = 350;
if (sneakbonus > 350) sneakbonus = 350;
radiusinner = combatReach; radiusmiddle = radiusinner + XXX - (YYY * sneakscale); radiusouter = radiusmiddle * ZZZ;