Make the retained toolbar consume retail's payload-free selection notice from canonical live state so a reentrant Auto Target replacement cannot be erased by the outer clear. Restrict automatic acquisition to the requested hostile non-player monster policy and record the intentional PK edge divergence. Co-Authored-By: Codex <codex@openai.com>
42 lines
1.5 KiB
C#
42 lines
1.5 KiB
C#
using AcDream.Core.Items;
|
|
|
|
namespace AcDream.Core.Combat;
|
|
|
|
/// <summary>
|
|
/// Eligibility policy for automatic monster acquisition.
|
|
/// </summary>
|
|
public static class CombatTargetPolicy
|
|
{
|
|
/// <summary>
|
|
/// Returns true only for a live-data creature that is attackable, is not a
|
|
/// player, and is not a pet. Friendly NPCs and non-creatures are rejected.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The attackability core is retail
|
|
/// <c>ClientCombatSystem::ObjectIsAttackable @ 0x0056A600</c>. Retail
|
|
/// <c>AutoTarget @ 0x0056BC80</c> falls back to
|
|
/// <c>SelectNext(SELECTION_TYPE_COMPASS_ITEM)</c>, whose combat filter also
|
|
/// uses ObjectIsAttackable. acdream deliberately narrows that set to
|
|
/// non-player monsters for its automatic acquisition policy; explicit
|
|
/// player-selection commands remain separate.
|
|
/// </remarks>
|
|
public static bool IsHostileMonster(
|
|
uint playerId,
|
|
ClientObject? player,
|
|
ClientObject? candidate)
|
|
{
|
|
if (candidate is null
|
|
|| candidate.ObjectId == playerId
|
|
|| (candidate.Type & ItemType.Creature) == 0
|
|
|| (candidate.PublicWeenieBitfield.GetValueOrDefault()
|
|
& SelectedObjectHealthPolicy.BfPlayer) != 0
|
|
|| candidate.PetOwnerId != 0)
|
|
return false;
|
|
|
|
return SelectedObjectHealthPolicy.ObjectIsAttackable(
|
|
playerId,
|
|
player,
|
|
candidate.ObjectId,
|
|
candidate);
|
|
}
|
|
}
|