-- Copyright 2008 James Whitehead II |
-- Credits for name 'DressToKill' go to Aska on StormReaver(EU) |
|
DressToKill = {} |
local L = DressToKillLocals |
|
local DEBUG = true |
local function debug(fmt, ...) |
if DEBUG then |
local msg = "|cffffff78DressToKill:|r " |
if select("#", ...) > 0 then |
msg = msg .. fmt:format(...) |
else |
msg = msg .. fmt |
end |
ChatFrame1:AddMessage(msg) |
end |
end |
|
local slotNames = { |
BackSlot = L["Back"], |
ChestSlot = L["Chest"], |
FeetSlot = L["Feet"], |
Finger0Slot = L["Left Finger"], |
Finger1Slot = L["Right Finger"], |
HeadSlot = L["Head"], |
HandsSlot = L["Hands"], |
LegsSlot = L["Legs"], |
MainHandSlot = L["Main Hand"], |
NeckSlot = L["Neck Slot"], |
RangedSlot = L["Ranged Slot"], |
--SecondaryHandSlot = L["Secondary Hand"], |
ShoulderSlot = L["Shoulders"], |
Trinket0Slot = L["Trinket 0"], |
Trinket1Slot = L["Trinket 1"], |
WaistSlot = L["Waist"], |
WristSlot = L["Wrist"], |
} |
|
local slotIds = {} |
|
function DressToKill:Initialize() |
debug(L["Scanning for inventory slot Ids"]) |
for slot in pairs(slotNames) do |
local id = GetInventorySlotInfo(slot) |
if id then |
slotIds[slot] = id |
else |
local err = string.format(L["Could not get inventory slot information for %s"], tostring(slot)) |
error(err) |
return |
end |
end |
end |
|
function DressToKill:FindEmptySlot() |
for bag=0,4 do |
for slot=1,GetContainerNumSlots(bag) do |
if not GetContainerItemInfo(bag, slot) then |
return bag, slot |
end |
end |
end |
end |
|
local function scanFunction() |
debug(L["Beginning an inventory scan"]) |
|
local blacklist = {} |
local slotAvail = {} |
for slotName,slotId in pairs(slotIds) do |
local avail = GetInventoryItemsForSlot(slotId) |
if next(avail) then |
slotAvail[slotId] = avail |
end |
end |
|
local stash = {} |
-- Loop through all of the inventory slots |
for slotId,avail in pairs(slotAvail) do |
local maxScore, winner = 0, nil |
local link = GetInventoryItemLink("player", slotId) |
if link then |
-- We current have an item equipped, so stash that item elsewhere |
local bag,slot = DressToKill:FindEmptySlot() |
if not bag or not slot then |
debug(L["Out of inventory space, cannot proceed"]) |
return |
end |
|
stash.bag = bag |
stash.slot = slot |
PickupInventoryItem(slotId) |
PickupContainerItem(bag, slot) |
coroutine.yield() |
end |
|
-- Loop through all of the available items, and try equipping each of them |
for mask,item in pairs(avail) do |
if not blacklist[mask] then |
local equipped = DressToKill:EquipItem(slotId, mask, stash) |
if equipped then |
local score = DressToKill:EvaluateScore() |
if score >= maxScore then |
maxScore = score |
winner = mask |
end |
|
-- Unequip the item |
DressToKill:UnequipItem(slotId, mask, stash) |
else |
debug(L["Item not equipped... skipping..."]) |
end |
else |
debug(L["Item blacklisted, skipping..."]) |
end |
end |
-- Now equip the item that won this round and blacklist |
debug(L["Equipping winning item"]) |
DressToKill:EquipItem(slotId, winner, stash) |
blacklist[winner] = true |
end |
debug(L["All done trying clothes on!"]) |
end |
|
function DressToKill:EvaluateScore() |
--local base,pos,neg = UnitAttackPower("player") |
--return base + pos - neg |
|
--[[ |
local health = UnitHealthMax("player") |
local base, pos, neg = UnitArmor("player") |
local armor = base + pos - neg |
local score = (health * 0.8) + (armor * 1.0) |
return score |
|
-- 1.0/0.8 - 7430 health, 7910 armor |
-- 1.0/1.0 - 7430 health, 7910 armor |
-- 0.8/1.0 - 7390 health, 7948 armor |
--]] |
|
local mana = UnitManaMax("player") |
local healing = GetSpellBonusHealing() |
local score = (mana * 1.0) + (healing * 1.0) |
return score |
end |
|
function DressToKill:EquipItem(slotId, mask, stash) |
local bag,slot = DressToKill:ItemInBag(mask) |
local eqslot = DressToKill:ItemEquipped(mask) |
if bag then |
-- Equip the item |
PickupContainerItem(bag, slot) |
EquipCursorItem(slotId) |
local equipped = coroutine.yield() |
return equipped |
elseif eqslot then |
-- The item was equipped, so find the current slot in the stash |
PickupContainerItem(stash.bag, stash.slot) |
EquipCursorItem(slotId) |
local equipped = coroutine.yield() |
return equipped |
end |
end |
|
function DressToKill:UnequipItem(slotId, mask, stash) |
local bag,slot = DressToKill:ItemInBag(mask) |
local eqslot = DressToKill:ItemEquipped(mask) |
if bag then |
-- Just put the item back |
PickupInventoryItem(slotId) |
PickupContainerItem(bag, slot) |
coroutine.yield() |
elseif eqslot then |
-- Put it back into the stash slot |
PickupInventoryItem(slotId) |
PickupContainerItem(stash.bag, stash.slot) |
coroutine.yield() |
end |
end |
|
local eventFrame = CreateFrame("Frame") |
eventFrame:RegisterEvent("UNIT_INVENTORY_CHANGED") |
eventFrame:RegisterEvent("EQUIP_BIND_CONFIRM") |
|
local function OnEvent(self, event) |
self.equipped = true |
if event == "EQUIP_BIND_CONFIRM" and CursorHasItem() then |
self.equipped = false |
debug(L["Clearing non-soulbound item"]) |
ClearCursor() |
end |
|
local thread = DressToKill.currentThread |
if thread and coroutine.status(thread) ~= "dead" then |
self:Show() |
end |
end |
|
local function OnUpdate(self, elapsed) |
self:Hide() |
local succ,err = coroutine.resume(DressToKill.currentThread, self.equipped) |
assert(succ, err) |
end |
|
eventFrame:SetScript("OnEvent", OnEvent) |
eventFrame:SetScript("OnUpdate", OnUpdate) |
eventFrame:Hide() |
|
SLASH_DRESSTOKILL1 = "/dtk" |
SLASH_DRESSTOKILL2 = "/dress" |
SLASH_DRESSTOKILL3 = "/dresstokill" |
|
SlashCmdList["DRESSTOKILL"] = function(msg, editbox) |
debug(L["Dressing to kill..."]) |
DressToKill:Initialize() |
DressToKill.currentThread = coroutine.create(scanFunction) |
coroutine.resume(DressToKill.currentThread) |
end |
|
local ITEM_INVENTORY_PLAYER = 0x00100000 |
local ITEM_INVENTORY_BACKPACK = 0x00200000 |
local ITEM_INVENTORY_BAGS = 0x00400000 |
local ITEM_INVENTORY_BANK = 0x00800000 |
local MASK_BAG = 0xf00 |
local MASK_SLOT = 0x3f |
local bagMap = { |
[0x100] = 1, |
[0x200] = 2, |
[0x400] = 3, |
[0x800] = 4, |
} |
function DressToKill:ItemInBag(mask) |
if bit.band(mask, ITEM_INVENTORY_BAGS) > 0 then |
local bag = bagMap[bit.band(mask, MASK_BAG)] |
local slot = bit.band(mask, MASK_SLOT) |
return bag, slot |
elseif bit.band(mask, ITEM_INVENTORY_BACKPACK) > 0 then |
local slot = bit.band(mask, MASK_SLOT) |
return 0, slot |
end |
end |
|
function DressToKill:ItemEquipped(mask) |
if bit.band(mask, ITEM_INVENTORY_PLAYER) > 0 then |
local slot = bit.band(mask, MASK_SLOT) |
return slot |
end |
end |
|
--[[ |
ITEM_INVENTORY_LOCATION_PLAYER = 0x00100000 |
ITEM_INVENTORY_LOCATION_BACKPACK = 0x00200000 |
ITEM_INVENTORY_LOCATION_BAGS = 0x00400000 |
ITEM_INVENTORY_LOCATION_BANK = 0x00800000 |
|
-- |
-- With four netherweave bags: |
-- In backpack, slots 1 -> 16 |
-- |
-- 001100000000000000000001 |
-- 001100000000000000000010 |
-- ... |
-- 001100000000000000010000 |
-- |
-- First bag, slots 1 -> 16 |
-- |
-- 010000000000000100000001 |
-- ... |
-- 010000000000000100010000 |
-- |
-- Second bag, slots 1 -> 16 |
-- |
-- 010000000000001000000001 |
-- ... |
-- 010000000000001000010000 |
-- |
-- Third bag, slots 1 -> 16 |
-- |
-- 010000000000010000000001 |
-- ... |
-- 010000000000010000010000 |
-- |
-- Fourth bag, slots 1 -> 16 |
-- |
-- 010000000000100000000001 |
-- ... |
-- 010000000000100000010000 |
-- |
-- Hands(10) |
-- 000100000000000000001010 |
-- |
-- Waist(6) |
-- 000100000000000000000110 |
-- |
-- Finger0(11) |
-- 000100000000000000001011 |
-- |
-- Finger1(12) |
-- 000100000000000000001011 |
--]] |