feat(inventory): port retail item giving (#216)
Preserve SmartBox drag-release coordinates, route the picked 3-D target through the retail AttemptPlaceIn3D policy, and send authoritative GiveObject requests with the selected stack quantity. Honor PlayerDescription's player secure-trade option and document the remaining trade-system boundary. Co-Authored-By: Codex <noreply@openai.com>
This commit is contained in:
parent
a944e49b9c
commit
30d294506c
13 changed files with 421 additions and 10 deletions
|
|
@ -76,7 +76,8 @@ public static class GameEventWiring
|
|||
Action<GameEvents.CharacterConfirmationDone>? onConfirmationDone = null,
|
||||
FriendsState? friends = null,
|
||||
SquelchState? squelch = null,
|
||||
Action<IReadOnlyList<(uint Id, uint Amount)>>? onDesiredComponents = null)
|
||||
Action<IReadOnlyList<(uint Id, uint Amount)>>? onDesiredComponents = null,
|
||||
Action<uint /*options1*/, uint /*options2*/>? onCharacterOptions = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(dispatcher);
|
||||
ArgumentNullException.ThrowIfNull(items);
|
||||
|
|
@ -439,6 +440,7 @@ public static class GameEventWiring
|
|||
Console.WriteLine($"vitals: PlayerDescription body.len={e.Payload.Length} parsed={(p is null ? "NULL" : $"vec={p.Value.VectorFlags} attrs={p.Value.Attributes.Count} spells={p.Value.Spells.Count}")}");
|
||||
if (p is null) return;
|
||||
|
||||
onCharacterOptions?.Invoke(p.Value.Options1, p.Value.Options2);
|
||||
onDesiredComponents?.Invoke(p.Value.DesiredComps);
|
||||
|
||||
// B-Wire: deliver the player's OWN properties to the player ClientObject.
|
||||
|
|
|
|||
|
|
@ -197,6 +197,20 @@ public static class PlayerDescriptionParser
|
|||
SpellLists8 = 0x00000400,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Character-option bits consumed by the client runtime. Values are the
|
||||
/// verbatim retail <c>CharacterOption</c> enum from
|
||||
/// <c>named-retail/acclient.h:3404</c>.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CharacterOptions1 : uint
|
||||
{
|
||||
None = 0,
|
||||
AllowGive = 0x00000040,
|
||||
DragItemOnPlayerOpensSecureTrade = 0x04000000,
|
||||
Default = 0x50C4A54A,
|
||||
}
|
||||
|
||||
/// <summary>One inventory entry — a guid plus a ContainerType
|
||||
/// discriminator (0=NonContainer, 1=Container, 2=Foci). Holtburger
|
||||
/// <c>events.rs:143-168</c> validates <c>ContainerType <= 2</c>
|
||||
|
|
|
|||
|
|
@ -1479,6 +1479,18 @@ public sealed class WorldSession : IDisposable
|
|||
SendGameAction(InventoryActions.BuildDropItem(seq, itemGuid));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send retail GiveObjectRequest (0x00CD). Retail
|
||||
/// <c>CM_Inventory::Event_GiveObjectRequest @ 0x006ABB00</c> writes
|
||||
/// target, source item, then selected stack amount.
|
||||
/// </summary>
|
||||
public void SendGiveObject(uint targetGuid, uint itemGuid, uint amount)
|
||||
{
|
||||
uint seq = NextGameActionSequence();
|
||||
SendGameAction(InventoryActions.BuildGiveObjectRequest(
|
||||
seq, targetGuid, itemGuid, amount));
|
||||
}
|
||||
|
||||
/// <summary>Send GetAndWieldItem (0x001A) — equip an item to an equip slot.</summary>
|
||||
public void SendGetAndWieldItem(uint itemGuid, uint equipMask)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue