From 1992c9d1b51a4eeda6b8aaed2dcaf327554cbb17 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Fri, 9 Oct 2026 17:02:36 -0700 Subject: [PATCH] fix: worn gear lifted off a corpse stays loot when put back (#2701) A corpse's worn-gear list was fixed at creation, and clients learn worn gear only from the 0x89 packet sent on first sight. A piece lifted and dropped back showed as loose loot to everyone watching, but came back "worn" after a relog. Lifting now takes the piece off the list, so every view agrees it is loot. Programmatic moves (the duel gather-and-re-equip in `DuelContext`) don't go through `OnItemLifted` and still see the original list. --- .../Items/Misc/Corpses/CorpseLootTests.cs | 42 +++++++++++++++++++ .../UOContent/Items/Misc/Corpses/Corpse.cs | 4 ++ 2 files changed, 46 insertions(+) create mode 100644 Projects/UOContent.Tests/Tests/Items/Misc/Corpses/CorpseLootTests.cs diff --git a/Projects/UOContent.Tests/Tests/Items/Misc/Corpses/CorpseLootTests.cs b/Projects/UOContent.Tests/Tests/Items/Misc/Corpses/CorpseLootTests.cs new file mode 100644 index 000000000..26556155e --- /dev/null +++ b/Projects/UOContent.Tests/Tests/Items/Misc/Corpses/CorpseLootTests.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using Server; +using Server.Items; +using Xunit; + +namespace UOContent.Tests; + +[Collection("Sequential UOContent Tests")] +public class CorpseLootTests +{ + [Fact] + public void LiftedWornGear_PutBack_StaysLoot() + { + var owner = new Mobile((Serial)0x1); + owner.DefaultMobileInit(); + owner.Body = 0x190; + + // Weapons take their layer from tiledata, which CI doesn't load. + var sword = new VikingSword { Layer = Layer.OneHanded }; + Assert.True(owner.EquipItem(sword)); + + var corpse = new Corpse(owner, new List { sword }); + corpse.DropItem(sword); + + try + { + Assert.Contains(sword, corpse.EquipItems); + + corpse.OnItemLifted(owner, sword); + sword.Internalize(); + corpse.DropItem(sword); + + Assert.Same(corpse, sword.Parent); + Assert.DoesNotContain(sword, corpse.EquipItems); + } + finally + { + corpse.Delete(); + owner.Delete(); + } + } +} diff --git a/Projects/UOContent/Items/Misc/Corpses/Corpse.cs b/Projects/UOContent/Items/Misc/Corpses/Corpse.cs index 04e9806c9..2cd0cea89 100644 --- a/Projects/UOContent/Items/Misc/Corpses/Corpse.cs +++ b/Projects/UOContent/Items/Misc/Corpses/Corpse.cs @@ -812,6 +812,10 @@ public partial class Corpse : Container, ICarvable AddToLooters(from); _instancedItems?.Remove(item); + + // Lifted gear is loot from then on. Clients only learn worn gear from 0x89 on first sight, so a + // piece put back would show worn after a relog but loose to everyone already watching. + RemoveFromEquipItems(item); } public override void GetContextMenuEntries(Mobile from, ref PooledRefList list)