fix(ui): port exact paperdoll body selection
Resolve and sample retail's authored nine-color paperdoll click map, preserve local click coordinates, and select the stable highest-priority worn item with the player fallback. Keep targeted-use body clicks routed to self and pin both synthetic and live-DAT conformance. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
2644d1d527
commit
0b74d19475
16 changed files with 490 additions and 32 deletions
47
src/AcDream.Core/Items/PaperdollSelectionPolicy.cs
Normal file
47
src/AcDream.Core/Items/PaperdollSelectionPolicy.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
namespace AcDream.Core.Items;
|
||||
|
||||
/// <summary>
|
||||
/// Retail paperdoll body-part selection. Ports
|
||||
/// <c>InventoryPlacement::DetermineHigherPriority @ 0x004A44B0</c> and
|
||||
/// <c>gmPaperDollUI::GetUpperInvObj @ 0x004A4750</c>.
|
||||
/// </summary>
|
||||
public static class PaperdollSelectionPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the visually upper equipped object covering <paramref name="bodyLocationMask"/>.
|
||||
/// When the body part is valid but uncovered, retail returns the player object itself.
|
||||
/// </summary>
|
||||
public static uint GetUpperInventoryObject(
|
||||
ClientObjectTable objects,
|
||||
uint playerId,
|
||||
EquipMask bodyLocationMask)
|
||||
{
|
||||
if (playerId == 0 || bodyLocationMask == EquipMask.None || objects.Get(playerId) is null)
|
||||
return 0;
|
||||
|
||||
ClientObject? winner = null;
|
||||
foreach (ClientObject candidate in objects.Objects)
|
||||
{
|
||||
if ((candidate.CurrentlyEquippedLocation & bodyLocationMask) == EquipMask.None)
|
||||
continue;
|
||||
if (candidate.WielderId != playerId && candidate.ContainerId != playerId)
|
||||
continue;
|
||||
|
||||
if (winner is null
|
||||
|| EffectivePriority(candidate, bodyLocationMask)
|
||||
> EffectivePriority(winner, bodyLocationMask))
|
||||
winner = candidate;
|
||||
}
|
||||
|
||||
return winner?.ObjectId ?? playerId;
|
||||
}
|
||||
|
||||
private static uint EffectivePriority(ClientObject item, EquipMask bodyLocationMask)
|
||||
{
|
||||
uint priority = item.Priority;
|
||||
uint coveredLocation = (uint)(item.CurrentlyEquippedLocation & bodyLocationMask);
|
||||
if (priority == 0 && coveredLocation is >= 0x200u and <= 0x4000u)
|
||||
priority = 0x7Fu;
|
||||
return priority;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue