@@ -190,7 +190,7 @@ public bool TargetHasStealth(Entity target)
190190 }
191191
192192 //Targeting
193- public void AssignTarget ( Entity en )
193+ public void AssignTarget ( Entity ? en )
194194 {
195195 var oldTarget = Target ;
196196
@@ -199,16 +199,7 @@ public void AssignTarget(Entity en)
199199 if ( AggroCenterMap != null && pathTarget != null &&
200200 pathTarget . TargetMapId == AggroCenterMap . Id && pathTarget . TargetX == AggroCenterX && pathTarget . TargetY == AggroCenterY )
201201 {
202- if ( en == null )
203- {
204- return ;
205-
206- }
207- else
208- {
209- return ;
210-
211- }
202+ return ;
212203 }
213204
214205 //Why are we doing all of this logic if we are assigning a target that we already have?
@@ -229,7 +220,7 @@ public void AssignTarget(Entity en)
229220
230221 if ( en is Projectile projectile )
231222 {
232- if ( projectile . Owner != this && ! TargetHasStealth ( projectile ) )
223+ if ( projectile . Owner != this && ! projectile . HasStatusEffect ( SpellEffect . Stealth ) )
233224 {
234225 Target = projectile . Owner ;
235226 }
@@ -246,21 +237,17 @@ public void AssignTarget(Entity en)
246237 }
247238 }
248239 }
249-
250- if ( en is Player )
240+ else if ( en is Player player )
251241 {
252242 //TODO Make sure that the npc can target the player
253- if ( this != en && ! TargetHasStealth ( en ) )
243+ if ( CanTarget ( player ) )
254244 {
255- Target = en ;
245+ Target = player ;
256246 }
257247 }
258- else
248+ else if ( CanTarget ( en ) )
259249 {
260- if ( this != en && ! TargetHasStealth ( en ) )
261- {
262- Target = en ;
263- }
250+ Target = en ;
264251 }
265252 }
266253
@@ -331,8 +318,20 @@ public override bool CanAttack(Entity entity, SpellBase spell)
331318 }
332319 }
333320
334- if ( TargetHasStealth ( entity ) )
321+ if ( entity . HasStatusEffect ( SpellEffect . Stealth ) )
335322 {
323+ // if spell is area or projectile, we can attack without knowing the target location
324+ if ( spell ? . Combat is { TargetType : SpellTargetType . AoE or SpellTargetType . Projectile } )
325+ {
326+ return true ;
327+ }
328+
329+ // this is for handle aoe when target is single target, we can hit the target if it's in the radius
330+ if ( spell ? . Combat . TargetType == SpellTargetType . Single && spell . Combat . HitRadius > 0 && InRangeOf ( entity , spell . Combat . HitRadius ) )
331+ {
332+ return true ;
333+ }
334+
336335 return false ;
337336 }
338337
@@ -669,6 +668,12 @@ private void TryCastSpells()
669668 Log . Warn ( $ "Combat data missing for { spellBase . Id } .") ;
670669 }
671670
671+ //TODO: try cast spell to find out hidden targets?
672+ // if (target.HasStatusEffect(SpellEffect.Stealth) /* && spellBase.Combat.TargetType != SpellTargetType.AoE*/)
673+ // {
674+ // return;
675+ // }
676+
672677 // Check if we are even allowed to cast this spell.
673678 if ( ! CanCastSpell ( spellBase , target , true , out _ ) )
674679 {
@@ -775,11 +780,12 @@ public override void Update(long timeMs)
775780 {
776781 var curMapLink = MapId ;
777782 base . Update ( timeMs ) ;
783+
778784 var tempTarget = Target ;
779785
780786 foreach ( var status in CachedStatuses )
781787 {
782- if ( status . Type == SpellEffect . Stun || status . Type == SpellEffect . Sleep )
788+ if ( status . Type is SpellEffect . Stun or SpellEffect . Sleep )
783789 {
784790 return ;
785791 }
@@ -794,6 +800,12 @@ public override void Update(long timeMs)
794800 var targetY = 0 ;
795801 var targetZ = 0 ;
796802
803+ if ( tempTarget != null && ( tempTarget . IsDead ( ) || ! InRangeOf ( tempTarget , Options . MapWidth * 2 ) || ! CanTarget ( tempTarget ) ) )
804+ {
805+ _ = TryFindNewTarget ( Timing . Global . Milliseconds , tempTarget . Id , ! CanTarget ( tempTarget ) ) ;
806+ tempTarget = Target ;
807+ }
808+
797809 //TODO Clear Damage Map if out of combat (target is null and combat timer is to the point that regen has started)
798810 if ( tempTarget != null && ( Options . Instance . NpcOpts . ResetIfCombatTimerExceeded && Timing . Global . Milliseconds > CombatTimer ) )
799811 {
@@ -803,6 +815,7 @@ public override void Update(long timeMs)
803815 {
804816 PacketSender . SendNpcAggressionToProximity ( this ) ;
805817 }
818+
806819 return ;
807820 }
808821 }
@@ -836,34 +849,17 @@ public override void Update(long timeMs)
836849 mResetDistance = 0 ;
837850 }
838851 }
839-
840- }
841-
842- if ( tempTarget != null && ( tempTarget . IsDead ( ) || ! InRangeOf ( tempTarget , Options . MapWidth * 2 ) ) )
843- {
844- TryFindNewTarget ( Timing . Global . Milliseconds , tempTarget . Id ) ;
845- tempTarget = Target ;
846852 }
847853
848854 //Check if there is a target, if so, run their ass down.
849- if ( tempTarget != null )
855+ if ( tempTarget != null && CanTarget ( tempTarget ) )
850856 {
851857 if ( ! tempTarget . IsDead ( ) && CanAttack ( tempTarget , null ) )
852858 {
853859 targetMap = tempTarget . MapId ;
854860 targetX = tempTarget . X ;
855861 targetY = tempTarget . Y ;
856862 targetZ = tempTarget . Z ;
857- foreach ( var targetStatus in tempTarget . CachedStatuses )
858- {
859- if ( targetStatus . Type == SpellEffect . Stealth )
860- {
861- targetMap = Guid . Empty ;
862- targetX = 0 ;
863- targetY = 0 ;
864- targetZ = 0 ;
865- }
866- }
867863 }
868864 }
869865 else //Find a target if able
@@ -910,7 +906,7 @@ public override void Update(long timeMs)
910906 {
911907 mPathFinder . SetTarget ( new PathfinderTarget ( targetMap , targetX , targetY , targetZ ) ) ;
912908
913- if ( tempTarget != Target )
909+ if ( tempTarget != null && tempTarget != Target )
914910 {
915911 tempTarget = Target ;
916912 }
@@ -1378,11 +1374,11 @@ public bool ShouldAttackPlayerOnSight(Player en)
13781374 return false ;
13791375 }
13801376
1381- public void TryFindNewTarget ( long timeMs , Guid avoidId = new Guid ( ) , bool ignoreTimer = false , Entity attackedBy = null )
1377+ public bool TryFindNewTarget ( long timeMs , Guid avoidId = new ( ) , bool ignoreTimer = false , Entity attackedBy = null )
13821378 {
13831379 if ( ! ignoreTimer && FindTargetWaitTime > timeMs )
13841380 {
1385- return ;
1381+ return false ;
13861382 }
13871383
13881384 // Are we resetting? If so, do not allow for a new target.
@@ -1392,16 +1388,14 @@ public bool ShouldAttackPlayerOnSight(Player en)
13921388 {
13931389 if ( ! Options . Instance . NpcOpts . AllowEngagingWhileResetting || attackedBy == null || attackedBy . GetDistanceTo ( AggroCenterMap , AggroCenterX , AggroCenterY ) > Math . Max ( Options . Instance . NpcOpts . ResetRadius , Base . ResetRadius ) )
13941390 {
1395- return ;
1396- }
1397- else
1398- {
1399- //We're resetting and just got attacked, and we allow reengagement.. let's stop resetting and fight!
1400- mPathFinder ? . SetTarget ( null ) ;
1401- mResetting = false ;
1402- AssignTarget ( attackedBy ) ;
1403- return ;
1391+ return false ;
14041392 }
1393+
1394+ //We're resetting and just got attacked, and we allow reengagement.. let's stop resetting and fight!
1395+ mPathFinder ? . SetTarget ( null ) ;
1396+ mResetting = false ;
1397+ AssignTarget ( attackedBy ) ;
1398+ return true ;
14051399 }
14061400
14071401 var possibleTargets = new List < Entity > ( ) ;
@@ -1538,9 +1532,12 @@ public bool ShouldAttackPlayerOnSight(Player en)
15381532 {
15391533 CheckForResetLocation ( true ) ;
15401534 }
1535+
1536+ AssignTarget ( null ) ;
15411537 }
15421538
15431539 FindTargetWaitTime = timeMs + FindTargetDelay ;
1540+ return Target != null ;
15441541 }
15451542
15461543 public override void ProcessRegen ( )
0 commit comments