@@ -571,6 +571,33 @@ func TestSharedWorldRegistryRegisterGroundGoldRejectsDuplicateVIDWithoutReplacin
571571 }
572572}
573573
574+ func TestSharedWorldRegistryRegisterGroundItemRejectsDuplicateVIDWithoutReplacingExistingItem(t *testing.T) {
575+ registry := newSharedWorldRegistry()
576+ owner := peerVisibilityCharacter("DuplicateItemVIDOwner", 0x0103019a, 0x0204019a, 1200, 2200, 0, 101, 201)
577+ ownerID, _ := registry.Join(owner, newPendingServerFrames(), nil)
578+ if ownerID == 0 {
579+ t.Fatal("expected duplicate-item-vid owner join to allocate a shared-world entity id")
580+ }
581+
582+ const groundVID uint32 = 0x0700001d
583+ original := inventory.ItemInstance{ID: 0x30010001, Vnum: 3001, Count: 1}
584+ replacement := inventory.ItemInstance{ID: 0x30010002, Vnum: 3002, Count: 1}
585+ if !registry.RegisterGroundItem(ownerID, "duplicate-item-vid-owner", owner, groundVID, original) {
586+ t.Fatal("expected first ground-item reward registration to succeed")
587+ }
588+ if registry.RegisterGroundItem(ownerID, "duplicate-item-vid-owner", owner, groundVID, replacement) {
589+ t.Fatal("expected duplicate ground-item reward VID registration to fail closed")
590+ }
591+
592+ pickup, ok := registry.GroundItemPickupFor(ownerID, owner, groundVID)
593+ if !ok {
594+ t.Fatal("expected original ground-item reward to remain reachable after duplicate VID rejection")
595+ }
596+ if pickup.Item.ID != original.ID || pickup.Item.Vnum != original.Vnum || pickup.Item.Count != original.Count {
597+ t.Fatalf("expected duplicate VID rejection to preserve original ground-item reward, got %+v", pickup.Item)
598+ }
599+ }
600+
574601func TestSharedWorldRegistryRegisterGroundRewardsRejectsEmptyOwnerLogin(t *testing.T) {
575602 registry := newSharedWorldRegistry()
576603 owner := peerVisibilityCharacter("EmptyLoginRewardOwner", 0x01030194, 0x02040194, 1200, 2200, 0, 101, 201)
0 commit comments