mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-02-02 18:43:48 +00:00
Merge branch 'master' into Playerbot
# Conflicts: # src/server/game/Entities/Creature/Creature.cpp # src/server/game/Entities/Creature/Creature.h # src/server/game/Movement/MovementGenerators/TargetedMovementGenerator.cpp
This commit is contained in:
@@ -219,8 +219,8 @@ Creature::Creature(bool isWorldObject): Unit(isWorldObject), MovableMapObject(),
|
||||
m_corpseRemoveTime(0), m_respawnTime(0), m_respawnDelay(300), m_corpseDelay(60), m_wanderDistance(0.0f), m_boundaryCheckTime(2500),
|
||||
m_transportCheckTimer(1000), lootPickPocketRestoreTime(0), m_reactState(REACT_AGGRESSIVE), m_defaultMovementType(IDLE_MOTION_TYPE),
|
||||
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), 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_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTarget(false), m_cannotReachTimer(0),
|
||||
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(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_detectionDistance(20.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), _lastDamagedTime(nullptr), m_cannotReachTimer(0),
|
||||
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false)
|
||||
{
|
||||
m_regenTimer = CREATURE_REGEN_INTERVAL;
|
||||
@@ -628,207 +628,238 @@ void Creature::Update(uint32 diff)
|
||||
LOG_ERROR("entities.unit", "Creature ({}) in wrong state: JUST_DEAD (1)", GetGUID().ToString());
|
||||
break;
|
||||
case DEAD:
|
||||
{
|
||||
time_t now = GameTime::GetGameTime().count();
|
||||
if (m_respawnTime <= now)
|
||||
{
|
||||
time_t now = GameTime::GetGameTime().count();
|
||||
if (m_respawnTime <= now)
|
||||
|
||||
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_RESPAWN, GetEntry());
|
||||
|
||||
if (!sConditionMgr->IsObjectMeetToConditions(this, conditions))
|
||||
{
|
||||
|
||||
ConditionList conditions = sConditionMgr->GetConditionsForNotGroupedEntry(CONDITION_SOURCE_TYPE_CREATURE_RESPAWN, GetEntry());
|
||||
|
||||
if (!sConditionMgr->IsObjectMeetToConditions(this, conditions))
|
||||
{
|
||||
// Creature should not respawn, reset respawn timer. Conditions will be checked again the next time it tries to respawn.
|
||||
m_respawnTime = GameTime::GetGameTime().count() + m_respawnDelay;
|
||||
break;
|
||||
}
|
||||
|
||||
bool allowed = !IsAIEnabled || AI()->CanRespawn(); // First check if there are any scripts that prevent us respawning
|
||||
if (!allowed) // Will be rechecked on next Update call
|
||||
break;
|
||||
|
||||
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(GetEntry(), m_spawnId);
|
||||
time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid);
|
||||
if (!linkedRespawntime) // Can respawn
|
||||
Respawn();
|
||||
else // the master is dead
|
||||
{
|
||||
ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid);
|
||||
if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day)
|
||||
SetRespawnTime(DAY);
|
||||
else
|
||||
m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + urand(5, MINUTE); // else copy time from master and add a little
|
||||
SaveRespawnTime(); // also save to DB immediately
|
||||
}
|
||||
// Creature should not respawn, reset respawn timer. Conditions will be checked again the next time it tries to respawn.
|
||||
m_respawnTime = GameTime::GetGameTime().count() + m_respawnDelay;
|
||||
break;
|
||||
}
|
||||
|
||||
bool allowed = !IsAIEnabled || AI()->CanRespawn(); // First check if there are any scripts that prevent us respawning
|
||||
if (!allowed) // Will be rechecked on next Update call
|
||||
break;
|
||||
|
||||
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(GetEntry(), m_spawnId);
|
||||
time_t linkedRespawntime = GetMap()->GetLinkedRespawnTime(dbtableHighGuid);
|
||||
if (!linkedRespawntime) // Can respawn
|
||||
Respawn();
|
||||
else // the master is dead
|
||||
{
|
||||
ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid);
|
||||
if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day)
|
||||
SetRespawnTime(DAY);
|
||||
else
|
||||
m_respawnTime = (now > linkedRespawntime ? now : linkedRespawntime) + urand(5, MINUTE); // else copy time from master and add a little
|
||||
SaveRespawnTime(); // also save to DB immediately
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CORPSE:
|
||||
{
|
||||
Unit::Update(diff);
|
||||
// deathstate changed on spells update, prevent problems
|
||||
if (m_deathState != CORPSE)
|
||||
break;
|
||||
|
||||
if (m_groupLootTimer && lootingGroupLowGUID)
|
||||
{
|
||||
if (m_groupLootTimer <= diff)
|
||||
{
|
||||
Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID);
|
||||
if (group)
|
||||
group->EndRoll(&loot, GetMap());
|
||||
m_groupLootTimer = 0;
|
||||
lootingGroupLowGUID = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_groupLootTimer -= diff;
|
||||
}
|
||||
}
|
||||
else if (m_corpseRemoveTime <= GameTime::GetGameTime().count())
|
||||
{
|
||||
RemoveCorpse(false);
|
||||
LOG_DEBUG("entities.unit", "Removing corpse... {} ", GetUInt32Value(OBJECT_FIELD_ENTRY));
|
||||
}
|
||||
{
|
||||
Unit::Update(diff);
|
||||
// deathstate changed on spells update, prevent problems
|
||||
if (m_deathState != CORPSE)
|
||||
break;
|
||||
}
|
||||
case ALIVE:
|
||||
|
||||
if (m_groupLootTimer && lootingGroupLowGUID)
|
||||
{
|
||||
Unit::Update(diff);
|
||||
|
||||
// creature can be dead after Unit::Update call
|
||||
// CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
|
||||
if (!IsAlive())
|
||||
break;
|
||||
|
||||
// if creature is charmed, switch to charmed AI
|
||||
if (NeedChangeAI)
|
||||
if (m_groupLootTimer <= diff)
|
||||
{
|
||||
UpdateCharmAI();
|
||||
NeedChangeAI = false;
|
||||
IsAIEnabled = true;
|
||||
Group* group = sGroupMgr->GetGroupByGUID(lootingGroupLowGUID);
|
||||
if (group)
|
||||
group->EndRoll(&loot, GetMap());
|
||||
m_groupLootTimer = 0;
|
||||
lootingGroupLowGUID = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_groupLootTimer -= diff;
|
||||
}
|
||||
}
|
||||
else if (m_corpseRemoveTime <= GameTime::GetGameTime().count())
|
||||
{
|
||||
RemoveCorpse(false);
|
||||
LOG_DEBUG("entities.unit", "Removing corpse... {} ", GetUInt32Value(OBJECT_FIELD_ENTRY));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ALIVE:
|
||||
{
|
||||
Unit::Update(diff);
|
||||
|
||||
// xinef: update combat state, if npc is not in combat - return to spawn correctly by calling EnterEvadeMode
|
||||
SelectVictim();
|
||||
// creature can be dead after Unit::Update call
|
||||
// CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
|
||||
if (!IsAlive())
|
||||
break;
|
||||
|
||||
// if creature is charmed, switch to charmed AI
|
||||
if (NeedChangeAI)
|
||||
{
|
||||
UpdateCharmAI();
|
||||
NeedChangeAI = false;
|
||||
IsAIEnabled = true;
|
||||
|
||||
// xinef: update combat state, if npc is not in combat - return to spawn correctly by calling EnterEvadeMode
|
||||
SelectVictim();
|
||||
}
|
||||
|
||||
// periodic check to see if the creature has passed an evade boundary
|
||||
if (IsAIEnabled && !IsInEvadeMode() && IsEngaged())
|
||||
{
|
||||
if (diff >= m_boundaryCheckTime)
|
||||
{
|
||||
AI()->CheckInRoom();
|
||||
m_boundaryCheckTime = 2500;
|
||||
}
|
||||
else
|
||||
m_boundaryCheckTime -= diff;
|
||||
}
|
||||
|
||||
Unit* owner = GetCharmerOrOwner();
|
||||
if (IsCharmed() && !IsWithinDistInMap(owner, GetMap()->GetVisibilityRange(), true, false))
|
||||
{
|
||||
RemoveCharmAuras();
|
||||
}
|
||||
|
||||
if (Unit* victim = GetVictim())
|
||||
{
|
||||
// If we are closer than 50% of the combat reach we are going to reposition the victim
|
||||
if (diff >= m_moveBackwardsMovementTime)
|
||||
{
|
||||
float MaxRange = GetCollisionRadius() + GetVictim()->GetCollisionRadius();
|
||||
|
||||
if (IsInDist(victim, MaxRange))
|
||||
AI()->MoveBackwardsChecks();
|
||||
|
||||
m_moveBackwardsMovementTime = urand(MOVE_BACKWARDS_CHECK_INTERVAL, MOVE_BACKWARDS_CHECK_INTERVAL * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveBackwardsMovementTime -= diff;
|
||||
}
|
||||
|
||||
// periodic check to see if the creature has passed an evade boundary
|
||||
if (IsAIEnabled && !IsInEvadeMode() && IsEngaged())
|
||||
// Circling the target
|
||||
if (diff >= m_moveCircleMovementTime)
|
||||
{
|
||||
if (diff >= m_boundaryCheckTime)
|
||||
{
|
||||
AI()->CheckInRoom();
|
||||
m_boundaryCheckTime = 2500;
|
||||
} else
|
||||
m_boundaryCheckTime -= diff;
|
||||
AI()->MoveCircleChecks();
|
||||
m_moveCircleMovementTime = urand(MOVE_CIRCLE_CHECK_INTERVAL, MOVE_CIRCLE_CHECK_INTERVAL * 2);
|
||||
}
|
||||
|
||||
Unit* owner = GetCharmerOrOwner();
|
||||
if (IsCharmed() && !IsWithinDistInMap(owner, GetMap()->GetVisibilityRange(), true, false))
|
||||
else
|
||||
{
|
||||
RemoveCharmAuras();
|
||||
m_moveCircleMovementTime -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
if (Unit *victim = GetVictim())
|
||||
// Call for assistance if not disabled
|
||||
if (m_assistanceTimer)
|
||||
{
|
||||
if (m_assistanceTimer <= diff)
|
||||
{
|
||||
// If we are closer than 50% of the combat reach we are going to reposition the victim
|
||||
if (diff >= m_moveBackwardsMovementTime)
|
||||
if (CanPeriodicallyCallForAssistance())
|
||||
{
|
||||
float MaxRange = GetCollisionRadius() + GetVictim()->GetCollisionRadius();
|
||||
|
||||
if (IsInDist(victim, MaxRange))
|
||||
AI()->MoveBackwardsChecks();
|
||||
|
||||
m_moveBackwardsMovementTime = urand(MOVE_BACKWARDS_CHECK_INTERVAL, MOVE_BACKWARDS_CHECK_INTERVAL * 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveBackwardsMovementTime -= diff;
|
||||
}
|
||||
|
||||
// Circling the target
|
||||
if (diff >= m_moveCircleMovementTime)
|
||||
{
|
||||
AI()->MoveCircleChecks();
|
||||
m_moveCircleMovementTime = urand(MOVE_CIRCLE_CHECK_INTERVAL, MOVE_CIRCLE_CHECK_INTERVAL * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_moveCircleMovementTime -= diff;
|
||||
SetNoCallAssistance(false);
|
||||
CallAssistance();
|
||||
}
|
||||
m_assistanceTimer = sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_PERIOD);
|
||||
}
|
||||
|
||||
// Call for assistance if not disabled
|
||||
if (m_assistanceTimer)
|
||||
else
|
||||
{
|
||||
if (m_assistanceTimer <= diff)
|
||||
m_assistanceTimer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsInEvadeMode() && IsAIEnabled)
|
||||
{
|
||||
// do not allow the AI to be changed during update
|
||||
m_AI_locked = true;
|
||||
i_AI->UpdateAI(diff);
|
||||
m_AI_locked = false;
|
||||
}
|
||||
|
||||
// creature can be dead after UpdateAI call
|
||||
// CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
|
||||
if (!IsAlive())
|
||||
break;
|
||||
|
||||
m_regenTimer -= diff;
|
||||
if (m_regenTimer <= 0)
|
||||
{
|
||||
if (!IsInEvadeMode())
|
||||
{
|
||||
// regenerate health if not in combat or if polymorphed)
|
||||
if (!IsInCombat() || IsPolymorphed())
|
||||
RegenerateHealth();
|
||||
else if (IsNotReachableAndNeedRegen())
|
||||
{
|
||||
if (CanPeriodicallyCallForAssistance())
|
||||
// regenerate health if cannot reach the target and the setting is set to do so.
|
||||
// this allows to disable the health regen of raid bosses if pathfinding has issues for whatever reason
|
||||
if (sWorld->getBoolConfig(CONFIG_REGEN_HP_CANNOT_REACH_TARGET_IN_RAID) || !GetMap()->IsRaid())
|
||||
{
|
||||
SetNoCallAssistance(false);
|
||||
CallAssistance();
|
||||
}
|
||||
m_assistanceTimer = sWorld->getIntConfig(CONFIG_CREATURE_FAMILY_ASSISTANCE_PERIOD);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_assistanceTimer -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsInEvadeMode() && IsAIEnabled)
|
||||
{
|
||||
// do not allow the AI to be changed during update
|
||||
m_AI_locked = true;
|
||||
i_AI->UpdateAI(diff);
|
||||
m_AI_locked = false;
|
||||
}
|
||||
|
||||
// creature can be dead after UpdateAI call
|
||||
// CORPSE/DEAD state will processed at next tick (in other case death timer will be updated unexpectedly)
|
||||
if (!IsAlive())
|
||||
break;
|
||||
|
||||
m_regenTimer -= diff;
|
||||
if (m_regenTimer <= 0)
|
||||
{
|
||||
if (!IsInEvadeMode())
|
||||
{
|
||||
// regenerate health if not in combat or if polymorphed)
|
||||
if (!IsInCombat() || IsPolymorphed())
|
||||
RegenerateHealth();
|
||||
else if (IsNotReachableAndNeedRegen())
|
||||
LOG_DEBUG("entities.unit", "RegenerateHealth() enabled because Creature cannot reach the target. Detail: {}", GetDebugInfo());
|
||||
}
|
||||
else
|
||||
LOG_DEBUG("entities.unit", "RegenerateHealth() disabled even if the Creature cannot reach the target. Detail: {}", GetDebugInfo());
|
||||
}
|
||||
}
|
||||
|
||||
if (getPowerType() == POWER_ENERGY)
|
||||
Regenerate(POWER_ENERGY);
|
||||
else
|
||||
Regenerate(POWER_MANA);
|
||||
|
||||
m_regenTimer += CREATURE_REGEN_INTERVAL;
|
||||
}
|
||||
|
||||
if (CanNotReachTarget() && !IsInEvadeMode())
|
||||
{
|
||||
m_cannotReachTimer += diff;
|
||||
if (m_cannotReachTimer >= (sWorld->getIntConfig(CONFIG_NPC_EVADE_IF_NOT_REACHABLE) * IN_MILLISECONDS))
|
||||
{
|
||||
Player* cannotReachPlayer = ObjectAccessor::GetPlayer(*this, m_cannotReachTarget);
|
||||
if (cannotReachPlayer && IsEngagedBy(cannotReachPlayer) && IsAIEnabled && AI()->OnTeleportUnreacheablePlayer(cannotReachPlayer))
|
||||
{
|
||||
SetCannotReachTarget();
|
||||
}
|
||||
else if (!GetMap()->IsRaid())
|
||||
{
|
||||
auto EnterEvade = [&]()
|
||||
{
|
||||
// regenerate health if cannot reach the target and the setting is set to do so.
|
||||
// this allows to disable the health regen of raid bosses if pathfinding has issues for whatever reason
|
||||
if (sWorld->getBoolConfig(CONFIG_REGEN_HP_CANNOT_REACH_TARGET_IN_RAID) || !GetMap()->IsRaid())
|
||||
if (CreatureAI* ai = AI())
|
||||
{
|
||||
RegenerateHealth();
|
||||
LOG_DEBUG("entities.unit", "RegenerateHealth() enabled because Creature cannot reach the target. Detail: {}", GetDebugInfo());
|
||||
ai->EnterEvadeMode(CreatureAI::EvadeReason::EVADE_REASON_NO_PATH);
|
||||
}
|
||||
};
|
||||
|
||||
if (GetThreatMgr().getThreatList().size() <= 1)
|
||||
{
|
||||
EnterEvade();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (HostileReference* ref = GetThreatMgr().getOnlineContainer().getReferenceByTarget(m_cannotReachTarget))
|
||||
{
|
||||
ref->removeReference();
|
||||
SetCannotReachTarget();
|
||||
}
|
||||
else
|
||||
LOG_DEBUG("entities.unit", "RegenerateHealth() disabled even if the Creature cannot reach the target. Detail: {}", GetDebugInfo());
|
||||
{
|
||||
EnterEvade();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (getPowerType() == POWER_ENERGY)
|
||||
Regenerate(POWER_ENERGY);
|
||||
else
|
||||
Regenerate(POWER_MANA);
|
||||
|
||||
m_regenTimer += CREATURE_REGEN_INTERVAL;
|
||||
}
|
||||
|
||||
if (CanNotReachTarget() && !IsInEvadeMode() && !GetMap()->IsRaid())
|
||||
{
|
||||
m_cannotReachTimer += diff;
|
||||
if (IsNotReachable() && IsAIEnabled)
|
||||
{
|
||||
AI()->EnterEvadeMode();
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -883,6 +914,11 @@ void Creature::Regenerate(Powers power)
|
||||
if (!HasUnitFlag2(UNIT_FLAG2_REGENERATE_POWER) && !GetOwnerGUID().IsPlayer())
|
||||
return;
|
||||
|
||||
if (!m_regenPower)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (curValue >= maxValue)
|
||||
return;
|
||||
|
||||
@@ -1020,7 +1056,7 @@ bool Creature::AIM_Initialize(CreatureAI* ai)
|
||||
// Xinef: called in add to world
|
||||
//Motion_Initialize();
|
||||
|
||||
i_AI = ai ? ai : FactorySelector::selectAI(this);
|
||||
i_AI = ai ? ai : FactorySelector::SelectAI(this);
|
||||
delete oldAI;
|
||||
IsAIEnabled = true;
|
||||
i_AI->InitializeAI();
|
||||
@@ -1927,7 +1963,7 @@ void Creature::setDeathState(DeathState s, bool despawn)
|
||||
SetFullHealth();
|
||||
SetLootRecipient(nullptr);
|
||||
ResetPlayerDamageReq();
|
||||
SetCannotReachTarget(false);
|
||||
SetCannotReachTarget();
|
||||
CreatureTemplate const* cinfo = GetCreatureTemplate();
|
||||
// Xinef: npc run by default
|
||||
//SetWalk(true);
|
||||
@@ -2861,7 +2897,7 @@ uint8 Creature::getLevelForTarget(WorldObject const* target) const
|
||||
return uint8(level);
|
||||
}
|
||||
|
||||
std::string Creature::GetAIName() const
|
||||
std::string const& Creature::GetAIName() const
|
||||
{
|
||||
return sObjectMgr->GetCreatureTemplate(GetEntry())->AIName;
|
||||
}
|
||||
@@ -3468,7 +3504,24 @@ bool Creature::SetCannotReachTarget(bool cannotReach, bool isChase /*= true*/)
|
||||
m_cannotReachTimer = 0;
|
||||
|
||||
if (cannotReach)
|
||||
{
|
||||
LOG_DEBUG("entities.unit", "Creature::SetCannotReachTarget() called with true. Details: {}", GetDebugInfo());
|
||||
}
|
||||
}
|
||||
|
||||
bool Creature::CanNotReachTarget() const
|
||||
{
|
||||
return m_cannotReachTarget;
|
||||
}
|
||||
|
||||
bool Creature::IsNotReachableAndNeedRegen() const
|
||||
{
|
||||
if (CanNotReachTarget())
|
||||
{
|
||||
return m_cannotReachTimer >= (sWorld->getIntConfig(CONFIG_NPC_REGEN_TIME_IF_NOT_REACHABLE_IN_RAID) * IN_MILLISECONDS);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
time_t Creature::GetLastDamagedTime() const
|
||||
|
||||
@@ -198,7 +198,7 @@ public:
|
||||
void SetDetectionDistance(float dist){ m_detectionDistance = dist; }
|
||||
[[nodiscard]] CreatureAddon const* GetCreatureAddon() const;
|
||||
|
||||
[[nodiscard]] std::string GetAIName() const;
|
||||
[[nodiscard]] std::string const& GetAIName() const;
|
||||
[[nodiscard]] std::string GetScriptName() const;
|
||||
[[nodiscard]] uint32 GetScriptId() const;
|
||||
|
||||
@@ -300,6 +300,7 @@ public:
|
||||
|
||||
bool isRegeneratingHealth() { return m_regenHealth; }
|
||||
void SetRegeneratingHealth(bool c) { m_regenHealth = c; }
|
||||
void SetRegeneratingPower(bool c) { m_regenPower = c; }
|
||||
[[nodiscard]] virtual uint8 GetPetAutoSpellSize() const { return MAX_SPELL_CHARM; }
|
||||
[[nodiscard]] virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
|
||||
{
|
||||
@@ -417,6 +418,7 @@ protected:
|
||||
bool m_AlreadyCallAssistance;
|
||||
bool m_AlreadySearchedAssistance;
|
||||
bool m_regenHealth;
|
||||
bool m_regenPower;
|
||||
bool m_AI_locked;
|
||||
|
||||
SpellSchoolMask m_meleeDamageSchoolMask;
|
||||
@@ -455,7 +457,7 @@ private:
|
||||
|
||||
mutable std::shared_ptr<time_t> _lastDamagedTime; // Part of Evade mechanics
|
||||
|
||||
bool m_cannotReachTarget;
|
||||
ObjectGuid m_cannotReachTarget;
|
||||
uint32 m_cannotReachTimer;
|
||||
|
||||
Spell const* _focusSpell; ///> Locks the target during spell cast for proper facing
|
||||
|
||||
@@ -80,8 +80,7 @@ enum CreatureFlagsExtra : uint32
|
||||
CREATURE_FLAG_EXTRA_HARD_RESET = 0x80000000,
|
||||
|
||||
// Masks
|
||||
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_26 |
|
||||
CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_28), // SKIP
|
||||
CREATURE_FLAG_EXTRA_UNUSED = (CREATURE_FLAG_EXTRA_UNUSED_12 | CREATURE_FLAG_EXTRA_UNUSED_26 | CREATURE_FLAG_EXTRA_UNUSED_27 | CREATURE_FLAG_EXTRA_UNUSED_28), // SKIP
|
||||
|
||||
CREATURE_FLAG_EXTRA_DB_ALLOWED = (0xFFFFFFFF & ~(CREATURE_FLAG_EXTRA_UNUSED | CREATURE_FLAG_EXTRA_DUNGEON_BOSS)) // SKIP
|
||||
};
|
||||
|
||||
@@ -381,3 +381,40 @@ void CreatureGroup::LeaderMoveTo(float x, float y, float z, bool run)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreatureGroup::RespawnFormation(bool force)
|
||||
{
|
||||
for (auto const& itr : m_members)
|
||||
{
|
||||
if (itr.first && !itr.first->IsAlive())
|
||||
{
|
||||
itr.first->Respawn(force);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CreatureGroup::IsFormationInCombat()
|
||||
{
|
||||
for (auto const& itr : m_members)
|
||||
{
|
||||
if (itr.first && itr.first->IsInCombat())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CreatureGroup::IsAnyMemberAlive()
|
||||
{
|
||||
for (auto const& itr : m_members)
|
||||
{
|
||||
if (itr.first && itr.first->IsAlive())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -109,6 +109,9 @@ public:
|
||||
void LeaderMoveTo(float x, float y, float z, bool run);
|
||||
void MemberEngagingTarget(Creature* member, Unit* target);
|
||||
void MemberEvaded(Creature* member);
|
||||
void RespawnFormation(bool force = false);
|
||||
[[nodiscard]] bool IsFormationInCombat();
|
||||
[[nodiscard]] bool IsAnyMemberAlive();
|
||||
|
||||
private:
|
||||
Creature* m_leader; //Important do not forget sometimes to work with pointers instead synonims :D:D
|
||||
|
||||
@@ -96,7 +96,7 @@ bool GameObject::AIM_Initialize()
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string GameObject::GetAIName() const
|
||||
std::string const& GameObject::GetAIName() const
|
||||
{
|
||||
return sObjectMgr->GetGameObjectTemplate(GetEntry())->AIName;
|
||||
}
|
||||
|
||||
@@ -1001,7 +1001,7 @@ public:
|
||||
[[nodiscard]] virtual uint32 GetScriptId() const;
|
||||
[[nodiscard]] GameObjectAI* AI() const { return m_AI; }
|
||||
|
||||
[[nodiscard]] std::string GetAIName() const;
|
||||
[[nodiscard]] std::string const& GetAIName() const;
|
||||
void SetDisplayId(uint32 displayid);
|
||||
[[nodiscard]] uint32 GetDisplayId() const { return GetUInt32Value(GAMEOBJECT_DISPLAYID); }
|
||||
|
||||
|
||||
@@ -1154,7 +1154,9 @@ bool Guardian::InitStatsForLevel(uint8 petlevel)
|
||||
{
|
||||
// xinef: Glyph of Felguard, so ugly im crying... no appropriate spell
|
||||
if (AuraEffect* aurEff = owner->GetAuraEffectDummy(SPELL_GLYPH_OF_FELGUARD))
|
||||
SetModifierValue(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, 1.0f + float(aurEff->GetAmount() / 100.0f));
|
||||
{
|
||||
HandleStatModifier(UNIT_MOD_ATTACK_POWER, TOTAL_PCT, aurEff->GetAmount(), true);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -8911,7 +8911,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
|
||||
return;
|
||||
}
|
||||
|
||||
if (returnreagent && (pet || m_temporaryUnsummonedPetNumber) && !InBattleground())
|
||||
if (returnreagent && (pet || (m_temporaryUnsummonedPetNumber && (!m_session || !m_session->PlayerLogout()))) && !InBattleground())
|
||||
{
|
||||
//returning of reagents only for players, so best done here
|
||||
uint32 spellId = pet ? pet->GetUInt32Value(UNIT_CREATED_BY_SPELL) : m_oldpetspell;
|
||||
@@ -12573,8 +12573,13 @@ void Player::SetMover(Unit* target)
|
||||
LOG_INFO("misc", "Player::SetMover (B2) - {}, {}, {}, {}, {}, {}, {}, {}", target->GetGUID().ToString(), target->GetMapId(), target->GetInstanceId(), target->FindMap()->GetId(), target->IsInWorld() ? 1 : 0, target->IsDuringRemoveFromWorld() ? 1 : 0, (target->ToPlayer() && target->ToPlayer()->IsBeingTeleported() ? 1 : 0), target->isBeingLoaded() ? 1 : 0);
|
||||
}
|
||||
m_mover->m_movedByPlayer = nullptr;
|
||||
if (m_mover->GetTypeId() == TYPEID_UNIT)
|
||||
m_mover->GetMotionMaster()->Initialize();
|
||||
|
||||
m_mover = target;
|
||||
m_mover->m_movedByPlayer = this;
|
||||
if (m_mover->GetTypeId() == TYPEID_UNIT)
|
||||
m_mover->GetMotionMaster()->Initialize();
|
||||
}
|
||||
|
||||
uint32 Player::GetCorpseReclaimDelay(bool pvp) const
|
||||
|
||||
@@ -289,8 +289,8 @@ typedef std::list<PlayerCreateInfoItem> PlayerCreateInfoItems;
|
||||
struct PlayerClassLevelInfo
|
||||
{
|
||||
PlayerClassLevelInfo() = default;
|
||||
uint16 basehealth{0};
|
||||
uint16 basemana{0};
|
||||
uint32 basehealth{0};
|
||||
uint32 basemana{0};
|
||||
};
|
||||
|
||||
struct PlayerClassInfo
|
||||
@@ -302,9 +302,12 @@ struct PlayerClassInfo
|
||||
|
||||
struct PlayerLevelInfo
|
||||
{
|
||||
PlayerLevelInfo() { for (unsigned char & stat : stats) stat = 0; }
|
||||
PlayerLevelInfo()
|
||||
{
|
||||
stats.fill(0);
|
||||
}
|
||||
|
||||
uint8 stats[MAX_STATS];
|
||||
std::array<uint32, MAX_STATS> stats = { };
|
||||
};
|
||||
|
||||
typedef std::list<uint32> PlayerCreateInfoSpells;
|
||||
@@ -2732,7 +2735,7 @@ public:
|
||||
ActionButtonList m_actionButtons;
|
||||
|
||||
float m_auraBaseMod[BASEMOD_END][MOD_END];
|
||||
int16 m_baseRatingValue[MAX_COMBAT_RATING];
|
||||
int32 m_baseRatingValue[MAX_COMBAT_RATING];
|
||||
uint32 m_baseSpellPower;
|
||||
uint32 m_baseFeralAP;
|
||||
uint32 m_baseManaRegen;
|
||||
|
||||
@@ -108,12 +108,11 @@ void Player::_SavePlayerSettings(CharacterDatabaseTransaction trans)
|
||||
void Player::UpdatePlayerSetting(std::string source, uint8 index, uint32 value)
|
||||
{
|
||||
auto itr = m_charSettingsMap.find(source);
|
||||
uint8 size = index + 1;
|
||||
|
||||
if (itr == m_charSettingsMap.end())
|
||||
{
|
||||
// Settings not found, initialize a new entry.
|
||||
uint8 size = index ? index : index + 1;
|
||||
|
||||
PlayerSettingVector setting;
|
||||
setting.resize(size);
|
||||
|
||||
@@ -129,6 +128,10 @@ void Player::UpdatePlayerSetting(std::string source, uint8 index, uint32 value)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (size > itr->second.size())
|
||||
{
|
||||
itr->second.resize(size);
|
||||
}
|
||||
itr->second[index].value = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,20 +34,13 @@ Totem::Totem(SummonPropertiesEntry const* properties, ObjectGuid owner) : Minion
|
||||
void Totem::Update(uint32 time)
|
||||
{
|
||||
Unit* owner = GetOwner();
|
||||
if (!owner || !owner->IsAlive() || !IsAlive())
|
||||
if (!owner || !owner->IsAlive() || !IsAlive() || m_duration <= time)
|
||||
{
|
||||
UnSummon(); // remove self
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_duration <= time)
|
||||
{
|
||||
UnSummon(); // remove self
|
||||
return;
|
||||
}
|
||||
else
|
||||
m_duration -= time;
|
||||
|
||||
m_duration -= time;
|
||||
Creature::Update(time);
|
||||
}
|
||||
|
||||
|
||||
@@ -1034,7 +1034,14 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
|
||||
victim->ToCreature()->SetLastDamagedTime(GameTime::GetGameTime().count() + MAX_AGGRO_RESET_TIME);
|
||||
|
||||
if (attacker)
|
||||
{
|
||||
if (spellProto && !victim->IsInCombatWith(attacker))
|
||||
{
|
||||
victim->CombatStart(attacker, !(spellProto->AttributesEx3 & SPELL_ATTR3_SUPRESS_TARGET_PROCS));
|
||||
}
|
||||
|
||||
victim->AddThreat(attacker, float(damage), damageSchoolMask, spellProto);
|
||||
}
|
||||
}
|
||||
else // victim is a player
|
||||
{
|
||||
@@ -8921,6 +8928,15 @@ bool Unit::HandleProcTriggerSpell(Unit* victim, uint32 damage, AuraEffect* trigg
|
||||
// Lightning Shield (overwrite non existing triggered spell call in spell.dbc
|
||||
if (auraSpellInfo->SpellFamilyFlags[0] & 0x400)
|
||||
{
|
||||
// Do not proc off from self-casted items
|
||||
if (Spell const* spell = eventInfo.GetProcSpell())
|
||||
{
|
||||
if (spell->m_castItemGUID && victim->GetGUID() == GetGUID())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
trigger_spell_id = sSpellMgr->GetSpellWithRank(26364, auraSpellInfo->GetRank());
|
||||
}
|
||||
// Nature's Guardian
|
||||
|
||||
Reference in New Issue
Block a user