mirror of
https://github.com/ProjectSkyfire/SkyFire_548
synced 2026-08-18 06:32:13 -04:00
Merge branch 'fix/creature-aggro-range'
This commit is contained in:
commit
9d040aba69
4 changed files with 59 additions and 23 deletions
|
|
@ -0,0 +1,26 @@
|
|||
-- Per-creature aggro detection range.
|
||||
--
|
||||
-- Sections:
|
||||
-- 1. New `creature_template`.`detection_range` column
|
||||
-- 2. Starting-zone detection ranges
|
||||
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 1. New `creature_template`.`detection_range` column
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Radius, in yards, at which a creature notices a target of its own level.
|
||||
-- The core adjusts it by one yard per level of difference and keeps the result
|
||||
-- inside the 5 to 45 yard range, so 20 reproduces the previous behavior.
|
||||
|
||||
ALTER TABLE `creature_template`
|
||||
ADD COLUMN `detection_range` FLOAT NOT NULL DEFAULT 20 AFTER `ModLevel`;
|
||||
|
||||
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- 2. Starting-zone detection ranges
|
||||
-- ---------------------------------------------------------------------------
|
||||
-- Creatures in the starting-zone level bracket let players come far closer
|
||||
-- before engaging than the rest of the world does, which keeps a single pull
|
||||
-- from dragging in the surrounding camp.
|
||||
|
||||
UPDATE `creature_template` SET `detection_range`=10 WHERE `maxlevel` <= 6;
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include "CreatureAISelector.h"
|
||||
#include "CreatureGroups.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "DBCStores.h"
|
||||
#include "Formulas.h"
|
||||
#include "GameEventMgr.h"
|
||||
#include "GossipDef.h"
|
||||
|
|
@ -1397,12 +1398,11 @@ bool Creature::CanStartAttack(Unit const* who, bool force) const
|
|||
if (!_IsTargetAcceptable(who))
|
||||
return false;
|
||||
|
||||
if (who->IsInCombat() && IsWithinDist(who, ATTACK_DISTANCE))
|
||||
if (Unit* victim = who->getAttackerForHelper())
|
||||
if (IsWithinDistInMap(victim, sWorld->GetFloatConfig(WorldFloatConfigs::CONFIG_CREATURE_FAMILY_ASSISTANCE_RADIUS)))
|
||||
force = true;
|
||||
if (IsNeutralToAll())
|
||||
return false;
|
||||
|
||||
if (!force && (IsNeutralToAll() || !IsWithinDistInMap(who, GetAttackDistance(who) + m_CombatDistance)))
|
||||
// measured between both centers, so the detection range is not silently widened by either model's size
|
||||
if (!IsInMap(who) || !InSamePhase(who) || GetExactDist(who) > GetAttackDistance(who) + m_CombatDistance)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1418,23 +1418,17 @@ float Creature::GetAttackDistance(Unit const* player) const
|
|||
if (aggroRate == 0)
|
||||
return 0.0f;
|
||||
|
||||
uint32 playerlevel = player->getLevelForTarget(this);
|
||||
uint32 creaturelevel = getLevelForTarget(player);
|
||||
int32 playerlevel = int32(player->getLevelForTarget(this));
|
||||
int32 creaturelevel = int32(getLevelForTarget(player));
|
||||
int32 leveldif = creaturelevel - playerlevel;
|
||||
|
||||
int32 leveldif = int32(playerlevel) - int32(creaturelevel);
|
||||
|
||||
// "The maximum Aggro Radius has a cap of 25 levels under. Example: A level 30 char has the same Aggro Radius of a level 5 char on a level 60 mob."
|
||||
if (leveldif < -25)
|
||||
leveldif = -25;
|
||||
|
||||
// "The aggro radius of a mob having the same level as the player is roughly 20 yards"
|
||||
float RetDistance = 20;
|
||||
// Blizzard sets the radius per creature; starting zones use much shorter ranges than the rest of the world
|
||||
float baseAggroDistance = GetCreatureTemplate()->DetectionRange;
|
||||
|
||||
// "Aggro Radius varies with level difference at a rate of roughly 1 yard/level"
|
||||
// radius grow if playlevel < creaturelevel
|
||||
RetDistance -= (float)leveldif;
|
||||
float RetDistance = baseAggroDistance + float(leveldif);
|
||||
|
||||
if (creaturelevel + 5 <= sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL))
|
||||
if (creaturelevel + 5 <= int32(sWorld->getIntConfig(WorldIntConfigs::CONFIG_MAX_PLAYER_LEVEL)))
|
||||
{
|
||||
// detect range auras
|
||||
RetDistance += GetTotalAuraModifier(SPELL_AURA_MOD_DETECT_RANGE);
|
||||
|
|
@ -1443,9 +1437,14 @@ float Creature::GetAttackDistance(Unit const* player) const
|
|||
RetDistance += player->GetTotalAuraModifier(SPELL_AURA_MOD_DETECTED_RANGE);
|
||||
}
|
||||
|
||||
// "Minimum Aggro Radius for a mob seems to be combat range (5 yards)"
|
||||
if (RetDistance < 5)
|
||||
RetDistance = 5;
|
||||
// Creatures above the level cap of their own expansion (bosses) must not out-range regular creatures.
|
||||
// Templates whose cap sits below the target's level carry an unusable `exp`, so they are left alone.
|
||||
int32 expansionMaxLevel = int32(GetMaxLevelForExpansion(GetCreatureTemplate()->expansion));
|
||||
if (creaturelevel > expansionMaxLevel && expansionMaxLevel >= playerlevel)
|
||||
RetDistance = baseAggroDistance + float(expansionMaxLevel - playerlevel);
|
||||
|
||||
// "Minimum Aggro Radius for a mob seems to be combat range (5 yards)", the maximum is 45 yards
|
||||
RetDistance = std::max(ATTACK_DISTANCE, std::min(RetDistance, MAX_AGGRO_RADIUS));
|
||||
|
||||
return (RetDistance * aggroRate);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ struct CreatureTemplate
|
|||
uint32 flags_extra;
|
||||
uint32 ScriptID;
|
||||
bool ModLevel;
|
||||
float DetectionRange; // aggro radius against a target of the same level
|
||||
uint32 GetRandomValidModelId() const;
|
||||
uint32 GetFirstValidModelId() const;
|
||||
|
||||
|
|
@ -429,6 +430,9 @@ typedef std::map<uint32, time_t> CreatureSpellCooldowns;
|
|||
// max different by z coordinate for creature aggro reaction
|
||||
#define CREATURE_Z_ATTACK_RANGE 3
|
||||
|
||||
// aggro radius against a target of the same level, used when `detection_range` holds no usable value
|
||||
#define DEFAULT_DETECTION_RANGE 20.0f
|
||||
|
||||
#define MAX_VENDOR_ITEMS 150 // Limitation in 4.x.x item count in SMSG_LIST_INVENTORY
|
||||
|
||||
class Creature : public Unit, public GridObject<Creature>, public MapObject
|
||||
|
|
|
|||
|
|
@ -452,8 +452,8 @@ void ObjectMgr::LoadCreatureTemplates()
|
|||
"spell1, spell2, spell3, spell4, spell5, spell6, spell7, spell8, PetSpellDataId, VehicleId, mingold, maxgold, AIName, MovementType, "
|
||||
// 69 70 71 72 73 74 75 76 77 78 79 80
|
||||
"InhabitType, HoverHeight, Health_mod, Mana_mod, Mana_mod_extra, Armor_mod, RacialLeader, questItem1, questItem2, questItem3, questItem4, questItem5, "
|
||||
// 81 82 83 84 85 86
|
||||
" questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName, ModLevel "
|
||||
// 81 82 83 84 85 86 87 88
|
||||
" questItem6, movementId, RegenHealth, mechanic_immune_mask, flags_extra, ScriptName, ModLevel, detection_range "
|
||||
"FROM creature_template;");
|
||||
|
||||
if (!result)
|
||||
|
|
@ -557,6 +557,7 @@ void ObjectMgr::LoadCreatureTemplates()
|
|||
creatureTemplate.flags_extra = fields[85].GetUInt32();
|
||||
creatureTemplate.ScriptID = GetScriptId(fields[86].GetCString());
|
||||
creatureTemplate.ModLevel = fields[87].GetBool();
|
||||
creatureTemplate.DetectionRange = fields[88].GetFloat();
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
|
@ -893,6 +894,12 @@ void ObjectMgr::CheckCreatureTemplate(CreatureTemplate const* cInfo)
|
|||
const_cast<CreatureTemplate*>(cInfo)->HoverHeight = 1.0f;
|
||||
}
|
||||
|
||||
if (cInfo->DetectionRange <= 0.0f || cInfo->DetectionRange > MAX_AGGRO_RADIUS)
|
||||
{
|
||||
SF_LOG_ERROR("sql.sql", "Creature (Entry: %u) has wrong value (%f) in `detection_range`, set to %f.", cInfo->Entry, cInfo->DetectionRange, DEFAULT_DETECTION_RANGE);
|
||||
const_cast<CreatureTemplate*>(cInfo)->DetectionRange = DEFAULT_DETECTION_RANGE;
|
||||
}
|
||||
|
||||
if (cInfo->VehicleId)
|
||||
{
|
||||
VehicleEntry const* vehId = sVehicleStore.LookupEntry(cInfo->VehicleId);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue