Merge branch 'master' into Playerbot

This commit is contained in:
Yunfan Li
2024-08-30 22:38:08 +08:00
49 changed files with 1958 additions and 1121 deletions

View File

@@ -1946,11 +1946,21 @@ bool Creature::CanStartAttack(Unit const* who) const
return IsWithinLOSInMap(who);
}
void Creature::setDeathState(DeathState s, bool despawn)
/**
* @brief A creature can be in 4 different states: Alive, JustDied, Corpse, and JustRespawned. The cycle follows the next order:
* - Alive: The creature is alive and has spawned in the world
* - JustDied: The creature has just died. This is the state just before his body appeared
* - Corpse: The creature has been removed from the world, and this corpse has been spawned
* - JustRespawned: The creature has just respawned. Follow when the corpse disappears and the respawn timer is finished
*
* @param state Specify one of 4 states above
* @param despawn Despawn the creature immediately, without waiting for any movement to finish
*/
void Creature::setDeathState(DeathState state, bool despawn)
{
Unit::setDeathState(s, despawn);
Unit::setDeathState(state, despawn);
if (s == DeathState::JustDied)
if (state == DeathState::JustDied)
{
_lastDamagedTime.reset();
@@ -1961,10 +1971,10 @@ void Creature::setDeathState(DeathState s, bool despawn)
if (GetMap()->IsDungeon() || isWorldBoss() || GetCreatureTemplate()->rank >= CREATURE_ELITE_ELITE)
SaveRespawnTime();
SetTarget(); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState)
SetTarget(); // remove target selection in any cases (can be set at aura remove in Unit::setDeathState)
ReplaceAllNpcFlags(UNIT_NPC_FLAG_NONE);
Dismount(); // if creature is mounted on a virtual mount, remove it at death
Dismount(); // if creature is mounted on a virtual mount, remove it at death
setActive(false);
@@ -1986,10 +1996,8 @@ void Creature::setDeathState(DeathState s, bool despawn)
Unit::setDeathState(DeathState::Corpse, despawn);
}
else if (s == DeathState::JustRespawned)
else if (state == DeathState::JustRespawned)
{
//if (IsPet())
// setActive(true);
SetFullHealth();
SetLootRecipient(nullptr);
ResetPlayerDamageReq();
@@ -2017,6 +2025,9 @@ void Creature::setDeathState(DeathState s, bool despawn)
}
}
/**
* @param force Force the respawn by killing the creature.
*/
void Creature::Respawn(bool force)
{
if (force)
@@ -2041,7 +2052,7 @@ void Creature::Respawn(bool force)
}
bool allowed = !IsAIEnabled || AI()->CanRespawn(); // First check if there are any scripts that prevent us respawning
if (!allowed && !force) // Will be rechecked on next Update call
if (!allowed && !force) // Will be rechecked on next Update call
return;
ObjectGuid dbtableHighGuid = ObjectGuid::Create<HighGuid::Unit>(m_creatureData ? m_creatureData->id1 : GetEntry(), m_spawnId);
@@ -2083,8 +2094,7 @@ void Creature::Respawn(bool force)
setDeathState(DeathState::JustRespawned);
// MDic - Acidmanifesto
// Do not override transform auras
// MDic - Acidmanifesto: Do not override transform auras
if (GetAuraEffectsByType(SPELL_AURA_TRANSFORM).empty())
{
CreatureModel display(GetNativeDisplayId(), GetNativeObjectScale(), 1.0f);
@@ -2103,7 +2113,7 @@ void Creature::Respawn(bool force)
{
//reset the AI to be sure no dirty or uninitialized values will be used till next tick
AI()->Reset();
TriggerJustRespawned = true;//delay event to next tick so all creatures are created on the map before processing
TriggerJustRespawned = true; //delay event to next tick so all creatures are created on the map before processing
}
uint32 poolid = m_spawnId ? sPoolMgr->IsPartOfAPool<Creature>(m_spawnId) : 0;
@@ -2121,7 +2131,7 @@ void Creature::Respawn(bool force)
UpdateObjectVisibility(false);
}
else // the master is dead
else // the master is dead
{
ObjectGuid targetGuid = sObjectMgr->GetLinkedRespawnGuid(dbtableHighGuid);
if (targetGuid == dbtableHighGuid) // if linking self, never respawn (check delayed to next day)
@@ -2149,7 +2159,7 @@ void Creature::ForcedDespawn(uint32 timeMSToDespawn, Seconds forceRespawnTimer)
if (IsAlive())
setDeathState(DeathState::JustDied, true);
// Xinef: set new respawn time, ignore corpse decay time...
// Xinef: Set new respawn time, ignore corpse decay time...
RemoveCorpse(true);
if (forceRespawnTimer > Seconds::zero())
@@ -2195,8 +2205,6 @@ void Creature::InitializeReactState()
SetReactState(REACT_PASSIVE);
else
SetReactState(REACT_AGGRESSIVE);
/*else if (IsCivilian())
SetReactState(REACT_DEFENSIVE);*/
}
bool Creature::HasMechanicTemplateImmunity(uint32 mask) const
@@ -2358,8 +2366,7 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim)
float range = spellInfo->GetMaxRange(true);
float minrange = spellInfo->GetMinRange(true);
float dist = GetDistance(victim);
//if (!isInFront(victim, range) && spellInfo->AttributesEx)
// continue;
if (dist > range || dist < minrange)
continue;
if (spellInfo->PreventionType == SPELL_PREVENTION_TYPE_SILENCE && HasUnitFlag(UNIT_FLAG_SILENCED))
@@ -2371,7 +2378,9 @@ SpellInfo const* Creature::reachWithSpellCure(Unit* victim)
return nullptr;
}
// select nearest hostile unit within the given distance (regardless of threat list).
/**
* @brief Select nearest hostile unit within the given distance (regardless of threat list).
*/
Unit* Creature::SelectNearestTarget(float dist, bool playerOnly /* = false */) const
{
if (dist == 0.0f)
@@ -2387,7 +2396,9 @@ Unit* Creature::SelectNearestTarget(float dist, bool playerOnly /* = false */) c
return target;
}
// select nearest hostile unit within the given attack distance (i.e. distance is ignored if > than ATTACK_DISTANCE), regardless of threat list.
/**
* @brief Select nearest hostile unit within the given attack distance (i.e. distance is ignored if > than ATTACK_DISTANCE), regardless of threat list.
*/
Unit* Creature::SelectNearestTargetInAttackDistance(float dist) const
{
if (dist < ATTACK_DISTANCE)
@@ -2630,7 +2641,7 @@ bool Creature::CanCreatureAttack(Unit const* victim, bool skipDistCheck) const
return false;
// cannot attack if is during 5 second grace period, unless being attacked
if (m_respawnedTime && (GameTime::GetGameTime().count() - m_respawnedTime) < 5 && victim->getAttackers().empty())
if (m_respawnedTime && (GameTime::GetGameTime().count() - m_respawnedTime) < 5 && !GetLastDamagedTime())
{
return false;
}
@@ -2781,6 +2792,9 @@ void Creature::SendZoneUnderAttackMessage(Player* attacker)
sWorld->SendGlobalMessage(&data, nullptr, (attacker->GetTeamId() == TEAM_ALLIANCE ? TEAM_HORDE : TEAM_ALLIANCE));
}
/**
* @brief Set in combat all units in the dungeon/raid. Affect only units with IsAIEnabled.
*/
void Creature::SetInCombatWithZone()
{
if (IsAIEnabled)
@@ -3147,6 +3161,9 @@ bool Creature::IsImmuneToKnockback() const
return cinfo && (cinfo->flags_extra & CREATURE_FLAG_EXTRA_IMMUNITY_KNOCKBACK);
}
/**
* @brief Enable or disable the creature's walk mode by removing: MOVEMENTFLAG_WALKING. Infom also the client
*/
bool Creature::SetWalk(bool enable)
{
if (!Unit::SetWalk(enable))
@@ -3158,6 +3175,9 @@ bool Creature::SetWalk(bool enable)
return true;
}
/**
* @brief Enable or disable the creature's fly mode by adding or removing: MOVEMENTFLAG_FLYING. Infom also the client
*/
bool Creature::SetDisableGravity(bool disable, bool packetOnly /*= false*/, bool updateAnimationTier /*= true*/)
{
//! It's possible only a packet is sent but moveflags are not updated

View File

@@ -40,7 +40,7 @@ class CreatureGroup;
// max different by z coordinate for creature aggro reaction
#define CREATURE_Z_ATTACK_RANGE 3
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
#define MAX_VENDOR_ITEMS 150 // Limitation in 3.x.x item count in SMSG_LIST_INVENTORY
class Creature : public Unit, public GridObject<Creature>, public MovableMapObject
{
@@ -67,7 +67,7 @@ public:
[[nodiscard]] ObjectGuid::LowType GetSpawnId() const { return m_spawnId; }
void Update(uint32 time) override; // overwrited Unit::Update
void Update(uint32 time) override; // overwrited Unit::Update
void GetRespawnPosition(float& x, float& y, float& z, float* ori = nullptr, float* dist = nullptr) const;
void SetCorpseDelay(uint32 delay) { m_corpseDelay = delay; }
@@ -88,9 +88,15 @@ public:
MovementGeneratorType GetDefaultMovementType() const override { return m_defaultMovementType; }
void SetDefaultMovementType(MovementGeneratorType mgt) { m_defaultMovementType = mgt; }
void SetReactState(ReactStates st) { m_reactState = st; }
/**
* @brief A creature can have 3 ReactStates : Agressive, Passive, Neutral
* - Agressive : The creature will attack any non friend units in sight
* - Passive : The creature will not attack anyone
* - Neutral : The creature will attack only if attacked
*/
void SetReactState(ReactStates state) { m_reactState = state; }
[[nodiscard]] ReactStates GetReactState() const { return m_reactState; }
[[nodiscard]] bool HasReactState(ReactStates state) const { return (m_reactState == state); }
[[nodiscard]] bool HasReactState(ReactStates state) const { return (m_reactState == state); } /// @brief Check if the creature has the specified ReactState
void InitializeReactState();
///// @todo RENAME THIS!!!!!
@@ -209,14 +215,14 @@ public:
// override WorldObject function for proper name localization
[[nodiscard]] std::string const& GetNameForLocaleIdx(LocaleConstant locale_idx) const override;
void setDeathState(DeathState s, bool despawn = false) override; // override virtual Unit::setDeathState
void setDeathState(DeathState s, bool despawn = false) override; // override virtual Unit::setDeathState
bool LoadFromDB(ObjectGuid::LowType guid, Map* map, bool allowDuplicate = false) { return LoadCreatureFromDB(guid, map, false, allowDuplicate); }
bool LoadCreatureFromDB(ObjectGuid::LowType guid, Map* map, bool addToMap = true, bool allowDuplicate = false);
void SaveToDB();
// overriden in Pet
virtual void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask);
virtual void DeleteFromDB(); // overriden in Pet
virtual void SaveToDB(uint32 mapid, uint8 spawnMask, uint32 phaseMask); // overriden in Pet
virtual void DeleteFromDB(); // overriden in Pet
Loot loot;
[[nodiscard]] ObjectGuid GetLootRecipientGUID() const { return m_lootRecipient; }
@@ -224,7 +230,7 @@ public:
[[nodiscard]] ObjectGuid::LowType GetLootRecipientGroupGUID() const { return m_lootRecipientGroup; }
[[nodiscard]] Group* GetLootRecipientGroup() const;
[[nodiscard]] bool hasLootRecipient() const { return m_lootRecipient || m_lootRecipientGroup; }
bool isTappedBy(Player const* player) const; // return true if the creature is tapped by the player or a member of his party.
bool isTappedBy(Player const* player) const; // return true if the creature is tapped by the player or a member of his party.
[[nodiscard]] bool CanGeneratePickPocketLoot() const;
void SetPickPocketLootTime();
void ResetPickPocketLootTime() { lootPickPocketRestoreTime = 0; }
@@ -266,7 +272,7 @@ public:
bool _IsTargetAcceptable(Unit const* target) const;
[[nodiscard]] bool CanIgnoreFeignDeath() const { return (GetCreatureTemplate()->flags_extra & CREATURE_FLAG_EXTRA_IGNORE_FEIGN_DEATH) != 0; }
// pussywizard: updated at faction change, disable move in line of sight if actual faction is not hostile to anyone
// pussywizard: Updated at faction change, disable move in line of sight if actual faction is not hostile to anyone
void UpdateMoveInLineOfSightState();
bool IsMoveInLineOfSightDisabled() { return m_moveInLineOfSightDisabled; }
bool IsMoveInLineOfSightStrictlyDisabled() { return m_moveInLineOfSightStrictlyDisabled; }
@@ -299,8 +305,8 @@ public:
void DoImmediateBoundaryCheck() { m_boundaryCheckTime = 0; }
uint32 m_groupLootTimer; // (msecs)timer used for group loot
uint32 lootingGroupLowGUID; // used to find group which is looting corpse
uint32 m_groupLootTimer; // (msecs)timer used for group loot
uint32 lootingGroupLowGUID; // used to find group which is looting corpse
void SendZoneUnderAttackMessage(Player* attacker);
@@ -310,8 +316,8 @@ public:
[[nodiscard]] bool hasInvolvedQuest(uint32 quest_id) const override;
bool isRegeneratingHealth() { return m_regenHealth; }
void SetRegeneratingHealth(bool c) { m_regenHealth = c; }
void SetRegeneratingPower(bool c) { m_regenPower = c; }
void SetRegeneratingHealth(bool enable) { m_regenHealth = enable; }
void SetRegeneratingPower(bool enable) { m_regenPower = enable; }
[[nodiscard]] virtual uint8 GetPetAutoSpellSize() const { return MAX_SPELL_CHARM; }
[[nodiscard]] virtual uint32 GetPetAutoSpellOnPos(uint8 pos) const
{
@@ -398,20 +404,17 @@ public:
/**
* @brief Helper to resume chasing current victim.
*
* */
*/
void ResumeChasingVictim() { GetMotionMaster()->MoveChase(GetVictim()); };
/**
* @brief Returns true if the creature is able to cast the spell.
*
* */
*/
bool CanCastSpell(uint32 spellID) const;
/**
* @brief Helper to get the creature's summoner GUID, if it is a summon
*
* */
* @brief Helper to get the creature's summoner GUID, if it is a summon
*/
[[nodiscard]] ObjectGuid GetSummonerGUID() const;
// Used to control if MoveChase() is to be used or not in AttackStart(). Some creatures does not chase victims
@@ -474,11 +477,11 @@ protected:
bool DisableReputationGain;
CreatureTemplate const* m_creatureInfo; // in difficulty mode > 0 can different from sObjectMgr->GetCreatureTemplate(GetEntry())
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
uint16 m_LootMode; // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
[[nodiscard]] bool IsInvisibleDueToDespawn() const override;
bool CanAlwaysSee(WorldObject const* obj) const override;
@@ -489,11 +492,11 @@ private:
[[nodiscard]] bool CanPeriodicallyCallForAssistance() const;
//WaypointMovementGenerator vars
// WaypointMovementGenerator variable
uint32 m_waypointID;
uint32 m_path_id;
//Formation var
// Formation variable
CreatureGroup* m_formation;
bool TriggerJustRespawned;

View File

@@ -13595,6 +13595,7 @@ uint32 Player::CalculateTalentsPoints() const
}
talentPointsForLevel += m_extraBonusTalentCount;
sScriptMgr->OnCalculateTalentsPoints(this, talentPointsForLevel);
return uint32(talentPointsForLevel * sWorld->getRate(RATE_TALENT));
}

View File

@@ -1141,6 +1141,9 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
return damage;
}
/**
* @brief Interrupt the unit cast for all the current spells
*/
void Unit::CastStop(uint32 except_spellid, bool withInstant)
{
for (uint32 i = CURRENT_FIRST_NON_MELEE_SPELL; i < CURRENT_MAX_SPELL; i++)
@@ -3034,6 +3037,10 @@ void Unit::SendMeleeAttackStart(Unit* victim, Player* sendTo)
LOG_DEBUG("entities.unit", "WORLD: Sent SMSG_ATTACKSTART");
}
/**
* @brief Send to the client SMSG_ATTACKSTOP but doesn't clear UNIT_STATE_MELEE_ATTACKING on server side
* or interrupt spells. Unless you know exactly what you're doing, use AttackStop() or RemoveAllAttackers() instead
*/
void Unit::SendMeleeAttackStop(Unit* victim)
{
// pussywizard: calling SendMeleeAttackStop without clearing UNIT_STATE_MELEE_ATTACKING and then AttackStart the same player may spoil npc rotating!
@@ -10348,6 +10355,10 @@ bool Unit::Attack(Unit* victim, bool meleeAttack)
return true;
}
/**
* @brief Force the unit to stop attacking. This will clear UNIT_STATE_MELEE_ATTACKING,
* Interrupt current spell, AI assistance, and call SendMeleeAttackStop() to the client
*/
bool Unit::AttackStop()
{
if (!m_attacking)
@@ -10424,6 +10435,9 @@ bool Unit::isAttackingPlayer() const
return false;
}
/**
* @brief Remove all units in m_attackers list and send them AttackStop()
*/
void Unit::RemoveAllAttackers()
{
while (!m_attackers.empty())
@@ -16617,7 +16631,7 @@ void Unit::ResumeMovement(uint32 timer /* = 0*/, uint8 slot /* = 0*/)
movementGenerator->Resume(timer);
}
void Unit::StopMovingOnCurrentPos() // pussywizard
void Unit::StopMovingOnCurrentPos()
{
ClearUnitState(UNIT_STATE_MOVING);
@@ -20518,6 +20532,12 @@ bool Unit::SetSwim(bool enable)
return true;
}
/**
* @brief Add the movement flag: MOVEMENTFLAGCAN_FLY. Generaly only use by players, allowing
* them to fly by pressing space for example. For creatures, please look for DisableGravity().
*
* Doesn't inform the client.
*/
bool Unit::SetCanFly(bool enable, bool /*packetOnly = false */)
{
if (enable == HasUnitMovementFlag(MOVEMENTFLAG_CAN_FLY))
@@ -20536,6 +20556,10 @@ bool Unit::SetCanFly(bool enable, bool /*packetOnly = false */)
return true;
}
/**
* @brief Allow to walk on water. Doesn't inform the client.
* Need to use SendMovementWaterWalking() if it's for players.
*/
bool Unit::SetWaterWalking(bool enable, bool /*packetOnly = false*/)
{
if (enable == HasUnitMovementFlag(MOVEMENTFLAG_WATERWALKING))

View File

@@ -717,6 +717,7 @@ public:
return nullptr;
}
bool Attack(Unit* victim, bool meleeAttack);
void CastStop(uint32 except_spellid = 0, bool withInstant = true);
bool AttackStop();
void RemoveAllAttackers();
@@ -821,10 +822,10 @@ public:
void SetUInt32Value(uint16 index, uint32 value);
UnitFlags GetUnitFlags() const { return UnitFlags(GetUInt32Value(UNIT_FIELD_FLAGS)); }
bool HasUnitFlag(UnitFlags flags) const { return HasFlag(UNIT_FIELD_FLAGS, flags); }
void SetUnitFlag(UnitFlags flags) { SetFlag(UNIT_FIELD_FLAGS, flags); }
void RemoveUnitFlag(UnitFlags flags) { RemoveFlag(UNIT_FIELD_FLAGS, flags); }
void ReplaceAllUnitFlags(UnitFlags flags) { SetUInt32Value(UNIT_FIELD_FLAGS, flags); }
bool HasUnitFlag(UnitFlags flags) const { return HasFlag(UNIT_FIELD_FLAGS, flags); } /// @brief UnitFlags available in UnitDefines.h
void SetUnitFlag(UnitFlags flags) { SetFlag(UNIT_FIELD_FLAGS, flags); } /// @brief UnitFlags available in UnitDefines.h
void RemoveUnitFlag(UnitFlags flags) { RemoveFlag(UNIT_FIELD_FLAGS, flags); } /// @brief Remove the Unit flag specify only
void ReplaceAllUnitFlags(UnitFlags flags) { SetUInt32Value(UNIT_FIELD_FLAGS, flags); } /// @brief Remove all UnitFlags and set new ones. UnitFlags available in UnitDefines.h
UnitFlags2 GetUnitFlags2() const { return UnitFlags2(GetUInt32Value(UNIT_FIELD_FLAGS_2)); }
bool HasUnitFlag2(UnitFlags2 flags) const { return HasFlag(UNIT_FIELD_FLAGS_2, flags); }
@@ -1609,7 +1610,7 @@ public:
[[nodiscard]] bool IsStopped() const { return !(HasUnitState(UNIT_STATE_MOVING)); }
void StopMoving();
void StopMovingOnCurrentPos();
void StopMovingOnCurrentPos(); /// @brief Disable the unit movement by clearing UNIT_STATE_MOVING and stopping the spline.
virtual void PauseMovement(uint32 timer = 0, uint8 slot = 0); // timer in ms
void ResumeMovement(uint32 timer = 0, uint8 slot = 0);