comparison Gear.lua @ 129:d9a059484b22 v60

Several bug fixes for 8.0.
author yellowfive
date Wed, 18 Jul 2018 13:08:22 -0700
parents e31b02b24488
children a0894ffebd15
comparison
equal deleted inserted replaced
128:b16e1f4d100e 129:d9a059484b22
82 -- given a table of items (keyed or indexed doesn't matter) find closest match to item, or nil if none are a match 82 -- given a table of items (keyed or indexed doesn't matter) find closest match to item, or nil if none are a match
83 local function findMatchingItemFromTable(item, list, bestItem, bestDiff, bestLoc, usedItems, tableType) 83 local function findMatchingItemFromTable(item, list, bestItem, bestDiff, bestLoc, usedItems, tableType)
84 if not list then return nil end 84 if not list then return nil end
85 85
86 local found = false 86 local found = false
87 for k,listItem in pairs(list) do 87 for k,listItem in pairs(list) do
88 if listItem then 88 if listItem then
89 local diff = countItemDifferences(item, listItem) 89 local diff = countItemDifferences(item, listItem)
90 if diff < bestDiff then 90 if diff < bestDiff then
91 -- each physical item can only be used once, the usedItems table has items we can't use in this search 91 -- each physical item can only be used once, the usedItems table has items we can't use in this search
92 local key = string.format("%s_%s", tableType, k) 92 local key = string.format("%s_%s", tableType, k)
110 110
111 local equipped = player.Equipped and player.Equipped[player.ActiveSpec] or nil 111 local equipped = player.Equipped and player.Equipped[player.ActiveSpec] or nil
112 local bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, equipped, nil, 10000, nil, usedItems, "equip") 112 local bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, equipped, nil, 10000, nil, usedItems, "equip")
113 bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, player.BagItems, bestItem, bestDiff, bestLoc, usedItems, "bag") 113 bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, player.BagItems, bestItem, bestDiff, bestLoc, usedItems, "bag")
114 if player.BankItems then 114 if player.BankItems then
115 for bagId,bagList in pairs(player.BankItems) do 115 bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, player.BankItems, bestItem, bestDiff, bestLoc, usedItems, "bank")
116 bestItem, bestDiff, bestLoc = findMatchingItemFromTable(item, bagList, bestItem, bestDiff, bestLoc, usedItems, "bank" .. bagId)
117 end
118 end 116 end
119 117
120 if bestDiff >= 10000 then 118 if bestDiff >= 10000 then
121 return nil, 10000 119 return nil, 10000
122 else 120 else
590 bestItem, bestDiff, bestLink = scanBagForItem(item, BACKPACK_CONTAINER, bestItem, bestDiff, bestLink) 588 bestItem, bestDiff, bestLink = scanBagForItem(item, BACKPACK_CONTAINER, bestItem, bestDiff, bestLink)
591 for bagId = 1, NUM_BAG_SLOTS do 589 for bagId = 1, NUM_BAG_SLOTS do
592 bestItem, bestDiff, bestLink = scanBagForItem(item, bagId, bestItem, bestDiff, bestLink) 590 bestItem, bestDiff, bestLink = scanBagForItem(item, bagId, bestItem, bestDiff, bestLink)
593 end 591 end
594 592
593 -- with new approach, the item to use should never be equipped, should be in bags at this point
594 --[[
595 -- equipped items, but skip slots we have just equipped (to avoid e.g. just moving 2 of the same item back and forth between mh oh weapon slots) 595 -- equipped items, but skip slots we have just equipped (to avoid e.g. just moving 2 of the same item back and forth between mh oh weapon slots)
596 for slotNum = 1, #Amr.SlotIds do 596 for slotNum = 1, #Amr.SlotIds do
597 local slotId = Amr.SlotIds[slotNum] 597 local slotId = Amr.SlotIds[slotNum]
598 if _currentGearOp.slotsRemaining[slotId] then 598 if _currentGearOp.slotsRemaining[slotId] then
599 local itemLink = GetInventoryItemLink("player", slotId) 599 local itemLink = GetInventoryItemLink("player", slotId)
608 end 608 end
609 end 609 end
610 end 610 end
611 end 611 end
612 end 612 end
613 613 ]]
614
614 -- bank 615 -- bank
615 if bestDiff > 0 then 616 if bestDiff > 0 then
616 bestItem, bestDiff, bestLink = scanBagForItem(item, BANK_CONTAINER, bestItem, bestDiff, bestLink) 617 bestItem, bestDiff, bestLink = scanBagForItem(item, BANK_CONTAINER, bestItem, bestDiff, bestLink)
617 for bagId = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do 618 for bagId = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do
618 bestItem, bestDiff, bestLink = scanBagForItem(item, bagId, bestItem, bestDiff, bestLink) 619 bestItem, bestDiff, bestLink = scanBagForItem(item, bagId, bestItem, bestDiff, bestLink)
751 -- if an item is not soulbound, then warn the user and quit 752 -- if an item is not soulbound, then warn the user and quit
752 Amr:Print(L.GearEquipErrorSoulbound(bestLink)) 753 Amr:Print(L.GearEquipErrorSoulbound(bestLink))
753 disposeGearOp() 754 disposeGearOp()
754 755
755 else 756 else
757
758 --print("equipping " .. bestLink .. " in slot " .. _currentGearOp.nextSlot)
756 759
757 -- an item in the player's bags or already equipped, equip it 760 -- an item in the player's bags or already equipped, equip it
758 if bestItem.bag then 761 if bestItem.bag then
759 PickupContainerItem(bestItem.bag, bestItem.slot) 762 PickupContainerItem(bestItem.bag, bestItem.slot)
760 else 763 else
895 tbl[i], tbl[rand] = tbl[rand], tbl[i] 898 tbl[i], tbl[rand] = tbl[rand], tbl[i]
896 end 899 end
897 return tbl 900 return tbl
898 end 901 end
899 902
903 local _ohFirst = {
904 [20] = true, -- PaladinProtection
905 [32] = true, -- WarlockDemonology
906 [36] = true -- WarriorProtection
907 }
908
900 function beginEquipGearSet(spec, passes) 909 function beginEquipGearSet(spec, passes)
901 910
902 local gear = Amr.db.char.GearSets[spec] 911 local gear = Amr.db.char.GearSets[spec]
903 if not gear then 912 if not gear then
904 Amr:Print(L.GearEquipErrorEmpty) 913 Amr:Print(L.GearEquipErrorEmpty)
905 return 914 return
906 end 915 end
907 916
908 -- ensure all our stored data is up to date 917 -- ensure all our stored data is up to date
909 local player = Amr:ExportCharacter() 918 local player = Amr:ExportCharacter()
919 local doOhFirst = _ohFirst[player.Specs[spec]]
910 920
911 local itemsToEquip = { 921 local itemsToEquip = {
912 legendaries = {}, 922 legendaries = {},
913 weapons = {}, 923 weapons = {},
924 mh = {},
925 oh = {},
914 rings = {}, 926 rings = {},
915 trinkets = {}, 927 trinkets = {},
916 others = {}, 928 others = {},
917 blanks = {} 929 blanks = {}
918 } 930 }
919 local remaining = 0 931 local remaining = 0
920 local usedItems = {} 932 local usedItems = {}
921 933
922 -- check for items that need to be equipped, do in a random order to try and defeat any unique constraint issues we might hit 934 -- check for items that need to be equipped, do in a random order to try and defeat any unique constraint issues we might hit
923 local slots = {} 935 local slots = {}
924 for i,s in ipairs(Amr.SlotIds) do 936 for i,s in ipairs(Amr.SlotIds) do
925 table.insert(slots, s) 937 table.insert(slots, s)
928 940
929 for i,slotId in ipairs(slots) do 941 for i,slotId in ipairs(slots) do
930 942
931 -- we do stuff in batches that avoids most unique conflicts 943 -- we do stuff in batches that avoids most unique conflicts
932 local list = itemsToEquip.others 944 local list = itemsToEquip.others
933 if slotId == 16 or slotId == 17 then 945 if slotId == 16 then
934 list = itemsToEquip.weapons 946 list = itemsToEquip.mh
947 elseif slotId == 17 then
948 list = itemsToEquip.oh
935 elseif slotId == 11 or slotId == 12 then 949 elseif slotId == 11 or slotId == 12 then
936 list = itemsToEquip.rings 950 list = itemsToEquip.rings
937 elseif slotId == 13 or slotId == 14 then 951 elseif slotId == 13 or slotId == 14 then
938 list = itemsToEquip.trinkets 952 list = itemsToEquip.trinkets
939 end 953 end
946 local newItem = Item:CreateFromItemID(new.id) 960 local newItem = Item:CreateFromItemID(new.id)
947 local quality = newItem and newItem:GetItemQuality() or 0 961 local quality = newItem and newItem:GetItemQuality() or 0
948 if quality == 6 then 962 if quality == 6 then
949 if not old or new.id ~= old.id then 963 if not old or new.id ~= old.id then
950 list[slotId] = new 964 list[slotId] = new
965 if list == itemsToEquip.mh or list == itemsToEquip.oh then
966 itemsToEquip.weapons[slotId] = {}
967 end
951 remaining = remaining + 1 968 remaining = remaining + 1
952 end 969 end
953 else 970 else
971 -- find the best matching item anywhere in the player's gear
972 local bestItem, bestDiff = Amr:FindMatchingItem(new, player, usedItems)
973 new = bestItem
974
954 local diff = countItemDifferences(old, new) 975 local diff = countItemDifferences(old, new)
976
977 --[[
955 if diff > 0 and diff < 1000 then 978 if diff > 0 and diff < 1000 then
956 -- same item, see if inventory has one that is closer (e.g. a duplicate item with correct enchants/gems) 979 -- same item, see if inventory has one that is closer (e.g. a duplicate item with correct enchants/gems)
957 local bestItem, bestDiff = Amr:FindMatchingItem(new, player, usedItems) 980 local bestItem, bestDiff = Amr:FindMatchingItem(new, player, usedItems)
958 if bestDiff and bestDiff < diff then 981 if bestDiff and bestDiff < diff then
959 new = bestItem 982 new = bestItem
960 diff = bestDiff 983 diff = bestDiff
961 end 984 end
962 end 985 end
963 986 ]]
964 if diff > 0 then 987
988 if diff > 0 then
965 list[slotId] = new 989 list[slotId] = new
990 if list == itemsToEquip.mh or list == itemsToEquip.oh then
991 itemsToEquip.weapons[slotId] = {}
992 end
966 remaining = remaining + 1 993 remaining = remaining + 1
967 end 994 end
968 end 995 end
969 else 996 elseif old then
970 -- need to remove this item 997 -- need to remove this item
971 itemsToEquip.blanks[slotId] = {} 998 itemsToEquip.blanks[slotId] = {}
972 remaining = remaining + 1 999 remaining = remaining + 1
973 end 1000 end
974 1001
986 if remaining > 0 then 1013 if remaining > 0 then
987 1014
988 if passes < 5 then 1015 if passes < 5 then
989 _pendingGearOps = {} 1016 _pendingGearOps = {}
990 1017
991 if not Amr.IsEmpty(itemsToEquip.blanks) then 1018 if not Amr.IsEmpty(itemsToEquip.blanks) then
992 -- if gear set wants slots to be blank, do that first 1019 -- if gear set wants slots to be blank, do that first
993 table.insert(_pendingGearOps, { items = itemsToEquip.blanks, remove = true, label = "blanks" }) 1020 table.insert(_pendingGearOps, { items = itemsToEquip.blanks, remove = true, label = "blanks" })
994 end 1021 end
995 if not Amr.IsEmpty(itemsToEquip.weapons) then 1022 if not Amr.IsEmpty(itemsToEquip.weapons) then
996 -- change weapons first: remove both, wait, then equip new ones 1023 -- change weapons first: remove both, wait, then equip each weapon one by one, waiting after each
997 table.insert(_pendingGearOps, { items = itemsToEquip.weapons, remove = true, label = "remove weapons" }) 1024 table.insert(_pendingGearOps, { items = itemsToEquip.weapons, remove = true, label = "remove weapons" })
998 table.insert(_pendingGearOps, { items = itemsToEquip.weapons, wait = true, label = "equip weapons" }) 1025 local thisWeapon = doOhFirst and itemsToEquip.oh or itemsToEquip.mh
1026 if not Amr.IsEmpty(thisWeapon) then
1027 table.insert(_pendingGearOps, { items = thisWeapon, wait = true, label = "equip weapon 1" })
1028 end
1029 thisWeapon = doOhFirst and itemsToEquip.mh or itemsToEquip.oh
1030 if not Amr.IsEmpty(thisWeapon) then
1031 table.insert(_pendingGearOps, { items = thisWeapon, wait = true, label = "equip weapon 2" })
1032 end
999 end 1033 end
1000 if not Amr.IsEmpty(itemsToEquip.legendaries) then 1034 if not Amr.IsEmpty(itemsToEquip.legendaries) then
1001 -- remove any legendaries, wait 1035 -- remove any legendaries, wait
1002 table.insert(_pendingGearOps, { items = itemsToEquip.legendaries, remove = true, label = "remove legendaries" }) 1036 table.insert(_pendingGearOps, { items = itemsToEquip.legendaries, remove = true, label = "remove legendaries" })
1003 end 1037 end
1039 1073
1040 local function onActiveTalentGroupChanged() 1074 local function onActiveTalentGroupChanged()
1041 1075
1042 local auto = Amr.db.profile.options.autoGear 1076 local auto = Amr.db.profile.options.autoGear
1043 local currentSpec = GetSpecialization() 1077 local currentSpec = GetSpecialization()
1044 1078 local waitingSpec = _waitingForSpec
1045 if currentSpec == _waitingForSpec or auto then
1046 -- spec is what we want, now equip the gear
1047 beginEquipGearSet(currentSpec, 0)
1048 end
1049
1050 _waitingForSpec = 0 1079 _waitingForSpec = 0
1080
1081 if currentSpec == waitingSpec or auto then
1082 -- spec is what we want, now equip the gear but after a short delay because the game auto-swaps artifact weapons
1083 Amr.Wait(2, function()
1084 beginEquipGearSet(GetSpecialization(), 0)
1085 end)
1086 end
1051 end 1087 end
1052 1088
1053 -- activate the specified spec and then equip the saved gear set 1089 -- activate the specified spec and then equip the saved gear set
1054 function Amr:EquipGearSet(spec) 1090 function Amr:EquipGearSet(spec)
1055 1091
1067 if UnitAffectingCombat("player") then 1103 if UnitAffectingCombat("player") then
1068 Amr:Print(L.GearEquipErrorCombat) 1104 Amr:Print(L.GearEquipErrorCombat)
1069 return 1105 return
1070 end 1106 end
1071 1107
1072 _waitingForSpec = spec
1073
1074 local currentSpec = GetSpecialization() 1108 local currentSpec = GetSpecialization()
1075 if currentSpec ~= spec then 1109 if currentSpec ~= spec then
1110 _waitingForSpec = spec
1076 SetSpecialization(spec) 1111 SetSpecialization(spec)
1077 else 1112 else
1078 onActiveTalentGroupChanged() 1113 -- spec is what we want, now equip the gear
1114 beginEquipGearSet(currentSpec, 0)
1079 end 1115 end
1080 end 1116 end
1081 1117
1082 -- moves any gear in bags to the bank if not part of a gear set 1118 -- moves any gear in bags to the bank if not part of a gear set
1083 function Amr:CleanBags() 1119 function Amr:CleanBags()