fix #234: port retail appraisal floaty and inscriptions

This commit is contained in:
Erik 2026-07-23 12:12:57 +02:00
parent 643cdfe66e
commit f1a7912160
23 changed files with 1310 additions and 106 deletions

View file

@ -60,19 +60,19 @@ public static class AppraiseInfoParser
{
None = 0x0000_0000,
IntStatsTable = 0x0000_0001,
Int64StatsTable = 0x0000_0002,
BoolStatsTable = 0x0000_0004,
FloatStatsTable = 0x0000_0008,
StringStatsTable = 0x0000_0010,
DidStatsTable = 0x0000_0020,
SpellBook = 0x0000_0040,
BoolStatsTable = 0x0000_0002,
FloatStatsTable = 0x0000_0004,
StringStatsTable = 0x0000_0008,
SpellBook = 0x0000_0010,
WeaponProfile = 0x0000_0020,
HookProfile = 0x0000_0040,
ArmorProfile = 0x0000_0080,
WeaponProfile = 0x0000_0100,
HookProfile = 0x0000_0200,
ArmorEnchantmentBitfield = 0x0000_0400,
CreatureProfile = 0x0000_0100,
ArmorEnchantmentBitfield = 0x0000_0200,
ResistEnchantmentBitfield= 0x0000_0400,
WeaponEnchantmentBitfield= 0x0000_0800,
ResistEnchantmentBitfield= 0x0000_1000,
CreatureProfile = 0x0000_2000,
DidStatsTable = 0x0000_1000,
Int64StatsTable = 0x0000_2000,
ArmorLevels = 0x0000_4000,
}

View file

@ -26,6 +26,7 @@ public static class InventoryActions
public const uint GetAndWieldItemOpcode = 0x001Au;
public const uint DropItemOpcode = 0x001Bu;
public const uint NoLongerViewingContentsOpcode = 0x0195u;
public const uint SetInscriptionOpcode = 0x00BFu;
/// <summary>
/// Merge stack A into stack B of the same item type. Server validates
@ -172,4 +173,36 @@ public static class InventoryActions
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(12), containerGuid);
return body;
}
/// <summary>
/// Set or clear an item's inscription. Retail
/// <c>CM_Writing::Event_SetInscription @ 0x006A98B0</c> writes the object
/// GUID followed by one CP-1252 String16L and receives no success response.
/// </summary>
public static byte[] BuildSetInscription(
uint seq,
uint itemGuid,
string inscription)
{
ArgumentNullException.ThrowIfNull(inscription);
byte[] text = Encodings.Windows1252.GetBytes(inscription);
if (text.Length > ushort.MaxValue)
throw new ArgumentException(
"Inscription is too long for String16L.",
nameof(inscription));
int stringRecordLength = (2 + text.Length + 3) & ~3;
byte[] body = new byte[16 + stringRecordLength];
BinaryPrimitives.WriteUInt32LittleEndian(body, GameActionEnvelope);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(4), seq);
BinaryPrimitives.WriteUInt32LittleEndian(
body.AsSpan(8),
SetInscriptionOpcode);
BinaryPrimitives.WriteUInt32LittleEndian(body.AsSpan(12), itemGuid);
BinaryPrimitives.WriteUInt16LittleEndian(
body.AsSpan(16),
(ushort)text.Length);
text.CopyTo(body, 18);
return body;
}
}

View file

@ -1788,6 +1788,20 @@ public sealed class WorldSession : IDisposable
SendGameAction(AppraiseRequest.Build(seq, targetGuid));
}
/// <summary>
/// Send retail SetInscription (0x00BF). The retail client updates the
/// examination field optimistically because the server sends no success
/// response.
/// </summary>
public void SendSetInscription(uint itemGuid, string inscription)
{
uint seq = NextGameActionSequence();
SendGameAction(InventoryActions.BuildSetInscription(
seq,
itemGuid,
inscription));
}
/// <summary>Send PutItemInContainer (0x0019) - move an item into a container at a slot. placement
/// = the target slot (server packs/shifts); the drag-drop drop handler computes it. Retail:
/// CM_Inventory::Event_PutItemInContainer -> ACE Player.HandleActionPutItemInContainer.</summary>