feat(Core): port aggro distance from vMaNGOS (#6214)

Read detection_range values from creature_template
This commit is contained in:
Shiroe
2021-07-08 18:01:27 +02:00
committed by GitHub
parent 6fa2ad4e33
commit f8c8e98a0a
15 changed files with 89 additions and 72 deletions

View File

@@ -65,7 +65,7 @@ void WorldDatabaseConnection::DoPrepareStatements()
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_DEL_CREATURE, "DELETE FROM creature WHERE guid = ?", CONNECTION_ASYNC);
PrepareStatement(WORLD_SEL_COMMANDS, "SELECT name, security, help FROM command", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, DamageModifier, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, type_flags, lootid, pickpocketloot, skinloot, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, detection_range, scale, `rank`, dmgschool, DamageModifier, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, type_flags, lootid, pickpocketloot, skinloot, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, InhabitType, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName FROM creature_template WHERE entry = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_ITEM_TEMPLATE_BY_NAME, "SELECT entry FROM item_template WHERE name = ?", CONNECTION_SYNCH);
PrepareStatement(WORLD_SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?", CONNECTION_SYNCH);

View File

@@ -120,7 +120,7 @@ void CreatureAI::MoveInLineOfSight(Unit* who)
if (me->IsMoveInLineOfSightDisabled())
if (me->GetCreatureType() == CREATURE_TYPE_NON_COMBAT_PET || // nothing more to do, return
!who->IsInCombat() || // if not in combat, nothing more to do
!me->IsWithinDist(who, ATTACK_DISTANCE)) // if in combat and in dist - neutral to all can actually assist other creatures
!me->IsWithinDist(who, ATTACK_DISTANCE, true, false)) // if in combat and in dist - neutral to all can actually assist other creatures
return;
if (me->CanStartAttack(who))

View File

@@ -469,7 +469,7 @@ Player* ScriptedAI::SelectTargetFromPlayerList(float maxdist, uint32 excludeAura
std::vector<Player*> tList;
for(Map::PlayerList::const_iterator itr = pList.begin(); itr != pList.end(); ++itr)
{
if (!me->IsWithinDistInMap(itr->GetSource(), maxdist) || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster())
if (!me->IsWithinDistInMap(itr->GetSource(), maxdist, true, false) || !itr->GetSource()->IsAlive() || itr->GetSource()->IsGameMaster())
continue;
if (excludeAura && itr->GetSource()->HasAura(excludeAura))
continue;

View File

@@ -216,10 +216,10 @@ bool npc_escortAI::IsPlayerOrGroupInRange()
{
for (GroupReference* groupRef = group->GetFirstMember(); groupRef != nullptr; groupRef = groupRef->next())
if (Player* member = groupRef->GetSource())
if (me->IsWithinDistInMap(member, GetMaxPlayerDistance()))
if (me->IsWithinDistInMap(member, GetMaxPlayerDistance(), true, false))
return true;
}
else if (me->IsWithinDistInMap(player, GetMaxPlayerDistance()))
else if (me->IsWithinDistInMap(player, GetMaxPlayerDistance(), true, false))
return true;
}

View File

@@ -197,7 +197,7 @@ void FollowerAI::UpdateAI(uint32 uiDiff)
{
Player* member = groupRef->GetSource();
if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE))
if (member && me->IsWithinDistInMap(member, MAX_PLAYER_DISTANCE, true, false))
{
bIsMaxRangeExceeded = false;
break;
@@ -206,7 +206,7 @@ void FollowerAI::UpdateAI(uint32 uiDiff)
}
else
{
if (me->IsWithinDistInMap(player, MAX_PLAYER_DISTANCE))
if (me->IsWithinDistInMap(player, MAX_PLAYER_DISTANCE, true, false))
bIsMaxRangeExceeded = false;
}
}

View File

@@ -168,7 +168,7 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(),
m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE),
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_originalAnimTier(UNIT_BYTE1_FLAG_GROUND), m_AlreadyCallAssistance(false),
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTarget(false), m_cannotReachTimer(0),
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTarget(false), m_cannotReachTimer(0),
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0)
{
m_regenTimer = CREATURE_REGEN_INTERVAL;
@@ -521,6 +521,8 @@ bool Creature::UpdateEntry(uint32 Entry, const CreatureData* data, bool changele
UpdateEnvironmentIfNeeded(3);
SetDetectionDistance(cInfo->detection_range);
LoadSpellTemplateImmunity();
return true;
}
@@ -617,7 +619,7 @@ void Creature::Update(uint32 diff)
}
Unit* owner = GetCharmerOrOwner();
if (IsCharmed() && !IsWithinDistInMap(owner, GetMap()->GetVisibilityRange()))
if (IsCharmed() && !IsWithinDistInMap(owner, GetMap()->GetVisibilityRange(), true, false))
{
RemoveCharmAuras();
}
@@ -1710,7 +1712,7 @@ bool Creature::CanStartAttack(Unit const* who) const
assist = true;
if (!assist)
if (IsNeutralToAll() || !IsWithinDistInMap(who, GetAggroRange(who) + m_CombatDistance)) // pussywizard: +m_combatDistance for turrets and similar
if (IsNeutralToAll() || !IsWithinDistInMap(who, GetAggroRange(who) + m_CombatDistance, true, false)) // pussywizard: +m_combatDistance for turrets and similar
return false;
if (!CanCreatureAttack(who))
@@ -2978,17 +2980,20 @@ float Creature::GetAggroRange(Unit const* target) const
if (aggroRate == 0)
return 0.0f;
uint32 targetLevel = target->getLevelForTarget(this);
uint32 myLevel = getLevelForTarget(target);
int32 levelDiff = int32(targetLevel) - int32(myLevel);
auto creatureLevel = target->getLevelForTarget(this);
auto playerLevel = getLevelForTarget(target);
int32 levelDiff = int32(creatureLevel) - int32(playerLevel);
// The maximum Aggro Radius is capped at 45 yards (25 level difference)
if (levelDiff < -25)
levelDiff = -25;
// The base aggro radius for mob of same level
float aggroRadius = 20.0f;
auto aggroRadius = GetDetectionRange();
if (aggroRadius < 1)
{
return 0.0f;
}
// Aggro Radius varies with level difference at a rate of roughly 1 yard/level
aggroRadius -= (float)levelDiff;

View File

@@ -176,6 +176,7 @@ public:
[[nodiscard]] CreatureTemplate const* GetCreatureTemplate() const { return m_creatureInfo; }
[[nodiscard]] CreatureData const* GetCreatureData() const { return m_creatureData; }
void SetDetectionDistance(float dist){ m_detectionDistance = dist; }
[[nodiscard]] CreatureAddon const* GetCreatureAddon() const;
[[nodiscard]] std::string GetAIName() const;
@@ -224,6 +225,7 @@ public:
bool CanStartAttack(Unit const* u) const;
float GetAggroRange(Unit const* target) const;
float GetAttackDistance(Unit const* player) const;
[[nodiscard]] float GetDetectionRange() const { return m_detectionDistance; }
void SendAIReaction(AiReaction reactionType);
@@ -413,6 +415,7 @@ protected:
CreatureTemplate const* m_creatureInfo; // in difficulty mode > 0 can different from sObjectMgr->GetCreatureTemplate(GetEntry())
CreatureData const* m_creatureData;
float m_detectionDistance;
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
[[nodiscard]] bool IsInvisibleDueToDespawn() const override;

View File

@@ -92,6 +92,7 @@ struct CreatureTemplate
uint32 npcflag;
float speed_walk;
float speed_run;
float detection_range; // Detection Range for Line of Sight aggro
float scale;
uint32 rank;
uint32 dmgschool;

View File

@@ -993,7 +993,7 @@ private:
void UpdatePackedRotation();
//! Object distance/size - overridden from Object::_IsWithinDist. Needs to take in account proper GO size.
bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool /*is3D*/) const override
bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool /*is3D*/, bool /*useBoundingRadius = true*/) const override
{
//! Following check does check 3d distance
dist2compare += obj->GetObjectSize();

View File

@@ -1069,9 +1069,9 @@ float WorldObject::GetDistanceZ(const WorldObject* obj) const
return (dist > 0 ? dist : 0);
}
bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const
bool WorldObject::_IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D, bool useBoundingRadius) const
{
float sizefactor = GetObjectSize() + obj->GetObjectSize();
float sizefactor = useBoundingRadius ? GetObjectSize() + obj->GetObjectSize() : 0.0f;
float maxdist = dist2compare + sizefactor;
if (m_transport && obj->GetTransport() && obj->GetTransport()->GetGUID() == m_transport->GetGUID())

View File

@@ -870,13 +870,13 @@ public:
bool IsWithinDist2d(const Position* pos, float dist) const
{ return IsInDist2d(pos, dist + GetObjectSize()); }
// 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 IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D = true, bool useBoundingRadius = true) const
{
return obj && _IsWithinDist(obj, dist2compare, is3D);
return obj && _IsWithinDist(obj, dist2compare, is3D, useBoundingRadius);
}
bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true) const
bool IsWithinDistInMap(WorldObject const* obj, float dist2compare, bool is3D = true, bool useBoundingRadius = true) const
{
return obj && IsInMap(obj) && InSamePhase(obj) && _IsWithinDist(obj, dist2compare, is3D);
return obj && IsInMap(obj) && InSamePhase(obj) && _IsWithinDist(obj, dist2compare, is3D, useBoundingRadius);
}
[[nodiscard]] bool IsWithinLOS(float x, float y, float z, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS) const;
bool IsWithinLOSInMap(WorldObject const* obj, LineOfSightChecks checks = LINEOFSIGHT_ALL_CHECKS) const;
@@ -1076,7 +1076,7 @@ private:
uint16 m_notifyflags;
uint16 m_executed_notifies;
virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D) const;
virtual bool _IsWithinDist(WorldObject const* obj, float dist2compare, bool is3D, bool useBoundingRadius = true) const;
bool CanNeverSee(WorldObject const* obj) const;
virtual bool CanAlwaysSee(WorldObject const* /*obj*/) const { return false; }

View File

@@ -465,15 +465,15 @@ void ObjectMgr::LoadCreatureTemplates()
// 0 1 2 3 4 5 6 7 8
QueryResult result = WorldDatabase.Query("SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, modelid1, modelid2, modelid3, "
// 9 10 11 12 13 14 15 16 17 18 19 20
"modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, "
// 21 22 23 24 25 26 27 28 29 30 31
// 9 10 11 12 13 14 15 16 17 18 19 20 21
"modelid4, name, subname, IconName, gossip_menu_id, minlevel, maxlevel, exp, faction, npcflag, speed_walk, speed_run, detection_range, "
// 22 23 24 25 26 27 28 29 30 31 32
"scale, `rank`, dmgschool, DamageModifier, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, "
// 32 33 34 35 36 37 38
// 33 34 35 36 37 38 39
"dynamicflags, family, trainer_type, trainer_spell, trainer_class, trainer_race, type, "
// 39 40 41 42 43 44 45 46 47 48
// 40 41 42 43 44 45 46 47 48 49
"type_flags, lootid, pickpocketloot, skinloot, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
// 49 50 51 52 53 54 55 56 57 58 59 60
// 50 51 52 53 54 55 56 57 58 59 60 61
"InhabitType, HoverHeight, HealthModifier, ManaModifier, ArmorModifier, RacialLeader, movementId, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName "
"FROM creature_template;");
@@ -555,28 +555,29 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields)
creatureTemplate.npcflag = fields[18].GetUInt32();
creatureTemplate.speed_walk = fields[19].GetFloat();
creatureTemplate.speed_run = fields[20].GetFloat();
creatureTemplate.scale = fields[21].GetFloat();
creatureTemplate.rank = uint32(fields[22].GetUInt8());
creatureTemplate.dmgschool = uint32(fields[23].GetInt8());
creatureTemplate.DamageModifier = fields[24].GetFloat();
creatureTemplate.BaseAttackTime = fields[25].GetUInt32();
creatureTemplate.RangeAttackTime = fields[26].GetUInt32();
creatureTemplate.BaseVariance = fields[27].GetFloat();
creatureTemplate.RangeVariance = fields[28].GetFloat();
creatureTemplate.unit_class = uint32(fields[29].GetUInt8());
creatureTemplate.unit_flags = fields[30].GetUInt32();
creatureTemplate.unit_flags2 = fields[31].GetUInt32();
creatureTemplate.dynamicflags = fields[32].GetUInt32();
creatureTemplate.family = uint32(fields[33].GetUInt8());
creatureTemplate.trainer_type = uint32(fields[34].GetUInt8());
creatureTemplate.trainer_spell = fields[35].GetUInt32();
creatureTemplate.trainer_class = uint32(fields[36].GetUInt8());
creatureTemplate.trainer_race = uint32(fields[37].GetUInt8());
creatureTemplate.type = uint32(fields[38].GetUInt8());
creatureTemplate.type_flags = fields[39].GetUInt32();
creatureTemplate.lootid = fields[40].GetUInt32();
creatureTemplate.pickpocketLootId = fields[41].GetUInt32();
creatureTemplate.SkinLootId = fields[42].GetUInt32();
creatureTemplate.detection_range = fields[21].GetFloat();
creatureTemplate.scale = fields[22].GetFloat();
creatureTemplate.rank = uint32(fields[23].GetUInt8());
creatureTemplate.dmgschool = uint32(fields[24].GetInt8());
creatureTemplate.DamageModifier = fields[25].GetFloat();
creatureTemplate.BaseAttackTime = fields[26].GetUInt32();
creatureTemplate.RangeAttackTime = fields[27].GetUInt32();
creatureTemplate.BaseVariance = fields[28].GetFloat();
creatureTemplate.RangeVariance = fields[29].GetFloat();
creatureTemplate.unit_class = uint32(fields[30].GetUInt8());
creatureTemplate.unit_flags = fields[31].GetUInt32();
creatureTemplate.unit_flags2 = fields[32].GetUInt32();
creatureTemplate.dynamicflags = fields[33].GetUInt32();
creatureTemplate.family = uint32(fields[34].GetUInt8());
creatureTemplate.trainer_type = uint32(fields[35].GetUInt8());
creatureTemplate.trainer_spell = fields[36].GetUInt32();
creatureTemplate.trainer_class = uint32(fields[37].GetUInt8());
creatureTemplate.trainer_race = uint32(fields[38].GetUInt8());
creatureTemplate.type = uint32(fields[39].GetUInt8());
creatureTemplate.type_flags = fields[40].GetUInt32();
creatureTemplate.lootid = fields[41].GetUInt32();
creatureTemplate.pickpocketLootId = fields[42].GetUInt32();
creatureTemplate.SkinLootId = fields[43].GetUInt32();
for (uint8 i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; ++i)
{
@@ -588,24 +589,24 @@ void ObjectMgr::LoadCreatureTemplate(Field* fields)
creatureTemplate.spells[i] = 0;
}
creatureTemplate.PetSpellDataId = fields[43].GetUInt32();
creatureTemplate.VehicleId = fields[44].GetUInt32();
creatureTemplate.mingold = fields[45].GetUInt32();
creatureTemplate.maxgold = fields[46].GetUInt32();
creatureTemplate.AIName = fields[47].GetString();
creatureTemplate.MovementType = uint32(fields[48].GetUInt8());
creatureTemplate.InhabitType = uint32(fields[49].GetUInt8());
creatureTemplate.HoverHeight = fields[50].GetFloat();
creatureTemplate.ModHealth = fields[51].GetFloat();
creatureTemplate.ModMana = fields[52].GetFloat();
creatureTemplate.ModArmor = fields[53].GetFloat();
creatureTemplate.RacialLeader = fields[54].GetBool();
creatureTemplate.movementId = fields[55].GetUInt32();
creatureTemplate.RegenHealth = fields[56].GetBool();
creatureTemplate.MechanicImmuneMask = fields[57].GetUInt32();
creatureTemplate.SpellSchoolImmuneMask = fields[58].GetUInt8();
creatureTemplate.flags_extra = fields[59].GetUInt32();
creatureTemplate.ScriptID = GetScriptId(fields[60].GetCString());
creatureTemplate.PetSpellDataId = fields[44].GetUInt32();
creatureTemplate.VehicleId = fields[45].GetUInt32();
creatureTemplate.mingold = fields[46].GetUInt32();
creatureTemplate.maxgold = fields[47].GetUInt32();
creatureTemplate.AIName = fields[48].GetString();
creatureTemplate.MovementType = uint32(fields[49].GetUInt8());
creatureTemplate.InhabitType = uint32(fields[50].GetUInt8());
creatureTemplate.HoverHeight = fields[51].GetFloat();
creatureTemplate.ModHealth = fields[52].GetFloat();
creatureTemplate.ModMana = fields[53].GetFloat();
creatureTemplate.ModArmor = fields[54].GetFloat();
creatureTemplate.RacialLeader = fields[55].GetBool();
creatureTemplate.movementId = fields[56].GetUInt32();
creatureTemplate.RegenHealth = fields[57].GetBool();
creatureTemplate.MechanicImmuneMask = fields[58].GetUInt32();
creatureTemplate.SpellSchoolImmuneMask = fields[59].GetUInt8();
creatureTemplate.flags_extra = fields[60].GetUInt32();
creatureTemplate.ScriptID = GetScriptId(fields[61].GetCString());
}
void ObjectMgr::LoadCreatureTemplateResistances()

View File

@@ -1060,7 +1060,7 @@ namespace Acore
}
bool operator()(Unit* u)
{
if (!me->IsWithinDistInMap(u, m_range))
if (!me->IsWithinDistInMap(u, m_range, true, false))
return false;
if (!me->IsValidAttackTarget(u))
@@ -1086,7 +1086,7 @@ namespace Acore
explicit NearestHostileUnitInAttackDistanceCheck(Creature const* creature, float dist) : me(creature), m_range(dist) {}
bool operator()(Unit* u)
{
if (!me->IsWithinDistInMap(u, m_range))
if (!me->IsWithinDistInMap(u, m_range, true, false))
return false;
if (!me->CanStartAttack(u))

View File

@@ -280,7 +280,7 @@ struct boss_twinemperorsAI : public ScriptedAI
if (me->_CanDetectFeignDeathOf(who) && me->CanCreatureAttack(who))
{
if (me->IsWithinDistInMap(who, PULL_RANGE) && me->GetDistanceZ(who) <= /*CREATURE_Z_ATTACK_RANGE*/7 /*there are stairs*/)
if (me->IsWithinDistInMap(who, PULL_RANGE, true, false) && me->GetDistanceZ(who) <= /*CREATURE_Z_ATTACK_RANGE*/7 /*there are stairs*/)
{
//if (who->HasStealthAura())
// who->RemoveSpellsCausingAura(SPELL_AURA_MOD_STEALTH);