diff options
| author | Shauren <shauren.trinity@gmail.com> | 2024-01-08 22:23:12 +0100 |
|---|---|---|
| committer | Shauren <shauren.trinity@gmail.com> | 2024-01-08 22:23:12 +0100 |
| commit | 605e5f94c0d71cad8e83fa5a07eaec4e6bed9cc3 (patch) | |
| tree | 5cad677458a22ef0dd187fa86d1cd574282384dd /src/server/game | |
| parent | eeb4407f077bf567361becdbe5083c2790f00313 (diff) | |
Core/Creatures: Moved autoattack handling from scripts to game
Diffstat (limited to 'src/server/game')
20 files changed, 110 insertions, 215 deletions
diff --git a/src/server/game/AI/CoreAI/CombatAI.cpp b/src/server/game/AI/CoreAI/CombatAI.cpp index 16c161dbd7a..b20cf471b0c 100644 --- a/src/server/game/AI/CoreAI/CombatAI.cpp +++ b/src/server/game/AI/CoreAI/CombatAI.cpp @@ -43,10 +43,7 @@ int32 AggressorAI::Permissible(Creature const* creature) void AggressorAI::UpdateAI(uint32 /*diff*/) { - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); + UpdateVictim(); } ///////////////// @@ -107,8 +104,6 @@ void CombatAI::UpdateAI(uint32 diff) if (AISpellInfoType const* info = GetAISpellInfo(spellId, me->GetMap()->GetDifficultyID())) _events.ScheduleEvent(spellId, info->cooldown, info->cooldown * 2); } - else - DoMeleeAttackIfReady(); } void CombatAI::SpellInterrupted(uint32 spellId, uint32 unTimeMs) @@ -202,6 +197,7 @@ TurretAI::TurretAI(Creature* creature, uint32 scriptId) : CreatureAI(creature, s _minimumRange = spellInfo ? spellInfo->GetMinRange(false) : 0; creature->m_CombatDistance = spellInfo ? spellInfo->GetMaxRange(false) : 0; creature->m_SightDistance = creature->m_CombatDistance; + creature->SetCanMelee(false); } bool TurretAI::CanAIAttack(Unit const* who) const @@ -235,6 +231,7 @@ VehicleAI::VehicleAI(Creature* creature, uint32 scriptId) : CreatureAI(creature, LoadConditions(); _dismiss = false; _dismissTimer = VEHICLE_DISMISS_TIME; + me->SetCanMelee(false); } // NOTE: VehicleAI::UpdateAI runs even while the vehicle is mounted diff --git a/src/server/game/AI/CoreAI/GuardAI.cpp b/src/server/game/AI/CoreAI/GuardAI.cpp index 5d6b62e83a9..21511c1f2c0 100644 --- a/src/server/game/AI/CoreAI/GuardAI.cpp +++ b/src/server/game/AI/CoreAI/GuardAI.cpp @@ -31,10 +31,7 @@ int32 GuardAI::Permissible(Creature const* creature) void GuardAI::UpdateAI(uint32 /*diff*/) { - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); + UpdateVictim(); } bool GuardAI::CanSeeAlways(WorldObject const* obj) diff --git a/src/server/game/AI/CoreAI/PassiveAI.cpp b/src/server/game/AI/CoreAI/PassiveAI.cpp index 8bae96a6092..82904e5f52f 100644 --- a/src/server/game/AI/CoreAI/PassiveAI.cpp +++ b/src/server/game/AI/CoreAI/PassiveAI.cpp @@ -22,6 +22,7 @@ PassiveAI::PassiveAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId) { me->SetReactState(REACT_PASSIVE); + me->SetCanMelee(false); } PossessedAI::PossessedAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId) @@ -32,6 +33,7 @@ PossessedAI::PossessedAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId) NullCreatureAI::NullCreatureAI(Creature* c, uint32 scriptId) : CreatureAI(c, scriptId) { me->SetReactState(REACT_PASSIVE); + me->SetCanMelee(false); } int32 NullCreatureAI::Permissible(Creature const* creature) @@ -62,8 +64,6 @@ void PossessedAI::UpdateAI(uint32 /*diff*/) { if (!me->IsValidAttackTarget(me->GetVictim())) me->AttackStop(); - else - DoMeleeAttackIfReady(); } } diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 42666d2a1e2..16e9356f646 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -80,15 +80,6 @@ void PetAI::UpdateAI(uint32 diff) StopAttack(); return; } - - // Check before attacking to prevent pets from leaving stay position - if (me->GetCharmInfo()->HasCommandState(COMMAND_STAY)) - { - if (me->GetCharmInfo()->IsCommandAttack() || (me->GetCharmInfo()->IsAtStay() && me->IsWithinMeleeRange(me->GetVictim()))) - DoMeleeAttackIfReady(); - } - else - DoMeleeAttackIfReady(); } else { diff --git a/src/server/game/AI/CoreAI/ReactorAI.cpp b/src/server/game/AI/CoreAI/ReactorAI.cpp index 8b15bed1908..a22876a067b 100644 --- a/src/server/game/AI/CoreAI/ReactorAI.cpp +++ b/src/server/game/AI/CoreAI/ReactorAI.cpp @@ -28,8 +28,5 @@ int32 ReactorAI::Permissible(Creature const* creature) void ReactorAI::UpdateAI(uint32 /*diff*/) { - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); + UpdateVictim(); } diff --git a/src/server/game/AI/CoreAI/UnitAI.cpp b/src/server/game/AI/CoreAI/UnitAI.cpp index c8d2f61e77b..1470ca07bd9 100644 --- a/src/server/game/AI/CoreAI/UnitAI.cpp +++ b/src/server/game/AI/CoreAI/UnitAI.cpp @@ -58,41 +58,6 @@ void UnitAI::AttackStartCaster(Unit* victim, float dist) me->GetMotionMaster()->MoveChase(victim, dist); } -void UnitAI::DoMeleeAttackIfReady() -{ - if (me->IsCreature() && !me->ToCreature()->CanMelee()) - return; - - if (me->HasUnitState(UNIT_STATE_CASTING)) - { - Spell* channeledSpell = me->GetCurrentSpell(CURRENT_CHANNELED_SPELL); - if (!channeledSpell || !channeledSpell->GetSpellInfo()->HasAttribute(SPELL_ATTR5_ALLOW_ACTIONS_DURING_CHANNEL)) - return; - } - - Unit* victim = me->GetVictim(); - - if (!me->IsWithinMeleeRange(victim)) - return; - - // Check that the victim is in front of the unit - if (!me->HasInArc(2 * float(M_PI) / 3, victim)) - return; - - //Make sure our attack is ready and we aren't currently casting before checking distance - if (me->isAttackReady()) - { - me->AttackerStateUpdate(victim); - me->resetAttackTimer(); - } - - if (me->haveOffhandWeapon() && me->isAttackReady(OFF_ATTACK)) - { - me->AttackerStateUpdate(victim, OFF_ATTACK); - me->resetAttackTimer(OFF_ATTACK); - } -} - bool UnitAI::DoSpellAttackIfReady(uint32 spellId) { if (me->HasUnitState(UNIT_STATE_CASTING) || !me->isAttackReady()) diff --git a/src/server/game/AI/CoreAI/UnitAI.h b/src/server/game/AI/CoreAI/UnitAI.h index fed0cae7203..1ae52ff00a7 100644 --- a/src/server/game/AI/CoreAI/UnitAI.h +++ b/src/server/game/AI/CoreAI/UnitAI.h @@ -160,7 +160,6 @@ class TC_GAME_API UnitAI SpellCastResult DoCastVictim(uint32 spellId, CastSpellExtraArgs const& args = {}); SpellCastResult DoCastAOE(uint32 spellId, CastSpellExtraArgs const& args = {}) { return DoCast(nullptr, spellId, args); } - void DoMeleeAttackIfReady(); bool DoSpellAttackIfReady(uint32 spellId); static std::unordered_map<std::pair<uint32, Difficulty>, AISpellInfoType> AISpellInfo; diff --git a/src/server/game/AI/PlayerAI/PlayerAI.cpp b/src/server/game/AI/PlayerAI/PlayerAI.cpp index 2f104c40eac..bfa4ea84f96 100644 --- a/src/server/game/AI/PlayerAI/PlayerAI.cpp +++ b/src/server/game/AI/PlayerAI/PlayerAI.cpp @@ -591,8 +591,6 @@ void PlayerAI::DoAutoAttackIfReady() { if (IsRangedAttacker()) DoRangedAttackIfReady(); - else - DoMeleeAttackIfReady(); } void PlayerAI::CancelAllShapeshifts() diff --git a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp index 00c15509f5a..82c8dac896f 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedCreature.cpp @@ -149,10 +149,7 @@ void ScriptedAI::AttackStart(Unit* who) void ScriptedAI::UpdateAI(uint32 /*diff*/) { // Check if we have a current target - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); + UpdateVictim(); } void ScriptedAI::DoStartMovement(Unit* victim, float distance, float angle) @@ -629,8 +626,6 @@ void BossAI::UpdateAI(uint32 diff) if (me->HasUnitState(UNIT_STATE_CASTING)) return; } - - DoMeleeAttackIfReady(); } bool BossAI::CanAIAttack(Unit const* target) const @@ -716,6 +711,4 @@ void WorldBossAI::UpdateAI(uint32 diff) if (me->HasUnitState(UNIT_STATE_CASTING)) return; } - - DoMeleeAttackIfReady(); } diff --git a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp index ca6290d1379..19d11c4b957 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedEscortAI.cpp @@ -248,10 +248,7 @@ void EscortAI::UpdateAI(uint32 diff) void EscortAI::UpdateEscortAI(uint32 /*diff*/) { - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); + UpdateVictim(); } void EscortAI::AddWaypoint(uint32 id, float x, float y, float z, bool run) diff --git a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp index f12b7aaf9b6..c0a5aa3350a 100644 --- a/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp +++ b/src/server/game/AI/ScriptedAI/ScriptedFollowerAI.cpp @@ -147,10 +147,7 @@ void FollowerAI::UpdateAI(uint32 uiDiff) void FollowerAI::UpdateFollowerAI(uint32 /*uiDiff*/) { - if (!UpdateVictim()) - return; - - DoMeleeAttackIfReady(); + UpdateVictim(); } void FollowerAI::StartFollow(Player* player, uint32 factionForFollower, uint32 quest) diff --git a/src/server/game/AI/SmartScripts/SmartAI.cpp b/src/server/game/AI/SmartScripts/SmartAI.cpp index 370e2d1a9f8..9177443d57f 100644 --- a/src/server/game/AI/SmartScripts/SmartAI.cpp +++ b/src/server/game/AI/SmartScripts/SmartAI.cpp @@ -283,21 +283,13 @@ void SmartAI::UpdateAI(uint32 diff) CheckConditions(diff); - bool hasVictim = UpdateVictim(); + UpdateVictim(); GetScript()->OnUpdate(diff); UpdatePath(diff); UpdateFollow(diff); UpdateDespawn(diff); - - if (!IsAIControlled()) - return; - - if (!hasVictim) - return; - - DoMeleeAttackIfReady(); } bool SmartAI::IsEscortInvokerInRange() diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index f690c8e7727..86a31159b61 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -852,6 +852,8 @@ void Creature::Update(uint32 diff) Unit::AIUpdateTick(diff); + DoMeleeAttackIfReady(); + // 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()) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 642d377d7dd..908f2c56863 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -235,8 +235,6 @@ Player::Player(WorldSession* session) : Unit(true), m_sceneMgr(this) m_deathTimer = 0; m_deathExpireTime = 0; - m_swingErrorMsg = 0; - for (uint8 j = 0; j < PLAYER_MAX_BATTLEGROUND_QUEUES; ++j) { m_bgBattlegroundQueueID[j].bgQueueTypeId = BATTLEGROUND_QUEUE_NONE; @@ -1011,78 +1009,7 @@ void Player::Update(uint32 p_time) m_achievementMgr->UpdateTimedCriteria(Milliseconds(p_time)); - if (HasUnitState(UNIT_STATE_MELEE_ATTACKING) && !HasUnitState(UNIT_STATE_CASTING | UNIT_STATE_CHARGING)) - { - if (Unit* victim = GetVictim()) - { - // default combat reach 10 - /// @todo add weapon, skill check - - if (isAttackReady(BASE_ATTACK)) - { - if (!IsWithinMeleeRange(victim)) - { - setAttackTimer(BASE_ATTACK, 100); - if (m_swingErrorMsg != 1) // send single time (client auto repeat) - { - SendAttackSwingNotInRange(); - m_swingErrorMsg = 1; - } - } - //120 degrees of radiant range, if player is not in boundary radius - else if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim)) - { - setAttackTimer(BASE_ATTACK, 100); - if (m_swingErrorMsg != 2) // send single time (client auto repeat) - { - SendAttackSwingBadFacingAttack(); - m_swingErrorMsg = 2; - } - } - else - { - m_swingErrorMsg = 0; // reset swing error state - - // prevent base and off attack in same time, delay attack at 0.2 sec - if (haveOffhandWeapon()) - if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY) - setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY); - - // do attack - AttackerStateUpdate(victim, BASE_ATTACK); - resetAttackTimer(BASE_ATTACK); - } - } - - if (!IsInFeralForm() && haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) - { - if (!IsWithinMeleeRange(victim)) - setAttackTimer(OFF_ATTACK, 100); - else if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim)) - { - setAttackTimer(BASE_ATTACK, 100); - } - else - { - // prevent base and off attack in same time, delay attack at 0.2 sec - if (getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY) - setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY); - - // do attack - AttackerStateUpdate(victim, OFF_ATTACK); - resetAttackTimer(OFF_ATTACK); - } - } - - /*Unit* owner = victim->GetOwner(); - Unit* u = owner ? owner : victim; - if (u->IsPvP() && (!duel || duel->opponent != u)) - { - UpdatePvP(true); - RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::PvPActive); - }*/ - } - } + DoMeleeAttackIfReady(); if (HasPlayerFlag(PLAYER_FLAGS_RESTING)) _restMgr->Update(now); @@ -21308,29 +21235,17 @@ void Player::SavePositionInDB(WorldLocation const& loc, uint16 zoneId, ObjectGui CharacterDatabase.ExecuteOrAppend(trans, stmt); } -void Player::SendAttackSwingCantAttack() const -{ - SendDirectMessage(WorldPackets::Combat::AttackSwingError(WorldPackets::Combat::AttackSwingError::CantAttack).Write()); -} - void Player::SendAttackSwingCancelAttack() const { SendDirectMessage(WorldPackets::Combat::CancelCombat().Write()); } -void Player::SendAttackSwingDeadTarget() const +void Player::SetAttackSwingError(Optional<AttackSwingErr> err) { - SendDirectMessage(WorldPackets::Combat::AttackSwingError(WorldPackets::Combat::AttackSwingError::DeadTarget).Write()); -} + if (err && err != m_swingErrorMsg) + SendDirectMessage(WorldPackets::Combat::AttackSwingError(*err).Write()); -void Player::SendAttackSwingNotInRange() const -{ - SendDirectMessage(WorldPackets::Combat::AttackSwingError(WorldPackets::Combat::AttackSwingError::NotInRange).Write()); -} - -void Player::SendAttackSwingBadFacingAttack() const -{ - SendDirectMessage(WorldPackets::Combat::AttackSwingError(WorldPackets::Combat::AttackSwingError::BadFacing).Write()); + m_swingErrorMsg = err; } void Player::SendAutoRepeatCancel(Unit* target) diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index e9be541a0e5..0dda39ea498 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2126,11 +2126,8 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> void DestroyForPlayer(Player* target) const override; // notifiers - void SendAttackSwingCantAttack() const; void SendAttackSwingCancelAttack() const; - void SendAttackSwingDeadTarget() const; - void SendAttackSwingNotInRange() const; - void SendAttackSwingBadFacingAttack() const; + void SetAttackSwingError(Optional<AttackSwingErr> err); void SendAutoRepeatCancel(Unit* target); void SendExplorationExperience(uint32 Area, uint32 Experience) const; @@ -3096,7 +3093,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> bool m_canBlock; bool m_canTitanGrip; uint32 m_titanGripPenaltySpellId; - uint8 m_swingErrorMsg; + Optional<AttackSwingErr> m_swingErrorMsg; // Social PlayerSocial* m_social; diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 368926acc5e..84273e7b8c2 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -407,8 +407,8 @@ Unit::~Unit() ASSERT(m_appliedAuras.empty()); ASSERT(m_ownedAuras.empty()); ASSERT(m_removedAuras.empty()); - ASSERT(m_gameObj.empty()); ASSERT(m_dynObj.empty()); + ASSERT(m_gameObj.empty()); ASSERT(m_areaTrigger.empty()); ASSERT(!m_unitMovedByMe || (m_unitMovedByMe == this)); ASSERT(!m_playerMovingMe || (m_playerMovingMe == this)); @@ -456,10 +456,10 @@ void Unit::Update(uint32 p_time) { if (uint32 base_att = getAttackTimer(BASE_ATTACK)) setAttackTimer(BASE_ATTACK, (p_time >= base_att ? 0 : base_att - p_time)); - if (uint32 ranged_att = getAttackTimer(RANGED_ATTACK)) - setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time)); if (uint32 off_att = getAttackTimer(OFF_ATTACK)) setAttackTimer(OFF_ATTACK, (p_time >= off_att ? 0 : off_att - p_time)); + if (uint32 ranged_att = getAttackTimer(RANGED_ATTACK)) + setAttackTimer(RANGED_ATTACK, (p_time >= ranged_att ? 0 : ranged_att - p_time)); } // update abilities available only for fraction of time @@ -2087,12 +2087,15 @@ void Unit::HandleEmoteCommand(Emote emoteId, Player* target /*=nullptr*/, Trinit } } -void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra) +void Unit::DoMeleeAttackIfReady() { - if (HasUnitFlag(UNIT_FLAG_PACIFIED)) + if (!HasUnitState(UNIT_STATE_MELEE_ATTACKING)) return; - if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra) + if (HasUnitState(UNIT_STATE_CHARGING)) + return; + + if (IsCreature() && !ToCreature()->CanMelee()) return; if (HasUnitState(UNIT_STATE_CASTING)) @@ -2102,6 +2105,69 @@ void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extr return; } + Unit* victim = GetVictim(); + if (!victim) + return; + + auto getAutoAttackError = [&]() -> Optional<AttackSwingErr> + { + if (!IsWithinMeleeRange(victim)) + return AttackSwingErr::NotInRange; + + //120 degrees of radiant range, if player is not in boundary radius + if (!IsWithinBoundaryRadius(victim) && !HasInArc(2 * float(M_PI) / 3, victim)) + return AttackSwingErr::BadFacing; + + return {}; + }; + + if (isAttackReady(BASE_ATTACK)) + { + Optional<AttackSwingErr> autoAttackError = getAutoAttackError(); + if (!autoAttackError) + { + // prevent base and off attack in same time, delay attack at 0.2 sec + if (haveOffhandWeapon()) + if (getAttackTimer(OFF_ATTACK) < ATTACK_DISPLAY_DELAY) + setAttackTimer(OFF_ATTACK, ATTACK_DISPLAY_DELAY); + + // do attack + AttackerStateUpdate(victim, BASE_ATTACK); + resetAttackTimer(BASE_ATTACK); + } + else + setAttackTimer(BASE_ATTACK, 100); + + if (Player* attackerPlayer = ToPlayer()) + attackerPlayer->SetAttackSwingError(autoAttackError); + } + + if (!IsInFeralForm() && haveOffhandWeapon() && isAttackReady(OFF_ATTACK)) + { + Optional<AttackSwingErr> autoAttackError = getAutoAttackError(); + if (!autoAttackError) + { + // prevent base and off attack in same time, delay attack at 0.2 sec + if (getAttackTimer(BASE_ATTACK) < ATTACK_DISPLAY_DELAY) + setAttackTimer(BASE_ATTACK, ATTACK_DISPLAY_DELAY); + + // do attack + AttackerStateUpdate(victim, OFF_ATTACK); + resetAttackTimer(OFF_ATTACK); + } + else + setAttackTimer(OFF_ATTACK, 100); + } +} + +void Unit::AttackerStateUpdate(Unit* victim, WeaponAttackType attType, bool extra) +{ + if (HasUnitFlag(UNIT_FLAG_PACIFIED)) + return; + + if (HasUnitState(UNIT_STATE_CANNOT_AUTOATTACK) && !extra) + return; + if (HasAuraType(SPELL_AURA_DISABLE_ATTACKING_EXCEPT_ABILITIES)) return; @@ -5070,7 +5136,7 @@ void Unit::_RegisterDynObject(DynamicObject* dynObj) void Unit::_UnregisterDynObject(DynamicObject* dynObj) { - m_dynObj.remove(dynObj); + std::erase(m_dynObj, dynObj); if (GetTypeId() == TYPEID_UNIT && IsAIEnabled()) ToCreature()->AI()->JustUnregisteredDynObject(dynObj); } @@ -5093,8 +5159,6 @@ std::vector<DynamicObject*> Unit::GetDynObjects(uint32 spellId) const void Unit::RemoveDynObject(uint32 spellId) { - if (m_dynObj.empty()) - return; for (DynObjectList::iterator i = m_dynObj.begin(); i != m_dynObj.end();) { DynamicObject* dynObj = *i; @@ -5111,7 +5175,7 @@ void Unit::RemoveDynObject(uint32 spellId) void Unit::RemoveAllDynObjects() { while (!m_dynObj.empty()) - m_dynObj.front()->Remove(); + m_dynObj.back()->Remove(); } GameObject* Unit::GetGameObject(uint32 spellId) const @@ -5598,14 +5662,8 @@ bool Unit::Attack(Unit* victim, bool meleeAttack) Creature* creature = ToCreature(); // creatures cannot attack while evading - if (creature) - { - if (creature->IsInEvadeMode()) - return false; - - if (!creature->CanMelee()) - meleeAttack = false; - } + if (creature && creature->IsInEvadeMode()) + return false; // nobody can attack GM in GM-mode if (victim->GetTypeId() == TYPEID_PLAYER) @@ -11022,7 +11080,6 @@ void Unit::SetControlled(bool apply, UnitState state) case UNIT_STATE_CONFUSED: if (!HasUnitState(UNIT_STATE_STUNNED)) { - ClearUnitState(UNIT_STATE_MELEE_ATTACKING); SendMeleeAttackStop(); // SendAutoRepeatCancel ? SetConfused(true); @@ -11031,7 +11088,6 @@ void Unit::SetControlled(bool apply, UnitState state) case UNIT_STATE_FLEEING: if (!HasUnitState(UNIT_STATE_STUNNED | UNIT_STATE_CONFUSED)) { - ClearUnitState(UNIT_STATE_MELEE_ATTACKING); SendMeleeAttackStop(); // SendAutoRepeatCancel ? SetFeared(true); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index 08beac15956..70124a92542 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -1053,7 +1053,8 @@ class TC_GAME_API Unit : public WorldObject void TriggerAurasProcOnEvent(ProcEventInfo& eventInfo, AuraApplicationProcContainer& procAuras); void HandleEmoteCommand(Emote emoteId, Player* target = nullptr, Trinity::IteratorPair<int32 const*> spellVisualKitIds = {}, int32 sequenceVariation = 0); - void AttackerStateUpdate (Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false); + void DoMeleeAttackIfReady(); + void AttackerStateUpdate(Unit* victim, WeaponAttackType attType = BASE_ATTACK, bool extra = false); void CalculateMeleeDamage(Unit* victim, CalcDamageInfo* damageInfo, WeaponAttackType attackType = BASE_ATTACK); void DealMeleeDamage(CalcDamageInfo* damageInfo, bool durabilityLoss); @@ -1957,7 +1958,7 @@ class TC_GAME_API Unit : public WorldObject int32 m_procDeep; // tracked for proc system correctness (what spells should proc what) int32 m_procChainLength; // tracked to protect against infinite proc loops (hard limit, will disallow procs even if they should happen) - typedef std::list<DynamicObject*> DynObjectList; + typedef std::vector<DynamicObject*> DynObjectList; DynObjectList m_dynObj; typedef std::list<GameObject*> GameObjectList; diff --git a/src/server/game/Entities/Unit/UnitDefines.h b/src/server/game/Entities/Unit/UnitDefines.h index 92d23e7a8a9..348a9f6d611 100644 --- a/src/server/game/Entities/Unit/UnitDefines.h +++ b/src/server/game/Entities/Unit/UnitDefines.h @@ -473,6 +473,14 @@ enum HitInfo HITINFO_FAKE_DAMAGE = 0x01000000 // enables damage animation even if no damage done, set only if no damage }; +enum class AttackSwingErr : uint8 +{ + NotInRange = 0, + BadFacing = 1, + CantAttack = 2, + DeadTarget = 3 +}; + #define MAX_DECLINED_NAME_CASES 5 struct TC_GAME_API DeclinedName diff --git a/src/server/game/Server/Packets/CombatPackets.cpp b/src/server/game/Server/Packets/CombatPackets.cpp index d662128556f..33dd2c9a64a 100644 --- a/src/server/game/Server/Packets/CombatPackets.cpp +++ b/src/server/game/Server/Packets/CombatPackets.cpp @@ -96,7 +96,7 @@ WorldPacket const* WorldPackets::Combat::AIReaction::Write() WorldPacket const* WorldPackets::Combat::AttackSwingError::Write() { - _worldPacket.WriteBits(Reason, 3); + _worldPacket.WriteBits(AsUnderlyingType(Reason), 3); _worldPacket.FlushBits(); return &_worldPacket; } diff --git a/src/server/game/Server/Packets/CombatPackets.h b/src/server/game/Server/Packets/CombatPackets.h index 4aaa57ceba9..27dc7ec44ad 100644 --- a/src/server/game/Server/Packets/CombatPackets.h +++ b/src/server/game/Server/Packets/CombatPackets.h @@ -20,6 +20,7 @@ #include "Packet.h" #include "ObjectGuid.h" +#include "UnitDefines.h" class Unit; enum Powers : int8; @@ -41,20 +42,12 @@ namespace WorldPackets class AttackSwingError final : public ServerPacket { public: - enum AttackSwingErr : uint8 - { - NotInRange = 0, - BadFacing = 1, - CantAttack = 2, - DeadTarget = 3 - }; - AttackSwingError() : ServerPacket(SMSG_ATTACK_SWING_ERROR, 4) { } AttackSwingError(AttackSwingErr reason) : ServerPacket(SMSG_ATTACK_SWING_ERROR, 4), Reason(reason) { } WorldPacket const* Write() override; - AttackSwingErr Reason = CantAttack; + AttackSwingErr Reason = AttackSwingErr::CantAttack; }; class AttackStop final : public ClientPacket |
