diff --git a/src/server/game/AI/CoreAI/PetAI.cpp b/src/server/game/AI/CoreAI/PetAI.cpp index 8416b5300a..0a35e19546 100644 --- a/src/server/game/AI/CoreAI/PetAI.cpp +++ b/src/server/game/AI/CoreAI/PetAI.cpp @@ -412,7 +412,7 @@ Unit* PetAI::SelectNextTarget(bool allowAutoSelect) const if (me->HasReactState(REACT_AGGRESSIVE) && allowAutoSelect) { if (!me->GetCharmInfo()->IsReturning() || me->GetCharmInfo()->IsFollowing() || me->GetCharmInfo()->IsAtStay()) - if (Unit* nearTarget = me->SelectNearestHostileUnitInAggroRange(true)) + if (Unit* nearTarget = me->SelectNearestHostileUnitInAggroRange(true, true)) return nearTarget; } @@ -445,7 +445,8 @@ void PetAI::HandleReturnMovement() me->GetCharmInfo()->GetStayPosition(x, y, z); ClearCharmInfoFlags(); me->GetCharmInfo()->SetIsReturning(true); - me->GetMotionMaster()->Clear(); + + me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE); me->GetMotionMaster()->MovePoint(me->GetGUID().GetCounter(), x, y, z); } } @@ -455,7 +456,7 @@ void PetAI::HandleReturnMovement() { ClearCharmInfoFlags(); me->GetCharmInfo()->SetIsReturning(true); - me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE); me->FollowTarget(me->GetCharmerOrOwner()); } } @@ -481,7 +482,7 @@ void PetAI::DoAttack(Unit* target, bool chase) bool oldCmdAttack = me->GetCharmInfo()->IsCommandAttack(); // This needs to be reset after other flags are cleared ClearCharmInfoFlags(); me->GetCharmInfo()->SetIsCommandAttack(oldCmdAttack); // For passive pets commanded to attack so they will use spells - me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE); float chaseDistance = me->GetPetChaseDistance(); @@ -494,26 +495,25 @@ void PetAI::DoAttack(Unit* target, bool chase) { ClearCharmInfoFlags(); me->GetCharmInfo()->SetIsAtStay(true); - me->GetMotionMaster()->Clear(); + me->GetMotionMaster()->Clear(MOTION_SLOT_ACTIVE); me->GetMotionMaster()->MoveIdle(); } } } -void PetAI::MovementInform(uint32 moveType, uint32 data) +void PetAI::MovementInform(uint32 type, uint32 id) { // Receives notification when pet reaches stay or follow owner - switch (moveType) + switch (type) { case POINT_MOTION_TYPE: { // Pet is returning to where stay was clicked. data should be // pet's GUIDLow since we set that as the waypoint ID - if (data == me->GetGUID().GetCounter() && me->GetCharmInfo()->IsReturning()) + if (id == me->GetGUID().GetCounter() && me->GetCharmInfo()->IsReturning()) { ClearCharmInfoFlags(); me->GetCharmInfo()->SetIsAtStay(true); - me->GetMotionMaster()->Clear(); me->GetMotionMaster()->MoveIdle(); } break; @@ -522,7 +522,7 @@ void PetAI::MovementInform(uint32 moveType, uint32 data) { // If data is owner's GUIDLow then we've reached follow point, // otherwise we're probably chasing a creature - if (me->GetCharmerOrOwner() && me->GetCharmInfo() && data == me->GetCharmerOrOwner()->GetGUID().GetCounter() && me->GetCharmInfo()->IsReturning()) + if (me->GetCharmerOrOwner() && me->GetCharmInfo() && id == me->GetCharmerOrOwner()->GetGUID().GetCounter() && me->GetCharmInfo()->IsReturning()) { ClearCharmInfoFlags(); me->GetCharmInfo()->SetIsFollowing(true); @@ -624,7 +624,7 @@ void PetAI::ReceiveEmote(Player* player, uint32 emote) void PetAI::OnCharmed(bool isNew) { - if (me->IsCharmed()) + if (!me->isPossessedByPlayer() && me->IsCharmed()) me->FollowTarget(me->GetCharmer()); CreatureAI::OnCharmed(isNew); diff --git a/src/server/game/AI/CoreAI/PetAI.h b/src/server/game/AI/CoreAI/PetAI.h index 2346b106ec..c7f339b528 100644 --- a/src/server/game/AI/CoreAI/PetAI.h +++ b/src/server/game/AI/CoreAI/PetAI.h @@ -38,11 +38,13 @@ class TC_GAME_API PetAI : public CreatureAI void KilledUnit(Unit* /*victim*/) override; void AttackStart(Unit* target) override; // only start attacking if not attacking something else already void _AttackStart(Unit* target); // always start attacking if possible - void MovementInform(uint32 moveType, uint32 data) override; + void MovementInform(uint32 type, uint32 id) override; void OwnerAttackedBy(Unit* attacker) override; void OwnerAttacked(Unit* target) override; void DamageTaken(Unit* attacker, uint32& /*damage*/) override { AttackStart(attacker); } void ReceiveEmote(Player* player, uint32 textEmote) override; + void JustEnteredCombat(Unit* who) override { EngagementStart(who); } + void JustExitedCombat() override { EngagementOver(); } void OnCharmed(bool isNew) override; // The following aren't used by the PetAI but need to be defined to override diff --git a/src/server/game/Entities/Creature/Creature.cpp b/src/server/game/Entities/Creature/Creature.cpp index 07baa3eecf..e324623b20 100644 --- a/src/server/game/Entities/Creature/Creature.cpp +++ b/src/server/game/Entities/Creature/Creature.cpp @@ -3010,14 +3010,14 @@ float Creature::GetAggroRange(Unit const* target) const return 0.0f; } -Unit* Creature::SelectNearestHostileUnitInAggroRange(bool useLOS) const +Unit* Creature::SelectNearestHostileUnitInAggroRange(bool useLOS, bool ignoreCivilians) const { // Selects nearest hostile target within creature's aggro range. Used primarily by // pets set to aggressive. Will not return neutral or friendly targets. Unit* target = nullptr; - Trinity::NearestHostileUnitInAggroRangeCheck u_check(this, useLOS); + Trinity::NearestHostileUnitInAggroRangeCheck u_check(this, useLOS, ignoreCivilians); Trinity::UnitSearcher searcher(this, target, u_check); Cell::VisitGridObjects(this, searcher, MAX_AGGRO_RADIUS); diff --git a/src/server/game/Entities/Creature/Creature.h b/src/server/game/Entities/Creature/Creature.h index 1c87a0ff57..fcb6a92a08 100644 --- a/src/server/game/Entities/Creature/Creature.h +++ b/src/server/game/Entities/Creature/Creature.h @@ -241,7 +241,7 @@ class TC_GAME_API Creature : public Unit, public GridObject, public Ma Unit* SelectNearestTarget(float dist = 0, bool playerOnly = false) const; Unit* SelectNearestTargetInAttackDistance(float dist = 0) const; - Unit* SelectNearestHostileUnitInAggroRange(bool useLOS = false) const; + Unit* SelectNearestHostileUnitInAggroRange(bool useLOS = false, bool ignoreCivilians = false) const; void DoFleeToGetAssistance(); void CallForHelp(float fRadius); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index 4d7ea57260..a4f52eefc9 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -13672,6 +13672,7 @@ void Unit::SetFacingTo(float ori, bool force) init.DisableTransportPathTransformations(); // It makes no sense to target global orientation init.SetFacing(ori); init.Launch(); + UpdateSplineMovement(1); } void Unit::SetFacingToObject(WorldObject const* object, bool force) @@ -13685,6 +13686,7 @@ void Unit::SetFacingToObject(WorldObject const* object, bool force) init.MoveTo(GetPositionX(), GetPositionY(), GetPositionZ(), false); init.SetFacing(GetAngle(object)); // when on transport, GetAngle will still return global coordinates (and angle) that needs transforming init.Launch(); + UpdateSplineMovement(1); } void Unit::SetFacingToPoint(Position const& point, bool force) @@ -13700,6 +13702,7 @@ void Unit::SetFacingToPoint(Position const& point, bool force) init.DisableTransportPathTransformations(); // It makes no sense to target global orientation init.SetFacing(point.GetPositionX(), point.GetPositionY(), point.GetPositionZ()); init.Launch(); + UpdateSplineMovement(1); } bool Unit::SetWalk(bool enable) diff --git a/src/server/game/Grids/Notifiers/GridNotifiers.h b/src/server/game/Grids/Notifiers/GridNotifiers.h index 7b695c557c..9016db11e4 100644 --- a/src/server/game/Grids/Notifiers/GridNotifiers.h +++ b/src/server/game/Grids/Notifiers/GridNotifiers.h @@ -1217,9 +1217,10 @@ namespace Trinity class NearestHostileUnitInAggroRangeCheck { public: - explicit NearestHostileUnitInAggroRangeCheck(Creature const* creature, bool useLOS = false) : _me(creature), _useLOS(useLOS) + explicit NearestHostileUnitInAggroRangeCheck(Creature const* creature, bool useLOS = false, bool ignoreCivilians = false) : _me(creature), _useLOS(useLOS), _ignoreCivilians(ignoreCivilians) { } + bool operator()(Unit* u) { if (!u->IsHostileTo(_me)) @@ -1234,12 +1235,19 @@ namespace Trinity if (_useLOS && !u->IsWithinLOSInMap(_me)) return false; + // pets in aggressive do not attack civilians + if (_ignoreCivilians) + if (Creature* c = u->ToCreature()) + if (c->IsCivilian()) + return false; + return true; } private: Creature const* _me; bool _useLOS; + bool _ignoreCivilians; NearestHostileUnitInAggroRangeCheck(NearestHostileUnitInAggroRangeCheck const&); }; diff --git a/src/server/game/Spells/Spell.cpp b/src/server/game/Spells/Spell.cpp index bacf32bf80..261b8f12ed 100644 --- a/src/server/game/Spells/Spell.cpp +++ b/src/server/game/Spells/Spell.cpp @@ -3434,7 +3434,7 @@ SpellCastResult Spell::prepare(SpellCastTargets const& targets, AuraEffect const { // stealth must be removed at cast starting (at show channel bar) // skip triggered spell (item equip spell casting and other not explicit character casts/item uses) - if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_AN_ACTION)) + if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_AN_ACTION)) unitCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::Action, m_spellInfo); unitCaster->SetCurrentCastSpell(this); @@ -3792,7 +3792,7 @@ void Spell::_cast(bool skipCheck) if (!(hitMask & PROC_HIT_CRITICAL)) hitMask |= PROC_HIT_NORMAL; - if (!(_triggeredCastFlags & TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_AN_ACTION)) + if (!(_triggeredCastFlags & TRIGGERED_IGNORE_CAST_IN_PROGRESS) && !m_spellInfo->HasAttribute(SPELL_ATTR2_NOT_AN_ACTION)) m_originalCaster->RemoveAurasWithInterruptFlags(SpellAuraInterruptFlags::ActionDelayed, m_spellInfo); Unit::ProcSkillsAndAuras(m_originalCaster, nullptr, procAttacker, PROC_FLAG_NONE, PROC_SPELL_TYPE_MASK_ALL, PROC_SPELL_PHASE_CAST, hitMask, this, nullptr, nullptr); @@ -4093,7 +4093,7 @@ void Spell::update(uint32 difftime) // if charmed by creature, trust the AI not to cheat and allow the cast to proceed // @todo this is a hack, "creature" movesplines don't differentiate turning/moving right now // however, checking what type of movement the spline is for every single spline would be really expensive - if (!m_caster->ToUnit()->GetCharmerGUID().IsCreature()) + if (!m_caster->ToUnit()->IsControlledByPlayer()) cancel(); } diff --git a/src/server/game/Spells/SpellDefines.h b/src/server/game/Spells/SpellDefines.h index e904c40125..b2f533b7b0 100644 --- a/src/server/game/Spells/SpellDefines.h +++ b/src/server/game/Spells/SpellDefines.h @@ -171,7 +171,7 @@ enum TriggerCastFlags : uint32 TRIGGERED_IGNORE_CAST_IN_PROGRESS = 0x00000020, //! Will not check if a current cast is in progress TRIGGERED_IGNORE_COMBO_POINTS = 0x00000040, //! Will ignore combo point requirement TRIGGERED_CAST_DIRECTLY = 0x00000080, //! In Spell::prepare, will be cast directly without setting containers for executed spell - TRIGGERED_IGNORE_AURA_INTERRUPT_FLAGS = 0x00000100, //! Will ignore interruptible aura's at cast + // reuse = 0x00000100, TRIGGERED_IGNORE_SET_FACING = 0x00000200, //! Will not adjust facing to target (if any) TRIGGERED_IGNORE_SHAPESHIFT = 0x00000400, //! Will ignore shapeshift checks TRIGGERED_IGNORE_CASTER_AURASTATE = 0x00000800, //! Will ignore caster aura states including combat requirements and death state