Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion Intersect.Server.Core/Entities/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public abstract partial class Entity : IEntity
public IReadOnlyDictionary<Vital, long> VitalsLookup => _vitals.Select((value, index) => (value, index))
.ToDictionary(t => (Vital)t.index, t => t.value).AsReadOnly();

[NotMapped, JsonIgnore] public Entity Target { get; set; } = null;
[NotMapped, JsonIgnore] public Entity? Target { get; set; }

public Entity() : this(Guid.NewGuid(), Guid.Empty)
{
Expand Down Expand Up @@ -318,6 +318,8 @@ public virtual void Dispose()
}
}

public bool HasStatusEffect(SpellEffect spellEffect) => CachedStatuses.Any(s => s.Type == spellEffect);

public virtual void Update(long timeMs)
{
var lockObtained = false;
Expand Down Expand Up @@ -1408,6 +1410,24 @@ public virtual int GetWeaponDamage()

public virtual bool CanAttack(Entity entity, SpellBase spell) => !IsCasting;

public virtual bool CanTarget(Entity? entity)
{
if (entity == null)
{
// If it's not an entity we can't target it
return false;
}

if (IsAllyOf(entity))
{
// If it's an ally we can always target them
return true;
}

// If it's not an ally we can't target it if it's stealthed
return !entity.HasStatusEffect(SpellEffect.Stealth);
}

public virtual void ProcessRegen()
{
}
Expand Down Expand Up @@ -2922,6 +2942,11 @@ protected Direction DirectionToTarget(Entity en)
return Dir;
}

if (en.CachedStatuses.Any(status => status.Type == SpellEffect.Stealth))
{
return Dir;
}

if (!MapController.TryGet(MapId, out var originMapController) ||
!MapController.TryGet(en.MapId, out var targetMapController))
{
Expand Down
103 changes: 50 additions & 53 deletions Intersect.Server.Core/Entities/Npc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public bool TargetHasStealth(Entity target)
}

//Targeting
public void AssignTarget(Entity en)
public void AssignTarget(Entity? en)
{
var oldTarget = Target;

Expand All @@ -199,16 +199,7 @@ public void AssignTarget(Entity en)
if (AggroCenterMap != null && pathTarget != null &&
pathTarget.TargetMapId == AggroCenterMap.Id && pathTarget.TargetX == AggroCenterX && pathTarget.TargetY == AggroCenterY)
{
if (en == null)
{
return;

}
else
{
return;

}
return;
}

//Why are we doing all of this logic if we are assigning a target that we already have?
Expand All @@ -229,7 +220,7 @@ public void AssignTarget(Entity en)

if (en is Projectile projectile)
{
if (projectile.Owner != this && !TargetHasStealth(projectile))
if (projectile.Owner != this && !projectile.HasStatusEffect(SpellEffect.Stealth))
{
Target = projectile.Owner;
}
Expand All @@ -246,21 +237,17 @@ public void AssignTarget(Entity en)
}
}
}

if (en is Player)
else if (en is Player player)
{
//TODO Make sure that the npc can target the player
if (this != en && !TargetHasStealth(en))
if (CanTarget(player))
{
Target = en;
Target = player;
}
}
else
else if (CanTarget(en))
{
if (this != en && !TargetHasStealth(en))
{
Target = en;
}
Target = en;
}
}

Expand Down Expand Up @@ -331,8 +318,20 @@ public override bool CanAttack(Entity entity, SpellBase spell)
}
}

if (TargetHasStealth(entity))
if (entity.HasStatusEffect(SpellEffect.Stealth))
{
// if spell is area or projectile, we can attack without knowing the target location
if (spell?.Combat is { TargetType: SpellTargetType.AoE or SpellTargetType.Projectile })
{
return true;
}

// this is for handle aoe when target is single target, we can hit the target if it's in the radius
if (spell?.Combat.TargetType == SpellTargetType.Single && spell.Combat.HitRadius > 0 && InRangeOf(entity, spell.Combat.HitRadius))
{
return true;
}

return false;
}

Expand Down Expand Up @@ -669,6 +668,12 @@ private void TryCastSpells()
Log.Warn($"Combat data missing for {spellBase.Id}.");
}

//TODO: try cast spell to find out hidden targets?
// if (target.HasStatusEffect(SpellEffect.Stealth) /* && spellBase.Combat.TargetType != SpellTargetType.AoE*/)
// {
// return;
// }

// Check if we are even allowed to cast this spell.
if (!CanCastSpell(spellBase, target, true, out _))
{
Expand Down Expand Up @@ -775,11 +780,12 @@ public override void Update(long timeMs)
{
var curMapLink = MapId;
base.Update(timeMs);

var tempTarget = Target;

foreach (var status in CachedStatuses)
{
if (status.Type == SpellEffect.Stun || status.Type == SpellEffect.Sleep)
if (status.Type is SpellEffect.Stun or SpellEffect.Sleep)
{
return;
}
Expand All @@ -794,6 +800,12 @@ public override void Update(long timeMs)
var targetY = 0;
var targetZ = 0;

if (tempTarget != null && (tempTarget.IsDead() || !InRangeOf(tempTarget, Options.MapWidth * 2) || !CanTarget(tempTarget)))
{
_ = TryFindNewTarget(Timing.Global.Milliseconds, tempTarget.Id, !CanTarget(tempTarget));
tempTarget = Target;
}

//TODO Clear Damage Map if out of combat (target is null and combat timer is to the point that regen has started)
if (tempTarget != null && (Options.Instance.NpcOpts.ResetIfCombatTimerExceeded && Timing.Global.Milliseconds > CombatTimer))
{
Expand All @@ -803,6 +815,7 @@ public override void Update(long timeMs)
{
PacketSender.SendNpcAggressionToProximity(this);
}

return;
}
}
Expand Down Expand Up @@ -836,34 +849,17 @@ public override void Update(long timeMs)
mResetDistance = 0;
}
}

}

if (tempTarget != null && (tempTarget.IsDead() || !InRangeOf(tempTarget, Options.MapWidth * 2)))
{
TryFindNewTarget(Timing.Global.Milliseconds, tempTarget.Id);
tempTarget = Target;
}

//Check if there is a target, if so, run their ass down.
if (tempTarget != null)
if (tempTarget != null && CanTarget(tempTarget))
{
if (!tempTarget.IsDead() && CanAttack(tempTarget, null))
{
targetMap = tempTarget.MapId;
targetX = tempTarget.X;
targetY = tempTarget.Y;
targetZ = tempTarget.Z;
foreach (var targetStatus in tempTarget.CachedStatuses)
{
if (targetStatus.Type == SpellEffect.Stealth)
{
targetMap = Guid.Empty;
targetX = 0;
targetY = 0;
targetZ = 0;
}
}
}
}
else //Find a target if able
Expand Down Expand Up @@ -910,7 +906,7 @@ public override void Update(long timeMs)
{
mPathFinder.SetTarget(new PathfinderTarget(targetMap, targetX, targetY, targetZ));

if (tempTarget != Target)
if (tempTarget != null && tempTarget != Target)
{
tempTarget = Target;
}
Expand Down Expand Up @@ -1378,11 +1374,11 @@ public bool ShouldAttackPlayerOnSight(Player en)
return false;
}

public void TryFindNewTarget(long timeMs, Guid avoidId = new Guid(), bool ignoreTimer = false, Entity attackedBy = null)
public bool TryFindNewTarget(long timeMs, Guid avoidId = new(), bool ignoreTimer = false, Entity attackedBy = null)
{
if (!ignoreTimer && FindTargetWaitTime > timeMs)
{
return;
return false;
}

// Are we resetting? If so, do not allow for a new target.
Expand All @@ -1392,16 +1388,14 @@ public bool ShouldAttackPlayerOnSight(Player en)
{
if (!Options.Instance.NpcOpts.AllowEngagingWhileResetting || attackedBy == null || attackedBy.GetDistanceTo(AggroCenterMap, AggroCenterX, AggroCenterY) > Math.Max(Options.Instance.NpcOpts.ResetRadius, Base.ResetRadius))
{
return;
}
else
{
//We're resetting and just got attacked, and we allow reengagement.. let's stop resetting and fight!
mPathFinder?.SetTarget(null);
mResetting = false;
AssignTarget(attackedBy);
return;
return false;
}

//We're resetting and just got attacked, and we allow reengagement.. let's stop resetting and fight!
mPathFinder?.SetTarget(null);
mResetting = false;
AssignTarget(attackedBy);
return true;
}

var possibleTargets = new List<Entity>();
Expand Down Expand Up @@ -1538,9 +1532,12 @@ public bool ShouldAttackPlayerOnSight(Player en)
{
CheckForResetLocation(true);
}

AssignTarget(null);
}

FindTargetWaitTime = timeMs + FindTargetDelay;
return Target != null;
}

public override void ProcessRegen()
Expand Down
Loading