feat(ui): port retail item interaction policy

This commit is contained in:
Erik 2026-07-11 01:23:31 +02:00
parent 0cf780478a
commit a8da4fd05a
20 changed files with 1110 additions and 104 deletions

View file

@ -449,6 +449,27 @@ public sealed class GameEventWiringTests
Assert.Equal(1u, items.Get(0x50000A02u)!.ContainerTypeHint);
}
[Fact]
public void UseDone_releasesAppBusyOwnerThroughCallback()
{
var dispatcher = new GameEventDispatcher();
uint? completedWith = null;
GameEventWiring.WireAll(
dispatcher,
new ClientObjectTable(),
new CombatState(),
new Spellbook(),
new ChatLog(),
onUseDone: error => completedWith = error);
byte[] payload = new byte[4];
BinaryPrimitives.WriteUInt32LittleEndian(payload, 0x1Du);
var env = GameEventEnvelope.TryParse(WrapEnvelope(GameEventType.UseDone, payload));
dispatcher.Dispatch(env!.Value);
Assert.Equal(0x1Du, completedWith);
}
[Fact]
public void PlayerDescription_ReplacesPlayerPackContents_InRetailManifestOrder()
{

View file

@ -172,6 +172,22 @@ public sealed class CreateObjectTests
Assert.Equal((uint)ItemType.Creature, parsed!.Value.TargetType);
}
[Fact]
public void TryParse_CombatUseFlag_CapturesByte()
{
byte[] body = BuildMinimalCreateObjectWithWeenieHeader(
guid: 0x5000000Du,
name: "Sword",
itemType: (uint)ItemType.MeleeWeapon,
weenieFlags: 0x00000200u,
combatUse: 2);
var parsed = CreateObject.TryParse(body);
Assert.NotNull(parsed);
Assert.Equal((byte)2, parsed.Value.CombatUse);
}
// -----------------------------------------------------------------------
// Retail radar: PublicWeenieDesc carries two independently gated bytes.
// Absence is distinct from an explicitly transmitted zero because zero is
@ -566,6 +582,7 @@ public sealed class CreateObjectTests
float? workmanship = null,
byte? radarBlipColor = null,
byte? radarBehavior = null,
byte? combatUse = null,
ushort movementSeq = 0)
{
var bytes = new List<byte>();
@ -618,7 +635,7 @@ public sealed class CreateObjectTests
}
if ((weenieFlags & 0x00080000u) != 0) WriteU32(bytes, targetType ?? 0u); // TargetType u32
if ((weenieFlags & 0x00000080u) != 0) WriteU32(bytes, uiEffects); // UiEffects u32
if ((weenieFlags & 0x00000200u) != 0) bytes.Add(0); // CombatUse sbyte/1 byte
if ((weenieFlags & 0x00000200u) != 0) bytes.Add(combatUse ?? 0); // CombatUse sbyte/1 byte
if ((weenieFlags & 0x00000400u) != 0) WriteU16(bytes, structure ?? 0); // Structure u16
if ((weenieFlags & 0x00000800u) != 0) WriteU16(bytes, maxStructure ?? 0); // MaxStructure u16
if ((weenieFlags & 0x00001000u) != 0) WriteU16(bytes, stackSize ?? 0); // StackSize u16

View file

@ -61,6 +61,8 @@ public sealed class ObjectTableWiringTests
TargetType = (uint)ItemType.Creature,
RadarBlipColor = 4,
RadarBehavior = 3,
ObjectDescriptionFlags = 0x20800200u,
CombatUse = 2,
};
var d = ObjectTableWiring.ToWeenieData(spawn);
@ -104,6 +106,8 @@ public sealed class ObjectTableWiringTests
Assert.Equal((uint)ItemType.Creature, d.TargetType);
Assert.Equal((byte)4, d.RadarBlipColor);
Assert.Equal((byte)3, d.RadarBehavior);
Assert.Equal(0x20800200u, d.PublicWeenieBitfield);
Assert.Equal((byte)2, d.CombatUse);
}
// -------------------------------------------------------------------------