vanilla-wow-addons – Rev 1
?pathlinks?
OUTFITDISPLAYFRAME_VERSION = "0.5.6";
OUTFITDISPLAYFRAME_NAME = "Outfit Display Frame";
OUTFITDISPLAYFRAME_TITLE = OUTFITDISPLAYFRAME_NAME.." v"..OUTFITDISPLAYFRAME_VERSION;
OUTFITDISPLAYFRAME_BANKDELAY = 0.5;
local PlayerSlotNames = {
[1] = { name = "HeadSlot", tooltip = HEADSLOT };
[2] = { name = "NeckSlot", tooltip = NECKSLOT },
[3] = { name = "ShoulderSlot", tooltip = SHOULDERSLOT },
[4] = { name = "BackSlot", tooltip = BACKSLOT },
[5] = { name = "ChestSlot", tooltip = CHESTSLOT },
[6] = { name = "ShirtSlot", tooltip = SHIRTSLOT },
[7] = { name = "TabardSlot", tooltip = TABARDSLOT },
[8] = { name = "WristSlot", tooltip = WRISTSLOT },
[9] = { name = "HandsSlot", tooltip = HANDSSLOT },
[10] = { name = "WaistSlot", tooltip = WAISTSLOT },
[11] = { name = "LegsSlot", tooltip = LEGSSLOT },
[12] = { name = "FeetSlot", tooltip = FEETSLOT },
[13] = { name = "Finger0Slot", tooltip = FINGER0SLOT },
[14] = { name = "Finger1Slot", tooltip = FINGER1SLOT },
[15] = { name = "Trinket0Slot", tooltip = TRINKET0SLOT },
[16] = { name = "Trinket1Slot", tooltip = TRINKET1SLOT },
[17] = { name = "MainHandSlot", tooltip = MAINHANDSLOT },
[18] = { name = "SecondaryHandSlot", tooltip = SECONDARYHANDSLOT },
[19] = { name = "RangedSlot", tooltip = RANGEDSLOT },
}
local SavedPickupContainerItem = nil;
local SavedPickupInventoryItem = nil;
local LastOffSource = nil;
local PerformSlowerSwap = false;
local BankIsOpen = false;
local function tonil(val)
if ( not val ) then
return "nil";
else
return val;
end
end
local function Print(msg, r, g, b)
if ( DEFAULT_CHAT_FRAME ) then
if ( not r ) then
DEFAULT_CHAT_FRAME:AddMessage(msg);
else
DEFAULT_CHAT_FRAME:AddMessage(msg, r, g, b);
end
end
end
-- Based on code in QuickMountEquip
local function SafeHookFunction(func, newfunc)
local oldValue = getglobal(func);
if ( oldValue ~= getglobal(newfunc) ) then
setglobal(func, getglobal(newfunc));
return true;
end
return false;
end
-- this really ought to be in a library somewhere
local function SplitLink(link)
local _,_, color, item, name = string.find(link, "|c(%x+)|Hitem:(%d+:%d+:%d+:%d+)|h%[(.-)%]|h|r");
return color, item, name;
end
function OutfitDisplayFrame_OnLoad()
local temp = PickupContainerItem;
if ( SafeHookFunction("PickupContainerItem", "OutfitDisplayFrame_PickupContainerItem") ) then
SavedPickupContainerItem = temp;
end
temp = PickupInventoryItem;
if ( SafeHookFunction("PickupInventoryItem", "OutfitDisplayFrame_PickupInventoryItem") ) then
SavedPickupInventoryItem = temp;
end
local parent = this:GetName();
for i=1,19,1 do
local slotName = PlayerSlotNames[i].name;
local button = getglobal(parent..slotName);
button.tooltip = PlayerSlotNames[i].tooltip;
OutfitDisplayItemButton_Draw(button);
PlayerSlotNames[i].id = GetInventorySlotInfo(slotName);
end
-- ideas borrowed from "WeaponQuickSwap - by CapnBry"
this:RegisterEvent("ITEM_LOCK_CHANGED");
this:RegisterEvent("BANKFRAME_OPENED");
this:RegisterEvent("BANKFRAME_CLOSED");
Print(OUTFITDISPLAYFRAME_TITLE.." loaded.");
end
local function DressUpItem(model, thing)
if ( not model or not thing or thing == "" ) then
return;
end
local item = gsub(thing, "(%d+).*", "%1", 1);
model:TryOn(item);
end
local BankFrameClosedTime = 0;
function OutfitDisplayFrame_OnEvent(...)
if ( arg[1] == "BANKFRAME_OPENED" or arg[1] == "BANKFRAME_CLOSED" ) then
BankFrameIsOpen = ( arg[1] == "BANKFRAME_OPENED" );
local frame = getglobal(this:GetName().."MessageUpdateFrame");
if ( frame ) then
BankFrameClosedTime = OUTFITDISPLAYFRAME_BANKDELAY;
frame:Show();
end
elseif (arg[1] == "ITEM_LOCK_CHANGED") and not arg[2] then
return OutfitDisplayFrame_ExecuteSwapIteration();
end
end
function OutfitDisplayFrame_MessageUpdate(elapsed)
BankFrameClosedTime = BankFrameClosedTime - elapsed;
if ( BankFrameClosedTime <= 0 ) then
this:Hide();
OutfitDisplayFrame_UpdateMessage(this:GetParent());
BankFrameClosedTime = 0;
end
end
local function GetSlotButton(button, slotName)
local parent = button:GetParent():GetName();
return getglobal(parent..slotName);
end
local function IsItemOneHanded(item)
if ( item ) then
local _,_,_,_,_,_,_,bodyslot = GetItemInfo("item:"..item);
if ( bodyslot == "INVTYPE_2HWEAPON" or bodyslot == INVTYPE_2HWEAPON ) then
return false;
end
end
return true;
end
function OutfitDisplayFrame_CursorCanGoInSlot(button)
if ( button.forced ) then
return false;
end
local secondary = GetSlotButton(button, "SecondaryHandSlot");
local mainbutton = GetSlotButton(button, "MainHandSlot");
if ( button == secondary and mainbutton and mainbutton.item ) then
return IsItemOneHanded(mainbutton.item);
end
return CursorCanGoInSlot(button:GetID())
end
-- much hackery to know what actually is in the cursor when somebody drops it on us
local OD_Track_Bag = nil;
local OD_Track_Slot = nil;
-- whatever we think the user picked up, apply it to our stuff
local function AcceptCursorItem(button)
local parent = button:GetParent();
local pname = parent:GetName();
if ( not OutfitDisplayFrame_CursorCanGoInSlot(button) ) then
button = nil;
for i=1,19,1 do
local temp = getglobal(pname..PlayerSlotNames[i].name);
if ( temp and OutfitDisplayFrame_CursorCanGoInSlot(temp) ) then
button = temp;
end
end
end
if ( button ) then
local link, texture;
if ( OD_Track_Bag ) then
link = GetContainerItemLink(OD_Track_Bag, OD_Track_Slot);
texture = GetContainerItemInfo(OD_Track_Bag, OD_Track_Slot);
else
link = GetInventoryItemLink("player", OD_Track_Slot);
texture = GetInventoryItemTexture("player", OD_Track_Slot);
end
button.color, button.item, button.name = SplitLink(link);
button.texture = texture;
button.used = true;
button.empty = nil;
button.missing = false;
if ( OD_Track_Bag and (OD_Track_Bag == BANK_CONTAINER or
OD_Track_Bag > NUM_BAG_SLOTS) ) then
button.banked = true;
end
OutfitDisplayItemButton_Change(button);
end
-- clear the cursor item
if ( OD_Track_Bag ) then
SavedPickupContainerItem(OD_Track_Bag, OD_Track_Slot);
elseif ( OD_Track_Slot ) then
SavedPickupInventoryItem(OD_Track_Slot);
end
OD_Track_Bag = nil;
OD_Track_Slot = nil;
end
-- figure out what the user picked up, so that if they drop it on us we can deal with it
function OutfitDisplayFrame_TrackItemPickup(bag, slot)
OD_Track_Bag = bag;
OD_Track_Slot = slot;
end
function OutfitDisplayFrame_PickupContainerItem(bag, slot)
if ( SavedPickupContainerItem ) then
SavedPickupContainerItem(bag, slot);
end
OutfitDisplayFrame_TrackItemPickup(bag, slot);
end
function OutfitDisplayFrame_PickupInventoryItem(slot)
if ( SavedPickupInventoryItem ) then
SavedPickupInventoryItem(slot);
end
OutfitDisplayFrame_TrackItemPickup(nil, slot);
end
-- handle making the items in the outfit pane do nice things
function OutfitDisplayItemButton_OnEnter()
if ( GameTooltip.finished ) then
return;
end
GameTooltip.finished = 1;
GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
if (this.item) then
local link = "item:"..this.item;
if ( GetItemInfo(link) ) then
GameTooltip:SetHyperlink(link);
elseif ( this.name ) then
GameTooltip:SetText(this.name);
elseif ( this.tooltip ) then
GameTooltip:SetText(this.tooltip);
else
GameTooltip:SetText("<unlinkable item>", 1, 0, 0);
end
elseif ( this.tooltip ) then
GameTooltip:AddLine(this.tooltip);
else
local parentlen = string.len(this:GetParent():GetName())+1;
local slotName = strsub(this:GetName(), parentlen);
slotName = strsub(slotName, 1, string.len(slotName) - 4);
this.tooltip = slotName;
GameTooltip:AddLine(this.tooltip);
end
GameTooltip:AddLine(OUTFITDISPLAYFRAME_ALTCLICK,.8,.8,.8,1);
GameTooltip:Show();
end
function OutfitDisplayItemButton_OnEvent(event)
if ( event == "CURSOR_UPDATE" ) then
if ( not this.forced ) then
if ((this.CursorCanGoInSlot and this.CursorCanGoInSlot(this)) or
OutfitDisplayFrame_CursorCanGoInSlot(this)) then
this:LockHighlight();
else
this:UnlockHighlight();
end
end
end
end
function OutfitDisplayItemButton_OnClick(clicked, ignoreModifiers)
if ( clicked == "LeftButton" ) then
if( not ignoreModifiers or ignoreModifiers == 0 ) then
if ( IsShiftKeyDown() ) then
if ( this.item and ChatFrameEditBox:IsVisible() ) then
local color = this.color;
if ( not color ) then
color = "ffffffff";
end
local link = "|c"..color.."|Hitem"..this.item.."|h["..this.name.."]|h|r";
ChatFrameEditBox:Insert(link);
return;
end
elseif ( IsAltKeyDown() ) then
OutfitDisplayItemButton_Clear(this, false, false);
OutfitDisplayItemButton_Change(this);
return;
end
end
-- fall through for drags and non-modified clicks
if ( CursorHasItem() ) then
AcceptCursorItem(this);
end
end
end
function OutfitDisplayItemButton_OnLoad()
local parentlen = string.len(this:GetParent():GetName())+1;
local slotName = strsub(this:GetName(), parentlen);
local id;
local textureName;
id, textureName = GetInventorySlotInfo(slotName);
this:SetID(id);
this.backgroundTextureName = textureName;
SetItemButtonTexture(this, this.backgroundTextureName);
this:RegisterForDrag("LeftButton");
this:RegisterForClicks("LeftButtonUp", "RightButtonUp");
this:RegisterEvent("CURSOR_UPDATE");
end
function OutfitDisplayItemButton_Draw(button)
if ( button.texture ) then
SetItemButtonTexture(button, button.texture);
else
SetItemButtonTexture(button, button.backgroundTextureName);
end
if ( button.missing ) then
SetItemButtonTextureVertexColor(button, 1.0, 0.1, 0.1);
elseif ( button.banked ) then
SetItemButtonTextureVertexColor(button, 0.1, 0.1, 1.0);
else
SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0);
end
local checkbox = getglobal(button:GetName().."CheckBox");
if (checkbox) then
local pname = button:GetParent():GetName();
local showhelm = getglobal(pname.."ShowHelm");
local showcloak = getglobal(pname.."ShowCloak");
if ( button.forced ) then
checkbox:SetChecked(true);
checkbox:Disable();
checkbox:Show();
elseif ( button.empty or not button.used ) then
if ( checkbox.slotName == "HeadSlot" ) then
showhelm:Hide();
showhelm:SetChecked(false);
elseif ( checkbox.slotName == "BackSlot" ) then
showcloak:Hide();
showcloak:SetChecked(false);
end
checkbox:Enable();
checkbox:SetChecked(button.empty);
checkbox:Show();
elseif ( button.used ) then
checkbox:Hide();
if ( checkbox.slotName == "HeadSlot" ) then
showhelm:Show();
elseif ( checkbox.slotName == "BackSlot" ) then
showcloak:Show();
end
end
end
end
function OutfitDisplayItemButton_Change(button)
OutfitDisplayItemButton_Draw(button);
-- handle two handed weapons
local parent = button:GetParent();
local pname = parent:GetName();
local parentlen = string.len(pname)+1;
local slotName = strsub(button:GetName(), parentlen);
if ( slotName == "MainHandSlot" ) then
local secondary = getglobal(pname.."SecondaryHandSlot");
if ( not button.used and secondary.forced ) then
OutfitDisplayItemButton_Clear(secondary, false, false);
elseif ( button.used and not IsItemOneHanded(button.item) ) then
OutfitDisplayItemButton_Clear(secondary, true);
secondary.forced = true;
end
OutfitDisplayItemButton_Draw(secondary);
end
OutfitDisplayFrame_UpdateMessage(parent);
OutfitDisplayFrame_UpdateModel(parent, button);
if( parent.OutfitChanged ) then
parent.OutfitChanged( button );
end
end
function OutfitDisplayItemButton_Clear(button, empty, used)
button.name = nil;
button.item = nil;
button.texture = nil;
button.color = nil;
button.missing = nil;
button.banked = nil;
button.forced = nil;
button.empty = empty;
button.used = used or empty;
end
-- override ShowHelm and ShowCloak
function OutfitDisplayOverrideBox_OnLoad()
local parentlen = string.len(this:GetParent():GetName())+1;
this.slotName = strsub(this:GetName(), parentlen);
end
function OutfitDisplayOverrideBox_OnEnter()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
local text;
if ( this.slotName == "ShowHelm" ) then
text = OUTFITDISPLAYFRAME_OVERRIDEHELM;
else
text = OUTFITDISPLAYFRAME_OVERRIDECLOAK;
end
GameTooltip:SetText(text, nil, nil, nil, nil, 1);
GameTooltip:Show();
end
-- check box handling
function OutfitDisplayCheckBox_OnEnter()
GameTooltip:SetOwner(this, "ANCHOR_RIGHT");
GameTooltip:SetText(OUTFITDISPLAYFRAME_USECHECKBOX, nil, nil, nil, nil, 1);
GameTooltip:Show();
end
function OutfitDisplayCheckBox_OnLoad()
local parentlen = string.len(this:GetParent():GetName())+1;
local name = strsub(this:GetName(), parentlen);
this.slotName = strsub(name, 1, -9);
end
function OutfitDisplayCheckBox_OnClick()
local pname = this:GetParent():GetName();
local button = getglobal(pname..this.slotName);
OutfitDisplayItemButton_Clear(button, this:GetChecked());
OutfitDisplayItemButton_Change(button);
end
local function UpdateModel_ThisSlot(pname, model, idx)
local slotName = PlayerSlotNames[idx].name;
local what = getglobal(pname..slotName);
local item = nil;
if ( what and what.used ) then
if ( not what.empty ) then
item = what.item;
end
else
local slot = PlayerSlotNames[idx].id;
local link = GetInventoryItemLink("player", slot);
if ( link ) then
_, item, _ = SplitLink(link);
end
end
if ( item ) then
DressUpItem(model, item);
end
end
function OutfitDisplayFrame_UpdateModel(frame, button)
local pname = frame:GetName();
local model = getglobal(pname.."Model");
local empty = false;
if ( not model ) then
return;
end
if ( button and button.used ) then
if ( button.empty and not button.forced ) then
empty = true;
end
else
for i=1,19,1 do
local what = getglobal(pname..PlayerSlotNames[i].name);
if ( what and what.empty ) then
empty = true;
end
end
end
if ( empty ) then
model:Undress();
end
for i=19,1,-1 do
UpdateModel_ThisSlot(pname, model, i);
end
end
function OutfitDisplayFrame_SetOutfit(frame, outfit)
if not outfit then
return;
end
local pname = frame:GetName();
for i=1,19,1 do
local slotName = PlayerSlotNames[i].name;
local button = getglobal(pname..slotName);
if ( button and outfit[slotName] and outfit[slotName].used ) then
OutfitDisplayItemButton_Clear(button);
if ( outfit[slotName].used ) then
button.name = outfit[slotName].name;
button.item = outfit[slotName].item;
button.texture = outfit[slotName].texture;
button.color = outfit[slotName].color;
button.missing = outfit[slotName].missing;
button.banked = outfit[slotName].banked;
button.forced = outfit[slotName].forced;
button.empty = outfit[slotName].empty;
button.used = true;
else
OutfitDisplayItemButton_Clear(button, true, true);
end
OutfitDisplayItemButton_Draw(button);
end
end
if ( outfit["Options"] ) then
local showhelm = getglobal(pname.."ShowHelm");
local showcloak = getglobal(pname.."ShowCloak");
showhelm:SetChecked(outfit["Options"].helm);
showcloak:SetChecked(outfit["Options"].cloak);
end
OutfitDisplayFrame_UpdateModel(frame);
OutfitDisplayFrame_UpdateMessage(frame, outfit);
end
function OutfitDisplayFrame_GetOutfit(frame, puthere)
local pname = frame:GetName();
local outfit = puthere or nil;
local showhelm = getglobal(pname.."ShowHelm");
local showcloak = getglobal(pname.."ShowCloak");
local setOptions = false;
if not outfit then
outfit = {};
end
outfit["Options"] = {};
for i=1,19,1 do
local slotName = PlayerSlotNames[i].name;
local button = getglobal(pname..slotName);
if ( button and button.used ) then
outfit[slotName] = {};
if ( not button.empty ) then
outfit[slotName].name = button.name;
outfit[slotName].item = button.item;
outfit[slotName].texture = button.texture;
outfit[slotName].color = button.color;
outfit[slotName].missing = button.missing;
outfit[slotName].banked = button.banked;
outfit[slotName].forced = button.forced;
end
outfit[slotName].empty = button.empty;
outfit[slotName].used = true;
if ( not button.empty ) then
if ( slotName == "HeadSlot" ) then
if ( showhelm and showhelm:GetChecked() ) then
outfit["Options"].helm = true;
setOptions = true;
end
elseif ( slotName == "BackSlot" ) then
if ( showcloak and showcloak:GetChecked() ) then
outfit["Options"].cloak = true;
setOptions = true;
end
end
end
elseif ( outfit and outfit.used ) then
outfit[slotName] = nil;
end
end
if ( not setOptions ) then
outfit["Options"] = nil;
end
if ( outfit ) then
-- check for two-handed weapon
local mainhand = outfit["MainHandSlot"];
if ( mainhand and not IsItemOneHanded(mainhand.item) ) then
outfit["SecondaryHandSlot"] = {};
outfit["SecondaryHandSlot"].forced = true;
outfit["SecondaryHandSlot"].empty = true;
outfit["SecondaryHandSlot"].used = true;
end
end
return outfit;
end
function OutfitDisplayFrame_GetItemInfo(bag, slot)
local link;
local c, i, n;
if ( bag ) then
link = GetContainerItemLink (bag,slot);
else
link = GetInventoryItemLink("player", slot);
end
if (link) then
c, i, n = SplitLink(link);
end
return c, i, n;
end
-- get a snapshot of the current state of the player
function OutfitDisplayFrame_GetBagInfo()
local contents = {};
local empties = {};
local numSlots = 0;
-- check each of the bags on the player
for bag=0, NUM_BAG_FRAMES do
-- get the number of slots in the bag (0 if no bag)
numSlots = GetContainerNumSlots(bag);
if (numSlots > 0) then
-- check each slot in the bag
for slot=1, numSlots do
local c, i, n = OutfitDisplayFrame_GetItemInfo(bag, slot);
if ( i ) then
contents[i] = {};
contents[i].bag = bag;
contents[i].slot = slot;
contents[i].color = c;
contents[i].name = n;
else
local what = {};
what.bag = bag;
what.slot = slot;
tinsert(empties, what);
end
end
end
end
for idx=1,19,1 do
local slot = PlayerSlotNames[idx].id;
local c, i, n = OutfitDisplayFrame_GetItemInfo(nil, slot);
if ( i ) then
contents[i] = {};
contents[i].slot = slot;
contents[i].color = c;
contents[i].name = n;
end
end
return contents, empties;
end
-- look in a particular bag
local function CheckThisBag(bag, id, skipcount)
-- get the number of slots in the bag (0 if no bag)
local numSlots = GetContainerNumSlots(bag);
if (numSlots > 0) then
-- check each slot in the bag
for slot=1, numSlots do
local c, i, n = OutfitDisplayFrame_GetItemInfo(bag, slot);
if ( i and id == i ) then
if ( skipcount == 0 ) then
return slot, skipcount;
end
skipcount = skipcount - 1;
end
end
end
return nil, skipcount;
end
-- look for the outfit anywhere we can find it
local function FindThisItem(id, skipcount)
if ( not id ) then
return nil,nil,nil;
end
local skipcount = skipcount or 0;
-- check each of the bags on the player
for bag=0, NUM_BAG_FRAMES do
local slot;
slot, skipcount = CheckThisBag(bag, id, skipcount);
if ( slot ) then
return bag, slot, false;
end
end
for idx=1,19,1 do
local slot = PlayerSlotNames[idx].id;
local c, i, n = OutfitDisplayFrame_GetItemInfo(nil, slot);
if ( (id and i and id == i) or (name and n and name == n) ) then
if ( skipcount == 0 ) then
return nil, slot, false;
end
skipcount = skipcount - 1;
end
end
-- look in the bank
-- Geez, this is ugly
local bankbags = { BANK_CONTAINER, 5, 6, 7, 8, 9, 10 };
for b=1,7 do
local slot;
slot, skipcount = CheckThisBag(bankbags[b], id, skipcount);
if ( slot ) then
return bankbags[b], slot, true;
end
end
-- return nil, nil, nil;
end
-- look for the outfit anywhere we can find it
-- we should look in the bank someday
function OutfitDisplayFrame_FindOutfit(outfit)
-- look for every item, if we find everything return a table of locations
-- otherwise don't return anything
if ( not outfit ) then
return nil;
end
local spots = { };
for slotName in outfit do
if ( outfit[slotName].use and not outfit[slotName].empty ) then
local bag, slot = FindThisItem( outfit[slotName].item );
if ( not bag and not slot ) then
spots = nil;
return nil;
else
spots[slotName] = { };
spots[slotName].bag = bag;
spots[slotName].slot = slot;
end
end
end
return spots;
end
function OutfitDisplayFrame_CanFindOutfit(outfit)
if ( not outfit ) then
return false;
end
for slotName in outfit do
if ( outfit[slotName].used and not outfit[slotName].empty ) then
local bag, slot = FindThisItem( outfit[slotName].item );
if ( not bag and not slot ) then
return false;
end
end
end
return true;
end
local function CheckSwitchWillFail(frame, outfit)
local contents, empties = OutfitDisplayFrame_GetBagInfo();
local numfree = table.getn(empties);
local needfree = 0;
local missing = false;
local banked = false;
for i=1,19,1 do
local slotName = PlayerSlotNames[i].name;
local check;
if ( outfit ) then
check = outfit[slotName];
else
check = getglobal(frame:GetName()..slotName);
end
if ( check and check.used ) then
if ( not check.empty ) then
local bag, slot, inbank = FindThisItem( check.item );
if ( not bag and not slot ) then
-- pretend it's still in the bank and we just can't get it
if ( check.banked ) then
check.banked = true;
banked = true;
else
missing = true;
end
check.missing = not check.banked;
else
check.missing = nil;
check.banked = inbank;
end
else
local slot = PlayerSlotNames[i].id;
if ( OutfitDisplayFrame_GetItemInfo(nil, slot) ) then
needfree = needfree + 1;
end
end
end
end
if ( missing ) then
return OUTFITDISPLAYFRAME_ITEMSNOTFOUND;
end
if ( banked and not BankIsOpen ) then
return OUTFITDISPLAYFRAME_ITEMSINBANK;
end
if ( needfree > numfree ) then
return OUTFITDISPLAYFRAME_NOTENOUGHFREESPACE;
end
return nil;
end
function OutfitDisplayFrame_SwitchWillFail(frame, outfit)
if ( not outfit ) then
return OUTFITDISPLAYFRAME_INVALIDOUTFIT;
end
-- if we're swapping, fail early
if ( OutfitDisplayFrame_IsSwapping() ) then
return OUTFITDISPLAYFRAME_TOOFASTMSG;
end
return CheckSwitchWillFail(frame, outfit);
end
function OutfitDisplayFrame_IsWearing(outfit)
if ( not outfit ) then
return false;
end
for slotName in outfit do
if ( outfit[slotName].used and not outfit[slotName].empty ) then
local slot = GetInventorySlotInfo(slotName);
local link = GetInventoryItemLink("player", slot);
local foundit = false;
if ( link ) then
local color, item, name = SplitLink(link);
if ( item == outfit[slotName].item ) then
foundit = true;
end
end
if ( not foundit ) then
return false;
end
end
end
return true;
end
function OutfitDisplayFrame_UpdateMessage(frame, outfit)
if ( frame and outfit ) then
local msg = CheckSwitchWillFail(frame, outfit);
local messages = getglobal(frame:GetName().."Message");
if ( msg ) then
messages:Show();
messages:SetText(msg);
messages:SetTextColor(1, 1, 1);
else
messages:SetText("");
messages:Hide();
end
end
end
function OutfitDisplayFrame_GetSlotContents(slotName, returnEmpty)
if ( slotName ~= "Options" ) then
local slot = GetInventorySlotInfo(slotName);
local link = GetInventoryItemLink("player", slot);
if ( link ) then
local contents = {};
local color, item, name = SplitLink(link);
contents.item = item;
contents.name = name;
contents.color = color;
contents.texture = texture;
contents.used = true;
local bag, slot = FindThisItem( item );
contents.bag = bag;
contents.slot = slot;
return contents;
end
end
-- return nil;
end
function OutfitDisplayFrame_GetWearing(check)
local wearing = {};
if ( check ) then
for slotName in check do
wearing[slotName] = OutfitDisplayFrame_GetSlotContents(slotName);
end
-- make sure we pick up the off hand if we're going to put something
-- two-handed in the main hand slot
local mainhand = check["MainHandSlot"];
local offhand = wearing["SecondaryHandSlot"];
if ( not offhand and mainhand and not IsItemOneHanded(mainhand.item) ) then
wearing["SecondaryHandSlot"] = OutfitDisplayFrame_GetSlotContents("SecondaryHandSlot");
end
else
for i=1,19,1 do
local slotName = PlayerSlotNames[i].name;
wearing[slotName] = OutfitDisplayFrame_GetSlotContents(slotName);
end
end
if ( not ShowingCloak() or not ShowingHelm() ) then
wearing["Options"] = {}
wearing["Options"].cloak = not(not ShowingCloak());
wearing["Options"].helm = not(not ShowingHelm());
end
return wearing;
end
function OutfitDisplayFrame_FindLastEmptyBagSlot(skipcount, bag_affinity, slot_affinity)
skipcount = skipcount or 0;
-- try to put the item in the requested affinity, if possible
if bag_affinity and slot_affinity and
not GetContainerItemInfo(bag_affinity, slot_affinity) then
return bag_affinity, slot_affinity;
end
-- if we couldn't get the bag and slot we wanted, just try the same bag
if bag_affinity then
for j=GetContainerNumSlots(bag_affinity),1,-1 do
if not GetContainerItemInfo(bag_affinity,j) then
if skipcount == 0 then return bag_affinity,j; end
skipcount = skipcount - 1;
end
end
end
-- no affinity, check all bags
for i=NUM_BAG_FRAMES,0,-1 do
-- but skip any bag we already have affinity for (because it might have
-- already modified skipcount)
if bag_affinity ~= i then
-- Make sure this isn't a quiver, those won't hold shit
local bagName = GetBagName(i);
if ( bagName ) then
local texture = GetInventoryItemTexture("player",
ContainerIDToInventoryID(i));
if ( string.find(texture, "INV_Misc_Bag_%d") and not string.find(bagName, AMMOSLOT) ) then
for j=GetContainerNumSlots(i),1,-1 do
if not GetContainerItemInfo(i,j) then
if skipcount == 0 then return i,j; end
skipcount = skipcount - 1;
end -- if empty
end -- for slots
end -- if normal bag
end -- if there is a bag
end -- if not affinity bag
end -- for bags
-- not found return nil,nil implicitly
end
-- okay, let's switch to the specified outfit
-- code liberally borrowed from "WeaponQuickSwap - by CapnBry"
-- list functions
local function swapentry_print(entry)
if ( DEFAULT_CHAT_FRAME ) then
local msg = "Entry "..tonil(entry.sb)..","..tonil(entry.si)..","..tonil(entry.db)..","..tonil(entry.di);
DEFAULT_CHAT_FRAME:AddMessage(msg, 1.0,0,0);
end
end
local function swaplist_print(list)
while ( list ) do
swapentry_print(list);
list = list.next;
end
end
local function swaplist_push(list, sb, si, db, di, helm, cloak)
list = { next = list, sb = sb, si = si, db = db, di = di,
helm = helm, cloak = cloak };
return list;
end
local function swaplist_popfirst(list)
if not list then return; end
list = list.next;
return list;
end
-- Unit variable to hold the stack of swaps
local outfitswap = nil;
function OutfitDisplayFrame_IsSwapping()
if ( outfitswap or OutfitDisplayFrame_AnyItemLocked() ) then
return true;
else
return false;
end
end
-- First we do everything except the main hand and secondary hand
-- Then we do the hard stuff
function OutfitDisplayFrame_ItemIsLocked(bag, slot)
if not bag and not slot then
return false;
end
if not bag then
return IsInventoryItemLocked(slot);
else
local _,_,locked = GetContainerItemInfo(bag,slot);
return locked;
end
end
function OutfitDisplayFrame_AnyItemLocked()
-- Checks all the bags and the equipped slots to see if any are still locked
for i=0,NUM_BAG_FRAMES do
for j=1,GetContainerNumSlots(i) do
local _,_,locked = GetContainerItemInfo(i,j);
if ( locked ) then
return true;
end
end
end
for i=1,19,1 do
if ( IsInventoryItemLocked(PlayerSlotNames[i].id) ) then
return true;
end
end
return false;
end
function OutfitDisplayFrame_ExecuteSwapIteration()
if not outfitswap then
PerformSlowerSwap = false;
return;
end
if OutfitDisplayFrame_ItemIsLocked(outfitswap.sb, outfitswap.si) or
OutfitDisplayFrame_ItemIsLocked(outfitswap.db, outfitswap.di) then
return;
end
if not outfitswap.sb then
SavedPickupInventoryItem(outfitswap.si);
else
SavedPickupContainerItem(outfitswap.sb, outfitswap.si);
end
if not outfitswap.db then
if not outfitswap.di then
PutItemInBackpack();
else
SavedPickupInventoryItem(outfitswap.di);
end
else
SavedPickupContainerItem(outfitswap.db, outfitswap.di);
end
if ( outfitswap.cloak ~= nil ) then
ShowCloak(outfitswap.cloak);
elseif ( outfitswap.helm ~= nil ) then
ShowHelm(outfitswap.helm);
end
outfitswap = swaplist_popfirst(outfitswap);
if ( outfitswap and not PerformSlowerSwap ) then
return OutfitDisplayFrame_ExecuteSwapIteration();
end
end
function OutfitDisplayFrame_SwitchOne(outfit, index, skipcount, showhelm, showcloak)
local slotName = PlayerSlotNames[index].name;
if ( outfit and outfit[slotName] ) then
local invslot = GetInventorySlotInfo(slotName);
if ( outfit[slotName].empty ) then
local bag, slot = OutfitDisplayFrame_FindLastEmptyBagSlot(skipcount);
outfitswap = swaplist_push(outfitswap, nil, invslot, bag, slot);
skipcount = skipcount + 1;
else
local helmflag, cloakflag;
if ( slotName == "HeadSlot" ) then
helmflag = showhelm;
elseif ( slotName == "BackSlot" ) then
cloakflag = showcloak;
end
local bag, slot = FindThisItem( outfit[slotName].item );
-- either we couldn't find it, or it's where it should be
if ( bag ~= nil or slot ~= invslot ) then
outfitswap = swaplist_push(outfitswap, bag, slot, nil, invslot, helmflag, cloakflag);
end
end
end
return skipcount;
end
local function OnSwapError(error)
outfitswap = nil;
if ( UIErrorsFrame ) then
UIErrorsFrame:AddMessage(error, 1.0, 0.1, 0.1, 1.0, UIERRORS_HOLD_TIME);
end
return;
end
function OutfitDisplayFrame_SwitchOutfit(outfit)
if ( CursorHasItem() or OutfitDisplayFrame_IsSwapping() ) then
return OnSwapError(OUTFITDISPLAYFRAME_TOOFASTMSG);
end
if ( not outfit ) then
return OnSwapError(OUTFITDISPLAYFRAME_INVALIDOUTFIT);
end
-- might not need to swap slowly
PerformSlowerSwap = false;
-- need to check to see that we have enough room
local old = OutfitDisplayFrame_GetWearing(outfit);
local showcloak;
local showhelm;
if ( outfit["Options"] ) then
showhelm = outfit["Options"].helm;
showcloak = outfit["Options"].cloak;
end
-- do everything except weapon slots
local skipcount = 0;
for i=1,16,1 do
skipcount = OutfitDisplayFrame_SwitchOne(outfit, i, skipcount, showhelm, showcloak);
end
OutfitDisplayFrame_SwitchOne(outfit, 19, skipcount);
if ( not outfit["MainHandSlot"] and not outfit["SecondaryHandSlot"] ) then
OutfitDisplayFrame_ExecuteSwapIteration();
return old;
end
local mainhandslot = GetInventorySlotInfo("MainHandSlot");
local secondaryslot = GetInventorySlotInfo("SecondaryHandSlot");
local mainhand = outfit["MainHandSlot"];
local offhand = outfit["SecondaryHandSlot"];
-- now do hands
local m_sb;
local m_si;
local o_sb;
local o_si;
local m_ok = not mainhand or not mainhand.item;
local o_ok = not offhand or not offhand.item;
if ( mainhand and mainhand.item ) then
m_sb, m_si = FindThisItem(mainhand.item);
m_ok = ( not m_sb and m_si == mainhandslot );
end
if ( offhand and offhand.item ) then
local multiples = 0;
if ( mainhand and mainhand.item == offhand.item ) then
multiples = 1;
end
o_sb, o_si = FindThisItem( offhand.item, multiples);
o_ok = ( not o_sb and o_si == secondaryslot );
end
if ( not m_ok ) then
-- do we need two of these?
if ( o_ok and not m_sb and m_si == secondaryslot ) then
m_sb, m_si = FindThisItem( mainhand.item, 1);
end
end
-- moving from bags
if ( m_sb and o_sb ) then
-- insert them backwards, since they get popped off
-- main hand has to get done first in case it's currently
-- a two hander
outfitswap = swaplist_push(outfitswap, o_sb, o_si, nil, secondaryslot);
outfitswap = swaplist_push(outfitswap, m_sb, m_si, nil, mainhandslot);
elseif ( not m_sb and m_si == secondaryslot and not o_sb and o_si == mainhandslot ) then
outfitswap = swaplist_push(outfitswap, nil, mainhandslot, nil, secondaryslot);
else
-- Install main hand
if not m_ok then
-- if nothing going to the main hand
if ( not m_sb and not m_si ) then
-- and the main is not going to the off: put it in a bag
if not ( not o_sb and o_si == mainhandslot) then
local bb, bi = OutfitDisplayFrame_FindLastEmptyBagSlot(skipcount);
if not (bb and bi) then
return OnSwapError(OUTFITDISPLAYFRAME_NOTENOUGHFREESPACE);
end
skipcount = skipcount + 1;
outfitswap = swaplist_push(outfitswap, nil, mainhandslot, bb, bi);
-- when moving A,"" -> "",B where A is a 2h, the offhand
-- doesn't lock properly, so work around it by swapping
-- slowly (only one swap per lock notify)
PerformSlowerSwap = not IsItemOneHanded(mainhand.item);
end
else
outfitswap = swaplist_push(outfitswap, m_sb, m_si, nil, mainhandslot);
end
end
-- Load offhand if not already there
if not o_ok then
if ( not o_sb and not o_si ) then
if not (not m_sb and m_si == secondaryslot) then
local bb, bi;
if LastOffSource then
bb, bi = OutfitDisplayFrame_FindLastEmptyBagSlot(skipcount,
LastOffSource.bag, LastOffSource.slot);
else
bb, bi = OutfitDisplayFrame_FindLastEmptyBagSlot(skipcount);
end
if not (bb and bi) then
return OnSwapError(OUTFITDISPLAYFRAME_NOTENOUGHFREESPACE);
end
skipcount = skipcount + 1;
outfitswap = swaplist_push(outfitswap, nil, secondaryslot, bb, bi);
end
else
-- if the main hand weapon is coming from the offhand slot
-- we need to fix up its source to be where the offhand is
-- GOING to be after the bag->off swap
if outfitswap and ( not m_sb and m_si == secondaryslot) then
outfitswap.sb = o_sb;
outfitswap.si = o_si;
-- don't set o_sb, o_si they're tested later
end
outfitswap = swaplist_push(outfitswap, o_sb, o_si, nil, secondaryslot);
end
end
-- Special Case: Moving off to main, and not main to off
-- This is because maybe the main hand weapon is main only
if (not m_sb and m_si == secondaryslot) and not ( not o_sb and o_si == mainhandslot) then
local bb, bi = OutfitDisplayFrame_FindLastEmptyBagSlot(skipcount);
if not (bb and bi) then
return OnSwapError(OUTFITDISPLAYFRAME_NOTENOUGHFREESPACE);
end
skipcount = skipcount + 1;
outfitswap = swaplist_push(outfitswap, nil, mainhandslot, bb, bi);
end
-- Same thing for off hand
if (not o_sb and o_si == mainhandslot) and not (not m_sb and m_si == secondaryslot) then
local bb, bi = OutfitDisplayFrame_FindLastEmptyBagSlot(skipcount);
if not (bb and bi) then
return OnSwapError(OUTFITDISPLAYFRAME_NOTENOUGHFREESPACE);
end
skipcount = skipcount + 1;
outfitswap = swaplist_push(outfitswap, nil, mainhandslot, bb, bi);
end
if o_sb then
LastOffSource = { bag = o_sb, slot = o_si };
end
end
-- Start moving
OutfitDisplayFrame_ExecuteSwapIteration();
return old;
end