Mercurial > wow > askmrrobot
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() |
