@@ -63,40 +63,36 @@ private readonly List<IBattleChara> GetCanTargets(bool skipStatusProvideCheck, b
63
63
return [ ] ;
64
64
}
65
65
66
- List < IBattleChara > validTargets = [ ] ;
67
- foreach ( IBattleChara target in TargetHelper . GetTargetsByRange ( Range ) )
66
+ List < IBattleChara > validTargets = new ( TargetFilter . GetObjectInRadius ( DataCenter . AllTargets , Range ) . Count ( ) ) ;
67
+
68
+ foreach ( IBattleChara target in TargetFilter . GetObjectInRadius ( DataCenter . AllTargets , Range ) )
68
69
{
69
70
if ( type == TargetType . Heal && target . GetHealthRatio ( ) == 1 )
70
71
{
71
72
continue ;
72
73
}
73
74
74
- var statusCheck = CheckStatus ( target , skipStatusProvideCheck , skipTargetStatusNeedCheck ) ;
75
- var ttkCheck = CheckTimeToKill ( target ) ;
76
- var resistanceCheck = CheckResistance ( target ) ;
75
+ if ( ! GeneralCheck ( target , skipStatusProvideCheck , skipTargetStatusNeedCheck ) )
76
+ {
77
+ continue ;
78
+ }
79
+
80
+ validTargets . Add ( target ) ;
81
+ }
77
82
78
- if ( statusCheck && ttkCheck && resistanceCheck )
83
+ List < IBattleChara > result = [ ] ;
84
+ foreach ( IBattleChara b in validTargets )
85
+ {
86
+ if ( ! DataCenter . IsManual || IsTargetFriendly || b . GameObjectId == Svc . Targets . Target ? . GameObjectId || b . GameObjectId == Player . Object ? . GameObjectId )
79
87
{
80
- // If auto targeting is enabled
81
- // or the skill is friendly
82
- // or the target is the currently selected hard-target
83
- // or the target is ourselves
84
- // then => Check target is in the view && ActionManager.CanUse on target && CanSee Target && action.setting predicate is true of target
85
- if ( ! DataCenter . IsManual || IsTargetFriendly || target . GameObjectId == Svc . Targets . Target ? . GameObjectId || target . GameObjectId == Player . Object ? . GameObjectId )
88
+ if ( InViewTarget ( b ) && CanUseTo ( b ) && action . Setting . CanTarget ( b ) )
86
89
{
87
- var view = InViewTarget ( target ) ;
88
- var canUse = CanUseTo ( target ) ;
89
- var asCanTarget = action . Setting . CanTarget ( target ) ;
90
-
91
- if ( view && canUse && asCanTarget )
92
- {
93
- validTargets . Add ( target ) ;
94
- }
90
+ result . Add ( b ) ;
95
91
}
96
92
}
97
93
}
98
94
99
- return validTargets ;
95
+ return result ;
100
96
}
101
97
102
98
/// <summary>
@@ -122,21 +118,35 @@ private readonly List<IBattleChara> GetCanAffects(bool skipStatusProvideCheck, b
122
118
return [ ] ;
123
119
}
124
120
125
- IEnumerable < IBattleChara > items = TargetHelper . GetTargetsByRange ( Range + EffectRange , action . Setting . IsFriendly ) ;
121
+ IEnumerable < IBattleChara > items = TargetFilter . GetObjectInRadius ( action . Setting . IsFriendly
122
+ ? DataCenter . PartyMembers
123
+ : DataCenter . AllHostileTargets , Range + EffectRange ) ;
126
124
127
- List < IBattleChara > validTargets = new ( items . Count ( ) ) ;
128
- foreach ( IBattleChara tar in items )
125
+ if ( type == TargetType . Heal )
129
126
{
130
- if ( type == TargetType . Heal && tar . GetHealthRatio ( ) >= 1 )
127
+ List < IBattleChara > filteredItems = [ ] ;
128
+ foreach ( IBattleChara i in items )
131
129
{
132
- continue ;
130
+ if ( i . GetHealthRatio ( ) < 1 )
131
+ {
132
+ filteredItems . Add ( i ) ;
133
+ }
133
134
}
135
+ items = filteredItems ;
136
+ }
134
137
135
- if ( CheckStatus ( tar , skipStatusProvideCheck , skipTargetStatusNeedCheck ) && CheckTimeToKill ( tar ) && CheckResistance ( tar ) )
138
+ List < IBattleChara > validTargets = new ( items . Count ( ) ) ;
139
+
140
+ foreach ( IBattleChara obj in items )
141
+ {
142
+ if ( ! GeneralCheck ( obj , skipStatusProvideCheck , skipTargetStatusNeedCheck ) )
136
143
{
137
- validTargets . Add ( tar ) ;
144
+ continue ;
138
145
}
146
+
147
+ validTargets . Add ( obj ) ;
139
148
}
149
+
140
150
return validTargets ;
141
151
}
142
152
@@ -196,26 +206,10 @@ private readonly unsafe bool CanUseTo(IBattleChara tar)
196
206
return false ;
197
207
}
198
208
199
- if ( ! ( tar . GameObjectId != 0 && tar . Struct ( ) != null ) )
200
- {
201
- return false ;
202
- }
203
-
204
- var specialAbilityCheck = IsSpecialAbility ( action . Info . ID ) ;
205
- var actionmanagerCheck = ActionManager . CanUseActionOnTarget ( action . Info . AdjustedID , ( GameObject * ) tar . Struct ( ) ) ;
206
-
207
- if ( ! ( specialAbilityCheck || actionmanagerCheck ) )
208
- {
209
- return false ;
210
- }
211
- if ( ! IsTargetFriendly ) // canSee check is already done as part of finding hostile targets
212
- {
213
- return DataCenter . AllHostileTargets . Contains ( tar ) ;
214
- }
215
- else // For friendly targets we still need to check CanSee
216
- {
217
- return tar . CanSee ( ) ;
218
- }
209
+ return tar . GameObjectId != 0 && tar . Struct ( ) != null &&
210
+ ( IsSpecialAbility ( action . Info . ID ) ||
211
+ ActionManager . CanUseActionOnTarget ( action . Info . AdjustedID , ( GameObject * ) tar . Struct ( ) ) ) &&
212
+ tar . CanSee ( ) ;
219
213
}
220
214
221
215
private readonly List < ActionID > _specialActions =
@@ -235,6 +229,82 @@ private readonly bool IsSpecialAbility(uint iD)
235
229
return _specialActions . Contains ( ( ActionID ) iD ) ;
236
230
}
237
231
232
+ /// <summary>
233
+ /// Performs a general check on the specified battle character to determine if it meets the criteria for targeting.
234
+ /// </summary>
235
+ /// <param name="battleChara">The battle character to check.</param>
236
+ /// <param name="skipStatusProvideCheck">If set to <c>true</c>, skips the status provide check.</param>
237
+ /// <param name="skipTargetStatusNeedCheck">If set to <c>true</c>, skips the target status need check.</param>
238
+ /// <returns>
239
+ /// <c>true</c> if the battle character meets the criteria for targeting; otherwise, <c>false</c>.
240
+ /// </returns>
241
+ public readonly bool GeneralCheck ( IBattleChara battleChara , bool skipStatusProvideCheck , bool skipTargetStatusNeedCheck )
242
+ {
243
+ if ( battleChara == null )
244
+ {
245
+ return false ;
246
+ }
247
+
248
+ unsafe
249
+ {
250
+ if ( battleChara . Struct ( ) == null )
251
+ {
252
+ return false ;
253
+ }
254
+ }
255
+
256
+ if ( ! battleChara . IsTargetable )
257
+ {
258
+ return false ;
259
+ }
260
+
261
+ try
262
+ {
263
+ if ( battleChara . StatusList == null )
264
+ {
265
+ return false ;
266
+ }
267
+ }
268
+ catch ( Exception ex )
269
+ {
270
+ PluginLog . Error ( $ "Exception accessing StatusList for { battleChara ? . NameId } : { ex . Message } ") ;
271
+ return false ;
272
+ }
273
+
274
+ bool isBlacklisted = false ;
275
+ foreach ( uint id in DataCenter . BlacklistedNameIds )
276
+ {
277
+ if ( id == battleChara . NameId )
278
+ {
279
+ isBlacklisted = true ;
280
+ break ;
281
+ }
282
+ }
283
+ if ( isBlacklisted )
284
+ {
285
+ return false ;
286
+ }
287
+
288
+ if ( battleChara . IsEnemy ( ) && ! battleChara . IsAttackable ( ) )
289
+ {
290
+ return false ;
291
+ }
292
+
293
+ bool isStopTarget = false ;
294
+ long [ ] stopTargets = MarkingHelper . GetStopTargets ( ) ;
295
+ foreach ( long stopId in stopTargets )
296
+ {
297
+ if ( stopId == ( long ) battleChara . GameObjectId )
298
+ {
299
+ isStopTarget = true ;
300
+ break ;
301
+ }
302
+ }
303
+ return ( ! isStopTarget || ! Service . Config . FilterStopMark ) && CheckStatus ( battleChara , skipStatusProvideCheck , skipTargetStatusNeedCheck )
304
+ && CheckTimeToKill ( battleChara )
305
+ && CheckResistance ( battleChara ) ;
306
+ }
307
+
238
308
/// <summary>
239
309
/// Checks the status of the specified game object to determine if it meets the criteria for the action.
240
310
/// </summary>
@@ -361,12 +431,14 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
361
431
/// </returns>
362
432
internal readonly TargetResult ? FindTarget ( bool skipAoeCheck , bool skipStatusProvideCheck , bool skipTargetStatusNeedCheck )
363
433
{
434
+ float range = Range ;
435
+
364
436
if ( action == null || action . Setting == null || action . Config == null )
365
437
{
366
438
return null ;
367
439
}
368
440
369
- if ( Range == 0 && EffectRange == 0 )
441
+ if ( range == 0 && EffectRange == 0 )
370
442
{
371
443
return new TargetResult ( Player . Object , [ ] , Player . Object . Position ) ;
372
444
}
@@ -383,7 +455,7 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
383
455
384
456
if ( IsTargetArea )
385
457
{
386
- return FindTargetArea ( canTargets , canAffects , Range , Player . Object ) ;
458
+ return FindTargetArea ( canTargets , canAffects , range , Player . Object ) ;
387
459
}
388
460
389
461
List < IBattleChara > targetsList = [ .. GetMostCanTargetObjects ( canTargets , canAffects , skipAoeCheck ? 0 : action . Config . AoeCount ) ] ;
@@ -406,7 +478,10 @@ private readonly bool CheckTimeToKill(IBattleChara battleChara)
406
478
List < IBattleChara > affectsList = [ ] ;
407
479
if ( affectsEnum != null )
408
480
{
409
- affectsList . AddRange ( affectsEnum ) ;
481
+ foreach ( var a in affectsEnum )
482
+ {
483
+ affectsList . Add ( a ) ;
484
+ }
410
485
}
411
486
affectedTargets = [ .. affectsList ] ;
412
487
}
@@ -1085,15 +1160,15 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
1085
1160
1086
1161
IBattleChara ? FindDarkCannonTarget ( )
1087
1162
{
1088
- if ( battleChara != null )
1163
+ if ( DataCenter . AllHostileTargets != null )
1089
1164
{
1090
1165
if ( PhantomRotation . CannoneerLevel < 4 )
1091
1166
{
1092
1167
return FindHostile ( ) ;
1093
1168
}
1094
1169
else
1095
1170
{
1096
- foreach ( var hostile in battleChara )
1171
+ foreach ( var hostile in DataCenter . AllHostileTargets )
1097
1172
{
1098
1173
if ( ! hostile . IsOCBlindImmuneTarget ( ) && hostile . InCombat ( ) )
1099
1174
{
@@ -1107,9 +1182,9 @@ private readonly bool CanGetTarget(IBattleChara target, IBattleChara subTarget)
1107
1182
1108
1183
IBattleChara ? FindShockCannonTarget ( )
1109
1184
{
1110
- if ( battleChara != null )
1185
+ if ( DataCenter . AllHostileTargets != null )
1111
1186
{
1112
- foreach ( var hostile in battleChara )
1187
+ foreach ( var hostile in DataCenter . AllHostileTargets )
1113
1188
{
1114
1189
if ( ! hostile . IsOCParalysisImmuneTarget ( ) && hostile . InCombat ( ) )
1115
1190
{
0 commit comments