Core/Creatures: Implemented CREATURE_STATIC_FLAG_4_NO_MELEE_APPROACH and fixed CREATURE_STATIC_FLAG_NO_MELEE_FLEE implementation (should cause fleeing from melee range)

Port From (https://github.com/TrinityCore/TrinityCore/commit/a748fddfa47216e1f516303e3bca9b5a86823748)
This commit is contained in:
hondacrx
2024-02-24 15:18:07 -05:00
parent dab3a891a7
commit 9d1589afd4
10 changed files with 93 additions and 34 deletions
+2 -2
View File
@@ -290,7 +290,7 @@ namespace Framework.Constants
CombatPing = 0x00020000, CombatPing = 0x00020000,
Aquatic = 0x00040000, // Aka Water Only, CreatureTemplateMovement.Ground = 0 Aquatic = 0x00040000, // Aka Water Only, CreatureTemplateMovement.Ground = 0
Amphibious = 0x00080000, // CreatureTemplateMovement.Swim = 1 Amphibious = 0x00080000, // CreatureTemplateMovement.Swim = 1
NoMelee = 0x00100000, // Prevents Melee(Does Not Prevent Chasing, Does Not Make Creature Passive). Not Sure What 'Flee' Means But Another Flag Is Named NoMeleeApproach NoMeleeFlee = 0x00100000, // "No Melee (Flee)" Prevents melee (moves as-if feared, does not make creature passive)
VisibleToGhosts = 0x00200000, // CreatureTypeFlagVisibleToGhosts VisibleToGhosts = 0x00200000, // CreatureTypeFlagVisibleToGhosts
PvpEnabling = 0x00400000, // Old UnitFlagPvpEnabling, Now UnitBytes2OffsetPvpFlag From UnitFieldBytes2 PvpEnabling = 0x00400000, // Old UnitFlagPvpEnabling, Now UnitBytes2OffsetPvpFlag From UnitFieldBytes2
DoNotPlayWoundAnim = 0x00800000, // CreatureTypeFlagDoNotPlayWoundAnim DoNotPlayWoundAnim = 0x00800000, // CreatureTypeFlagDoNotPlayWoundAnim
@@ -390,7 +390,7 @@ namespace Framework.Constants
DealsTripleDamageToPcControlledPets = 0x00000040, DealsTripleDamageToPcControlledPets = 0x00000040,
NoNpcDamageBelow85ptc = 0x00000080, NoNpcDamageBelow85ptc = 0x00000080,
ObeysTauntDiminishingReturns = 0x00000100, // CreatureFlagExtraObeysTauntDiminishingReturns ObeysTauntDiminishingReturns = 0x00000100, // CreatureFlagExtraObeysTauntDiminishingReturns
NoMeleeApproach = 0x00000200, NoMeleeApproach = 0x00000200, // "No Melee (Approach)" Prevents melee (chases into melee range, does not make creature passive)
UpdateCreatureRecordWhenInstanceChangesDifficulty = 0x00000400, // Used Only By Snobold Vassal UpdateCreatureRecordWhenInstanceChangesDifficulty = 0x00000400, // Used Only By Snobold Vassal
CannotDaze = 0x00000800, // "Cannot Daze (Combat Stun)" CannotDaze = 0x00000800, // "Cannot Daze (Combat Stun)"
FlatHonorAward = 0x00001000, FlatHonorAward = 0x00001000,
+17 -2
View File
@@ -27,9 +27,9 @@ namespace Game.AI
protected TaskScheduler _scheduler = new(); protected TaskScheduler _scheduler = new();
protected InstanceScript _instanceScript; protected InstanceScript _instanceScript;
public CreatureAI(Creature _creature) : base(_creature) public CreatureAI(Creature creature) : base(creature)
{ {
me = _creature; me = creature;
_moveInLOSLocked = false; _moveInLOSLocked = false;
} }
@@ -514,6 +514,21 @@ namespace Game.AI
// called when the corpse of this creature gets removed // called when the corpse of this creature gets removed
public virtual void CorpseRemoved(long respawnDelay) { } public virtual void CorpseRemoved(long respawnDelay) { }
public override void AttackStart(Unit victim)
{
if (victim != null && me.Attack(victim, true))
{
// Clear distracted state on attacking
if (me.HasUnitState(UnitState.Distracted))
{
me.ClearUnitState(UnitState.Distracted);
me.GetMotionMaster().Clear();
}
me.StartDefaultCombatMovement(victim);
}
}
/// == Gossip system ================================ /// == Gossip system ================================
// Called when the dialog status between a player and the creature is requested. // Called when the dialog status between a player and the creature is requested.
+20 -13
View File
@@ -4,6 +4,7 @@
using Framework.Constants; using Framework.Constants;
using Game.Entities; using Game.Entities;
using Game.Spells; using Game.Spells;
using System;
namespace Game.AI namespace Game.AI
{ {
@@ -92,28 +93,34 @@ namespace Game.AI
public class CritterAI : PassiveAI public class CritterAI : PassiveAI
{ {
public CritterAI(Creature c) : base(c) TimeTracker _evadeTimer;
public CritterAI(Creature creature) : base(creature)
{ {
me.SetReactState(ReactStates.Passive); _evadeTimer = new();
me.SetCanMelee(false, true);
} }
public override void JustEngagedWith(Unit who) public override void JustEngagedWith(Unit who)
{ {
if (!me.HasUnitState(UnitState.Fleeing)) me.StartDefaultCombatMovement(who);
me.SetControlled(true, UnitState.Fleeing); _evadeTimer.Reset(TimeSpan.FromMilliseconds(WorldConfig.GetIntValue(WorldCfg.CreatureFamilyFleeDelay)));
} }
public override void MovementInform(MovementGeneratorType type, uint id) public override void UpdateAI(uint diff)
{ {
if (type == MovementGeneratorType.TimedFleeing) if (me.IsEngaged())
EnterEvadeMode(EvadeReason.Other); {
} if (!me.IsInCombat())
{
EnterEvadeMode(EvadeReason.NoHostiles);
return;
}
public override void EnterEvadeMode(EvadeReason why) _evadeTimer.Update(diff);
{ if (_evadeTimer.Passed())
if (me.HasUnitState(UnitState.Fleeing)) EnterEvadeMode(EvadeReason.Other);
me.SetControlled(false, UnitState.Fleeing); }
base.EnterEvadeMode(why);
} }
} }
+1 -1
View File
@@ -52,7 +52,7 @@ namespace Game.AI
public void DoStartMovement(Unit target, float distance = 0.0f, float angle = 0.0f) public void DoStartMovement(Unit target, float distance = 0.0f, float angle = 0.0f)
{ {
if (target != null) if (target != null)
me.GetMotionMaster().MoveChase(target, distance, angle); me.StartDefaultCombatMovement(target, distance, angle);
} }
//Start no movement on victim //Start no movement on victim
+2 -2
View File
@@ -618,7 +618,7 @@ namespace Game.AI
if (_canCombatMove) if (_canCombatMove)
{ {
SetRun(_run); SetRun(_run);
me.GetMotionMaster().MoveChase(who); me.StartDefaultCombatMovement(who);
} }
} }
} }
@@ -830,7 +830,7 @@ namespace Game.AI
})) }))
{ {
SetRun(_run); SetRun(_run);
me.GetMotionMaster().MoveChase(me.GetVictim()); me.StartDefaultCombatMovement(me.GetVictim());
} }
} }
else else
+1 -1
View File
@@ -1515,7 +1515,7 @@ namespace Game.AI
if (creature != null) if (creature != null)
if (IsSmart(creature) && creature.GetVictim() != null) if (IsSmart(creature) && creature.GetVictim() != null)
if (((SmartAI)creature.GetAI()).CanCombatMove()) if (((SmartAI)creature.GetAI()).CanCombatMove())
creature.GetMotionMaster().MoveChase(creature.GetVictim(), attackDistance, attackAngle); creature.StartDefaultCombatMovement(creature.GetVictim(), attackDistance, attackAngle);
} }
break; break;
} }
+42 -3
View File
@@ -2602,6 +2602,47 @@ namespace Game.Entities
Global.WorldMgr.SendGlobalMessage(packet, null, (enemy_team == Team.Alliance ? Team.Horde : Team.Alliance)); Global.WorldMgr.SendGlobalMessage(packet, null, (enemy_team == Team.Alliance ? Team.Horde : Team.Alliance));
} }
public void SetCanMelee(bool canMelee, bool fleeFromMelee = false)
{
bool wasFleeingFromMelee = HasFlag(CreatureStaticFlags.NoMeleeFlee);
_staticFlags.ApplyFlag(CreatureStaticFlags.NoMeleeFlee, !canMelee && fleeFromMelee);
_staticFlags.ApplyFlag(CreatureStaticFlags4.NoMeleeApproach, !canMelee && !fleeFromMelee);
if (wasFleeingFromMelee == HasFlag(CreatureStaticFlags.NoMeleeFlee))
return;
Unit victim = GetVictim();
if (victim == null)
return;
var currentMovement = GetMotionMaster().GetCurrentMovementGenerator();
if (currentMovement == null)
return;
var canChangeMovement = new Func<bool>(() =>
{
if (wasFleeingFromMelee)
return currentMovement.GetMovementGeneratorType() == MovementGeneratorType.Fleeing && !HasUnitFlag(UnitFlags.Fleeing);
return currentMovement.GetMovementGeneratorType() == MovementGeneratorType.Chase;
})();
if (!canChangeMovement)
return;
GetMotionMaster().Remove(currentMovement);
StartDefaultCombatMovement(victim);
}
public void StartDefaultCombatMovement(Unit victim, float? range = null, float? angle = null)
{
if (!HasFlag(CreatureStaticFlags.NoMeleeFlee) || IsSummon())
GetMotionMaster().MoveChase(victim, range.GetValueOrDefault(0), angle.GetValueOrDefault(0));
else
GetMotionMaster().MoveFleeing(victim);
}
public override bool HasSpell(uint spellId) public override bool HasSpell(uint spellId)
{ {
return m_spells.Contains(spellId); return m_spells.Contains(spellId);
@@ -3376,9 +3417,7 @@ namespace Game.Entities
public override SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = WeaponAttackType.BaseAttack) { return m_meleeDamageSchoolMask; } public override SpellSchoolMask GetMeleeDamageSchoolMask(WeaponAttackType attackType = WeaponAttackType.BaseAttack) { return m_meleeDamageSchoolMask; }
public void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = (SpellSchoolMask)(1 << (int)school); } public void SetMeleeDamageSchool(SpellSchools school) { m_meleeDamageSchoolMask = (SpellSchoolMask)(1 << (int)school); }
public bool CanMelee() { return !_staticFlags.HasFlag(CreatureStaticFlags.NoMelee); } public bool CanMelee() { return !_staticFlags.HasFlag(CreatureStaticFlags.NoMeleeFlee) && !_staticFlags.HasFlag(CreatureStaticFlags4.NoMeleeApproach); }
public void SetCanMelee(bool canMelee) { _staticFlags.ApplyFlag(CreatureStaticFlags.NoMelee, !canMelee); }
public bool CanIgnoreLineOfSightWhenCastingOnMe() { return _staticFlags.HasFlag(CreatureStaticFlags4.IgnoreLosWhenCastingOnMe); } public bool CanIgnoreLineOfSightWhenCastingOnMe() { return _staticFlags.HasFlag(CreatureStaticFlags4.IgnoreLosWhenCastingOnMe); }
+5 -2
View File
@@ -1391,14 +1391,17 @@ namespace Game.Entities
if (caster == null) if (caster == null)
caster = GetAttackerForHelper(); caster = GetAttackerForHelper();
GetMotionMaster().MoveFleeing(caster, TimeSpan.FromMilliseconds(fearAuras.Empty() ? WorldConfig.GetIntValue(WorldCfg.CreatureFamilyFleeDelay) : 0)); // caster == NULL processed in MoveFleeing GetMotionMaster().MoveFleeing(caster, TimeSpan.FromMilliseconds(fearAuras.Empty() ? WorldConfig.GetIntValue(WorldCfg.CreatureFamilyFleeDelay) : 0)); // caster == NULL processed in MoveFleeing
SetUnitFlag(UnitFlags.Fleeing);
} }
else else
{ {
RemoveUnitFlag(UnitFlags.Fleeing);
if (IsAlive()) if (IsAlive())
{ {
GetMotionMaster().Remove(MovementGeneratorType.Fleeing); GetMotionMaster().Remove(MovementGeneratorType.Fleeing);
if (GetVictim() != null) Unit victim = GetVictim();
SetTarget(GetVictim().GetGUID()); if (victim != null)
SetTarget(victim.GetGUID());
if (!IsPlayer() && !IsInCombat()) if (!IsPlayer() && !IsInCombat())
GetMotionMaster().MoveTargetedHome(); GetMotionMaster().MoveTargetedHome();
} }
@@ -32,8 +32,6 @@ namespace Game.Movement
if (owner == null || !owner.IsAlive()) if (owner == null || !owner.IsAlive())
return; return;
// TODO: UNIT_FIELD_FLAGS should not be handled by generators
owner.SetUnitFlag(UnitFlags.Fleeing);
_path = null; _path = null;
SetTargetLocation(owner); SetTargetLocation(owner);
} }
@@ -83,16 +81,15 @@ namespace Game.Movement
{ {
if (owner.IsPlayer()) if (owner.IsPlayer())
{ {
owner.RemoveUnitFlag(UnitFlags.Fleeing);
owner.ClearUnitState(UnitState.FleeingMove); owner.ClearUnitState(UnitState.FleeingMove);
owner.StopMoving(); owner.StopMoving();
} }
else else
{ {
owner.RemoveUnitFlag(UnitFlags.Fleeing);
owner.ClearUnitState(UnitState.FleeingMove); owner.ClearUnitState(UnitState.FleeingMove);
if (owner.GetVictim() != null) Unit victim = owner.GetVictim();
owner.SetTarget(owner.GetVictim().GetGUID()); if (victim != null)
owner.SetTarget(victim.GetGUID());
} }
} }
} }
@@ -220,7 +217,6 @@ namespace Game.Movement
if (!active) if (!active)
return; return;
owner.RemoveUnitFlag(UnitFlags.Fleeing);
Unit victim = owner.GetVictim(); Unit victim = owner.GetVictim();
if (victim != null) if (victim != null)
{ {
-1
View File
@@ -563,7 +563,6 @@ namespace Game.Movement
} }
public void MoveChase(Unit target, float dist, float angle = 0.0f) { MoveChase(target, new ChaseRange(dist), new ChaseAngle(angle)); } public void MoveChase(Unit target, float dist, float angle = 0.0f) { MoveChase(target, new ChaseRange(dist), new ChaseAngle(angle)); }
public void MoveChase(Unit target, float dist) { MoveChase(target, new ChaseRange(dist)); }
public void MoveChase(Unit target, ChaseRange? dist = null, ChaseAngle? angle = null) public void MoveChase(Unit target, ChaseRange? dist = null, ChaseAngle? angle = null)
{ {
// Ignore movement request if target not exist // Ignore movement request if target not exist