diff --git a/reference/AddOns/Blizzard_AchievementUI/Blizzard_AchievementUI.lua b/reference/AddOns/Blizzard_AchievementUI/Blizzard_AchievementUI.lua
new file mode 100644
index 0000000..217687a
--- /dev/null
+++ b/reference/AddOns/Blizzard_AchievementUI/Blizzard_AchievementUI.lua
@@ -0,0 +1,2889 @@
+UIPanelWindows["AchievementFrame"] = { area = "doublewide", pushable = 0, width = 840, xoffset = 80, whileDead = 1 };
+
+ACHIEVEMENTUI_CATEGORIES = {};
+
+ACHIEVEMENTUI_GOLDBORDER_R = 1;
+ACHIEVEMENTUI_GOLDBORDER_G = 0.675;
+ACHIEVEMENTUI_GOLDBORDER_B = 0.125;
+ACHIEVEMENTUI_GOLDBORDER_A = 1;
+
+ACHIEVEMENTUI_REDBORDER_R = 0.7;
+ACHIEVEMENTUI_REDBORDER_G = 0.15;
+ACHIEVEMENTUI_REDBORDER_B = 0.05;
+ACHIEVEMENTUI_REDBORDER_A = 1;
+
+ACHIEVEMENTUI_CATEGORIESWIDTH = 175;
+
+ACHIEVEMENTUI_PROGRESSIVEHEIGHT = 50;
+ACHIEVEMENTUI_PROGRESSIVEWIDTH = 42;
+
+ACHIEVEMENTUI_MAX_SUMMARY_ACHIEVEMENTS = 4;
+
+ACHIEVEMENTUI_MAXCONTENTWIDTH = 330;
+local ACHIEVEMENTUI_FONTHEIGHT; -- set in AchievementButton_OnLoad
+local ACHIEVEMENTUI_MAX_LINES_COLLAPSED = 3; -- can show 3 lines of text when achievement is collapsed
+
+ACHIEVEMENTUI_DEFAULTSUMMARYACHIEVEMENTS = {6, 503, 116, 545, 1017};
+
+ACHIEVEMENT_CATEGORY_NORMAL_R = 0;
+ACHIEVEMENT_CATEGORY_NORMAL_G = 0;
+ACHIEVEMENT_CATEGORY_NORMAL_B = 0;
+ACHIEVEMENT_CATEGORY_NORMAL_A = .9;
+
+ACHIEVEMENT_CATEGORY_HIGHLIGHT_R = 0;
+ACHIEVEMENT_CATEGORY_HIGHLIGHT_G = .6;
+ACHIEVEMENT_CATEGORY_HIGHLIGHT_B = 0;
+ACHIEVEMENT_CATEGORY_HIGHLIGHT_A = .65;
+
+ACHIEVEMENTBUTTON_LABELWIDTH = 320;
+
+ACHIEVEMENT_COMPARISON_SUMMARY_ID = -1
+ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID = -2
+
+ACHIEVEMENT_FILTER_ALL = 1;
+ACHIEVEMENT_FILTER_COMPLETE = 2;
+ACHIEVEMENT_FILTER_INCOMPLETE = 3;
+
+local FEAT_OF_STRENGTH_ID = 81;
+
+local trackedAchievements = {};
+local function updateTrackedAchievements (...)
+ local count = select("#", ...);
+
+ for i = 1, count do
+ trackedAchievements[select(i, ...)] = true;
+ end
+end
+
+
+-- [[ AchievementFrame ]] --
+
+function AchievementFrame_ToggleAchievementFrame(toggleStatFrame)
+ AchievementFrameComparison:Hide();
+ AchievementFrameTab_OnClick = AchievementFrameBaseTab_OnClick;
+ if ( not toggleStatFrame ) then
+ if ( AchievementFrame:IsShown() and AchievementFrame.selectedTab == 1 ) then
+ HideUIPanel(AchievementFrame);
+ else
+ ShowUIPanel(AchievementFrame);
+ AchievementFrameTab_OnClick(1);
+ end
+ return;
+ end
+ if ( AchievementFrame:IsShown() and AchievementFrame.selectedTab == 2 ) then
+ HideUIPanel(AchievementFrame);
+ else
+ ShowUIPanel(AchievementFrame);
+ AchievementFrameTab_OnClick(2);
+ end
+end
+
+function AchievementFrame_DisplayComparison (unit)
+ AchievementFrame.wasShown = nil;
+ AchievementFrameTab_OnClick = AchievementFrameComparisonTab_OnClick;
+ AchievementFrameTab_OnClick(1);
+ ShowUIPanel(AchievementFrame);
+ --AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameSummary);
+ AchievementFrameComparison_SetUnit(unit);
+ AchievementFrameComparison_ForceUpdate();
+end
+
+function AchievementFrame_OnLoad (self)
+ PanelTemplates_SetNumTabs(self, 2);
+ self.selectedTab = 1;
+ PanelTemplates_UpdateTabs(self);
+end
+
+function AchievementFrame_OnShow (self)
+ PlaySound("AchievementMenuOpen");
+ AchievementFrameHeaderPoints:SetText(GetTotalAchievementPoints());
+ if ( not AchievementFrame.wasShown ) then
+ AchievementFrame.wasShown = true;
+ AchievementCategoryButton_OnClick(AchievementFrameCategoriesContainerButton1);
+ end
+ UpdateMicroButtons();
+ AchievementFrame_LoadTextures();
+end
+
+function AchievementFrame_OnHide (self)
+ PlaySound("AchievementMenuClose");
+ UpdateMicroButtons();
+ AchievementFrame_ClearTextures();
+end
+
+function AchievementFrame_ForceUpdate ()
+ if ( AchievementFrameAchievements:IsShown() ) then
+ AchievementFrameAchievements_ForceUpdate();
+ elseif ( AchievementFrameStats:IsShown() ) then
+ AchievementFrameStats_Update();
+ elseif ( AchievementFrameComparison:IsShown() ) then
+ AchievementFrameComparison_ForceUpdate();
+ end
+end
+
+function AchievementFrameBaseTab_OnClick (id)
+ PanelTemplates_Tab_OnClick(_G["AchievementFrameTab"..id], AchievementFrame);
+
+ local isSummary = false
+ if ( id == 1 ) then
+ achievementFunctions = ACHIEVEMENT_FUNCTIONS;
+ AchievementFrameCategories_GetCategoryList(ACHIEVEMENTUI_CATEGORIES); -- This needs to happen before AchievementFrame_ShowSubFrame (fix for bug 157885)
+ if ( achievementFunctions.selectedCategory == "summary" ) then
+ isSummary = true;
+ AchievementFrame_ShowSubFrame(AchievementFrameSummary);
+ else
+ AchievementFrame_ShowSubFrame(AchievementFrameAchievements);
+ end
+ AchievementFrameWaterMark:SetTexture("Interface\\AchievementFrame\\UI-Achievement-AchievementWatermark");
+ else
+ achievementFunctions = STAT_FUNCTIONS;
+ AchievementFrameCategories_GetCategoryList(ACHIEVEMENTUI_CATEGORIES);
+ if ( achievementFunctions.selectedCategory == "summary" ) then
+ AchievementFrame_ShowSubFrame(AchievementFrameStats);
+ achievementFunctions.selectedCategory = ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID;
+ AchievementFrameStatsContainerScrollBar:SetValue(0);
+ else
+ AchievementFrame_ShowSubFrame(AchievementFrameStats);
+ end
+ AchievementFrameWaterMark:SetTexture("Interface\\AchievementFrame\\UI-Achievement-StatWatermark");
+ end
+
+ AchievementFrameCategories_Update();
+
+ if ( not isSummary ) then
+ achievementFunctions.updateFunc();
+ end
+end
+
+AchievementFrameTab_OnClick = AchievementFrameBaseTab_OnClick;
+
+function AchievementFrameComparisonTab_OnClick (id)
+ if ( id == 1 ) then
+ achievementFunctions = COMPARISON_ACHIEVEMENT_FUNCTIONS;
+ AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonContainer);
+ AchievementFrameWaterMark:SetTexture("Interface\\AchievementFrame\\UI-Achievement-AchievementWatermark");
+ else
+ achievementFunctions = COMPARISON_STAT_FUNCTIONS;
+ AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonStatsContainer);
+ AchievementFrameWaterMark:SetTexture("Interface\\AchievementFrame\\UI-Achievement-StatWatermark");
+ end
+
+ AchievementFrameCategories_GetCategoryList(ACHIEVEMENTUI_CATEGORIES);
+ AchievementFrameCategories_Update();
+ PanelTemplates_Tab_OnClick(_G["AchievementFrameTab"..id], AchievementFrame);
+
+ achievementFunctions.updateFunc();
+end
+
+ACHIEVEMENTFRAME_SUBFRAMES = {
+ "AchievementFrameSummary",
+ "AchievementFrameAchievements",
+ "AchievementFrameStats",
+ "AchievementFrameComparison",
+ "AchievementFrameComparisonContainer",
+ "AchievementFrameComparisonStatsContainer"
+};
+
+function AchievementFrame_ShowSubFrame(...)
+ local subFrame, show;
+ for _, name in next, ACHIEVEMENTFRAME_SUBFRAMES do
+ subFrame = _G[name];
+ show = false;
+ for i=1, select("#", ...) do
+ if ( subFrame == select(i, ...)) then
+ show = true
+ end
+ end
+ if ( show ) then
+ subFrame:Show();
+ else
+ subFrame:Hide();
+ end
+ end
+end
+
+-- [[ AchievementFrameCategories ]] --
+
+function AchievementFrameCategories_OnLoad (self)
+ self:SetBackdropBorderColor(ACHIEVEMENTUI_GOLDBORDER_R, ACHIEVEMENTUI_GOLDBORDER_G, ACHIEVEMENTUI_GOLDBORDER_B, ACHIEVEMENTUI_GOLDBORDER_A);
+ self.buttons = {};
+ self:RegisterEvent("ADDON_LOADED");
+ self:SetScript("OnEvent", AchievementFrameCategories_OnEvent);
+end
+
+function AchievementFrameCategories_OnEvent (self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local addonName = ...;
+ if ( addonName and addonName ~= "Blizzard_AchievementUI" ) then
+ return;
+ end
+
+ AchievementFrameCategories_GetCategoryList(ACHIEVEMENTUI_CATEGORIES);
+
+ AchievementFrameCategoriesContainerScrollBar.Show =
+ function (self)
+ ACHIEVEMENTUI_CATEGORIESWIDTH = 175;
+ AchievementFrameCategories:SetWidth(175);
+ AchievementFrameCategoriesContainer:GetScrollChild():SetWidth(175);
+ AchievementFrameAchievements:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 22, 0);
+ AchievementFrameStats:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 22, 0);
+ AchievementFrameComparison:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 22, 0)
+ AchievementFrameWaterMark:SetWidth(145);
+ AchievementFrameWaterMark:SetTexCoord(0, 145/256, 0, 1);
+ for _, button in next, AchievementFrameCategoriesContainer.buttons do
+ AchievementFrameCategories_DisplayButton(button, button.element)
+ end
+ getmetatable(self).__index.Show(self);
+ end
+
+ AchievementFrameCategoriesContainerScrollBar.Hide =
+ function (self)
+ ACHIEVEMENTUI_CATEGORIESWIDTH = 197;
+ AchievementFrameCategories:SetWidth(197);
+ AchievementFrameCategoriesContainer:GetScrollChild():SetWidth(197);
+ AchievementFrameAchievements:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 0, 0);
+ AchievementFrameStats:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 0, 0);
+ AchievementFrameComparison:SetPoint("TOPLEFT", "$parentCategories", "TOPRIGHT", 0, 0)
+ AchievementFrameWaterMark:SetWidth(167);
+ AchievementFrameWaterMark:SetTexCoord(0, 167/256, 0, 1);
+ for _, button in next, AchievementFrameCategoriesContainer.buttons do
+ AchievementFrameCategories_DisplayButton(button, button.element);
+ end
+ getmetatable(self).__index.Hide(self);
+ end
+
+ AchievementFrameCategoriesContainerScrollBarBG:Show();
+ AchievementFrameCategoriesContainer.update = AchievementFrameCategories_Update;
+ HybridScrollFrame_CreateButtons(AchievementFrameCategoriesContainer, "AchievementCategoryTemplate", 0, 0, "TOP", "TOP", 0, 0, "TOP", "BOTTOM");
+ AchievementFrameCategories_Update();
+ self:UnregisterEvent(event)
+ end
+end
+
+function AchievementFrameCategories_OnShow (self)
+ AchievementFrameCategories_Update();
+end
+
+function AchievementFrameCategories_GetCategoryList (categories)
+ local cats = achievementFunctions.categoryAccessor();
+
+ for i in next, categories do
+ categories[i] = nil;
+ end
+ -- Insert the fake Summary category
+ tinsert(categories, { ["id"] = "summary" });
+
+ for i, id in next, cats do
+ local _, parent = GetCategoryInfo(id);
+ if ( parent == -1 ) then
+ tinsert(categories, { ["id"] = id });
+ end
+ end
+
+ local _, parent;
+ for i = #cats, 1, -1 do
+ _, parent = GetCategoryInfo(cats[i]);
+ for j, category in next, categories do
+ if ( category.id == parent ) then
+ category.parent = true;
+ category.collapsed = true;
+ tinsert(categories, j+1, { ["id"] = cats[i], ["parent"] = category.id, ["hidden"] = true});
+ end
+ end
+ end
+end
+
+local displayCategories = {};
+function AchievementFrameCategories_Update ()
+ local scrollFrame = AchievementFrameCategoriesContainer
+
+ local categories = ACHIEVEMENTUI_CATEGORIES;
+ local offset = HybridScrollFrame_GetOffset(scrollFrame);
+ local buttons = scrollFrame.buttons;
+
+ local displayCategories = displayCategories;
+
+ for i in next, displayCategories do
+ displayCategories[i] = nil;
+ end
+
+ local selection = achievementFunctions.selectedCategory;
+ if ( selection == ACHIEVEMENT_COMPARISON_SUMMARY_ID or selection == ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID ) then
+ selection = "summary";
+ end
+
+ local parent;
+ if ( selection ) then
+ for i, category in next, categories do
+ if ( category.id == selection ) then
+ parent = category.parent;
+ end
+ end
+ end
+
+ for i, category in next, categories do
+ if ( not category.hidden ) then
+ tinsert(displayCategories, category);
+ elseif ( parent and category.id == parent ) then
+ category.collapsed = false;
+ tinsert(displayCategories, category);
+ elseif ( parent and category.parent and category.parent == parent ) then
+ category.hidden = false;
+ tinsert(displayCategories, category);
+ end
+ end
+
+ local numCategories = #displayCategories;
+ local numButtons = #buttons;
+
+ local totalHeight = numCategories * buttons[1]:GetHeight();
+ local displayedHeight = 0;
+
+ local element
+ for i = 1, numButtons do
+ element = displayCategories[i + offset];
+ displayedHeight = displayedHeight + buttons[i]:GetHeight();
+ if ( element ) then
+ AchievementFrameCategories_DisplayButton(buttons[i], element);
+ if ( selection and element.id == selection ) then
+ buttons[i]:LockHighlight();
+ else
+ buttons[i]:UnlockHighlight();
+ end
+ buttons[i]:Show();
+ else
+ buttons[i].element = nil;
+ buttons[i]:Hide();
+ end
+ end
+
+ HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight);
+
+ return displayCategories;
+end
+
+function AchievementFrameCategories_DisplayButton (button, element)
+ if ( not element ) then
+ button.element = nil;
+ button:Hide();
+ return;
+ end
+
+ button:Show();
+ if ( type(element.parent) == "number" ) then
+ button:SetWidth(ACHIEVEMENTUI_CATEGORIESWIDTH - 25);
+ button.label:SetFontObject("GameFontHighlight");
+ button.parentID = element.parent;
+ button.background:SetVertexColor(0.6, 0.6, 0.6);
+ else
+ button:SetWidth(ACHIEVEMENTUI_CATEGORIESWIDTH - 10);
+ button.label:SetFontObject("GameFontNormal");
+ button.parentID = element.parent;
+ button.background:SetVertexColor(1, 1, 1);
+ end
+
+ local categoryName, parentID, flags;
+ local numAchievements, numCompleted;
+
+ local id = element.id;
+
+ -- kind of janky
+ if ( id == "summary" ) then
+ categoryName = ACHIEVEMENT_SUMMARY_CATEGORY;
+ numAchievements, numCompleted = GetNumCompletedAchievements();
+ else
+ categoryName, parentID, flags = GetCategoryInfo(id);
+ numAchievements, numCompleted = AchievementFrame_GetCategoryTotalNumAchievements(id, true);
+ end
+ button.label:SetText(categoryName);
+ button.categoryID = id;
+ button.flags = flags;
+ button.element = element;
+
+ -- For the tooltip
+ button.name = categoryName;
+ if ( id == FEAT_OF_STRENGTH_ID ) then
+ -- This is the feat of strength category since it's sorted to the end of the list
+ button.text = FEAT_OF_STRENGTH_DESCRIPTION;
+ button.showTooltipFunc = AchievementFrameCategory_FeatOfStrengthTooltip;
+ elseif ( AchievementFrame.selectedTab == 1 ) then
+ button.text = nil;
+ button.numAchievements = numAchievements;
+ button.numCompleted = numCompleted;
+ button.numCompletedText = numCompleted.."/"..numAchievements;
+ button.showTooltipFunc = AchievementFrameCategory_StatusBarTooltip;
+ else
+ button.showTooltipFunc = nil;
+ end
+end
+
+function AchievementFrameCategory_StatusBarTooltip(self)
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ GameTooltip:SetMinimumWidth(128, 1);
+ GameTooltip:SetText(self.name, 1, 1, 1, nil, 1);
+ GameTooltip_ShowStatusBar(GameTooltip, 0, self.numAchievements, self.numCompleted, self.numCompletedText);
+ GameTooltip:Show();
+end
+
+function AchievementFrameCategory_FeatOfStrengthTooltip(self)
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ GameTooltip:SetText(self.name, 1, 1, 1);
+ GameTooltip:AddLine(self.text, nil, nil, nil, 1);
+ GameTooltip:Show();
+end
+
+function AchievementFrameCategories_UpdateTooltip()
+ local container = AchievementFrameCategoriesContainer;
+ if ( not container:IsVisible() or not container.buttons ) then
+ return;
+ end
+
+ for _, button in next, AchievementFrameCategoriesContainer.buttons do
+ if ( button:IsMouseOver() and button.showTooltipFunc ) then
+ button:showTooltipFunc();
+ break;
+ end
+ end
+end
+
+function AchievementFrameCategories_SelectButton (button)
+ local id = button.element.id;
+
+ if ( type(button.element.parent) ~= "number" ) then
+ -- Is top level category (can expand/contract)
+ if ( button.isSelected and button.element.collapsed == false ) then
+ button.element.collapsed = true;
+ for i, category in next, ACHIEVEMENTUI_CATEGORIES do
+ if ( category.parent == id ) then
+ category.hidden = true;
+ end
+ end
+ else
+ for i, category in next, ACHIEVEMENTUI_CATEGORIES do
+ if ( category.parent == id ) then
+ category.hidden = false;
+ elseif ( category.parent == true ) then
+ category.collapsed = true;
+ elseif ( category.parent ) then
+ category.hidden = true;
+ end
+ end
+ button.element.collapsed = false;
+ end
+ end
+
+ local buttons = AchievementFrameCategoriesContainer.buttons;
+ for _, button in next, buttons do
+ button.isSelected = nil;
+ end
+
+ button.isSelected = true;
+
+ if ( id == achievementFunctions.selectedCategory ) then
+ -- If this category was selected already, bail after changing collapsed states
+ return
+ end
+
+ --Intercept "summary" category
+ if ( id == "summary" ) then
+ if ( achievementFunctions == ACHIEVEMENT_FUNCTIONS ) then
+ AchievementFrame_ShowSubFrame(AchievementFrameSummary);
+ achievementFunctions.selectedCategory = id;
+ return;
+ elseif ( achievementFunctions == STAT_FUNCTIONS ) then
+ AchievementFrame_ShowSubFrame(AchievementFrameStats);
+ achievementFunctions.selectedCategory = ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID;
+ AchievementFrameStatsContainerScrollBar:SetValue(0);
+ elseif ( achievementFunctions == COMPARISON_ACHIEVEMENT_FUNCTIONS ) then
+ -- Put the summary stuff for comparison here, Derek!
+ AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonContainer);
+ achievementFunctions.selectedCategory = ACHIEVEMENT_COMPARISON_SUMMARY_ID;
+ AchievementFrameComparisonContainerScrollBar:SetValue(0);
+ AchievementFrameComparison_UpdateStatusBars(ACHIEVEMENT_COMPARISON_SUMMARY_ID);
+ elseif ( achievementFunctions == COMPARISON_STAT_FUNCTIONS ) then
+ AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonStatsContainer);
+ achievementFunctions.selectedCategory = ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID;
+ AchievementFrameComparisonStatsContainerScrollBar:SetValue(0);
+ end
+
+ else
+ if ( achievementFunctions == STAT_FUNCTIONS ) then
+ AchievementFrame_ShowSubFrame(AchievementFrameStats);
+ AchievementFrameStatsContainerScrollBar:SetValue(0);
+ elseif ( achievementFunctions == ACHIEVEMENT_FUNCTIONS ) then
+ AchievementFrame_ShowSubFrame(AchievementFrameAchievements);
+ AchievementFrameAchievementsContainerScrollBar:SetValue(0);
+ if ( id == FEAT_OF_STRENGTH_ID ) then
+ AchievementFrameFilterDropDown:Hide();
+ AchievementFrameHeaderRightDDLInset:Hide();
+ else
+ AchievementFrameFilterDropDown:Show();
+ AchievementFrameHeaderRightDDLInset:Show();
+ end
+ elseif ( achievementFunctions == COMPARISON_ACHIEVEMENT_FUNCTIONS ) then
+ AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonContainer);
+ AchievementFrameComparisonContainerScrollBar:SetValue(0);
+ AchievementFrameComparison_UpdateStatusBars(id);
+ else
+ AchievementFrame_ShowSubFrame(AchievementFrameComparison, AchievementFrameComparisonStatsContainer);
+ AchievementFrameComparisonStatsContainerScrollBar:SetValue(0);
+ end
+ achievementFunctions.selectedCategory = id;
+ end
+
+ if ( achievementFunctions.clearFunc ) then
+ achievementFunctions.clearFunc();
+ end
+
+ achievementFunctions.updateFunc();
+end
+
+function AchievementFrameAchievements_OnShow()
+ if ( achievementFunctions.selectedCategory == FEAT_OF_STRENGTH_ID ) then
+ AchievementFrameFilterDropDown:Hide();
+ AchievementFrameHeaderRightDDLInset:Hide();
+ else
+ AchievementFrameFilterDropDown:Show();
+ AchievementFrameHeaderRightDDLInset:Show();
+ end
+end
+
+function AchievementFrameCategories_ClearSelection ()
+ local buttons = AchievementFrameCategoriesContainer.buttons;
+ for _, button in next, buttons do
+ button.isSelected = nil;
+ button:UnlockHighlight();
+ end
+
+ for i, category in next, ACHIEVEMENTUI_CATEGORIES do
+ if ( category.parent == true ) then
+ category.collapsed = true;
+ elseif ( category.parent ) then
+ category.hidden = true;
+ end
+ end
+end
+
+function AchievementFrameComparison_UpdateStatusBars (id)
+ local numAchievements, numCompleted = GetCategoryNumAchievements(id);
+ local name = GetCategoryInfo(id);
+
+ if ( id == ACHIEVEMENT_COMPARISON_SUMMARY_ID ) then
+ name = ACHIEVEMENT_SUMMARY_CATEGORY;
+ end
+
+ local statusBar = AchievementFrameComparisonSummaryPlayerStatusBar;
+ statusBar:SetMinMaxValues(0, numAchievements);
+ statusBar:SetValue(numCompleted);
+ statusBar.title:SetText(string.format(ACHIEVEMENTS_COMPLETED_CATEGORY, name));
+ statusBar.text:SetText(numCompleted.."/"..numAchievements);
+
+ local friendCompleted = GetComparisonCategoryNumAchievements(id);
+
+ statusBar = AchievementFrameComparisonSummaryFriendStatusBar;
+ statusBar:SetMinMaxValues(0, numAchievements);
+ statusBar:SetValue(friendCompleted);
+ statusBar.text:SetText(friendCompleted.."/"..numAchievements);
+end
+
+-- [[ AchievementCategoryButton ]] --
+
+function AchievementCategoryButton_OnLoad (button)
+ button:EnableMouse(true);
+ button:EnableMouseWheel(true);
+
+ local buttonName = button:GetName();
+
+ button.label = _G[buttonName .. "Label"];
+ button.background = _G[buttonName.."Background"];
+end
+
+function AchievementCategoryButton_OnClick (button)
+ AchievementFrameCategories_SelectButton(button);
+ AchievementFrameCategories_Update();
+end
+
+-- [[ AchievementFrameAchievements ]] --
+
+function AchievementFrameAchievements_OnLoad (self)
+ AchievementFrameAchievementsContainerScrollBar.Show =
+ function (self)
+ AchievementFrameAchievements:SetWidth(504);
+ for _, button in next, AchievementFrameAchievements.buttons do
+ button:SetWidth(496);
+ end
+ getmetatable(self).__index.Show(self);
+ end
+
+ AchievementFrameAchievementsContainerScrollBar.Hide =
+ function (self)
+ AchievementFrameAchievements:SetWidth(530);
+ for _, button in next, AchievementFrameAchievements.buttons do
+ button:SetWidth(522);
+ end
+ getmetatable(self).__index.Hide(self);
+ end
+
+ self:RegisterEvent("ADDON_LOADED");
+ AchievementFrameAchievementsContainerScrollBarBG:Show();
+ AchievementFrameAchievementsContainer.update = AchievementFrameAchievements_Update;
+ HybridScrollFrame_CreateButtons(AchievementFrameAchievementsContainer, "AchievementTemplate", 0, -2);
+end
+
+function AchievementFrameAchievements_OnEvent (self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ self:RegisterEvent("ACHIEVEMENT_EARNED");
+ self:RegisterEvent("CRITERIA_UPDATE");
+ self:RegisterEvent("TRACKED_ACHIEVEMENT_UPDATE");
+
+ updateTrackedAchievements(GetTrackedAchievements());
+ elseif ( event == "ACHIEVEMENT_EARNED" ) then
+ local achievementID = ...;
+ AchievementFrameCategories_Update();
+ AchievementFrameCategories_UpdateTooltip();
+ -- This has to happen before AchievementFrameAchievements_ForceUpdate() in order to achieve the behavior we want, since it clears the selection for progressive achievements.
+ local selection = AchievementFrameAchievements.selection;
+ AchievementFrameAchievements_ForceUpdate();
+ if ( AchievementFrameAchievementsContainer:IsShown() and selection == achievementID ) then
+ AchievementFrame_SelectAchievement(selection, true);
+ end
+ AchievementFrameHeaderPoints:SetText(GetTotalAchievementPoints());
+
+ elseif ( event == "CRITERIA_UPDATE" ) then
+ if ( AchievementFrameAchievements.selection ) then
+ local id = AchievementFrameAchievementsObjectives.id;
+ local button = AchievementFrameAchievementsObjectives:GetParent();
+ AchievementFrameAchievementsObjectives.id = nil;
+ AchievementButton_DisplayObjectives(button, id, button.completed);
+ AchievementFrameAchievements_Update();
+ else
+ AchievementFrameAchievementsObjectives.id = nil; -- Force redraw
+ end
+ elseif ( event == "TRACKED_ACHIEVEMENT_UPDATE" ) then
+ for k, v in next, trackedAchievements do
+ trackedAchievements[k] = nil;
+ end
+
+ updateTrackedAchievements(GetTrackedAchievements());
+ end
+
+ if ( not AchievementMicroButton:IsShown() ) then
+ AchievementMicroButton_Update();
+ end
+end
+
+function AchievementFrameAchievementsBackdrop_OnLoad (self)
+ self:SetBackdropBorderColor(ACHIEVEMENTUI_GOLDBORDER_R, ACHIEVEMENTUI_GOLDBORDER_G, ACHIEVEMENTUI_GOLDBORDER_B, ACHIEVEMENTUI_GOLDBORDER_A);
+ self:SetFrameLevel(self:GetFrameLevel()+1);
+end
+
+function AchievementFrameAchievements_Update ()
+ local category = achievementFunctions.selectedCategory;
+ if ( category == "summary" ) then
+ return;
+ end
+ local scrollFrame = AchievementFrameAchievementsContainer
+
+ local offset = HybridScrollFrame_GetOffset(scrollFrame);
+ local buttons = scrollFrame.buttons;
+ local numAchievements, numCompleted, completedOffset = ACHIEVEMENTUI_SELECTEDFILTER(category);
+ local numButtons = #buttons;
+
+ -- If the current category is feats of strength and there are no entries then show the explanation text
+ if ( AchievementFrame_IsFeatOfStrength() and numAchievements == 0 ) then
+ AchievementFrameAchievementsFeatOfStrengthText:Show();
+ else
+ AchievementFrameAchievementsFeatOfStrengthText:Hide();
+ end
+
+ local selection = AchievementFrameAchievements.selection;
+ if ( selection ) then
+ AchievementButton_ResetObjectives();
+ end
+
+ local extraHeight = scrollFrame.largeButtonHeight or ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT
+
+ local achievementIndex;
+ local displayedHeight = 0;
+ for i = 1, numButtons do
+ achievementIndex = i + offset + completedOffset;
+ if ( achievementIndex > numAchievements + completedOffset ) then
+ buttons[i]:Hide();
+ else
+ AchievementButton_DisplayAchievement(buttons[i], category, achievementIndex, selection);
+ displayedHeight = displayedHeight + buttons[i]:GetHeight();
+ end
+ end
+
+ local totalHeight = numAchievements * ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT;
+ totalHeight = totalHeight + (extraHeight - ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT);
+
+ HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight);
+
+ if ( selection ) then
+ AchievementFrameAchievements.selection = selection;
+ else
+ HybridScrollFrame_CollapseButton(scrollFrame);
+ end
+end
+
+function AchievementFrameAchievements_ForceUpdate ()
+ if ( AchievementFrameAchievements.selection ) then
+ local nextID = GetNextAchievement(AchievementFrameAchievements.selection);
+ local id, _, _, completed = GetAchievementInfo(AchievementFrameAchievements.selection);
+ if ( nextID and completed ) then
+ AchievementFrameAchievements.selection = nil;
+ end
+ end
+ AchievementFrameAchievementsObjectives:Hide();
+ AchievementFrameAchievementsObjectives.id = nil;
+
+ local buttons = AchievementFrameAchievementsContainer.buttons;
+ for i, button in next, buttons do
+ button.id = nil;
+ end
+
+ AchievementFrameAchievements_Update();
+end
+
+function AchievementFrameAchievements_ClearSelection ()
+ AchievementButton_ResetObjectives();
+ for _, button in next, AchievementFrameAchievements.buttons do
+ button:Collapse();
+ if ( not button:IsMouseOver() ) then
+ button.highlight:Hide();
+ end
+ button.selected = nil;
+ if ( not button.tracked:GetChecked() ) then
+ button.tracked:Hide();
+ end
+ button.description:Show();
+ button.hiddenDescription:Hide();
+ end
+
+ AchievementFrameAchievements.selection = nil;
+end
+
+-- [[ Achievement Icon ]] --
+
+function AchievementIcon_Desaturate (self)
+ self.bling:SetVertexColor(.6, .6, .6, 1);
+ self.frame:SetVertexColor(.75, .75, .75, 1);
+ self.texture:SetVertexColor(.55, .55, .55, 1);
+end
+
+function AchievementIcon_Saturate (self)
+ self.bling:SetVertexColor(1, 1, 1, 1);
+ self.frame:SetVertexColor(1, 1, 1, 1);
+ self.texture:SetVertexColor(1, 1, 1, 1);
+end
+
+function AchievementIcon_OnLoad (self)
+ local name = self:GetName();
+ self.bling = _G[name .. "Bling"];
+ self.texture = _G[name .. "Texture"];
+ self.frame = _G[name .. "Overlay"];
+
+ self.Desaturate = AchievementIcon_Desaturate;
+ self.Saturate = AchievementIcon_Saturate;
+end
+
+-- [[ Achievement Shield ]] --
+
+function AchievementShield_Desaturate (self)
+ self.icon:SetTexCoord(.5, 1, 0, 1);
+end
+
+function AchievementShield_Saturate (self)
+ self.icon:SetTexCoord(0, .5, 0, 1);
+end
+
+function AchievementShield_OnLoad (self)
+ local name = self:GetName();
+ self.icon = _G[name .. "Icon"];
+ self.points = _G[name .. "Points"];
+
+ self.Desaturate = AchievementShield_Desaturate;
+ self.Saturate = AchievementShield_Saturate;
+end
+
+-- [[ AchievementButton ]] --
+
+ACHIEVEMENTBUTTON_DESCRIPTIONHEIGHT = 20;
+ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT = 84;
+ACHIEVEMENTBUTTON_CRITERIAROWHEIGHT = 15;
+ACHIEVEMENTBUTTON_METAROWHEIGHT = 14;
+ACHIEVEMENTBUTTON_MAXHEIGHT = 232;
+ACHIEVEMENTBUTTON_TEXTUREHEIGHT = 128;
+
+function AchievementButton_UpdatePlusMinusTexture (button)
+ local id = button.id;
+ if ( not id ) then
+ return; -- This happens when we create buttons
+ end
+
+ local display = false;
+ if ( GetAchievementNumCriteria(id) ~= 0 ) then
+ display = true;
+ elseif ( GetPreviousAchievement(id) and button.completed ) then
+ display = true;
+ end
+
+ if ( display ) then
+ button.plusMinus:Show();
+ if ( button.collapsed and button.saturated ) then
+ button.plusMinus:SetTexCoord(0, .5, 0, .5);
+ elseif ( button.collapsed ) then
+ button.plusMinus:SetTexCoord(.5, 1, 0, .5);
+ elseif ( button.saturated ) then
+ button.plusMinus:SetTexCoord(0, .5, .5, 1);
+ else
+ button.plusMinus:SetTexCoord(.5, 1, .5, 1);
+ end
+ else
+ button.plusMinus:Hide();
+ end
+end
+
+function AchievementButton_Collapse (self)
+ if ( self.collapsed ) then
+ return;
+ end
+
+ self.collapsed = true;
+ AchievementButton_UpdatePlusMinusTexture(self);
+ self:SetHeight(ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT);
+ _G[self:GetName() .. "Background"]:SetTexCoord(0, 1, 1-(ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT / 256), 1);
+ _G[self:GetName() .. "Glow"]:SetTexCoord(0, 1, 0, ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT / 128);
+
+ if ( not self.tracked:GetChecked() ) then
+ self.tracked:Hide();
+ end
+end
+
+function AchievementButton_Expand (self, height)
+ if ( not self.collapsed ) then
+ return;
+ end
+
+ self.collapsed = nil;
+ AchievementButton_UpdatePlusMinusTexture(self);
+ self:SetHeight(height);
+ _G[self:GetName() .. "Background"]:SetTexCoord(0, 1, max(0, 1-(height / 256)), 1);
+ _G[self:GetName() .. "Glow"]:SetTexCoord(0, 1, 0, (height+5) / 128);
+end
+
+function AchievementButton_Saturate (self)
+ local name = self:GetName();
+ self.saturated = true;
+ _G[name .. "TitleBackground"]:SetTexCoord(0, 0.9765625, 0, 0.3125);
+ _G[name .. "Background"]:SetTexture("Interface\\AchievementFrame\\UI-Achievement-Parchment-Horizontal");
+ _G[name .. "Glow"]:SetVertexColor(1.0, 1.0, 1.0);
+ self.icon:Saturate();
+ self.shield:Saturate();
+ self.shield.points:SetVertexColor(1, 1, 1);
+ self.reward:SetVertexColor(1, .82, 0);
+ self.label:SetVertexColor(1, 1, 1);
+ self.description:SetTextColor(0, 0, 0, 1);
+ self.description:SetShadowOffset(0, 0);
+ AchievementButton_UpdatePlusMinusTexture(self);
+ self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
+end
+
+function AchievementButton_Desaturate (self)
+ local name = self:GetName();
+ self.saturated = nil;
+ _G[name .. "TitleBackground"]:SetTexCoord(0, 0.9765625, 0.34375, 0.65625);
+ _G[name .. "Background"]:SetTexture("Interface\\AchievementFrame\\UI-Achievement-Parchment-Horizontal-Desaturated");
+ _G[name .. "Glow"]:SetVertexColor(.22, .17, .13);
+ self.icon:Desaturate();
+ self.shield:Desaturate();
+ self.shield.points:SetVertexColor(.65, .65, .65);
+ self.reward:SetVertexColor(.8, .8, .8);
+ self.label:SetVertexColor(.65, .65, .65);
+ self.description:SetTextColor(1, 1, 1, 1);
+ self.description:SetShadowOffset(1, -1);
+ AchievementButton_UpdatePlusMinusTexture(self);
+ self:SetBackdropBorderColor(.5, .5, .5);
+end
+
+function AchievementButton_OnLoad (self)
+ local name = self:GetName();
+ self.label = _G[name .. "Label"];
+ self.description = _G[name .. "Description"];
+ self.hiddenDescription = _G[name .. "HiddenDescription"];
+ self.reward = _G[name .. "Reward"];
+ self.rewardBackground = _G[name.."RewardBackground"];
+ self.icon = _G[name .. "Icon"];
+ self.shield = _G[name .. "Shield"];
+ self.objectives = _G[name .. "Objectives"];
+ self.highlight = _G[name .. "Highlight"];
+ self.dateCompleted = _G[name .. "DateCompleted"]
+ self.tracked = _G[name .. "Tracked"];
+ self.check = _G[name .. "Check"];
+ self.plusMinus = _G[name .. "PlusMinus"];
+
+ self.dateCompleted:ClearAllPoints();
+ self.dateCompleted:SetPoint("TOP", self.shield, "BOTTOM", -3, 6);
+ if ( not ACHIEVEMENTUI_FONTHEIGHT ) then
+ local _, fontHeight = self.description:GetFont();
+ ACHIEVEMENTUI_FONTHEIGHT = fontHeight;
+ end
+ self.description:SetHeight(ACHIEVEMENTUI_FONTHEIGHT * ACHIEVEMENTUI_MAX_LINES_COLLAPSED);
+ self.description:SetWidth(ACHIEVEMENTUI_MAXCONTENTWIDTH);
+ self.hiddenDescription:SetWidth(ACHIEVEMENTUI_MAXCONTENTWIDTH);
+
+ self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
+ self.Collapse = AchievementButton_Collapse;
+ self.Expand = AchievementButton_Expand;
+ self.Saturate = AchievementButton_Saturate;
+ self.Desaturate = AchievementButton_Desaturate;
+
+ self:Collapse();
+ self:Desaturate();
+
+ AchievementFrameAchievements.buttons = AchievementFrameAchievements.buttons or {};
+ tinsert(AchievementFrameAchievements.buttons, self);
+end
+
+function AchievementButton_OnClick (self, ignoreModifiers)
+ if(IsModifiedClick() and not ignoreModifiers) then
+ if ( IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow() ) then
+ local achievementLink = GetAchievementLink(self.id);
+ if ( achievementLink ) then
+ ChatEdit_InsertLink(achievementLink);
+ end
+ elseif ( IsModifiedClick("QUESTWATCHTOGGLE") ) then
+ AchievementButton_ToggleTracking(self.id);
+ end
+
+ return;
+ end
+
+ if ( self.selected ) then
+ if ( not self:IsMouseOver() ) then
+ self.highlight:Hide();
+ end
+ AchievementFrameAchievements_ClearSelection()
+ HybridScrollFrame_CollapseButton(AchievementFrameAchievementsContainer);
+ AchievementFrameAchievements_Update();
+ return;
+ end
+ AchievementFrameAchievements_ClearSelection()
+ AchievementFrameAchievements_SelectButton(self);
+ AchievementButton_DisplayAchievement(self, achievementFunctions.selectedCategory, self.index, self.id);
+ HybridScrollFrame_ExpandButton(AchievementFrameAchievementsContainer, ((self.index - 1) * ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT), self:GetHeight());
+ AchievementFrameAchievements_Update();
+ if ( not ignoreModifiers ) then
+ AchievementFrameAchievements_AdjustSelection();
+ end
+end
+
+function AchievementButton_ToggleTracking (id)
+ if ( trackedAchievements[id] ) then
+ RemoveTrackedAchievement(id);
+ AchievementFrameAchievements_ForceUpdate();
+ WatchFrame_Update();
+ return;
+ end
+
+ local count = GetNumTrackedAchievements();
+
+ if ( count >= WATCHFRAME_MAXACHIEVEMENTS ) then
+ UIErrorsFrame:AddMessage(format(ACHIEVEMENT_WATCH_TOO_MANY, WATCHFRAME_MAXACHIEVEMENTS), 1.0, 0.1, 0.1, 1.0);
+ return;
+ end
+
+ local _, _, _, completed = GetAchievementInfo(id)
+ if ( completed ) then
+ UIErrorsFrame:AddMessage(ERR_ACHIEVEMENT_WATCH_COMPLETED, 1.0, 0.1, 0.1, 1.0);
+ return;
+ end
+
+ AddTrackedAchievement(id);
+ AchievementFrameAchievements_ForceUpdate();
+ WatchFrame_Update();
+
+ return true;
+end
+
+function AchievementButton_DisplayAchievement (button, category, achievement, selectionID)
+ local id, name, points, completed, month, day, year, description, flags, icon, rewardText = GetAchievementInfo(category, achievement);
+ if ( not id ) then
+ button:Hide();
+ return;
+ else
+ button:Show();
+ end
+
+ button.index = achievement;
+ button.element = true;
+
+ if ( button.id ~= id ) then
+ button.id = id;
+ button.label:SetWidth(ACHIEVEMENTBUTTON_LABELWIDTH);
+ button.label:SetText(name)
+
+ if ( GetPreviousAchievement(id) ) then
+ -- If this is a progressive achievement, show the total score.
+ AchievementShield_SetPoints(AchievementButton_GetProgressivePoints(id), button.shield.points, AchievementPointsFont, AchievementPointsFontSmall);
+ else
+ AchievementShield_SetPoints(points, button.shield.points, AchievementPointsFont, AchievementPointsFontSmall);
+ end
+
+ if ( points > 0 ) then
+ button.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields]]);
+ else
+ button.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields-NoPoints]]);
+ end
+ button.description:SetText(description);
+ button.hiddenDescription:SetText(description);
+ button.numLines = ceil(button.hiddenDescription:GetHeight() / ACHIEVEMENTUI_FONTHEIGHT);
+ button.icon.texture:SetTexture(icon);
+ if ( completed and not button.completed ) then
+ button.completed = true;
+ button.dateCompleted:SetText(string.format(SHORTDATE, day, month, year));
+ button.dateCompleted:Show();
+ button:Saturate();
+ elseif ( completed ) then
+ button.dateCompleted:SetText(string.format(SHORTDATE, day, month, year));
+ else
+ button.completed = nil;
+ button.dateCompleted:Hide();
+ button:Desaturate();
+ end
+
+ if ( rewardText == "" ) then
+ button.reward:Hide();
+ button.rewardBackground:Hide();
+ else
+ button.reward:SetText(rewardText);
+ button.reward:Show();
+ button.rewardBackground:Show();
+ if ( button.completed ) then
+ button.rewardBackground:SetVertexColor(1, 1, 1);
+ else
+ button.rewardBackground:SetVertexColor(0.35, 0.35, 0.35);
+ end
+ end
+
+ if ( IsTrackedAchievement(id) ) then
+ button.check:Show();
+ button.label:SetWidth(button.label:GetStringWidth() + 4); -- This +4 here is to fudge around any string width issues that arize from resizing a string set to its string width. See bug 144418 for an example.
+ button.tracked:SetChecked(true);
+ button.tracked:Show();
+ else
+ button.check:Hide();
+ button.tracked:SetChecked(false);
+ button.tracked:Hide();
+ end
+
+ AchievementButton_UpdatePlusMinusTexture(button);
+ end
+
+ if ( id == selectionID ) then
+ local achievements = AchievementFrameAchievements;
+
+ achievements.selection = button.id;
+ achievements.selectionIndex = button.index;
+ button.selected = true;
+ button.highlight:Show();
+ local height = AchievementButton_DisplayObjectives(button, button.id, button.completed);
+ if ( height == ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT ) then
+ button:Collapse();
+ else
+ button:Expand(height);
+ end
+ if ( not completed ) then
+ button.tracked:Show();
+ end
+ elseif ( button.selected ) then
+ button.selected = nil;
+ if ( not button:IsMouseOver() ) then
+ button.highlight:Hide();
+ end
+ button:Collapse();
+ button.description:Show();
+ button.hiddenDescription:Hide();
+ end
+
+ return id;
+end
+
+function AchievementFrameAchievements_SelectButton (button)
+ local achievements = AchievementFrameAchievements;
+
+ achievements.selection = button.id;
+ achievements.selectionIndex = button.index;
+ button.selected = true;
+end
+
+function AchievementButton_ResetObjectives ()
+ AchievementFrameAchievementsObjectives:Hide();
+end
+
+function AchievementButton_DisplayObjectives (button, id, completed)
+ local objectives = AchievementFrameAchievementsObjectives;
+
+ objectives:ClearAllPoints();
+ objectives:SetParent(button);
+ objectives:Show();
+ objectives.completed = completed;
+ local height = 0;
+ if ( objectives.id == id ) then
+ local ACHIEVEMENTMODE_CRITERIA = 1;
+ if ( objectives.mode == ACHIEVEMENTMODE_CRITERIA ) then
+ if ( objectives:GetHeight() > 0 ) then
+ objectives:SetPoint("TOP", "$parentHiddenDescription", "BOTTOM", 0, -8);
+ objectives:SetPoint("LEFT", "$parentIcon", "RIGHT", -5, 0);
+ objectives:SetPoint("RIGHT", "$parentShield", "LEFT", -10, 0);
+ end
+ height = ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT + objectives:GetHeight();
+ else
+ objectives:SetPoint("TOP", "$parentHiddenDescription", "BOTTOM", 0, -8);
+ height = ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT + objectives:GetHeight();
+ end
+ elseif ( completed and GetPreviousAchievement(id) ) then
+ objectives:SetHeight(0);
+ AchievementButton_ResetCriteria();
+ AchievementButton_ResetProgressBars();
+ AchievementButton_ResetMiniAchievements();
+ AchievementButton_ResetMetas();
+ AchievementObjectives_DisplayProgressiveAchievement(objectives, id);
+ objectives:SetPoint("TOP", "$parentHiddenDescription", "BOTTOM", 0, -8);
+ height = ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT + objectives:GetHeight();
+ else
+ objectives:SetHeight(0);
+ AchievementButton_ResetCriteria();
+ AchievementButton_ResetProgressBars();
+ AchievementButton_ResetMiniAchievements();
+ AchievementButton_ResetMetas();
+ AchievementObjectives_DisplayCriteria(objectives, id);
+ if ( objectives:GetHeight() > 0 ) then
+ objectives:SetPoint("TOP", "$parentHiddenDescription", "BOTTOM", 0, -8);
+ objectives:SetPoint("LEFT", "$parentIcon", "RIGHT", -5, -25);
+ objectives:SetPoint("RIGHT", "$parentShield", "LEFT", -10, 0);
+ end
+ height = ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT + objectives:GetHeight();
+ end
+
+ if ( height ~= ACHIEVEMENTBUTTON_COLLAPSEDHEIGHT or button.numLines > ACHIEVEMENTUI_MAX_LINES_COLLAPSED ) then
+ button.hiddenDescription:Show();
+ button.description:Hide();
+ local descriptionHeight = button.hiddenDescription:GetHeight();
+ height = height + descriptionHeight - ACHIEVEMENTBUTTON_DESCRIPTIONHEIGHT;
+ if ( button.reward:IsShown() ) then
+ height = height + 4;
+ end
+ end
+
+ objectives.id = id;
+ return height;
+end
+
+function AchievementShield_SetPoints(points, pointString, normalFont, smallFont)
+ if ( points == 0 ) then
+ pointString:SetText("");
+ return;
+ end
+ if ( points <= 100 ) then
+ pointString:SetFontObject(normalFont);
+ else
+ pointString:SetFontObject(smallFont);
+ end
+ pointString:SetText(points);
+end
+
+function AchievementButton_ResetTable (t)
+ for k, v in next, t do
+ v:Hide();
+ end
+end
+
+local criteriaTable = {}
+
+function AchievementButton_ResetCriteria ()
+ AchievementButton_ResetTable(criteriaTable);
+end
+
+function AchievementButton_GetCriteria (index)
+ local criteriaTable = criteriaTable;
+
+ if ( criteriaTable[index] ) then
+ return criteriaTable[index];
+ end
+
+ local frame = CreateFrame("FRAME", "AchievementFrameCriteria" .. index, AchievementFrameAchievements, "AchievementCriteriaTemplate");
+ AchievementFrame_LocalizeCriteria(frame);
+ criteriaTable[index] = frame;
+
+ return frame;
+end
+
+-- The smallest table in WoW.
+local miniTable = {}
+
+function AchievementButton_ResetMiniAchievements ()
+ AchievementButton_ResetTable(miniTable);
+end
+
+function AchievementButton_GetMiniAchievement (index)
+ local miniTable = miniTable;
+ if ( miniTable[index] ) then
+ return miniTable[index];
+ end
+
+ local frame = CreateFrame("FRAME", "AchievementFrameMiniAchievement" .. index, AchievementFrameAchievements, "MiniAchievementTemplate");
+ AchievementButton_LocalizeMiniAchievement(frame);
+ miniTable[index] = frame;
+
+ return frame;
+end
+
+local progressBarTable = {};
+
+function AchievementButton_ResetProgressBars ()
+ AchievementButton_ResetTable(progressBarTable);
+end
+
+function AchievementButton_GetProgressBar (index)
+ local progressBarTable = progressBarTable;
+ if ( progressBarTable[index] ) then
+ return progressBarTable[index];
+ end
+
+ local frame = CreateFrame("STATUSBAR", "AchievementFrameProgressBar" .. index, AchievementFrameAchievements, "AchievementProgressBarTemplate");
+ AchievementButton_LocalizeProgressBar(frame);
+ progressBarTable[index] = frame;
+
+ return frame;
+end
+
+local metaCriteriaTable = {};
+
+function AchievementButton_ResetMetas ()
+ AchievementButton_ResetTable(metaCriteriaTable);
+end
+
+function AchievementButton_GetMeta (index)
+ local metaCriteriaTable = metaCriteriaTable;
+ if ( metaCriteriaTable[index] ) then
+ return metaCriteriaTable[index];
+ end
+
+ local frame = CreateFrame("BUTTON", "AchievementFrameMeta" .. index, AchievementFrameAchievements, "MetaCriteriaTemplate");
+ AchievementButton_LocalizeMetaAchievement(frame);
+ metaCriteriaTable[index] = frame;
+
+ return frame;
+end
+
+function AchievementButton_GetProgressivePoints(achievementID)
+ local points;
+ local _, _, progressivePoints, completed = GetAchievementInfo(achievementID);
+
+ while GetPreviousAchievement(achievementID) do
+ achievementID = GetPreviousAchievement(achievementID);
+ _, _, points, completed = GetAchievementInfo(achievementID);
+ progressivePoints = progressivePoints+points;
+ end
+
+ if ( progressivePoints ) then
+ return progressivePoints;
+ else
+ return 0;
+ end
+end
+
+local achievementList = {};
+
+function AchievementObjectives_DisplayProgressiveAchievement (objectivesFrame, id)
+ local ACHIEVEMENTMODE_PROGRESSIVE = 2;
+ local achievementID = id;
+
+ local achievementList = achievementList;
+ for i in next, achievementList do
+ achievementList[i] = nil;
+ end
+
+ tinsert(achievementList, 1, achievementID);
+ while GetPreviousAchievement(achievementID) do
+ tinsert(achievementList, 1, GetPreviousAchievement(achievementID));
+ achievementID = GetPreviousAchievement(achievementID);
+ end
+
+ local i = 0;
+ for index, achievementID in ipairs(achievementList) do
+ local _, achievementName, points, completed, month, day, year, description, flags, iconpath = GetAchievementInfo(achievementID);
+
+ local miniAchievement = AchievementButton_GetMiniAchievement(index);
+
+ miniAchievement:Show();
+ miniAchievement:SetParent(objectivesFrame);
+ _G[miniAchievement:GetName() .. "Icon"]:SetTexture(iconpath);
+ if ( index == 1 ) then
+ miniAchievement:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", -4, -4);
+ elseif ( index == 7 ) then
+ miniAchievement:SetPoint("TOPLEFT", miniTable[1], "BOTTOMLEFT", 0, -8);
+ else
+ miniAchievement:SetPoint("TOPLEFT", miniTable[index-1], "TOPRIGHT", 4, 0);
+ end
+
+ miniAchievement.points:SetText(points);
+
+ miniAchievement.numCriteria = 0;
+ if ( not ( bit.band(flags, ACHIEVEMENT_FLAGS_HAS_PROGRESS_BAR) == ACHIEVEMENT_FLAGS_HAS_PROGRESS_BAR ) ) then
+ for i = 1, GetAchievementNumCriteria(achievementID) do
+ local criteriaString, criteriaType, completed = GetAchievementCriteriaInfo(achievementID, i);
+ if ( completed == false ) then
+ criteriaString = "|CFF808080 - " .. criteriaString;
+ else
+ criteriaString = "|CFF00FF00 - " .. criteriaString;
+ end
+ miniAchievement["criteria" .. i] = criteriaString;
+ miniAchievement.numCriteria = i;
+ end
+ end
+ miniAchievement.name = achievementName;
+ miniAchievement.desc = description;
+ if ( month ) then
+ miniAchievement.date = string.format(SHORTDATE, day, month, year);
+ end
+ i = index;
+ end
+
+ objectivesFrame:SetHeight(math.ceil(i/6) * ACHIEVEMENTUI_PROGRESSIVEHEIGHT);
+ objectivesFrame:SetWidth(min(i, 6) * ACHIEVEMENTUI_PROGRESSIVEWIDTH);
+ objectivesFrame.mode = ACHIEVEMENTMODE_PROGRESSIVE;
+end
+
+function AchievementFrame_GetCategoryNumAchievements_All (categoryID)
+ local numAchievements, numCompleted = GetCategoryNumAchievements(categoryID);
+
+ return numAchievements, numCompleted, 0;
+end
+
+function AchievementFrame_GetCategoryNumAchievements_Complete (categoryID)
+ local numAchievements, numCompleted = GetCategoryNumAchievements(categoryID);
+
+ return numCompleted, numCompleted, 0;
+end
+
+function AchievementFrame_GetCategoryNumAchievements_Incomplete (categoryID)
+ local numAchievements, numCompleted = GetCategoryNumAchievements(categoryID);
+
+ return numAchievements - numCompleted, 0, numCompleted
+end
+
+ACHIEVEMENTUI_SELECTEDFILTER = AchievementFrame_GetCategoryNumAchievements_All;
+
+AchievementFrameFilters = { {text=ACHIEVEMENTFRAME_FILTER_ALL, func= AchievementFrame_GetCategoryNumAchievements_All},
+ {text=ACHIEVEMENTFRAME_FILTER_COMPLETED, func=AchievementFrame_GetCategoryNumAchievements_Complete},
+{text=ACHIEVEMENTFRAME_FILTER_INCOMPLETE, func=AchievementFrame_GetCategoryNumAchievements_Incomplete} };
+
+function AchievementFrameFilterDropDown_OnLoad (self)
+ self.relativeTo = "AchievementFrameFilterDropDown"
+ self.xOffset = -14;
+ self.yOffset = 10;
+ UIDropDownMenu_Initialize(self, AchievementFrameFilterDropDown_Initialize);
+end
+
+function AchievementFrameFilterDropDown_Initialize (self)
+ local info = UIDropDownMenu_CreateInfo();
+ for i, filter in ipairs(AchievementFrameFilters) do
+ info.text = filter.text;
+ info.value = i;
+ info.func = AchievementFrameFilterDropDownButton_OnClick;
+ if ( filter.func == ACHIEVEMENTUI_SELECTEDFILTER ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, filter.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function AchievementFrameFilterDropDownButton_OnClick (self)
+ AchievementFrame_SetFilter(self.value);
+end
+
+function AchievementFrame_SetFilter(value)
+ local func = AchievementFrameFilters[value].func;
+ if ( func ~= ACHIEVEMENTUI_SELECTEDFILTER ) then
+ ACHIEVEMENTUI_SELECTEDFILTER = func;
+ UIDropDownMenu_SetText(AchievementFrameFilterDropDown, AchievementFrameFilters[value].text)
+ AchievementFrameAchievementsContainerScrollBar:SetValue(0);
+ AchievementFrameAchievements_ForceUpdate();
+ end
+end
+
+function AchievementObjectives_DisplayCriteria (objectivesFrame, id)
+ if ( not id ) then
+ return;
+ end
+
+ local ACHIEVEMENTMODE_CRITERIA = 1;
+ local numCriteria = GetAchievementNumCriteria(id);
+
+ if ( numCriteria == 0 ) then
+ objectivesFrame.mode = ACHIEVEMENTMODE_CRITERIA;
+ objectivesFrame:SetHeight(0);
+ return;
+ end
+
+ local frameLevel = objectivesFrame:GetFrameLevel() + 1;
+
+ -- Why textStrings? You try naming anything just "string" and see how happy you are.
+ local textStrings, progressBars, metas = 0, 0, 0;
+
+ local numRows = 0;
+ local maxCriteriaWidth = 0;
+ local yPos;
+ for i = 1, numCriteria do
+ local criteriaString, criteriaType, completed, quantity, reqQuantity, charName, flags, assetID, quantityString = GetAchievementCriteriaInfo(id, i);
+
+ if ( criteriaType == CRITERIA_TYPE_ACHIEVEMENT and assetID ) then
+ metas = metas + 1;
+ local metaCriteria = AchievementButton_GetMeta(metas);
+
+ if ( metas == 1 ) then
+ metaCriteria:SetPoint("TOP", objectivesFrame, "TOP", 0, -4);
+ numRows = numRows + 2;
+ elseif ( math.fmod(metas, 2) == 0 ) then
+ yPos = -((metas/2 - 1) * 28) - 8;
+ metaCriteriaTable[metas-1]:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", 20, yPos);
+ metaCriteria:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", 210, yPos);
+ else
+ metaCriteria:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", 20, -(math.ceil(metas/2 - 1) * 28) - 8);
+ numRows = numRows + 2;
+ end
+
+ local id, achievementName, points, completed, month, day, year, description, flags, iconpath = GetAchievementInfo(assetID);
+
+ if ( month ) then
+ metaCriteria.date = string.format(SHORTDATE, day, month, year);
+ else
+ metaCriteria.date = nil;
+ end
+
+ metaCriteria.id = id;
+ metaCriteria.label:SetText(achievementName);
+ metaCriteria.icon:SetTexture(iconpath);
+
+ if ( objectivesFrame.completed and completed ) then
+ metaCriteria.check:Show();
+ metaCriteria.border:SetVertexColor(1, 1, 1, 1);
+ metaCriteria.icon:SetVertexColor(1, 1, 1, 1);
+ metaCriteria.label:SetShadowOffset(0, 0)
+ metaCriteria.label:SetTextColor(0, 0, 0, 1);
+ elseif ( completed ) then
+ metaCriteria.check:Show();
+ metaCriteria.border:SetVertexColor(1, 1, 1, 1);
+ metaCriteria.icon:SetVertexColor(1, 1, 1, 1);
+ metaCriteria.label:SetShadowOffset(1, -1)
+ metaCriteria.label:SetTextColor(0, 1, 0, 1);
+ else
+ metaCriteria.check:Hide();
+ metaCriteria.border:SetVertexColor(.75, .75, .75, 1);
+ metaCriteria.icon:SetVertexColor(.55, .55, .55, 1);
+ metaCriteria.label:SetShadowOffset(1, -1)
+ metaCriteria.label:SetTextColor(.6, .6, .6, 1);
+ end
+
+ metaCriteria:SetParent(objectivesFrame);
+ metaCriteria:Show();
+ elseif ( bit.band(flags, ACHIEVEMENT_CRITERIA_PROGRESS_BAR) == ACHIEVEMENT_CRITERIA_PROGRESS_BAR ) then
+ -- Display this criteria as a progress bar!
+ progressBars = progressBars + 1;
+ local progressBar = AchievementButton_GetProgressBar(progressBars);
+
+ if ( progressBars == 1 ) then
+ progressBar:SetPoint("TOP", objectivesFrame, "TOP", 4, -4);
+ else
+ progressBar:SetPoint("TOP", progressBarTable[progressBars-1], "BOTTOM", 0, 0);
+ end
+
+ progressBar.text:SetText(string.format("%s", quantityString));
+ progressBar:SetMinMaxValues(0, reqQuantity);
+ progressBar:SetValue(quantity);
+
+ progressBar:SetParent(objectivesFrame);
+ progressBar:Show();
+
+ numRows = numRows + 1;
+ else
+ textStrings = textStrings + 1;
+ local criteria = AchievementButton_GetCriteria(textStrings);
+ criteria:ClearAllPoints();
+ if ( textStrings == 1 ) then
+ if ( numCriteria == 1 ) then
+ criteria:SetPoint("TOP", objectivesFrame, "TOP", -14, 0);
+ else
+ criteria:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", 0, 0);
+ end
+
+ else
+ criteria:SetPoint("TOPLEFT", criteriaTable[textStrings-1], "BOTTOMLEFT", 0, 0);
+ end
+
+ if ( objectivesFrame.completed and completed ) then
+ criteria.name:SetTextColor(0, 0, 0, 1);
+ criteria.name:SetShadowOffset(0, 0);
+ elseif ( completed ) then
+ criteria.name:SetTextColor(0, 1, 0, 1);
+ criteria.name:SetShadowOffset(1, -1);
+ else
+ criteria.name:SetTextColor(.6, .6, .6, 1);
+ criteria.name:SetShadowOffset(1, -1);
+ end
+
+ if ( completed ) then
+ criteria.check:SetPoint("LEFT", 18, -3);
+ criteria.name:SetPoint("LEFT", criteria.check, "RIGHT", 0, 2);
+ criteria.check:Show();
+ criteria.name:SetText(criteriaString);
+ else
+ criteria.check:SetPoint("LEFT", 0, -3);
+ criteria.name:SetPoint("LEFT", criteria.check, "RIGHT", 5, 2);
+ criteria.check:Hide();
+ criteria.name:SetText("- "..criteriaString);
+ end
+
+ criteria:SetParent(objectivesFrame);
+ criteria:Show();
+ local stringWidth = criteria.name:GetStringWidth()
+ criteria:SetWidth(stringWidth + criteria.check:GetWidth());
+ maxCriteriaWidth = max(maxCriteriaWidth, stringWidth + criteria.check:GetWidth());
+
+ numRows = numRows + 1;
+ end
+ end
+
+ if ( textStrings > 0 and progressBars > 0 ) then
+ -- If we have text criteria and progressBar criteria, display the progressBar criteria first and position the textStrings under them.
+ criteriaTable[1]:ClearAllPoints();
+ if ( textStrings == 1 ) then
+ criteriaTable[1]:SetPoint("TOP", progressBarTable[progressBars], "BOTTOM", -14, -4);
+ else
+ criteriaTable[1]:SetPoint("TOP", progressBarTable[progressBars], "BOTTOM", 0, -4);
+ criteriaTable[1]:SetPoint("LEFT", objectivesFrame, "LEFT", 0, 0);
+ end
+ elseif ( textStrings > 1 ) then
+ -- Figure out if we can make multiple columns worth of criteria instead of one long one
+ local numColumns = floor(ACHIEVEMENTUI_MAXCONTENTWIDTH/maxCriteriaWidth);
+ if ( numColumns > 1 ) then
+ local step;
+ local rows = 1;
+ local position = 0;
+ for i=1, #criteriaTable do
+ position = position + 1;
+ if ( position > numColumns ) then
+ position = position - numColumns;
+ rows = rows + 1;
+ end
+
+ if ( rows == 1 ) then
+ criteriaTable[i]:ClearAllPoints();
+ criteriaTable[i]:SetPoint("TOPLEFT", objectivesFrame, "TOPLEFT", (position - 1)*(ACHIEVEMENTUI_MAXCONTENTWIDTH/numColumns), 0);
+ else
+ criteriaTable[i]:ClearAllPoints();
+ criteriaTable[i]:SetPoint("TOPLEFT", criteriaTable[position + ((rows - 2) * numColumns)], "BOTTOMLEFT", 0, 0);
+ end
+ end
+ numRows = ceil(numRows/numColumns);
+ end
+ end
+
+ if ( metas > 0 ) then
+ objectivesFrame:SetHeight(numRows * ACHIEVEMENTBUTTON_METAROWHEIGHT + 10);
+ else
+ objectivesFrame:SetHeight(numRows * ACHIEVEMENTBUTTON_CRITERIAROWHEIGHT);
+ end
+ objectivesFrame.mode = ACHIEVEMENTMODE_CRITERIA;
+end
+
+-- [[ StatsFrames ]]--
+
+function AchievementFrameStats_OnEvent (self, event, ...)
+ if ( event == "CRITERIA_UPDATE" and self:IsShown() ) then
+ AchievementFrameStats_Update();
+ end
+end
+
+function AchievementFrameStats_OnLoad (self)
+ AchievementFrameStatsContainerScrollBar.Show =
+ function (self)
+ AchievementFrameStats:SetWidth(504);
+ for _, button in next, AchievementFrameStats.buttons do
+ button:SetWidth(496);
+ end
+ getmetatable(self).__index.Show(self);
+ end
+
+ AchievementFrameStatsContainerScrollBar.Hide =
+ function (self)
+ AchievementFrameStats:SetWidth(530);
+ for _, button in next, AchievementFrameStats.buttons do
+ button:SetWidth(522);
+ end
+ getmetatable(self).__index.Hide(self);
+ end
+
+ self:RegisterEvent("CRITERIA_UPDATE");
+ AchievementFrameStatsContainerScrollBarBG:Show();
+ AchievementFrameStatsContainer.update = AchievementFrameStats_Update;
+ HybridScrollFrame_CreateButtons(AchievementFrameStatsContainer, "StatTemplate");
+end
+
+local displayStatCategories = {};
+
+function AchievementFrameStats_Update ()
+ local category = achievementFunctions.selectedCategory;
+ local scrollFrame = AchievementFrameStatsContainer;
+ local offset = HybridScrollFrame_GetOffset(scrollFrame);
+ local buttons = scrollFrame.buttons;
+ local numButtons = #buttons;
+ local statHeight = 24;
+
+ local numStats, numCompleted = GetCategoryNumAchievements(category);
+
+ local categories = ACHIEVEMENTUI_CATEGORIES;
+ -- clear out table
+ if ( achievementFunctions.lastCategory ~= category ) then
+ local statCat;
+ for i in next, displayStatCategories do
+ displayStatCategories[i] = nil;
+ end
+ -- build a list of shown category and stat id's
+
+ tinsert(displayStatCategories, {id = category, header = true});
+ for i=1, numStats do
+ tinsert(displayStatCategories, {id = GetAchievementInfo(category, i)});
+ end
+ -- add all the subcategories and their stat id's
+ for i, cat in next, categories do
+ if ( cat.parent == category ) then
+ tinsert(displayStatCategories, {id = cat.id, header = true});
+ numStats = GetCategoryNumAchievements(cat.id);
+ for k=1, numStats do
+ tinsert(displayStatCategories, {id = GetAchievementInfo(cat.id, k)});
+ end
+ end
+ end
+ achievementFunctions.lastCategory = category;
+ end
+
+ -- iterate through the displayStatCategories and display them
+ local selection = AchievementFrameStats.selection;
+ local statCount = #displayStatCategories;
+ local statIndex, id, button;
+ local stat;
+
+ local totalHeight = statCount * statHeight;
+ local displayedHeight = numButtons * statHeight;
+ for i = 1, numButtons do
+ button = buttons[i];
+ statIndex = offset + i;
+ if ( statIndex <= statCount ) then
+ stat = displayStatCategories[statIndex];
+ if ( stat.header ) then
+ AchievementFrameStats_SetHeader(button, stat.id);
+ else
+ AchievementFrameStats_SetStat(button, stat.id, nil, statIndex);
+ end
+ button:Show();
+ else
+ button:Hide();
+ end
+ end
+ HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight);
+end
+
+function AchievementFrameStats_SetStat(button, category, index, colorIndex, isSummary)
+ --Remove these variables when we know for sure we don't need them
+ local id, name, points, completed, month, day, year, description, flags, icon;
+ if ( not isSummary ) then
+ if ( not index ) then
+ id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(category);
+ else
+ id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(category, index);
+ end
+
+ else
+ -- This is on the summary page
+ id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfoFromCriteria(category);
+ end
+
+ button.id = id;
+
+ if ( not colorIndex ) then
+ if ( not index ) then
+ message("Error, need a color index or index");
+ end
+ colorIndex = index;
+ end
+ button:SetText(name);
+ button.background:Show();
+ -- Color every other line yellow
+ if ( mod(colorIndex, 2) == 1 ) then
+ button.background:SetTexCoord(0, 1, 0.1875, 0.3671875);
+ button.background:SetBlendMode("BLEND");
+ button.background:SetAlpha(1.0);
+ button:SetHeight(24);
+ else
+ button.background:SetTexCoord(0, 1, 0.375, 0.5390625);
+ button.background:SetBlendMode("ADD");
+ button.background:SetAlpha(0.5);
+ button:SetHeight(24);
+ end
+
+ -- Figure out the criteria
+ local numCriteria = GetAchievementNumCriteria(id);
+ if ( numCriteria == 0 ) then
+ -- This is no good!
+ end
+ -- Just show the first criteria for now
+ local criteriaString, criteriaType, completed, quantityNumber, reqQuantity, charName, flags, assetID, quantity;
+ if ( not isSummary ) then
+ quantity = GetStatistic(id);
+ else
+ criteriaString, criteriaType, completed, quantityNumber, reqQuantity, charName, flags, assetID, quantity = GetAchievementCriteriaInfo(category);
+ end
+ if ( not quantity ) then
+ quantity = "--";
+ end
+ button.value:SetText(quantity);
+
+ -- Hide the header images
+ button.title:Hide();
+ button.left:Hide();
+ button.middle:Hide();
+ button.right:Hide();
+ button.isHeader = false;
+end
+
+function AchievementFrameStats_SetHeader(button, id)
+ -- show header
+ button.left:Show();
+ button.middle:Show();
+ button.right:Show();
+ local text;
+ if ( id == ACHIEVEMENT_COMPARISON_STATS_SUMMARY_ID ) then
+ text = ACHIEVEMENT_SUMMARY_CATEGORY;
+ else
+ text = GetCategoryInfo(id);
+ end
+ button.title:SetText(text);
+ button.title:Show();
+ button.value:SetText("");
+ button:SetText("");
+ button:SetHeight(24);
+ button.background:Hide();
+ button.isHeader = true;
+ button.id = id;
+end
+
+function AchievementStatButton_OnLoad(self, parentFrame)
+ local name = self:GetName();
+ self.background = _G[name.."BG"];
+ self.left = _G[name.."HeaderLeft"];
+ self.middle = _G[name.."HeaderMiddle"];
+ self.right = _G[name.."HeaderRight"];
+ self.text = _G[name.."Text"];
+ self.title = _G[name.."Title"];
+ self.value = _G[name.."Value"];
+ self.value:SetVertexColor(1, 0.97, 0.6);
+ parentFrame.buttons = parentFrame.buttons or {};
+ tinsert(parentFrame.buttons, self);
+end
+
+function AchievementStatButton_OnClick(self)
+ if ( self.isHeader ) then
+ achievementFunctions.selectedCategory = self.id;
+ AchievementFrameCategories_Update();
+ AchievementFrameStats_Update();
+ elseif ( self.summary ) then
+ AchievementFrame_SelectSummaryStatistic(self.id);
+ end
+end
+
+-- [[ Summary Frame ]] --
+function AchievementFrameSummary_OnShow()
+ if ( achievementFunctions ~= COMPARISON_ACHIEVEMENT_FUNCTIONS and achievementFunctions ~= COMPARISON_STAT_FUNCTIONS ) then
+ AchievementFrameSummary:SetWidth(530);
+ AchievementFrameSummary_Update();
+ else
+ AchievementFrameComparisonDark:Hide();
+ AchievementFrameComparisonWatermark:Hide();
+ AchievementFrameComparison:SetWidth(650);
+ AchievementFrameSummary:SetWidth(650);
+ AchievementFrameSummary_Update(true);
+ end
+end
+
+function AchievementFrameSummary_Update(isCompare)
+ AchievementFrameSummaryCategoriesStatusBar_Update();
+ AchievementFrameSummary_UpdateAchievements(GetLatestCompletedAchievements());
+end
+
+function AchievementFrameSummary_UpdateAchievements(...)
+ local numAchievements = select("#", ...);
+ local id, name, points, completed, month, day, year, description, flags, icon;
+ local buttons = AchievementFrameSummaryAchievements.buttons;
+ local button, anchorTo, achievementID;
+ local defaultAchievementCount = 1;
+
+ for i=1, ACHIEVEMENTUI_MAX_SUMMARY_ACHIEVEMENTS do
+ if ( buttons ) then
+ button = buttons[i];
+ end
+ if ( not button ) then
+ button = CreateFrame("Button", "AchievementFrameSummaryAchievement"..i, AchievementFrameSummaryAchievements, "SummaryAchievementTemplate");
+
+ if ( i == 1 ) then
+ button:SetPoint("TOPLEFT",AchievementFrameSummaryAchievementsHeader, "BOTTOMLEFT", 18, 2 );
+ button:SetPoint("TOPRIGHT",AchievementFrameSummaryAchievementsHeader, "BOTTOMRIGHT", -18, 2 );
+ else
+ anchorTo = _G["AchievementFrameSummaryAchievement"..i-1];
+ button:SetPoint("TOPLEFT",anchorTo, "BOTTOMLEFT", 0, 3 );
+ button:SetPoint("TOPRIGHT",anchorTo, "BOTTOMRIGHT", 0, 3 );
+ end
+
+ if ( not buttons ) then
+ buttons = AchievementFrameSummaryAchievements.buttons;
+ end
+ AchievementFrameSummary_LocalizeButton(button);
+ end;
+
+ if ( i <= numAchievements ) then
+ achievementID = select(i, ...);
+ id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(achievementID);
+ button.label:SetText(name);
+ button.description:SetText(description);
+ AchievementShield_SetPoints(points, button.shield.points, GameFontNormal, GameFontNormalSmall);
+ if ( points > 0 ) then
+ button.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields]]);
+ else
+ button.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields-NoPoints]]);
+ end
+ button.icon.texture:SetTexture(icon);
+ button.id = id;
+
+ if ( completed ) then
+ button.dateCompleted:SetText(string.format(SHORTDATE, day, month, year));
+ else
+ button.dateCompleted:SetText("");
+ end
+
+ button:Saturate();
+ button.tooltipTitle = nil;
+ button:Show();
+ else
+ for i=defaultAchievementCount, ACHIEVEMENTUI_MAX_SUMMARY_ACHIEVEMENTS do
+ achievementID = ACHIEVEMENTUI_DEFAULTSUMMARYACHIEVEMENTS[defaultAchievementCount];
+ if ( not achievementID ) then
+ break;
+ end
+ id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(achievementID);
+ if ( completed ) then
+ defaultAchievementCount = defaultAchievementCount+1;
+ else
+ id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(achievementID);
+ button.label:SetText(name);
+ button.description:SetText(description);
+ AchievementShield_SetPoints(points, button.shield.points, GameFontNormal, GameFontNormalSmall);
+ if ( points > 0 ) then
+ button.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields]]);
+ else
+ button.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields-NoPoints]]);
+ end
+ button.icon.texture:SetTexture(icon);
+ button.id = id;
+ if ( month ) then
+ button.dateCompleted:SetText(string.format(SHORTDATE, day, month, year));
+ else
+ button.dateCompleted:SetText("");
+ end
+ button:Show();
+ defaultAchievementCount = defaultAchievementCount+1;
+ button:Desaturate();
+ button.tooltipTitle = SUMMARY_ACHIEVEMENT_INCOMPLETE;
+ button.tooltip = SUMMARY_ACHIEVEMENT_INCOMPLETE_TEXT;
+ break;
+ end
+ end
+ end
+ end
+ if ( numAchievements == 0 ) then
+ AchievementFrameSummaryAchievementsEmptyText:Show();
+ else
+ AchievementFrameSummaryAchievementsEmptyText:Hide();
+ end
+end
+
+function AchievementFrameSummaryCategoriesStatusBar_Update()
+ local total, completed = GetNumCompletedAchievements();
+ AchievementFrameSummaryCategoriesStatusBar:SetMinMaxValues(0, total);
+ AchievementFrameSummaryCategoriesStatusBar:SetValue(completed);
+ AchievementFrameSummaryCategoriesStatusBarText:SetText(completed.."/"..total);
+end
+
+function AchievementFrameSummaryAchievement_OnLoad(self)
+ AchievementComparisonPlayerButton_OnLoad(self);
+ self.highlight = _G[self:GetName().."Highlight"];
+ AchievementFrameSummaryAchievements.buttons = AchievementFrameSummaryAchievements.buttons or {};
+ tinsert(AchievementFrameSummaryAchievements.buttons, self);
+ self:Saturate();
+ self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, 0.5);
+ self.titleBar:SetVertexColor(1,1,1,0.5);
+ self.dateCompleted:Show();
+end
+
+function AchievementFrameSummaryAchievement_OnClick(self)
+ local id = self.id
+ local nextID, completed = GetNextAchievement(id);
+ if ( nextID and completed ) then
+ local newID;
+ while ( nextID and completed ) do
+ newID, completed = GetNextAchievement(nextID);
+ if ( completed ) then
+ nextID = newID;
+ end
+ end
+ id = nextID;
+ end
+
+ AchievementFrame_SelectAchievement(id);
+end
+
+function AchievementFrameSummaryAchievement_OnEnter(self)
+ self.highlight:Show();
+ if ( self.tooltipTitle ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltipTitle,1,1,1);
+ GameTooltip:AddLine(self.tooltip, nil, nil, nil, 1);
+ GameTooltip:Show();
+ end
+end
+
+function AchievementFrameSummaryCategoryButton_OnClick (self)
+ local id = self:GetParent():GetID();
+ for _, button in next, AchievementFrameCategoriesContainer.buttons do
+ if ( button.categoryID == id ) then
+ button:Click();
+ return;
+ end
+ end
+end
+
+function AchievementFrameSummaryCategory_OnLoad (self)
+ self:SetMinMaxValues(0, 100);
+ self:SetValue(0);
+ local name = self:GetName();
+ self.text = _G[name .. "Text"];
+
+ local categoryName = GetCategoryInfo(self:GetID());
+ _G[name .. "Label"]:SetText(categoryName);
+end
+
+function AchievementFrame_GetCategoryTotalNumAchievements (id, showAll)
+ -- Not recursive because we only have one deep and this saves time.
+ local totalAchievements, totalCompleted = 0, 0;
+ local numAchievements, numCompleted = GetCategoryNumAchievements(id, showAll);
+ totalAchievements = totalAchievements + numAchievements;
+ totalCompleted = totalCompleted + numCompleted;
+
+ for _, category in next, ACHIEVEMENTUI_CATEGORIES do
+ if ( category.parent == id ) then
+ numAchievements, numCompleted = GetCategoryNumAchievements(category.id, showAll);
+ totalAchievements = totalAchievements + numAchievements;
+ totalCompleted = totalCompleted + numCompleted;
+ end
+ end
+
+ return totalAchievements, totalCompleted;
+end
+
+function AchievementFrameSummaryCategory_OnEvent (self, event, ...)
+ AchievementFrameSummaryCategory_OnShow(self);
+end
+
+function AchievementFrameSummaryCategory_OnShow (self)
+ local totalAchievements, totalCompleted = AchievementFrame_GetCategoryTotalNumAchievements(self:GetID(), true);
+
+ self.text:SetText(string.format("%d/%d", totalCompleted, totalAchievements));
+ self:SetMinMaxValues(0, totalAchievements);
+ self:SetValue(totalCompleted);
+ self:RegisterEvent("ACHIEVEMENT_EARNED");
+end
+
+function AchievementFrameSummaryCategory_OnHide (self)
+ self:UnregisterEvent("ACHIEVEMENT_EARNED");
+end
+
+function AchievementFrame_SelectAchievement(id, forceSelect)
+ if ( not AchievementFrame:IsShown() and not forceSelect ) then
+ return;
+ end
+
+ local _, _, _, achCompleted = GetAchievementInfo(id);
+ if ( achCompleted and (ACHIEVEMENTUI_SELECTEDFILTER == AchievementFrameFilters[ACHIEVEMENT_FILTER_INCOMPLETE].func) ) then
+ AchievementFrame_SetFilter(ACHIEVEMENT_FILTER_ALL);
+ elseif ( (not achCompleted) and (ACHIEVEMENTUI_SELECTEDFILTER == AchievementFrameFilters[ACHIEVEMENT_FILTER_COMPLETE].func) ) then
+ AchievementFrame_SetFilter(ACHIEVEMENT_FILTER_ALL);
+ end
+
+ AchievementFrameTab_OnClick = AchievementFrameBaseTab_OnClick;
+ AchievementFrameTab_OnClick(1);
+ AchievementFrameSummary:Hide();
+ AchievementFrameAchievements:Show();
+
+ -- Figure out if this is part of a progressive achievement; if it is and it's incomplete, make sure the previous level was completed. If not, find the first incomplete achievement in the chain and display that instead.
+ local _, _, _, completed = GetAchievementInfo(id);
+ if ( not completed and GetPreviousAchievement(id) ) then
+ local prevID = GetPreviousAchievement(id);
+ _, _, _, completed = GetAchievementInfo(prevID);
+ while ( prevID and not completed ) do
+ id = prevID;
+ prevID = GetPreviousAchievement(id);
+ if ( prevID ) then
+ _, _, _, completed = GetAchievementInfo(prevID);
+ end
+ end
+ elseif ( completed ) then
+ local nextID, completed = GetNextAchievement(id);
+ if ( nextID and completed ) then
+ local newID
+ while ( nextID and completed ) do
+ newID, completed = GetNextAchievement(nextID);
+ if ( completed ) then
+ nextID = newID;
+ end
+ end
+ id = nextID;
+ end
+ end
+
+ AchievementFrameCategories_ClearSelection();
+ local category = GetAchievementCategory(id);
+
+ local categoryIndex, parent, hidden = 0;
+ for i, entry in next, ACHIEVEMENTUI_CATEGORIES do
+ if ( entry.id == category ) then
+ parent = entry.parent;
+ end
+ end
+
+ for i, entry in next, ACHIEVEMENTUI_CATEGORIES do
+ if ( entry.id == parent ) then
+ entry.collapsed = false;
+ elseif ( entry.parent == parent ) then
+ entry.hidden = false;
+ elseif ( entry.parent == true ) then
+ entry.collapsed = true;
+ elseif ( entry.parent ) then
+ entry.hidden = true;
+ end
+ end
+
+ achievementFunctions.selectedCategory = category;
+ AchievementFrameCategoriesContainerScrollBar:SetValue(0);
+ AchievementFrameCategories_Update();
+
+ local shown, i = false, 1;
+ while ( not shown ) do
+ for _, button in next, AchievementFrameCategoriesContainer.buttons do
+ if ( button.categoryID == category and math.ceil(button:GetBottom()) >= math.ceil(AchievementFrameAchievementsContainer:GetBottom())) then
+ shown = true;
+ end
+ end
+
+ if ( not shown ) then
+ local _, maxVal = AchievementFrameCategoriesContainerScrollBar:GetMinMaxValues();
+ if ( AchievementFrameCategoriesContainerScrollBar:GetValue() == maxVal ) then
+ --assert(false)
+ return;
+ else
+ HybridScrollFrame_OnMouseWheel(AchievementFrameCategoriesContainer, -1);
+ end
+ end
+
+ -- Remove me if everything's working fine
+ i = i + 1;
+ if ( i > 100 ) then
+ --assert(false);
+ return;
+ end
+ end
+
+ AchievementFrameAchievements_ClearSelection();
+ AchievementFrameAchievementsContainerScrollBar:SetValue(0);
+ AchievementFrameAchievements_Update();
+
+ local shown = false;
+ while ( not shown ) do
+ for _, button in next, AchievementFrameAchievementsContainer.buttons do
+ if ( button.id == id and math.ceil(button:GetTop()) >= math.ceil(AchievementFrameAchievementsContainer:GetBottom())) then
+ -- The "True" here ignores modifiers, so you don't accidentally track or link this achievement. :P
+ AchievementButton_OnClick(button, true);
+
+ -- We found the button!
+ shown = button;
+ break;
+ end
+ end
+
+ local _, maxVal = AchievementFrameAchievementsContainerScrollBar:GetMinMaxValues();
+ if ( shown ) then
+ -- If we can, move the achievement we're scrolling to to the top of the screen.
+ local newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetTop() - shown:GetTop();
+ newHeight = min(newHeight, maxVal);
+ AchievementFrameAchievementsContainerScrollBar:SetValue(newHeight);
+ else
+ if ( AchievementFrameAchievementsContainerScrollBar:GetValue() == maxVal ) then
+ --assert(false, "Failed to find achievement " .. id .. " while jumping!")
+ return;
+ else
+ HybridScrollFrame_OnMouseWheel(AchievementFrameAchievementsContainer, -1);
+ end
+ end
+ end
+end
+
+function AchievementFrameAchievements_FindSelection()
+ local _, maxVal = AchievementFrameAchievementsContainerScrollBar:GetMinMaxValues();
+ local scrollHeight = AchievementFrameAchievementsContainer:GetHeight();
+ local newHeight = 0;
+ AchievementFrameAchievementsContainerScrollBar:SetValue(0);
+ while ( not shown ) do
+ for _, button in next, AchievementFrameAchievementsContainer.buttons do
+ if ( button.selected ) then
+ newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetTop() - button:GetTop();
+ newHeight = min(newHeight, maxVal);
+ AchievementFrameAchievementsContainerScrollBar:SetValue(newHeight);
+ return;
+ end
+ end
+ if ( AchievementFrameAchievementsContainerScrollBar:GetValue() == maxVal ) then
+ return;
+ else
+ newHeight = newHeight + scrollHeight;
+ newHeight = min(newHeight, maxVal);
+ AchievementFrameAchievementsContainerScrollBar:SetValue(newHeight);
+ end
+ end
+end
+
+function AchievementFrameAchievements_AdjustSelection()
+ local selectedButton;
+ -- check if selection is visible
+ for _, button in next, AchievementFrameAchievementsContainer.buttons do
+ if ( button.selected ) then
+ selectedButton = button;
+ break;
+ end
+ end
+
+ if ( not selectedButton ) then
+ AchievementFrameAchievements_FindSelection();
+ else
+ local newHeight;
+ if ( selectedButton:GetTop() > AchievementFrameAchievementsContainer:GetTop() ) then
+ newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetTop() - selectedButton:GetTop();
+ elseif ( selectedButton:GetBottom() < AchievementFrameAchievementsContainer:GetBottom() ) then
+ if ( selectedButton:GetHeight() > AchievementFrameAchievementsContainer:GetHeight() ) then
+ newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetTop() - selectedButton:GetTop();
+ else
+ newHeight = AchievementFrameAchievementsContainerScrollBar:GetValue() + AchievementFrameAchievementsContainer:GetBottom() - selectedButton:GetBottom();
+ end
+ end
+ if ( newHeight ) then
+ local _, maxVal = AchievementFrameAchievementsContainerScrollBar:GetMinMaxValues();
+ newHeight = min(newHeight, maxVal);
+ AchievementFrameAchievementsContainerScrollBar:SetValue(newHeight);
+ end
+ end
+end
+
+function AchievementFrame_SelectSummaryStatistic (criteriaId)
+ AchievementFrameTab_OnClick = AchievementFrameBaseTab_OnClick;
+ AchievementFrameTab_OnClick(2);
+ AchievementFrameStats:Show();
+ AchievementFrameSummary:Hide();
+
+ AchievementFrameCategories_ClearSelection();
+
+ local id = GetAchievementInfoFromCriteria(criteriaId);
+ local category = GetAchievementCategory(id);
+
+ local categoryIndex, parent, hidden = 0;
+
+ local categoryIndex, parent, hidden = 0;
+ for i, entry in next, ACHIEVEMENTUI_CATEGORIES do
+ if ( entry.id == category ) then
+ parent = entry.parent;
+ end
+ end
+
+ for i, entry in next, ACHIEVEMENTUI_CATEGORIES do
+ if ( entry.id == parent ) then
+ entry.collapsed = false;
+ elseif ( entry.parent == parent ) then
+ entry.hidden = false;
+ elseif ( entry.parent == true ) then
+ entry.collapsed = true;
+ elseif ( entry.parent ) then
+ entry.hidden = true;
+ end
+ end
+
+ achievementFunctions.selectedCategory = category;
+ AchievementFrameCategories_Update();
+ AchievementFrameCategoriesContainerScrollBar:SetValue(0);
+
+ local shown, i = false, 1;
+ while ( not shown ) do
+ for _, button in next, AchievementFrameCategoriesContainer.buttons do
+ if ( button.categoryID == category and math.ceil(button:GetBottom()) >= math.ceil(AchievementFrameAchievementsContainer:GetBottom())) then
+ shown = true;
+ end
+ end
+
+ if ( not shown ) then
+ local _, maxVal = AchievementFrameCategoriesContainerScrollBar:GetMinMaxValues();
+ if ( AchievementFrameCategoriesContainerScrollBar:GetValue() == maxVal ) then
+ assert(false)
+ else
+ HybridScrollFrame_OnMouseWheel(AchievementFrameCategoriesContainer, -1);
+ end
+ end
+
+ -- Remove me if everything's working fine
+ i = i + 1;
+ if ( i > 100 ) then
+ assert(false);
+ end
+ end
+
+ AchievementFrameStats_Update();
+ AchievementFrameStatsContainerScrollBar:SetValue(0);
+
+ local shown, i = false, 1;
+ while ( not shown ) do
+ for _, button in next, AchievementFrameStatsContainer.buttons do
+ if ( button.id == id and math.ceil(button:GetBottom()) >= math.ceil(AchievementFrameStatsContainer:GetBottom())) then
+ AchievementStatButton_OnClick(button);
+
+ -- We found the button! MAKE IT SHOWN ZOMG!
+ shown = button;
+ end
+ end
+
+ if ( shown and AchievementFrameStatsContainerScrollBar:IsShown() ) then
+ -- If we can, move the achievement we're scrolling to to the top of the screen.
+ AchievementFrameStatsContainerScrollBar:SetValue(AchievementFrameStatsContainerScrollBar:GetValue() + AchievementFrameStatsContainer:GetTop() - shown:GetTop());
+ elseif ( not shown ) then
+ local _, maxVal = AchievementFrameStatsContainerScrollBar:GetMinMaxValues();
+ if ( AchievementFrameStatsContainerScrollBar:GetValue() == maxVal ) then
+ assert(false)
+ else
+ HybridScrollFrame_OnMouseWheel(AchievementFrameStatsContainer, -1);
+ end
+ end
+
+ -- Remove me if everything's working fine.
+ i = i + 1;
+ if ( i > 100 ) then
+ assert(false);
+ end
+ end
+end
+
+function AchievementFrameComparison_OnLoad (self)
+ AchievementFrameComparisonContainer_OnLoad(self);
+ AchievementFrameComparisonStatsContainer_OnLoad(self);
+ self:RegisterEvent("ACHIEVEMENT_EARNED");
+ self:RegisterEvent("INSPECT_ACHIEVEMENT_READY");
+end
+
+function AchievementFrameComparisonContainer_OnLoad (parent)
+ AchievementFrameComparisonContainerScrollBar.Show =
+ function (self)
+ AchievementFrameComparison:SetWidth(626);
+ AchievementFrameComparisonSummaryPlayer:SetWidth(498);
+ for _, button in next, AchievementFrameComparisonContainer.buttons do
+ button:SetWidth(616);
+ button.player:SetWidth(498);
+ end
+ getmetatable(self).__index.Show(self);
+ end
+
+ AchievementFrameComparisonContainerScrollBar.Hide =
+ function (self)
+ AchievementFrameComparison:SetWidth(650);
+ AchievementFrameComparisonSummaryPlayer:SetWidth(522);
+ for _, button in next, AchievementFrameComparisonContainer.buttons do
+ button:SetWidth(640);
+ button.player:SetWidth(522);
+ end
+ getmetatable(self).__index.Hide(self);
+ end
+
+ AchievementFrameComparisonContainerScrollBarBG:Show();
+ AchievementFrameComparisonContainer.update = AchievementFrameComparison_Update;
+ HybridScrollFrame_CreateButtons(AchievementFrameComparisonContainer, "ComparisonTemplate", 0, -2);
+end
+
+function AchievementFrameComparisonStatsContainer_OnLoad (parent)
+ AchievementFrameComparisonStatsContainerScrollBar.Show =
+ function (self)
+ AchievementFrameComparison:SetWidth(626);
+ for _, button in next, AchievementFrameComparisonStatsContainer.buttons do
+ button:SetWidth(616);
+ end
+ getmetatable(self).__index.Show(self);
+ end
+
+ AchievementFrameComparisonStatsContainerScrollBar.Hide =
+ function (self)
+ AchievementFrameComparison:SetWidth(650);
+ for _, button in next, AchievementFrameComparisonStatsContainer.buttons do
+ button:SetWidth(640);
+ end
+ getmetatable(self).__index.Hide(self);
+ end
+
+ AchievementFrameComparisonStatsContainerScrollBarBG:Show();
+ AchievementFrameComparisonStatsContainer.update = AchievementFrameComparison_UpdateStats;
+ HybridScrollFrame_CreateButtons(AchievementFrameComparisonStatsContainer, "ComparisonStatTemplate", 0, -2);
+end
+
+function AchievementFrameComparison_OnShow ()
+ AchievementFrameStats:Hide();
+ AchievementFrameAchievements:Hide();
+ AchievementFrame:SetWidth(890);
+ AchievementFrame:SetAttribute("UIPanelLayout-xOffset", 38);
+ UpdateUIPanelPositions(AchievementFrame);
+ AchievementFrame.isComparison = true;
+end
+
+function AchievementFrameComparison_OnHide ()
+ AchievementFrame.selectedTab = nil;
+ AchievementFrame:SetWidth(768);
+ AchievementFrame:SetAttribute("UIPanelLayout-xOffset", 80);
+ UpdateUIPanelPositions(AchievementFrame);
+ AchievementFrame.isComparison = false;
+ ClearAchievementComparisonUnit();
+end
+
+function AchievementFrameComparison_OnEvent (self, event, ...)
+ if ( event == "INSPECT_ACHIEVEMENT_READY" ) then
+ AchievementFrameComparisonHeaderPoints:SetText(GetComparisonAchievementPoints());
+ AchievementFrameComparison_UpdateStatusBars(achievementFunctions.selectedCategory)
+ elseif ( event == "UNIT_PORTRAIT_UPDATE" ) then
+ local updateUnit = ...;
+ if ( updateUnit and updateUnit == AchievementFrameComparisonHeaderPortrait.unit and UnitName(updateUnit) == AchievementFrameComparisonHeaderName:GetText() ) then
+ SetPortraitTexture(AchievementFrameComparisonHeaderPortrait, updateUnit);
+ end
+ end
+
+ AchievementFrameComparison_ForceUpdate();
+end
+
+function AchievementFrameComparison_SetUnit (unit)
+ ClearAchievementComparisonUnit();
+ SetAchievementComparisonUnit(unit);
+
+ AchievementFrameComparisonHeaderPoints:SetText(GetComparisonAchievementPoints());
+ AchievementFrameComparisonHeaderName:SetText(UnitName(unit));
+ SetPortraitTexture(AchievementFrameComparisonHeaderPortrait, unit);
+ AchievementFrameComparisonHeaderPortrait.unit = unit;
+ AchievementFrameComparisonHeaderPortrait.race = UnitRace(unit);
+ AchievementFrameComparisonHeaderPortrait.sex = UnitSex(unit);
+end
+
+function AchievementFrameComparison_ClearSelection ()
+ -- Doesn't do anything WHEE~!
+end
+
+function AchievementFrameComparison_ForceUpdate ()
+ if ( achievementFunctions == COMPARISON_ACHIEVEMENT_FUNCTIONS ) then
+ local buttons = AchievementFrameComparisonContainer.buttons;
+ for i, button in next, buttons do
+ button.id = nil;
+ end
+
+ AchievementFrameComparison_Update();
+ elseif ( achievementFunctions == COMPARISON_STAT_FUNCTIONS ) then
+ AchievementFrameComparison_UpdateStats();
+ end
+end
+
+function AchievementFrameComparison_Update ()
+ local category = achievementFunctions.selectedCategory;
+ if ( not category or category == "summary" ) then
+ return;
+ end
+ local scrollFrame = AchievementFrameComparisonContainer
+
+ local offset = HybridScrollFrame_GetOffset(scrollFrame);
+ local buttons = scrollFrame.buttons;
+ local numAchievements, numCompleted = GetCategoryNumAchievements(category);
+ local numButtons = #buttons;
+
+ local achievementIndex;
+ local buttonHeight = buttons[1]:GetHeight();
+ for i = 1, numButtons do
+ achievementIndex = i + offset;
+ AchievementFrameComparison_DisplayAchievement(buttons[i], category, achievementIndex);
+ end
+
+ HybridScrollFrame_Update(scrollFrame, buttonHeight*numAchievements, buttonHeight*numButtons);
+end
+
+ACHIEVEMENTCOMPARISON_PLAYERSHIELDFONT1 = GameFontNormal;
+ACHIEVEMENTCOMPARISON_PLAYERSHIELDFONT2 = GameFontNormalSmall;
+ACHIEVEMENTCOMPARISON_FRIENDSHIELDFONT1 = GameFontNormalSmall;
+ACHIEVEMENTCOMPARISON_FRIENDSHIELDFONT2 = GameFontNormalSmall;
+
+function AchievementFrameComparison_DisplayAchievement (button, category, index)
+ local id, name, points, completed, month, day, year, description, flags, icon, rewardText = GetAchievementInfo(category, index);
+ if ( not id ) then
+ button:Hide();
+ return;
+ else
+ button:Show();
+ end
+
+ if ( GetPreviousAchievement(id) ) then
+ -- If this is a progressive achievement, show the total score.
+ points = AchievementButton_GetProgressivePoints(id);
+ end
+
+ if ( button.id ~= id ) then
+ button.id = id;
+
+ local player = button.player;
+ local friend = button.friend;
+
+ local friendCompleted, friendMonth, friendDay, friendYear = GetAchievementComparisonInfo(id);
+ player.label:SetText(name);
+
+ player.description:SetText(description);
+
+ player.icon.texture:SetTexture(icon);
+ friend.icon.texture:SetTexture(icon);
+
+ if ( points > 0 ) then
+ player.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields]]);
+ friend.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields]]);
+ else
+ player.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields-NoPoints]]);
+ friend.shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields-NoPoints]]);
+ end
+ AchievementShield_SetPoints(points, player.shield.points, ACHIEVEMENTCOMPARISON_PLAYERSHIELDFONT1, ACHIEVEMENTCOMPARISON_PLAYERSHIELDFONT2);
+ AchievementShield_SetPoints(points, friend.shield.points, ACHIEVEMENTCOMPARISON_FRIENDSHIELDFONT1, ACHIEVEMENTCOMPARISON_FRIENDSHIELDFONT2);
+
+ if ( completed and not player.completed ) then
+ player.completed = true;
+ player.dateCompleted:SetText(string.format(SHORTDATE, day, month, year));
+ player.dateCompleted:Show();
+ player:Saturate();
+ elseif ( completed ) then
+ player.dateCompleted:SetText(string.format(SHORTDATE, day, month, year));
+ else
+ player.completed = nil;
+ player.dateCompleted:Hide();
+ player:Desaturate();
+ end
+
+ if ( friendCompleted and not friend.completed ) then
+ friend.completed = true;
+ friend.status:SetText(string.format(SHORTDATE, friendDay, friendMonth, friendYear));
+ friend:Saturate();
+ elseif ( friendCompleted ) then
+ friend.status:SetText(string.format(SHORTDATE, friendDay, friendMonth, friendYear));
+ else
+ friend.completed = nil;
+ friend.status:SetText(INCOMPLETE);
+ friend:Desaturate();
+ end
+ end
+end
+
+local displayStatCategories = {};
+function AchievementFrameComparison_UpdateStats ()
+ local category = achievementFunctions.selectedCategory;
+ local scrollFrame = AchievementFrameComparisonStatsContainer;
+ local offset = HybridScrollFrame_GetOffset(scrollFrame);
+ local buttons = scrollFrame.buttons;
+ local numButtons = #buttons;
+ local headerHeight = 24;
+ local statHeight = 24;
+ local totalHeight = 0;
+ local numStats, numCompleted = GetCategoryNumAchievements(category);
+
+ local categories = ACHIEVEMENTUI_CATEGORIES;
+ -- clear out table
+ if ( achievementFunctions.lastCategory ~= category ) then
+ local statCat;
+ for i in next, displayStatCategories do
+ displayStatCategories[i] = nil;
+ end
+ -- build a list of shown category and stat id's
+
+ tinsert(displayStatCategories, {id = category, header = true});
+ totalHeight = totalHeight+headerHeight;
+
+ for i=1, numStats do
+ tinsert(displayStatCategories, {id = GetAchievementInfo(category, i)});
+ totalHeight = totalHeight+statHeight;
+ end
+ achievementFunctions.lastCategory = category;
+ achievementFunctions.lastHeight = totalHeight;
+ else
+ totalHeight = achievementFunctions.lastHeight;
+ end
+
+ -- add all the subcategories and their stat id's
+ for i, cat in next, categories do
+ if ( cat.parent == category ) then
+ tinsert(displayStatCategories, {id = cat.id, header = true});
+ totalHeight = totalHeight+headerHeight;
+ numStats = GetCategoryNumAchievements(cat.id);
+ for k=1, numStats do
+ tinsert(displayStatCategories, {id = GetAchievementInfo(cat.id, k)});
+ totalHeight = totalHeight+statHeight;
+ end
+ end
+ end
+
+ -- iterate through the displayStatCategories and display them
+ local statCount = #displayStatCategories;
+ local statIndex, id, button;
+ local stat;
+ local displayedHeight = 0;
+ for i = 1, numButtons do
+ button = buttons[i];
+ statIndex = offset + i;
+ if ( statIndex <= statCount ) then
+ stat = displayStatCategories[statIndex];
+ if ( stat.header ) then
+ AchievementFrameComparisonStats_SetHeader(button, stat.id);
+ else
+ AchievementFrameComparisonStats_SetStat(button, stat.id, nil, statIndex);
+ end
+ button:Show();
+ else
+ button:Hide();
+ end
+ displayedHeight = displayedHeight+button:GetHeight();
+ end
+ HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight);
+end
+
+function AchievementFrameComparisonStat_OnLoad (self)
+ local name = self:GetName();
+ self.background = _G[name.."BG"];
+ self.left = _G[name.."HeaderLeft"];
+ self.middle = _G[name.."HeaderMiddle"];
+ self.right = _G[name.."HeaderRight"];
+ self.left2 = _G[name.."HeaderLeft2"];
+ self.middle2 = _G[name.."HeaderMiddle2"];
+ self.right2 = _G[name.."HeaderRight2"];
+ self.text = _G[name.."Text"];
+ self.title = _G[name.."Title"];
+ self.value = _G[name.."Value"];
+ self.value:SetVertexColor(1, 0.97, 0.6);
+ self.friendValue = _G[name.."ComparisonValue"];
+ self.friendValue:SetVertexColor(1, 0.97, 0.6);
+ self.mouseover = _G[name.. "Mouseover"];
+end
+
+function AchievementFrameComparisonStats_SetStat (button, category, index, colorIndex, isSummary)
+--Remove these variables when we know for sure we don't need them
+ local id, name, points, completed, month, day, year, description, flags, icon;
+ if ( not isSummary ) then
+ if ( not index ) then
+ id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(category);
+ else
+ id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(category, index);
+ end
+
+ else
+ -- This is on the summary page
+ id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfoFromCriteria(category);
+ end
+
+ button.id = id;
+
+ if ( not colorIndex ) then
+ if ( not index ) then
+ message("Error, need a color index or index");
+ end
+ colorIndex = index;
+ end
+
+ button.background:Show();
+ -- Color every other line yellow
+ if ( mod(colorIndex, 2) == 1 ) then
+ button.background:SetTexCoord(0, 1, 0.1875, 0.3671875);
+ button.background:SetBlendMode("BLEND");
+ button.background:SetAlpha(1.0);
+ button:SetHeight(24);
+ else
+ button.background:SetTexCoord(0, 1, 0.375, 0.5390625);
+ button.background:SetBlendMode("ADD");
+ button.background:SetAlpha(0.5);
+ button:SetHeight(24);
+ end
+
+ -- Figure out the criteria
+ local numCriteria = GetAchievementNumCriteria(id);
+ if ( numCriteria == 0 ) then
+ -- This is no good!
+ end
+ -- Just show the first criteria for now
+ local criteriaString, criteriaType, completed, quantityNumber, reqQuantity, charName, flags, assetID, quantity, friendQuantity;
+ if ( not isSummary ) then
+ friendQuantity = GetComparisonStatistic(id);
+ quantity = GetStatistic(id);
+ else
+ criteriaString, criteriaType, completed, quantityNumber, reqQuantity, charName, flags, assetID, quantity = GetAchievementCriteriaInfo(category);
+ end
+ if ( not quantity ) then
+ quantity = "--";
+ end
+ if ( not friendQuantity ) then
+ friendQuantity = "--";
+ end
+
+ button.value:SetText(quantity);
+
+ -- We're gonna use button.text here to measure string width for friendQuantity. This saves us many strings!
+ button.text:SetText(friendQuantity);
+ local width = button.text:GetStringWidth();
+ if ( width > button.friendValue:GetWidth() ) then
+ button.friendValue:SetFontObject("AchievementFont_Small");
+ button.mouseover:Show();
+ button.mouseover.tooltip = friendQuantity;
+ else
+ button.friendValue:SetFontObject("GameFontHighlightRight");
+ button.mouseover:Hide();
+ button.mouseover.tooltip = nil;
+ end
+
+ button.text:SetText(name);
+ button.friendValue:SetText(friendQuantity);
+
+
+ -- Hide the header images
+ button.title:Hide();
+ button.left:Hide();
+ button.middle:Hide();
+ button.right:Hide();
+ button.left2:Hide();
+ button.middle2:Hide();
+ button.right2:Hide();
+ button.isHeader = false;
+end
+
+function AchievementFrameComparisonStats_SetHeader(button, id)
+ -- show header
+ button.left:Show();
+ button.middle:Show();
+ button.right:Show();
+ button.left2:Show();
+ button.middle2:Show();
+ button.right2:Show();
+ button.title:SetText(GetCategoryInfo(id));
+ button.title:Show();
+ button.friendValue:SetText("");
+ button.value:SetText("");
+ button.text:SetText("");
+ button:SetHeight(24);
+ button.background:Hide();
+ button.isHeader = true;
+ button.id = id;
+end
+
+function AchievementComparisonPlayerButton_Saturate (self)
+ local name = self:GetName();
+ _G[name .. "TitleBackground"]:SetTexCoord(0, 0.9765625, 0, 0.3125);
+ _G[name .. "Background"]:SetTexture("Interface\\AchievementFrame\\UI-Achievement-Parchment-Horizontal");
+ _G[name .. "Glow"]:SetVertexColor(1.0, 1.0, 1.0);
+ self.icon:Saturate();
+ self.shield:Saturate();
+ self.shield.points:SetVertexColor(1, 1, 1);
+ self.label:SetVertexColor(1, 1, 1);
+ self.description:SetTextColor(0, 0, 0, 1);
+ self.description:SetShadowOffset(0, 0);
+ self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
+end
+
+function AchievementComparisonPlayerButton_Desaturate (self)
+ local name = self:GetName();
+ _G[name .. "TitleBackground"]:SetTexCoord(0, 0.9765625, 0.34375, 0.65625);
+ _G[name .. "Background"]:SetTexture("Interface\\AchievementFrame\\UI-Achievement-Parchment-Horizontal-Desaturated");
+ _G[name .. "Glow"]:SetVertexColor(.22, .17, .13);
+ self.icon:Desaturate();
+ self.shield:Desaturate();
+ self.shield.points:SetVertexColor(.65, .65, .65);
+ self.label:SetVertexColor(.65, .65, .65);
+ self.description:SetTextColor(1, 1, 1, 1);
+ self.description:SetShadowOffset(1, -1);
+ self:SetBackdropBorderColor(.5, .5, .5);
+end
+
+function AchievementComparisonPlayerButton_OnLoad (self)
+ local name = self:GetName();
+
+ self.label = _G[name .. "Label"];
+ self.description = _G[name .. "Description"];
+ self.icon = _G[name .. "Icon"];
+ self.shield = _G[name .. "Shield"];
+ self.dateCompleted = _G[name .. "DateCompleted"];
+ self.titleBar = _G[name .. "TitleBackground"];
+
+ self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
+ self.Saturate = AchievementComparisonPlayerButton_Saturate;
+ self.Desaturate = AchievementComparisonPlayerButton_Desaturate;
+
+ self:Desaturate();
+
+ -- AchievementFrameComparison.buttons = AchievementFrameComparison.buttons or {};
+ -- tinsert(AchievementFrameComparison.buttons, self);
+end
+
+function AchievementComparisonFriendButton_Saturate (self)
+ local name = self:GetName();
+ _G[name .. "TitleBackground"]:SetTexCoord(0.3, 0.575, 0, 0.3125);
+ _G[name .. "Background"]:SetTexture("Interface\\AchievementFrame\\UI-Achievement-Parchment-Horizontal");
+ _G[name .. "Glow"]:SetVertexColor(1.0, 1.0, 1.0);
+ self.icon:Saturate();
+ self.shield:Saturate();
+ self.shield.points:SetVertexColor(1, 1, 1);
+ self.status:SetVertexColor(1, .82, 0);
+ self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
+end
+
+function AchievementComparisonFriendButton_Desaturate (self)
+ local name = self:GetName();
+ _G[name .. "TitleBackground"]:SetTexCoord(0.3, 0.575, 0.34375, 0.65625);
+ _G[name .. "Background"]:SetTexture("Interface\\AchievementFrame\\UI-Achievement-Parchment-Horizontal-Desaturated");
+ _G[name .. "Glow"]:SetVertexColor(.22, .17, .13);
+ self.icon:Desaturate();
+ self.shield:Desaturate();
+ self.shield.points:SetVertexColor(.65, .65, .65);
+ self.status:SetVertexColor(.65, .65, .65);
+ self:SetBackdropBorderColor(.5, .5, .5);
+end
+
+function AchievementComparisonFriendButton_OnLoad (self)
+ local name = self:GetName();
+
+ self.status = _G[name .. "Status"];
+ self.icon = _G[name .. "Icon"];
+ self.shield = _G[name .. "Shield"];
+
+ self:SetBackdropBorderColor(ACHIEVEMENTUI_REDBORDER_R, ACHIEVEMENTUI_REDBORDER_G, ACHIEVEMENTUI_REDBORDER_B, ACHIEVEMENTUI_REDBORDER_A);
+ self.Saturate = AchievementComparisonFriendButton_Saturate;
+ self.Desaturate = AchievementComparisonFriendButton_Desaturate;
+
+ self:Desaturate();
+end
+
+function AchievementFrame_IsComparison()
+ return AchievementFrame.isComparison;
+end
+
+function AchievementFrame_IsFeatOfStrength()
+ if ( AchievementFrame.selectedTab == 1 and achievementFunctions.selectedCategory == displayCategories[#displayCategories].id ) then
+ return true;
+ end
+ return false;
+end
+
+ACHIEVEMENT_FUNCTIONS = {
+ categoryAccessor = GetCategoryList,
+ clearFunc = AchievementFrameAchievements_ClearSelection,
+ updateFunc = AchievementFrameAchievements_Update,
+ selectedCategory = "summary";
+}
+
+STAT_FUNCTIONS = {
+ categoryAccessor = GetStatisticsCategoryList,
+ clearFunc = nil,
+ updateFunc = AchievementFrameStats_Update,
+ selectedCategory = "summary";
+}
+
+COMPARISON_ACHIEVEMENT_FUNCTIONS = {
+ categoryAccessor = GetCategoryList,
+ clearFunc = AchievementFrameComparison_ClearSelection,
+ updateFunc = AchievementFrameComparison_Update,
+ selectedCategory = -1,
+}
+
+COMPARISON_STAT_FUNCTIONS = {
+ categoryAccessor = GetStatisticsCategoryList,
+ clearFunc = AchievementFrameComparison_ClearSelection,
+ updateFunc = AchievementFrameComparison_UpdateStats,
+ selectedCategory = -2,
+}
+
+achievementFunctions = ACHIEVEMENT_FUNCTIONS;
+
+
+ACHIEVEMENT_TEXTURES_TO_LOAD = {
+ {
+ name="AchievementFrameAchievementsBackground",
+ file="Interface\\AchievementFrame\\UI-Achievement-AchievementBackground",
+ },
+ {
+ name="AchievementFrameSummaryBackground",
+ file="Interface\\AchievementFrame\\UI-Achievement-AchievementBackground",
+ },
+ {
+ name="AchievementFrameComparisonBackground",
+ file="Interface\\AchievementFrame\\UI-Achievement-AchievementBackground",
+ },
+ {
+ name="AchievementFrameCategoriesBG",
+ file="Interface\\AchievementFrame\\UI-Achievement-AchievementBackground",
+ },
+ {
+ name="AchievementFrameWaterMark",
+ },
+ {
+ name="AchievementFrameHeaderLeft",
+ file="Interface\\AchievementFrame\\UI-Achievement-Header",
+ },
+ {
+ name="AchievementFrameHeaderRight",
+ file="Interface\\AchievementFrame\\UI-Achievement-Header",
+ },
+ {
+ name="AchievementFrameHeaderPointBorder",
+ file="Interface\\AchievementFrame\\UI-Achievement-Header",
+ },
+ {
+ name="AchievementFrameComparisonWatermark",
+ file="Interface\\AchievementFrame\\UI-Achievement-StatsComparisonBackground",
+ },
+}
+
+function AchievementFrame_ClearTextures()
+ for k, v in pairs(ACHIEVEMENT_TEXTURES_TO_LOAD) do
+ _G[v.name]:SetTexture(nil);
+ end
+end
+
+function AchievementFrame_LoadTextures()
+ for k, v in pairs(ACHIEVEMENT_TEXTURES_TO_LOAD) do
+ if ( v.file ) then
+ _G[v.name]:SetTexture(v.file);
+ end
+ end
+end
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_AchievementUI/Blizzard_AchievementUI.toc b/reference/AddOns/Blizzard_AchievementUI/Blizzard_AchievementUI.toc
new file mode 100644
index 0000000..3bce478
--- /dev/null
+++ b/reference/AddOns/Blizzard_AchievementUI/Blizzard_AchievementUI.toc
@@ -0,0 +1,10 @@
+## Interface: 30300
+## Title: Blizzard_AchievementUI
+## Notes: Hooray for Achievements! Everybody loves Achievements =D
+## Secure: 1
+## Author: Blizzard Entertainment
+## Version: 1.0
+## LoadOnDemand: 1
+Blizzard_AchievementUI.lua
+Blizzard_AchievementUI.xml
+Localization.lua
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_AchievementUI/Blizzard_AchievementUI.xml b/reference/AddOns/Blizzard_AchievementUI/Blizzard_AchievementUI.xml
new file mode 100644
index 0000000..1b70db5
--- /dev/null
+++ b/reference/AddOns/Blizzard_AchievementUI/Blizzard_AchievementUI.xml
@@ -0,0 +1,3379 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AchievementFrameSummaryCategory_OnLoad(self);
+
+
+ AchievementFrameSummaryCategory_OnShow(self);
+
+
+ AchievementFrameSummaryCategory_OnHide(self);
+
+
+ AchievementFrameSummaryCategory_OnEvent(self, event, ...);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ local tracked = AchievementButton_ToggleTracking(self:GetParent().id);
+ if ( not tracked ) then
+ self:SetChecked(0);
+ end
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self:GetChecked() ) then
+ GameTooltip:SetText(UNTRACK_ACHIEVEMENT_TOOLTIP, nil, nil, nil, nil, 1);
+ else
+ GameTooltip:SetText(TRACK_ACHIEVEMENT_TOOLTIP, nil, nil, nil, nil, 1);
+ end
+
+
+ GameTooltip:Hide();
+
+
+ self:SetChecked(IsTrackedAchievement(self:GetParent().id));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ self.points = _G[name .. "Points"];
+ self.icon = _G[name .. "Icon"];
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self.name ) then
+ GameTooltip:AddDoubleLine(self.name, self.date, nil, nil, nil, .5, .5, .5);
+ end
+ if ( self.desc ) then
+ GameTooltip:AddLine(self.desc, 1, 1, 1, 1);
+ end
+ if ( self.numCriteria ) then
+ for i = 1, self.numCriteria do
+ GameTooltip:AddLine(self["criteria"..i]);
+ end
+ end
+ GameTooltip:Show();
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetStatusBarColor(0, .6, 0, 1);
+ self:SetMinMaxValues(0, 100);
+ self:SetValue(0);
+ self.text = _G[self:GetName() .. "Text"];
+ self:GetStatusBarTexture():SetDrawLayer("BORDER");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ self.title = _G[name .. "Title"];
+ self.text = _G[name .. "Text"];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AchievementIcon_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ self.name = _G[name .. "Name"];
+ self.check = _G[name .. "Check"];
+
+
+ if ( button == "LeftButton" ) then
+ self:GetParent():GetParent():Click();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AchievementComparisonPlayerButton_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AchievementIcon_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AchievementShield_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AchievementFrameSummaryAchievement_OnLoad(self);
+
+
+ AchievementFrameSummaryAchievement_OnClick(self, button, down);
+
+
+ AchievementFrameSummaryAchievement_OnEnter(self, motion);
+
+
+ self.highlight:Hide();
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AchievementComparisonFriendButton_OnLoad(self);
+
+
+
+
+
+
+ local name = self:GetName();
+ self.player = _G[name .. "Player"];
+ self.friend = _G[name .. "Friend"];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local tooltip = self.tooltip;
+ if ( tooltip ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+ AchievementFrameComparisonStat_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AchievementFrameFilterDropDown:Hide();
+ AchievementFrameHeaderRightDDLInset:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("ACHIEVEMENT_EARNED");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ --Temporaries
+ SetPortraitTexture(_G[self:GetName().."Portrait"], "player");
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 4);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.2, 0, 1);
+ self.statusBar = _G[self:GetName().."StatusBar"];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.2, 0, 1);
+ self.statusBar = _G[self:GetName().."StatusBar"];
+ self.statusBar.title:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parentName = self:GetParent():GetName();
+ _G[parentName .. "Summary"]:Show();
+ _G[parentName .. "Watermark"]:Hide();
+ _G[parentName .. "Dark"]:Show();
+
+
+ local parentName = self:GetParent():GetName();
+ _G[parentName .. "Summary"]:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parentName = self:GetParent():GetName();
+ _G[parentName .. "Watermark"]:Show();
+ _G[parentName .. "Dark"]:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CloseDropDownMenus()
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_AchievementUI/Localization.lua b/reference/AddOns/Blizzard_AchievementUI/Localization.lua
new file mode 100644
index 0000000..f4b6d1c
--- /dev/null
+++ b/reference/AddOns/Blizzard_AchievementUI/Localization.lua
@@ -0,0 +1,21 @@
+-- This file is executed at the end of addon load
+
+function AchievementFrameSummary_LocalizeButton (button)
+
+end
+
+function AchievementButton_LocalizeMiniAchievement (frame)
+
+end
+
+function AchievementButton_LocalizeProgressBar (frame)
+
+end
+
+function AchievementButton_LocalizeMetaAchievement (frame)
+
+end
+
+function AchievementFrame_LocalizeCriteria (frame)
+
+end
diff --git a/reference/AddOns/Blizzard_ArenaUI/Blizzard_ArenaUI.lua b/reference/AddOns/Blizzard_ArenaUI/Blizzard_ArenaUI.lua
new file mode 100644
index 0000000..d72b6ec
--- /dev/null
+++ b/reference/AddOns/Blizzard_ArenaUI/Blizzard_ArenaUI.lua
@@ -0,0 +1,335 @@
+MAX_ARENA_ENEMIES = 5;
+
+function ArenaEnemyFrames_OnLoad(self)
+ self:RegisterEvent("CVAR_UPDATE");
+ self:RegisterEvent("VARIABLES_LOADED");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+ if ( GetCVarBool("showArenaEnemyFrames") ) then
+ ArenaEnemyFrames_Enable(self);
+ else
+ ArenaEnemyFrames_Disable(self);
+ end
+ local showCastbars = GetCVarBool("showArenaEnemyCastbar");
+ local castFrame;
+ for i = 1, MAX_ARENA_ENEMIES do
+ castFrame = _G["ArenaEnemyFrame"..i.."CastingBar"];
+ castFrame.showCastbar = showCastbars;
+ CastingBarFrame_UpdateIsShown(castFrame);
+ end
+
+ UpdateArenaEnemyBackground(GetCVarBool("showPartyBackground"));
+ ArenaEnemyBackground_SetOpacity(tonumber(GetCVar("partyBackgroundOpacity")));
+end
+
+function ArenaEnemyFrames_OnEvent(self, event, ...)
+ local arg1, arg2 = ...;
+ if ( (event == "CVAR_UPDATE") and (arg1 == "SHOW_ARENA_ENEMY_FRAMES_TEXT") ) then
+ if ( arg2 == "1" ) then
+ ArenaEnemyFrames_Enable(self);
+ else
+ ArenaEnemyFrames_Disable(self);
+ end
+ elseif ( event == "VARIABLES_LOADED" ) then
+ if ( GetCVarBool("showArenaEnemyFrames") ) then
+ ArenaEnemyFrames_Enable(self);
+ else
+ ArenaEnemyFrames_Disable(self);
+ end
+ local showCastbars = GetCVarBool("showArenaEnemyCastbar");
+ local castFrame;
+ for i = 1, MAX_ARENA_ENEMIES do
+ castFrame = _G["ArenaEnemyFrame"..i.."CastingBar"];
+ castFrame.showCastbar = showCastbars;
+ CastingBarFrame_UpdateIsShown(castFrame);
+ end
+ for i=1, MAX_ARENA_ENEMIES do
+ ArenaEnemyFrame_UpdatePet(_G["ArenaEnemyFrame"..i], i, true);
+ end
+ UpdateArenaEnemyBackground(GetCVarBool("showPartyBackground"));
+ ArenaEnemyBackground_SetOpacity(tonumber(GetCVar("partyBackgroundOpacity")));
+ elseif ( event == "PLAYER_ENTERING_WORLD" ) then
+ ArenaEnemyFrames_UpdateVisible();
+ end
+end
+
+function ArenaEnemyFrames_OnShow(self)
+ --Set it up to hide stuff we don't want shown in an arena.
+ ArenaEnemyFrames_UpdateWatchFrame();
+
+ DurabilityFrame_SetAlerts();
+ UIParent_ManageFramePositions();
+end
+
+function ArenaEnemyFrames_UpdateWatchFrame()
+ local ArenaEnemyFrames = ArenaEnemyFrames;
+ if ( not WatchFrame:IsUserPlaced() ) then
+ if ( ArenaEnemyFrames:IsShown() ) then
+ if ( WatchFrame_RemoveObjectiveHandler(WatchFrame_DisplayTrackedQuests) ) then
+ ArenaEnemyFrames.hidWatchedQuests = true;
+ end
+ else
+ if ( ArenaEnemyFrames.hidWatchedQuests ) then
+ WatchFrame_AddObjectiveHandler(WatchFrame_DisplayTrackedQuests);
+ ArenaEnemyFrames.hidWatchedQuests = false;
+ end
+ end
+ WatchFrame_ClearDisplay();
+ WatchFrame_Update();
+ elseif ( ArenaEnemyFrames.hidWatchedQuests ) then
+ WatchFrame_AddObjectiveHandler(WatchFrame_DisplayTrackedQuests);
+ ArenaEnemyFrames.hidWatchedQuests = false;
+ WatchFrame_ClearDisplay();
+ WatchFrame_Update();
+ end
+end
+
+function ArenaEnemyFrames_OnHide(self)
+ --Make the stuff that needs to be shown shown again.
+ ArenaEnemyFrames_UpdateWatchFrame();
+
+ DurabilityFrame_SetAlerts();
+ UIParent_ManageFramePositions();
+end
+
+function ArenaEnemyFrames_Enable(self)
+ self.show = true;
+ ArenaEnemyFrames_UpdateVisible();
+end
+
+function ArenaEnemyFrames_Disable(self)
+ self.show = false;
+ ArenaEnemyFrames_UpdateVisible();
+end
+
+function ArenaEnemyFrames_UpdateVisible()
+ local _, instanceType = IsInInstance();
+ if ( ArenaEnemyFrames.show and (instanceType == "arena")) then
+ ArenaEnemyFrames:Show();
+ else
+ ArenaEnemyFrames:Hide();
+ end
+end
+
+function ArenaEnemyFrame_OnLoad(self)
+ self.statusCounter = 0;
+ self.statusSign = -1;
+ self.unitHPPercent = 1;
+
+ self.classPortrait = _G[self:GetName().."ClassPortrait"];
+ ArenaEnemyFrame_UpdatePlayer(self, true);
+ self:RegisterEvent("UNIT_PET");
+ self:RegisterEvent("ARENA_OPPONENT_UPDATE");
+ self:RegisterEvent("UNIT_NAME_UPDATE");
+
+ UIDropDownMenu_Initialize(self.DropDown, ArenaEnemyDropDown_Initialize, "MENU");
+
+ local setfocus = function()
+ FocusUnit("arena"..self:GetID());
+ end
+ SecureUnitButton_OnLoad(self, "arena"..self:GetID(), setfocus);
+
+ local id = self:GetID();
+ if ( UnitClass("arena"..id) and (not UnitExists("arena"..id))) then --It is possible for the unit itself to no longer exist on the client, but some of the information to remain (after reloading the UI)
+ self:Show();
+ ArenaEnemyFrame_Lock(self);
+ elseif ( UnitExists("arenapet"..id) and ( not UnitClass("arena"..id) ) ) then --We use UnitClass because even if the unit doesn't exist on the client, we may still have enough info to populate the frame.
+ ArenaEnemyFrame_SetMysteryPlayer(self);
+ end
+end
+
+function ArenaEnemyFrame_UpdatePlayer(self, useCVars)--At some points, we need to use CVars instead of UVars even though UVars are faster.
+ local id = self:GetID();
+ if ( UnitGUID(self.unit) ) then --Use UnitGUID instead of UnitExists in case the unit is a remote update.
+ self:Show();
+ UnitFrame_Update(self);
+ end
+
+ local _, class = UnitClass(self.unit);
+
+ if( class ) then
+ self.classPortrait:SetTexture("Interface\\TargetingFrame\\UI-Classes-Circles");
+ self.classPortrait:SetTexCoord(unpack(CLASS_ICON_TCOORDS[class]));
+ end
+
+ ArenaEnemyFrames_UpdateVisible();
+end
+
+function ArenaEnemyFrame_Lock(self)
+ self.healthbar:SetStatusBarColor(0.5, 0.5, 0.5);
+ self.healthbar.lockColor = true;
+ self.manabar:SetStatusBarColor(0.5, 0.5, 0.5);
+ self.manabar.lockColor = true;
+ self.hideStatusOnTooltip = true;
+end
+
+function ArenaEnemyFrame_Unlock(self)
+ self.healthbar.lockColor = false;
+ self.healthbar.forceHideText = false;
+ self.manabar.lockColor = false;
+ self.manabar.forceHideText = false;
+ self.hideStatusOnTooltip = false;
+end
+
+function ArenaEnemyFrame_SetMysteryPlayer(self)
+ self.healthbar:SetMinMaxValues(0,100);
+ self.healthbar:SetValue(100);
+ self.healthbar.forceHideText = true;
+ self.manabar:SetMinMaxValues(0,100);
+ self.manabar:SetValue(100);
+ self.manabar.forceHideText = true;
+ self.classPortrait:SetTexture("Interface\\CharacterFrame\\TempPortrait");
+ self.classPortrait:SetTexCoord(0, 1, 0, 1);
+ self.name:SetText("");
+ ArenaEnemyFrame_Lock(self);
+ self:Show();
+end
+
+function ArenaEnemyFrame_OnEvent(self, event, arg1, arg2)
+ if ( event == "ARENA_OPPONENT_UPDATE" and arg1 == self.unit ) then
+ if ( arg2 == "seen" or arg2 == "destroyed") then
+ ArenaEnemyFrame_Unlock(self);
+ ArenaEnemyFrame_UpdatePlayer(self);
+
+ if ( self.healthbar.frequentUpdates and GetCVarBool("predictedHealth") ) then
+ self.healthbar:SetScript("OnUpdate", UnitFrameHealthBar_OnUpdate);
+ self.healthbar:UnregisterEvent("UNIT_HEALTH");
+ end
+ if ( self.manabar.frequentUpdates and GetCVarBool("predictedPower") ) then
+ self.manabar:SetScript("OnUpdate", UnitFrameManaBar_OnUpdate);
+ UnitFrameManaBar_UnregisterDefaultEvents(self.manabar);
+ end
+ UpdateArenaEnemyBackground();
+ UIParent_ManageFramePositions();
+ elseif ( arg2 == "unseen" ) then
+ ArenaEnemyFrame_Lock(self);
+
+ self.healthbar:RegisterEvent("UNIT_HEALTH");
+ self.healthbar:SetScript("OnUpdate", nil);
+ UnitFrameManaBar_RegisterDefaultEvents(self.manabar);
+ self.manabar:SetScript("OnUpdate", nil);
+ elseif ( arg2 == "cleared" ) then
+ ArenaEnemyFrame_Unlock(self);
+ self:Hide();
+ ArenaEnemyFrames_UpdateVisible();
+ end
+ elseif ( event == "UNIT_PET" and arg1 == self.unit ) then
+ ArenaEnemyFrame_UpdatePet(self);
+ elseif ( event == "UNIT_NAME_UPDATE" and arg1 == self.unit ) then
+ ArenaEnemyFrame_UpdatePlayer(self);
+ end
+end
+
+function ArenaEnemyFrame_UpdatePet(self, id, useCVars) --At some points, we need to use CVars instead of UVars even though UVars are faster.
+ if ( not id ) then
+ id = self:GetID();
+ end
+
+ local unitFrame = _G["ArenaEnemyFrame"..id];
+ local petFrame = _G["ArenaEnemyFrame"..id.."PetFrame"];
+
+ local showArenaEnemyPets = (SHOW_ARENA_ENEMY_PETS == "1");
+ if ( useCVars ) then
+ showArenaEnemyPets = GetCVarBool("showArenaEnemyPets");
+ end
+
+ if ( UnitGUID(petFrame.unit) and showArenaEnemyPets) then
+ petFrame:Show();
+ else
+ petFrame:Hide();
+ end
+
+ UnitFrame_Update(petFrame);
+end
+
+function ArenaEnemyPetFrame_OnLoad(self)
+ local id = self:GetParent():GetID();
+ local prefix = "ArenaEnemyFrame"..id.."PetFrame";
+ local unit = "arenapet"..id;
+ UnitFrame_Initialize(self, unit, _G[prefix.."Name"], _G[prefix.."Portrait"],
+ _G[prefix.."HealthBar"], _G[prefix.."HealthBarText"], _G[prefix.."ManaBar"], _G[prefix.."ManaBarText"]);
+ SetTextStatusBarTextZeroText(_G[prefix.."HealthBar"], DEAD);
+ _G[prefix.."Name"]:Hide();
+ SecureUnitButton_OnLoad(self, unit);
+ self:SetID(id);
+ self:SetParent(ArenaEnemyFrames);
+ ArenaEnemyFrame_UpdatePet(self, id, true);
+ self:RegisterEvent("ARENA_OPPONENT_UPDATE");
+ self:RegisterEvent("UNIT_CLASSIFICATION_CHANGED");
+
+ UIDropDownMenu_Initialize(self.DropDown, ArenaEnemyPetDropDown_Initialize, "MENU");
+
+ local setfocus = function()
+ FocusUnit("arenapet"..self:GetID());
+ end
+ SecureUnitButton_OnLoad(self, "arenapet"..self:GetID(), setfocus);
+end
+
+function ArenaEnemyPetFrame_OnEvent(self, event, ...)
+ local arg1, arg2 = ...;
+ if ( event == "ARENA_OPPONENT_UPDATE" and arg1 == self.unit ) then
+ if ( arg2 == "seen" or arg2 == "destroyed") then
+ ArenaEnemyFrame_Unlock(self);
+ ArenaEnemyFrame_UpdatePet(self);
+ UpdateArenaEnemyBackground();
+ local ownerFrame = _G["ArenaEnemyFrame"..self:GetID()];
+ if ( not ownerFrame:IsShown() ) then
+ ArenaEnemyFrame_SetMysteryPlayer(ownerFrame);
+ ownerFrame:Show();
+ end
+ if ( self.healthbar.frequentUpdates and GetCVarBool("predictedHealth") ) then
+ self.healthbar:SetScript("OnUpdate", UnitFrameHealthBar_OnUpdate);
+ self.healthbar:UnregisterEvent("UNIT_HEALTH");
+ end
+ if ( self.manabar.frequentUpdates and GetCVarBool("predictedPower") ) then
+ self.manabar:SetScript("OnUpdate", UnitFrameManaBar_OnUpdate);
+ UnitFrameManaBar_UnregisterDefaultEvents(self.manabar);
+ end
+ elseif ( arg2 == "unseen" ) then
+ ArenaEnemyFrame_Lock(self);
+ self.healthbar:RegisterEvent("UNIT_HEALTH");
+ self.healthbar:SetScript("OnUpdate", nil);
+ UnitFrameManaBar_RegisterDefaultEvents(self.manabar);
+ self.manabar:SetScript("OnUpdate", nil);
+ elseif ( arg2 == "cleared" ) then
+ ArenaEnemyFrame_Unlock(self);
+ self:Hide()
+ end
+ elseif ( event == "UNIT_CLASSIFICATION_CHANGED" and arg1 == self.unit ) then
+ UnitFrame_Update(self);
+ end
+ UnitFrame_OnEvent(self, event, ...);
+end
+
+function ArenaEnemyDropDown_Initialize(self)
+ UnitPopup_ShowMenu(self, "ARENAENEMY", "arena"..self:GetParent():GetID());
+end
+
+function ArenaEnemyPetDropDown_Initialize(self)
+ UnitPopup_ShowMenu(self, "ARENAENEMY", "arenapet"..self:GetParent():GetID());
+end
+
+function UpdateArenaEnemyBackground(force)
+ if ( (SHOW_PARTY_BACKGROUND == "1") or force ) then
+ ArenaEnemyBackground:Show();
+ local numOpps = GetNumArenaOpponents();
+ if ( numOpps > 0 ) then
+ ArenaEnemyBackground:SetPoint("BOTTOMLEFT", "ArenaEnemyFrame"..numOpps.."PetFrame", "BOTTOMLEFT", -15, -10);
+ else
+ ArenaEnemyBackground:Hide();
+ end
+ else
+ ArenaEnemyBackground:Hide();
+ end
+
+end
+
+function ArenaEnemyBackground_SetOpacity(opacity)
+ local alpha;
+ if ( not opacity ) then
+ alpha = 1.0 - OpacityFrameSlider:GetValue();
+ else
+ alpha = 1.0 - opacity;
+ end
+ ArenaEnemyBackground:SetAlpha(alpha);
+end
diff --git a/reference/AddOns/Blizzard_ArenaUI/Blizzard_ArenaUI.toc b/reference/AddOns/Blizzard_ArenaUI/Blizzard_ArenaUI.toc
new file mode 100644
index 0000000..01ad956
--- /dev/null
+++ b/reference/AddOns/Blizzard_ArenaUI/Blizzard_ArenaUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard Arena UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_ArenaUI.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_ArenaUI/Blizzard_ArenaUI.xml b/reference/AddOns/Blizzard_ArenaUI/Blizzard_ArenaUI.xml
new file mode 100644
index 0000000..e434e37
--- /dev/null
+++ b/reference/AddOns/Blizzard_ArenaUI/Blizzard_ArenaUI.xml
@@ -0,0 +1,577 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CastingBarFrame_OnLoad(self, "arena"..self:GetParent():GetID(), false, true);
+ _G[self:GetName().."Icon"]:Show();
+
+
+ CastingBarFrame_OnEvent(self, event, ...);
+
+
+ CastingBarFrame_OnUpdate(self, elapsed);
+
+
+ CastingBarFrame_OnShow(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("VARIABLES_LOADED");
+ UpdateArenaEnemyBackground();
+
+
+ self:SetFrameLevel(1);
+
+
+ if ( event == "VARIABLES_LOADED" ) then
+ UpdateArenaEnemyBackground();
+ OpacityFrameSlider:SetValue(tonumber(GetCVar("partyBackgroundOpacity")));
+ ArenaEnemyBackground_SetOpacity();
+ end
+
+
+ if ( button == "RightButton" ) then
+ PartyMemberBackground_ToggleOpacity(self);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_ArenaUI/Localization.lua b/reference/AddOns/Blizzard_ArenaUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_ArenaUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionDressUp.lua b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionDressUp.lua
new file mode 100644
index 0000000..33464f7
--- /dev/null
+++ b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionDressUp.lua
@@ -0,0 +1,35 @@
+
+local DressUpItemLink_orig = DressUpItemLink;
+
+function DressUpItemLink(link)
+ if ( not link ) then
+ return;
+ end
+ if ( AuctionFrame:IsShown() ) then
+ if ( not AuctionDressUpFrame:IsShown() ) then
+ ShowUIPanel(AuctionDressUpFrame);
+ AuctionDressUpModel:SetUnit("player");
+ end
+ AuctionDressUpModel:TryOn(link);
+ else
+ DressUpItemLink_orig(link);
+ end
+end
+
+function SetAuctionDressUpBackground()
+ local texture = DressUpTexturePath();
+ AuctionDressUpBackgroundTop:SetTexture(texture..1);
+ AuctionDressUpBackgroundBot:SetTexture(texture..3);
+end
+
+function AuctionDressUpFrame_OnShow()
+ UIPanelWindows["AuctionFrame"].width = 1020;
+ UpdateUIPanelPositions(AuctionFrame);
+ PlaySound("igCharacterInfoOpen");
+end
+
+function AuctionDressUpFrame_OnHide()
+ UIPanelWindows["AuctionFrame"].width = 840;
+ UpdateUIPanelPositions();
+ PlaySound("igCharacterInfoClose");
+end
diff --git a/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionDressUp.xml b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionDressUp.xml
new file mode 100644
index 0000000..5387e88
--- /dev/null
+++ b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionDressUp.xml
@@ -0,0 +1,175 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateLeft(self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateRight(self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionDressUpModel:Dress();
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUI.lua b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUI.lua
new file mode 100644
index 0000000..448a0f2
--- /dev/null
+++ b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUI.lua
@@ -0,0 +1,1695 @@
+
+NUM_BROWSE_TO_DISPLAY = 8;
+NUM_AUCTION_ITEMS_PER_PAGE = 50;
+NUM_FILTERS_TO_DISPLAY = 15;
+BROWSE_FILTER_HEIGHT = 20;
+NUM_BIDS_TO_DISPLAY = 9;
+NUM_AUCTIONS_TO_DISPLAY = 9;
+AUCTIONS_BUTTON_HEIGHT = 37;
+CLASS_FILTERS = {};
+OPEN_FILTER_LIST = {};
+AUCTION_TIMER_UPDATE_DELAY = 0.3;
+MAXIMUM_BID_PRICE = 2000000000;
+
+-- keep last item sent to auction & it's price
+LAST_ITEM_AUCTIONED = "";
+LAST_ITEM_COUNT = 0;
+LAST_ITEM_START_BID = 0;
+LAST_ITEM_BUYOUT = 0;
+
+local BROWSE_PARAM_INDEX_PAGE = 7;
+local PRICE_TYPE_UNIT = 1;
+local PRICE_TYPE_STACK = 2;
+
+AuctionSort = { };
+
+-- owner sorts
+AuctionSort["owner_status"] = {
+ { column = "quantity", reverse = true },
+ { column = "bid", reverse = false },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "duration", reverse = false },
+ { column = "status", reverse = false },
+};
+
+AuctionSort["owner_bid"] = {
+ { column = "quantity", reverse = true },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "duration", reverse = false },
+ { column = "status", reverse = false },
+ { column = "bid", reverse = false },
+};
+
+AuctionSort["owner_quality"] = {
+ { column = "bid", reverse = false },
+ { column = "quantity", reverse = true },
+ { column = "minbidbuyout", reverse = false },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+};
+
+AuctionSort["owner_duration"] = {
+ { column = "quantity", reverse = true },
+ { column = "bid", reverse = false },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "status", reverse = false },
+ { column = "duration", reverse = false },
+};
+
+-- bidder sorts
+AuctionSort["bidder_quality"] = {
+ { column = "bid", reverse = false },
+ { column = "quantity", reverse = true },
+ { column = "minbidbuyout", reverse = false },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+};
+
+AuctionSort["bidder_level"] = {
+ { column = "minbidbuyout", reverse = true },
+ { column = "status", reverse = true },
+ { column = "bid", reverse = true },
+ { column = "duration", reverse = true },
+ { column = "quantity", reverse = false },
+ { column = "name", reverse = true },
+ { column = "quality", reverse = true },
+ { column = "level", reverse = false },
+};
+
+AuctionSort["bidder_buyout"] = {
+ { column = "quantity", reverse = true },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "status", reverse = false },
+ { column = "bid", reverse = false },
+ { column = "duration", reverse = false },
+ { column = "buyout", reverse = false },
+};
+
+AuctionSort["bidder_status"] = {
+ { column = "quantity", reverse = true },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "minbidbuyout", reverse = false },
+ { column = "bid", reverse = false },
+ { column = "duration", reverse = false },
+ { column = "status", reverse = false },
+};
+
+AuctionSort["bidder_bid"] = {
+ { column = "quantity", reverse = true },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "minbidbuyout", reverse = false },
+ { column = "status", reverse = false },
+ { column = "duration", reverse = false },
+ { column = "bid", reverse = false },
+};
+
+AuctionSort["bidder_duration"] = {
+ { column = "quantity", reverse = true },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "minbidbuyout", reverse = false },
+ { column = "status", reverse = false },
+ { column = "bid", reverse = false },
+ { column = "duration", reverse = false },
+};
+
+-- list sorts
+AuctionSort["list_level"] = {
+ { column = "duration", reverse = true },
+ { column = "bid", reverse = true },
+ { column = "quantity", reverse = false },
+ { column = "minbidbuyout", reverse = true },
+ { column = "name", reverse = true },
+ { column = "quality", reverse = true },
+ { column = "level", reverse = false },
+};
+AuctionSort["list_duration"] = {
+ { column = "bid", reverse = false },
+ { column = "quantity", reverse = true },
+ { column = "minbidbuyout", reverse = false },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "duration", reverse = false },
+};
+AuctionSort["list_seller"] = {
+ { column = "duration", reverse = false },
+ { column = "bid", reverse = false },
+ { column = "quantity", reverse = true },
+ { column = "minbidbuyout", reverse = false },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "seller", reverse = false },
+};
+AuctionSort["list_bid"] = {
+ { column = "duration", reverse = false },
+ { column = "quantity", reverse = true },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+ { column = "bid", reverse = false },
+};
+
+AuctionSort["list_quality"] = {
+ { column = "duration", reverse = false },
+ { column = "bid", reverse = false },
+ { column = "quantity", reverse = true },
+ { column = "minbidbuyout", reverse = false },
+ { column = "name", reverse = false },
+ { column = "level", reverse = true },
+ { column = "quality", reverse = false },
+};
+
+
+UIPanelWindows["AuctionFrame"] = { area = "doublewide", pushable = 0, width = 840 };
+
+MoneyTypeInfo["AUCTION_DEPOSIT"] = {
+ UpdateFunc = function()
+ if ( not AuctionFrameAuctions.duration ) then
+ AuctionFrameAuctions.duration = 0
+ end
+ return CalculateAuctionDeposit(AuctionFrameAuctions.duration);
+ end,
+ collapse = 1,
+};
+
+StaticPopupDialogs["BUYOUT_AUCTION"] = {
+ text = BUYOUT_AUCTION_CONFIRMATION,
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = function(self)
+ PlaceAuctionBid(AuctionFrame.type, GetSelectedAuctionItem(AuctionFrame.type), AuctionFrame.buyoutPrice);
+ end,
+ OnShow = function(self)
+ MoneyFrame_Update(self.moneyFrame, AuctionFrame.buyoutPrice);
+ end,
+ hasMoneyFrame = 1,
+ showAlert = 1,
+ timeout = 0,
+ exclusive = 1,
+ hideOnEscape = 1
+};
+StaticPopupDialogs["BID_AUCTION"] = {
+ text = BID_AUCTION_CONFIRMATION,
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = function(self)
+ PlaceAuctionBid(AuctionFrame.type, GetSelectedAuctionItem(AuctionFrame.type), MoneyInputFrame_GetCopper(BrowseBidPrice));
+ end,
+ OnShow = function(self)
+ MoneyFrame_Update(self.moneyFrame, MoneyInputFrame_GetCopper(BrowseBidPrice));
+ end,
+ hasMoneyFrame = 1,
+ showAlert = 1,
+ timeout = 0,
+ exclusive = 1,
+ hideOnEscape = 1
+};
+StaticPopupDialogs["CANCEL_AUCTION"] = {
+ text = CANCEL_AUCTION_CONFIRMATION,
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = function()
+ CancelAuction(GetSelectedAuctionItem("owner"));
+ end,
+ OnShow = function(self)
+ MoneyFrame_Update(self.moneyFrame, AuctionFrameAuctions.cancelPrice);
+ if ( AuctionFrameAuctions.cancelPrice > 0 ) then
+ self.text:SetText(CANCEL_AUCTION_CONFIRMATION_MONEY);
+ else
+ self.text:SetText(CANCEL_AUCTION_CONFIRMATION);
+ end
+
+ end,
+ hasMoneyFrame = 1,
+ showAlert = 1,
+ timeout = 0,
+ exclusive = 1,
+ hideOnEscape = 1
+};
+
+function AuctionFrame_OnLoad (self)
+
+ -- Tab Handling code
+ PanelTemplates_SetNumTabs(self, 3);
+ PanelTemplates_SetTab(self, 1);
+ AuctionsBuyoutText:SetText(BUYOUT_PRICE.." |cff808080("..OPTIONAL..")|r");
+
+ -- Set focus rules
+ AuctionsStackSizeEntry.prevFocus = BuyoutPriceCopper;
+ AuctionsStackSizeEntry.nextFocus = AuctionsNumStacksEntry;
+ AuctionsNumStacksEntry.prevFocus = AuctionsStackSizeEntry;
+ AuctionsNumStacksEntry.nextFocus = StartPriceGold;
+
+ MoneyInputFrame_SetPreviousFocus(BrowseBidPrice, BrowseMaxLevel);
+ MoneyInputFrame_SetNextFocus(BrowseBidPrice, BrowseName);
+
+ MoneyInputFrame_SetPreviousFocus(BidBidPrice, BidBidPriceCopper);
+ MoneyInputFrame_SetNextFocus(BidBidPrice, BidBidPriceGold);
+
+ MoneyInputFrame_SetPreviousFocus(StartPrice, AuctionsNumStacksEntry);
+ MoneyInputFrame_SetNextFocus(StartPrice, BuyoutPriceGold);
+
+ MoneyInputFrame_SetPreviousFocus(BuyoutPrice, StartPriceCopper);
+ MoneyInputFrame_SetNextFocus(BuyoutPrice, AuctionsStackSizeEntry);
+
+ -- Init search dot count
+ AuctionFrameBrowse.dotCount = 0;
+ AuctionFrameBrowse.isSearchingThrottle = 0;
+
+ AuctionFrameBrowse.page = 0;
+ FauxScrollFrame_SetOffset(BrowseScrollFrame,0);
+
+ AuctionFrameBid.page = 0;
+ FauxScrollFrame_SetOffset(BidScrollFrame,0);
+ GetBidderAuctionItems(AuctionFrameBid.page);
+
+ AuctionFrameAuctions.page = 0;
+ FauxScrollFrame_SetOffset(AuctionsScrollFrame,0);
+ GetOwnerAuctionItems(AuctionFrameAuctions.page);
+end
+
+function AuctionFrame_Show()
+ if ( AuctionFrame:IsShown() ) then
+ AuctionFrameBrowse_Update();
+ AuctionFrameBid_Update();
+ AuctionFrameAuctions_Update();
+ else
+ ShowUIPanel(AuctionFrame);
+
+ AuctionFrameBrowse.page = 0;
+ FauxScrollFrame_SetOffset(BrowseScrollFrame,0);
+
+ AuctionFrameBid.page = 0;
+ FauxScrollFrame_SetOffset(BidScrollFrame,0);
+ GetBidderAuctionItems(AuctionFrameBid.page);
+
+ AuctionFrameAuctions.page = 0;
+ FauxScrollFrame_SetOffset(AuctionsScrollFrame,0);
+ GetOwnerAuctionItems(AuctionFrameAuctions.page)
+
+ BrowsePrevPageButton.isEnabled = false;
+ BrowseNextPageButton.isEnabled = false;
+
+ if ( not AuctionFrame:IsShown() ) then
+ CloseAuctionHouse();
+ end
+ end
+end
+
+function AuctionFrame_Hide()
+ HideUIPanel(AuctionFrame);
+end
+
+function AuctionFrame_OnShow (self)
+ self.gotAuctions = nil;
+ self.gotBids = nil;
+ AuctionFrameTab_OnClick(AuctionFrameTab1);
+ SetPortraitTexture(AuctionPortraitTexture,"npc");
+ BrowseNoResultsText:SetText(BROWSE_SEARCH_TEXT);
+ PlaySound("AuctionWindowOpen");
+end
+
+function AuctionFrameTab_OnClick(self, index)
+ local index = self:GetID();
+ PanelTemplates_SetTab(AuctionFrame, index);
+ AuctionFrameAuctions:Hide();
+ AuctionFrameBrowse:Hide();
+ AuctionFrameBid:Hide();
+ PlaySound("igCharacterInfoTab");
+ if ( index == 1 ) then
+ -- Browse tab
+ AuctionFrameTopLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-TopLeft");
+ AuctionFrameTop:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-Top");
+ AuctionFrameTopRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-TopRight");
+ AuctionFrameBotLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Browse-BotLeft");
+ AuctionFrameBot:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-Bot");
+ AuctionFrameBotRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-BotRight");
+ AuctionFrameBrowse:Show();
+ AuctionFrame.type = "list";
+ SetAuctionsTabShowing(false);
+ elseif ( index == 2 ) then
+ -- Bids tab
+ AuctionFrameTopLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-TopLeft");
+ AuctionFrameTop:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-Top");
+ AuctionFrameTopRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-TopRight");
+ AuctionFrameBotLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-BotLeft");
+ AuctionFrameBot:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-Bot");
+ AuctionFrameBotRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Bid-BotRight");
+ AuctionFrameBid:Show();
+ AuctionFrame.type = "bidder";
+ SetAuctionsTabShowing(false);
+ elseif ( index == 3 ) then
+ -- Auctions tab
+ AuctionFrameTopLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-TopLeft");
+ AuctionFrameTop:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-Top");
+ AuctionFrameTopRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-TopRight");
+ AuctionFrameBotLeft:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-BotLeft");
+ AuctionFrameBot:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-Bot");
+ AuctionFrameBotRight:SetTexture("Interface\\AuctionFrame\\UI-AuctionFrame-Auction-BotRight");
+ AuctionFrameAuctions:Show();
+ SetAuctionsTabShowing(true);
+ end
+end
+
+-- Browse tab functions
+
+function AuctionFrameBrowse_OnLoad(self)
+ self:RegisterEvent("AUCTION_ITEM_LIST_UPDATE");
+
+ -- set default sort
+ AuctionFrame_SetSort("list", "quality", false);
+
+ -- initialize class filter array
+ AuctionFrameBrowse_InitClasses(GetAuctionItemClasses());
+end
+
+function AuctionFrameBrowse_OnShow()
+ AuctionFrameBrowse_Update();
+ AuctionFrameFilters_Update();
+end
+
+function AuctionFrameBrowse_UpdateArrows()
+ SortButton_UpdateArrow(BrowseQualitySort, "list", "quality");
+ SortButton_UpdateArrow(BrowseLevelSort, "list", "level");
+ SortButton_UpdateArrow(BrowseDurationSort, "list", "duration");
+ SortButton_UpdateArrow(BrowseHighBidderSort, "list", "seller");
+ SortButton_UpdateArrow(BrowseCurrentBidSort, "list", "bid");
+end
+
+function AuctionFrameBrowse_OnEvent(self, event, ...)
+ if ( event == "AUCTION_ITEM_LIST_UPDATE" ) then
+ AuctionFrameBrowse_Update();
+ -- Stop "searching" messaging
+ AuctionFrameBrowse.isSearching = nil;
+ BrowseNoResultsText:SetText(BROWSE_NO_RESULTS);
+ -- update arrows now that we're not searching
+ AuctionFrameBrowse_UpdateArrows();
+ end
+end
+
+function BrowseButton_OnClick(button)
+ assert(button);
+
+ if ( GetCVarBool("auctionDisplayOnCharacter") ) then
+ DressUpItemLink(GetAuctionItemLink("list", button:GetID() + FauxScrollFrame_GetOffset(BrowseScrollFrame)));
+ end
+ SetSelectedAuctionItem("list", button:GetID() + FauxScrollFrame_GetOffset(BrowseScrollFrame));
+ -- Close any auction related popups
+ CloseAuctionStaticPopups();
+ AuctionFrameBrowse_Update();
+end
+
+function BrowseDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, BrowseDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(BrowseDropDown,-1);
+end
+
+function BrowseDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+ info.text = ALL;
+ info.value = -1;
+ info.func = BrowseDropDown_OnClick;
+ UIDropDownMenu_AddButton(info);
+ for i=0, getn(ITEM_QUALITY_COLORS)-2 do
+ info.text = _G["ITEM_QUALITY"..i.."_DESC"];
+ info.value = i;
+ info.func = BrowseDropDown_OnClick;
+ info.checked = nil;
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function BrowseDropDown_OnClick(self)
+ UIDropDownMenu_SetSelectedValue(BrowseDropDown, self.value);
+end
+
+function AuctionFrameBrowse_InitClasses(...)
+ for i=1, select("#", ...) do
+ CLASS_FILTERS[i] = select(i, ...);
+ end
+end
+
+function AuctionFrameBrowse_Reset(self)
+ BrowseName:SetText("");
+ BrowseMinLevel:SetText("");
+ BrowseMaxLevel:SetText("");
+ IsUsableCheckButton:SetChecked(0);
+ UIDropDownMenu_SetSelectedValue(BrowseDropDown,-1);
+
+ -- reset the filters
+ OPEN_FILTER_LIST = {};
+ AuctionFrameBrowse.selectedClass = nil;
+ AuctionFrameBrowse.selectedClassIndex = nil;
+ AuctionFrameBrowse.selectedSubclass = nil;
+ AuctionFrameBrowse.selectedSubclassIndex = nil;
+ AuctionFrameBrowse.selectedInvtype = nil;
+ AuctionFrameBrowse.selectedInvtypeIndex = nil;
+
+ AuctionFrameFilters_Update()
+ self:Disable();
+end
+
+function BrowseResetButton_OnUpdate(self, elapsed)
+ if ( (BrowseName:GetText() == "") and (BrowseMinLevel:GetText() == "") and (BrowseMaxLevel:GetText() == "") and
+ (not IsUsableCheckButton:GetChecked()) and (UIDropDownMenu_GetSelectedValue(BrowseDropDown) == -1) and
+ (not AuctionFrameBrowse.selectedClass) and (not AuctionFrameBrowse.selectedSubclass) and (not AuctionFrameBrowse.selectedInvtype) )
+ then
+ self:Disable();
+ else
+ self:Enable();
+ end
+end
+
+function AuctionFrame_SetSort(sortTable, sortColumn, oppositeOrder)
+ -- clear the existing sort.
+ SortAuctionClearSort(sortTable);
+
+ -- set the columns
+ for index, row in pairs(AuctionSort[sortTable.."_"..sortColumn]) do
+ if (oppositeOrder) then
+ SortAuctionSetSort(sortTable, row.column, not row.reverse);
+ else
+ SortAuctionSetSort(sortTable, row.column, row.reverse);
+ end
+ end
+end
+
+function AuctionFrame_OnClickSortColumn(sortTable, sortColumn)
+ -- change the sort as appropriate
+ local existingSortColumn, existingSortReverse = GetAuctionSort(sortTable, 1);
+ local oppositeOrder = false;
+ if (existingSortColumn and (existingSortColumn == sortColumn)) then
+ oppositeOrder = not existingSortReverse;
+ elseif (sortColumn == "level") then
+ oppositeOrder = true;
+ end
+
+ -- set the new sort order
+ AuctionFrame_SetSort(sortTable, sortColumn, oppositeOrder);
+
+ -- apply the sort
+ if (sortTable == "list") then
+ AuctionFrameBrowse_Search();
+ else
+ SortAuctionApplySort(sortTable);
+ end
+end
+
+local prevBrowseParams;
+local function AuctionFrameBrowse_SearchHelper(...)
+ local text, minLevel, maxLevel, invType, class, subclass, page, usable, rarity = ...;
+
+ if ( not prevBrowseParams ) then
+ -- if we are doing a search for the first time then create the browse param cache
+ prevBrowseParams = { };
+ else
+ -- if we have already done a browse then see if any of the params have changed (except for the page number)
+ local param;
+ for i = 1, select('#', ...) do
+ if ( i ~= BROWSE_PARAM_INDEX_PAGE and select(i, ...) ~= prevBrowseParams[i] ) then
+ -- if we detect a change then we want to reset the page number back to the first page
+ page = 0;
+ AuctionFrameBrowse.page = page;
+ break;
+ end
+ end
+ end
+
+ QueryAuctionItems(text, minLevel, maxLevel, invType, class, subclass, page, usable, rarity);
+
+ -- store this query's params so we can compare them with the next set of params we get
+ for i = 1, select('#', ...) do
+ if ( i == BROWSE_PARAM_INDEX_PAGE ) then
+ prevBrowseParams[i] = page;
+ else
+ prevBrowseParams[i] = select(i, ...);
+ end
+ end
+end
+
+function AuctionFrameBrowse_Search()
+ if ( not AuctionFrameBrowse.page ) then
+ AuctionFrameBrowse.page = 0;
+ end
+
+ AuctionFrameBrowse_SearchHelper(BrowseName:GetText(), BrowseMinLevel:GetText(), BrowseMaxLevel:GetText(), AuctionFrameBrowse.selectedInvtypeIndex, AuctionFrameBrowse.selectedClassIndex, AuctionFrameBrowse.selectedSubclassIndex, AuctionFrameBrowse.page, IsUsableCheckButton:GetChecked(), UIDropDownMenu_GetSelectedValue(BrowseDropDown));
+
+ -- Start "searching" messaging
+ AuctionFrameBrowse.isSearching = 1;
+end
+
+function BrowseSearchButton_OnUpdate(self, elapsed)
+ if ( CanSendAuctionQuery("list") ) then
+ self:Enable();
+ if ( BrowsePrevPageButton.isEnabled ) then
+ BrowsePrevPageButton:Enable();
+ else
+ BrowsePrevPageButton:Disable();
+ end
+ if ( BrowseNextPageButton.isEnabled ) then
+ BrowseNextPageButton:Enable();
+ else
+ BrowseNextPageButton:Disable();
+ end
+ BrowseQualitySort:Enable();
+ BrowseLevelSort:Enable();
+ BrowseDurationSort:Enable();
+ BrowseHighBidderSort:Enable();
+ BrowseCurrentBidSort:Enable();
+ AuctionFrameBrowse_UpdateArrows();
+ else
+ self:Disable();
+ BrowsePrevPageButton:Disable();
+ BrowseNextPageButton:Disable();
+ BrowseQualitySort:Disable();
+ BrowseLevelSort:Disable();
+ BrowseDurationSort:Disable();
+ BrowseHighBidderSort:Disable();
+ BrowseCurrentBidSort:Disable();
+ end
+ if (AuctionFrameBrowse.isSearching) then
+ if ( AuctionFrameBrowse.isSearchingThrottle <= 0 ) then
+ AuctionFrameBrowse.dotCount = AuctionFrameBrowse.dotCount + 1;
+ if ( AuctionFrameBrowse.dotCount > 3 ) then
+ AuctionFrameBrowse.dotCount = 0
+ end
+ local dotString = "";
+ for i=1, AuctionFrameBrowse.dotCount do
+ dotString = dotString..".";
+ end
+ BrowseSearchDotsText:Show();
+ BrowseSearchDotsText:SetText(dotString);
+ BrowseNoResultsText:SetText(SEARCHING_FOR_ITEMS);
+ AuctionFrameBrowse.isSearchingThrottle = 0.3;
+ else
+ AuctionFrameBrowse.isSearchingThrottle = AuctionFrameBrowse.isSearchingThrottle - elapsed;
+ end
+ else
+ BrowseSearchDotsText:Hide();
+ end
+end
+
+function AuctionFrameFilters_Update()
+ AuctionFrameFilters_UpdateClasses();
+ -- Update scrollFrame
+ FauxScrollFrame_Update(BrowseFilterScrollFrame, getn(OPEN_FILTER_LIST), NUM_FILTERS_TO_DISPLAY, BROWSE_FILTER_HEIGHT);
+end
+
+function AuctionFrameFilters_UpdateClasses()
+ -- Initialize the list of open filters
+ OPEN_FILTER_LIST = {};
+ for i=1, getn(CLASS_FILTERS) do
+ if ( AuctionFrameBrowse.selectedClass and AuctionFrameBrowse.selectedClass == CLASS_FILTERS[i] ) then
+ tinsert(OPEN_FILTER_LIST, {CLASS_FILTERS[i], "class", i, 1});
+ AuctionFrameFilters_UpdateSubClasses(GetAuctionItemSubClasses(i));
+ else
+ tinsert(OPEN_FILTER_LIST, {CLASS_FILTERS[i], "class", i, nil});
+ end
+ end
+
+ -- Display the list of open filters
+ local button, index, info, isLast;
+ local offset = FauxScrollFrame_GetOffset(BrowseFilterScrollFrame);
+ index = offset;
+ for i=1, NUM_FILTERS_TO_DISPLAY do
+ button = _G["AuctionFilterButton"..i];
+ if ( getn(OPEN_FILTER_LIST) > NUM_FILTERS_TO_DISPLAY ) then
+ button:SetWidth(136);
+ else
+ button:SetWidth(156);
+ end
+
+ index = index + 1;
+ if ( index <= getn(OPEN_FILTER_LIST) ) then
+ info = OPEN_FILTER_LIST[index];
+ while ((info[2] == "invtype") and (not info[6])) do
+ index = index + 1
+ if ( index <= getn(OPEN_FILTER_LIST) ) then
+ info = OPEN_FILTER_LIST[index];
+ else
+ info = nil;
+ button:Hide();
+ break;
+ end
+ end
+
+ if ( info ) then
+ FilterButton_SetType(button, info[2], info[1], info[5]);
+ button.index = info[3];
+ if ( info[4] ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+ button:Show();
+ end
+ else
+ button:Hide();
+ end
+ end
+end
+
+function AuctionFrameFilters_UpdateSubClasses(...)
+ local subClass;
+ for i=1, select("#", ...) do
+ subClass = HIGHLIGHT_FONT_COLOR_CODE..select(i, ...)..FONT_COLOR_CODE_CLOSE;
+ if ( AuctionFrameBrowse.selectedSubclass and AuctionFrameBrowse.selectedSubclass == subClass ) then
+ tinsert(OPEN_FILTER_LIST, {select(i, ...), "subclass", i, 1});
+ AuctionFrameFilters_UpdateInvTypes(GetAuctionInvTypes(AuctionFrameBrowse.selectedClassIndex,i));
+ else
+ tinsert(OPEN_FILTER_LIST, {select(i, ...), "subclass", i, nil});
+ end
+ end
+end
+
+function AuctionFrameFilters_UpdateInvTypes(...)
+ local invType, isLast, idx;
+ for i=1, select("#", ...), 2 do
+-- each type has 2 args: token name(i), display in list(i+1)
+ idx = (i + 1) / 2;
+ invType = HIGHLIGHT_FONT_COLOR_CODE.._G[select(i, ...)]..FONT_COLOR_CODE_CLOSE;
+ if ( (i + 1) == select("#", ...) ) then
+ isLast = 1;
+ end
+
+ if ( AuctionFrameBrowse.selectedInvtypeIndex and AuctionFrameBrowse.selectedInvtypeIndex == idx ) then
+ tinsert(OPEN_FILTER_LIST, {invType, "invtype", idx, 1, isLast, select(i+1, ...)} );
+ else
+ tinsert(OPEN_FILTER_LIST, {invType, "invtype", idx, nil, isLast, select(i+1, ...)} );
+ end
+ end
+end
+
+function FilterButton_SetType(button, type, text, isLast)
+ local normalText = _G[button:GetName().."NormalText"];
+ local normalTexture = _G[button:GetName().."NormalTexture"];
+ local line = _G[button:GetName().."Lines"];
+ if ( type == "class" ) then
+ button:SetText(text);
+ normalText:SetPoint("LEFT", button, "LEFT", 4, 0);
+ normalTexture:SetAlpha(1.0);
+ line:Hide();
+ elseif ( type == "subclass" ) then
+ button:SetText(HIGHLIGHT_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE);
+ normalText:SetPoint("LEFT", button, "LEFT", 12, 0);
+ normalTexture:SetAlpha(0.4);
+ line:Hide();
+ elseif ( type == "invtype" ) then
+ button:SetText(HIGHLIGHT_FONT_COLOR_CODE..text..FONT_COLOR_CODE_CLOSE);
+ normalText:SetPoint("LEFT", button, "LEFT", 20, 0);
+ normalTexture:SetAlpha(0.0);
+ if ( isLast ) then
+ line:SetTexCoord(0.4375, 0.875, 0, 0.625);
+ else
+ line:SetTexCoord(0, 0.4375, 0, 0.625);
+ end
+ line:Show();
+ end
+ button.type = type;
+end
+
+function AuctionFrameFilter_OnClick(self, button)
+ if ( self.type == "class" ) then
+ if ( AuctionFrameBrowse.selectedClass == self:GetText() ) then
+ AuctionFrameBrowse.selectedClass = nil;
+ AuctionFrameBrowse.selectedClassIndex = nil;
+ else
+ AuctionFrameBrowse.selectedClass = self:GetText();
+ AuctionFrameBrowse.selectedClassIndex = self.index;
+ end
+ AuctionFrameBrowse.selectedSubclass = nil;
+ AuctionFrameBrowse.selectedSubclassIndex = nil;
+ AuctionFrameBrowse.selectedInvtype = nil;
+ AuctionFrameBrowse.selectedInvtypeIndex = nil;
+ elseif ( self.type == "subclass" ) then
+ if ( AuctionFrameBrowse.selectedSubclass == self:GetText() ) then
+ AuctionFrameBrowse.selectedSubclass = nil;
+ AuctionFrameBrowse.selectedSubclassIndex = nil;
+ else
+ AuctionFrameBrowse.selectedSubclass = self:GetText();
+ AuctionFrameBrowse.selectedSubclassIndex = self.index;
+ end
+ AuctionFrameBrowse.selectedInvtype = nil;
+ AuctionFrameBrowse.selectedInvtypeIndex = nil;
+ elseif ( self.type == "invtype" ) then
+ AuctionFrameBrowse.selectedInvtype = self:GetText();
+ AuctionFrameBrowse.selectedInvtypeIndex = self.index;
+ end
+ AuctionFrameFilters_Update()
+end
+
+function AuctionFrameBrowse_Update()
+ local numBatchAuctions, totalAuctions = GetNumAuctionItems("list");
+ local button, buttonName, buttonHighlight, iconTexture, itemName, color, itemCount, moneyFrame, yourBidText, buyoutFrame, buyoutMoney;
+ local offset = FauxScrollFrame_GetOffset(BrowseScrollFrame);
+ local index;
+ local isLastSlotEmpty;
+ local name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, duration, bidAmount, highBidder, owner;
+ local displayedPrice, requiredBid;
+ BrowseBidButton:Disable();
+ BrowseBuyoutButton:Disable();
+ -- Update sort arrows
+ AuctionFrameBrowse_UpdateArrows();
+
+ -- Show the no results text if no items found
+ if ( numBatchAuctions == 0 ) then
+ BrowseNoResultsText:Show();
+ else
+ BrowseNoResultsText:Hide();
+ end
+
+ for i=1, NUM_BROWSE_TO_DISPLAY do
+ index = offset + i + (NUM_AUCTION_ITEMS_PER_PAGE * AuctionFrameBrowse.page);
+ button = _G["BrowseButton"..i];
+ -- Show or hide auction buttons
+ if ( index > (numBatchAuctions + (NUM_AUCTION_ITEMS_PER_PAGE * AuctionFrameBrowse.page)) ) then
+ button:Hide();
+ -- If the last button is empty then set isLastSlotEmpty var
+ if ( i == NUM_BROWSE_TO_DISPLAY ) then
+ isLastSlotEmpty = 1;
+ end
+ else
+ button:Show();
+
+ buttonName = "BrowseButton"..i;
+ name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner = GetAuctionItemInfo("list", offset + i);
+ if ( not name ) then --Bug 145328
+ button:Hide();
+ -- If the last button is empty then set isLastSlotEmpty var
+ isLastSlotEmpty = (i == NUM_BROWSE_TO_DISPLAY);
+ end
+ duration = GetAuctionItemTimeLeft("list", offset + i);
+
+ -- Resize button if there isn't a scrollbar
+ buttonHighlight = _G["BrowseButton"..i.."Highlight"];
+ if ( numBatchAuctions < NUM_BROWSE_TO_DISPLAY ) then
+ button:SetWidth(625);
+ buttonHighlight:SetWidth(589);
+ BrowseCurrentBidSort:SetWidth(207);
+ elseif ( numBatchAuctions == NUM_BROWSE_TO_DISPLAY and totalAuctions <= NUM_BROWSE_TO_DISPLAY ) then
+ button:SetWidth(625);
+ buttonHighlight:SetWidth(589);
+ BrowseCurrentBidSort:SetWidth(207);
+ else
+ button:SetWidth(600);
+ buttonHighlight:SetWidth(562);
+ BrowseCurrentBidSort:SetWidth(184);
+ end
+ -- Set name and quality color
+ color = ITEM_QUALITY_COLORS[quality];
+ itemName = _G[buttonName.."Name"];
+ itemName:SetText(name);
+ itemName:SetVertexColor(color.r, color.g, color.b);
+ -- Set level
+ if ( level > UnitLevel("player") ) then
+ _G[buttonName.."Level"]:SetText(RED_FONT_COLOR_CODE..level..FONT_COLOR_CODE_CLOSE);
+ else
+ _G[buttonName.."Level"]:SetText(level);
+ end
+ -- Set closing time
+ _G[buttonName.."ClosingTimeText"]:SetText(AuctionFrame_GetTimeLeftText(duration));
+ _G[buttonName.."ClosingTime"].tooltip = AuctionFrame_GetTimeLeftTooltipText(duration);
+ -- Set item texture, count, and usability
+ iconTexture = _G[buttonName.."ItemIconTexture"];
+ iconTexture:SetTexture(texture);
+ if ( not canUse ) then
+ iconTexture:SetVertexColor(1.0, 0.1, 0.1);
+ else
+ iconTexture:SetVertexColor(1.0, 1.0, 1.0);
+ end
+ itemCount = _G[buttonName.."ItemCount"];
+ if ( count > 1 ) then
+ itemCount:SetText(count);
+ itemCount:Show();
+ else
+ itemCount:Hide();
+ end
+ -- Set high bid
+ moneyFrame = _G[buttonName.."MoneyFrame"];
+ -- If not bidAmount set the bid amount to the min bid
+ if ( bidAmount == 0 ) then
+ displayedPrice = minBid;
+ requiredBid = minBid;
+ else
+ displayedPrice = bidAmount;
+ requiredBid = bidAmount + minIncrement ;
+ end
+ MoneyFrame_Update(moneyFrame:GetName(), displayedPrice);
+
+ yourBidText = _G[buttonName.."YourBidText"];
+ if ( highBidder ) then
+ yourBidText:Show();
+ else
+ yourBidText:Hide();
+ end
+
+ if ( requiredBid >= MAXIMUM_BID_PRICE ) then
+ -- Lie about our buyout price
+ buyoutPrice = requiredBid;
+ end
+ buyoutFrame = _G[buttonName.."BuyoutFrame"];
+ if ( buyoutPrice > 0 ) then
+ moneyFrame:SetPoint("RIGHT", button, "RIGHT", 10, 10);
+ buyoutMoney = _G[buyoutFrame:GetName().."Money"];
+ MoneyFrame_Update(buyoutMoney, buyoutPrice);
+ buyoutFrame:Show();
+ else
+ moneyFrame:SetPoint("RIGHT", button, "RIGHT", 10, 3);
+ buyoutFrame:Hide();
+ end
+ -- Set high bidder
+ --if ( not highBidder ) then
+ -- highBidder = RED_FONT_COLOR_CODE..NO_BIDS..FONT_COLOR_CODE_CLOSE;
+ --end
+ _G[buttonName.."HighBidder"]:SetText(owner);
+
+ button.bidAmount = displayedPrice;
+ button.buyoutPrice = buyoutPrice;
+ button.itemCount = count;
+
+ -- Set highlight
+ if ( GetSelectedAuctionItem("list") and (offset + i) == GetSelectedAuctionItem("list") ) then
+ button:LockHighlight();
+
+ if ( buyoutPrice > 0 and buyoutPrice >= minBid ) then
+ local canBuyout = 1;
+ if ( GetMoney() < buyoutPrice ) then
+ if ( not highBidder or GetMoney()+bidAmount < buyoutPrice ) then
+ canBuyout = nil;
+ end
+ end
+ if ( canBuyout and (owner ~= UnitName("player")) ) then
+ BrowseBuyoutButton:Enable();
+ AuctionFrame.buyoutPrice = buyoutPrice;
+ end
+ else
+ AuctionFrame.buyoutPrice = nil;
+ end
+ -- Set bid
+ MoneyInputFrame_SetCopper(BrowseBidPrice, requiredBid);
+
+ if ( not highBidder and owner ~= UnitName("player") and GetMoney() >= MoneyInputFrame_GetCopper(BrowseBidPrice) and MoneyInputFrame_GetCopper(BrowseBidPrice) <= MAXIMUM_BID_PRICE ) then
+ BrowseBidButton:Enable();
+ end
+ else
+ button:UnlockHighlight();
+ end
+ end
+ end
+
+ -- Update scrollFrame
+ -- If more than one page of auctions show the next and prev arrows when the scrollframe is scrolled all the way down
+ if ( totalAuctions > NUM_AUCTION_ITEMS_PER_PAGE ) then
+ BrowsePrevPageButton.isEnabled = (AuctionFrameBrowse.page ~= 0);
+ BrowseNextPageButton.isEnabled = (AuctionFrameBrowse.page ~= (ceil(totalAuctions/NUM_AUCTION_ITEMS_PER_PAGE) - 1));
+ if ( isLastSlotEmpty ) then
+ BrowseSearchCountText:Show();
+ local itemsMin = AuctionFrameBrowse.page * NUM_AUCTION_ITEMS_PER_PAGE + 1;
+ local itemsMax = itemsMin + numBatchAuctions - 1;
+ BrowseSearchCountText:SetFormattedText(NUMBER_OF_RESULTS_TEMPLATE, itemsMin, itemsMax, totalAuctions);
+ else
+ BrowseSearchCountText:Hide();
+ end
+
+ -- Artifically inflate the number of results so the scrollbar scrolls one extra row
+ numBatchAuctions = numBatchAuctions + 1;
+ else
+ BrowsePrevPageButton.isEnabled = false;
+ BrowseNextPageButton.isEnabled = false;
+ BrowseSearchCountText:Hide();
+ end
+ FauxScrollFrame_Update(BrowseScrollFrame, numBatchAuctions, NUM_BROWSE_TO_DISPLAY, AUCTIONS_BUTTON_HEIGHT);
+end
+
+-- Bid tab functions
+
+function AuctionFrameBid_OnLoad(self)
+ self:RegisterEvent("AUCTION_BIDDER_LIST_UPDATE");
+
+ -- set default sort
+ AuctionFrame_SetSort("bidder", "duration", false);
+end
+
+function AuctionFrameBid_OnEvent(self, event, ...)
+ if ( event == "AUCTION_BIDDER_LIST_UPDATE" ) then
+ AuctionFrameBid_Update();
+ end
+end
+
+function AuctionFrameBid_OnShow()
+ -- So the get auctions query is only run once per session, after that you only get updates
+ if ( not AuctionFrame.gotBids ) then
+ GetBidderAuctionItems();
+ AuctionFrame.gotBids = 1;
+ end
+ AuctionFrameBid_Update();
+end
+
+function AuctionFrameBid_Update()
+ local numBatchAuctions, totalAuctions = GetNumAuctionItems("bidder");
+ local button, buttonName, buttonHighlight, iconTexture, itemName, color, itemCount;
+ local offset = FauxScrollFrame_GetOffset(BidScrollFrame);
+ local index;
+ local isLastSlotEmpty;
+ local name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, duration, bidAmount, highBidder, owner;
+ BidBidButton:Disable();
+ BidBuyoutButton:Disable();
+ -- Update sort arrows
+ SortButton_UpdateArrow(BidQualitySort, "bidder", "quality");
+ SortButton_UpdateArrow(BidLevelSort, "bidder", "level");
+ SortButton_UpdateArrow(BidDurationSort, "bidder", "duration");
+ SortButton_UpdateArrow(BidBuyoutSort, "bidder", "buyout");
+ SortButton_UpdateArrow(BidStatusSort, "bidder", "status");
+ SortButton_UpdateArrow(BidBidSort, "bidder", "bid");
+
+ for i=1, NUM_BIDS_TO_DISPLAY do
+ index = offset + i;
+ button = _G["BidButton"..i];
+ -- Show or hide auction buttons
+ if ( index > numBatchAuctions ) then
+ button:Hide();
+ -- If the last button is empty then set isLastSlotEmpty var
+ isLastSlotEmpty = (i == NUM_BIDS_TO_DISPLAY);
+ else
+ button:Show();
+ buttonName = "BidButton"..i;
+ name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner = GetAuctionItemInfo("bidder", index);
+ duration = GetAuctionItemTimeLeft("bidder", offset + i);
+
+ -- Resize button if there isn't a scrollbar
+ buttonHighlight = _G["BidButton"..i.."Highlight"];
+ if ( numBatchAuctions < NUM_BIDS_TO_DISPLAY ) then
+ button:SetWidth(793);
+ buttonHighlight:SetWidth(758);
+ BidBidSort:SetWidth(169);
+ elseif ( numBatchAuctions == NUM_BIDS_TO_DISPLAY and totalAuctions <= NUM_BIDS_TO_DISPLAY ) then
+ button:SetWidth(793);
+ buttonHighlight:SetWidth(758);
+ BidBidSort:SetWidth(169);
+ else
+ button:SetWidth(769);
+ buttonHighlight:SetWidth(735);
+ BidBidSort:SetWidth(145);
+ end
+ -- Set name and quality color
+ color = ITEM_QUALITY_COLORS[quality];
+ itemName = _G[buttonName.."Name"];
+ itemName:SetText(name);
+ itemName:SetVertexColor(color.r, color.g, color.b);
+ -- Set level
+ if ( level > UnitLevel("player") ) then
+ _G[buttonName.."Level"]:SetText(RED_FONT_COLOR_CODE..level..FONT_COLOR_CODE_CLOSE);
+ else
+ _G[buttonName.."Level"]:SetText(level);
+ end
+ -- Set bid status
+ if ( highBidder ) then
+ _G[buttonName.."BidStatus"]:SetText(GREEN_FONT_COLOR_CODE..HIGH_BIDDER..FONT_COLOR_CODE_CLOSE);
+ else
+ _G[buttonName.."BidStatus"]:SetText(RED_FONT_COLOR_CODE..OUTBID..FONT_COLOR_CODE_CLOSE);
+ end
+
+ -- Set closing time
+ _G[buttonName.."ClosingTimeText"]:SetText(AuctionFrame_GetTimeLeftText(duration));
+ _G[buttonName.."ClosingTime"].tooltip = AuctionFrame_GetTimeLeftTooltipText(duration);
+ -- Set item texture, count, and usability
+ iconTexture = _G[buttonName.."ItemIconTexture"];
+ iconTexture:SetTexture(texture);
+ if ( not canUse ) then
+ iconTexture:SetVertexColor(1.0, 0.1, 0.1);
+ else
+ iconTexture:SetVertexColor(1.0, 1.0, 1.0);
+ end
+ itemCount = _G[buttonName.."ItemCount"];
+ if ( count > 1 ) then
+ itemCount:SetText(count);
+ itemCount:Show();
+ else
+ itemCount:Hide();
+ end
+
+ -- Set current bid
+ -- If not bidAmount set the bid amount to the min bid
+ if ( bidAmount == 0 ) then
+ bidAmount = minBid;
+ end
+ MoneyFrame_Update(buttonName.."CurrentBidMoneyFrame", bidAmount);
+ -- Set buyout price
+ MoneyFrame_Update(buttonName.."BuyoutMoneyFrame", buyoutPrice);
+
+ button.bidAmount = bidAmount;
+ button.buyoutPrice = buyoutPrice;
+ button.itemCount = count;
+
+ -- Set highlight
+ if ( GetSelectedAuctionItem("bidder") and (offset + i) == GetSelectedAuctionItem("bidder") ) then
+ button:LockHighlight();
+
+ if ( buyoutPrice > 0 and buyoutPrice >= bidAmount ) then
+ local canBuyout = 1;
+ if ( GetMoney() < buyoutPrice ) then
+ if ( not highBidder or GetMoney()+bidAmount < buyoutPrice ) then
+ canBuyout = nil;
+ end
+ end
+ if ( canBuyout ) then
+ BidBuyoutButton:Enable();
+ AuctionFrame.buyoutPrice = buyoutPrice;
+ end
+ else
+ AuctionFrame.buyoutPrice = nil;
+ end
+ -- Set bid
+ MoneyInputFrame_SetCopper(BidBidPrice, bidAmount + minIncrement);
+
+ if ( not highBidder and GetMoney() >= MoneyInputFrame_GetCopper(BidBidPrice) ) then
+ BidBidButton:Enable();
+ end
+ else
+ button:UnlockHighlight();
+ end
+ end
+ end
+ -- If more than one page of auctions show the next and prev arrows when the scrollframe is scrolled all the way down
+ if ( totalAuctions > NUM_AUCTION_ITEMS_PER_PAGE ) then
+ if ( isLastSlotEmpty ) then
+ BidSearchCountText:Show();
+ BidSearchCountText:SetFormattedText(SINGLE_PAGE_RESULTS_TEMPLATE, totalAuctions);
+ else
+ BidSearchCountText:Hide();
+ end
+
+ -- Artifically inflate the number of results so the scrollbar scrolls one extra row
+ numBatchAuctions = numBatchAuctions + 1;
+ else
+ BidSearchCountText:Hide();
+ end
+
+ -- Update scrollFrame
+ FauxScrollFrame_Update(BidScrollFrame, numBatchAuctions, NUM_BIDS_TO_DISPLAY, AUCTIONS_BUTTON_HEIGHT);
+end
+
+function BidButton_OnClick(button)
+ assert(button)
+
+ if ( GetCVarBool("auctionDisplayOnCharacter") ) then
+ DressUpItemLink(GetAuctionItemLink("bidder", button:GetID() + FauxScrollFrame_GetOffset(BidScrollFrame)));
+ end
+ SetSelectedAuctionItem("bidder", button:GetID() + FauxScrollFrame_GetOffset(BidScrollFrame));
+ -- Close any auction related popups
+ CloseAuctionStaticPopups();
+ AuctionFrameBid_Update();
+end
+
+
+-- Auctions tab functions
+
+function AuctionFrameAuctions_OnLoad(self)
+ self:RegisterEvent("AUCTION_OWNED_LIST_UPDATE");
+ self:RegisterEvent("AUCTION_MULTISELL_START");
+ self:RegisterEvent("AUCTION_MULTISELL_UPDATE");
+ self:RegisterEvent("AUCTION_MULTISELL_FAILURE");
+ -- set default sort
+ AuctionFrame_SetSort("owner", "duration", false);
+
+ UIDropDownMenu_DisableDropDown(PriceDropDown);
+end
+
+function AuctionFrameAuctions_OnEvent(self, event, ...)
+ if ( event == "AUCTION_OWNED_LIST_UPDATE" ) then
+ AuctionFrameAuctions_Update();
+ elseif ( event == "AUCTION_MULTISELL_START" ) then
+ AuctionsCreateAuctionButton:Disable();
+ MoneyInputFrame_ClearFocus(StartPrice);
+ MoneyInputFrame_ClearFocus(BuyoutPrice);
+ AuctionsStackSizeEntry:ClearFocus();
+ AuctionsNumStacksEntry:ClearFocus();
+ AuctionsBlockFrame:Show();
+ AuctionProgressBar:SetMinMaxValues(0, arg1);
+ AuctionProgressBar:SetValue(0.01); -- TEMPORARY
+ AuctionProgressBarText:SetFormattedText(AUCTION_CREATING, 0, arg1);
+ local _, iconTexture = GetAuctionSellItemInfo();
+ AuctionProgressBarIcon:SetTexture(iconTexture);
+ AuctionProgressFrame:Show();
+ elseif ( event == "AUCTION_MULTISELL_UPDATE" ) then
+ AuctionProgressBar:SetValue(arg1);
+ AuctionProgressBarText:SetFormattedText(AUCTION_CREATING, arg1, arg2);
+ if ( arg1 == arg2 ) then
+ AuctionsBlockFrame:Hide();
+ AuctionProgressFrame.fadeOut = true;
+ end
+ elseif ( event == "AUCTION_MULTISELL_FAILURE" ) then
+ AuctionsBlockFrame:Hide();
+ AuctionProgressFrame:Hide();
+ end
+end
+
+function AuctionFrameAuctions_OnShow()
+ AuctionsTitle:SetFormattedText(AUCTION_TITLE, UnitName("player"));
+ --MoneyFrame_Update("AuctionsDepositMoneyFrame", 0);
+ AuctionsFrameAuctions_ValidateAuction();
+ -- So the get auctions query is only run once per session, after that you only get updates
+ if ( not AuctionFrame.gotAuctions ) then
+ GetOwnerAuctionItems();
+ AuctionFrame.gotAuctions = 1;
+ end
+ AuctionFrameAuctions_Update();
+end
+
+function AuctionFrameAuctions_Update()
+ local numBatchAuctions, totalAuctions = GetNumAuctionItems("owner");
+ local offset = FauxScrollFrame_GetOffset(AuctionsScrollFrame);
+ local index;
+ local isLastSlotEmpty;
+ local auction, button, buttonName, buttonHighlight, iconTexture, itemName, color, itemCount;
+ local highBidderFrame;
+ local closingTimeFrame, closingTimeText;
+ local buttonBuyoutFrame, buttonBuyoutMoney;
+ local bidAmountMoneyFrame, bidAmountMoneyFrameLabel;
+ local name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, duration, bidAmount, highBidder, owner, saleStatus;
+
+ -- Update sort arrows
+ SortButton_UpdateArrow(AuctionsQualitySort, "owner", "quality");
+ SortButton_UpdateArrow(AuctionsHighBidderSort, "owner", "status");
+ SortButton_UpdateArrow(AuctionsDurationSort, "owner", "duration");
+ SortButton_UpdateArrow(AuctionsBidSort, "owner", "bid");
+
+ for i=1, NUM_AUCTIONS_TO_DISPLAY do
+ index = offset + i + (NUM_AUCTION_ITEMS_PER_PAGE * AuctionFrameAuctions.page);
+ auction = _G["AuctionsButton"..i];
+ -- Show or hide auction buttons
+ if ( index > (numBatchAuctions + (NUM_AUCTION_ITEMS_PER_PAGE * AuctionFrameAuctions.page)) ) then
+ auction:Hide();
+ -- If the last button is empty then set isLastSlotEmpty var
+ isLastSlotEmpty = (i == NUM_AUCTIONS_TO_DISPLAY);
+ else
+ auction:Show();
+
+ name, texture, count, quality, canUse, level, minBid, minIncrement, buyoutPrice, bidAmount, highBidder, owner, saleStatus = GetAuctionItemInfo("owner", offset + i);
+ duration = GetAuctionItemTimeLeft("owner", offset + i);
+
+ buttonName = "AuctionsButton"..i;
+ button = _G[buttonName];
+
+ -- Resize button if there isn't a scrollbar
+ buttonHighlight = _G[buttonName.."Highlight"];
+ if ( numBatchAuctions < NUM_AUCTIONS_TO_DISPLAY ) then
+ auction:SetWidth(599);
+ buttonHighlight:SetWidth(565);
+ AuctionsBidSort:SetWidth(213);
+ elseif ( numBatchAuctions == NUM_AUCTIONS_TO_DISPLAY and totalAuctions <= NUM_AUCTIONS_TO_DISPLAY ) then
+ auction:SetWidth(599);
+ buttonHighlight:SetWidth(565);
+ AuctionsBidSort:SetWidth(213);
+ else
+ auction:SetWidth(576);
+ buttonHighlight:SetWidth(543);
+ AuctionsBidSort:SetWidth(193);
+ end
+
+ -- Display differently based on the saleStatus
+ -- saleStatus "1" means that the item was sold
+ -- Set name and quality color
+ color = ITEM_QUALITY_COLORS[quality];
+ itemName = _G[buttonName.."Name"];
+ iconTexture = _G[buttonName.."ItemIconTexture"];
+ iconTexture:SetTexture(texture);
+ highBidderFrame = _G[buttonName.."HighBidder"];
+ closingTimeFrame = _G[buttonName.."ClosingTime"];
+ closingTimeText = _G[buttonName.."ClosingTimeText"];
+ itemCount = _G[buttonName.."ItemCount"];
+ bidAmountMoneyFrame = _G[buttonName.."MoneyFrame"];
+ bidAmountMoneyFrameLabel = _G[buttonName.."MoneyFrameLabel"];
+ buttonBuyoutFrame = _G[buttonName.."BuyoutFrame"];
+ if ( saleStatus == 1 ) then
+ -- Sold item
+ itemName:SetFormattedText(AUCTION_ITEM_SOLD, name);
+ itemName:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+
+ if ( highBidder ) then
+ highBidder = GREEN_FONT_COLOR_CODE..highBidder..FONT_COLOR_CODE_CLOSE;
+ highBidderFrame:SetText(highBidder);
+ end
+
+ closingTimeText:SetFormattedText(AUCTION_ITEM_TIME_UNTIL_DELIVERY, SecondsToTime(duration));
+ closingTimeFrame.tooltip = closingTimeText:GetText();
+
+ iconTexture:SetVertexColor(0.5, 0.5, 0.5);
+
+ itemCount:Hide();
+ button.itemCount = count;
+
+ MoneyFrame_Update(buttonName.."MoneyFrame", bidAmount);
+ bidAmountMoneyFrame:SetAlpha(1);
+ bidAmountMoneyFrame:SetPoint("RIGHT", button, "RIGHT", 10, -4);
+ bidAmountMoneyFrameLabel:Show();
+
+ buttonBuyoutFrame:Hide();
+ else
+ -- Normal item
+ itemName:SetText(name);
+ itemName:SetVertexColor(color.r, color.g, color.b);
+
+ if ( not highBidder ) then
+ highBidder = RED_FONT_COLOR_CODE..NO_BIDS..FONT_COLOR_CODE_CLOSE;
+ end
+ highBidderFrame:SetText(highBidder);
+
+ closingTimeText:SetText(AuctionFrame_GetTimeLeftText(duration));
+ closingTimeFrame.tooltip = AuctionFrame_GetTimeLeftTooltipText(duration);
+
+ if ( not canUse ) then
+ iconTexture:SetVertexColor(1.0, 0.1, 0.1);
+ else
+ iconTexture:SetVertexColor(1.0, 1.0, 1.0);
+ end
+
+ if ( count > 1 ) then
+ itemCount:SetText(count);
+ itemCount:Show();
+ else
+ itemCount:Hide();
+ end
+ button.itemCount = count;
+
+ bidAmountMoneyFrameLabel:Hide();
+ if ( bidAmount > 0 ) then
+ -- Set high bid
+ MoneyFrame_Update(buttonName.."MoneyFrame", bidAmount);
+ bidAmountMoneyFrame:SetAlpha(1);
+ -- Set cancel price
+ auction.cancelPrice = floor(bidAmount * 0.05);
+ button.bidAmount = bidAmount;
+ else
+ -- No bids so show minBid and gray it out
+ MoneyFrame_Update(buttonName.."MoneyFrame", minBid);
+ bidAmountMoneyFrame:SetAlpha(0.5);
+ -- No cancel price
+ auction.cancelPrice = 0;
+ button.bidAmount = minBid;
+ end
+
+ -- Set buyout price and adjust bid amount accordingly
+ if ( buyoutPrice > 0 ) then
+ bidAmountMoneyFrame:SetPoint("RIGHT", buttonName, "RIGHT", 10, 10);
+ buttonBuyoutMoney = _G[buttonName.."BuyoutFrameMoney"];
+ MoneyFrame_Update(buttonBuyoutMoney, buyoutPrice);
+ buttonBuyoutFrame:Show();
+ else
+ bidAmountMoneyFrame:SetPoint("RIGHT", buttonName, "RIGHT", 10, 3);
+ buttonBuyoutFrame:Hide();
+ end
+ button.buyoutPrice = buyoutPrice;
+ end
+
+ -- Enable/Disable cancel auction button
+ if ( (GetSelectedAuctionItem("owner") > 0) and (saleStatus == 0) ) then
+ AuctionsCancelAuctionButton:Enable();
+ else
+ AuctionsCancelAuctionButton:Disable();
+ end
+ -- Set highlight
+ if ( GetSelectedAuctionItem("owner") and (offset + i) == GetSelectedAuctionItem("owner") ) then
+ auction:LockHighlight();
+ else
+ auction:UnlockHighlight();
+ end
+ end
+ end
+ -- If more than one page of auctions show the next and prev arrows when the scrollframe is scrolled all the way down
+ if ( totalAuctions > NUM_AUCTION_ITEMS_PER_PAGE ) then
+ if ( isLastSlotEmpty ) then
+ AuctionsSearchCountText:Show();
+ AuctionsSearchCountText:SetFormattedText(SINGLE_PAGE_RESULTS_TEMPLATE, totalAuctions);
+ else
+ AuctionsSearchCountText:Hide();
+ end
+
+ -- Artifically inflate the number of results so the scrollbar scrolls one extra row
+ numBatchAuctions = numBatchAuctions + 1;
+ else
+ AuctionsSearchCountText:Hide();
+ end
+
+ if ( GetSelectedAuctionItem("owner") and (GetSelectedAuctionItem("owner") > 0) and CanCancelAuction(GetSelectedAuctionItem("owner")) ) then
+ AuctionsCancelAuctionButton:Enable();
+ else
+ AuctionsCancelAuctionButton:Disable();
+ end
+
+ -- Update scrollFrame
+ FauxScrollFrame_Update(AuctionsScrollFrame, numBatchAuctions, NUM_AUCTIONS_TO_DISPLAY, AUCTIONS_BUTTON_HEIGHT);
+end
+
+function AuctionsButton_OnClick(button)
+ assert(button);
+
+ if ( GetCVarBool("auctionDisplayOnCharacter") ) then
+ DressUpItemLink(GetAuctionItemLink("owner", button:GetID() + FauxScrollFrame_GetOffset(AuctionsScrollFrame)));
+ end
+ SetSelectedAuctionItem("owner", button:GetID() + FauxScrollFrame_GetOffset(AuctionsScrollFrame));
+ -- Close any auction related popups
+ CloseAuctionStaticPopups();
+ AuctionFrameAuctions.cancelPrice = button.cancelPrice;
+ AuctionFrameAuctions_Update();
+end
+
+function PriceDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, PriceDropDown_Initialize);
+ if ( not AuctionFrameAuctions.priceType ) then
+ AuctionFrameAuctions.priceType = PRICE_TYPE_STACK;
+ end
+ UIDropDownMenu_SetSelectedValue(PriceDropDown, AuctionFrameAuctions.priceType);
+ UIDropDownMenu_SetWidth(PriceDropDown, 80);
+end
+
+function PriceDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = AUCTION_PRICE_PER_ITEM;
+ info.value = PRICE_TYPE_UNIT;
+ info.checked = nil;
+ info.func = PriceDropDown_OnClick;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = AUCTION_PRICE_PER_STACK;
+ info.value = PRICE_TYPE_STACK;
+ info.checked = nil;
+ info.func = PriceDropDown_OnClick;
+ UIDropDownMenu_AddButton(info);
+end
+
+function PriceDropDown_OnClick(self)
+ AuctionFrameAuctions.priceType = self.value;
+ UIDropDownMenu_SetSelectedValue(PriceDropDown, self.value);
+ local startPrice = MoneyInputFrame_GetCopper(StartPrice);
+ local buyoutPrice = MoneyInputFrame_GetCopper(BuyoutPrice);
+ local stackSize = AuctionsStackSizeEntry:GetNumber();
+ if ( stackSize > 1 ) then
+ if ( self.value == PRICE_TYPE_UNIT ) then
+ MoneyInputFrame_SetCopper(StartPrice, math.floor(startPrice / stackSize));
+ MoneyInputFrame_SetCopper(BuyoutPrice, math.floor(buyoutPrice / stackSize));
+ else
+ MoneyInputFrame_SetCopper(StartPrice, startPrice * stackSize);
+ MoneyInputFrame_SetCopper(BuyoutPrice, buyoutPrice * stackSize);
+ end
+ end
+end
+
+function DurationDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, DurationDropDown_Initialize);
+ if ( not AuctionFrameAuctions.duration ) then
+ AuctionFrameAuctions.duration = 2;
+ end
+ UIDropDownMenu_SetSelectedValue(DurationDropDown, AuctionFrameAuctions.duration);
+ UIDropDownMenu_SetWidth(DurationDropDown, 80);
+end
+
+function DurationDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = AUCTION_DURATION_ONE;
+ info.value = 1;
+ info.checked = nil;
+ info.func = DurationDropDown_OnClick;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = AUCTION_DURATION_TWO;
+ info.value = 2;
+ info.checked = nil;
+ info.func = DurationDropDown_OnClick;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = AUCTION_DURATION_THREE;
+ info.value = 3;
+ info.checked = nil;
+ info.func = DurationDropDown_OnClick;
+ UIDropDownMenu_AddButton(info);
+end
+
+function DurationDropDown_OnClick(self)
+ AuctionFrameAuctions.duration = self.value;
+ UIDropDownMenu_SetSelectedValue(DurationDropDown, self.value);
+ UpdateDeposit();
+end
+
+function UpdateDeposit()
+ MoneyFrame_Update("AuctionsDepositMoneyFrame", CalculateAuctionDeposit(AuctionFrameAuctions.duration, AuctionsStackSizeEntry:GetNumber() * AuctionsNumStacksEntry:GetNumber()));
+end
+
+function AuctionSellItemButton_OnEvent(self, event, ...)
+ if ( event == "NEW_AUCTION_UPDATE") then
+ local name, texture, count, quality, canUse, price, pricePerUnit, stackCount, totalCount = GetAuctionSellItemInfo();
+ AuctionsItemButton:SetNormalTexture(texture);
+ AuctionsItemButton.stackCount = stackCount;
+ AuctionsItemButton.totalCount = totalCount;
+ AuctionsItemButton.pricePerUnit = pricePerUnit;
+ AuctionsItemButtonName:SetText(name);
+ local color = ITEM_QUALITY_COLORS[quality];
+ AuctionsItemButtonName:SetVertexColor(color.r, color.g, color.b);
+ if ( totalCount > 1 ) then
+ AuctionsItemButtonCount:SetText(totalCount);
+ AuctionsItemButtonCount:Show();
+ AuctionsStackSizeEntry:Show();
+ AuctionsStackSizeMaxButton:Show();
+ AuctionsNumStacksEntry:Show();
+ AuctionsNumStacksMaxButton:Show();
+ UIDropDownMenu_EnableDropDown(PriceDropDown);
+ UpdateMaximumButtons();
+ else
+ AuctionsItemButtonCount:Hide();
+ AuctionsStackSizeEntry:Hide();
+ AuctionsStackSizeMaxButton:Hide();
+ AuctionsNumStacksEntry:Hide();
+ AuctionsNumStacksMaxButton:Hide();
+ -- checking for count of 1 so when a stack of 2 or more is removed by the user, we don't reset to "per item"
+ -- totalCount will be 0 when the sell item is removed
+ if ( totalCount == 1 ) then
+ AuctionFrameAuctions.priceType = PRICE_TYPE_UNIT;
+ UIDropDownMenu_SetSelectedValue(PriceDropDown, PRICE_TYPE_UNIT);
+ UIDropDownMenu_SetText(PriceDropDown, AUCTION_PRICE_PER_ITEM);
+ end
+ UIDropDownMenu_DisableDropDown(PriceDropDown);
+ end
+ AuctionsStackSizeEntry:SetNumber(count);
+ AuctionsNumStacksEntry:SetNumber(1);
+ if ( name == LAST_ITEM_AUCTIONED and count == LAST_ITEM_COUNT ) then
+ MoneyInputFrame_SetCopper(StartPrice, LAST_ITEM_START_BID);
+ MoneyInputFrame_SetCopper(BuyoutPrice, LAST_ITEM_BUYOUT);
+ else
+ if ( UIDropDownMenu_GetSelectedValue(PriceDropDown) == 1 and stackCount > 0 ) then
+ -- unit price
+ MoneyInputFrame_SetCopper(StartPrice, max(100, floor(pricePerUnit * 1.5)));
+
+ else
+ MoneyInputFrame_SetCopper(StartPrice, max(100, floor(price * 1.5)));
+ end
+ MoneyInputFrame_SetCopper(BuyoutPrice, 0);
+ if ( name ) then
+ LAST_ITEM_AUCTIONED = name;
+ LAST_ITEM_COUNT = count;
+ LAST_ITEM_START_BID = MoneyInputFrame_GetCopper(StartPrice);
+ LAST_ITEM_BUYOUT = MoneyInputFrame_GetCopper(BuyoutPrice);
+ end
+ end
+ UpdateDeposit();
+ AuctionsFrameAuctions_ValidateAuction();
+ end
+end
+
+function AuctionSellItemButton_OnClick(self, button)
+ ClickAuctionSellItemButton(self, button);
+ AuctionsFrameAuctions_ValidateAuction();
+end
+
+function AuctionsFrameAuctions_ValidateAuction()
+ AuctionsCreateAuctionButton:Disable();
+ AuctionsBuyoutText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ AuctionsBuyoutError:Hide();
+ -- No item
+ if ( not GetAuctionSellItemInfo() ) then
+ return;
+ end
+ -- Buyout price is less than the start price
+ if ( MoneyInputFrame_GetCopper(BuyoutPrice) > 0 and MoneyInputFrame_GetCopper(StartPrice) > MoneyInputFrame_GetCopper(BuyoutPrice) ) then
+ AuctionsBuyoutText:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ AuctionsBuyoutError:Show();
+ return;
+ end
+ -- Start price is 0 or greater than the max allowed
+ if ( MoneyInputFrame_GetCopper(StartPrice) < 1 or MoneyInputFrame_GetCopper(StartPrice) > MAXIMUM_BID_PRICE) then
+ return;
+ end
+ -- The stack size is greater than total count
+ local stackCount = AuctionsItemButton.stackCount or 0;
+ local totalCount = AuctionsItemButton.totalCount or 0;
+ if ( AuctionsStackSizeEntry:GetNumber() == 0 or AuctionsStackSizeEntry:GetNumber() > stackCount or AuctionsNumStacksEntry:GetNumber() == 0 or (AuctionsStackSizeEntry:GetNumber() * AuctionsNumStacksEntry:GetNumber() > totalCount) ) then
+ return;
+ end
+ AuctionsCreateAuctionButton:Enable();
+end
+
+--[[
+function AuctionFrame_UpdateTimeLeft(elapsed, type)
+ if ( not self.updateCounter ) then
+ self.updateCounter = 0;
+ end
+ if ( self.updateCounter > AUCTION_TIMER_UPDATE_DELAY ) then
+ self.updateCounter = 0;
+ local index = self:GetID();
+ if ( type == "list" ) then
+ index = index + FauxScrollFrame_GetOffset(BrowseScrollFrame);
+ elseif ( type == "bidder" ) then
+ index = index + FauxScrollFrame_GetOffset(BidScrollFrame);
+ elseif ( type == "owner" ) then
+ index = index + FauxScrollFrame_GetOffset(AuctionsScrollFrame);
+ end
+ _G[self:GetName().."ClosingTime"]:SetText(SecondsToTime(GetAuctionItemTimeLeft(type, index)));
+ else
+ self.updateCounter = self.updateCounter + elapsed;
+ end
+end
+]]
+
+function AuctionFrame_GetTimeLeftText(id)
+ return _G["AUCTION_TIME_LEFT"..id];
+end
+
+function AuctionFrame_GetTimeLeftTooltipText(id)
+ return _G["AUCTION_TIME_LEFT"..id.."_DETAIL"];
+end
+
+function AuctionFrameItem_OnEnter(self, type, index)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetAuctionItem(type, index);
+
+ -- add price per unit info
+ local button;
+ if ( type == "owner" ) then
+ button = _G["AuctionsButton"..self:GetParent():GetID()];
+ elseif ( type == "bidder" ) then
+ button = _G["BidButton"..self:GetParent():GetID()];
+ elseif ( type == "list" ) then
+ button = _G["BrowseButton"..self:GetParent():GetID()];
+ end
+ if ( button and button.itemCount > 1 ) then
+ if ( button.bidAmount > 0 ) then
+ GameTooltip:AddLine("|n");
+ SetTooltipMoney(GameTooltip, ceil(button.bidAmount / button.itemCount), "STATIC", AUCTION_TOOLTIP_BID_PREFIX);
+ end
+ if ( button.buyoutPrice > 0 ) then
+ SetTooltipMoney(GameTooltip, ceil(button.buyoutPrice / button.itemCount), "STATIC", AUCTION_TOOLTIP_BUYOUT_PREFIX);
+ end
+ GameTooltip:Show();
+ end
+
+ GameTooltip_ShowCompareItem();
+
+ if ( IsModifiedClick("DRESSUP") ) then
+ ShowInspectCursor();
+ else
+ ResetCursor();
+ end
+end
+
+-- SortButton functions
+function SortButton_UpdateArrow(button, type, sort)
+ local primaryColumn, reversed = GetAuctionSort(type, 1);
+ if (sort == primaryColumn) then
+ -- primary column, show the sort arrow
+ if (reversed) then
+ _G[button:GetName().."Arrow"]:Show();
+ _G[button:GetName().."Arrow"]:SetTexCoord(0, 0.5625, 1.0, 0);
+ else
+ _G[button:GetName().."Arrow"]:Show();
+ _G[button:GetName().."Arrow"]:SetTexCoord(0, 0.5625, 0, 1.0);
+ end
+ else
+ -- hide sort arrows for non-primary column
+ _G[button:GetName().."Arrow"]:Hide();
+ end
+end
+
+-- Function to close popups if another auction item is selected
+function CloseAuctionStaticPopups()
+ StaticPopup_Hide("BUYOUT_AUCTION");
+ StaticPopup_Hide("BID_AUCTION");
+ StaticPopup_Hide("CANCEL_AUCTION");
+end
+
+function AuctionsCreateAuctionButton_OnClick()
+ LAST_ITEM_START_BID = MoneyInputFrame_GetCopper(StartPrice);
+ LAST_ITEM_BUYOUT = MoneyInputFrame_GetCopper(BuyoutPrice);
+ DropCursorMoney();
+ PlaySound("LOOTWINDOWCOINSOUND");
+ local startPrice = MoneyInputFrame_GetCopper(StartPrice);
+ local buyoutPrice = MoneyInputFrame_GetCopper(BuyoutPrice);
+ if ( AuctionFrameAuctions.priceType == PRICE_TYPE_UNIT ) then
+ startPrice = startPrice * AuctionsStackSizeEntry:GetNumber();
+ buyoutPrice = buyoutPrice * AuctionsStackSizeEntry:GetNumber();
+ end
+ StartAuction(startPrice, buyoutPrice, AuctionFrameAuctions.duration, AuctionsStackSizeEntry:GetNumber(), AuctionsNumStacksEntry:GetNumber());
+end
+
+function SetMaxStackSize()
+ local stackCount = AuctionsItemButton.stackCount;
+ local totalCount = AuctionsItemButton.totalCount;
+ if ( totalCount and totalCount > 0 ) then
+ if ( totalCount > stackCount ) then
+ AuctionsStackSizeEntry:SetNumber(stackCount);
+ AuctionsNumStacksEntry:SetNumber(math.floor(totalCount / stackCount));
+ else
+ AuctionsStackSizeEntry:SetNumber(totalCount);
+ AuctionsNumStacksEntry:SetNumber(1);
+ end
+ else
+ AuctionsStackSizeEntry:SetNumber("");
+ AuctionsNumStacksEntry:SetNumber("");
+ end
+end
+
+function UpdateMaximumButtons()
+ local stackCount = AuctionsItemButton.stackCount;
+ local totalCount = AuctionsItemButton.totalCount;
+ local stackSize = AuctionsStackSizeEntry:GetNumber();
+ if ( stackSize ~= min(totalCount, stackCount) ) then
+ AuctionsStackSizeMaxButton:Enable();
+ else
+ AuctionsStackSizeMaxButton:Disable();
+ end
+ if ( AuctionsNumStacksEntry:GetNumber() ~= math.floor(totalCount / stackSize) ) then
+ AuctionsNumStacksMaxButton:Enable();
+ else
+ AuctionsNumStacksMaxButton:Disable();
+ end
+end
+
+function AuctionProgressFrame_OnUpdate(self)
+ if ( self.fadeOut ) then
+ local alpha = self:GetAlpha() - CASTING_BAR_ALPHA_STEP;
+ if ( alpha > 0 ) then
+ self:SetAlpha(alpha);
+ else
+ self.fadeOut = nil;
+ self:Hide();
+ self:SetAlpha(1);
+ end
+ end
+end
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUI.toc b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUI.toc
new file mode 100644
index 0000000..4e1da83
--- /dev/null
+++ b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUI.toc
@@ -0,0 +1,7 @@
+## Interface: 30300
+## Title: Blizzard Auction UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_AuctionUI.xml
+Blizzard_AuctionDressUp.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUI.xml b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUI.xml
new file mode 100644
index 0000000..4ff86bc
--- /dev/null
+++ b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUI.xml
@@ -0,0 +1,1965 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, BROWSE_FILTER_HEIGHT, AuctionFrameFilters_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, AUCTIONS_BUTTON_HEIGHT, AuctionFrameBrowse_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("list", "quality")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("list", "level")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("list", "duration")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("list", "seller")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("list", "bid");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsShiftKeyDown() ) then
+ BrowseBidPriceCopper:SetFocus();
+ else
+ BrowseMinLevel:SetFocus();
+ end
+
+
+ AuctionFrameBrowse_Search();
+ self:ClearFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsShiftKeyDown() ) then
+ BrowseName:SetFocus();
+ else
+ BrowseMaxLevel:SetFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsShiftKeyDown() ) then
+ BrowseMinLevel:SetFocus();
+ else
+ BrowseBidPriceGold:SetFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IsUsableCheckButtonText:SetFontObject(GameFontHighlightSmall);
+ IsUsableCheckButtonText:SetText(USABLE_ITEMS);
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ShowOnPlayerCheckButtonText:SetFontObject(GameFontHighlightSmall);
+ ShowOnPlayerCheckButtonText:SetText(DISPLAY_ON_CHARACTER);
+
+
+ self:SetChecked(GetCVarBool("auctionDisplayOnCharacter"));
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ SetCVar("auctionDisplayOnCharacter", self:GetChecked());
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(DISPLAY_ON_CHAR_TOOLTIP, nil, nil, nil, nil, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrameBrowse_Search();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ AuctionFrameBrowse.page = AuctionFrameBrowse.page - 1;
+ self:Disable();
+ BrowseScrollFrameScrollBar:SetValue(0);
+ AuctionFrameBrowse_Search();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ AuctionFrameBrowse.page = AuctionFrameBrowse.page + 1;
+ self:Disable();
+ BrowseScrollFrameScrollBar:SetValue(0);
+ AuctionFrameBrowse_Search();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("BUYOUT_AUCTION");
+ self:Disable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("BID_AUCTION");
+ self:Disable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("bidder", "quality")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("bidder", "level")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("bidder", "duration")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("bidder", "buyout")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("bidder", "status")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("bidder", "bid")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, AUCTIONS_BUTTON_HEIGHT, AuctionFrameBid_Update)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("BUYOUT_AUCTION");
+ self:Disable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaceAuctionBid("bidder", GetSelectedAuctionItem("bidder"), MoneyInputFrame_GetCopper(BidBidPrice))
+ self:Disable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("owner", "quality")
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("owner", "duration")
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("owner", "status")
+
+
+
+
+
+
+
+
+
+
+ AuctionFrame_OnClickSortColumn("owner", "bid")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, AUCTIONS_BUTTON_HEIGHT, AuctionFrameAuctions_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("NEW_AUCTION_UPDATE");
+ self:RegisterForDrag("LeftButton");
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( GetAuctionSellItemInfo() ) then
+ GameTooltip:SetAuctionSellItem();
+ else
+ GameTooltip:SetText(AUCTION_ITEM_TEXT, 1.0, 1.0, 1.0);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsShiftKeyDown() ) then
+ if ( self.prevFocus ) then
+ self.prevFocus:SetFocus();
+ else
+ self:ClearFocus();
+ end
+ else
+ if ( self.nextFocus ) then
+ self.nextFocus:SetFocus();
+ else
+ self:ClearFocus();
+ end
+ end
+
+
+ if ( self.nextFocus ) then
+ self.nextFocus:SetFocus();
+ else
+ self:ClearFocus();
+ end
+
+
+ EditBox_ClearFocus(self);
+
+
+ AuctionsFrameAuctions_ValidateAuction();
+ UpdateMaximumButtons();
+ UpdateDeposit();
+
+
+ EditBox_ClearHighlight(self);
+
+
+ EditBox_HighlightText(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsShiftKeyDown() ) then
+ if ( self.prevFocus ) then
+ self.prevFocus:SetFocus();
+ else
+ self:ClearFocus();
+ end
+ else
+ if ( self.nextFocus ) then
+ self.nextFocus:SetFocus();
+ else
+ self:ClearFocus();
+ end
+ end
+
+
+ if ( self.nextFocus ) then
+ self.nextFocus:SetFocus();
+ else
+ self:ClearFocus();
+ end
+
+
+ EditBox_ClearFocus(self);
+
+
+ AuctionsFrameAuctions_ValidateAuction();
+ UpdateMaximumButtons();
+ UpdateDeposit();
+
+
+ EditBox_ClearHighlight(self);
+
+
+ EditBox_HighlightText(self);
+
+
+
+
+
+
+
+
+
+
+
+ local stackSize = AuctionsStackSizeEntry:GetNumber();
+ if ( stackSize == 0 ) then
+ AuctionsStackSizeEntry:SetText(1);
+ stackSize = 1;
+ end
+ if ( AuctionsItemButton.stackCount and AuctionsItemButton.totalCount and AuctionsItemButton.totalCount > 0) then
+ AuctionsNumStacksEntry:SetNumber( floor(AuctionsItemButton.totalCount / stackSize) );
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MoneyInputFrame_SetOnValueChangedFunc(self, AuctionsFrameAuctions_ValidateAuction);
+ StartPriceGold:SetMaxLetters(6);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MoneyInputFrame_SetOnValueChangedFunc(self, AuctionsFrameAuctions_ValidateAuction);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(AUCTION_BUYOUT_ERROR, 1.0, 0.0, 0.0);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.small = 1;
+ MoneyFrame_SetType(self, "AUCTION_DEPOSIT");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GetSelectedAuctionItem("owner") and (GetSelectedAuctionItem("owner") > 0) ) then
+ StaticPopup_Show("CANCEL_AUCTION");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(9001);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("AuctionWindowClose");
+ StaticPopup_Hide("BUYOUT_AUCTION");
+ StaticPopup_Hide("CANCEL_AUCTION");
+ HideUIPanel(AuctionDressUpFrame);
+ SetAuctionsTabShowing(false);
+ CloseAuctionHouse();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionProgressBarSpark:Hide();
+ AuctionProgressBarFlash:Hide();
+ AuctionProgressBarIcon:Show();
+ AuctionProgressBarIcon:SetWidth(24);
+ AuctionProgressBarIcon:SetHeight(24);
+ AuctionProgressBarIcon:SetPoint("RIGHT", "$parent", "LEFT", -10, 2);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CancelSell();
+
+
+
+
+
+
+
+
+
+ UIParent_ManageFramePositions();
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUITemplates.xml b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUITemplates.xml
new file mode 100644
index 0000000..153ebb5
--- /dev/null
+++ b/reference/AddOns/Blizzard_AuctionUI/Blizzard_AuctionUITemplates.xml
@@ -0,0 +1,977 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrameFilter_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():LockHighlight();
+ AuctionFrameItem_OnEnter(self, "list", self:GetParent():GetID() + FauxScrollFrame_GetOffset(BrowseScrollFrame));
+
+
+ local selected = GetSelectedAuctionItem("list");
+ if ( selected and ( selected == self:GetParent():GetID() + FauxScrollFrame_GetOffset(BrowseScrollFrame) ) ) then
+
+ else
+ self:GetParent():UnlockHighlight();
+ end
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ if ( IsModifiedClick() ) then
+ HandleModifiedItemClick(GetAuctionItemLink("list", self:GetParent():GetID() + FauxScrollFrame_GetOffset(BrowseScrollFrame)));
+ else
+ BrowseButton_OnClick(self:GetParent());
+ end
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ AuctionFrameItem_OnEnter(self, "list", self:GetParent():GetID() + FauxScrollFrame_GetOffset(BrowseScrollFrame));
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():LockHighlight();
+ GameTooltip:SetOwner(self);
+ GameTooltip:SetText(self.tooltip);
+
+
+ local selected = GetSelectedAuctionItem("list");
+ if ( selected and ( selected == self:GetParent():GetID() + FauxScrollFrame_GetOffset(BrowseScrollFrame) ) ) then
+
+ else
+ self:GetParent():UnlockHighlight();
+ end
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+ SetMoneyFrameColor(self:GetName(), "yellow")
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsModifiedClick() ) then
+ HandleModifiedItemClick(GetAuctionItemLink("list", self:GetID() + FauxScrollFrame_GetOffset(BrowseScrollFrame)));
+ else
+ BrowseButton_OnClick(self);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():LockHighlight();
+ AuctionFrameItem_OnEnter(self, "bidder", self:GetParent():GetID() + FauxScrollFrame_GetOffset(BidScrollFrame));
+
+
+ local selected = GetSelectedAuctionItem("bidder");
+ if ( selected and ( selected == self:GetParent():GetID() + FauxScrollFrame_GetOffset(BidScrollFrame) ) ) then
+
+ else
+ self:GetParent():UnlockHighlight();
+ end
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ if ( IsModifiedClick() ) then
+ HandleModifiedItemClick(GetAuctionItemLink("bidder", self:GetParent():GetID() + FauxScrollFrame_GetOffset(BidScrollFrame)));
+ else
+ BidButton_OnClick(self:GetParent());
+ end
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ AuctionFrameItem_OnEnter(self, "bidder", self:GetParent():GetID() + FauxScrollFrame_GetOffset(BidScrollFrame));
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():LockHighlight();
+ GameTooltip:SetOwner(self);
+ GameTooltip:SetText(self.tooltip);
+
+
+ local selected = GetSelectedAuctionItem("bidder");
+ if ( selected and ( selected == self:GetParent():GetID() + FauxScrollFrame_GetOffset(BidScrollFrame) ) ) then
+
+ else
+ self:GetParent():UnlockHighlight();
+ end
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+
+
+
+
+
+
+ if ( IsModifiedClick() ) then
+ HandleModifiedItemClick(GetAuctionItemLink("bidder", self:GetID() + FauxScrollFrame_GetOffset(BidScrollFrame)));
+ else
+ BidButton_OnClick(self);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():LockHighlight();
+ AuctionFrameItem_OnEnter(self, "owner", self:GetParent():GetID() + FauxScrollFrame_GetOffset(AuctionsScrollFrame));
+
+
+ local selected = GetSelectedAuctionItem("owner");
+ if ( selected and ( selected == ( self:GetParent():GetID() + FauxScrollFrame_GetOffset(AuctionsScrollFrame) ) ) ) then
+
+ else
+ self:GetParent():UnlockHighlight();
+ end
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ if ( IsModifiedClick() ) then
+ HandleModifiedItemClick(GetAuctionItemLink("owner", self:GetParent():GetID() + FauxScrollFrame_GetOffset(AuctionsScrollFrame)));
+ else
+ AuctionsButton_OnClick(self:GetParent());
+ end
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ AuctionFrameItem_OnEnter(self, "owner", self:GetParent():GetID() + FauxScrollFrame_GetOffset(AuctionsScrollFrame));
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():LockHighlight();
+ GameTooltip:SetOwner(self);
+ GameTooltip:SetText(self.tooltip);
+
+
+ local selected = GetSelectedAuctionItem("owner");
+ if ( selected and ( selected == ( self:GetParent():GetID() + FauxScrollFrame_GetOffset(AuctionsScrollFrame) ) ) ) then
+
+ else
+ self:GetParent():UnlockHighlight();
+ end
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsModifiedClick() ) then
+ HandleModifiedItemClick(GetAuctionItemLink("owner", self:GetID() + FauxScrollFrame_GetOffset(AuctionsScrollFrame)));
+ else
+ AuctionsButton_OnClick(self);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AuctionFrameTab_OnClick(self, button, down);
+
+
+
+
diff --git a/reference/AddOns/Blizzard_AuctionUI/Localization.lua b/reference/AddOns/Blizzard_AuctionUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_AuctionUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_BarbershopUI/Blizzard_BarberShopUI.lua b/reference/AddOns/Blizzard_BarbershopUI/Blizzard_BarberShopUI.lua
new file mode 100644
index 0000000..b9ba178
--- /dev/null
+++ b/reference/AddOns/Blizzard_BarbershopUI/Blizzard_BarberShopUI.lua
@@ -0,0 +1,111 @@
+function BarberShop_OnLoad(self)
+ BarberShop_UpdateHairCustomization();
+ BarberShop_UpdateFacialHairCustomization();
+ self:RegisterEvent("BARBER_SHOP_APPEARANCE_APPLIED");
+ self:RegisterEvent("BARBER_SHOP_SUCCESS");
+
+ if ( CanAlterSkin() ) then
+ BarberShop_ToFourAttributeFormat();
+ end
+end
+
+function BarberShop_OnShow(self)
+ CloseAllBags();
+ BarberShop_ResetLabelColors();
+ BarberShop_UpdateCost();
+ if ( BarberShopBannerFrame ) then
+ BarberShopBannerFrame:Show();
+ BarberShopBannerFrame.caption:SetText(BARBERSHOP);
+ end
+ self:ClearAllPoints();
+ self:SetPoint("RIGHT", min(-50, -CONTAINER_OFFSET_X), -50);
+
+ PlaySound("BarberShop_Sit");
+
+ WatchFrame:Hide();
+
+ --load the texture
+ BarberShopFrameBackground:SetTexture("Interface\\Barbershop\\UI-Barbershop");
+end
+
+function BarberShop_OnHide(self)
+ BarberShopBannerFrame:Hide();
+
+ WatchFrame:Show();
+
+ --unload the texture to save memory
+ BarberShopFrameBackground:SetTexture(nil);
+end
+
+function BarberShop_OnEvent(self, event, ...)
+ if(event == "BARBER_SHOP_SUCCESS") then
+ PlaySound("Barbershop_Haircut");
+ end
+ BarberShop_Update(self);
+end
+
+function BarberShop_UpdateCost()
+ MoneyFrame_Update(BarberShopFrameMoneyFrame:GetName(), GetBarberShopTotalCost());
+ -- The 4th return from GetBarberShopStyleInfo is whether the selected style is the active character style
+ if ( select(4, GetBarberShopStyleInfo(1)) and select(4, GetBarberShopStyleInfo(2)) and select(4, GetBarberShopStyleInfo(3)) and ( not BarberShopFrameSelector4:IsShown() or select(4, GetBarberShopStyleInfo(4)) ) ) then
+ BarberShopFrameOkayButton:Disable();
+ BarberShopFrameResetButton:Disable();
+ else
+ BarberShopFrameOkayButton:Enable();
+ BarberShopFrameResetButton:Enable();
+ end
+end
+
+function BarberShop_UpdateBanner(name)
+ if ( name ) then
+ BarberShopBannerFrameCaption:SetText(name);
+ end
+end
+
+function BarberShop_Update(self)
+ BarberShop_UpdateCost();
+ BarberShop_UpdateSelector(BarberShopFrameSelector4);
+ BarberShop_UpdateSelector(BarberShopFrameSelector3);
+ BarberShop_UpdateSelector(BarberShopFrameSelector2);
+ BarberShop_UpdateSelector(BarberShopFrameSelector1);
+end
+
+function BarberShop_UpdateSelector(self)
+ local name, _, _, isCurrent = GetBarberShopStyleInfo(self:GetID());
+ BarberShop_UpdateBanner(name);
+ local frameName = self:GetName();
+ BarberShop_SetLabelColor(_G[frameName.."Category"], isCurrent);
+end
+
+function BarberShop_UpdateHairCustomization()
+ local hairCustomization = GetHairCustomization();
+ BarberShopFrameSelector1Category:SetText(_G["HAIR_"..hairCustomization.."_STYLE"]);
+ BarberShopFrameSelector2Category:SetText(_G["HAIR_"..hairCustomization.."_COLOR"]);
+end
+
+function BarberShop_UpdateFacialHairCustomization()
+ BarberShopFrameSelector3Category:SetText(_G["FACIAL_HAIR_"..GetFacialHairCustomization()]);
+end
+
+function BarberShop_SetLabelColor(label, isCurrent)
+ if ( isCurrent ) then
+ label:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ else
+ label:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+end
+
+function BarberShop_ResetLabelColors()
+ BarberShop_SetLabelColor(BarberShopFrameSelector1Category, 1);
+ BarberShop_SetLabelColor(BarberShopFrameSelector2Category, 1);
+ BarberShop_SetLabelColor(BarberShopFrameSelector3Category, 1);
+ BarberShop_SetLabelColor(BarberShopFrameSelector4Category, 1);
+end
+
+function BarberShop_ToFourAttributeFormat()
+ BarberShopFrameSelector2:SetPoint("TOPLEFT", BarberShopFrameSelector1, "BOTTOMLEFT", 0, 3);
+ BarberShopFrameSelector3:SetPoint("TOPLEFT", BarberShopFrameSelector2, "BOTTOMLEFT", 0, 3);
+ BarberShopFrameSelector4:Show();
+ BarberShopFrameMoneyFrame:SetPoint("TOP", BarberShopFrameSelector4, "BOTTOM", 7, -7);
+ BarberShopFrameOkayButton:SetPoint("RIGHT", BarberShopFrameSelector4, "BOTTOM", -2, -36);
+end
diff --git a/reference/AddOns/Blizzard_BarbershopUI/Blizzard_BarberShopUI.toc b/reference/AddOns/Blizzard_BarbershopUI/Blizzard_BarberShopUI.toc
new file mode 100644
index 0000000..eee603f
--- /dev/null
+++ b/reference/AddOns/Blizzard_BarbershopUI/Blizzard_BarberShopUI.toc
@@ -0,0 +1,10 @@
+## Interface: 30300
+## Title: Blizzard Barber Shop UI
+## Notes: The barber's blade went snicker-snack! Have you seen my Jabberwocky?
+## Secure: 1
+## Author: Blizzard Entertainment
+## Version: 1.0
+## LoadOnDemand: 1
+Blizzard_BarberShopUI.lua
+Blizzard_BarberShopUI.xml
+Localization.lua
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_BarbershopUI/Blizzard_BarberShopUI.xml b/reference/AddOns/Blizzard_BarbershopUI/Blizzard_BarberShopUI.xml
new file mode 100644
index 0000000..65b4291
--- /dev/null
+++ b/reference/AddOns/Blizzard_BarbershopUI/Blizzard_BarberShopUI.xml
@@ -0,0 +1,277 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parent = self:GetParent();
+ SetNextBarberShopStyle(parent:GetID(), 1);
+ PlaySound("UChatScrollButton");
+ BarberShop_UpdateCost();
+ BarberShop_UpdateSelector(parent);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parent = self:GetParent();
+ SetNextBarberShopStyle(parent:GetID());
+ PlaySound("UChatScrollButton");
+ BarberShop_UpdateCost();
+ BarberShop_UpdateSelector(parent);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Category"]:SetText("Hair Style");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Category"]:SetText("Hair Color");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Category"]:SetText("Facial Style");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Category"]:SetText(SKIN_COLOR);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "GUILD_REPAIR");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CancelBarberShop();
+ PlaySound("igCharacterInfoClose");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BarberShopReset();
+ BarberShop_ResetLabelColors();
+ BarberShop_UpdateCost();
+ BarberShop_UpdateBanner(GetBarberShopStyleInfo(1));
+ PlaySound("igCharacterInfoClose");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.caption = _G[self:GetName() .. "Caption"];
+
+
+ UIErrorsFrame:SetPoint("TOP", self, "BOTTOM", 0, 0);
+ BarberShopBannerFrameBGTexture:SetTexture("Interface\\Barbershop\\UI-Barbershop-Banner");
+
+
+ UIErrorsFrame:SetPoint("TOP", UIParent, "TOP", 0, -122);
+ BarberShopBannerFrameBGTexture:SetTexture(nil);
+
+
+
+
diff --git a/reference/AddOns/Blizzard_BarbershopUI/Localization.lua b/reference/AddOns/Blizzard_BarbershopUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_BarbershopUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_BattlefieldMinimap/Blizzard_BattlefieldMinimap.lua b/reference/AddOns/Blizzard_BattlefieldMinimap/Blizzard_BattlefieldMinimap.lua
new file mode 100644
index 0000000..2e72f8a
--- /dev/null
+++ b/reference/AddOns/Blizzard_BattlefieldMinimap/Blizzard_BattlefieldMinimap.lua
@@ -0,0 +1,596 @@
+
+BATTLEFIELD_TAB_SHOW_DELAY = 0.2;
+BATTLEFIELD_TAB_FADE_TIME = 0.15;
+DEFAULT_BATTLEFIELD_TAB_ALPHA = 0.75;
+DEFAULT_POI_ICON_SIZE = 12;
+BATTLEFIELD_MINIMAP_UPDATE_RATE = 0.1;
+NUM_BATTLEFIELDMAP_POIS = 0;
+NUM_BATTLEFIELDMAP_OVERLAYS = 0;
+
+local BattlefieldMinimapDefaults = {
+ opacity = 0.7,
+ locked = true,
+ showPlayers = true,
+};
+
+BG_VEHICLES = {};
+
+
+function BattlefieldMinimap_Toggle()
+ if ( BattlefieldMinimap:IsShown() ) then
+ SetCVar("showBattlefieldMinimap", "0");
+ BattlefieldMinimap:Hide();
+ WorldMapZoneMinimapDropDown_Update();
+ else
+ local _, instanceType = IsInInstance();
+ if ( instanceType == "pvp" ) then
+ SetCVar("showBattlefieldMinimap", "1");
+ BattlefieldMinimap:Show();
+ WorldMapZoneMinimapDropDown_Update();
+ elseif ( instanceType ~= "arena" ) then
+ SetCVar("showBattlefieldMinimap", "2");
+ BattlefieldMinimap:Show();
+ WorldMapZoneMinimapDropDown_Update();
+ end
+ end
+end
+
+function BattlefieldMinimap_OnLoad (self)
+ self:RegisterEvent("ADDON_LOADED");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("ZONE_CHANGED");
+ self:RegisterEvent("ZONE_CHANGED_NEW_AREA");
+ self:RegisterEvent("PLAYER_LOGOUT");
+ self:RegisterEvent("WORLD_MAP_UPDATE");
+ self:RegisterEvent("ZONE_CHANGED_NEW_AREA");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("RAID_ROSTER_UPDATE");
+
+ CreateMiniWorldMapArrowFrame(BattlefieldMinimap);
+
+ BattlefieldMinimap.updateTimer = 0;
+ -- PlayerMiniArrowEffectFrame is created in code: CWorldMap::CreateMiniPlayerArrowFrame()
+ PlayerMiniArrowEffectFrame:SetFrameLevel(WorldMapParty1:GetFrameLevel() + 1);
+ PlayerMiniArrowEffectFrame:SetAlpha(0.65);
+end
+
+function BattlefieldMinimap_OnShow(self)
+ SetMapToCurrentZone();
+ BattlefieldMinimap_Update();
+ BattlefieldMinimap_UpdateOpacity(BattlefieldMinimapOptions.opacity);
+ BattlefieldMinimapTab:Show();
+ WorldMapFrame_UpdateUnits("BattlefieldMinimapRaid", "BattlefieldMinimapParty");
+end
+
+function BattlefieldMinimap_OnHide(self)
+ BattlefieldMinimapTab:Hide();
+ BattlefieldMinimap_ClearTextures();
+end
+
+function BattlefieldMinimap_OnEvent(self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local arg1 = ...;
+ if ( arg1 == "Blizzard_BattlefieldMinimap" ) then
+ if ( not BattlefieldMinimapOptions ) then
+ BattlefieldMinimapOptions = BattlefieldMinimapDefaults;
+ end
+
+ if ( BattlefieldMinimapOptions.position ) then
+ BattlefieldMinimapTab:SetPoint("CENTER", "UIParent", "BOTTOMLEFT", BattlefieldMinimapOptions.position.x, BattlefieldMinimapOptions.position.y);
+ BattlefieldMinimapTab:SetUserPlaced(true);
+ else
+ BattlefieldMinimapTab:SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMRIGHT", -225-CONTAINER_OFFSET_X, BATTLEFIELD_TAB_OFFSET_Y);
+ end
+
+ UIDropDownMenu_Initialize(BattlefieldMinimapTabDropDown, BattlefieldMinimapTabDropDown_Initialize, "MENU");
+
+ OpacityFrameSlider:SetValue(BattlefieldMinimapOptions.opacity);
+ BattlefieldMinimap_UpdateOpacity();
+ end
+ elseif ( event == "PLAYER_ENTERING_WORLD" or event == "ZONE_CHANGED" or event == "ZONE_CHANGED_NEW_AREA") then
+ if ( BattlefieldMinimap:IsShown() ) then
+ SetMapToCurrentZone();
+ BattlefieldMinimap_Update();
+ end
+ elseif ( event == "PLAYER_LOGOUT" ) then
+ if ( BattlefieldMinimapTab:IsUserPlaced() ) then
+ if ( not BattlefieldMinimapOptions.position ) then
+ BattlefieldMinimapOptions.position = {};
+ end
+ BattlefieldMinimapOptions.position.x, BattlefieldMinimapOptions.position.y = BattlefieldMinimapTab:GetCenter();
+ BattlefieldMinimapTab:SetUserPlaced(false);
+ else
+ BattlefieldMinimapOptions.position = nil;
+ end
+ elseif ( event == "WORLD_MAP_UPDATE" ) then
+ if ( BattlefieldMinimap:IsVisible() ) then
+ BattlefieldMinimap_Update();
+ end
+ elseif ( event == "PARTY_MEMBERS_CHANGED" or event == "RAID_ROSTER_UPDATE" ) then
+ if ( self:IsShown() ) then
+ WorldMapFrame_UpdateUnits("BattlefieldMinimapRaid", "BattlefieldMinimapParty");
+ end
+ end
+end
+
+function BattlefieldMinimap_Update()
+ -- Fill in map tiles
+ local mapFileName, textureHeight = GetMapInfo();
+ if ( not mapFileName ) then
+ return;
+ end
+ local texName;
+ local dungeonLevel = GetCurrentMapDungeonLevel();
+ local completeMapFileName;
+ if ( dungeonLevel > 0 ) then
+ completeMapFileName = mapFileName..dungeonLevel.."_";
+ else
+ completeMapFileName = mapFileName;
+ end
+ for i=1, NUM_WORLDMAP_DETAIL_TILES do
+ texName = "Interface\\WorldMap\\"..mapFileName.."\\"..completeMapFileName..i;
+ _G["BattlefieldMinimap"..i]:SetTexture(texName);
+ end
+
+ -- Setup the POI's
+ local iconSize = DEFAULT_POI_ICON_SIZE * GetBattlefieldMapIconScale();
+ local numPOIs = GetNumMapLandmarks();
+ if ( NUM_BATTLEFIELDMAP_POIS < numPOIs ) then
+ for i=NUM_BATTLEFIELDMAP_POIS+1, numPOIs do
+ BattlefieldMinimap_CreatePOI(i);
+ end
+ NUM_BATTLEFIELDMAP_POIS = numPOIs;
+ end
+ for i=1, NUM_BATTLEFIELDMAP_POIS do
+ local battlefieldPOIName = "BattlefieldMinimapPOI"..i;
+ local battlefieldPOI = _G[battlefieldPOIName];
+ if ( i <= numPOIs ) then
+ local name, description, textureIndex, x, y, maplinkID, showInBattleMap = GetMapLandmarkInfo(i);
+ if ( showInBattleMap ) then
+ local x1, x2, y1, y2 = WorldMap_GetPOITextureCoords(textureIndex);
+ _G[battlefieldPOIName.."Texture"]:SetTexCoord(x1, x2, y1, y2);
+ x = x * BattlefieldMinimap:GetWidth();
+ y = -y * BattlefieldMinimap:GetHeight();
+ battlefieldPOI:SetPoint("CENTER", "BattlefieldMinimap", "TOPLEFT", x, y );
+ battlefieldPOI:SetWidth(iconSize);
+ battlefieldPOI:SetHeight(iconSize);
+ battlefieldPOI:Show();
+ else
+ battlefieldPOI:Hide();
+ end
+ else
+ battlefieldPOI:Hide();
+ end
+ end
+
+ -- Setup the overlays
+ local numOverlays = GetNumMapOverlays();
+ local textureCount = 0;
+ -- Use this value to scale the texture sizes and offsets
+ local battlefieldMinimapScale = BattlefieldMinimap1:GetWidth()/256;
+ for i=1, numOverlays do
+ local textureName, textureWidth, textureHeight, offsetX, offsetY, mapPointX, mapPointY = GetMapOverlayInfo(i);
+ if (textureName ~= "" or textureWidth == 0 or textureHeight == 0) then
+ local numTexturesWide = ceil(textureWidth/256);
+ local numTexturesTall = ceil(textureHeight/256);
+ local neededTextures = textureCount + (numTexturesWide * numTexturesTall);
+ if ( neededTextures > NUM_BATTLEFIELDMAP_OVERLAYS ) then
+ for j=NUM_BATTLEFIELDMAP_OVERLAYS+1, neededTextures do
+ BattlefieldMinimap:CreateTexture("BattlefieldMinimapOverlay"..j, "ARTWORK");
+ end
+ NUM_BATTLEFIELDMAP_OVERLAYS = neededTextures;
+ end
+ local texturePixelWidth, textureFileWidth, texturePixelHeight, textureFileHeight;
+ for j=1, numTexturesTall do
+ if ( j < numTexturesTall ) then
+ texturePixelHeight = 256;
+ textureFileHeight = 256;
+ else
+ texturePixelHeight = mod(textureHeight, 256);
+ if ( texturePixelHeight == 0 ) then
+ texturePixelHeight = 256;
+ end
+ textureFileHeight = 16;
+ while(textureFileHeight < texturePixelHeight) do
+ textureFileHeight = textureFileHeight * 2;
+ end
+ end
+ for k=1, numTexturesWide do
+ textureCount = textureCount + 1;
+ local texture = _G["BattlefieldMinimapOverlay"..textureCount];
+ if ( k < numTexturesWide ) then
+ texturePixelWidth = 256;
+ textureFileWidth = 256;
+ else
+ texturePixelWidth = mod(textureWidth, 256);
+ if ( texturePixelWidth == 0 ) then
+ texturePixelWidth = 256;
+ end
+ textureFileWidth = 16;
+ while(textureFileWidth < texturePixelWidth) do
+ textureFileWidth = textureFileWidth * 2;
+ end
+ end
+ texture:SetWidth(texturePixelWidth*battlefieldMinimapScale);
+ texture:SetHeight(texturePixelHeight*battlefieldMinimapScale);
+ texture:SetTexCoord(0, texturePixelWidth/textureFileWidth, 0, texturePixelHeight/textureFileHeight);
+ texture:SetPoint("TOPLEFT", "BattlefieldMinimap", "TOPLEFT", (offsetX + (256 * (k-1)))*battlefieldMinimapScale, -((offsetY + (256 * (j - 1)))*battlefieldMinimapScale));
+ texture:SetTexture(textureName..(((j - 1) * numTexturesWide) + k));
+ texture:SetAlpha(1 - ( BattlefieldMinimapOptions.opacity or 0 ));
+ texture:Show();
+ end
+ end
+ end
+ end
+ for i=textureCount+1, NUM_BATTLEFIELDMAP_OVERLAYS do
+ _G["BattlefieldMinimapOverlay"..i]:Hide();
+ end
+end
+
+function BattlefieldMinimap_ClearTextures()
+ for i=1, NUM_BATTLEFIELDMAP_OVERLAYS do
+ _G["BattlefieldMinimapOverlay"..i]:SetTexture(nil);
+ end
+ for i=1, NUM_WORLDMAP_DETAIL_TILES do
+ _G["BattlefieldMinimap"..i]:SetTexture(nil);
+ end
+end
+
+function BattlefieldMinimap_CreatePOI(index)
+ local frame = CreateFrame("Frame", "BattlefieldMinimapPOI"..index, BattlefieldMinimap);
+ frame:SetWidth(DEFAULT_POI_ICON_SIZE);
+ frame:SetHeight(DEFAULT_POI_ICON_SIZE);
+
+ local texture = frame:CreateTexture(frame:GetName().."Texture", "BACKGROUND");
+ texture:SetAllPoints(frame);
+ texture:SetTexture("Interface\\Minimap\\POIIcons");
+end
+
+function BattlefieldMinimap_OnUpdate(self, elapsed)
+ -- Throttle updates
+ if ( BattlefieldMinimap.updateTimer < 0 ) then
+ BattlefieldMinimap.updateTimer = BATTLEFIELD_MINIMAP_UPDATE_RATE;
+ else
+ BattlefieldMinimap.updateTimer = BattlefieldMinimap.updateTimer - elapsed;
+ end
+
+ --Position player
+ UpdateWorldMapArrowFrames();
+ local playerX, playerY = GetPlayerMapPosition("player");
+ if ( playerX == 0 and playerY == 0 ) then
+ SetMapToCurrentZone();
+ playerX, playerY = GetPlayerMapPosition("player");
+ end
+ if ( playerX == 0 and playerY == 0 ) then
+ ShowMiniWorldMapArrowFrame(nil);
+ else
+ playerX = playerX * BattlefieldMinimap:GetWidth();
+ playerY = -playerY * BattlefieldMinimap:GetHeight();
+ PositionMiniWorldMapArrowFrame("CENTER", "BattlefieldMinimap", "TOPLEFT", playerX, playerY);
+ ShowMiniWorldMapArrowFrame(1);
+ end
+
+ -- If resizing the frame then scale everything accordingly
+ if ( BattlefieldMinimap.resizing ) then
+ local sizeUnit = BattlefieldMinimap:GetWidth()/4;
+ local mapPiece;
+ for i=1, NUM_WORLDMAP_DETAIL_TILES do
+ mapPiece = _G["BattlefieldMinimap"..i];
+ mapPiece:SetWidth(sizeUnit);
+ mapPiece:SetHeight(sizeUnit);
+ end
+ local numPOIs = GetNumMapLandmarks();
+ for i=1, NUM_BATTLEFIELDMAP_POIS, 1 do
+ local battlefieldPOIName = "BattlefieldMinimapPOI"..i;
+ local battlefieldPOI = _G[battlefieldPOIName];
+ if ( i <= numPOIs ) then
+ local name, description, textureIndex, x, y, maplinkID,showInBattleMap = GetMapLandmarkInfo(i);
+ if ( showInBattleMap ) then
+ local x1, x2, y1, y2 = WorldMap_GetPOITextureCoords(textureIndex);
+ _G[battlefieldPOIName.."Texture"]:SetTexCoord(x1, x2, y1, y2);
+ x = x * BattlefieldMinimap:GetWidth();
+ y = -y * BattlefieldMinimap:GetHeight();
+ battlefieldPOI:SetPoint("CENTER", "BattlefieldMinimap", "TOPLEFT", x, y );
+ battlefieldPOI:Show();
+ else
+ battlefieldPOI:Hide();
+ end
+ else
+ battlefieldPOI:Hide();
+ end
+ end
+ end
+
+ if ( not BattlefieldMinimapOptions.showPlayers ) then
+ for i=1, MAX_PARTY_MEMBERS do
+ _G["BattlefieldMinimapParty"..i]:Hide();
+ end
+ for i=1, MAX_RAID_MEMBERS do
+ _G["BattlefieldMinimapRaid"..i]:Hide();
+ end
+ wipe(BG_VEHICLES);
+ else
+ --Position groupmates
+ local playerCount = 0;
+ if ( GetNumRaidMembers() > 0 ) then
+ for i=1, MAX_PARTY_MEMBERS do
+ local partyMemberFrame = _G["BattlefieldMinimapParty"..i];
+ partyMemberFrame:Hide();
+ end
+ for i=1, MAX_RAID_MEMBERS do
+ local unit = "raid"..i;
+ local partyX, partyY = GetPlayerMapPosition(unit);
+ local partyMemberFrame = _G["BattlefieldMinimapRaid"..(playerCount + 1)];
+ if ( (partyX ~= 0 or partyY ~= 0) and not UnitIsUnit("raid"..i, "player") ) then
+ partyX = partyX * BattlefieldMinimap:GetWidth();
+ partyY = -partyY * BattlefieldMinimap:GetHeight();
+ partyMemberFrame:SetPoint("CENTER", "BattlefieldMinimap", "TOPLEFT", partyX, partyY);
+ partyMemberFrame.name = nil;
+ partyMemberFrame.unit = unit;
+ partyMemberFrame:Show();
+ playerCount = playerCount + 1;
+ end
+ end
+ else
+ for i=1, MAX_PARTY_MEMBERS do
+ local partyX, partyY = GetPlayerMapPosition("party"..i);
+ local partyMemberFrame = _G["BattlefieldMinimapParty"..i];
+ if ( partyX == 0 and partyY == 0 ) then
+ partyMemberFrame:Hide();
+ else
+ partyX = partyX * BattlefieldMinimap:GetWidth();
+ partyY = -partyY * BattlefieldMinimap:GetHeight();
+ partyMemberFrame:SetPoint("CENTER", "BattlefieldMinimap", "TOPLEFT", partyX, partyY);
+ partyMemberFrame:Show();
+ end
+ end
+ end
+ -- Position Team Members
+ local numTeamMembers = GetNumBattlefieldPositions();
+ for i=playerCount+1, MAX_RAID_MEMBERS do
+ local partyX, partyY, name = GetBattlefieldPosition(i - playerCount);
+ local partyMemberFrame = _G["BattlefieldMinimapRaid"..i];
+ if ( partyX == 0 and partyY == 0 ) then
+ partyMemberFrame:Hide();
+ else
+ partyX = partyX * BattlefieldMinimap:GetWidth();
+ partyY = -partyY * BattlefieldMinimap:GetHeight();
+ partyMemberFrame:SetPoint("CENTER", "BattlefieldMinimap", "TOPLEFT", partyX, partyY);
+ partyMemberFrame.name = name;
+ partyMemberFrame.unit = nil;
+ partyMemberFrame:Show();
+ end
+ end
+
+ -- Position flags
+ local numFlags = GetNumBattlefieldFlagPositions();
+ for i=1, NUM_WORLDMAP_FLAGS do
+ local flagFrameName = "BattlefieldMinimapFlag"..i;
+ local flagFrame = _G[flagFrameName];
+ if ( i <= numFlags ) then
+ local flagX, flagY, flagToken = GetBattlefieldFlagPosition(i);
+ local flagTexture = _G[flagFrameName.."Texture"];
+ if ( flagX == 0 and flagY == 0 ) then
+ flagFrame:Hide();
+ else
+ flagX = flagX * BattlefieldMinimap:GetWidth();
+ flagY = -flagY * BattlefieldMinimap:GetHeight();
+ flagFrame:SetPoint("CENTER", "BattlefieldMinimap", "TOPLEFT", flagX, flagY);
+ local flagTexture = _G[flagFrameName.."Texture"];
+ flagTexture:SetTexture("Interface\\WorldStateFrame\\"..flagToken);
+ flagFrame:Show();
+ end
+ else
+ flagFrame:Hide();
+ end
+ end
+
+ -- position vehicles
+ local numVehicles = GetNumBattlefieldVehicles();
+ local totalVehicles = #BG_VEHICLES;
+ local index = 0;
+ for i=1, numVehicles do
+ if (i > totalVehicles) then
+ local vehicleName = "BattlefieldMinimap"..i;
+ BG_VEHICLES[i] = CreateFrame("FRAME", vehicleName, BattlefieldMinimap, "WorldMapVehicleTemplate");
+ BG_VEHICLES[i].texture = _G[vehicleName.."Texture"];
+ BG_VEHICLES[i]:SetWidth(30 * GetBattlefieldMapIconScale());
+ BG_VEHICLES[i]:SetHeight(30 * GetBattlefieldMapIconScale());
+ end
+ local vehicleX, vehicleY, unitName, isPossessed, vehicleType, orientation, isPlayer = GetBattlefieldVehicleInfo(i);
+ -- If vehicle has position and isn't the player
+ if ( vehicleX and not isPlayer) then
+ vehicleX = vehicleX * BattlefieldMinimap:GetWidth();
+ vehicleY = -vehicleY * BattlefieldMinimap:GetHeight();
+ BG_VEHICLES[i].texture:SetTexture(WorldMap_GetVehicleTexture(vehicleType, isPossessed));
+ BG_VEHICLES[i].texture:SetRotation( orientation );
+ BG_VEHICLES[i]:SetPoint("CENTER", "BattlefieldMinimap", "TOPLEFT", vehicleX, vehicleY);
+ BG_VEHICLES[i]:Show();
+ index = i; -- save for later
+ else
+ BG_VEHICLES[i]:Hide();
+ end
+ end
+ if (index < totalVehicles) then
+ for i=index+1, totalVehicles do
+ BG_VEHICLES[i]:Hide();
+ end
+ end
+ end
+
+ -- Fadein tab if mouse is over
+ if ( BattlefieldMinimap:IsMouseOver(45, -10, -5, 5) ) then
+ local xPos, yPos = GetCursorPosition();
+ -- If mouse is hovering don't show the tab until the elapsed time reaches the tab show delay
+ if ( BattlefieldMinimap.hover ) then
+ if ( (BattlefieldMinimap.oldX == xPos and BattlefieldMinimap.oldy == yPos) ) then
+ BattlefieldMinimap.hoverTime = BattlefieldMinimap.hoverTime + elapsed;
+ else
+ BattlefieldMinimap.hoverTime = 0;
+ BattlefieldMinimap.oldX = xPos;
+ BattlefieldMinimap.oldy = yPos;
+ end
+ if ( BattlefieldMinimap.hoverTime > BATTLEFIELD_TAB_SHOW_DELAY ) then
+ -- If the battlefieldtab's alpha is less than the current default, then fade it in
+ if ( not BattlefieldMinimap.hasBeenFaded and (BattlefieldMinimap.oldAlpha and BattlefieldMinimap.oldAlpha < DEFAULT_BATTLEFIELD_TAB_ALPHA) ) then
+ UIFrameFadeIn(BattlefieldMinimapTab, BATTLEFIELD_TAB_FADE_TIME, BattlefieldMinimap.oldAlpha, DEFAULT_BATTLEFIELD_TAB_ALPHA);
+ -- Set the fact that the chatFrame has been faded so we don't try to fade it again
+ BattlefieldMinimap.hasBeenFaded = 1;
+ end
+ end
+ else
+ -- Start hovering counter
+ BattlefieldMinimap.hover = 1;
+ BattlefieldMinimap.hoverTime = 0;
+ BattlefieldMinimap.hasBeenFaded = nil;
+ CURSOR_OLD_X, CURSOR_OLD_Y = GetCursorPosition();
+ -- Remember the oldAlpha so we can return to it later
+ if ( not BattlefieldMinimap.oldAlpha ) then
+ BattlefieldMinimap.oldAlpha = BattlefieldMinimapTab:GetAlpha();
+ end
+ end
+ else
+ -- If the tab's alpha was less than the current default, then fade it back out to the oldAlpha
+ if ( BattlefieldMinimap.hasBeenFaded and BattlefieldMinimap.oldAlpha and BattlefieldMinimap.oldAlpha < DEFAULT_BATTLEFIELD_TAB_ALPHA ) then
+ UIFrameFadeOut(BattlefieldMinimapTab, BATTLEFIELD_TAB_FADE_TIME, DEFAULT_BATTLEFIELD_TAB_ALPHA, BattlefieldMinimap.oldAlpha);
+ BattlefieldMinimap.hover = nil;
+ BattlefieldMinimap.hasBeenFaded = nil;
+ end
+ BattlefieldMinimap.hoverTime = 0;
+ end
+end
+
+
+function BattlefieldMinimapTab_OnClick(self, button)
+ PlaySound("UChatScrollButton");
+
+ -- If Rightclick bring up the options menu
+ if ( button == "RightButton" ) then
+ ToggleDropDownMenu(1, nil, BattlefieldMinimapTabDropDown, self:GetName(), 0, 0);
+ return;
+ end
+
+ -- Close all dropdowns
+ CloseDropDownMenus();
+
+ -- If frame is not locked then allow the frame to be dragged or dropped
+ if ( self:GetButtonState() == "PUSHED" ) then
+ BattlefieldMinimapTab:StopMovingOrSizing();
+ else
+ -- If locked don't allow any movement
+ if ( BattlefieldMinimapOptions.locked ) then
+ return;
+ else
+ BattlefieldMinimapTab:StartMoving();
+ end
+ end
+ ValidateFramePosition(BattlefieldMinimapTab);
+end
+
+function BattlefieldMinimapTabDropDown_Initialize()
+ local checked;
+ local info = UIDropDownMenu_CreateInfo();
+ -- Show battlefield players
+ info.text = SHOW_BATTLEFIELDMINIMAP_PLAYERS;
+ info.func = BattlefieldMinimapTabDropDown_TogglePlayers;
+ info.checked = BattlefieldMinimapOptions.showPlayers;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+
+ -- Battlefield minimap lock
+ info.text = LOCK_BATTLEFIELDMINIMAP;
+ info.func = BattlefieldMinimapTabDropDown_ToggleLock;
+ info.checked = BattlefieldMinimapOptions.locked;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+
+ -- Opacity
+ info.text = BATTLEFIELDMINIMAP_OPACITY_LABEL;
+ info.func = BattlefieldMinimapTabDropDown_ShowOpacity;
+ info.checked = nil;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+end
+
+function BattlefieldMinimapTabDropDown_TogglePlayers()
+ BattlefieldMinimapOptions.showPlayers = not BattlefieldMinimapOptions.showPlayers;
+end
+
+function BattlefieldMinimapTabDropDown_ToggleLock()
+ BattlefieldMinimapOptions.locked = not BattlefieldMinimapOptions.locked;
+end
+
+function BattlefieldMinimapTabDropDown_ShowOpacity()
+ OpacityFrame:ClearAllPoints();
+ OpacityFrame:SetPoint("TOPRIGHT", "BattlefieldMinimap", "TOPLEFT", 0, 7);
+ OpacityFrame.opacityFunc = BattlefieldMinimap_UpdateOpacity;
+ OpacityFrame:Show();
+ OpacityFrameSlider:SetValue(BattlefieldMinimapOptions.opacity);
+end
+
+function BattlefieldMinimap_UpdateOpacity(opacity)
+ BattlefieldMinimapOptions.opacity = opacity or OpacityFrameSlider:GetValue();
+ local alpha = 1.0 - BattlefieldMinimapOptions.opacity;
+ BattlefieldMinimapBackground:SetAlpha(alpha);
+ for i=1, NUM_WORLDMAP_DETAIL_TILES do
+ _G["BattlefieldMinimap"..i]:SetAlpha(alpha);
+ end
+ if ( alpha >= 0.15 ) then
+ alpha = alpha - 0.15;
+ end
+ for i=1, NUM_BATTLEFIELDMAP_OVERLAYS do
+ _G["BattlefieldMinimapOverlay"..i]:SetAlpha(alpha);
+ end
+ BattlefieldMinimapCloseButton:SetAlpha(alpha);
+ BattlefieldMinimapCorner:SetAlpha(alpha);
+end
+
+
+function BattlefieldMinimapUnit_OnEnter(self, motion)
+ -- Adjust the tooltip based on which side the unit button is on
+ local x, y = self:GetCenter();
+ local parentX, parentY = self:GetParent():GetCenter();
+ if ( x > parentX ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+
+ -- See which POI's are in the same region and include their names in the tooltip
+ local unitButton;
+ local newLineString = "";
+ local tooltipText = "";
+
+ -- Check party
+ for i=1, MAX_PARTY_MEMBERS do
+ unitButton = _G["BattlefieldMinimapParty"..i];
+ if ( unitButton:IsVisible() and unitButton:IsMouseOver() ) then
+ if ( PlayerIsPVPInactive(unitButton.unit) ) then
+ tooltipText = tooltipText..newLineString..format(PLAYER_IS_PVP_AFK, UnitName(unitButton.unit));
+ else
+ tooltipText = tooltipText..newLineString..UnitName(unitButton.unit);
+ end
+ newLineString = "\n";
+ end
+ end
+ --Check Raid
+ for i=1, MAX_RAID_MEMBERS do
+ unitButton = _G["BattlefieldMinimapRaid"..i];
+ if ( unitButton:IsVisible() and unitButton:IsMouseOver() ) then
+ -- Handle players not in your raid or party, but on your team
+ if ( unitButton.name ) then
+ if ( PlayerIsPVPInactive(unitButton.name) ) then
+ tooltipText = tooltipText..newLineString..format(PLAYER_IS_PVP_AFK, unitButton.name);
+ else
+ tooltipText = tooltipText..newLineString..unitButton.name;
+ end
+ else
+ if ( PlayerIsPVPInactive(unitButton.unit) ) then
+ tooltipText = tooltipText..newLineString..format(PLAYER_IS_PVP_AFK, UnitName(unitButton.unit));
+ else
+ tooltipText = tooltipText..newLineString..UnitName(unitButton.unit);
+ end
+ end
+ newLineString = "\n";
+ end
+ end
+ GameTooltip:SetText(tooltipText);
+ GameTooltip:Show();
+end
diff --git a/reference/AddOns/Blizzard_BattlefieldMinimap/Blizzard_BattlefieldMinimap.toc b/reference/AddOns/Blizzard_BattlefieldMinimap/Blizzard_BattlefieldMinimap.toc
new file mode 100644
index 0000000..07d4e59
--- /dev/null
+++ b/reference/AddOns/Blizzard_BattlefieldMinimap/Blizzard_BattlefieldMinimap.toc
@@ -0,0 +1,7 @@
+## Interface: 30300
+## Title: Blizzard Battlefield Minimap
+## Secure: 1
+## LoadOnDemand: 1
+## SavedVariablesPerCharacter: BattlefieldMinimapOptions
+Blizzard_BattlefieldMinimap.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_BattlefieldMinimap/Blizzard_BattlefieldMinimap.xml b/reference/AddOns/Blizzard_BattlefieldMinimap/Blizzard_BattlefieldMinimap.xml
new file mode 100644
index 0000000..8a86b2e
--- /dev/null
+++ b/reference/AddOns/Blizzard_BattlefieldMinimap/Blizzard_BattlefieldMinimap.xml
@@ -0,0 +1,428 @@
+
+
+
+
+
+
+
+
+ BattlefieldMinimapUnit_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+ WorldMapUnit_OnMouseUp(self, button, "BattlefieldMinimapRaid", "BattlefieldMinimapParty");
+
+
+
+
+
+
+ WorldMapUnit_OnLoad(self);
+ self.unit = "party"..self:GetID();
+
+
+
+
+
+
+ WorldMapUnit_OnLoad(self);
+ self.unit = "raid"..self:GetID();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonUp");
+ self:RegisterForDrag("LeftButton");
+ BattlefieldMinimapTab:SetAlpha(0);
+
+
+ PanelTemplates_TabResize(self, 0);
+
+
+ BattlefieldMinimapTab_OnClick(self, button);
+
+
+ GameTooltip_AddNewbieTip(self, BATTLEFIELDMINIMAP_OPTIONS_LABEL, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_BATTLEFIELDMINIMAP_OPTIONS, 1);
+
+
+
+ if ( BattlefieldMinimapOptions.locked ) then
+ return;
+ end
+ BattlefieldMinimapTab:StartMoving();
+
+
+ BattlefieldMinimapTab:StopMovingOrSizing();
+ ValidateFramePosition(BattlefieldMinimapTab);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SetCVar("showBattlefieldMinimap", "0");
+ HideUIPanel(self:GetParent());
+ WorldMapZoneMinimapDropDown_Update();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_BattlefieldMinimap/Localization.lua b/reference/AddOns/Blizzard_BattlefieldMinimap/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_BattlefieldMinimap/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_BindingUI/Blizzard_BindingUI.lua b/reference/AddOns/Blizzard_BindingUI/Blizzard_BindingUI.lua
new file mode 100644
index 0000000..d55c2bf
--- /dev/null
+++ b/reference/AddOns/Blizzard_BindingUI/Blizzard_BindingUI.lua
@@ -0,0 +1,354 @@
+KEY_BINDINGS_DISPLAYED = 17;
+KEY_BINDING_HEIGHT = 25;
+
+DEFAULT_BINDINGS = 0;
+ACCOUNT_BINDINGS = 1;
+CHARACTER_BINDINGS = 2;
+
+UIPanelWindows["KeyBindingFrame"] = { area = "center", pushable = 0, whileDead = 1 };
+
+StaticPopupDialogs["CONFIRM_DELETING_CHARACTER_SPECIFIC_BINDINGS"] = {
+ text = CONFIRM_DELETING_CHARACTER_SPECIFIC_BINDINGS,
+ button1 = OKAY,
+ button2 = CANCEL,
+ OnAccept = function(self)
+ SaveBindings(KeyBindingFrame.which);
+ KeyBindingFrameOutputText:SetText("");
+ KeyBindingFrame_SetSelected(nil);
+ HideUIPanel(KeyBindingFrame);
+ CONFIRMED_DELETING_CHARACTER_SPECIFIC_BINDINGS = 1;
+ end,
+ timeout = 0,
+ whileDead = 1,
+ showAlert = 1,
+};
+
+StaticPopupDialogs["CONFIRM_LOSE_BINDING_CHANGES"] = {
+ text = CONFIRM_LOSE_BINDING_CHANGES,
+ button1 = OKAY,
+ button2 = CANCEL,
+ OnAccept = function(self)
+ KeyBindingFrame_ChangeBindingProfile();
+ KeyBindingFrame.bindingsChanged = nil;
+ end,
+ OnCancel = function(self)
+ if ( KeyBindingFrameCharacterButton:GetChecked() ) then
+ KeyBindingFrameCharacterButton:SetChecked();
+ else
+ KeyBindingFrameCharacterButton:SetChecked(1);
+ end
+ end,
+ timeout = 0,
+ whileDead = 1,
+ showAlert = 1,
+};
+
+function KeyBindingFrame_OnLoad(self)
+ self:RegisterForClicks("AnyUp");
+ KeyBindingFrame_SetSelected(nil);
+end
+
+function KeyBindingFrame_OnShow()
+ KeyBindingFrame_Update();
+
+ -- Update character button
+ KeyBindingFrameCharacterButton:SetChecked(GetCurrentBindingSet() == 2);
+ -- Update header text
+ if ( KeyBindingFrameCharacterButton:GetChecked() ) then
+ KeyBindingFrameHeaderText:SetFormattedText(CHARACTER_KEY_BINDINGS, UnitName("player"));
+ else
+ KeyBindingFrameHeaderText:SetText(KEY_BINDINGS);
+ end
+
+ -- Reset bindingsChanged
+ KeyBindingFrame.bindingsChanged = nil;
+end
+
+function KeyBindingFrame_Update()
+ local numBindings = GetNumBindings();
+ local keyOffset;
+ local keyBindingButton1, keyBindingButton2, commandName, binding1, binding2;
+ local keyBindingName, keyBindingDescription;
+ local keyBindingButton1NormalTexture, keyBindingButton1PushedTexture, keyBindingButton2NormalTexture, keyBindingButton2PushedTexture;
+ for i=1, KEY_BINDINGS_DISPLAYED, 1 do
+ keyOffset = FauxScrollFrame_GetOffset(KeyBindingFrameScrollFrame) + i;
+ if ( keyOffset <= numBindings) then
+ keyBindingButton1 = _G["KeyBindingFrameBinding"..i.."Key1Button"];
+ keyBindingButton1NormalTexture = _G["KeyBindingFrameBinding"..i.."Key1ButtonNormalTexture"];
+ keyBindingButton1PushedTexture = _G["KeyBindingFrameBinding"..i.."Key1ButtonPushedTexture"];
+ keyBindingButton2NormalTexture = _G["KeyBindingFrameBinding"..i.."Key2ButtonNormalTexture"];
+ keyBindingButton2PushedTexture = _G["KeyBindingFrameBinding"..i.."Key2ButtonPushedTexture"];
+ keyBindingButton2 = _G["KeyBindingFrameBinding"..i.."Key2Button"];
+ keyBindingDescription = _G["KeyBindingFrameBinding"..i.."Description"];
+ -- Set binding text
+ commandName, binding1, binding2 = GetBinding(keyOffset, KeyBindingFrame.mode);
+ -- Handle header
+ local headerText = _G["KeyBindingFrameBinding"..i.."Header"];
+ if ( strsub(commandName, 1, 6) == "HEADER" ) then
+ headerText:SetText(_G["BINDING_"..commandName]);
+ headerText:Show();
+ keyBindingButton1:Hide();
+ keyBindingButton2:Hide();
+ keyBindingDescription:Hide();
+ else
+ headerText:Hide();
+ keyBindingButton1:Show();
+ keyBindingButton2:Show();
+ keyBindingDescription:Show();
+ keyBindingButton1.commandName = commandName;
+ keyBindingButton2.commandName = commandName;
+ if ( binding1 ) then
+ keyBindingButton1:SetText(GetBindingText(binding1, "KEY_"));
+ keyBindingButton1:SetAlpha(1);
+ else
+ keyBindingButton1:SetText(NORMAL_FONT_COLOR_CODE..NOT_BOUND..FONT_COLOR_CODE_CLOSE);
+ keyBindingButton1:SetAlpha(0.8);
+ end
+ if ( binding2 ) then
+ keyBindingButton2:SetText(GetBindingText(binding2, "KEY_"));
+ keyBindingButton2:SetAlpha(1);
+ else
+ keyBindingButton2:SetText(NORMAL_FONT_COLOR_CODE..NOT_BOUND..FONT_COLOR_CODE_CLOSE);
+ keyBindingButton2:SetAlpha(0.8);
+ end
+ -- Set description
+ keyBindingDescription:SetText(GetBindingText(commandName, "BINDING_NAME_"));
+ -- Handle highlight
+ keyBindingButton1:UnlockHighlight();
+ keyBindingButton2:UnlockHighlight();
+ if ( KeyBindingFrame.selected == commandName ) then
+ if ( KeyBindingFrame.keyID == 1 ) then
+ keyBindingButton1:LockHighlight();
+ else
+ keyBindingButton2:LockHighlight();
+ end
+ end
+ _G["KeyBindingFrameBinding"..i]:Show();
+ end
+ else
+ _G["KeyBindingFrameBinding"..i]:Hide();
+ end
+ end
+
+ -- Scroll frame stuff
+ FauxScrollFrame_Update(KeyBindingFrameScrollFrame, numBindings, KEY_BINDINGS_DISPLAYED, KEY_BINDING_HEIGHT );
+
+ -- Update Unbindkey button
+ KeyBindingFrame_UpdateUnbindKey();
+end
+
+function KeyBindingFrame_UnbindKey(keyPressed)
+ local oldAction = GetBindingAction(keyPressed, KeyBindingFrame.mode);
+ if ( oldAction ~= "" and oldAction ~= KeyBindingFrame.selected ) then
+ local key1, key2 = GetBindingKey(oldAction, KeyBindingFrame.mode);
+ if ( (not key1 or key1 == keyPressed) and (not key2 or key2 == keyPressed) ) then
+ --Error message
+ KeyBindingFrameOutputText:SetFormattedText(KEY_UNBOUND_ERROR, GetBindingText(oldAction, "BINDING_NAME_"));
+ end
+ end
+ SetBinding(keyPressed, nil, KeyBindingFrame.mode);
+end
+
+function KeyBindingFrame_OnKeyDown(self, keyOrButton)
+ if ( GetBindingFromClick(keyOrButton) == "SCREENSHOT" ) then
+ RunBinding("SCREENSHOT");
+ return;
+ end
+
+ if ( KeyBindingFrame.selected ) then
+ local keyPressed = keyOrButton;
+
+ if ( keyPressed == "UNKNOWN" ) then
+ return;
+ end
+
+ -- Convert the mouse button names
+ if ( keyPressed == "LeftButton" ) then
+ keyPressed = "BUTTON1";
+ elseif ( keyPressed == "RightButton" ) then
+ keyPressed = "BUTTON2";
+ elseif ( keyPressed == "MiddleButton" ) then
+ keyPressed = "BUTTON3";
+ elseif ( keyPressed == "Button4" ) then
+ keyPressed = "BUTTON4"
+ elseif ( keyOrButton == "Button5" ) then
+ keyPressed = "BUTTON5"
+ elseif ( keyPressed == "Button6" ) then
+ keyPressed = "BUTTON6"
+ elseif ( keyOrButton == "Button7" ) then
+ keyPressed = "BUTTON7"
+ elseif ( keyPressed == "Button8" ) then
+ keyPressed = "BUTTON8"
+ elseif ( keyOrButton == "Button9" ) then
+ keyPressed = "BUTTON9"
+ elseif ( keyPressed == "Button10" ) then
+ keyPressed = "BUTTON10"
+ elseif ( keyOrButton == "Button11" ) then
+ keyPressed = "BUTTON11"
+ elseif ( keyPressed == "Button12" ) then
+ keyPressed = "BUTTON12"
+ elseif ( keyOrButton == "Button13" ) then
+ keyPressed = "BUTTON13"
+ elseif ( keyPressed == "Button14" ) then
+ keyPressed = "BUTTON14"
+ elseif ( keyOrButton == "Button15" ) then
+ keyPressed = "BUTTON15"
+ elseif ( keyPressed == "Button16" ) then
+ keyPressed = "BUTTON16"
+ elseif ( keyOrButton == "Button17" ) then
+ keyPressed = "BUTTON17"
+ elseif ( keyPressed == "Button18" ) then
+ keyPressed = "BUTTON18"
+ elseif ( keyOrButton == "Button19" ) then
+ keyPressed = "BUTTON19"
+ elseif ( keyPressed == "Button20" ) then
+ keyPressed = "BUTTON20"
+ elseif ( keyOrButton == "Button21" ) then
+ keyPressed = "BUTTON21"
+ elseif ( keyPressed == "Button22" ) then
+ keyPressed = "BUTTON22"
+ elseif ( keyOrButton == "Button23" ) then
+ keyPressed = "BUTTON23"
+ elseif ( keyPressed == "Button24" ) then
+ keyPressed = "BUTTON24"
+ elseif ( keyOrButton == "Button25" ) then
+ keyPressed = "BUTTON25"
+ elseif ( keyPressed == "Button26" ) then
+ keyPressed = "BUTTON26"
+ elseif ( keyOrButton == "Button27" ) then
+ keyPressed = "BUTTON27"
+ elseif ( keyPressed == "Button28" ) then
+ keyPressed = "BUTTON28"
+ elseif ( keyOrButton == "Button29" ) then
+ keyPressed = "BUTTON29"
+ elseif ( keyPressed == "Button30" ) then
+ keyPressed = "BUTTON30"
+ elseif ( keyOrButton == "Button31" ) then
+ keyPressed = "BUTTON31"
+ end
+ if ( keyPressed == "BUTTON1" or keyPressed == "BUTTON2" ) then
+ return;
+ end
+
+ if ( keyPressed == "LSHIFT" or
+ keyPressed == "RSHIFT" or
+ keyPressed == "LCTRL" or
+ keyPressed == "RCTRL" or
+ keyPressed == "LALT" or
+ keyPressed == "RALT" ) then
+ return;
+ end
+ if ( IsShiftKeyDown() ) then
+ keyPressed = "SHIFT-"..keyPressed;
+ end
+ if ( IsControlKeyDown() ) then
+ keyPressed = "CTRL-"..keyPressed;
+ end
+ if ( IsAltKeyDown() ) then
+ keyPressed = "ALT-"..keyPressed;
+ end
+
+ -- Unbind the current action
+ local key1, key2 = GetBindingKey(KeyBindingFrame.selected, KeyBindingFrame.mode);
+ if ( key1 ) then
+ SetBinding(key1, nil, KeyBindingFrame.mode);
+ end
+ if ( key2 ) then
+ SetBinding(key2, nil, KeyBindingFrame.mode);
+ end
+ -- Unbind the current key and rebind current action
+ KeyBindingFrameOutputText:SetText(KEY_BOUND);
+ KeyBindingFrame_UnbindKey(keyPressed);
+ if ( KeyBindingFrame.keyID == 1 ) then
+ KeyBindingFrame_SetBinding(keyPressed, KeyBindingFrame.selected, key1);
+ if ( key2 ) then
+ SetBinding(key2, KeyBindingFrame.selected, KeyBindingFrame.mode);
+ end
+ else
+ if ( key1 ) then
+ KeyBindingFrame_SetBinding(key1, KeyBindingFrame.selected);
+ end
+ KeyBindingFrame_SetBinding(keyPressed, KeyBindingFrame.selected, key2);
+ end
+ KeyBindingFrame_Update();
+ -- Button highlighting stuff
+ KeyBindingFrame_SetSelected(nil);
+ KeyBindingFrame.buttonPressed:UnlockHighlight();
+ KeyBindingFrame.bindingsChanged = 1;
+ elseif ( GetBindingFromClick(keyOrButton) == "TOGGLEGAMEMENU" ) then
+ LoadBindings(GetCurrentBindingSet());
+ KeyBindingFrameOutputText:SetText("");
+ KeyBindingFrame_SetSelected(nil);
+ HideUIPanel(self);
+ end
+ KeyBindingFrame_UpdateUnbindKey();
+end
+
+function KeyBindingButton_OnClick(self, button)
+ if ( KeyBindingFrame.selected ) then
+ -- Code to be able to deselect or select another key to bind
+ if ( button == "LeftButton" or button == "RightButton" ) then
+ -- Deselect button if it was the pressed previously pressed
+ if (KeyBindingFrame.buttonPressed == self) then
+ KeyBindingFrame_SetSelected(nil);
+ KeyBindingFrameOutputText:SetText("");
+ else
+ -- Select a different button
+ KeyBindingFrame.buttonPressed = self;
+ KeyBindingFrame_SetSelected(self.commandName);
+ KeyBindingFrame.keyID = self:GetID();
+ KeyBindingFrameOutputText:SetFormattedText(BIND_KEY_TO_COMMAND, GetBindingText(self.commandName, "BINDING_NAME_"));
+ end
+ KeyBindingFrame_Update();
+ return;
+ end
+ KeyBindingFrame_OnKeyDown(self, button);
+ else
+ if (KeyBindingFrame.buttonPressed) then
+ KeyBindingFrame.buttonPressed:UnlockHighlight();
+ end
+ KeyBindingFrame.buttonPressed = self;
+ KeyBindingFrame_SetSelected(self.commandName);
+ KeyBindingFrame.keyID = self:GetID();
+ KeyBindingFrameOutputText:SetFormattedText(BIND_KEY_TO_COMMAND, GetBindingText(self.commandName, "BINDING_NAME_"));
+ KeyBindingFrame_Update();
+ end
+ KeyBindingFrame_UpdateUnbindKey();
+end
+
+function KeyBindingFrame_SetBinding(key, selectedBinding, oldKey)
+ if ( SetBinding(key, selectedBinding, KeyBindingFrame.mode) ) then
+ return;
+ else
+ if ( oldKey ) then
+ SetBinding(oldKey, selectedBinding, KeyBindingFrame.mode);
+ end
+ --Error message
+ KeyBindingFrameOutputText:SetText(KEYBINDINGFRAME_MOUSEWHEEL_ERROR);
+ end
+end
+
+function KeyBindingFrame_UpdateUnbindKey()
+ if ( KeyBindingFrame.selected ) then
+ KeyBindingFrameUnbindButton:Enable();
+ else
+ KeyBindingFrameUnbindButton:Disable();
+ end
+end
+
+function KeyBindingFrame_ChangeBindingProfile()
+ if ( KeyBindingFrameCharacterButton:GetChecked() ) then
+ LoadBindings(CHARACTER_BINDINGS);
+ KeyBindingFrameHeaderText:SetFormattedText(CHARACTER_KEY_BINDINGS, UnitName("player"));
+ else
+ LoadBindings(ACCOUNT_BINDINGS);
+ KeyBindingFrameHeaderText:SetText(KEY_BINDINGS);
+ end
+ KeyBindingFrameOutputText:SetText("");
+ KeyBindingFrame_SetSelected(nil);
+ KeyBindingFrame_Update();
+end
+
+function KeyBindingFrame_SetSelected(value)
+ KeyBindingFrame.selected = value;
+end
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_BindingUI/Blizzard_BindingUI.toc b/reference/AddOns/Blizzard_BindingUI/Blizzard_BindingUI.toc
new file mode 100644
index 0000000..858cce5
--- /dev/null
+++ b/reference/AddOns/Blizzard_BindingUI/Blizzard_BindingUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard Key Binding UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_BindingUI.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_BindingUI/Blizzard_BindingUI.xml b/reference/AddOns/Blizzard_BindingUI/Blizzard_BindingUI.xml
new file mode 100644
index 0000000..efd8a09
--- /dev/null
+++ b/reference/AddOns/Blizzard_BindingUI/Blizzard_BindingUI.xml
@@ -0,0 +1,553 @@
+
+
+
+
+
+ KeyBindingButton_OnClick(self, button, down);
+
+
+ self:RegisterForClicks("AnyUp");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, KEY_BINDING_HEIGHT, KeyBindingFrame_Update);
+
+
+ if ( KeyBindingFrame.selected ) then
+ if ( delta > 0 ) then
+ KeyBindingFrame_OnKeyDown(self, "MOUSEWHEELUP");
+ else
+ KeyBindingFrame_OnKeyDown(self, "MOUSEWHEELDOWN");
+ end
+ else
+ ScrollFrameTemplate_OnMouseWheel(self, delta);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KeyBindingFrameCharacterButtonText:SetText(HIGHLIGHT_FONT_COLOR_CODE..CHARACTER_SPECIFIC_KEYBINDINGS..FONT_COLOR_CODE_CLOSE);
+
+
+ if ( KeyBindingFrame.bindingsChanged ) then
+ StaticPopup_Show("CONFIRM_LOSE_BINDING_CHANGES");
+ else
+ KeyBindingFrame_ChangeBindingProfile();
+ end
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP, nil, nil, nil, nil, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadBindings(DEFAULT_BINDINGS);
+ KeyBindingFrameOutputText:SetText("");
+ KeyBindingFrame_SetSelected(nil);
+ KeyBindingFrame_Update();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadBindings(GetCurrentBindingSet());
+ KeyBindingFrameOutputText:SetText("");
+ KeyBindingFrame_SetSelected(nil);
+ HideUIPanel(KeyBindingFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( KeyBindingFrameCharacterButton:GetChecked() ) then
+ KeyBindingFrame.which = CHARACTER_BINDINGS;
+ else
+ KeyBindingFrame.which = ACCOUNT_BINDINGS;
+ if ( GetCurrentBindingSet() == CHARACTER_BINDINGS ) then
+ if ( not CONFIRMED_DELETING_CHARACTER_SPECIFIC_BINDINGS ) then
+ StaticPopup_Show("CONFIRM_DELETING_CHARACTER_SPECIFIC_BINDINGS");
+ return;
+ end
+ end
+ end
+ SaveBindings(KeyBindingFrame.which);
+ KeyBindingFrameOutputText:SetText("");
+ KeyBindingFrame_SetSelected(nil);
+ HideUIPanel(KeyBindingFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local key1, key2 = GetBindingKey(KeyBindingFrame.selected, KeyBindingFrame.mode);
+ if ( key1 ) then
+ SetBinding(key1, nil, KeyBindingFrame.mode);
+ end
+ if ( key2 ) then
+ SetBinding(key2, nil, KeyBindingFrame.mode);
+ end
+ if ( key1 and KeyBindingFrame.keyID == 1 ) then
+ KeyBindingFrame_SetBinding(key1, nil, key1);
+ if ( key2 ) then
+ SetBinding(key2, KeyBindingFrame.selected, KeyBindingFrame.mode);
+ end
+ else
+ if ( key1 ) then
+ KeyBindingFrame_SetBinding(key1, KeyBindingFrame.selected);
+ end
+ if ( key2 ) then
+ KeyBindingFrame_SetBinding(key2, nil, key2);
+ end
+ end
+ KeyBindingFrame_Update();
+ -- Button highlighting stuff
+ KeyBindingFrame_SetSelected(nil);
+ KeyBindingFrame.buttonPressed:UnlockHighlight();
+ KeyBindingFrame_UpdateUnbindKey();
+ KeyBindingFrameOutputText:SetText();
+
+
+
+
+
+
+
+
+
+ KeyBindingFrame_OnShow(self);
+ Disable_BagButtons();
+ UpdateMicroButtons();
+
+
+ KeyBindingFrameOutputText:SetText("");
+ PlaySound("gsTitleOptionExit");
+ ShowUIPanel(GameMenuFrame);
+ UpdateMicroButtons();
+
+
+
+
diff --git a/reference/AddOns/Blizzard_BindingUI/Localization.lua b/reference/AddOns/Blizzard_BindingUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_BindingUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_Calendar/Blizzard_Calendar.lua b/reference/AddOns/Blizzard_Calendar/Blizzard_Calendar.lua
new file mode 100644
index 0000000..3967947
--- /dev/null
+++ b/reference/AddOns/Blizzard_Calendar/Blizzard_Calendar.lua
@@ -0,0 +1,5425 @@
+
+-- static popups
+StaticPopupDialogs["CALENDAR_DELETE_EVENT"] = {
+ text = "%s",
+ button1 = OKAY,
+ button2 = CANCEL,
+ whileDead = 1,
+ OnAccept = function (self)
+ CalendarContextEventRemove();
+ end,
+ OnShow = function (self)
+ CalendarFrame_PushModal(self);
+ end,
+ OnHide = function (self)
+ CalendarFrame_PopModal();
+ end,
+ timeout = 0,
+ hideOnEscape = 1,
+ enterClicksFirstButton = 1,
+};
+StaticPopupDialogs["CALENDAR_ERROR"] = {
+ text = CALENDAR_ERROR,
+ button1 = OKAY,
+ whileDead = 1,
+ OnShow = function (self)
+ --CalendarFrame_PushModal(self);
+ end,
+ OnHide = function (self)
+ --CalendarFrame_PopModal();
+ end,
+ timeout = 0,
+ showAlert = 1,
+ hideOnEscape = 1,
+ enterClicksFirstButton = 1,
+};
+
+
+-- UIParent integration
+tinsert(UIMenus, "CalendarContextMenu");
+UIPanelWindows["CalendarFrame"] = { area = "doublewide", pushable = 0, width = 840, whileDead = 1, yOffset = 20 };
+
+-- CalendarMenus is an ORDERED table of frames, one of which will close when you press Escape.
+local CalendarMenus = {
+ "CalendarEventPickerFrame",
+ "CalendarTexturePickerFrame",
+ "CalendarMassInviteFrame",
+ "CalendarCreateEventFrame",
+ "CalendarViewEventFrame",
+ "CalendarViewHolidayFrame",
+ "CalendarViewRaidFrame"
+};
+-- this function will attempt to close the first open menu in the CalendarMenus table
+function CloseCalendarMenus()
+ for _, menuName in next, CalendarMenus do
+ local menu = _G[menuName];
+ if ( menu and menu:IsShown() ) then
+ if ( menu == CalendarFrame_GetEventFrame() ) then
+ CalendarFrame_CloseEvent();
+ PlaySound("igMainMenuQuit");
+ else
+ menu:Hide();
+ end
+ return true;
+ end
+ end
+ return false;
+end
+
+
+-- tab handling
+CALENDAR_CREATEEVENTFRAME_TAB_LIST = {
+ "CalendarCreateEventTitleEdit",
+ "CalendarCreateEventDescriptionEdit",
+ "CalendarCreateEventInviteEdit",
+};
+
+
+-- speed optimizations
+local next = next;
+local date = date;
+local abs = abs;
+local min = min;
+local max = max;
+local floor = floor;
+local mod = mod;
+local tonumber = tonumber;
+local random = random;
+local format = format;
+local select = select;
+local tinsert = tinsert;
+local band = bit.band;
+local cos = math.cos;
+local strtrim = strtrim;
+local GetCVarBool = GetCVarBool;
+local PI = PI;
+local TWOPI = PI * 2.0;
+
+-- dev constants
+CALENDAR_USE_SEQUENCE_FOR_EVENT_TEXTURE = true;
+CALENDAR_USE_SEQUENCE_FOR_OVERLAY_TEXTURE = false;
+
+-- local constants
+local CALENDAR_MAX_DAYS_PER_MONTH = 42; -- 6 weeks
+local CALENDAR_MAX_DARKDAYS_PER_MONTH = 14; -- max days from the previous and next months when viewing the current month
+
+-- Weekday constants
+local CALENDAR_WEEKDAY_NORMALIZED_TEX_LEFT = 0.0;
+local CALENDAR_WEEKDAY_NORMALIZED_TEX_TOP = 180 / 256;
+local CALENDAR_WEEKDAY_NORMALIZED_TEX_WIDTH = 90 / 256 - 0.001; -- fudge factor to prevent texture seams
+local CALENDAR_WEEKDAY_NORMALIZED_TEX_HEIGHT = 28 / 256 - 0.001; -- fudge factor to prevent texture seams
+
+-- DayButton constants
+local CALENDAR_DAYBUTTON_NORMALIZED_TEX_WIDTH = 90 / 256 - 0.001; -- fudge factor to prevent texture seams
+local CALENDAR_DAYBUTTON_NORMALIZED_TEX_HEIGHT = 90 / 256 - 0.001; -- fudge factor to prevent texture seams
+local CALENDAR_DAYBUTTON_MAX_VISIBLE_EVENTS = 4;
+local CALENDAR_DAYBUTTON_MAX_VISIBLE_BIGEVENTS = 2;
+local CALENDAR_DAYBUTTON_MAX_TOOLTIP_EVENTS = 30;
+local CALENDAR_DAYBUTTON_SELECTION_ALPHA = 1.0;
+local CALENDAR_DAYBUTTON_HIGHLIGHT_ALPHA = 0.5;
+
+-- DayEventButton constants
+local CALENDAR_DAYEVENTBUTTON_HEIGHT = 12;
+local CALENDAR_DAYEVENTBUTTON_BIGHEIGHT = 24;
+local CALENDAR_DAYEVENTBUTTON_XOFFSET = 4;
+local CALENDAR_DAYEVENTBUTTON_YOFFSET = -3;
+
+-- ContextMenu flags
+local CALENDAR_CONTEXTMENU_FLAG_SHOWDAY = 0x01;
+local CALENDAR_CONTEXTMENU_FLAG_SHOWEVENT = 0x02;
+
+-- CreateEventFrame constants
+local CALENDAR_CREATEEVENTFRAME_DEFAULT_TITLE = CALENDAR_EVENT_NAME;
+local CALENDAR_CREATEEVENTFRAME_DEFAULT_DESCRIPTION = CALENDAR_EVENT_DESCRIPTION;
+local CALENDAR_CREATEEVENTFRAME_DEFAULT_TYPE = CALENDAR_EVENTTYPE_OTHER;
+local CALENDAR_CREATEEVENTFRAME_DEFAULT_REPEAT_OPTION = 1;
+local CALENDAR_CREATEEVENTFRAME_DEFAULT_HOUR = 12; -- default is standard (not military) time
+local CALENDAR_CREATEEVENTFRAME_DEFAULT_MINUTE = 0;
+local CALENDAR_CREATEEVENTFRAME_DEFAULT_AM = true;
+local CALENDAR_CREATEEVENTFRAME_DEFAULT_AUTOAPPROVE = nil;
+local CALENDAR_CREATEEVENTFRAME_DEFAULT_LOCK = nil;
+
+-- ViewEventFrame constants
+local CALENDAR_VIEWEVENTFRAME_EVENT_RSVPBUTTON_WIDTH = 128;
+local CALENDAR_VIEWEVENTFRAME_GUILDEVENT_RSVPBUTTON_WIDTH = 94;
+local CALENDAR_VIEWEVENTFRAME_EVENT_INVITELIST_HEIGHT = 230;
+local CALENDAR_VIEWEVENTFRAME_GUILDEVENT_INVITELIST_HEIGHT = 250;
+
+-- dark flags
+local DARKFLAG_PREVMONTH = 0x0001;
+local DARKFLAG_NEXTMONTH = 0x0002;
+local DARKFLAG_CORNER = 0x0004;
+local DARKFLAG_SIDE_LEFT = 0x0008;
+local DARKFLAG_SIDE_RIGHT = 0x0010;
+local DARKFLAG_SIDE_TOP = 0x0020;
+local DARKFLAG_SIDE_BOTTOM = 0x0040;
+-- top flags
+local DARKFLAG_PREVMONTH_TOP = DARKFLAG_PREVMONTH + DARKFLAG_SIDE_TOP;
+local DARKFLAG_PREVMONTH_TOPLEFT = DARKFLAG_PREVMONTH_TOP + DARKFLAG_SIDE_LEFT;
+local DARKFLAG_PREVMONTH_TOPRIGHT = DARKFLAG_PREVMONTH_TOP + DARKFLAG_SIDE_RIGHT;
+local DARKFLAG_PREVMONTH_TOPLEFTRIGHT = DARKFLAG_PREVMONTH_TOPLEFT + DARKFLAG_SIDE_RIGHT;
+local DARKFLAG_NEXTMONTH_TOP = DARKFLAG_NEXTMONTH + DARKFLAG_SIDE_TOP;
+local DARKFLAG_NEXTMONTH_TOPLEFT = DARKFLAG_NEXTMONTH_TOP + DARKFLAG_SIDE_LEFT;
+local DARKFLAG_NEXTMONTH_TOPRIGHT = DARKFLAG_NEXTMONTH_TOP + DARKFLAG_SIDE_RIGHT;
+-- corner flags
+local DARKFLAG_NEXTMONTH_CORNER = DARKFLAG_NEXTMONTH + DARKFLAG_CORNER; -- day 8 of next month
+local DARKFLAG_NEXTMONTH_CORNER_TOP = DARKFLAG_NEXTMONTH_CORNER + DARKFLAG_SIDE_TOP; -- day 7 of next month
+local DARKFLAG_NEXTMONTH_CORNER_RIGHT = DARKFLAG_NEXTMONTH_CORNER + DARKFLAG_SIDE_RIGHT; -- day 8 of next month, index 42
+local DARKFLAG_NEXTMONTH_CORNER_TOPLEFT = DARKFLAG_NEXTMONTH_CORNER_TOP + DARKFLAG_SIDE_LEFT; -- day 1 of next month
+local DARKFLAG_NEXTMONTH_CORNER_TOPLEFTRIGHT = DARKFLAG_NEXTMONTH_CORNER_TOPLEFT + DARKFLAG_SIDE_RIGHT; -- day 1 of next month, 7th day of the week
+-- bottom flags
+local DARKFLAG_PREVMONTH_BOTTOM = DARKFLAG_PREVMONTH + DARKFLAG_SIDE_BOTTOM;
+local DARKFLAG_PREVMONTH_BOTTOMLEFT = DARKFLAG_PREVMONTH_BOTTOM + DARKFLAG_SIDE_LEFT;
+local DARKFLAG_PREVMONTH_BOTTOMRIGHT = DARKFLAG_PREVMONTH_BOTTOM + DARKFLAG_SIDE_RIGHT;
+local DARKFLAG_PREVMONTH_BOTTOMLEFTRIGHT = DARKFLAG_PREVMONTH_BOTTOMLEFT + DARKFLAG_SIDE_RIGHT;
+local DARKFLAG_NEXTMONTH_BOTTOM = DARKFLAG_NEXTMONTH + DARKFLAG_SIDE_BOTTOM;
+local DARKFLAG_NEXTMONTH_BOTTOMLEFT = DARKFLAG_NEXTMONTH_BOTTOM + DARKFLAG_SIDE_LEFT;
+local DARKFLAG_NEXTMONTH_BOTTOMRIGHT = DARKFLAG_NEXTMONTH_BOTTOM + DARKFLAG_SIDE_RIGHT;
+local DARKFLAG_NEXTMONTH_BOTTOMLEFTRIGHT = DARKFLAG_NEXTMONTH_BOTTOMLEFT + DARKFLAG_SIDE_RIGHT;
+local DARKFLAG_NEXTMONTH_LEFTRIGHT = DARKFLAG_NEXTMONTH + DARKFLAG_SIDE_LEFT + DARKFLAG_SIDE_RIGHT; -- day 1 of next month, 7th day of the week, not index 42
+-- shared flags
+local DARKFLAG_NEXTMONTH_LEFT = DARKFLAG_NEXTMONTH + DARKFLAG_SIDE_LEFT;
+local DARKFLAG_NEXTMONTH_RIGHT = DARKFLAG_NEXTMONTH + DARKFLAG_SIDE_RIGHT;
+-- the dark day tcoord tables simplify tex coord setup for dark days
+local DARKDAY_TOP_TCOORDS = {
+ [DARKFLAG_PREVMONTH_TOP] = {
+ left = 90 / 512,
+ right = 180 / 512,
+ top = 0.0,
+ bottom = 45 / 256,
+ },
+ [DARKFLAG_PREVMONTH_TOPLEFT] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 0.0,
+ bottom = 45 / 256 - 0.001, -- fudge factor to prevent texture seams
+ },
+ [DARKFLAG_PREVMONTH_TOPRIGHT] = {
+ left = 90 / 512,
+ right = 0.0,
+ top = 0.0,
+ bottom = 45 / 256 - 0.001, -- fudge factor to prevent texture seams
+ },
+ [DARKFLAG_PREVMONTH_TOPLEFTRIGHT] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 180 / 256,
+ bottom = 225 / 256 - 0.001, -- fudge factor to prevent texture seams
+ },
+
+ -- next 3 are same as DARKDAY_BOTTOM_TCOORDS (blank, left, right--no difference between top & bottom)
+ [DARKFLAG_NEXTMONTH] = { -- no drop shadowing
+ left = 90 / 512,
+ right = 180 / 512,
+ top = 45 / 256,
+ bottom = 90 / 256,
+ },
+ [DARKFLAG_NEXTMONTH_LEFT] = {
+ left = 90 / 512,
+ right = 0.0,
+ top = 90 / 256,
+ bottom = 135 / 256,
+ },
+ [DARKFLAG_NEXTMONTH_RIGHT] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 90 / 256,
+ bottom = 135 / 256 - 0.001, -- fudge factor to prevent texture seams
+ },
+
+ [DARKFLAG_NEXTMONTH_TOP] = {
+ left = 90 / 512,
+ right = 180 / 512,
+ top = 0.0,
+ bottom = 45 / 256,
+ },
+ [DARKFLAG_NEXTMONTH_TOPLEFT] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 0.0,
+ bottom = 45 / 256 - 0.001, -- fudge factor to prevent texture seams
+ },
+ [DARKFLAG_NEXTMONTH_TOPRIGHT] = {
+ left = 90 / 512,
+ right = 0.0,
+ top = 0.0,
+ bottom = 45 / 256 - 0.001, -- fudge factor to prevent texture seams
+ },
+
+ -- day 8 of next month
+ [DARKFLAG_NEXTMONTH_CORNER] = {
+ left = 90 / 512,
+ right = 180 / 512 - 0.001, -- fudge factor to prevent texture seams
+ top = 135 / 256,
+ bottom = 180 / 256,
+ },
+ -- day 7 of next month
+ [DARKFLAG_NEXTMONTH_CORNER_TOP] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 135 / 256,
+ bottom = 180 / 256 - 0.001, -- fudge factor to prevent texture seams
+ },
+ -- day 8 of next month, index 42
+ [DARKFLAG_NEXTMONTH_CORNER_RIGHT] = {
+ left = 180 / 512,
+ right = 270 / 512 - 0.001, -- fudge factor to prevent texture seams
+ top = 45 / 256,
+ bottom = 90 / 256 - 0.001, -- fudge factor to prevent texture seams
+ },
+ -- day 1 of next month
+ [DARKFLAG_NEXTMONTH_CORNER_TOPLEFT] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 45 / 256,
+ bottom = 90 / 256,
+ },
+ -- day 1 of next month, 7th day of the week
+ [DARKFLAG_NEXTMONTH_CORNER_TOPLEFTRIGHT] = {
+ left = 180 / 512,
+ right = 90 / 512,
+ top = 225 / 256,
+ bottom = 180 / 256,
+ },
+};
+local DARKDAY_BOTTOM_TCOORDS = {
+ [DARKFLAG_PREVMONTH_BOTTOM] = {
+ left = 90 / 512,
+ right = 180 / 512,
+ top = 45 / 256,
+ bottom = 0.0,
+ },
+ [DARKFLAG_PREVMONTH_BOTTOMLEFT] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 45 / 256 - 0.001, -- fudge factor to prevent texture seams
+ bottom = 0.0,
+ },
+ [DARKFLAG_PREVMONTH_BOTTOMRIGHT] = {
+ left = 90 / 512,
+ right = 0.0,
+ top = 90 / 256,
+ bottom = 45 / 256,
+ },
+ [DARKFLAG_PREVMONTH_BOTTOMLEFTRIGHT] = {
+ left = 90 / 512,
+ right = 180 / 512,
+ top = 180 / 256,
+ bottom = 225 / 256,
+ },
+
+ -- next 3 are same as DARKDAY_TOP_TCOORDS (blank, left, right--no difference between top & bottom)
+ [DARKFLAG_NEXTMONTH] = { -- no drop shadowing
+ left = 90 / 512,
+ right = 180 / 512,
+ top = 45 / 256,
+ bottom = 90 / 256,
+ },
+ [DARKFLAG_NEXTMONTH_LEFT] = {
+ left = 90 / 512,
+ right = 0.0,
+ top = 90 / 256,
+ bottom = 135 / 256,
+ },
+ [DARKFLAG_NEXTMONTH_RIGHT] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 90 / 256,
+ bottom = 135 / 256,
+ },
+
+ [DARKFLAG_NEXTMONTH_BOTTOM] = {
+ left = 90 / 512,
+ right = 180 / 512,
+ top = 45 / 256,
+ bottom = 0.0,
+ },
+ [DARKFLAG_NEXTMONTH_BOTTOMLEFT] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 45 / 256 - 0.001, -- fudge factor to prevent texture seams
+ bottom = 0.0,
+ },
+ [DARKFLAG_NEXTMONTH_BOTTOMRIGHT] = {
+ left = 90 / 512,
+ right = 0.0,
+ top = 45 / 256 - 0.001, -- fudge factor to prevent texture seams
+ bottom = 0.0,
+ },
+ [DARKFLAG_NEXTMONTH_BOTTOMLEFTRIGHT] = {
+ left = 0.0,
+ right = 90 / 512,
+ top = 225 / 256,
+ bottom = 180 / 256,
+ },
+
+ -- day 1 of next month, 7th day of the week, not index 42
+ [DARKFLAG_NEXTMONTH_LEFTRIGHT] = {
+ left = 180 / 512,
+ right = 270 / 512 - 0.001, -- fudge factor to prevent texture seams
+ top = 0.0,
+ bottom = 45 / 256,
+ },
+};
+
+-- more local constants
+local CALENDAR_MONTH_NAMES = {
+ MONTH_JANUARY,
+ MONTH_FEBRUARY,
+ MONTH_MARCH,
+ MONTH_APRIL,
+ MONTH_MAY,
+ MONTH_JUNE,
+ MONTH_JULY,
+ MONTH_AUGUST,
+ MONTH_SEPTEMBER,
+ MONTH_OCTOBER,
+ MONTH_NOVEMBER,
+ MONTH_DECEMBER,
+};
+
+-- month names show up differently for full date displays in some languages
+local CALENDAR_FULLDATE_MONTH_NAMES = {
+ FULLDATE_MONTH_JANUARY,
+ FULLDATE_MONTH_FEBRUARY,
+ FULLDATE_MONTH_MARCH,
+ FULLDATE_MONTH_APRIL,
+ FULLDATE_MONTH_MAY,
+ FULLDATE_MONTH_JUNE,
+ FULLDATE_MONTH_JULY,
+ FULLDATE_MONTH_AUGUST,
+ FULLDATE_MONTH_SEPTEMBER,
+ FULLDATE_MONTH_OCTOBER,
+ FULLDATE_MONTH_NOVEMBER,
+ FULLDATE_MONTH_DECEMBER,
+};
+
+local CALENDAR_WEEKDAY_NAMES = {
+ WEEKDAY_SUNDAY,
+ WEEKDAY_MONDAY,
+ WEEKDAY_TUESDAY,
+ WEEKDAY_WEDNESDAY,
+ WEEKDAY_THURSDAY,
+ WEEKDAY_FRIDAY,
+ WEEKDAY_SATURDAY,
+};
+
+local CALENDAR_EVENTCOLOR_MODERATOR = {r=0.54, g=0.75, b=1.0};
+
+local CALENDAR_INVITESTATUS_INFO = {
+ ["UNKNOWN"] = {
+ name = UNKNOWN,
+ color = NORMAL_FONT_COLOR,
+-- colorCode = NORMAL_FONT_COLOR_CODE,
+ },
+ [CALENDAR_INVITESTATUS_CONFIRMED] = {
+ name = CALENDAR_STATUS_CONFIRMED,
+ color = GREEN_FONT_COLOR,
+-- colorCode = GREEN_FONT_COLOR_CODE,
+ },
+ [CALENDAR_INVITESTATUS_ACCEPTED] = {
+ name = CALENDAR_STATUS_ACCEPTED,
+ color = GREEN_FONT_COLOR,
+-- colorCode = GREEN_FONT_COLOR_CODE,
+ },
+ [CALENDAR_INVITESTATUS_DECLINED] = {
+ name = CALENDAR_STATUS_DECLINED,
+ color = RED_FONT_COLOR,
+-- colorCode = RED_FONT_COLOR_CODE,
+ },
+ [CALENDAR_INVITESTATUS_OUT] = {
+ name = CALENDAR_STATUS_OUT,
+ color = RED_FONT_COLOR,
+-- colorCode = RED_FONT_COLOR_CODE,
+ },
+ [CALENDAR_INVITESTATUS_STANDBY] = {
+ name = CALENDAR_STATUS_STANDBY,
+ color = ORANGE_FONT_COLOR,
+-- colorCode = ORANGE_FONT_COLOR_CODE,
+ },
+ [CALENDAR_INVITESTATUS_INVITED] = {
+ name = CALENDAR_STATUS_INVITED,
+ color = NORMAL_FONT_COLOR,
+-- colorCode = NORMAL_FONT_COLOR_CODE,
+ },
+ [CALENDAR_INVITESTATUS_SIGNEDUP] = {
+ name = CALENDAR_STATUS_SIGNEDUP,
+ color = GREEN_FONT_COLOR,
+-- colorCode = GREEN_FONT_COLOR_CODE,
+ },
+ [CALENDAR_INVITESTATUS_NOT_SIGNEDUP] = {
+ name = CALENDAR_STATUS_NOT_SIGNEDUP,
+ color = NORMAL_FONT_COLOR,
+-- colorCode = NORMAL_FONT_COLOR_CODE,
+ },
+ [CALENDAR_INVITESTATUS_TENTATIVE] = {
+ name = CALENDAR_STATUS_TENTATIVE,
+ color = ORANGE_FONT_COLOR,
+-- colorCode = ORANGE_FONT_COLOR_CODE,
+ },
+};
+
+local CALENDAR_CALENDARTYPE_NAMEFORMAT = {
+ ["PLAYER"] = {
+ [""] = "%s",
+ },
+ ["GUILD_ANNOUNCEMENT"] = {
+ [""] = "%s",
+ },
+ ["GUILD_EVENT"] = {
+ [""] = "%s",
+ },
+ ["SYSTEM"] = {
+ [""] = "%s",
+ },
+ ["HOLIDAY"] = {
+ ["START"] = CALENDAR_EVENTNAME_FORMAT_START,
+ ["END"] = CALENDAR_EVENTNAME_FORMAT_END,
+ [""] = "%s",
+ },
+ ["RAID_LOCKOUT"] = {
+ [""] = CALENDAR_EVENTNAME_FORMAT_RAID_LOCKOUT,
+ },
+ ["RAID_RESET"] = {
+ [""] = CALENDAR_EVENTNAME_FORMAT_RAID_RESET,
+ },
+};
+local CALENDAR_CALENDARTYPE_TEXTURE_PATHS = {
+-- ["PLAYER"] = "",
+-- ["GUILD_ANNOUNCEMENT"] = "",
+-- ["GUILD_EVENT"] = "",
+-- ["SYSTEM"] = "",
+ ["HOLIDAY"] = "Interface\\Calendar\\Holidays\\",
+-- ["RAID_LOCKOUT"] = "",
+-- ["RAID_RESET"] = "",
+};
+local CALENDAR_CALENDARTYPE_TEXTURES = {
+ ["PLAYER"] = {
+-- [""] = "",
+ },
+ ["GUILD_ANNOUNCEMENT"] = {
+-- [""] = "",
+ },
+ ["GUILD_EVENT"] = {
+-- [""] = "",
+ },
+ ["SYSTEM"] = {
+-- [""] = "",
+ },
+ ["HOLIDAY"] = {
+ ["START"] = "Interface\\Calendar\\Holidays\\Calendar_DefaultHoliday",
+-- ["ONGOING"] = "",
+ ["END"] = "Interface\\Calendar\\Holidays\\Calendar_DefaultHoliday",
+ ["INFO"] = "Interface\\Calendar\\Holidays\\Calendar_DefaultHoliday",
+-- [""] = "",
+ },
+ ["RAID_LOCKOUT"] = {
+-- [""] = "",
+ },
+ ["RAID_RESET"] = {
+-- [""] = "",
+ },
+};
+local CALENDAR_CALENDARTYPE_TEXTURE_APPEND = {
+-- ["PLAYER"] = {
+-- },
+-- ["GUILD_ANNOUNCEMENT"] = {
+-- },
+-- ["GUILD_EVENT"] = {
+-- },
+-- ["SYSTEM"] = {
+-- },
+ ["HOLIDAY"] = {
+ ["START"] = "Start",
+ ["ONGOING"] = "Ongoing",
+ ["END"] = "End",
+ ["INFO"] = "Info",
+ [""] = "",
+ },
+-- ["RAID_LOCKOUT"] = {
+-- },
+-- ["RAID_RESET"] = {
+-- },
+};
+local CALENDAR_CALENDARTYPE_TCOORDS = {
+ ["PLAYER"] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+ ["GUILD_ANNOUNCEMENT"] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+ ["GUILD_EVENT"] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+ ["SYSTEM"] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+ ["HOLIDAY"] = {
+ left = 0.0,
+ right = 0.7109375,
+ top = 0.0,
+ bottom = 0.7109375,
+ },
+ ["RAID_LOCKOUT"] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+ ["RAID_RESET"] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+};
+local CALENDAR_CALENDARTYPE_COLORS = {
+-- ["PLAYER"] = ,
+-- ["GUILD_ANNOUNCEMENT"] = ,
+-- ["GUILD_EVENT"] = ,
+ ["SYSTEM"] = YELLOW_FONT_COLOR,
+ ["HOLIDAY"] = HIGHLIGHT_FONT_COLOR,
+ ["RAID_LOCKOUT"] = HIGHLIGHT_FONT_COLOR,
+ ["RAID_RESET"] = HIGHLIGHT_FONT_COLOR,
+};
+
+local CALENDAR_EVENTTYPE_TEXTURE_PATHS = {
+ [CALENDAR_EVENTTYPE_RAID] = "Interface\\LFGFrame\\LFGIcon-",
+ [CALENDAR_EVENTTYPE_DUNGEON] = "Interface\\LFGFrame\\LFGIcon-",
+-- [CALENDAR_EVENTTYPE_PVP] = "",
+-- [CALENDAR_EVENTTYPE_MEETING] = "",
+-- [CALENDAR_EVENTTYPE_OTHER] = "",
+};
+local CALENDAR_EVENTTYPE_TEXTURES = {
+ [CALENDAR_EVENTTYPE_RAID] = "Interface\\LFGFrame\\LFGIcon-Raid",
+ [CALENDAR_EVENTTYPE_DUNGEON] = "Interface\\LFGFrame\\LFGIcon-Dungeon",
+ [CALENDAR_EVENTTYPE_PVP] = "Interface\\Calendar\\UI-Calendar-Event-PVP",
+ [CALENDAR_EVENTTYPE_MEETING] = "Interface\\Calendar\\MeetingIcon",
+ [CALENDAR_EVENTTYPE_OTHER] = "Interface\\Calendar\\UI-Calendar-Event-Other",
+};
+local CALENDAR_EVENTTYPE_TCOORDS = {
+ [CALENDAR_EVENTTYPE_RAID] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+ [CALENDAR_EVENTTYPE_DUNGEON] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+ [CALENDAR_EVENTTYPE_PVP] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+ [CALENDAR_EVENTTYPE_MEETING] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+ [CALENDAR_EVENTTYPE_OTHER] = {
+ left = 0.0,
+ right = 1.0,
+ top = 0.0,
+ bottom = 1.0,
+ },
+};
+do
+ -- set the pvp icon to the player's faction
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ -- need new texcoords too?
+ if ( factionGroup == "Alliance" ) then
+ CALENDAR_EVENTTYPE_TEXTURES[CALENDAR_EVENTTYPE_PVP] = "Interface\\Calendar\\UI-Calendar-Event-PVP02";
+ else
+ CALENDAR_EVENTTYPE_TEXTURES[CALENDAR_EVENTTYPE_PVP] = "Interface\\Calendar\\UI-Calendar-Event-PVP01";
+ end
+ end
+end
+
+local CALENDAR_FILTER_CVARS = {
+ {text = CALENDAR_FILTER_BATTLEGROUND, cvar = "calendarShowBattlegrounds" },
+ {text = CALENDAR_FILTER_DARKMOON, cvar = "calendarShowDarkmoon" },
+ {text = CALENDAR_FILTER_RAID_LOCKOUTS, cvar = "calendarShowLockouts" },
+ {text = CALENDAR_FILTER_RAID_RESETS, cvar = "calendarShowResets" },
+ {text = CALENDAR_FILTER_WEEKLY_HOLIDAYS, cvar = "calendarShowWeeklyHolidays" },
+};
+
+-- local data
+
+-- CalendarDayButtons is just a table of all the Calendar day buttons...the size of this table should
+-- equal CALENDAR_MAX_DAYS_PER_MONTH once the CalendarFrame is done loading
+local CalendarDayButtons = { };
+
+-- CalendarEventTextureCache gets updated whenever event type textures are requested (currently only
+-- the Dungeon and Raid event types have texture lists)
+local CalendarEventTextureCache = { };
+
+-- CalendarClassData gets updated whenever the current event's invite list is updated
+local CalendarClassData = { };
+do
+ for i, class in ipairs(CLASS_SORT_ORDER) do
+ CalendarClassData[class] = {
+ name = nil,
+ tcoords = CLASS_ICON_TCOORDS[class],
+ counts = {
+ [CALENDAR_INVITESTATUS_INVITED] = 0,
+ [CALENDAR_INVITESTATUS_ACCEPTED] = 0,
+ [CALENDAR_INVITESTATUS_DECLINED] = 0,
+ [CALENDAR_INVITESTATUS_CONFIRMED] = 0,
+ [CALENDAR_INVITESTATUS_OUT] = 0,
+ [CALENDAR_INVITESTATUS_STANDBY] = 0,
+ [CALENDAR_INVITESTATUS_SIGNEDUP] = 0,
+ [CALENDAR_INVITESTATUS_NOT_SIGNEDUP] = 0,
+ [CALENDAR_INVITESTATUS_TENTATIVE] = 0,
+ },
+ };
+ end
+end
+
+-- CalendarModalStack is a stack of modal dialog frames. The reason why we use a stack (instead of a single
+-- frame), for the modal system is because modal dialogs can stack on top of each other...for example,
+-- try deleting an event from the event picker frame. The stack will have two elements: the bottom element
+-- is the event picker frame and the top element is the delete confirmation popup.
+local CalendarModalStack = { };
+
+
+-- local helper functions
+
+local function safeselect(index, ...)
+ local count = select("#", ...);
+ if ( count > 0 and index <= count ) then
+ return select(index, ...);
+ else
+ return nil;
+ end
+end
+
+local function _CalendarFrame_SafeGetName(name)
+ if ( not name or name == "" ) then
+ return UNKNOWN;
+ end
+ return name;
+end
+
+local function _CalendarFrame_GetDayOfWeek(index)
+ return mod(index - 1, 7) + 1;
+end
+
+-- _CalendarFrame_GetWeekdayIndex takes an index in the range [1, n] and maps it to a weekday starting
+-- at CALENDAR_FIRST_WEEKDAY. For example,
+-- CALENDAR_FIRST_WEEKDAY = 1 => [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY]
+-- CALENDAR_FIRST_WEEKDAY = 2 => [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
+-- CALENDAR_FIRST_WEEKDAY = 6 => [FRIDAY, SATURDAY, SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY]
+local function _CalendarFrame_GetWeekdayIndex(index)
+ -- the expanded form for the left input to mod() is:
+ -- (index - 1) + (CALENDAR_FIRST_WEEKDAY - 1)
+ -- why the - 1 and then + 1 before return? because lua has 1-based indexes! awesome!
+ return mod(index - 2 + CALENDAR_FIRST_WEEKDAY, 7) + 1;
+end
+
+local function _CalendarFrame_GetFullDate(weekday, month, day, year)
+ local weekdayName = CALENDAR_WEEKDAY_NAMES[weekday];
+ local monthName = CALENDAR_FULLDATE_MONTH_NAMES[month];
+ return weekdayName, monthName, day, year, month;
+end
+
+local function _CalendarFrame_GetFullDateFromDay(dayButton)
+ local weekday = _CalendarFrame_GetWeekdayIndex(dayButton:GetID());
+ local month, year = CalendarGetMonth(dayButton.monthOffset);
+ local day = dayButton.day;
+ return _CalendarFrame_GetFullDate(weekday, month, day, year);
+end
+
+local function _CalendarFrame_IsTodayOrLater(month, day, year)
+ local presentWeekday, presentMonth, presentDay, presentYear = CalendarGetDate();
+ local todayOrLater = false;
+ if ( year > presentYear ) then
+ todayOrLater = true;
+ elseif ( year == presentYear ) then
+ if ( month > presentMonth ) then
+ todayOrLater = true;
+ elseif ( month == presentMonth ) then
+ todayOrLater = day >= presentDay;
+ end
+ end
+ return todayOrLater;
+end
+
+local function _CalendarFrame_IsAfterMaxCreateDate(month, day, year)
+ local maxWeekday, maxMonth, maxDay, maxYear = CalendarGetMaxCreateDate();
+ local afterMaxDate = false;
+ if ( year > maxYear ) then
+ afterMaxDate = true;
+ elseif ( year == maxYear ) then
+ if ( month > maxMonth ) then
+ afterMaxDate = true;
+ elseif ( month == maxMonth ) then
+ afterMaxDate = day > maxDay;
+ end
+ end
+ return afterMaxDate;
+end
+
+local function _CalendarFrame_IsPlayerCreatedEvent(calendarType)
+ return
+ calendarType == "PLAYER" or
+ calendarType == "GUILD_ANNOUNCEMENT" or
+ calendarType == "GUILD_EVENT";
+end
+
+local function _CalendarFrame_CanInviteeRSVP(inviteStatus)
+ return
+ inviteStatus == CALENDAR_INVITESTATUS_INVITED or
+ inviteStatus == CALENDAR_INVITESTATUS_ACCEPTED or
+ inviteStatus == CALENDAR_INVITESTATUS_DECLINED or
+ inviteStatus == CALENDAR_INVITESTATUS_SIGNEDUP or
+ inviteStatus == CALENDAR_INVITESTATUS_NOT_SIGNEDUP or
+ inviteStatus == CALENDAR_INVITESTATUS_TENTATIVE;
+end
+
+local function _CalendarFrame_IsSignUpEvent(calendarType, inviteType)
+ return calendarType == "GUILD_EVENT" and inviteType == CALENDAR_INVITETYPE_SIGNUP;
+end
+
+local function _CalendarFrame_CanRemoveEvent(modStatus, calendarType, inviteType, inviteStatus)
+ return
+ modStatus ~= "CREATOR" and
+ (calendarType == "PLAYER" or (calendarType == "GUILD_EVENT" and inviteType == CALENDAR_INVITETYPE_NORMAL));
+end
+
+local function _CalendarFrame_CacheEventTextures_Internal(...)
+ local numTextures = select("#", ...) / 4;
+ if ( numTextures <= 0 ) then
+ CalendarEventTextureCache.eventType = nil;
+ return false;
+ end
+
+ while ( #CalendarEventTextureCache > numTextures ) do
+ tremove(CalendarEventTextureCache);
+ end
+
+ local param = 1;
+ local cacheIndex = 1;
+ for textureIndex = 1, numTextures do
+ if ( not CalendarEventTextureCache[cacheIndex] ) then
+ CalendarEventTextureCache[cacheIndex] = { };
+ end
+
+ -- insert texture
+ CalendarEventTextureCache[cacheIndex].textureIndex = textureIndex;
+ CalendarEventTextureCache[cacheIndex].title = select(param, ...);
+ param = param + 1;
+ CalendarEventTextureCache[cacheIndex].texture = select(param, ...);
+ param = param + 1;
+ CalendarEventTextureCache[cacheIndex].expansionLevel = select(param, ...);
+ param = param + 1;
+ CalendarEventTextureCache[cacheIndex].difficultyName = select(param, ...);
+ param = param + 1;
+
+ -- insert headers between expansion levels
+ local entry = CalendarEventTextureCache[cacheIndex];
+ local prevEntry = CalendarEventTextureCache[cacheIndex - 1];
+ if ( not prevEntry or (prevEntry and prevEntry.expansionLevel ~= entry.expansionLevel) ) then
+ -- insert empty entry...
+ if ( prevEntry ) then
+ --...only if we had a previous entry
+ CalendarEventTextureCache[cacheIndex] = { };
+ cacheIndex = cacheIndex + 1;
+ end
+ -- insert header
+ CalendarEventTextureCache[cacheIndex] = {
+ title = _G["EXPANSION_NAME"..entry.expansionLevel],
+ expansionLevel = entry.expansionLevel,
+ };
+ cacheIndex = cacheIndex + 1;
+ -- make the current entry the next entry
+ CalendarEventTextureCache[cacheIndex] = entry;
+ end
+
+ cacheIndex = cacheIndex + 1;
+ end
+ return true;
+end
+
+local function _CalendarFrame_CacheEventTextures(eventType)
+ if ( eventType ~= CalendarEventTextureCache.eventType ) then
+ CalendarEventTextureCache.eventType = eventType
+ if ( eventType ) then
+ return _CalendarFrame_CacheEventTextures_Internal(CalendarEventGetTextures(eventType));
+ end
+ end
+ return true;
+end
+
+local function _CalendarFrame_GetEventTexture(index, eventType)
+ if ( not _CalendarFrame_CacheEventTextures(eventType) ) then
+ return nil;
+ end
+ for cacheIndex = 1, #CalendarEventTextureCache do
+ local entry = CalendarEventTextureCache[cacheIndex];
+ if ( entry.textureIndex and index == entry.textureIndex ) then
+ return entry;
+ end
+ end
+ return nil;
+end
+
+local function _CalendarFrame_GetTextureFile(textureName, calendarType, sequenceType, eventType)
+ local texture, tcoords;
+ if ( textureName and textureName ~= "" ) then
+ if ( CALENDAR_CALENDARTYPE_TEXTURE_PATHS[calendarType] ) then
+ texture = CALENDAR_CALENDARTYPE_TEXTURE_PATHS[calendarType]..textureName;
+ if ( CALENDAR_CALENDARTYPE_TEXTURE_APPEND[calendarType] ) then
+ texture = texture..CALENDAR_CALENDARTYPE_TEXTURE_APPEND[calendarType][sequenceType];
+ end
+ tcoords = CALENDAR_CALENDARTYPE_TCOORDS[calendarType];
+ elseif ( CALENDAR_EVENTTYPE_TEXTURE_PATHS[eventType] ) then
+ texture = CALENDAR_EVENTTYPE_TEXTURE_PATHS[eventType]..textureName;
+ tcoords = CALENDAR_EVENTTYPE_TCOORDS[eventType];
+ elseif ( CALENDAR_CALENDARTYPE_TEXTURES[calendarType][sequenceType] ) then
+ texture = CALENDAR_CALENDARTYPE_TEXTURES[calendarType][sequenceType];
+ tcoords = CALENDAR_CALENDARTYPE_TCOORDS[calendarType];
+ elseif ( CALENDAR_EVENTTYPE_TEXTURES[eventType] ) then
+ texture = CALENDAR_EVENTTYPE_TEXTURES[eventType];
+ tcoords = CALENDAR_EVENTTYPE_TCOORDS[eventType];
+ end
+ elseif ( CALENDAR_CALENDARTYPE_TEXTURES[calendarType][sequenceType] ) then
+ texture = CALENDAR_CALENDARTYPE_TEXTURES[calendarType][sequenceType];
+ tcoords = CALENDAR_CALENDARTYPE_TCOORDS[calendarType];
+ elseif ( CALENDAR_EVENTTYPE_TEXTURES[eventType] ) then
+ texture = CALENDAR_EVENTTYPE_TEXTURES[eventType];
+ tcoords = CALENDAR_EVENTTYPE_TCOORDS[eventType];
+ end
+ return texture, tcoords;
+end
+
+local function _CalendarFrame_GetEventColor(calendarType, modStatus, inviteStatus)
+ if ( calendarType == "PLAYER" or calendarType == "GUILD_ANNOUNCEMENT" or calendarType == "GUILD_EVENT" ) then
+ if ( modStatus == "MODERATOR" or modStatus == "CREATOR" ) then
+ return CALENDAR_EVENTCOLOR_MODERATOR;
+ elseif ( inviteStatus and CALENDAR_INVITESTATUS_INFO[inviteStatus] ) then
+ return CALENDAR_INVITESTATUS_INFO[inviteStatus].color;
+ end
+ elseif ( CALENDAR_CALENDARTYPE_COLORS[calendarType] ) then
+ return CALENDAR_CALENDARTYPE_COLORS[calendarType];
+ end
+ -- default to normal color
+ return NORMAL_FONT_COLOR;
+end
+
+local function _CalendarFrame_SafeGetInviteStatusInfo(inviteStatus)
+ return CALENDAR_INVITESTATUS_INFO[inviteStatus] or CALENDAR_INVITESTATUS_INFO["UNKNOWN"];
+end
+
+local function _CalendarFrame_ResetClassData()
+ for _, classData in next, CalendarClassData do
+ for i in next, classData.counts do
+ classData.counts[i] = 0;
+ end
+ end
+end
+
+local function _CalendarFrame_UpdateClassData()
+ _CalendarFrame_ResetClassData();
+
+ for i = 1, CalendarEventGetNumInvites() do
+ local _, _, className, classFilename, inviteStatus = CalendarEventGetInvite(i);
+ if ( classFilename and classFilename ~= "" ) then
+ CalendarClassData[classFilename].counts[inviteStatus] = CalendarClassData[classFilename].counts[inviteStatus] + 1;
+ -- HACK: doing this because we don't have class names in global strings
+ CalendarClassData[classFilename].name = className;
+ end
+ end
+end
+
+local function _CalendarFrame_InviteToRaid(maxInviteCount)
+ local inviteCount = 0;
+ local i = 1;
+ while ( inviteCount < maxInviteCount and i <= CalendarEventGetNumInvites() ) do
+ local name, level, className, classFilename, inviteStatus = CalendarEventGetInvite(i);
+ if ( not UnitInParty(name) and not UnitInRaid(name) and
+ (inviteStatus == CALENDAR_INVITESTATUS_ACCEPTED or
+ inviteStatus == CALENDAR_INVITESTATUS_CONFIRMED or
+ inviteStatus == CALENDAR_INVITESTATUS_SIGNEDUP) ) then
+ InviteUnit(name);
+ inviteCount = inviteCount + 1;
+ end
+ i = i + 1;
+ end
+ return inviteCount;
+end
+
+local function _CalendarFrame_GetInviteToRaidCount(maxInviteCount)
+ local inviteCount = 0;
+ local i = 1;
+ while ( inviteCount < maxInviteCount and i <= CalendarEventGetNumInvites() ) do
+ local name, level, className, classFilename, inviteStatus = CalendarEventGetInvite(i);
+ if ( not UnitInParty(name) and not UnitInRaid(name) and
+ (inviteStatus == CALENDAR_INVITESTATUS_ACCEPTED or
+ inviteStatus == CALENDAR_INVITESTATUS_CONFIRMED or
+ inviteStatus == CALENDAR_INVITESTATUS_SIGNEDUP) ) then
+ inviteCount = inviteCount + 1;
+ end
+ i = i + 1;
+ end
+ return inviteCount;
+end
+
+
+-- CalendarFrame
+
+function Calendar_Toggle()
+ if ( CalendarFrame:IsShown() ) then
+ Calendar_Hide();
+ else
+ Calendar_Show();
+ end
+end
+
+function Calendar_Hide()
+ HideUIPanel(CalendarFrame);
+end
+
+function Calendar_Show()
+ ShowUIPanel(CalendarFrame);
+end
+
+function CalendarFrame_ShowEventFrame(frame)
+ if ( frame == CalendarFrame.eventFrame ) then
+ if ( frame ) then
+ if ( not frame:IsShown() ) then
+ frame:Show();
+ CalendarEventFrameBlocker:Show();
+ elseif ( frame.update ) then
+ frame.update();
+ CalendarEventFrameBlocker:Show();
+ end
+ end
+ else
+ if ( CalendarFrame.eventFrame ) then
+ CalendarFrame.eventFrame:Hide();
+ CalendarEventFrameBlocker:Hide();
+ end
+ CalendarFrame.eventFrame = frame;
+ if ( frame ) then
+ frame:Show();
+ CalendarEventFrameBlocker:Show();
+ end
+ end
+end
+
+function CalendarFrame_HideEventFrame(frame)
+ if ( not frame or frame and frame == CalendarFrame.eventFrame ) then
+ CalendarFrame_ShowEventFrame(nil);
+ end
+end
+
+function CalendarFrame_GetEventFrame()
+ return CalendarFrame.eventFrame;
+end
+
+function CalendarFrame_UpdateTimeFormat()
+ -- update all frames that display a time
+ local militaryTime = GetCVarBool("timeMgrUseMilitaryTime");
+ if ( CalendarFrame:IsShown() and militaryTime ~= CalendarFrame.militaryTime ) then
+ -- update the main frame
+ CalendarFrame_Update();
+ local eventFrame = CalendarFrame.eventFrame;
+ if ( eventFrame ) then
+ -- update the event frame
+ if ( eventFrame == CalendarCreateEventFrame ) then
+ -- the create event frame is handled specially because a full update could potentially clobber
+ -- a player's changes if he is creating or editing an event
+ CalendarCreateEvent_UpdateTimeFormat();
+ elseif ( eventFrame.update ) then
+ eventFrame.update();
+ end
+ end
+ if ( CalendarEventPickerFrame:IsShown() ) then
+ -- update the event picker frame
+ CalendarEventPickerScrollFrame_Update();
+ end
+ CalendarFrame.militaryTime = militaryTime;
+ end
+end
+
+function CalendarFrame_OnLoad(self)
+ self:RegisterEvent("CALENDAR_UPDATE_EVENT_LIST");
+-- self:RegisterEvent("CALENDAR_UPDATE_PENDING_INVITES"); -- event list updates are fired for invite status changes now
+ self:RegisterEvent("CALENDAR_OPEN_EVENT");
+ self:RegisterEvent("CALENDAR_UPDATE_ERROR");
+
+ -- initialize weekdays
+ for i = 1, 7 do
+ CalendarFrame_InitWeekday(i);
+ end
+
+ -- initialize day buttons
+ for i = 1, CALENDAR_MAX_DAYS_PER_MONTH do
+ CalendarDayButtons[i] = CreateFrame("Button", "CalendarDayButton"..i, self, "CalendarDayButtonTemplate");
+ CalendarFrame_InitDay(i);
+ end
+
+ -- initialize the selected date
+ self.selectedMonth = nil;
+ self.selectedDay = nil;
+ self.selectedYear = nil;
+
+ -- initialize the viewed date
+ self.viewedMonth = nil;
+ self.viewedYear = nil;
+
+ -- initialize modal dialog handling
+ self.modalFrame = nil;
+end
+
+function CalendarFrame_OnEvent(self, event, ...)
+ if ( event == "CALENDAR_UPDATE_EVENT_LIST" ) then
+ CalendarFrame_Update();
+ elseif ( event == "CALENDAR_OPEN_EVENT" ) then
+ -- hide the invite context menu right off the bat, since it's probably going to be invalid
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+ -- now open the event based on its calendar type
+ local calendarType = ...;
+ if ( calendarType == "HOLIDAY" ) then
+ CalendarFrame_ShowEventFrame(CalendarViewHolidayFrame);
+ elseif ( calendarType == "RAID_RESET" or calendarType == "RAID_LOCKOUT" ) then
+ CalendarFrame_ShowEventFrame(CalendarViewRaidFrame);
+ else
+ -- for now, it could only be a player-created type
+ if ( CalendarEventCanEdit() ) then
+ CalendarCreateEventFrame.mode = "edit";
+ CalendarFrame_ShowEventFrame(CalendarCreateEventFrame);
+ else
+ CalendarFrame_ShowEventFrame(CalendarViewEventFrame);
+ end
+ end
+ elseif ( event == "CALENDAR_UPDATE_ERROR" ) then
+ local message = ...;
+ StaticPopup_Show("CALENDAR_ERROR", message);
+ end
+end
+
+function CalendarFrame_OnShow(self)
+ -- an event could have stayed selected if the calendar closed without the player doing so explicitly
+ -- (e.g. reloadui) so make sure that we're not selecting an event when the calendar comes back
+ CalendarFrame_CloseEvent();
+
+ self.militaryTime = GetCVarBool("timeMgrUseMilitaryTime");
+
+ local weekday, month, day, year = CalendarGetDate();
+ CalendarSetAbsMonth(month, year);
+ CalendarFrame_Update();
+
+ OpenCalendar();
+
+ PlaySound("igSpellBookOpen");
+end
+
+function CalendarFrame_OnHide(self)
+ -- close the event now...the reason is that the calendar may clear the current event data next time
+ -- the frame opens up
+ CalendarFrame_CloseEvent();
+ CalendarEventPickerFrame_Hide();
+ CalendarTexturePickerFrame_Hide();
+ CalendarContextMenu_Reset();
+ HideDropDownMenu(1);
+ StaticPopup_Hide("CALENDAR_DELETE_EVENT");
+ StaticPopup_Hide("CALENDAR_ERROR");
+ -- pop all modal frames as a fail safe, just in case we somehow end up in a state where modal frames
+ -- are left shown, which shouldn't happen
+ CalendarFrame_PopModal(true);
+
+ -- clean up texture references
+ local dayButton, dayButtonName;
+ for i = 1, CALENDAR_MAX_DAYS_PER_MONTH do
+ dayButton = CalendarDayButtons[i];
+ dayButtonName = dayButton:GetName();
+ _G[dayButtonName.."EventTexture"]:SetTexture();
+ _G[dayButtonName.."OverlayFrameTexture"]:SetTexture();
+ end
+
+ PlaySound("igSpellBookClose");
+end
+
+function CalendarFrame_InitWeekday(index)
+ local backgroundName = "CalendarWeekday"..index.."Background";
+ local background = _G[backgroundName];
+
+ local left = (band(index, 1) * CALENDAR_WEEKDAY_NORMALIZED_TEX_WIDTH) + CALENDAR_WEEKDAY_NORMALIZED_TEX_LEFT; -- mod(index, 2) * width
+ local right = left + CALENDAR_WEEKDAY_NORMALIZED_TEX_WIDTH;
+ local top = CALENDAR_WEEKDAY_NORMALIZED_TEX_TOP;
+ local bottom = top + CALENDAR_WEEKDAY_NORMALIZED_TEX_HEIGHT;
+ background:SetTexCoord(left, right, top, bottom);
+end
+
+function CalendarFrame_InitDay(buttonIndex)
+ local button = CalendarDayButtons[buttonIndex];
+ local buttonName = button:GetName();
+
+ button:SetID(buttonIndex);
+
+ -- set anchors
+ button:ClearAllPoints();
+ if ( buttonIndex == 1 ) then
+ button:SetPoint("TOPLEFT", CalendarWeekday1Background, "BOTTOMLEFT", 0, 0);
+ elseif ( mod(buttonIndex, 7) == 1 ) then
+ button:SetPoint("TOPLEFT", CalendarDayButtons[buttonIndex - 7], "BOTTOMLEFT", 0, 0);
+ else
+ button:SetPoint("TOPLEFT", CalendarDayButtons[buttonIndex - 1], "TOPRIGHT", 0, 0);
+ end
+
+ -- set the normal texture to be the background
+ local tex = button:GetNormalTexture();
+ tex:SetDrawLayer("BACKGROUND");
+ local texLeft = random(0,1) * CALENDAR_DAYBUTTON_NORMALIZED_TEX_WIDTH;
+ local texRight = texLeft + CALENDAR_DAYBUTTON_NORMALIZED_TEX_WIDTH;
+ local texTop = random(0,1) * CALENDAR_DAYBUTTON_NORMALIZED_TEX_HEIGHT;
+ local texBottom = texTop + CALENDAR_DAYBUTTON_NORMALIZED_TEX_HEIGHT;
+ tex:SetTexCoord(texLeft, texRight, texTop, texBottom);
+ -- adjust the highlight texture layer
+ tex = button:GetHighlightTexture();
+ tex:SetAlpha(CALENDAR_DAYBUTTON_HIGHLIGHT_ALPHA);
+
+ -- create event buttons
+ local eventButtonPrefix = buttonName.."EventButton";
+ -- anchor first event button to the parent...
+ local eventButton = CreateFrame("Button", buttonName.."EventButton1", button, "CalendarDayEventButtonTemplate");
+ eventButton:SetPoint("BOTTOMLEFT", button, "BOTTOMLEFT", CALENDAR_DAYEVENTBUTTON_XOFFSET, -CALENDAR_DAYEVENTBUTTON_YOFFSET);
+ -- ...anchor the rest to the previous event button
+ for i = 2, CALENDAR_DAYBUTTON_MAX_VISIBLE_EVENTS do
+ eventButton = CreateFrame("Button", eventButtonPrefix..i, button, "CalendarDayEventButtonTemplate");
+ eventButton:SetPoint("BOTTOMLEFT", eventButtonPrefix..(i-1), "TOPLEFT", 0, CALENDAR_DAYEVENTBUTTON_YOFFSET);
+ eventButton:Hide();
+ end
+end
+
+function CalendarFrame_Update()
+ local presentWeekday, presentMonth, presentDay, presentYear = CalendarGetDate();
+ local prevMonth, prevYear, prevNumDays = CalendarGetMonth(-1);
+ local nextMonth, nextYear, nextNumDays = CalendarGetMonth(1);
+ local month, year, numDays, firstWeekday = CalendarGetMonth();
+
+ -- update the viewed month
+ CalendarFrame.viewedMonth = month;
+ CalendarFrame.viewedYear = year;
+
+ -- get selected elements
+ local selectedMonth = CalendarFrame.selectedMonth;
+ local selectedDay = CalendarFrame.selectedDay;
+ local selectedYear = CalendarFrame.selectedYear;
+ local selectedEventMonthOffset, selectedEventDay, selectedEventIndex = CalendarGetEventIndex();
+ local contextEventMonthOffset, contextEventDay, contextEventIndex = CalendarContextGetEventIndex();
+
+ -- set title
+ CalendarFrame_UpdateTitle();
+ -- update the prev/next month buttons in case we hit a min or max month
+ CalendarFrame_UpdateMonthOffsetButtons();
+
+ -- initialize weekdays
+ for i = 1, 7 do
+ local weekday = _CalendarFrame_GetWeekdayIndex(i);
+ _G["CalendarWeekday"..i.."Name"]:SetText(CALENDAR_WEEKDAY_NAMES[weekday]);
+ end
+
+ -- initialize hidden attributes
+ CalendarTodayFrame:Hide();
+ CalendarWeekdaySelectedTexture:Hide();
+ CalendarLastDayDarkTexture:Hide();
+ CalendarFrame_SetSelectedEvent();
+
+ local buttonIndex = 1;
+ local darkTexIndex = 1;
+ local darkTopFlags = 0;
+ local darkBottomFlags = 0;
+ local isSelectedDay, isSelectedMonth;
+ local isToday, isThisMonth;
+ local isContextEventDay;
+ local isSelectedEventMonthOffset;
+ local isContextEventMonthOffset;
+ local day;
+
+ -- adjust the first week day
+ --firstWeekday = _CalendarFrame_GetWeekdayIndex(firstWeekday);
+
+ -- set the previous month's days before the first day of the week
+ local viewablePrevMonthDays = mod((firstWeekday - CALENDAR_FIRST_WEEKDAY - 1) + 7, 7);
+ day = prevNumDays - viewablePrevMonthDays;
+ isSelectedMonth = selectedMonth == prevMonth and selectedYear == prevYear;
+ isThisMonth = presentMonth == prevMonth and presentYear == prevYear;
+ isSelectedEventMonthOffset = selectedEventMonthOffset == -1;
+ isContextEventMonthOffset = contextEventMonthOffset == -1;
+ while ( _CalendarFrame_GetWeekdayIndex(buttonIndex) ~= firstWeekday ) do
+ darkTopFlags = DARKFLAG_PREVMONTH + DARKFLAG_SIDE_TOP;
+ darkBottomFlags = DARKFLAG_PREVMONTH + DARKFLAG_SIDE_BOTTOM;
+ if ( buttonIndex == 1 ) then
+ darkTopFlags = darkTopFlags + DARKFLAG_SIDE_LEFT;
+ darkBottomFlags = darkBottomFlags + DARKFLAG_SIDE_LEFT;
+ end
+ if ( buttonIndex == (firstWeekday - 1) ) then
+ darkTopFlags = darkTopFlags + DARKFLAG_SIDE_RIGHT;
+ darkBottomFlags = darkBottomFlags + DARKFLAG_SIDE_RIGHT;
+ end
+
+ isSelectedDay = isSelectedMonth and selectedDay == day;
+ isToday = isThisMonth and presentDay == day;
+ isContextEventDay = isContextEventMonthOffset and contextEventDay == day;
+
+ CalendarFrame_UpdateDay(buttonIndex, day, -1, isSelectedDay, isContextEventDay, isToday, darkTopFlags, darkBottomFlags);
+ CalendarFrame_UpdateDayEvents(buttonIndex, day, -1,
+ isSelectedEventMonthOffset and selectedEventDay == day and selectedEventIndex,
+ isContextEventDay and contextEventIndex);
+
+ day = day + 1;
+ darkTexIndex = darkTexIndex + 1;
+ buttonIndex = buttonIndex + 1;
+ end
+ -- set the days of this month
+ day = 1;
+ isSelectedMonth = selectedMonth == month and selectedYear == year;
+ isThisMonth = presentMonth == month and presentYear == year;
+ isSelectedEventMonthOffset = selectedEventMonthOffset == 0;
+ isContextEventMonthOffset = contextEventMonthOffset == 0;
+ while ( day <= numDays ) do
+ isSelectedDay = isSelectedMonth and selectedDay == day;
+ isToday = isThisMonth and presentDay == day;
+ isContextEventDay = isContextEventMonthOffset and contextEventDay == day;
+
+ CalendarFrame_UpdateDay(buttonIndex, day, 0, isSelectedDay, isContextEventDay, isToday);
+ CalendarFrame_UpdateDayEvents(buttonIndex, day, 0,
+ isSelectedEventMonthOffset and selectedEventDay == day and selectedEventIndex,
+ isContextEventDay and contextEventIndex);
+
+ day = day + 1;
+ buttonIndex = buttonIndex + 1;
+ end
+ -- set the special last-day-of-month texture
+ if ( buttonIndex < 36 and mod(buttonIndex - 1, 7) ~= 0 ) then
+ -- if we are not the last day of the week then we set a special corner texture
+ -- to match up with the dark textures of the following month
+ CalendarFrame_SetLastDay(CalendarDayButtons[buttonIndex - 1], numDays);
+ end
+ -- set the first days of the next month
+ day = 1;
+ isSelectedMonth = selectedMonth == nextMonth and selectedYear == nextYear;
+ isThisMonth = presentMonth == nextMonth and presentYear == nextYear;
+ isSelectedEventMonthOffset = selectedEventMonthOffset == 1;
+ local dayOfWeek;
+ local checkCorners = mod(buttonIndex, 7) ~= 1; -- last day of the viewed month is not the last day of the week
+ while ( buttonIndex <= CALENDAR_MAX_DAYS_PER_MONTH ) do
+ darkTopFlags = DARKFLAG_NEXTMONTH;
+ darkBottomFlags = DARKFLAG_NEXTMONTH;
+ -- left darkness
+ dayOfWeek = _CalendarFrame_GetDayOfWeek(buttonIndex);
+ if ( dayOfWeek == 1 or day == 1 ) then
+ darkTopFlags = darkTopFlags + DARKFLAG_SIDE_LEFT;
+ darkBottomFlags = darkBottomFlags + DARKFLAG_SIDE_LEFT;
+ end
+ -- right darkness
+ if ( dayOfWeek == 7 ) then
+ darkTopFlags = darkTopFlags + DARKFLAG_SIDE_RIGHT;
+ darkBottomFlags = darkBottomFlags + DARKFLAG_SIDE_RIGHT;
+ end
+ -- top darkness
+ if ( not CalendarDayButtons[buttonIndex - 7].dark ) then
+ -- this day last week was not dark
+ darkTopFlags = darkTopFlags + DARKFLAG_SIDE_TOP;
+ end
+ -- bottom darkness
+ if ( not CalendarDayButtons[buttonIndex + 7] ) then
+ -- this day next week does not exist
+ darkBottomFlags = darkBottomFlags + DARKFLAG_SIDE_BOTTOM;
+ end
+ -- corner stuff
+ if ( checkCorners and (day == 1 or day == 7 or day == 8) ) then
+ darkTopFlags = darkTopFlags + DARKFLAG_CORNER;
+ end
+
+ isSelectedDay = isSelectedMonth and selectedDay == day;
+ isToday = isThisMonth and presentDay == day;
+ isContextEventDay = isContextEventMonthOffset and contextEventDay == day;
+
+ CalendarFrame_UpdateDay(buttonIndex, day, 1, isSelectedDay, isContextEventDay, isToday, darkTopFlags, darkBottomFlags);
+ CalendarFrame_UpdateDayEvents(buttonIndex, day, 1,
+ isSelectedEventMonthOffset and selectedEventDay == day and selectedEventIndex,
+ isContextEventDay and contextEventIndex);
+
+ day = day + 1;
+ darkTexIndex = darkTexIndex + 1;
+ buttonIndex = buttonIndex + 1;
+ end
+
+ -- if this month didn't have a selected event...
+ if ( not CalendarFrame.selectedEventButton ) then
+ local eventFrame = CalendarFrame_GetEventFrame();
+ if ( eventFrame and (eventFrame ~= CalendarCreateEventFrame or eventFrame.mode ~= "create") ) then
+ --...and the event frame was open and not in create mode, hide the event frame
+ CalendarFrame_CloseEvent();
+ end
+ end
+
+ -- if the context menu was set to an event...
+ if ( CalendarContextMenu.eventButton and
+ CalendarContextMenu.func == CalendarDayContextMenu_Initialize ) then
+ if ( contextEventDay == 0 ) then
+ --...and the context event no longer exists
+ -- hide the context menu
+ CalendarContextMenu_Hide();
+ -- hide the event deletion popup
+ -- this might seem kludgy, but it takes just as long, if not longer, to check visibility of the popup
+ -- as it does to just hide it, that's why we don't check visibility first
+ StaticPopup_Hide("CALENDAR_DELETE_EVENT");
+ elseif ( CalendarContextMenu:IsShown() ) then
+ local dayButton = CalendarContextMenu.dayButton;
+ local eventButton = CalendarContextMenu.eventButton;
+ if ( dayButton.monthOffset ~= contextEventMonthOffset or
+ dayButton.day ~= contextEventDay or
+ eventButton.eventIndex ~= contextEventIndex ) then
+ --...and the event index changed, hide the context menu
+ -- you might be thinking "why don't we just reanchor the context menu to the proper day?"
+ -- great question! we don't do this because we don't want the UI to jump around on the user
+ -- like that, especially since calendar updates are not always caused by the user
+ CalendarContextMenu_Hide();
+ end
+ end
+ end
+end
+
+function CalendarFrame_UpdateTitle()
+ CalendarMonthName:SetText(CALENDAR_MONTH_NAMES[CalendarFrame.viewedMonth]);
+ CalendarYearName:SetText(CalendarFrame.viewedYear);
+end
+
+function CalendarFrame_UpdateDay(index, day, monthOffset, isSelected, isContext, isToday, darkTopFlags, darkBottomFlags)
+ local button = CalendarDayButtons[index];
+ local buttonName = button:GetName();
+ local dateLabel = _G[buttonName.."DateFrameDate"];
+ local darkTop = _G[buttonName.."DarkFrameTop"];
+ local darkBottom = _G[buttonName.."DarkFrameBottom"];
+ local darkFrame = darkTop:GetParent(); -- darkBottom:GetParent() also works
+
+ -- set date
+ dateLabel:SetText(day);
+ button.day = day;
+ button.monthOffset = monthOffset;
+
+ -- set darkened textures, these are for days not in the viewed month
+ button.dark = darkTopFlags and darkBottomFlags;
+ if ( button.dark ) then
+ local tcoords;
+ tcoords = DARKDAY_TOP_TCOORDS[darkTopFlags];
+ darkTop:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ tcoords = DARKDAY_BOTTOM_TCOORDS[darkBottomFlags];
+ darkBottom:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ darkFrame:Show();
+ else
+ darkFrame:Hide();
+ end
+
+ -- highlight the button if it is the selected day
+ if ( isSelected ) then
+ CalendarFrame_SetSelectedDay(button);
+ else
+ if ( not isContext ) then
+ button:UnlockHighlight();
+ end
+ end
+
+ -- highlight the button if it is today
+ if ( isToday ) then
+ --CalendarFrame_SetToday(button, dateLabel);
+ CalendarFrame_SetToday(button);
+ end
+end
+
+function CalendarFrame_UpdateDayEvents(index, day, monthOffset, selectedEventIndex, contextEventIndex)
+ local dayButton = CalendarDayButtons[index];
+ local dayButtonName = dayButton:GetName();
+
+ local numEvents = CalendarGetNumDayEvents(monthOffset, day);
+
+ -- turn pending invite on if we have one on this day
+ local pendingInviteIndex = CalendarGetFirstPendingInvite(monthOffset, day);
+ local pendingInviteTex = _G[dayButtonName.."PendingInviteTexture"];
+ if ( pendingInviteIndex > 0 ) then
+ pendingInviteTex:Show();
+ else
+ pendingInviteTex:Hide();
+ end
+
+ -- first pass:
+ -- record the number of viewable events
+ -- record first holiday index
+ local numViewableEvents = 0;
+ local firstHolidayIndex;
+ for i = 1, numEvents do
+ local title, hour, minute, calendarType, sequenceType = CalendarGetDayEvent(monthOffset, day, i);
+ if ( title ) then
+ if ( calendarType == "HOLIDAY" and not firstHolidayIndex ) then
+ -- record the first holiday index...the first holiday can have sequenceType "ONGOING"
+ firstHolidayIndex = i;
+ end
+ if ( sequenceType ~= "ONGOING" ) then
+ numViewableEvents = numViewableEvents + 1;
+ end
+ end
+ end
+ dayButton.numViewableEvents = numViewableEvents;
+
+ -- setup for second pass:
+ -- adjust the event buttons based on the number of viewable events in the day
+ -- also, determine whether or not we need the more events button
+ local moreEventsButton = _G[dayButtonName.."MoreEventsButton"];
+ moreEventsButton:Hide();
+ local buttonHeight;
+ local text1RelPoint, text2Point, text2JustifyH;
+ local showingBigEvents = numViewableEvents <= CALENDAR_DAYBUTTON_MAX_VISIBLE_BIGEVENTS;
+ if ( numViewableEvents > 0 ) then
+ if ( showingBigEvents ) then
+ buttonHeight = CALENDAR_DAYEVENTBUTTON_BIGHEIGHT;
+ --text1RelPoint = nil;
+ text2Point = "BOTTOMLEFT";
+ text2JustifyH = "LEFT";
+ else
+ if ( numViewableEvents > CALENDAR_DAYBUTTON_MAX_VISIBLE_EVENTS ) then
+ -- we have more viewable events than we have buttons
+ moreEventsButton:Show();
+ end
+ buttonHeight = CALENDAR_DAYEVENTBUTTON_HEIGHT;
+ text1RelPoint = "BOTTOMLEFT";
+ text2Point = "RIGHT";
+ text2JustifyH = "RIGHT";
+ end
+ end
+
+ -- second pass:
+ -- record the first event button
+ -- show viewable events
+ local firstEventButton;
+ local eventIndex = 1;
+ local eventButtonIndex = 1;
+ local eventButton, eventButtonName, eventButtonBackground, eventButtonText1, eventButtonText2, eventColor;
+ local prevEventButton;
+ while ( eventButtonIndex <= CALENDAR_DAYBUTTON_MAX_VISIBLE_EVENTS and eventIndex <= numEvents ) do
+ eventButton = _G[dayButtonName.."EventButton"..eventButtonIndex];
+ eventButtonName = eventButton:GetName();
+ eventButtonText1 = _G[eventButtonName.."Text1"];
+ eventButtonText2 = _G[eventButtonName.."Text2"];
+
+ local title, hour, minute, calendarType, sequenceType, eventType, texture,
+ modStatus, inviteStatus, invitedBy, difficulty, inviteType,
+ sequenceIndex, numSequenceDays, difficultyName = CalendarGetDayEvent(monthOffset, day, eventIndex);
+ if ( title and sequenceType ~= "ONGOING" ) then
+ -- set the event button if the sequence type is not ongoing
+
+ -- record the event Index
+ eventButton.eventIndex = eventIndex;
+
+ -- set the event button size
+ eventButton:SetHeight(buttonHeight);
+ -- set the event time and title
+ if ( calendarType == "HOLIDAY" ) then
+ -- any event that does not display the time should go here
+ eventButtonText2:Hide();
+ eventButtonText1:SetFormattedText(CALENDAR_CALENDARTYPE_NAMEFORMAT[calendarType][sequenceType], title);
+ eventButtonText1:ClearAllPoints();
+ eventButtonText1:SetAllPoints(eventButton);
+ eventButtonText1:Show();
+ elseif ( calendarType == "RAID_LOCKOUT" or calendarType == "RAID_RESET" ) then
+ eventButtonText2:Hide();
+ title = GetDungeonNameWithDifficulty(title, difficultyName);
+ eventButtonText1:SetFormattedText(CALENDAR_CALENDARTYPE_NAMEFORMAT[calendarType][sequenceType], title);
+ eventButtonText1:ClearAllPoints();
+ eventButtonText1:SetAllPoints(eventButton);
+ eventButtonText1:Show();
+ else
+ eventButtonText2:SetText(GameTime_GetFormattedTime(hour, minute, showingBigEvents));
+ eventButtonText2:ClearAllPoints();
+ eventButtonText2:SetPoint(text2Point, eventButton, text2Point);
+ eventButtonText2:SetJustifyH(text2JustifyH);
+ eventButtonText2:Show();
+ eventButtonText1:SetFormattedText(CALENDAR_CALENDARTYPE_NAMEFORMAT[calendarType][sequenceType], title);
+ eventButtonText1:ClearAllPoints();
+ eventButtonText1:SetPoint("TOPLEFT", eventButton, "TOPLEFT");
+ if ( text1RelPoint ) then
+ eventButtonText1:SetPoint("BOTTOMRIGHT", eventButtonText2, text1RelPoint);
+ end
+ eventButtonText1:Show();
+ end
+ -- set the event color
+ eventColor = _CalendarFrame_GetEventColor(calendarType, modStatus, inviteStatus);
+ eventButtonText1:SetTextColor(eventColor.r, eventColor.g, eventColor.b);
+
+ -- anchor the event button
+ eventButton:SetPoint("BOTTOMLEFT", dayButton, "BOTTOMLEFT", CALENDAR_DAYEVENTBUTTON_XOFFSET, -CALENDAR_DAYEVENTBUTTON_YOFFSET);
+ if ( prevEventButton ) then
+ -- anchor the prev event button to this one...this makes the latest event stay at the bottom
+ prevEventButton:SetPoint("BOTTOMLEFT", eventButton, "TOPLEFT", 0, -CALENDAR_DAYEVENTBUTTON_YOFFSET);
+ end
+ prevEventButton = eventButton;
+
+ -- highlight the selected event
+ if ( selectedEventIndex and eventIndex == selectedEventIndex ) then
+ CalendarFrame_SetSelectedEvent(eventButton);
+ else
+ -- only unlock the highlight if this is not the context event
+ if ( not contextEventIndex or eventIndex ~= contextEventIndex ) then
+ eventButton:UnlockHighlight();
+ end
+ end
+
+ -- show the event button
+ eventButton:Show();
+
+ -- record the first event button
+ firstEventButton = firstEventButton or eventButton;
+
+ eventButtonIndex = eventButtonIndex + 1;
+ end
+
+ eventIndex = eventIndex + 1;
+ end
+ -- hide unused event buttons
+ while ( eventButtonIndex <= CALENDAR_DAYBUTTON_MAX_VISIBLE_EVENTS ) do
+ eventButton = _G[dayButtonName.."EventButton"..eventButtonIndex];
+ eventButton.eventIndex = nil;
+ eventButton:Hide();
+ eventButtonIndex = eventButtonIndex + 1;
+ end
+
+ -- update day textures
+ CalendarFrame_UpdateDayTextures(dayButton, numEvents, firstEventButton, firstHolidayIndex);
+end
+
+function CalendarFrame_UpdateDayTextures(dayButton, numEvents, firstEventButton, firstHolidayIndex)
+ local dayButtonName = dayButton:GetName();
+
+-- local dateBackground = _G[dayButtonName.."DateFrameBackground"];
+-- if ( dayButton.numViewableEvents > 0 ) then
+-- dateBackground:Show();
+-- else
+-- dateBackground:Hide();
+-- end
+
+ local monthOffset, day = dayButton.monthOffset, dayButton.day;
+ local texturePath, tcoords;
+
+ -- set event textures
+ local eventBackground = _G[dayButtonName.."EventBackgroundTexture"];
+ local eventTex = _G[dayButtonName.."EventTexture"];
+ if ( firstEventButton ) then
+ dayButton.firstEventButton = firstEventButton;
+
+ -- anchor the top of the event background to the first event button since it is always
+ -- the highest button
+ eventBackground:SetPoint("TOP", firstEventButton, "TOP", 0, 40);
+ eventBackground:SetPoint("BOTTOM", dayButton, "BOTTOM");
+ eventBackground:Show();
+
+ -- set day texture
+ local title, hour, minute, calendarType, sequenceType, eventType, texture =
+ CalendarGetDayEvent(monthOffset, day, firstEventButton.eventIndex);
+ eventTex:SetTexture();
+ if ( CALENDAR_USE_SEQUENCE_FOR_EVENT_TEXTURE ) then
+ texturePath, tcoords = _CalendarFrame_GetTextureFile(texture, calendarType, sequenceType, eventType);
+ else
+ texturePath, tcoords = _CalendarFrame_GetTextureFile(texture, calendarType, "", eventType);
+ end
+ if ( texturePath ) then
+ eventTex:SetTexture(texturePath);
+ eventTex:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ eventTex:Show();
+ else
+ eventTex:Hide();
+ end
+ else
+ eventBackground:Hide();
+ eventTex:Hide();
+ dayButton.firstEventButton = nil;
+ end
+
+ -- set overlay texture
+ local overlayTex = _G[dayButtonName.."OverlayFrameTexture"];
+ if ( firstHolidayIndex ) then
+ -- for now, the overlay texture is the first holiday's sequence texture
+ local title, hour, minute, calendarType, sequenceType, eventType, texture,
+ modStatus, inviteStatus, invitedBy, difficulty, inviteType,
+ sequenceIndex, numSequenceDays = CalendarGetDayEvent(monthOffset, day, firstHolidayIndex);
+-- local sequenceIndex, numSequenceDays, sequenceType = CalendarGetDayEventSequenceInfo(monthOffset, day, firstHolidayIndex);
+ if ( numSequenceDays > 2 ) then
+ -- by art/design request, we're not going to show sequence textures if the sequence only lasts up to 2 days
+ overlayTex:SetTexture();
+ if ( CALENDAR_USE_SEQUENCE_FOR_OVERLAY_TEXTURE ) then
+ texturePath, tcoords = _CalendarFrame_GetTextureFile(texture, calendarType, sequenceType, eventType);
+ else
+ texturePath, tcoords = _CalendarFrame_GetTextureFile(texture, calendarType, "ONGOING", eventType);
+ end
+ if ( texturePath ) then
+ overlayTex:SetTexture(texturePath);
+ overlayTex:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ overlayTex:GetParent():Show();
+ return;
+ end
+ end
+ end
+ overlayTex:GetParent():Hide();
+end
+
+function CalendarFrame_SetSelectedDay(dayButton)
+ local prevSelectedDayButton = CalendarFrame.selectedDayButton;
+ if ( prevSelectedDayButton ) then
+ prevSelectedDayButton:UnlockHighlight();
+ prevSelectedDayButton:GetHighlightTexture():SetAlpha(CALENDAR_DAYBUTTON_HIGHLIGHT_ALPHA);
+ end
+ dayButton:LockHighlight();
+ dayButton:GetHighlightTexture():SetAlpha(CALENDAR_DAYBUTTON_SELECTION_ALPHA);
+ CalendarFrame.selectedDayButton = dayButton;
+
+ -- highlight the weekday label at this point too
+ local weekdayBackground = _G["CalendarWeekday".._CalendarFrame_GetDayOfWeek(dayButton:GetID()).."Background"];
+ CalendarWeekdaySelectedTexture:ClearAllPoints();
+ CalendarWeekdaySelectedTexture:SetPoint("CENTER", weekdayBackground, "CENTER");
+ CalendarWeekdaySelectedTexture:Show();
+end
+
+function CalendarFrame_SetToday(dayButton)
+ --CalendarTodayTexture:SetParent(dayButton);
+ --CalendarTodayTexture:ClearAllPoints();
+ --CalendarTodayTexture:SetPoint("CENTER", anchor, "CENTER");
+ --CalendarTodayTexture:Show();
+ CalendarTodayFrame:SetParent(dayButton);
+ CalendarTodayFrame:ClearAllPoints();
+ CalendarTodayFrame:SetPoint("CENTER", dayButton, "CENTER");
+ CalendarTodayFrame:Show();
+ local darkFrame = _G[dayButton:GetName().."DarkFrame"];
+ CalendarTodayFrame:SetFrameLevel(darkFrame:GetFrameLevel() + 1);
+end
+
+function CalendarTodayFrame_OnUpdate(self, elapsed)
+ self.timer = self.timer - elapsed;
+ if (self.timer < 0) then
+ self.timer = self.fadeTime;
+ if (self.fadein) then
+ self.fadein = false;
+ else
+ self.fadein = true;
+ end
+ else
+ if (self.fadein) then
+ CalendarTodayTextureGlow:SetAlpha(1-(self.timer/self.fadeTime));
+ else
+ CalendarTodayTextureGlow:SetAlpha(self.timer/self.fadeTime);
+ end
+ end
+end
+
+function CalendarFrame_SetLastDay(dayButton, day)
+ CalendarLastDayDarkTexture:SetParent(dayButton);
+ CalendarLastDayDarkTexture:ClearAllPoints();
+ CalendarLastDayDarkTexture:SetPoint("BOTTOMRIGHT", dayButton, "BOTTOMRIGHT");
+ CalendarLastDayDarkTexture:Show();
+end
+
+function CalendarFrame_SetSelectedEvent(eventButton)
+ if ( CalendarFrame.selectedEventButton ) then
+ CalendarFrame.selectedEventButton:UnlockHighlight();
+ CalendarFrame.selectedEventButton.black:Hide();
+ end
+ CalendarFrame.selectedEventButton = eventButton;
+ if ( CalendarFrame.selectedEventButton ) then
+ CalendarFrame.selectedEventButton:LockHighlight();
+ CalendarFrame.selectedEventButton.black:Show();
+ end
+end
+
+function CalendarFrame_OpenEvent(dayButton, eventIndex)
+ local day = dayButton.day;
+ local monthOffset = dayButton.monthOffset;
+ CalendarOpenEvent(monthOffset, day, eventIndex);
+end
+
+function CalendarFrame_CloseEvent()
+ CalendarCloseEvent();
+ CalendarFrame_HideEventFrame();
+ CalendarDayEventButton_Click();
+end
+
+function CalendarFrame_OffsetMonth(offset)
+ CalendarSetMonth(offset);
+ CalendarContextMenu_Hide();
+ StaticPopup_Hide("CALENDAR_DELETE_EVENT");
+ CalendarEventPickerFrame_Hide();
+ CalendarTexturePickerFrame_Hide();
+ CalendarFrame_Update();
+end
+
+function CalendarFrame_UpdateMonthOffsetButtons()
+ if ( CalendarFrame_GetModal() ) then
+ CalendarPrevMonthButton:Disable();
+ CalendarNextMonthButton:Disable();
+ return;
+ end
+
+ local testWeekday, testMonth, testDay, testYear = CalendarGetMinDate();
+ CalendarPrevMonthButton:Enable();
+ if ( CalendarFrame.viewedYear <= testYear ) then
+ if ( CalendarFrame.viewedMonth <= testMonth ) then
+ CalendarPrevMonthButton:Disable();
+ end
+ end
+ -- the max create date is the max date we're going to allow people to view
+ testWeekday, testMonth, testDay, testYear = CalendarGetMaxCreateDate();
+ CalendarNextMonthButton:Enable();
+ if ( CalendarFrame.viewedYear >= testYear ) then
+ if ( CalendarFrame.viewedMonth >= testMonth ) then
+ CalendarNextMonthButton:Disable();
+ end
+ end
+end
+
+function CalendarPrevMonthButton_OnClick()
+ PlaySound("igAbiliityPageTurn");
+ CalendarFrame_OffsetMonth(-1);
+end
+
+function CalendarNextMonthButton_OnClick()
+ PlaySound("igAbiliityPageTurn");
+ CalendarFrame_OffsetMonth(1);
+end
+
+function CalendarFilterButton_OnClick(self)
+ ToggleDropDownMenu(1, nil, CalendarFilterDropDown, self, 0, 0);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+function CalendarFilterDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, CalendarFilterDropDown_Initialize);
+ UIDropDownMenu_SetText(self, CALENDAR_FILTERS);
+ UIDropDownMenu_SetAnchor(self, 0, 0, "TOPRIGHT", CalendarFilterButton, "BOTTOMRIGHT");
+end
+
+function CalendarFilterDropDown_Initialize(self)
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.keepShownOnClick = 1;
+ for index, value in next, CALENDAR_FILTER_CVARS do
+ info.text = value.text;
+ info.func = CalendarFilterDropDown_OnClick;
+ if ( GetCVarBool(value.cvar) ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function CalendarFilterDropDown_OnClick(self)
+ SetCVar(CALENDAR_FILTER_CVARS[self:GetID()].cvar, UIDropDownMenuButton_GetChecked(self));
+ CalendarFrame_Update();
+end
+
+function CalendarFrame_UpdateFilter()
+ if ( CalendarFrame_GetModal() ) then
+ HideDropDownMenu(1);
+ CalendarFilterButton:Disable();
+ else
+ CalendarFilterButton:Enable();
+ end
+end
+
+
+-- Modal Dialog Support
+
+function CalendarFrame_PushModal(frame)
+ local numModalDialogs = #CalendarModalStack;
+ local changed = numModalDialogs == 0 or CalendarModalStack[numModalDialogs] ~= frame;
+ if ( changed and frame ) then
+ tinsert(CalendarModalStack, frame);
+ CalendarModalDummy:SetParent(frame);
+ CalendarModalDummy:SetFrameLevel(frame:GetFrameLevel() - 1);
+ CalendarModalDummy_Show();
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+end
+
+function CalendarFrame_PopModal(popAll)
+ local numModalDialogs = #CalendarModalStack;
+ if ( numModalDialogs > 0 ) then
+ if ( popAll ) then
+ wipe(CalendarModalStack);
+ else
+ tremove(CalendarModalStack);
+ end
+
+ numModalDialogs = #CalendarModalStack;
+ if ( numModalDialogs == 0 ) then
+ -- if we have no more modal dialogs, undo the modal state...
+ CalendarModalDummy:SetParent(CalendarFrame);
+ --CalendarModalDummy:SetFrameLevel(CalendarFrame:GetFrameLevel());
+ CalendarModalDummy_Hide();
+ else
+ --...otherwise reparent to the new top
+ local top = CalendarModalStack[numModalDialogs];
+ CalendarModalDummy:SetParent(top);
+ CalendarModalDummy:SetFrameLevel(top:GetFrameLevel() - 1);
+ CalendarModalDummy_Show();
+ end
+ PlaySound("igMainMenuQuit");
+ end
+end
+
+function CalendarFrame_GetModal()
+ return CalendarModalStack[#CalendarModalStack];
+end
+
+function CalendarModalDummy_Show(self)
+ CalendarFrameModalOverlay:Show();
+ CalendarEventFrameBlocker:Show();
+ CalendarFrame_UpdateMonthOffsetButtons();
+ CalendarFrame_UpdateFilter();
+ CalendarClassButtonContainer_Update();
+ CalendarModalDummy:Show();
+end
+
+function CalendarModalDummy_Hide(self)
+ CalendarFrameModalOverlay:Hide();
+ CalendarEventFrameBlocker:Hide();
+ CalendarFrame_UpdateMonthOffsetButtons();
+ CalendarFrame_UpdateFilter();
+ CalendarClassButtonContainer_Update();
+ CalendarModalDummy:Hide();
+end
+
+function CalendarEventFrameBlocker_OnShow(self)
+ local eventFrame = CalendarFrame_GetEventFrame();
+ if ( eventFrame and eventFrame:IsShown() ) then
+ -- can't do SetAllPoints because the eventFrame anchors haven't been determined yet
+ --CalendarEventFrameBlocker:SetAllPoints(eventFrame);
+ CalendarEventFrameBlocker:SetWidth(eventFrame:GetWidth());
+ CalendarEventFrameBlocker:SetHeight(eventFrame:GetHeight());
+
+ local eventFrameOverlay = _G[eventFrame:GetName().."ModalOverlay"];
+ if ( eventFrameOverlay ) then
+ eventFrameOverlay:Show();
+ end
+ else
+ CalendarEventFrameBlocker:Hide();
+ end
+end
+
+function CalendarEventFrameBlocker_OnHide(self)
+ local eventFrame = CalendarFrame_GetEventFrame();
+ if ( eventFrame ) then
+ local eventFrameOverlay = _G[eventFrame:GetName().."ModalOverlay"];
+ if ( eventFrameOverlay ) then
+ eventFrameOverlay:Hide();
+ end
+ end
+end
+
+function CalendarEventFrameBlocker_Update()
+ local eventFrame = CalendarFrame_GetEventFrame();
+ if ( CalendarFrame_GetModal() ) then
+ if ( eventFrame and eventFrame:IsShown() ) then
+ -- can't do SetAllPoints because the eventFrame anchors haven't been determined yet
+ --CalendarEventFrameBlocker:SetAllPoints(eventFrame);
+ CalendarEventFrameBlocker:SetWidth(eventFrame:GetWidth());
+ CalendarEventFrameBlocker:SetHeight(eventFrame:GetHeight());
+ CalendarEventFrameBlocker:Show();
+
+ local eventFrameOverlay = _G[eventFrame:GetName().."ModalOverlay"];
+ if ( eventFrameOverlay ) then
+ eventFrameOverlay:Show();
+ end
+ end
+ else
+ if ( eventFrame ) then
+ local eventFrameOverlay = _G[eventFrame:GetName().."ModalOverlay"];
+ if ( eventFrameOverlay ) then
+ eventFrameOverlay:Hide();
+ end
+ end
+ CalendarEventFrameBlocker:Hide();
+ end
+end
+
+
+-- CalendarContextMenu
+
+function CalendarContextMenu_Show(attachFrame, func, anchorName, xOffset, yOffset, ...)
+ local uiScale;
+ local uiParentScale = UIParent:GetScale();
+ if ( GetCVarBool("useUIScale") ) then
+ uiScale = tonumber(GetCVar("uiscale"));
+ if ( uiParentScale < uiScale ) then
+ uiScale = uiParentScale;
+ end
+ else
+ uiScale = uiParentScale;
+ end
+ --CalendarContextMenu:SetScale(uiScale);
+
+ local point = "TOPLEFT";
+ local relativePoint = "BOTTOMLEFT";
+ local relativeTo;
+ if ( anchorName == "cursor" ) then
+ relativeTo = nil;
+ local cursorX, cursorY = GetCursorPosition();
+ cursorX = cursorX / uiScale;
+ cursorY = cursorY / uiScale;
+
+ if ( not xOffset ) then
+ xOffset = 0;
+ end
+ if ( not yOffset ) then
+ yOffset = 0;
+ end
+ xOffset = cursorX + xOffset;
+ yOffset = cursorY + yOffset;
+ else
+ relativeTo = anchorName;
+ end
+ local subMenu = _G[CalendarContextMenu.subMenu];
+ if ( subMenu ) then
+ subMenu:Hide();
+ end
+ CalendarContextMenu:ClearAllPoints();
+ CalendarContextMenu:SetPoint(point, relativeTo, relativePoint, xOffset, yOffset);
+ CalendarContextMenu.attachFrame = attachFrame;
+ CalendarContextMenu.func = func;
+ if ( func(CalendarContextMenu, ...) ) then
+ CalendarContextMenu:Show();
+ else
+ CalendarContextMenu:Hide();
+ end
+end
+
+function CalendarContextMenu_Toggle(attachFrame, func, anchorName, xOffset, yOffset, ...)
+ if ( CalendarContextMenu:IsShown() ) then
+ if ( not func or func == CalendarContextMenu.func ) then
+ CalendarContextMenu_Hide();
+ else
+ CalendarContextMenu_Show(attachFrame, func, anchorName, xOffset, yOffset, ...);
+ end
+ else
+ CalendarContextMenu_Show(attachFrame, func, anchorName, xOffset, yOffset, ...);
+ end
+end
+
+function CalendarContextMenu_Hide(func)
+ if ( not func or func == CalendarContextMenu.func ) then
+ CalendarContextMenu:Hide();
+ end
+end
+
+function CalendarContextMenu_Reset()
+ CalendarContextMenu.func = nil;
+ CalendarContextMenu.dayButton = nil;
+ CalendarContextMenu.eventButton = nil;
+end
+
+function CalendarContextMenu_OnLoad(self)
+ self:RegisterEvent("GUILD_ROSTER_UPDATE");
+ self:RegisterEvent("PLAYER_GUILD_UPDATE");
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+end
+
+function CalendarContextMenu_OnEvent(self, event, ...)
+ if ( event == "GUILD_ROSTER_UPDATE" or event == "PLAYER_GUILD_UPDATE" ) then
+ CalendarDayContextMenu_RefreshEvent();
+ end
+end
+
+function CalendarContextMenu_OnHide(self)
+ -- fail safe: unlock old highlights
+ CalendarDayContextMenu_UnlockHighlights();
+ CalendarInviteContextMenu_UnlockHighlights();
+ -- fail safe: always hide nested menus
+ CalendarArenaTeamContextMenu:Hide();
+ CalendarInviteStatusContextMenu:Hide();
+end
+
+
+-- CalendarDayContextMenu
+
+function CalendarDayContextMenu_Initialize(self, flags, dayButton, eventButton)
+ UIMenu_Initialize(self);
+
+ -- unlock old highlights
+ CalendarDayContextMenu_UnlockHighlights();
+
+ -- record the new day and event buttons
+ self.dayButton = dayButton;
+ self.eventButton = eventButton;
+ self.flags = flags;
+
+ local day = dayButton.day;
+ local monthOffset = dayButton.monthOffset;
+ local month, year = CalendarGetMonth(monthOffset);
+
+ -- record whether or not
+ local isTodayOrLater = _CalendarFrame_IsTodayOrLater(month, day, year);
+ local isAfterMaxDate = _CalendarFrame_IsAfterMaxCreateDate(month, day, year);
+ local validCreationDate = isTodayOrLater and not isAfterMaxDate;
+
+ local canPaste = validCreationDate and CalendarContextEventClipboard();
+
+ local showDay = validCreationDate and band(flags, CALENDAR_CONTEXTMENU_FLAG_SHOWDAY) ~= 0;
+ local showEvent = eventButton and band(flags, CALENDAR_CONTEXTMENU_FLAG_SHOWEVENT) ~= 0;
+
+ local needSpacer = false;
+ if ( showDay ) then
+ -- add guild selections if the player has a guild
+ UIMenu_AddButton(self, CALENDAR_CREATE_EVENT, nil, CalendarDayContextMenu_CreateEvent);
+ if ( CanEditGuildEvent() ) then
+-- UIMenu_AddButton(self, CALENDAR_CREATE_GUILDWIDE_EVENT, nil, CalendarDayContextMenu_CreateGuildWideEvent);
+ UIMenu_AddButton(self, CALENDAR_CREATE_GUILD_EVENT, nil, CalendarDayContextMenu_CreateGuildEvent);
+ UIMenu_AddButton(self, CALENDAR_CREATE_GUILD_ANNOUNCEMENT, nil, CalendarDayContextMenu_CreateGuildAnnouncement);
+ end
+--[[
+ -- add arena team selection if the player has an arena team
+ if ( IsInArenaTeam() ) then
+ --UIMenu_AddButton(self, CALENDAR_CREATE_ARENATEAM_EVENT, nil, nil, "CalendarArenaTeamContextMenu");
+ end
+--]]
+ needSpacer = true;
+ end
+
+ if ( showEvent ) then
+ local eventIndex = eventButton.eventIndex;
+ local title, hour, minute, calendarType, sequenceType, eventType, texture,
+ modStatus, inviteStatus, invitedBy, difficulty, inviteType = CalendarGetDayEvent(monthOffset, day, eventIndex);
+ -- add context items for the selected event
+ if ( _CalendarFrame_IsPlayerCreatedEvent(calendarType) ) then
+ if ( CalendarContextEventCanEdit(monthOffset, day, eventIndex) ) then
+ -- spacer
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ -- copy
+ UIMenu_AddButton(self, CALENDAR_COPY_EVENT, nil, CalendarDayContextMenu_CopyEvent);
+ -- paste
+ if ( canPaste ) then
+ UIMenu_AddButton(self, CALENDAR_PASTE_EVENT, nil, CalendarDayContextMenu_PasteEvent);
+ end
+ -- delete
+ UIMenu_AddButton(self, CALENDAR_DELETE_EVENT, nil, CalendarDayContextMenu_DeleteEvent);
+ needSpacer = true;
+ elseif ( canPaste ) then
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ -- paste
+ UIMenu_AddButton(self, CALENDAR_PASTE_EVENT, nil, CalendarDayContextMenu_PasteEvent);
+ needSpacer = true;
+ end
+ if ( calendarType ~= "GUILD_ANNOUNCEMENT" ) then
+ if ( validCreationDate and _CalendarFrame_CanInviteeRSVP(inviteStatus) ) then
+ -- spacer
+ if ( _CalendarFrame_IsSignUpEvent(calendarType, inviteType) ) then
+ if ( inviteStatus == CALENDAR_INVITESTATUS_NOT_SIGNEDUP ) then
+ -- sign up
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ UIMenu_AddButton(self, CALENDAR_SIGNUP, nil, CalendarDayContextMenu_SignUp);
+ else
+ -- cancel sign up
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ UIMenu_AddButton(self, CALENDAR_REMOVE_SIGNUP, nil, CalendarDayContextMenu_RemoveInvite);
+ end
+ else
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ -- accept invitation
+ if ( inviteStatus ~= CALENDAR_INVITESTATUS_ACCEPTED ) then
+ UIMenu_AddButton(self, CALENDAR_ACCEPT_INVITATION, nil, CalendarDayContextMenu_AcceptInvite);
+ end
+ -- tentative invitation
+ if ( inviteStatus ~= CALENDAR_INVITESTATUS_TENTATIVE ) then
+ UIMenu_AddButton(self, CALENDAR_TENTATIVE_INVITATION, nil, CalendarDayContextMenu_TentativeInvite);
+ end
+ -- decline invitation
+ if ( inviteStatus ~= CALENDAR_INVITESTATUS_DECLINED ) then
+ UIMenu_AddButton(self, CALENDAR_DECLINE_INVITATION, nil, CalendarDayContextMenu_DeclineInvite);
+ end
+ end
+ needSpacer = false;
+ end
+ if ( _CalendarFrame_CanRemoveEvent(modStatus, calendarType, inviteType, inviteStatus) ) then
+ -- spacer
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ -- remove event
+ UIMenu_AddButton(self, CALENDAR_REMOVE_INVITATION, nil, CalendarDayContextMenu_RemoveInvite);
+ needSpacer = true;
+ end
+ end
+ if ( CalendarContextEventCanComplain(monthOffset, day, eventIndex) ) then
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ -- report spam
+ UIMenu_AddButton(self, REPORT_SPAM, nil, CalendarDayContextMenu_ReportSpam);
+ needSpacer = true;
+ end
+ elseif ( canPaste ) then
+ -- add paste if we have a clipboard
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ UIMenu_AddButton(self, CALENDAR_PASTE_EVENT, nil, CalendarDayContextMenu_PasteEvent);
+ end
+ elseif ( canPaste ) then
+ -- add paste if we have a clipboard
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ UIMenu_AddButton(self, CALENDAR_PASTE_EVENT, nil, CalendarDayContextMenu_PasteEvent);
+ end
+
+ if ( UIMenu_FinishInitializing(self) ) then
+ -- lock new highlights
+ if ( dayButton ) then
+ dayButton:LockHighlight();
+ end
+ if ( eventButton ) then
+ -- if we're highlighting an event, then register it with the context selection system
+ CalendarContextSelectEvent(monthOffset, day, eventButton.eventIndex);
+ eventButton:LockHighlight();
+ end
+ return true;
+ else
+ -- show an error if they summoned a context menu that they could not create an event for, and
+ -- there are no buttons on the context menu
+ if ( not isTodayOrLater ) then
+ StaticPopup_Show("CALENDAR_ERROR", CALENDAR_ERROR_CREATEDATE_BEFORE_TODAY);
+ elseif ( isAfterMaxDate ) then
+ StaticPopup_Show("CALENDAR_ERROR", format(CALENDAR_ERROR_CREATEDATE_AFTER_MAX, _CalendarFrame_GetFullDate(CalendarGetMaxCreateDate())));
+ end
+ return false;
+ end
+end
+
+function CalendarDayContextMenu_RefreshEvent()
+ -- this function assumes that the CalendarContextMenu is already attached to an event
+ local menu = CalendarContextMenu;
+ if ( menu:IsShown() and menu.func == CalendarDayContextMenu_Initialize ) then
+ CalendarContextMenu_Show(menu.attachFrame, menu.func, "cursor", 3, -3, menu.flags, menu.dayButton, menu.eventButton);
+ end
+end
+
+function CalendarDayContextMenu_UnlockHighlights()
+ local dayButton = CalendarContextMenu.dayButton;
+ local eventButton = CalendarContextMenu.eventButton;
+ if ( dayButton and
+ dayButton ~= CalendarFrame.selectedDayButton and
+ dayButton ~= GameTooltip:GetOwner() ) then
+ dayButton:UnlockHighlight();
+ end
+ if ( eventButton and
+ eventButton ~= CalendarFrame.selectedEventButton and
+ eventButton ~= CalendarEventPickerFrame.selectedEventButton ) then
+ eventButton:UnlockHighlight();
+ end
+end
+
+function CalendarDayContextMenu_CreateEvent()
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+ CalendarCloseEvent();
+ CalendarFrame_HideEventFrame();
+ CalendarDayButton_Click(CalendarContextMenu.dayButton);
+
+ CalendarNewEvent();
+ CalendarCreateEventFrame.mode = "create";
+ CalendarCreateEventFrame.dayButton = CalendarContextMenu.dayButton;
+ CalendarFrame_ShowEventFrame(CalendarCreateEventFrame);
+end
+
+function CalendarDayContextMenu_CreateGuildAnnouncement()
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+ CalendarCloseEvent();
+ CalendarFrame_HideEventFrame();
+ CalendarDayButton_Click(CalendarContextMenu.dayButton);
+
+ CalendarNewGuildAnnouncement();
+ CalendarCreateEventFrame.mode = "create";
+ CalendarCreateEventFrame.dayButton = CalendarContextMenu.dayButton;
+ CalendarFrame_ShowEventFrame(CalendarCreateEventFrame);
+end
+
+function CalendarDayContextMenu_CreateGuildEvent()
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+ CalendarCloseEvent();
+ CalendarFrame_HideEventFrame();
+ CalendarDayButton_Click(CalendarContextMenu.dayButton);
+
+ CalendarNewGuildEvent();
+ CalendarCreateEventFrame.mode = "create";
+ CalendarCreateEventFrame.dayButton = CalendarContextMenu.dayButton;
+ CalendarFrame_ShowEventFrame(CalendarCreateEventFrame);
+end
+
+function CalendarDayContextMenu_CopyEvent()
+ CalendarContextEventCopy();
+end
+
+function CalendarDayContextMenu_PasteEvent()
+ local dayButton = CalendarContextMenu.dayButton;
+ CalendarContextEventPaste(dayButton.monthOffset, dayButton.day);
+end
+
+function CalendarDayContextMenu_DeleteEvent()
+ local text;
+ local calendarType = CalendarContextEventGetCalendarType();
+ if ( calendarType == "GUILD_ANNOUNCEMENT" ) then
+ text = CALENDAR_DELETE_ANNOUNCEMENT_CONFIRM;
+ elseif ( calendarType == "GUILD_EVENT" ) then
+ text = CALENDAR_DELETE_GUILD_EVENT_CONFIRM;
+ else
+ text = CALENDAR_DELETE_EVENT_CONFIRM;
+ end
+ StaticPopup_Show("CALENDAR_DELETE_EVENT", text);
+end
+
+function CalendarDayContextMenu_ReportSpam()
+ CalendarContextEventComplain();
+end
+
+function CalendarDayContextMenu_AcceptInvite()
+ CalendarContextInviteAvailable();
+end
+
+function CalendarDayContextMenu_TentativeInvite()
+ CalendarContextInviteTentative();
+end
+
+function CalendarDayContextMenu_DeclineInvite()
+ CalendarContextInviteDecline();
+end
+
+function CalendarDayContextMenu_RemoveInvite()
+ CalendarContextInviteRemove();
+end
+
+function CalendarDayContextMenu_SignUp()
+ CalendarContextEventSignUp();
+end
+
+function CalendarArenaTeamContextMenu_OnLoad(self)
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+ -- get updated arena team info for the context menu
+ self:RegisterEvent("ARENA_TEAM_ROSTER_UPDATE");
+ for i = 1, MAX_ARENA_TEAMS do
+ ArenaTeamRoster(i);
+ end
+ self.parentMenu = "CalendarContextMenu";
+ self.onlyAutoHideSelf = true;
+end
+
+function CalendarArenaTeamContextMenu_OnShow(self)
+ CalendarArenaTeamContextMenu_Initialize(self);
+end
+
+function CalendarArenaTeamContextMenu_OnEvent(self, event, ...)
+ if ( event == "ARENA_TEAM_ROSTER_UPDATE" ) then
+ CalendarArenaTeamContextMenu_Initialize(self);
+ end
+end
+
+function CalendarArenaTeamContextMenu_Initialize(self)
+ UIMenu_Initialize(self);
+ local teamName, teamSize;
+ for i = 1, MAX_ARENA_TEAMS do
+ teamName, teamSize = GetArenaTeam(i);
+ if ( teamName ) then
+ UIMenu_AddButton(
+ CalendarArenaTeamContextMenu, -- menu
+ format(PVP_TEAMSIZE, teamSize, teamSize), -- text
+ nil, -- shortcut
+ CalendarArenaTeamContextMenuButton_OnClick_CreateArenaTeamEvent, -- func
+ nil, -- nested
+ i); -- value
+ end
+ end
+ return UIMenu_FinishInitializing(self);
+end
+
+function CalendarArenaTeamContextMenuButton_OnClick_CreateArenaTeamEvent(self)
+ -- hide parent menu
+ CalendarContextMenu_Hide(CalendarDayContextMenu_Initialize);
+ CalendarCloseEvent();
+ CalendarFrame_HideEventFrame();
+ CalendarDayButton_Click(CalendarContextMenu.dayButton)
+
+ CalendarNewArenaTeamEvent(self.value);
+ CalendarCreateEventFrame.mode = "create";
+ CalendarCreateEventFrame.dayButton = CalendarContextMenu.dayButton;
+ CalendarFrame_ShowEventFrame(CalendarCreateEventFrame);
+end
+
+
+-- CalendarDayButtonTemplate
+
+function CalendarDayButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+end
+
+function CalendarDayButton_OnEnter(self)
+ if ( not self.day ) then
+ -- not yet updated
+ return;
+ end
+
+ local monthOffset = self.monthOffset;
+ local day = self.day;
+ local numEvents = CalendarGetNumDayEvents(monthOffset, day);
+ if ( numEvents <= 0 ) then
+ return;
+ end
+
+ -- add events
+ local eventTime, eventColor;
+ local numShownEvents = 0;
+ for i = 1, numEvents do
+ local title, hour, minute, calendarType, sequenceType, eventType, texture,
+ modStatus, inviteStatus, invitedBy, difficulty, inviteType,
+ sequenceIndex, numSequenceDays, difficultyName = CalendarGetDayEvent(monthOffset, day, i);
+ if ( title and sequenceType ~= "ONGOING" ) then
+ if ( numShownEvents == 0 ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:ClearLines();
+
+ -- add date if we hit our first viewable event
+ local fullDate = format(FULLDATE, _CalendarFrame_GetFullDateFromDay(self));
+ GameTooltip:AddLine(fullDate, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(" ");
+ else
+ GameTooltip:AddLine(" ");
+ end
+
+ eventTime = GameTime_GetFormattedTime(hour, minute, true);
+ eventColor = _CalendarFrame_GetEventColor(calendarType, modStatus, inviteStatus);
+ if ( calendarType == "RAID_RESET" or calendarType == "RAID_LOCKOUT" ) then
+ title = GetDungeonNameWithDifficulty(title, difficultyName);
+ end
+ GameTooltip:AddDoubleLine(
+ format(CALENDAR_CALENDARTYPE_NAMEFORMAT[calendarType][sequenceType], title),
+ eventTime,
+ eventColor.r, eventColor.g, eventColor.b,
+ HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b,
+ 1
+ );
+ if ( _CalendarFrame_IsPlayerCreatedEvent(calendarType) ) then
+ local text;
+ if ( UnitIsUnit("player", invitedBy) ) then
+ if ( calendarType == "GUILD_ANNOUNCEMENT" ) then
+ text = CALENDAR_ANNOUNCEMENT_CREATEDBY_YOURSELF;
+ elseif ( calendarType == "GUILD_EVENT" ) then
+ text = CALENDAR_GUILDEVENT_INVITEDBY_YOURSELF;
+ else
+ text = CALENDAR_EVENT_INVITEDBY_YOURSELF;
+ end
+ else
+ if ( _CalendarFrame_IsSignUpEvent(calendarType, inviteType) ) then
+ local inviteStatusInfo = _CalendarFrame_SafeGetInviteStatusInfo(inviteStatus);
+ if ( inviteStatus == CALENDAR_INVITESTATUS_NOT_SIGNEDUP or
+ inviteStatus == CALENDAR_INVITESTATUS_SIGNEDUP ) then
+ text = inviteStatusInfo.name;
+ else
+ text = format(CALENDAR_SIGNEDUP_FOR_GUILDEVENT_WITH_STATUS, inviteStatusInfo.name);
+ end
+ else
+ if ( calendarType == "GUILD_ANNOUNCEMENT" ) then
+ text = format(CALENDAR_ANNOUNCEMENT_CREATEDBY_PLAYER, _CalendarFrame_SafeGetName(invitedBy));
+ else
+ text = format(CALENDAR_EVENT_INVITEDBY_PLAYER, _CalendarFrame_SafeGetName(invitedBy));
+ end
+ end
+ end
+ GameTooltip:AddLine(text, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+
+ numShownEvents = numShownEvents + 1;
+ end
+ end
+ if ( numShownEvents > 0 ) then
+ GameTooltip:Show();
+ end
+end
+
+function CalendarDayButton_OnLeave(self)
+ GameTooltip:Hide();
+ if ( self ~= CalendarFrame.selectedDayButton and
+ (not CalendarContextMenu:IsShown() or self ~= CalendarContextMenu.dayButton) ) then
+ self:UnlockHighlight();
+ end
+end
+
+function CalendarDayButton_OnClick(self, button)
+--[[
+ local month, year = CalendarGetMonth(self.monthOffset);
+ local dayChanged = month ~= CalendarFrame.selectedMonth or self.day ~= CalendarFrame.selectedDay or year ~= CalendarFrame.selectedYear;
+ CalendarDayButton_Click(self);
+
+ if ( button == "LeftButton" ) then
+ CalendarContextMenu_Hide();
+ elseif ( button == "RightButton" ) then
+ local flags = CALENDAR_CONTEXTMENU_FLAG_SHOWDAY;
+ if ( dayChanged ) then
+ CalendarContextMenu_Show(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, self);
+ else
+ CalendarContextMenu_Toggle(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, self);
+ end
+ end
+--]]
+ if ( self.firstEventButton ) then
+ CalendarDayEventButton_OnClick(self.firstEventButton, button);
+ else
+ if ( button == "LeftButton" ) then
+ local dayChanged = self ~= CalendarFrame.selectedDayButton;
+
+ CalendarDayButton_Click(self);
+ if ( dayChanged ) then
+ CalendarFrame_CloseEvent();
+ end
+ CalendarContextMenu_Hide();
+ elseif ( button == "RightButton" ) then
+ local dayChanged = self ~= CalendarContextMenu.dayButton;
+
+ local flags = CALENDAR_CONTEXTMENU_FLAG_SHOWDAY;
+ if ( dayChanged ) then
+ CalendarContextMenu_Show(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, self);
+ else
+ CalendarContextMenu_Toggle(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, self);
+ end
+ end
+ end
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+-- CalendarDayButton_Click allows the OnClick for a day and its event buttons to do some of the same processing
+function CalendarDayButton_Click(button)
+ -- close the event picker if it doesn't belong to this day
+ if ( CalendarEventPickerFrame.dayButton and CalendarEventPickerFrame.dayButton ~= button ) then
+ CalendarEventPickerFrame_Hide();
+ end
+
+ local day, monthOffset = button.day, button.monthOffset;
+ local month, year = CalendarGetMonth(monthOffset);
+ if ( day ~= CalendarFrame.selectedDay or month ~= CalendarFrame.selectedMonth or year ~= CalendarFrame.selectedYear ) then
+ -- a new day has been selected
+ CalendarFrame.selectedDay = day;
+ CalendarFrame.selectedMonth = month;
+ CalendarFrame.selectedYear = year;
+ CalendarFrame_SetSelectedDay(button);
+ end
+end
+
+function CalendarDayButtonMoreEventsButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+end
+
+function CalendarDayButtonMoreEventsButton_OnEnter(self)
+ local dayButton = self:GetParent();
+ CalendarDayButton_OnEnter(dayButton);
+ dayButton:LockHighlight();
+end
+
+function CalendarDayButtonMoreEventsButton_OnLeave(self)
+ local dayButton = self:GetParent();
+ CalendarDayButton_OnLeave(dayButton);
+end
+
+function CalendarDayButtonMoreEventsButton_OnClick(self, button)
+--[[
+ local dayButton = self:GetParent();
+ local dayChanged = CalendarFrame.selectedDayButton ~= dayButton;
+
+ CalendarDayButton_Click(dayButton);
+
+ if ( button == "LeftButton" ) then
+ CalendarEventPickerFrame_Toggle(dayButton);
+ elseif ( button == "RightButton" ) then
+ local flags = CALENDAR_CONTEXTMENU_FLAG_SHOWDAY;
+ if ( dayChanged ) then
+ CalendarContextMenu_Show(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton);
+ else
+ CalendarContextMenu_Toggle(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton);
+ end
+ end
+--]]
+ local dayButton = self:GetParent();
+
+ if ( button == "LeftButton" ) then
+ CalendarDayButton_Click(dayButton);
+ CalendarEventPickerFrame_Toggle(dayButton);
+ elseif ( button == "RightButton" ) then
+ local dayChanged = CalendarFrame.selectedDayButton ~= dayButton;
+
+ local flags = CALENDAR_CONTEXTMENU_FLAG_SHOWDAY;
+ if ( firstEventButton ) then
+ local eventChanged =
+ CalendarContextMenu.eventButton ~= self or
+ CalendarContextMenu.dayButton ~= dayButton;
+
+ local flags = CALENDAR_CONTEXTMENU_FLAG_SHOWDAY + CALENDAR_CONTEXTMENU_FLAG_SHOWEVENT;
+ if ( eventChanged ) then
+ CalendarContextMenu_Show(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton, self);
+ else
+ CalendarContextMenu_Toggle(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton, self);
+ end
+ flags = flags + CALENDAR_CONTEXTMENU_FLAG_SHOWEVENT;
+
+ else
+ if ( dayChanged ) then
+ CalendarContextMenu_Show(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton);
+ else
+ CalendarContextMenu_Toggle(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton);
+ end
+ end
+ end
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+
+-- CalendarDayEventButtonTemplate
+
+function CalendarDayEventButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self.black = _G[self:GetName().."Black"];
+ self.black:SetAlpha(0.7);
+end
+
+function CalendarDayEventButton_OnEnter(self)
+ local dayButton = self:GetParent();
+ CalendarDayButton_OnEnter(dayButton);
+ dayButton:LockHighlight();
+end
+
+function CalendarDayEventButton_OnLeave(self)
+ local dayButton = self:GetParent();
+ CalendarDayButton_OnLeave(dayButton);
+end
+
+function CalendarDayEventButton_OnClick(self, button)
+ local dayButton = self:GetParent();
+
+ if ( button == "LeftButton" ) then
+ CalendarDayButton_Click(dayButton);
+ CalendarDayEventButton_Click(self, true);
+ CalendarContextMenu_Hide();
+ elseif ( button == "RightButton" ) then
+ local eventChanged =
+ CalendarContextMenu.eventButton ~= self or
+ CalendarContextMenu.dayButton ~= dayButton;
+
+ local flags = CALENDAR_CONTEXTMENU_FLAG_SHOWDAY + CALENDAR_CONTEXTMENU_FLAG_SHOWEVENT;
+ if ( eventChanged ) then
+ CalendarContextMenu_Show(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton, self);
+ else
+ CalendarContextMenu_Toggle(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton, self);
+ end
+ end
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+function CalendarDayEventButton_Click(button, openEvent)
+ if ( not button ) then
+ StaticPopup_Hide("CALENDAR_DELETE_EVENT");
+ CalendarFrame_SetSelectedEvent();
+ return;
+ end
+
+ local dayButton = button:GetParent();
+ local day = dayButton.day;
+ local monthOffset = dayButton.monthOffset;
+ local eventIndex = button.eventIndex;
+ local selectedEventMonthOffset, selectedEventDay, selectedEventIndex = CalendarGetEventIndex();
+ if ( selectedEventIndex ~= eventIndex or selectedEventDay ~= day or selectedEventMonthOffset ~= monthOffset ) then
+ StaticPopup_Hide("CALENDAR_DELETE_EVENT");
+ end
+ CalendarFrame_SetSelectedEvent(button);
+
+ if ( openEvent ) then
+ CalendarFrame_OpenEvent(dayButton, eventIndex);
+ end
+end
+
+
+-- Calendar Misc Templates
+function CalendarTitleFrame_SetText(titleFrame, text)
+ local name = titleFrame:GetName();
+ local textFrame = _G[name.."Text"];
+ local middleFrame = _G[name.."BackgroundMiddle"];
+ textFrame:SetWidth(0);
+ textFrame:SetText(text);
+ middleFrame:SetWidth(min(240, max(140, textFrame:GetWidth())));
+ textFrame:SetWidth(middleFrame:GetWidth());
+end
+
+
+-- CalendarViewHolidayFrame
+
+function CalendarViewHolidayFrame_OnLoad(self)
+ self.update = CalendarViewHolidayFrame_Update;
+ CalendarViewHolidayInfoTexture:SetAlpha(0.4);
+end
+
+function CalendarViewHolidayFrame_OnShow(self)
+ CalendarViewHolidayFrame_Update();
+end
+
+function CalendarViewHolidayFrame_OnHide(self)
+end
+
+function CalendarViewHolidayFrame_Update()
+ local name, description, texture = CalendarGetHolidayInfo(CalendarGetEventIndex());
+ CalendarTitleFrame_SetText(CalendarViewHolidayTitleFrame, name);
+ CalendarViewHolidayDescription:SetText(description);
+ CalendarViewHolidayInfoTexture:SetTexture();
+ -- mschweitzer NOTE: we're going to use the default texture here until we can get real INFO art
+ local texture = CALENDAR_CALENDARTYPE_TEXTURES["HOLIDAY"]["INFO"];
+ local tcoords = CALENDAR_CALENDARTYPE_TCOORDS["HOLIDAY"];
+-- local texture, tcoords = _CalendarFrame_GetTextureFile(texture, "HOLIDAY", "INFO", 0);
+ if ( texture ) then
+ CalendarViewHolidayInfoTexture:SetTexture(texture);
+ CalendarViewHolidayInfoTexture:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ CalendarViewHolidayInfoTexture:Show();
+ else
+ CalendarViewHolidayInfoTexture:Hide();
+ end
+end
+
+
+-- CalendarViewRaidFrame
+
+function CalendarViewRaidFrame_OnLoad(self)
+ self.update = CalendarViewRaidFrame_Update;
+end
+
+function CalendarViewRaidFrame_OnShow(self)
+ CalendarViewRaidFrame_Update();
+end
+
+function CalendarViewRaidFrame_OnHide(self)
+end
+
+function CalendarViewRaidFrame_Update()
+ local name, calendarType, raidID, hour, minute, difficulty, difficultyName = CalendarGetRaidInfo(CalendarGetEventIndex());
+ name = GetDungeonNameWithDifficulty(name, difficultyName);
+ CalendarTitleFrame_SetText(CalendarViewRaidTitleFrame, name);
+ if ( calendarType == "RAID_LOCKOUT" ) then
+ CalendarViewRaidDescription:SetFormattedText(CALENDAR_RAID_LOCKOUT_DESCRIPTION, name, GameTime_GetFormattedTime(hour, minute, true));
+ else
+ -- calendarType should be "RAID_RESET"
+ CalendarViewRaidDescription:SetFormattedText(CALENDAR_RAID_RESET_DESCRIPTION, name, GameTime_GetFormattedTime(hour, minute, true));
+ end
+end
+
+
+-- Calendar Event Templates
+
+function CalendarEventCloseButton_OnClick(self)
+ CalendarContextMenu_Hide();
+ CalendarFrame_CloseEvent();
+ PlaySound("igMainMenuQuit");
+end
+
+function CalendarEventDescriptionScrollFrame_OnLoad(self)
+ ScrollFrame_OnLoad(self);
+
+ -- we need to mess with the size of the scroll bar and the position of the up and down buttons
+ -- in order to get the thumb texture to stop closer to the up and down buttons
+ -- first: resize the scrollbar
+ local scrollBar = _G[self:GetName().."ScrollBar"];
+ scrollBar:ClearAllPoints();
+ scrollBar:SetPoint("TOPLEFT", self, "TOPRIGHT", 0, -10);
+ scrollBar:SetPoint("BOTTOMLEFT", self, "BOTTOMRIGHT", 0, 10);
+ -- second: reposition the up and down buttons
+ _G[self:GetName().."ScrollBarScrollDownButton"]:SetPoint("TOP", scrollBar, "BOTTOM", 0, 4);
+ _G[self:GetName().."ScrollBarScrollUpButton"]:SetPoint("BOTTOM", scrollBar, "TOP", 0, -4);
+ -- now save off the scroll bar for convenience's sake
+ self.scrollBar = scrollBar;
+ -- make the scroll bar hideable and force it to start off hidden so positioning calculations can be done
+ -- as soon as it needs to be shown
+ self.scrollBarHideable = 1;
+ scrollBar:Hide();
+
+ -- register the addon loaded event for post-load fixups
+ self:RegisterEvent("ADDON_LOADED");
+ self:SetScript("OnEvent", CalendarEventDescriptionScrollFrame_OnEvent);
+end
+
+function CalendarEventDescriptionScrollFrame_OnEvent(self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local addonName = ...;
+ if ( not addonName or (addonName and addonName ~= "Blizzard_Calendar") ) then
+ return;
+ end
+
+ -- NOTE: this function expects the scroll frame to have a .content member, which should be the
+ -- stuff we're scrolling on (scroll frame's scroll child's frame)!
+ if ( self.content ) then
+ local scrollBar = self.scrollBar;
+ scrollBar.Show =
+ function (self)
+ local scrollFrame = self:GetParent();
+ -- adjust scroll frame width
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollFrame:GetParent(), "BOTTOMRIGHT", -4 - self:GetWidth(), 4);
+ scrollFrame:GetScrollChild():SetWidth(scrollFrame:GetWidth());
+ -- adjust content width
+ scrollFrame.content:SetWidth(scrollFrame.defaultContentWidth);
+ getmetatable(self).__index.Show(self);
+ end
+ scrollBar.Hide =
+ function (self)
+ local scrollFrame = self:GetParent();
+ -- adjust scroll frame width
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollFrame:GetParent(), "BOTTOMRIGHT", -4, 4);
+ scrollFrame:GetScrollChild():SetWidth(scrollFrame:GetWidth());
+ -- adjust content width
+ scrollFrame.content:SetWidth(scrollFrame.defaultContentWidth + self:GetWidth());
+ getmetatable(self).__index.Hide(self);
+ end
+
+ self.defaultContentWidth = self.content:GetWidth();
+ end
+
+ -- we don't need this event any more
+ self:UnregisterEvent(event)
+ end
+end
+
+function CalendarEventInviteList_OnLoad(self)
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(0.0, 0.0, 0.0, 0.9);
+
+ self.sortButtons = {
+ name = _G[self:GetName().."NameSortButton"],
+ class = _G[self:GetName().."ClassSortButton"],
+ status = _G[self:GetName().."StatusSortButton"],
+ };
+
+ -- register the addon loaded event for post-load fixups
+ self:RegisterEvent("ADDON_LOADED");
+ self:SetScript("OnEvent", CalendarEventInviteList_OnEvent);
+end
+
+function CalendarEventInviteList_OnEvent(self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local addonName = ...;
+ if ( not addonName or (addonName and addonName ~= "Blizzard_Calendar") ) then
+ return;
+ end
+
+ local scrollBar = self.scrollFrame.scrollBar;
+ scrollBar.Show =
+ function (self)
+ local scrollFrame = self:GetParent();
+ local scrollFrameParent = scrollFrame:GetParent();
+ local scrollBarWidth = scrollFrameParent.scrollBarWidth;
+ -- adjust scroll frame width
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollFrameParent, "BOTTOMRIGHT", -scrollBarWidth, 3);
+ scrollFrame.scrollChild:SetWidth(scrollFrame:GetWidth());
+ -- adjust button width
+ local buttonWidth = scrollFrameParent.defaultButtonWidth - scrollBarWidth;
+ for _, button in next, scrollFrame.buttons do
+ button:SetWidth(buttonWidth);
+ end
+ getmetatable(self).__index.Show(self);
+ end
+ scrollBar.Hide =
+ function (self)
+ local scrollFrame = self:GetParent();
+ local scrollFrameParent = scrollFrame:GetParent();
+ -- adjust scroll frame width
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollFrameParent, "BOTTOMRIGHT", 0, 3);
+ scrollFrame.scrollChild:SetWidth(scrollFrame:GetWidth());
+ -- adjust button width
+ local buttonWidth = scrollFrameParent.defaultButtonWidth;
+ for _, button in next, scrollFrame.buttons do
+ button:SetWidth(buttonWidth);
+ end
+ getmetatable(self).__index.Hide(self);
+ end
+
+ -- kinda cheesy...might wanna unify the create and view invite lists more at some point...
+ self.scrollFrame.update = _G[self.scrollFrame:GetName().."_Update"];
+ HybridScrollFrame_CreateButtons(self.scrollFrame, self:GetName().."ButtonTemplate");
+
+ self.scrollBarWidth = 25; -- looks better than actual scroll bar width
+ self.defaultButtonWidth = self.scrollFrame.buttons[1]:GetWidth() + self.scrollBarWidth;
+
+ -- we don't need this event any more
+ self:UnregisterEvent(event);
+ end
+end
+
+function CalendarEventInviteList_AnchorSortButtons(inviteList)
+ local scrollFrame = inviteList.scrollFrame;
+ if ( not scrollFrame.buttons or not scrollFrame.buttons[1] ) then
+ return;
+ end
+ local inviteButton = scrollFrame.buttons[1];
+ local inviteButtonName = inviteButton:GetName();
+
+ local nameSortButton = inviteList.sortButtons.name;
+ if ( inviteList.partyMode ) then
+ local inviteName = _G[inviteButtonName.."Name"];
+ nameSortButton:SetPoint("LEFT", inviteName, "LEFT");
+ else
+ local invitePartyIcon = _G[inviteButtonName.."PartyIcon"];
+ nameSortButton:SetPoint("LEFT", invitePartyIcon, "LEFT");
+ end
+
+ local classSortButton = inviteList.sortButtons.class;
+ local inviteClass = _G[inviteButtonName.."Class"];
+ classSortButton:SetPoint("LEFT", inviteClass, "LEFT");
+
+ local statusSortButton = inviteList.sortButtons.status;
+ local inviteSort = _G[inviteButtonName.."Status"];
+ statusSortButton:SetPoint("RIGHT", inviteSort, "RIGHT");
+end
+
+function CalendarEventInviteList_UpdateSortButtons(inviteList)
+ local criterion, reverse = CalendarEventGetInviteSortCriterion();
+ for index, button in pairs(inviteList.sortButtons) do
+ local direction = _G[button:GetName().."Direction"];
+ if ( button.criterion == criterion ) then
+ if ( reverse ) then
+ direction:SetTexCoord(0.0, 0.9375, 0.0, 0.6875);
+ else
+ direction:SetTexCoord(0.0, 0.9375, 0.6875, 0.0);
+ end
+ direction:Show();
+ button:SetWidth(button:GetTextWidth() + direction:GetWidth());
+ else
+ direction:Hide();
+ button:SetWidth(button:GetTextWidth());
+ end
+ end
+end
+
+function CalendarEventInviteSortButton_OnLoad(self)
+ local width = self:GetTextWidth() + _G[self:GetName().."Direction"]:GetWidth();
+ self:SetWidth(width);
+end
+
+function CalendarEventInviteSortButton_OnClick(self)
+ CalendarEventSortInvites(self.criterion, self.criterion == CalendarEventGetInviteSortCriterion());
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ CalendarContextMenu_Hide(CalendarViewEventInviteContextMenu_Initialize);
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+end
+
+function CalendarEventInviteListButton_OnEnter(self)
+ if ( self.inviteIndex ) then
+ local weekday, month, day, year, hour, minute = CalendarEventGetInviteResponseTime(self.inviteIndex);
+ if ( weekday ~= 0 ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:AddLine(CALENDAR_TOOLTIP_INVITE_RESPONDED);
+ -- date
+ GameTooltip:AddLine(
+ format(FULLDATE, _CalendarFrame_GetFullDate(weekday, month, day, year)),
+ HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b
+ );
+ -- time
+ GameTooltip:AddLine(
+ GameTime_GetFormattedTime(hour, minute, true),
+ HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b
+ );
+ GameTooltip:Show();
+ end
+ end
+end
+
+
+-- CalendarViewEventFrame
+
+function CalendarViewEventFrame_OnLoad(self)
+ self:RegisterEvent("CALENDAR_UPDATE_EVENT");
+ self:RegisterEvent("CALENDAR_UPDATE_INVITE_LIST");
+ self:RegisterEvent("CALENDAR_CLOSE_EVENT");
+ self:RegisterEvent("GUILD_ROSTER_UPDATE");
+ self:RegisterEvent("PLAYER_GUILD_UPDATE");
+-- self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+
+ self.update = CalendarViewEventFrame_Update;
+ self.selectedInvite = nil;
+ self.myInviteIndex = nil;
+
+ self.defaultHeight = self:GetHeight();
+end
+
+function CalendarViewEventFrame_OnEvent(self, event, ...)
+ if ( CalendarViewEventFrame:IsShown() ) then
+ if ( event == "CALENDAR_UPDATE_EVENT" ) then
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+ if ( CalendarEventCanEdit() ) then
+ CalendarCreateEventFrame.mode = "edit";
+ CalendarFrame_ShowEventFrame(CalendarCreateEventFrame);
+ else
+ CalendarViewEventFrame_Update();
+ end
+ elseif ( event == "CALENDAR_UPDATE_INVITE_LIST" ) then
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+ if ( CalendarEventCanEdit() ) then
+ CalendarCreateEventFrame.mode = "edit";
+ CalendarFrame_ShowEventFrame(CalendarCreateEventFrame);
+ else
+ -- RSVP'ing to the event can induce an invite list update, so we
+ -- need to do an RSVP update
+ local title, description, creator, eventType, repeatOption, maxSize, textureIndex,
+ weekday, month, day, year, hour, minute,
+ lockoutWeekday, lockoutMonth, lockoutDay, lockoutYear, lockoutHour, lockoutMinute,
+ locked, autoApprove, pendingInvite, inviteStatus, inviteType, calendarType = CalendarGetEventInfo();
+ CalendarViewEventRSVP_Update(month, day, year, pendingInvite, inviteStatus, inviteType, calendarType);
+ CalendarViewEventInviteList_Update(inviteType, calendarType);
+ end
+ elseif ( event == "CALENDAR_CLOSE_EVENT" ) then
+ CalendarFrame_HideEventFrame(CalendarViewEventFrame);
+ elseif ( event == "GUILD_ROSTER_UPDATE" or event == "PLAYER_GUILD_UPDATE" ) then
+ if ( CalendarEventCanEdit() ) then
+ -- our permissions changed and we can now edit this event
+ CalendarCreateEventFrame.mode = "edit";
+ CalendarFrame_ShowEventFrame(CalendarCreateEventFrame);
+ end
+-- elseif ( event == "PARTY_MEMBERS_CHANGED" ) then
+-- CalendarViewEventInviteList_Update();
+ end
+ end
+end
+
+function CalendarViewEventFrame_OnShow(self)
+ CalendarViewEventFrame_Update();
+end
+
+function CalendarViewEventFrame_OnHide(self)
+ CalendarContextMenu_Hide(CalendarViewEventInviteContextMenu_Initialize);
+ --CalendarDayEventButton_Click();
+end
+
+function CalendarViewEventFrame_Update()
+ local title, description, creator, eventType, repeatOption, maxSize, textureIndex,
+ weekday, month, day, year, hour, minute,
+ lockoutWeekday, lockoutMonth, lockoutDay, lockoutYear, lockoutHour, lockoutMinute,
+ locked, autoApprove, pendingInvite, inviteStatus, inviteType, calendarType = CalendarGetEventInfo();
+ if ( not title ) then
+ -- event was probably deleted
+ CalendarFrame_HideEventFrame(CalendarViewEventFrame);
+ CalendarClassButtonContainer_Hide();
+ return;
+ end
+ -- record the invite type
+ CalendarViewEventFrame.inviteType = inviteType;
+ -- reset the flash timer to reinforce the visual feedback that the player is switching between events
+ CalendarViewEventFlashTimer:Stop();
+ -- set the icon
+ CalendarViewEventIcon:SetTexture();
+ local tcoords = CALENDAR_EVENTTYPE_TCOORDS[eventType];
+ CalendarViewEventIcon:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ local eventTex = _CalendarFrame_GetEventTexture(textureIndex, eventType);
+ if ( eventTex ) then
+ -- set the event type
+ local name = eventTex.title;
+ name = GetDungeonNameWithDifficulty(name, eventTex.difficultyName);
+ CalendarViewEventTypeName:SetFormattedText(CALENDAR_VIEW_EVENTTYPE, safeselect(eventType, CalendarEventGetTypes()), name);
+ -- set the eventTex texture
+ if ( eventTex.texture ~= "" ) then
+ CalendarViewEventIcon:SetTexture(CALENDAR_EVENTTYPE_TEXTURE_PATHS[eventType]..eventTex.texture);
+ else
+ CalendarViewEventIcon:SetTexture(CALENDAR_EVENTTYPE_TEXTURES[eventType]);
+ end
+ else
+ -- set the event type
+ CalendarViewEventTypeName:SetText(safeselect(eventType, CalendarEventGetTypes()));
+ CalendarViewEventIcon:SetTexture(CALENDAR_EVENTTYPE_TEXTURES[eventType]);
+ end
+ -- set the creator
+ CalendarViewEventCreatorName:SetFormattedText(CALENDAR_EVENT_CREATORNAME, _CalendarFrame_SafeGetName(creator));
+ -- set the date
+ CalendarViewEventDateLabel:SetFormattedText(FULLDATE, _CalendarFrame_GetFullDate(weekday, month, day, year));
+ -- set the time
+ CalendarViewEventTimeLabel:SetText(GameTime_GetFormattedTime(hour, minute, true));
+ -- set the description
+ CalendarViewEventDescription:SetText(description);
+ CalendarViewEventDescriptionScrollFrame:SetVerticalScroll(0);
+ -- change the look based on the locked status
+ if ( locked ) then
+ -- set the event title
+ CalendarViewEventTitle:SetFormattedText(CALENDAR_VIEW_EVENTTITLE_LOCKED, title);
+ SetDesaturation(CalendarViewEventIcon, true);
+ CalendarViewEventTypeName:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ CalendarViewEventCreatorName:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ --CalendarViewEventDateLabel:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ --CalendarViewEventTimeLabel:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ CalendarViewEventDescription:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ else
+ -- set the event title
+ CalendarViewEventTitle:SetText(title);
+ SetDesaturation(CalendarViewEventIcon, false);
+ CalendarViewEventTypeName:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ CalendarViewEventCreatorName:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ --CalendarViewEventDateLabel:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b)
+ --CalendarViewEventTimeLabel:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ CalendarViewEventDescription:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+ if ( calendarType == "GUILD_ANNOUNCEMENT" ) then
+ CalendarTitleFrame_SetText(CalendarViewEventTitleFrame, CALENDAR_VIEW_ANNOUNCEMENT);
+ -- guild wide events don't have invite lists, auto approval, or event locks
+ CalendarViewEventInviteListSection:Hide();
+ CalendarViewEventFrame:SetHeight(CalendarViewEventFrame.defaultHeight - CalendarViewEventInviteListSection:GetHeight());
+ CalendarClassButtonContainer_Hide();
+ else
+ if ( calendarType == "GUILD_EVENT" ) then
+ CalendarTitleFrame_SetText(CalendarViewEventTitleFrame, CALENDAR_VIEW_GUILD_EVENT);
+ else
+ CalendarTitleFrame_SetText(CalendarViewEventTitleFrame, CALENDAR_VIEW_EVENT);
+ end
+ CalendarViewEventInviteListSection:Show();
+ CalendarViewEventFrame:SetHeight(CalendarViewEventFrame.defaultHeight);
+ if ( locked ) then
+ -- event locked...you cannot respond to the event
+ CalendarViewEventAcceptButton:Disable();
+ CalendarViewEventTentativeButton:Disable();
+ CalendarViewEventDeclineButton:Disable();
+ CalendarViewEventAcceptButtonFlashTexture:Hide();
+ CalendarViewEventTentativeButtonFlashTexture:Hide();
+ CalendarViewEventDeclineButtonFlashTexture:Hide()
+ CalendarViewEventFrame:SetScript("OnUpdate", nil);
+ else
+ CalendarViewEventRSVP_Update(month, day, year, pendingInvite, inviteStatus, inviteType, calendarType);
+ end
+
+ CalendarViewEventInviteList_Update(inviteType, calendarType);
+ end
+ CalendarEventFrameBlocker_Update();
+end
+
+function CalendarViewEventDescriptionScrollFrame_OnLoad(self)
+ self.content = CalendarViewEventDescription;
+ CalendarEventDescriptionScrollFrame_OnLoad(self);
+end
+
+function CalendarViewEventRSVPButton_OnUpdate(self)
+ self.flashTexture:SetAlpha(CalendarViewEventFlashTimer:GetSmoothProgress());
+end
+
+function CalendarViewEventAcceptButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if ( CalendarViewEventFrame.inviteType == CALENDAR_INVITETYPE_SIGNUP ) then
+ GameTooltip:SetText(CALENDAR_TOOLTIP_SIGNUPBUTTON, nil, nil, nil, nil, 1);
+ else
+ GameTooltip:SetText(CALENDAR_TOOLTIP_AVAILABLEBUTTON, nil, nil, nil, nil, 1);
+ end
+ GameTooltip:Show();
+ --GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, CALENDAR_TOOLTIP_AVAILABLEBUTTON, 1);
+end
+
+function CalendarViewEventAcceptButton_OnClick(self)
+ if ( CalendarViewEventFrame.inviteType == CALENDAR_INVITETYPE_SIGNUP ) then
+ CalendarEventSignUp();
+ else
+ CalendarEventAvailable();
+ end
+end
+
+function CalendarViewEventTentativeButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(CALENDAR_TOOLTIP_TENTATIVEBUTTON, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+ --GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, CALENDAR_TOOLTIP_TENTATIVEBUTTON, 1);
+end
+
+function CalendarViewEventTentativeButton_OnClick(self)
+ CalendarEventTentative();
+end
+
+function CalendarViewEventDeclineButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(CALENDAR_TOOLTIP_DECLINEBUTTON, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+ --GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, CALENDAR_TOOLTIP_DECLINEBUTTON, 1);
+end
+
+function CalendarViewEventDeclineButton_OnClick(self)
+ CalendarEventDecline();
+end
+
+function CalendarViewEventRemoveButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if ( CalendarViewEventFrame.inviteType == CALENDAR_INVITETYPE_SIGNUP ) then
+ GameTooltip:SetText(CALENDAR_TOOLTIP_REMOVESIGNUPBUTTON, nil, nil, nil, nil, 1);
+ else
+ GameTooltip:SetText(CALENDAR_TOOLTIP_REMOVEBUTTON, nil, nil, nil, nil, 1);
+ end
+ GameTooltip:Show();
+ --GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, CALENDAR_TOOLTIP_REMOVEBUTTON, 1);
+end
+
+function CalendarViewEventRemoveButton_OnClick(self)
+ CalendarRemoveEvent();
+end
+
+function CalendarViewEventRSVP_Update(month, day, year, pendingInvite, inviteStatus, inviteType, calendarType)
+ -- record the invite type
+ CalendarViewEventFrame.inviteType = inviteType;
+
+ local isTodayOrLater = _CalendarFrame_IsTodayOrLater(month, day, year);
+ if ( _CalendarFrame_IsSignUpEvent(calendarType, inviteType) ) then
+ -- set buttons to sign up mode
+ CalendarViewEventAcceptButton:SetText(CALENDAR_SIGNUP);
+ CalendarViewEventAcceptButton:ClearAllPoints();
+ CalendarViewEventAcceptButton:SetPoint("TOPLEFT", CalendarViewEventTentativeButton:GetParent(), "TOPLEFT", 14, 0);
+ CalendarViewEventAcceptButton:SetWidth(CALENDAR_VIEWEVENTFRAME_GUILDEVENT_RSVPBUTTON_WIDTH);
+ CalendarViewEventAcceptButtonFlashTexture:Hide();
+ CalendarViewEventTentativeButton:ClearAllPoints();
+ CalendarViewEventTentativeButton:SetPoint("TOP", CalendarViewEventTentativeButton:GetParent(), "TOP", 0, 0);
+ CalendarViewEventTentativeButton:SetWidth(CALENDAR_VIEWEVENTFRAME_GUILDEVENT_RSVPBUTTON_WIDTH);
+ CalendarViewEventTentativeButtonFlashTexture:Hide();
+ CalendarViewEventRemoveButton:ClearAllPoints();
+ CalendarViewEventRemoveButton:SetWidth(CALENDAR_VIEWEVENTFRAME_GUILDEVENT_RSVPBUTTON_WIDTH);
+ CalendarViewEventRemoveButton:SetPoint("TOPRIGHT", CalendarViewEventRemoveButton:GetParent(), "TOPRIGHT", -14, 0);
+ CalendarViewEventDeclineButton:Hide();
+ -- update shown buttons
+ if ( isTodayOrLater ) then
+ if ( inviteStatus == CALENDAR_INVITESTATUS_NOT_SIGNEDUP ) then
+ CalendarViewEventAcceptButton:Enable();
+ CalendarViewEventTentativeButton:Enable();
+ CalendarViewEventRemoveButton:Disable();
+ else
+ CalendarViewEventAcceptButton:Disable();
+ CalendarViewEventTentativeButton:Disable();
+ CalendarViewEventRemoveButton:Enable();
+ end
+ else
+ CalendarViewEventAcceptButton:Disable();
+ CalendarViewEventTentativeButton:Disable();
+ CalendarViewEventRemoveButton:Disable();
+ end
+ CalendarViewEventFrame:SetScript("OnUpdate", nil);
+ else
+ -- set buttons to normal mode
+ CalendarViewEventAcceptButton:ClearAllPoints();
+ CalendarViewEventAcceptButton:SetPoint("TOPRIGHT", CalendarViewEventTentativeButton:GetParent(), "TOP", -10, 4);
+ CalendarViewEventAcceptButton:SetWidth(CALENDAR_VIEWEVENTFRAME_EVENT_RSVPBUTTON_WIDTH);
+ CalendarViewEventAcceptButton:SetText(ACCEPT);
+ CalendarViewEventTentativeButton:ClearAllPoints();
+ CalendarViewEventTentativeButton:SetPoint("TOPLEFT", CalendarViewEventTentativeButton:GetParent(), "TOP", 10, 4);
+ CalendarViewEventTentativeButton:SetWidth(CALENDAR_VIEWEVENTFRAME_EVENT_RSVPBUTTON_WIDTH);
+ CalendarViewEventDeclineButton:Show();
+ CalendarViewEventRemoveButton:ClearAllPoints();
+ CalendarViewEventRemoveButton:SetPoint("TOPLEFT", CalendarViewEventRemoveButton:GetParent(), "TOP", 10, -26);
+ CalendarViewEventRemoveButton:SetWidth(CALENDAR_VIEWEVENTFRAME_EVENT_RSVPBUTTON_WIDTH);
+ -- update shown buttons
+ local canRSVP = _CalendarFrame_CanInviteeRSVP(inviteStatus);
+ if ( isTodayOrLater and canRSVP ) then
+ if ( inviteStatus ~= CALENDAR_INVITESTATUS_ACCEPTED ) then
+ CalendarViewEventAcceptButton:Enable();
+ else
+ CalendarViewEventAcceptButton:Disable();
+ end
+ if ( inviteStatus ~= CALENDAR_INVITESTATUS_TENTATIVE ) then
+ CalendarViewEventTentativeButton:Enable();
+ else
+ CalendarViewEventTentativeButton:Disable();
+ end
+ if ( inviteStatus ~= CALENDAR_INVITESTATUS_DECLINED ) then
+ CalendarViewEventDeclineButton:Enable();
+ else
+ CalendarViewEventDeclineButton:Disable();
+ end
+ if ( pendingInvite ) then
+ CalendarViewEventAcceptButtonFlashTexture:Show();
+ CalendarViewEventTentativeButtonFlashTexture:Show();
+ CalendarViewEventDeclineButtonFlashTexture:Show()
+ else
+ CalendarViewEventAcceptButtonFlashTexture:Hide();
+ CalendarViewEventTentativeButtonFlashTexture:Hide();
+ CalendarViewEventDeclineButtonFlashTexture:Hide()
+ end
+ CalendarViewEventFlashTimer:Play();
+ else
+ CalendarViewEventAcceptButton:Disable();
+ CalendarViewEventTentativeButton:Disable();
+ CalendarViewEventDeclineButton:Disable();
+ CalendarViewEventAcceptButtonFlashTexture:Hide();
+ CalendarViewEventTentativeButtonFlashTexture:Hide();
+ CalendarViewEventDeclineButtonFlashTexture:Hide()
+ CalendarViewEventFlashTimer:Stop();
+ end
+ end
+end
+
+function CalendarViewEventInviteList_Update(inviteType, calendarType)
+-- CalendarViewEventInviteList.partyMode = GetRealNumPartyMembers() > 0 or GetRealNumRaidMembers() > 0;
+ CalendarViewEventInviteList.partyMode = false;
+
+ if ( _CalendarFrame_IsSignUpEvent(calendarType, inviteType) ) then
+ -- expand the event list so there is not so much empty space around the buttons
+ CalendarViewEventDivider:SetPoint("TOPLEFT", CalendarViewEventDivider:GetParent(), "TOPLEFT", 10, -30);
+ CalendarViewEventInviteList:SetPoint("TOP", CalendarViewEventInviteList:GetParent(), "TOP", 0, -60);
+ CalendarViewEventInviteList:SetHeight(CALENDAR_VIEWEVENTFRAME_GUILDEVENT_INVITELIST_HEIGHT);
+ else
+ -- shrink the event list to make room for the buttons
+ CalendarViewEventDivider:SetPoint("TOPLEFT", CalendarViewEventDivider:GetParent(), "TOPLEFT", 10, -50);
+ CalendarViewEventInviteList:SetPoint("TOP", CalendarViewEventInviteList:GetParent(), "TOP", 0, -80);
+ CalendarViewEventInviteList:SetHeight(CALENDAR_VIEWEVENTFRAME_EVENT_INVITELIST_HEIGHT);
+ end
+
+ CalendarViewEventInviteListScrollFrame_Update();
+ CalendarEventInviteList_AnchorSortButtons(CalendarViewEventInviteList);
+ CalendarEventInviteList_UpdateSortButtons(CalendarViewEventInviteList);
+end
+
+function CalendarViewEventInviteListScrollFrame_Update()
+ local buttons = CalendarViewEventInviteListScrollFrame.buttons;
+ local numInvites = CalendarEventGetNumInvites();
+ local numButtons = #buttons;
+ local buttonHeight = buttons[1]:GetHeight();
+
+ CalendarViewEventFrame.myInviteIndex = nil;
+
+ local selectedInviteIndex = CalendarEventGetSelectedInvite();
+ if ( selectedInviteIndex <= 0 ) then
+ selectedInviteIndex = nil;
+ end
+
+ local displayedHeight = 0;
+ local selectedInvite = CalendarViewEventFrame.selectedInvite;
+ local offset = HybridScrollFrame_GetOffset(CalendarViewEventInviteListScrollFrame);
+ for i = 1, numButtons do
+ -- get current button info
+ local button = buttons[i];
+ local buttonName = button:GetName();
+ local inviteIndex = i + offset;
+ local name, level, className, classFilename, inviteStatus, modStatus, inviteIsMine = CalendarEventGetInvite(inviteIndex);
+ if ( name ) then
+ button.inviteIndex = inviteIndex;
+ -- setup moderator status
+ local buttonModIcon = _G[buttonName.."ModIcon"];
+ if ( modStatus == "CREATOR" ) then
+ buttonModIcon:SetTexture("Interface\\GroupFrame\\UI-Group-LeaderIcon");
+ buttonModIcon:Show();
+ elseif ( modStatus == "MODERATOR" ) then
+ buttonModIcon:SetTexture("Interface\\GroupFrame\\UI-Group-AssistantIcon");
+ buttonModIcon:Show();
+ else
+ buttonModIcon:SetTexture();
+ buttonModIcon:Hide();
+ end
+--[[
+ -- setup party status
+ buttonPartyIcon = _G[buttonName.."PartyIcon"];
+ if ( not CalendarViewEventInviteList.partyMode or not UnitInParty(name) or not UnitInRaid(name) ) then
+ buttonPartyIcon:Hide();
+ else
+ buttonPartyIcon:Show();
+ -- the party icon overrides the mod icon
+ buttonModIcon:Hide();
+ end
+--]]
+ -- setup name
+ -- NOTE: classFilename could be invalid when a character is being transferred
+ local classColor = (classFilename and RAID_CLASS_COLORS[classFilename]) or NORMAL_FONT_COLOR;
+ local buttonNameString = _G[buttonName.."Name"];
+ buttonNameString:SetText(_CalendarFrame_SafeGetName(name));
+ buttonNameString:SetTextColor(classColor.r, classColor.g, classColor.b);
+ -- setup class
+ local buttonClass = _G[buttonName.."Class"];
+ buttonClass:SetText(_CalendarFrame_SafeGetName(className));
+ buttonClass:SetTextColor(classColor.r, classColor.g, classColor.b);
+ -- setup status
+ local buttonStatus = _G[buttonName.."Status"];
+ local inviteStatusInfo = _CalendarFrame_SafeGetInviteStatusInfo(inviteStatus);
+ buttonStatus:SetText(inviteStatusInfo.name);
+ buttonStatus:SetTextColor(inviteStatusInfo.color.r, inviteStatusInfo.color.g, inviteStatusInfo.color.b);
+
+ -- fixup anchors
+ if ( CalendarViewEventInviteList.partyMode ) then
+ buttonNameString:SetPoint("LEFT", buttonPartyIcon, "RIGHT");
+ --buttonClass:SetPoint("LEFT", buttonNameString, "RIGHT", -buttonPartyIcon:GetWidth(), 0);
+ elseif ( buttonModIcon:IsShown() ) then
+ buttonNameString:SetPoint("LEFT", buttonModIcon, "RIGHT");
+ --buttonClass:SetPoint("LEFT", buttonNameString, "RIGHT", -buttonModIcon:GetWidth(), 0);
+ else
+ buttonNameString:SetPoint("LEFT", button, "LEFT");
+ --buttonClass:SetPoint("LEFT", buttonNameString, "RIGHT", 0, 0);
+ end
+
+ -- set the selected button
+ if ( selectedInviteIndex and inviteIndex == selectedInviteIndex ) then
+ CalendarViewEventFrame_SetSelectedInvite(button);
+ else
+ button:UnlockHighlight();
+ end
+
+ button:Show();
+ else
+ button.inviteIndex = nil;
+ button:Hide();
+ end
+ displayedHeight = displayedHeight + buttonHeight;
+ end
+ CalendarClassButtonContainer_Show(CalendarViewEventFrame);
+ local totalHeight = numInvites * buttonHeight;
+ HybridScrollFrame_Update(CalendarViewEventInviteListScrollFrame, totalHeight, displayedHeight);
+end
+
+function CalendarViewEventFrame_SetSelectedInvite(inviteButton)
+ if ( CalendarViewEventFrame.selectedInvite ) then
+ CalendarViewEventFrame.selectedInvite:UnlockHighlight();
+ end
+ CalendarViewEventFrame.selectedInvite = inviteButton;
+ if ( CalendarViewEventFrame.selectedInvite ) then
+ CalendarViewEventFrame.selectedInvite:LockHighlight();
+ end
+end
+
+function CalendarViewEventInviteListButton_OnClick(self, button)
+ if ( button == "LeftButton" ) then
+ --CalendarViewEventInviteListButton_Click(self);
+ CalendarContextMenu_Hide();
+ elseif ( button == "RightButton" ) then
+ local inviteChanged = CalendarContextMenu.inviteButton ~= self;
+
+ if ( CalendarEventHasPendingInvite() and self.inviteIndex == CalendarViewEventFrame.myInviteIndex ) then
+ if ( inviteChanged ) then
+ CalendarContextMenu_Show(self, CalendarViewEventInviteContextMenu_Initialize, "cursor", 3, -3, self);
+ else
+ CalendarContextMenu_Toggle(self, CalendarViewEventInviteContextMenu_Initialize, "cursor", 3, -3, self);
+ end
+ end
+ end
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+function CalendarViewEventInviteListButton_Click(button)
+ CalendarEventSelectInvite(button.inviteIndex);
+ CalendarViewEventFrame_SetSelectedInvite(button);
+end
+
+function CalendarViewEventInviteContextMenu_Initialize(self, inviteButton)
+ UIMenu_Initialize(self);
+
+ -- unlock old highlights
+ CalendarInviteContextMenu_UnlockHighlights();
+
+ -- record the invite button
+ self.inviteButton = inviteButton;
+
+ -- set invite status submenu
+ UIMenu_AddButton(self, CALENDAR_SET_INVITE_STATUS, nil, nil, "CalendarInviteStatusContextMenu");
+
+ -- lock new highlights
+ inviteButton:LockHighlight();
+
+ return UIMenu_FinishInitializing(self);
+end
+
+
+-- CalendarCreateEventFrame
+
+function CalendarCreateEventFrame_OnLoad(self)
+ self:RegisterEvent("CALENDAR_UPDATE_EVENT");
+ self:RegisterEvent("CALENDAR_UPDATE_INVITE_LIST");
+ self:RegisterEvent("CALENDAR_NEW_EVENT");
+ self:RegisterEvent("CALENDAR_CLOSE_EVENT");
+-- self:RegisterEvent("CALENDAR_ACTION_PENDING");
+ self:RegisterEvent("GUILD_ROSTER_UPDATE");
+ self:RegisterEvent("PLAYER_GUILD_UPDATE");
+-- self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+
+ -- used to update the frame when it is shown via CalendarFrame_ShowEventFrame
+ self.update = CalendarCreateEventFrame_Update;
+
+ -- record the default (non-guild-wide) frame size
+ self.defaultHeight = self:GetHeight();
+
+ -- initialize UI elements
+ UIDropDownMenu_Initialize(CalendarCreateEventTypeDropDown, CalendarCreateEventTypeDropDown_Initialize);
+ UIDropDownMenu_SetWidth(CalendarCreateEventTypeDropDown, 100);
+ UIDropDownMenu_Initialize(CalendarCreateEventHourDropDown, CalendarCreateEventHourDropDown_Initialize);
+ UIDropDownMenu_SetWidth(CalendarCreateEventHourDropDown, 30, 40);
+ UIDropDownMenu_Initialize(CalendarCreateEventMinuteDropDown, CalendarCreateEventMinuteDropDown_Initialize);
+ UIDropDownMenu_SetWidth(CalendarCreateEventMinuteDropDown, 30, 40);
+ UIDropDownMenu_Initialize(CalendarCreateEventAMPMDropDown, CalendarCreateEventAMPMDropDown_Initialize);
+ UIDropDownMenu_SetWidth(CalendarCreateEventAMPMDropDown, 40, 40);
+ UIDropDownMenu_Initialize(CalendarCreateEventRepeatOptionDropDown, CalendarCreateEventRepeatOptionDropDown_Initialize);
+ UIDropDownMenu_SetWidth(CalendarCreateEventRepeatOptionDropDown, 80);
+end
+
+function CalendarCreateEventFrame_OnEvent(self, event, ...)
+ if ( CalendarCreateEventFrame:IsShown() ) then
+ if ( event == "CALENDAR_UPDATE_EVENT" ) then
+ if ( CalendarEventCanEdit() ) then
+ CalendarCreateEventFrame_Update();
+ else
+ CalendarFrame_ShowEventFrame(CalendarViewEventFrame);
+ end
+ elseif ( event == "CALENDAR_UPDATE_INVITE_LIST" ) then
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+ if ( not CalendarEventCanEdit() ) then
+ -- if we can't edit the event any more, show the view event frame immediately
+ CalendarFrame_ShowEventFrame(CalendarViewEventFrame);
+ return;
+ end
+--[[
+ local initialList = ...;
+ if ( initialList ) then
+ -- in this case, a new event was made and the initial invite list is now ready
+ -- we need to update the new event with data now
+ CalendarCreateEventFrame_Update();
+ else
+ CalendarCreateEventInviteListScrollFrame_Update();
+ end
+--]]
+ CalendarCreateEventInviteList_Update();
+ CalendarCreateEventRaidInviteButton_Update();
+ elseif ( event == "CALENDAR_NEW_EVENT" ) then
+ local isCopy = ...;
+ -- the CALENDAR_NEW_EVENT event gets fired when you successfully create a calendar event,
+ -- so to provide feedback to the player, we close the current event frame when we get this
+ -- event...the other part of the feedback is that the event shows up on their calendar
+ -- (that part gets picked up by a CALENDAR_UPDATE_EVENT_LIST event)
+ if ( not isCopy ) then
+ CalendarFrame_HideEventFrame(CalendarCreateEventFrame);
+ end
+ elseif ( event == "CALENDAR_CLOSE_EVENT" ) then
+ CalendarFrame_HideEventFrame(CalendarCreateEventFrame);
+--[[
+ elseif ( event == "CALENDAR_ACTION_PENDING" ) then
+ CalendarCreateEventInviteButton_Update();
+ CalendarCreateEventCreateButton_Update();
+--]]
+ elseif ( event == "GUILD_ROSTER_UPDATE" or event == "PLAYER_GUILD_UPDATE" ) then
+ if ( event == "GUILD_ROSTER_UPDATE" ) then
+ local arg1 = ...;
+ if ( arg1 ) then
+ GuildRoster();
+ end
+ end
+ if ( CalendarEventCanEdit() ) then
+ if ( CalendarCreateEventFrame.mode == "edit" ) then
+ CalendarCreateEventFrame_Update();
+ end
+ else
+ CalendarFrame_ShowEventFrame(CalendarViewEventFrame);
+ end
+-- elseif ( event == "PARTY_MEMBERS_CHANGED" ) then
+-- CalendarCreateEventInviteList_Update();
+ end
+ end
+end
+
+function CalendarCreateEventFrame_OnShow(self)
+ CalendarCreateEventFrame_Update();
+end
+
+function CalendarCreateEventFrame_OnHide(self)
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+ -- clear the raid invite button data so we don't get strange party-invite behavior next time we show this frame
+ CalendarCreateEventRaidInviteButton.inviteLostMembers = false;
+ CalendarCreateEventRaidInviteButton.inviteCount = 0;
+ CalendarMassInviteFrame:Hide();
+end
+
+function CalendarCreateEventFrame_Update()
+ if ( CalendarCreateEventFrame.mode == "create" ) then
+ CalendarCreateEventCreateButton_SetText(CALENDAR_CREATE);
+
+ -- set the event date based on the selected date
+ local dayButton = CalendarCreateEventFrame.dayButton;
+ CalendarCreateEventDateLabel:SetFormattedText(FULLDATE, _CalendarFrame_GetFullDateFromDay(dayButton));
+ local month, year = CalendarGetMonth(dayButton.monthOffset);
+ CalendarEventSetDate(month, dayButton.day, year);
+ -- deselect the selected event
+ CalendarDayEventButton_Click();
+ -- reset event title
+ CalendarCreateEventTitleEdit:SetText(CALENDAR_CREATEEVENTFRAME_DEFAULT_TITLE);
+ CalendarCreateEventTitleEdit:HighlightText();
+ CalendarCreateEventTitleEdit:SetFocus();
+ CalendarEventSetTitle("");
+ -- reset event description
+ CalendarCreateEventDescriptionEdit:SetText(CALENDAR_CREATEEVENTFRAME_DEFAULT_DESCRIPTION);
+ CalendarEventSetDescription("");
+ -- reset event time
+ CalendarCreateEventFrame.selectedMinute = CALENDAR_CREATEEVENTFRAME_DEFAULT_MINUTE;
+ CalendarCreateEventFrame.selectedAM = CALENDAR_CREATEEVENTFRAME_DEFAULT_AM;
+ if ( CalendarFrame.militaryTime ) then
+ CalendarCreateEventFrame.selectedHour = GameTime_ComputeMilitaryTime(CALENDAR_CREATEEVENTFRAME_DEFAULT_HOUR, CalendarCreateEventFrame.selectedAM);
+ else
+ CalendarCreateEventFrame.selectedHour = CALENDAR_CREATEEVENTFRAME_DEFAULT_HOUR;
+ end
+ CalendarCreateEvent_UpdateEventTime();
+ CalendarCreateEvent_SetEventTime();
+ -- reset event type
+ CalendarCreateEventFrame.selectedEventType = CALENDAR_CREATEEVENTFRAME_DEFAULT_TYPE;
+ CalendarCreateEvent_UpdateEventType();
+ CalendarEventSetType(CalendarCreateEventFrame.selectedEventType);
+ -- reset event texture (must come after event type)
+ CalendarCreateEventFrame.selectedTextureIndex = nil;
+ CalendarCreateEventTexture_Update();
+ -- hide the creator
+ CalendarCreateEventCreatorName:Hide();
+ -- reset repeat option
+ CalendarCreateEventFrame.selectedRepeatOption = CALENDAR_CREATEEVENTFRAME_DEFAULT_REPEAT_OPTION;
+ CalendarCreateEvent_UpdateRepeatOption();
+ CalendarEventSetRepeatOption(CalendarCreateEventFrame.selectedRepeatOption);
+ local calendarType = CalendarEventGetCalendarType();
+ if ( calendarType == "GUILD_ANNOUNCEMENT" ) then
+ CalendarTitleFrame_SetText(CalendarCreateEventTitleFrame, CALENDAR_CREATE_ANNOUNCEMENT);
+ -- guild wide events don't have invites
+ CalendarCreateEventInviteListSection:Hide();
+ CalendarCreateEventMassInviteButton:Hide();
+ CalendarCreateEventFrame:SetHeight(CalendarCreateEventFrame.defaultHeight - CalendarCreateEventInviteListSection:GetHeight());
+ CalendarClassButtonContainer_Hide();
+ else
+ if ( calendarType == "GUILD_EVENT" ) then
+ CalendarTitleFrame_SetText(CalendarCreateEventTitleFrame, CALENDAR_CREATE_GUILD_EVENT);
+ CalendarCreateEventMassInviteButton:Hide();
+ else
+ CalendarTitleFrame_SetText(CalendarCreateEventTitleFrame, CALENDAR_CREATE_EVENT);
+ -- update mass invite button
+ CalendarCreateEventMassInviteButton_Update();
+ CalendarCreateEventMassInviteButton:Show();
+ end
+ -- reset auto-approve
+ CalendarCreateEventAutoApproveCheck:SetChecked(CALENDAR_CREATEEVENTFRAME_DEFAULT_AUTOAPPROVE);
+ CalendarCreateEvent_SetAutoApprove();
+ -- reset lock event
+ CalendarCreateEventLockEventCheck:SetChecked(CALENDAR_CREATEEVENTFRAME_DEFAULT_LOCKEVENT);
+ CalendarCreateEvent_SetLockEvent();
+ -- update invite list
+ CalendarCreateEventInviteList_Update();
+ CalendarCreateEventInviteListSection:Show();
+ CalendarCreateEventFrame:SetHeight(CalendarCreateEventFrame.defaultHeight);
+ end
+ -- hide the raid invite button, it is only used when editing events
+ CalendarCreateEventRaidInviteButton:Hide();
+ -- update the modal frame blocker
+ CalendarEventFrameBlocker_Update();
+ elseif ( CalendarCreateEventFrame.mode == "edit" ) then
+ local title, description, creator, eventType, repeatOption, maxSize, textureIndex,
+ weekday, month, day, year, hour, minute,
+ lockoutWeekday, lockoutMonth, lockoutDay, lockoutYear, lockoutHour, lockoutMinute,
+ locked, autoApprove, pendingInvite, inviteStatus, inviteType, calendarType = CalendarGetEventInfo();
+ if ( not title ) then
+ CalendarFrame_HideEventFrame(CalendarCreateEventFrame);
+ CalendarClassButtonContainer_Hide();
+ return;
+ end
+
+ CalendarCreateEventCreateButton_SetText(CALENDAR_UPDATE);
+
+ -- update event title
+ CalendarCreateEventTitleEdit:SetText(title);
+ CalendarCreateEventTitleEdit:SetCursorPosition(0);
+ CalendarCreateEventTitleEdit:ClearFocus();
+ -- update description
+ CalendarCreateEventDescriptionEdit:SetText(description);
+ CalendarCreateEventDescriptionEdit:SetCursorPosition(0);
+ CalendarCreateEventDescriptionEdit:ClearFocus();
+ CalendarCreateEventDescriptionScrollFrame:SetVerticalScroll(0);
+ -- update date
+ CalendarCreateEventDateLabel:SetFormattedText(FULLDATE, _CalendarFrame_GetFullDate(weekday, month, day, year));
+ -- update time
+ if ( CalendarFrame.militaryTime ) then
+ CalendarCreateEventFrame.selectedHour = hour;
+ else
+ CalendarCreateEventFrame.selectedHour = GameTime_ComputeStandardTime(hour);
+ end
+ CalendarCreateEventFrame.selectedMinute = minute;
+ CalendarCreateEventFrame.selectedAM = hour < 12;
+ if ( CalendarFrame.militaryTime ) then
+ CalendarCreateEventFrame.selectedHour = hour;
+ else
+ CalendarCreateEventFrame.selectedHour = GameTime_ComputeStandardTime(hour, CalendarCreateEventFrame.selectedAM);
+ end
+ CalendarCreateEvent_UpdateEventTime();
+ -- update type
+ CalendarCreateEventFrame.selectedEventType = eventType;
+ CalendarCreateEvent_UpdateEventType();
+ -- reset event texture (must come after event type)
+ CalendarCreateEventFrame.selectedTextureIndex = textureIndex > 0 and textureIndex;
+ CalendarCreateEventTexture_Update();
+ -- update the creator (must come after event texture)
+ CalendarCreateEventCreatorName:SetFormattedText(CALENDAR_EVENT_CREATORNAME, _CalendarFrame_SafeGetName(creator));
+ CalendarCreateEventCreatorName:Show();
+ -- update repeat option
+ CalendarCreateEventFrame.selectedRepeatOption = repeatOption;
+ CalendarCreateEvent_UpdateRepeatOption();
+ if ( calendarType == "GUILD_ANNOUNCEMENT" ) then
+ CalendarTitleFrame_SetText(CalendarCreateEventTitleFrame, CALENDAR_EDIT_ANNOUNCEMENT);
+ -- guild wide events don't have invites
+ CalendarCreateEventInviteListSection:Hide();
+ CalendarCreateEventRaidInviteButton:Hide();
+ CalendarCreateEventFrame:SetHeight(CalendarCreateEventFrame.defaultHeight - CalendarCreateEventInviteListSection:GetHeight());
+ CalendarClassButtonContainer_Hide();
+ else
+ if ( calendarType == "GUILD_EVENT" ) then
+ CalendarTitleFrame_SetText(CalendarCreateEventTitleFrame, CALENDAR_EDIT_GUILD_EVENT);
+ else
+ CalendarTitleFrame_SetText(CalendarCreateEventTitleFrame, CALENDAR_EDIT_EVENT);
+ end
+ -- update auto approve
+ CalendarCreateEventAutoApproveCheck:SetChecked(autoApprove);
+ -- update locked
+ CalendarCreateEventLockEventCheck:SetChecked(locked);
+ -- update invite list
+ CalendarCreateEventInviteList_Update();
+ -- update raid invite button
+ CalendarCreateEventRaidInviteButton_Update();
+ CalendarCreateEventInviteListSection:Show();
+ CalendarCreateEventRaidInviteButton:Show();
+ CalendarCreateEventFrame:SetHeight(CalendarCreateEventFrame.defaultHeight);
+ end
+ -- we're not able to mass invite after an event is created...
+ CalendarCreateEventMassInviteButton:Hide();
+ -- update the modal frame blocker
+ CalendarEventFrameBlocker_Update();
+ end
+end
+
+function CalendarCreateEventTitleEdit_OnTextChanged(self)
+ local text = self:GetText();
+ local trimmedText = strtrim(text);
+ if ( trimmedText == "" or trimmedText == CALENDAR_CREATEEVENTFRAME_DEFAULT_TITLE ) then
+ -- if the title is either the default or all whitespace, just set it to the empty string
+ CalendarEventSetTitle("");
+ else
+ CalendarEventSetTitle(text);
+ end
+ CalendarCreateEventCreateButton_Update();
+end
+
+function CalendarCreateEventTitleEdit_OnEditFocusLost(self)
+ local text = self:GetText();
+ if ( strtrim(text) == "" ) then
+ self:SetText(CALENDAR_CREATEEVENTFRAME_DEFAULT_TITLE);
+ end
+ self:HighlightText(0, 0);
+end
+
+function CalendarCreateEventCreatorName_Update()
+ if ( CalendarCreateEventTextureName:IsShown() ) then
+ CalendarCreateEventCreatorName:SetPoint("TOPLEFT", CalendarCreateEventTextureName, "BOTTOMLEFT");
+ else
+ CalendarCreateEventCreatorName:SetPoint("TOPLEFT", CalendarCreateEventDateLabel, "BOTTOMLEFT");
+ end
+end
+
+function CalendarCreateEventTexture_Update()
+ local eventType = CalendarCreateEventFrame.selectedEventType;
+ local textureIndex = CalendarCreateEventFrame.selectedTextureIndex;
+
+ CalendarCreateEventIcon:SetTexture();
+ local tcoords = CALENDAR_EVENTTYPE_TCOORDS[eventType];
+ CalendarCreateEventIcon:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ local eventTex = _CalendarFrame_GetEventTexture(textureIndex, eventType);
+ if ( eventTex ) then
+ -- set the eventTex name since we have one
+ local name = eventTex.title;
+ CalendarCreateEventTextureName:SetText(GetDungeonNameWithDifficulty(name, eventTex.difficultyName));
+ CalendarCreateEventTextureName:Show();
+ -- set the eventTex texture
+ if ( eventTex.texture ~= "" ) then
+ CalendarCreateEventIcon:SetTexture(CALENDAR_EVENTTYPE_TEXTURE_PATHS[eventType]..eventTex.texture);
+ else
+ CalendarCreateEventIcon:SetTexture(CALENDAR_EVENTTYPE_TEXTURES[eventType]);
+ end
+ else
+ CalendarCreateEventTextureName:Hide();
+ CalendarCreateEventIcon:SetTexture(CALENDAR_EVENTTYPE_TEXTURES[eventType]);
+ end
+ -- need to update the creator name at this point since it is affected by the texture name
+ CalendarCreateEventCreatorName_Update();
+end
+
+function CalendarCreateEventTypeDropDown_Initialize(self)
+ CalendarCreateEventTypeDropDown_InitEventTypes(self, CalendarEventGetTypes());
+end
+
+function CalendarCreateEventTypeDropDown_InitEventTypes(self, ...)
+ local info = UIDropDownMenu_CreateInfo();
+ for i = 1, select("#", ...) do
+ info.text = select(i, ...);
+ info.func = CalendarCreateEventTypeDropDown_OnClick;
+ if ( CalendarCreateEventFrame.selectedEventType == i ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function CalendarCreateEventTypeDropDown_OnClick(self)
+ local id = self:GetID();
+ if ( id == CALENDAR_EVENTTYPE_DUNGEON or id == CALENDAR_EVENTTYPE_RAID ) then
+ CalendarTexturePickerFrame_Show(id);
+ else
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventTypeDropDown, id);
+ CalendarCreateEventFrame.selectedEventType = id;
+ CalendarEventSetType(id);
+ -- NOTE: clear the texture selection for non-dungeon types since those don't have texture selections
+ CalendarCreateEventFrame.selectedTextureIndex = nil;
+ CalendarCreateEventTexture_Update();
+
+ CalendarCreateEventCreateButton_Update();
+ end
+end
+
+function CalendarCreateEvent_UpdateEventType()
+ UIDropDownMenu_Initialize(CalendarCreateEventTypeDropDown, CalendarCreateEventTypeDropDown_Initialize);
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventTypeDropDown, CalendarCreateEventFrame.selectedEventType);
+end
+
+function CalendarCreateEventRepeatOptionDropDown_Initialize(self)
+ CalendarCreateEventTypeDropDown_InitRepeatOptions(self, CalendarEventGetRepeatOptions());
+end
+
+function CalendarCreateEventTypeDropDown_InitRepeatOptions(self, ...)
+ local info = UIDropDownMenu_CreateInfo();
+ for i = 1, select("#", ...) do
+ info.text = select(i, ...);
+ info.func = CalendarCreateEventRepeatOptionDropDown_OnClick;
+ if ( CalendarCreateEventFrame.selectedRepeatOption == i ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function CalendarCreateEventRepeatOptionDropDown_OnClick(self)
+ local id = self:GetID();
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventRepeatOptionDropDown, id);
+ CalendarCreateEventFrame.selectedRepeatOption = id;
+ CalendarEventSetRepeatOption(id);
+
+ CalendarCreateEventCreateButton_Update();
+end
+
+function CalendarCreateEvent_UpdateRepeatOption()
+ UIDropDownMenu_Initialize(CalendarCreateEventRepeatOptionDropDown, CalendarCreateEventRepeatOptionDropDown_Initialize);
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventRepeatOptionDropDown, CalendarCreateEventFrame.selectedRepeatOption);
+end
+
+function CalendarCreateEventHourDropDown_Initialize(self)
+ local info = UIDropDownMenu_CreateInfo();
+
+ local militaryTime = GetCVarBool("timeMgrUseMilitaryTime");
+
+ local hourMin, hourMax;
+ if ( militaryTime ) then
+ hourMin = 0;
+ hourMax = 23;
+ else
+ hourMin = 1;
+ hourMax = 12;
+ end
+ for hour = hourMin, hourMax, 1 do
+ info.value = hour;
+ if ( militaryTime ) then
+ info.text = format(TIMEMANAGER_24HOUR, hour);
+ else
+ info.text = hour;
+ info.justifyH = "RIGHT";
+ end
+ info.func = CalendarCreateEventHourDropDown_OnClick;
+ if ( hour == CalendarCreateEventFrame.selectedHour ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function CalendarCreateEventHourDropDown_OnClick(self)
+ UIDropDownMenu_SetSelectedValue(CalendarCreateEventHourDropDown, self.value);
+ CalendarCreateEventFrame.selectedHour = self.value;
+ CalendarCreateEvent_SetEventTime();
+
+ CalendarCreateEventCreateButton_Update();
+end
+
+function CalendarCreateEventMinuteDropDown_Initialize(self)
+ local info = UIDropDownMenu_CreateInfo();
+
+ for minute = 0, 55, 5 do
+ info.value = minute;
+ info.text = format(TIMEMANAGER_MINUTE, minute);
+ info.func = CalendarCreateEventMinuteDropDown_OnClick;
+ if ( minute == CalendarCreateEventFrame.selectedMinute ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function CalendarCreateEventMinuteDropDown_OnClick(self)
+ UIDropDownMenu_SetSelectedValue(CalendarCreateEventMinuteDropDown, self.value);
+ CalendarCreateEventFrame.selectedMinute = self.value;
+ CalendarCreateEvent_SetEventTime();
+
+ CalendarCreateEventCreateButton_Update();
+end
+
+function CalendarCreateEventAMPMDropDown_Initialize(self)
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = TIMEMANAGER_AM;
+ info.func = CalendarCreateEventAMPMDropDown_OnClick;
+ if ( CalendarCreateEventFrame.selectedAM ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+
+ info.text = TIMEMANAGER_PM;
+ info.func = CalendarCreateEventAMPMDropDown_OnClick;
+ if ( CalendarCreateEventFrame.selectedAM ) then
+ info.checked = nil;
+ else
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ end
+ UIDropDownMenu_AddButton(info);
+end
+
+function CalendarCreateEventAMPMDropDown_OnClick(self)
+ local id = self:GetID();
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventAMPMDropDown, id);
+ CalendarCreateEventFrame.selectedAM = id == 1;
+ CalendarCreateEvent_SetEventTime();
+
+ CalendarCreateEventCreateButton_Update();
+end
+
+function CalendarCreateEvent_SetEventTime()
+ local hour = CalendarCreateEventFrame.selectedHour;
+ if ( not CalendarFrame.militaryTime ) then
+ hour = GameTime_ComputeMilitaryTime(hour, CalendarCreateEventFrame.selectedAM);
+ end
+ CalendarEventSetTime(hour, CalendarCreateEventFrame.selectedMinute);
+end
+
+function CalendarCreateEvent_UpdateEventTime()
+ if ( CalendarFrame.militaryTime ) then
+ CalendarCreateEventAMPMDropDown:Hide();
+ else
+ CalendarCreateEventAMPMDropDown:Show();
+ UIDropDownMenu_Initialize(CalendarCreateEventAMPMDropDown, CalendarCreateEventAMPMDropDown_Initialize);
+ if ( CalendarCreateEventFrame.selectedAM ) then
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventAMPMDropDown, 1);
+ else
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventAMPMDropDown, 2);
+ end
+ end
+ UIDropDownMenu_Initialize(CalendarCreateEventHourDropDown, CalendarCreateEventHourDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(CalendarCreateEventHourDropDown, CalendarCreateEventFrame.selectedHour);
+ UIDropDownMenu_Initialize(CalendarCreateEventMinuteDropDown, CalendarCreateEventMinuteDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(CalendarCreateEventMinuteDropDown, CalendarCreateEventFrame.selectedMinute);
+end
+
+function CalendarCreateEvent_UpdateTimeFormat()
+ local hour, am = CalendarCreateEventFrame.selectedHour, CalendarCreateEventFrame.selectedAM;
+ local militaryTime = GetCVarBool("timeMgrUseMilitaryTime");
+ if ( militaryTime ) then
+ if ( not CalendarFrame.militaryTime ) then
+ -- need to convert from 12hr to 24hr
+ CalendarCreateEventFrame.selectedHour = GameTime_ComputeMilitaryTime(hour, am);
+ CalendarCreateEventAMPMDropDown:Hide();
+ end
+ else
+ if ( CalendarFrame.militaryTime ) then
+ -- need to convert from 24hr to 12hr
+ CalendarCreateEventFrame.selectedHour, CalendarCreateEventFrame.selectedAM = GameTime_ComputeStandardTime(hour);
+ CalendarCreateEventAMPMDropDown:Show();
+ end
+ UIDropDownMenu_Initialize(CalendarCreateEventAMPMDropDown, CalendarCreateEventAMPMDropDown_Initialize);
+ if ( CalendarCreateEventFrame.selectedAM ) then
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventAMPMDropDown, 1);
+ else
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventAMPMDropDown, 2);
+ end
+ end
+ CalendarFrame.militaryTime = militaryTime;
+ UIDropDownMenu_Initialize(CalendarCreateEventHourDropDown, CalendarCreateEventHourDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(CalendarCreateEventHourDropDown, CalendarCreateEventFrame.selectedHour);
+ UIDropDownMenu_Initialize(CalendarCreateEventMinuteDropDown, CalendarCreateEventMinuteDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(CalendarCreateEventMinuteDropDown, CalendarCreateEventFrame.selectedMinute);
+end
+
+function CalendarCreateEventDescriptionScrollFrame_OnLoad(self)
+ self.content = CalendarCreateEventDescriptionEdit;
+ CalendarEventDescriptionScrollFrame_OnLoad(self);
+end
+
+function CalendarCreateEventAutoApproveCheck_OnLoad(self)
+ CalendarCreateEventAutoApproveCheckText:SetText(CALENDAR_AUTO_APPROVE);
+ CalendarCreateEventAutoApproveCheckText:SetFontObject(GameFontNormalSmallLeft);
+ self:SetHitRectInsets(0, -CalendarCreateEventAutoApproveCheckText:GetWidth(), 0, 0);
+end
+
+function CalendarCreateEventAutoApproveCheck_OnClick(self)
+ CalendarCreateEvent_SetAutoApprove();
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ CalendarCreateEventCreateButton_Update();
+end
+
+function CalendarCreateEvent_SetAutoApprove()
+ if ( CalendarCreateEventAutoApproveCheck:GetChecked() ) then
+ CalendarEventSetAutoApprove();
+ else
+ CalendarEventClearAutoApprove();
+ end
+end
+
+function CalendarCreateEventLockEventCheck_OnLoad(self)
+ CalendarCreateEventLockEventCheckText:SetText(CALENDAR_LOCK_EVENT);
+ CalendarCreateEventLockEventCheckText:SetFontObject(GameFontNormalSmallLeft);
+ self:SetHitRectInsets(0, -CalendarCreateEventLockEventCheckText:GetWidth(), 0, 0);
+end
+
+function CalendarCreateEventLockEventCheck_OnClick(self)
+ CalendarCreateEvent_SetLockEvent();
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ CalendarCreateEventCreateButton_Update();
+end
+
+function CalendarCreateEvent_SetLockEvent()
+ if ( CalendarCreateEventLockEventCheck:GetChecked() ) then
+ CalendarEventSetLocked();
+ else
+ CalendarEventClearLocked();
+ end
+end
+
+function CalendarCreateEventInviteList_Update()
+-- CalendarCreateEventInviteList.partyMode = CalendarCreateEventFrame.mode == "edit" and GetRealNumPartyMembers() > 0 and GetRealNumRaidMembers() > 0;
+ CalendarCreateEventInviteList.partyMode = false;
+
+ CalendarCreateEventInviteListScrollFrame_Update();
+ CalendarEventInviteList_AnchorSortButtons(CalendarCreateEventInviteList);
+ CalendarEventInviteList_UpdateSortButtons(CalendarCreateEventInviteList);
+end
+
+function CalendarCreateEventInviteListScrollFrame_Update()
+ local buttons = CalendarCreateEventInviteListScrollFrame.buttons;
+ local numInvites = CalendarEventGetNumInvites();
+ local numButtons = #buttons;
+ local buttonHeight = buttons[1]:GetHeight();
+
+ local selectedInviteIndex = CalendarEventGetSelectedInvite();
+ if ( selectedInviteIndex <= 0 ) then
+ selectedInviteIndex = nil;
+ end
+
+ local isEditMode = CalendarCreateEventFrame.mode == "edit";
+
+ local displayedHeight = 0;
+ local offset = HybridScrollFrame_GetOffset(CalendarCreateEventInviteListScrollFrame);
+ for i = 1, numButtons do
+ -- get current button info
+ local button = buttons[i];
+ local buttonName = button:GetName();
+ local inviteIndex = i + offset;
+ -- NOTE: if we ever end up storing invites in a cache rather than getting it from C, then be sure to
+ -- add a flag that stores whether or not we can invite the player to a party; that would make the
+ -- CalendarCreateEventRaidInviteButton code more efficient as well
+ local name, level, className, classFilename, inviteStatus, modStatus, inviteIsMine = CalendarEventGetInvite(inviteIndex);
+ if ( name ) then
+ -- set the button index
+ button.inviteIndex = inviteIndex;
+ -- setup moderator status
+ local buttonModIcon = _G[buttonName.."ModIcon"];
+ if ( modStatus == "CREATOR" ) then
+ buttonModIcon:SetTexture("Interface\\GroupFrame\\UI-Group-LeaderIcon");
+ buttonModIcon:Show();
+ elseif ( modStatus == "MODERATOR" ) then
+ buttonModIcon:SetTexture("Interface\\GroupFrame\\UI-Group-AssistantIcon");
+ buttonModIcon:Show();
+ else
+ buttonModIcon:SetTexture();
+ buttonModIcon:Hide();
+ end
+--[[
+ -- setup party status
+ buttonPartyIcon = _G[buttonName.."PartyIcon"];
+ if ( not CalendarCreateEventInviteList.partyMode or not UnitInParty(name) or not UnitInRaid(name) ) then
+ buttonPartyIcon:Hide();
+ else
+ buttonPartyIcon:Show();
+ -- the party icon overrides the mod icon
+ buttonModIcon:Hide();
+ end
+--]]
+ -- setup name
+ -- NOTE: classFilename could be invalid when a character is being transferred
+ local classColor = (classFilename and RAID_CLASS_COLORS[classFilename]) or NORMAL_FONT_COLOR;
+ local buttonNameString = _G[buttonName.."Name"];
+ buttonNameString:SetText(_CalendarFrame_SafeGetName(name));
+ buttonNameString:SetTextColor(classColor.r, classColor.g, classColor.b);
+ -- setup class
+ local buttonClass = _G[buttonName.."Class"];
+ buttonClass:SetText(_CalendarFrame_SafeGetName(className));
+ buttonClass:SetTextColor(classColor.r, classColor.g, classColor.b);
+ -- setup status
+ local buttonStatus = _G[buttonName.."Status"];
+ local inviteStatusInfo = _CalendarFrame_SafeGetInviteStatusInfo(inviteStatus);
+ buttonStatus:SetText(inviteStatusInfo.name);
+ buttonStatus:SetTextColor(inviteStatusInfo.color.r, inviteStatusInfo.color.g, inviteStatusInfo.color.b);
+
+ -- fixup anchors
+ if ( CalendarCreateEventInviteList.partyMode ) then
+ buttonNameString:SetPoint("LEFT", buttonPartyIcon, "RIGHT");
+ --buttonClass:SetPoint("LEFT", buttonNameString, "RIGHT", -buttonPartyIcon:GetWidth(), 0);
+ elseif ( buttonModIcon:IsShown() ) then
+ buttonNameString:SetPoint("LEFT", buttonModIcon, "RIGHT");
+ --buttonClass:SetPoint("LEFT", buttonNameString, "RIGHT", -buttonModIcon:GetWidth(), 0);
+ else
+ buttonNameString:SetPoint("LEFT", button, "LEFT");
+ --buttonClass:SetPoint("LEFT", buttonNameString, "RIGHT", 0, 0);
+ end
+
+ -- set the selected button
+ if ( selectedInviteIndex and inviteIndex == selectedInviteIndex ) then
+ CalendarCreateEventFrame_SetSelectedInvite(button);
+ else
+ button:UnlockHighlight();
+ end
+
+ -- set the onclick handler based on the parent mode
+ if ( isEditMode ) then
+ button:SetScript("OnEnter", CalendarEventInviteListButton_OnEnter);
+ else
+ button:SetScript("OnEnter", nil);
+ end
+
+ -- update class counts
+ if ( classFilename ~= "" ) then
+ CalendarClassData[classFilename].counts[inviteStatus] = CalendarClassData[classFilename].counts[inviteStatus] + 1;
+ -- MFS HACK: doing this because we don't have class names in global strings
+ CalendarClassData[classFilename].name = className;
+ end
+
+ button:Show();
+ else
+ button.inviteIndex = nil;
+ button:Hide();
+ end
+ displayedHeight = displayedHeight + buttonHeight;
+ end
+ CalendarClassButtonContainer_Show(CalendarCreateEventFrame);
+ local totalHeight = numInvites * buttonHeight;
+ HybridScrollFrame_Update(CalendarCreateEventInviteListScrollFrame, totalHeight, displayedHeight);
+end
+
+function CalendarCreateEventFrame_SetSelectedInvite(inviteButton)
+ if ( CalendarCreateEventFrame.selectedInvite ) then
+ CalendarCreateEventFrame.selectedInvite:UnlockHighlight();
+ end
+ CalendarCreateEventFrame.selectedInvite = inviteButton;
+ if ( CalendarCreateEventFrame.selectedInvite ) then
+ CalendarCreateEventFrame.selectedInvite:LockHighlight();
+ end
+end
+
+function CalendarCreateEventInviteListButton_OnClick(self, button)
+ if ( button == "LeftButton" ) then
+ --CalendarCreateEventInviteListButton_Click(self);
+ CalendarContextMenu_Hide();
+ elseif ( button == "RightButton" ) then
+ local inviteChanged = CalendarContextMenu.inviteButton ~= self;
+
+ if ( inviteChanged ) then
+ CalendarContextMenu_Show(self, CalendarCreateEventInviteContextMenu_Initialize, "cursor", 3, -3, self);
+ else
+ CalendarContextMenu_Toggle(self, CalendarCreateEventInviteContextMenu_Initialize, "cursor", 3, -3, self);
+ end
+ end
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+function CalendarCreateEventInviteListButton_Click(button)
+ CalendarEventSelectInvite(button.inviteIndex);
+ CalendarCreateEventFrame_SetSelectedInvite(button);
+end
+
+function CalendarCreateEventInviteContextMenu_Initialize(self, inviteButton)
+ UIMenu_Initialize(self);
+
+ -- unlock old highlights
+ CalendarInviteContextMenu_UnlockHighlights();
+
+ -- record the invite button
+ self.inviteButton = inviteButton;
+
+ local inviteIndex = inviteButton.inviteIndex;
+ local name, _, _, _, _, modStatus = CalendarEventGetInvite(inviteIndex);
+
+ local needSpacer = false;
+ if ( modStatus ~= "CREATOR" ) then
+ -- remove invite
+ UIMenu_AddButton(self, REMOVE, nil, CalendarInviteContextMenu_RemoveInvite);
+ -- spacer
+ --UIMenu_AddButton(self, "");
+ if ( modStatus == "MODERATOR" ) then
+ -- clear moderator status
+ UIMenu_AddButton(self, CALENDAR_INVITELIST_CLEARMODERATOR, nil, CalendarInviteContextMenu_ClearModerator);
+ else
+ -- set moderator status
+ UIMenu_AddButton(self, CALENDAR_INVITELIST_SETMODERATOR, nil, CalendarInviteContextMenu_SetModerator);
+ end
+ end
+ if ( CalendarCreateEventFrame.mode == "edit" ) then
+ if ( needSpacer ) then
+ UIMenu_AddButton(self);
+ end
+ -- set invite status submenu
+ UIMenu_AddButton(self, CALENDAR_INVITELIST_SETINVITESTATUS, nil, nil, "CalendarInviteStatusContextMenu");
+ needSpacer = true;
+ end
+
+ if ( not UnitIsUnit("player", name) and (not UnitInParty(name) or not UnitInRaid(name)) ) then
+ -- spacer
+ if ( needSpacer ) then
+ UIMenu_AddButton(self, "");
+ end
+ UIMenu_AddButton(
+ self, -- self
+ CALENDAR_INVITELIST_INVITETORAID, -- text
+ nil, -- shortcut
+ CalendarInviteContextMenu_InviteToGroup, -- func
+ nil, -- nested self name
+ name); -- value
+ end
+
+ if ( UIMenu_FinishInitializing(self) ) then
+ -- lock new highlights
+ inviteButton:LockHighlight();
+ return true;
+ else
+ return false;
+ end
+end
+
+function CalendarInviteContextMenu_UnlockHighlights()
+ local inviteButton = CalendarContextMenu.inviteButton;
+ if ( inviteButton and
+ inviteButton ~= CalendarViewEventFrame.selectedInvite and
+ inviteButton ~= CalendarCreateEventFrame.selectedInvite ) then
+ inviteButton:UnlockHighlight();
+ end
+end
+
+function CalendarInviteContextMenu_RemoveInvite()
+ local inviteButton = CalendarContextMenu.inviteButton;
+ CalendarEventRemoveInvite(inviteButton.inviteIndex);
+end
+
+function CalendarInviteContextMenu_SetModerator()
+ local inviteButton = CalendarContextMenu.inviteButton;
+ CalendarEventSetModerator(inviteButton.inviteIndex);
+end
+
+function CalendarInviteContextMenu_ClearModerator()
+ local inviteButton = CalendarContextMenu.inviteButton;
+ CalendarEventClearModerator(inviteButton.inviteIndex);
+end
+
+function CalendarInviteContextMenu_InviteToGroup(self)
+ InviteUnit(self.value);
+end
+
+function CalendarInviteStatusContextMenu_OnLoad(self)
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+ self:RegisterEvent("CALENDAR_UPDATE_EVENT");
+ self.parentMenu = "CalendarContextMenu";
+ self.onlyAutoHideSelf = true;
+end
+
+function CalendarInviteStatusContextMenu_OnShow(self)
+ CalendarInviteStatusContextMenu_Initialize(self, CalendarEventGetStatusOptions(CalendarContextMenu.inviteButton.inviteIndex));
+end
+
+function CalendarInviteStatusContextMenu_OnEvent(self, event, ...)
+ if ( event == "CALENDAR_UPDATE_EVENT" ) then
+ if ( self:IsShown() ) then
+ CalendarInviteStatusContextMenu_Initialize(self, CalendarEventGetStatusOptions(CalendarContextMenu.inviteButton.inviteIndex));
+ end
+ end
+end
+
+function CalendarInviteStatusContextMenu_Initialize(self, ...)
+ UIMenu_Initialize(self);
+
+ local statusIndex, statusName;
+ for i = 1, select("#", ...), 2 do
+ statusIndex = select(i, ...);
+ statusName = select(i + 1, ...);
+ UIMenu_AddButton(
+ self, -- self
+ statusName, -- text
+ nil, -- shortcut
+ CalendarInviteStatusContextMenu_SetStatusOption, -- func
+ nil, -- nested
+ statusIndex -- value
+ );
+ end
+
+ return UIMenu_FinishInitializing(self);
+end
+
+function CalendarInviteStatusContextMenu_SetStatusOption(self)
+ CalendarEventSetStatus(CalendarContextMenu.inviteButton.inviteIndex, self.value);
+ -- hide parent
+ CalendarContextMenu_Hide(CalendarCreateEventInviteContextMenu_Initialize);
+end
+
+function CalendarCreateEventInviteEdit_OnEnterPressed(self)
+ if ( not AutoCompleteEditBox_OnEnterPressed(self) ) then
+ local text = strtrim(self:GetText());
+ local trimmedText = strtrim(text);
+ if ( trimmedText == "" or trimmedText == CALENDAR_PLAYER_NAME ) then
+ self:ClearFocus();
+ elseif ( CalendarCanSendInvite() ) then
+ CalendarEventInvite(text);
+ self:SetText("");
+ end
+ end
+end
+
+function CalendarCreateEventInviteEdit_OnEditFocusLost(self)
+ AutoCompleteEditBox_OnEditFocusLost(self);
+ self:HighlightText(0, 0);
+ local trimmedText = strtrim(self:GetText());
+ if ( trimmedText == "" ) then
+ self:SetText(CALENDAR_PLAYER_NAME);
+ end
+end
+
+function CalendarCreateEventInviteButton_OnClick(self)
+ local text = strtrim(CalendarCreateEventInviteEdit:GetText());
+ local trimmedText = strtrim(text);
+ if ( trimmedText == "" or trimmedText == CALENDAR_PLAYER_NAME ) then
+ CalendarCreateEventInviteEdit:ClearFocus();
+ else
+ CalendarEventInvite(text);
+ CalendarCreateEventInviteEdit:SetText("");
+ --CalendarCreateEventInviteEdit:ClearFocus();
+ end
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+function CalendarCreateEventInviteButton_OnUpdate(self)
+ CalendarCreateEventInviteButton_Update();
+end
+
+function CalendarCreateEventInviteButton_Update()
+ if ( CalendarCanSendInvite() ) then
+ CalendarCreateEventInviteButton:Enable();
+ else
+ CalendarCreateEventInviteButton:Disable();
+ end
+end
+
+function CalendarCreateEventMassInviteButton_OnClick()
+ CalendarMassInviteFrame:Show();
+end
+
+function CalendarCreateEventMassInviteButton_OnUpdate(self)
+ CalendarCreateEventMassInviteButton_Update();
+end
+
+function CalendarCreateEventMassInviteButton_Update()
+ if ( CalendarCanSendInvite() and (CanEditGuildEvent() or IsInArenaTeam()) ) then
+ CalendarCreateEventMassInviteButton:Enable();
+ else
+ CalendarCreateEventMassInviteButton:Disable();
+ end
+end
+
+function CalendarCreateEventRaidInviteButton_OnLoad(self)
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("PARTY_CONVERTED_TO_RAID");
+
+ self:SetWidth(self:GetTextWidth() + 40);
+end
+
+function CalendarCreateEventRaidInviteButton_OnEvent(self, event, ...)
+ if ( self:IsShown() and self:GetParent():IsShown() ) then
+ if ( event == "PARTY_MEMBERS_CHANGED" ) then
+ CalendarCreateEventRaidInviteButton_Update();
+ if ( GetRealNumRaidMembers() == 0 and GetRealNumPartyMembers() >= 1 and self.inviteLostMembers ) then
+ -- in case we weren't able to convert to a raid when the player clicked the raid invite button
+ -- (which means the player was not in a party), we want to convert to a raid now since he has a party
+ ConvertToRaid();
+ end
+ elseif ( event == "PARTY_CONVERTED_TO_RAID" ) then
+ CalendarCreateEventRaidInviteButton_Update();
+ if ( self.inviteLostMembers ) then
+ -- should already be in a raid at this point, invite members who were not invited due to the party to raid conversion
+ local maxInviteCount = MAX_RAID_MEMBERS - GetRealNumRaidMembers();
+ local inviteCount = _CalendarFrame_InviteToRaid(maxInviteCount);
+ self.inviteLostMembers = false;
+ end
+ end
+ end
+end
+
+function CalendarCreateEventRaidInviteButton_OnClick(self)
+ -- compute the max number of players that we should invite
+ local maxInviteCount;
+ local realNumRaidMembers = GetRealNumRaidMembers();
+ local realNumPartyMembers = GetRealNumPartyMembers();
+ if ( realNumRaidMembers == 0 ) then
+ if ( realNumPartyMembers + self.inviteCount > MAX_PARTY_MEMBERS ) then
+ -- if I can't invite the number of people that I'm supposed to...
+ self.inviteLostMembers = true;
+ if ( realNumPartyMembers > 0 ) then
+ --...and I'm already in a party, then I need to form a raid first to fit everyone
+ ConvertToRaid();
+ return;
+ end
+ --...and I'm NOT already in a party, then I need to form a party first (happens below),
+ -- then form a raid to fit everyone (happens in response to the PARTY_CONVERTED_TO_RAID event)
+ end
+ maxInviteCount = MAX_PARTY_MEMBERS - realNumPartyMembers;
+ else
+ maxInviteCount = MAX_RAID_MEMBERS - realNumRaidMembers;
+ end
+
+ _CalendarFrame_InviteToRaid(maxInviteCount);
+end
+
+function CalendarCreateEventRaidInviteButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if ( GetRealNumRaidMembers() > 0 or GetRealNumPartyMembers() + self.inviteCount > MAX_PARTY_MEMBERS ) then
+ GameTooltip:SetText(CALENDAR_TOOLTIP_INVITEMEMBERS_BUTTON_RAID, nil, nil, nil, nil, 1);
+ else
+ GameTooltip:SetText(CALENDAR_TOOLTIP_INVITEMEMBERS_BUTTON_PARTY, nil, nil, nil, nil, 1);
+ end
+ GameTooltip:Show();
+ --GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, CALENDAR_TOOLTIP_INVITETORAID_BUTTON, 1);
+end
+
+function CalendarCreateEventRaidInviteButton_Update()
+ -- NOTE: it might be an efficiency concern that we go through the list twice: once to get a count
+ -- and once to do the actual inviting (that's in the OnClick), but I thought it would be better to
+ -- go through the list twice than to take up extra space in memory and potentially cause a lot of
+ -- garbage collection due to constantly rebuilding a saved table
+ local maxInviteCount = MAX_RAID_MEMBERS - GetRealNumRaidMembers();
+ local inviteCount = _CalendarFrame_GetInviteToRaidCount(maxInviteCount);
+ if ( inviteCount > 0 ) then
+ CalendarCreateEventRaidInviteButton:Enable();
+ else
+ CalendarCreateEventRaidInviteButton:Disable();
+ end
+ CalendarCreateEventRaidInviteButton.inviteCount = inviteCount;
+end
+
+function CalendarCreateEventCreateButton_OnClick(self)
+ if ( CalendarCreateEventFrame.mode == "create" ) then
+ CalendarAddEvent();
+ elseif ( CalendarCreateEventFrame.mode == "edit" ) then
+ CalendarUpdateEvent();
+ end
+end
+
+function CalendarCreateEventCreateButton_OnUpdate(self)
+ CalendarCreateEventCreateButton_Update();
+end
+
+function CalendarCreateEventCreateButton_SetText(text)
+ local button = CalendarCreateEventCreateButton;
+ button:SetText(text);
+ button:SetWidth(button:GetTextWidth() + 40);
+end
+
+function CalendarCreateEventCreateButton_Update()
+ if ( CalendarCreateEventFrame.mode == "create" ) then
+ if ( CalendarCanAddEvent() ) then
+ CalendarCreateEventCreateButton:Enable();
+ else
+ CalendarCreateEventCreateButton:Disable();
+ end
+ --CalendarCreateEventCreateButton_SetText(CALENDAR_CREATE);
+ elseif ( CalendarCreateEventFrame.mode == "edit" ) then
+ if ( CalendarEventHaveSettingsChanged() and not CalendarIsActionPending() ) then
+ CalendarCreateEventCreateButton:Enable();
+ else
+ CalendarCreateEventCreateButton:Disable();
+ end
+ --CalendarCreateEventCreateButton_SetText(CALENDAR_UPDATE);
+ end
+end
+
+
+-- CalendarMassInviteFrame
+
+function CalendarMassInviteFrame_OnLoad(self)
+ self:RegisterEvent("CALENDAR_ACTION_PENDING");
+ self:RegisterEvent("GUILD_ROSTER_UPDATE");
+ self:RegisterEvent("PLAYER_GUILD_UPDATE");
+ self:RegisterEvent("ARENA_TEAM_UPDATE");
+
+ local minLevel, maxLevel = CalendarDefaultGuildFilter();
+ CalendarMassInviteGuildMinLevelEdit:SetNumber(minLevel);
+ CalendarMassInviteGuildMaxLevelEdit:SetNumber(maxLevel);
+ UIDropDownMenu_SetWidth(CalendarMassInviteGuildRankMenu, 100);
+
+ -- try to fire off a guild roster event so we can properly update our guild options
+ if ( IsInGuild() and GetNumGuildMembers() == 0 ) then
+ GuildRoster();
+ end
+ -- do the same for arena teams
+ for i = 1, MAX_ARENA_TEAMS do
+ ArenaTeamRoster(i);
+ end
+ -- update the arena team section in order to fill initial data
+ CalendarMassInviteArena_Update();
+end
+
+function CalendarMassInviteFrame_OnShow(self)
+ CalendarFrame_PushModal(self);
+ CalendarMassInviteGuild_Update();
+ CalendarMassInviteArena_Update();
+end
+
+function CalendarMassInviteFrame_OnEvent(self, event, ...)
+ if ( event == "GUILD_ROSTER_UPDATE" ) then
+ local arg1 = ...;
+ if ( arg1 ) then
+ GuildRoster();
+ end
+ end
+ if ( self:IsShown() ) then
+ if ( not CanEditGuildEvent() and not IsInArenaTeam() ) then
+ -- if we are no longer in a guild OR an arena team, we can't mass invite
+ CalendarMassInviteFrame:Hide();
+ CalendarCreateEventMassInviteButton_Update();
+ else
+ if ( event == "CALENDAR_ACTION_PENDING" ) then
+ CalendarMassInviteGuild_Update();
+ CalendarMassInviteArena_Update();
+ elseif ( event == "GUILD_ROSTER_UPDATE" or event == "PLAYER_GUILD_UPDATE" ) then
+ CalendarMassInviteGuild_Update();
+ elseif ( event == "ARENA_TEAM_UPDATE" ) then
+ CalendarMassInviteArena_Update();
+ end
+ end
+ end
+end
+
+function CalendarMassInviteFrame_OnUpdate(self)
+ CalendarMassInviteGuild_Update();
+ CalendarMassInviteArena_Update();
+end
+
+function CalendarMassInviteGuild_Update()
+ if ( CalendarCanSendInvite() and CanEditGuildEvent() ) then
+ -- enable the accept button
+ CalendarMassInviteGuildAcceptButton:Enable();
+ -- set the selected rank
+ if ( not CalendarMassInviteFrame.selectedRank or CalendarMassInviteFrame.selectedRank > GuildControlGetNumRanks() ) then
+ local _, _, rank = CalendarDefaultGuildFilter();
+ CalendarMassInviteFrame.selectedRank = rank;
+ end
+ -- enable and initialize the rank drop down
+ UIDropDownMenu_EnableDropDown(CalendarMassInviteGuildRankMenu);
+ UIDropDownMenu_Initialize(CalendarMassInviteGuildRankMenu, CalendarMassInviteGuildRankMenu_Initialize);
+ -- set text color back to normal
+ CalendarMassInviteGuildLevelText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ CalendarMassInviteGuildMinLevelEdit:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ CalendarMassInviteGuildMaxLevelEdit:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ CalendarMassInviteGuildRankText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ else
+ -- disable the accept button
+ CalendarMassInviteGuildAcceptButton:Disable();
+ -- disable the rank drop down
+ UIDropDownMenu_DisableDropDown(CalendarMassInviteGuildRankMenu);
+ -- set text color to a disabled color
+ CalendarMassInviteGuildLevelText:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ CalendarMassInviteGuildMinLevelEdit:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ CalendarMassInviteGuildMaxLevelEdit:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ CalendarMassInviteGuildRankText:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+end
+
+function CalendarMassInviteGuildRankMenu_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+
+ for i = 1, GuildControlGetNumRanks() do
+ info.text = GuildControlGetRankName(i);
+ info.func = CalendarMassInviteGuildRankMenu_OnClick;
+ if ( i == CalendarMassInviteFrame.selectedRank ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(CalendarMassInviteGuildRankMenu, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function CalendarMassInviteGuildRankMenu_OnClick(self)
+ CalendarMassInviteFrame.selectedRank = self:GetID();
+ UIDropDownMenu_SetSelectedID(CalendarMassInviteGuildRankMenu, CalendarMassInviteFrame.selectedRank);
+end
+
+function CalendarMassInviteGuildAcceptButton_OnClick(self)
+ local minLevel = CalendarMassInviteGuildMinLevelEdit:GetNumber();
+ local maxLevel = CalendarMassInviteGuildMaxLevelEdit:GetNumber();
+ CalendarMassInviteGuild(minLevel, maxLevel, CalendarMassInviteFrame.selectedRank);
+ CalendarMassInviteFrame:Hide();
+end
+
+local ARENA_TEAMS = {2, 3, 5};
+function CalendarMassInviteArena_Update()
+ -- initialize the teams
+ local teamName, teamSize;
+ local button;
+ for i = 1, MAX_ARENA_TEAMS do
+ button = _G["CalendarMassInviteArenaButton"..ARENA_TEAMS[i]];
+ button.teamName = nil;
+ button:Disable();
+ end
+
+ -- set the teams
+ local canSendInvite = CalendarCanSendInvite();
+ for i = 1, MAX_ARENA_TEAMS do
+ teamName, teamSize = GetArenaTeam(i);
+ if ( canSendInvite and teamName ) then
+ button = _G["CalendarMassInviteArenaButton"..teamSize];
+ button:SetFormattedText(PVP_TEAMTYPE, teamSize, teamSize);
+ button.teamName = teamName;
+ button:SetID(i);
+ button:Enable();
+ end
+ end
+
+ -- optimization note: using two separate init and set loops yields less redundancy and less branches than two nested loops
+end
+
+function CalendarMassInviteArenaButton_OnLoad(self)
+ local teamSize = ARENA_TEAMS[self:GetID()];
+ self:SetFormattedText(PVP_TEAMTYPE, teamSize, teamSize);
+end
+
+function CalendarMassInviteArenaButton_OnClick(self)
+ CalendarMassInviteArenaTeam(self:GetID());
+ CalendarMassInviteFrame:Hide();
+end
+
+function CalendarMassInviteArenaButton_OnEnter(self)
+ if ( self.teamName ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.teamName);
+ end
+end
+
+
+-- CalendarEventPickerFrame
+
+function CalendarEventPickerFrame_OnLoad(self)
+ self:RegisterEvent("CALENDAR_UPDATE_EVENT_LIST");
+ self.dayButton = nil;
+ self.selectedEvent = nil;
+end
+
+function CalendarEventPickerFrame_OnEvent(self, event, ...)
+ if ( self:IsShown() and event == "CALENDAR_UPDATE_EVENT_LIST" and self.dayButton ) then
+ CalendarEventPickerScrollFrame_Update();
+ end
+end
+
+function CalendarEventPickerFrame_Show(dayButton)
+ CalendarEventPickerFrame.dayButton = dayButton;
+ CalendarEventPickerFrame:ClearAllPoints();
+ if ( _CalendarFrame_GetDayOfWeek(dayButton:GetID()) > 4 ) then
+ CalendarEventPickerFrame:SetPoint("TOPRIGHT", dayButton, "TOPLEFT");
+ else
+ CalendarEventPickerFrame:SetPoint("TOPLEFT", dayButton, "TOPRIGHT");
+ end
+ CalendarContextMenu_Hide();
+ CalendarEventPickerFrame:Show();
+ CalendarEventPickerScrollBar:SetValue(0);
+ CalendarEventPickerScrollFrame_Update();
+end
+
+function CalendarEventPickerFrame_Hide()
+ CalendarContextMenu_Hide(CalendarDayContextMenu_Initialize);
+ CalendarEventPickerFrame.dayButton = nil;
+ CalendarEventPickerFrame:Hide();
+ -- clean up texture references
+ for i = 1, #CalendarEventPickerScrollFrame.buttons do
+ _G[CalendarEventPickerScrollFrame.buttons[i]:GetName().."Icon"]:SetTexture();
+ end
+end
+
+function CalendarEventPickerFrame_Toggle(dayButton)
+ if ( CalendarEventPickerFrame:IsShown() ) then
+ CalendarEventPickerFrame_Hide();
+ else
+ CalendarEventPickerFrame_Show(dayButton);
+ end
+end
+
+function CalendarEventPickerFrame_SetSelectedEvent(eventButton)
+ if ( CalendarEventPickerFrame.selectedEventButton ) then
+ CalendarEventPickerFrame.selectedEventButton:UnlockHighlight();
+ end
+ CalendarEventPickerFrame.selectedEventButton = eventButton;
+ if ( CalendarEventPickerFrame.selectedEventButton ) then
+ CalendarEventPickerFrame.selectedEventButton:LockHighlight();
+ end
+end
+
+function CalendarEventPickerScrollFrame_OnLoad(self)
+ HybridScrollFrame_OnLoad(self);
+ -- register the addon loaded event for post-load fixups
+ self:RegisterEvent("ADDON_LOADED");
+ self:SetScript("OnEvent", CalendarEventPickerScrollFrame_OnEvent);
+end
+
+function CalendarEventPickerScrollFrame_OnEvent(self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local addonName = ...;
+ if ( not addonName or (addonName and addonName ~= "Blizzard_Calendar") ) then
+ return;
+ end
+
+ local scrollBar = self.scrollBar;
+ scrollBar.Show =
+ function (self)
+ local scrollFrame = self:GetParent();
+ local scrollBarWidth = self:GetWidth();
+ -- adjust scroll frame width
+ local scrollFrameWidth = scrollFrame.defaultWidth - scrollBarWidth;
+ scrollFrame:SetWidth(scrollFrameWidth);
+ scrollFrame.scrollChild:SetWidth(scrollFrameWidth);
+ -- adjust button width
+ local buttonWidth = scrollFrame.defaultButtonWidth - scrollBarWidth;
+ for _, button in next, scrollFrame.buttons do
+ button:SetWidth(buttonWidth);
+ end
+ getmetatable(self).__index.Show(self);
+ end
+ scrollBar.Hide =
+ function (self)
+ local scrollFrame = self:GetParent();
+ -- adjust scroll frame width
+ local scrollFrameWidth = scrollFrame.defaultWidth;
+ scrollFrame:SetWidth(scrollFrameWidth);
+ scrollFrame.scrollChild:SetWidth(scrollFrameWidth);
+ -- adjust button width
+ local buttonWidth = scrollFrame.defaultButtonWidth;
+ for _, button in next, scrollFrame.buttons do
+ button:SetWidth(buttonWidth);
+ end
+ getmetatable(self).__index.Hide(self);
+ end
+
+ self.update = CalendarEventPickerScrollFrame_Update;
+ HybridScrollFrame_CreateButtons(self, "CalendarEventPickerButtonTemplate");
+
+ local scrollBarWidth = scrollBar:GetWidth();
+ self.defaultWidth = self:GetWidth() + scrollBarWidth;
+ self.defaultButtonWidth = self.buttons[1]:GetWidth() + scrollBarWidth;
+
+ -- we don't need this event any more
+ self:UnregisterEvent(event);
+ end
+end
+
+function CalendarEventPickerScrollFrame_Update()
+ local dayButton = CalendarEventPickerFrame.dayButton;
+ local monthOffset = dayButton.monthOffset;
+ local day = dayButton.day;
+ local numViewableEvents = dayButton.numViewableEvents;
+ if ( numViewableEvents <= CALENDAR_DAYBUTTON_MAX_VISIBLE_EVENTS ) then
+ CalendarEventPickerFrame_Hide();
+ return;
+ end
+
+ -- since we aren't displaying ongoing events, we need to count all ongoing events towards the offset
+ -- if they come before the offset
+ local offset = HybridScrollFrame_GetOffset(CalendarEventPickerScrollFrame);
+ local eventIndex = 1 + offset;
+ for i=1, offset do
+ local title, hour, minute, calendarType, sequenceType = CalendarGetDayEvent(monthOffset, day, i);
+ if ( title and sequenceType == "ONGOING" ) then
+ eventIndex = eventIndex + 1;
+ end
+ end
+
+ -- only check the selected event index if we're looking at the right month
+ local selectedEventMonthOffset, selectedEventDay, selectedEventIndex = CalendarGetEventIndex();
+ if ( selectedEventIndex <= 0 or
+ day ~= selectedEventDay or monthOffset ~= selectedEventMonthOffset ) then
+ selectedEventIndex = nil;
+ end
+
+ -- now fill in the buttons starting from the already-offset event index
+ local buttons = CalendarEventPickerScrollFrame.buttons;
+ local numButtons = #buttons;
+ local buttonHeight = buttons[1]:GetHeight();
+ local displayedHeight = 0;
+
+ local numEvents = CalendarGetNumDayEvents(monthOffset, day);
+
+ local button, buttonName, buttonIcon, buttonTitle, buttonTime;
+ local texturePath, tcoords;
+ local eventColor;
+ local i = 1;
+ while ( i <= numButtons and eventIndex <= numEvents ) do
+ local title, hour, minute, calendarType, sequenceType, eventType, texture,
+ modStatus, inviteStatus, invitedBy, difficulty, inviteType,
+ sequenceIndex, numSequenceDays, difficultyName = CalendarGetDayEvent(monthOffset, day, eventIndex);
+ if ( sequenceType ~= "ONGOING" ) then
+ -- pretend like ongoing events aren't even in the event list
+ button = buttons[i];
+ if ( title ) then
+ buttonName = button:GetName();
+ buttonIcon = _G[buttonName.."Icon"];
+ buttonTitle = _G[buttonName.."Title"];
+ buttonTime = _G[buttonName.."Time"];
+
+ button.eventIndex = eventIndex;
+
+ -- set event texture
+ buttonIcon:SetTexture();
+ texturePath, tcoords = _CalendarFrame_GetTextureFile(texture, calendarType, sequenceType, eventType);
+ if ( texturePath and texturePath ~= "" ) then
+ buttonIcon:SetTexture(texturePath);
+ buttonIcon:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ buttonIcon:Show();
+ buttonTitle:SetPoint("TOPLEFT", buttonIcon, "TOPRIGHT");
+ else
+ buttonIcon:Hide();
+ buttonTitle:SetPoint("TOPLEFT", button, "TOPLEFT");
+ end
+
+ -- set event title and time
+ if ( calendarType == "HOLIDAY" ) then
+ buttonTime:Hide();
+ buttonTitle:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT");
+ else
+ if ( calendarType == "RAID_RESET" or calendarType == "RAID_LOCKOUT" ) then
+ title = GetDungeonNameWithDifficulty(title, difficultyName);
+ end
+ buttonTime:SetText(GameTime_GetFormattedTime(hour, minute, true));
+ buttonTime:Show();
+ buttonTitle:SetPoint("BOTTOMLEFT", buttonTime, "BOTTOMLEFT");
+ end
+ buttonTitle:SetFormattedText(CALENDAR_CALENDARTYPE_NAMEFORMAT[calendarType][sequenceType], title);
+ -- set event color
+ eventColor = _CalendarFrame_GetEventColor(calendarType, modStatus, inviteStatus);
+ buttonTitle:SetTextColor(eventColor.r, eventColor.g, eventColor.b);
+
+ -- set selected event
+ if ( selectedEventIndex and eventIndex == selectedEventIndex ) then
+ CalendarEventPickerFrame_SetSelectedEvent(button);
+ else
+ button:UnlockHighlight();
+ end
+
+ button:Show();
+ else
+ -- non-existent events, unlike ongoing events, will take up button slots to indicate
+ -- holes in the event list (though the holes should all be at the end)
+ button.eventIndex = nil;
+ button:Hide();
+ end
+ i = i + 1;
+ displayedHeight = displayedHeight + buttonHeight;
+ end
+ eventIndex = eventIndex + 1;
+ end
+ -- hide any unused buttons
+ while ( i <= numButtons ) do
+ button = buttons[i];
+ button.eventIndex = nil;
+ button:Hide();
+ i = i + 1;
+ end
+ local totalHeight = numViewableEvents * buttonHeight;
+ HybridScrollFrame_Update(CalendarEventPickerScrollFrame, totalHeight, displayedHeight);
+end
+
+function CalendarEventPickerCloseButton_OnClick()
+ CalendarEventPickerFrame_Hide();
+end
+
+function CalendarEventPickerButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+end
+
+function CalendarEventPickerButton_OnClick(self, button)
+ if ( button == "LeftButton" ) then
+ CalendarEventPickerButton_Click(self);
+ CalendarContextMenu_Hide();
+ elseif ( button == "RightButton" ) then
+ local dayButton = CalendarEventPickerFrame.dayButton;
+
+ local eventChanged =
+ CalendarContextMenu.eventButton ~= self or
+ CalendarContextMenu.dayButton ~= dayButton;
+
+ local flags = CALENDAR_CONTEXTMENU_FLAG_SHOWEVENT;
+ if ( eventChanged ) then
+ CalendarContextMenu_Show(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton, self);
+ else
+ CalendarContextMenu_Toggle(self, CalendarDayContextMenu_Initialize, "cursor", 3, -3, flags, dayButton, self);
+ end
+ end
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+function CalendarEventPickerButton_Click(button)
+ -- select the event
+ CalendarEventPickerFrame_SetSelectedEvent(button);
+
+ local eventIndex = button.eventIndex;
+ local dayButton = CalendarEventPickerFrame.dayButton;
+
+ -- search for the corresponding event button on the calendar frame if the event changed
+ local dayButtonName = dayButton:GetName();
+ local dayEventButton;
+ for i = 1, CALENDAR_DAYBUTTON_MAX_VISIBLE_EVENTS do
+ local curDayEventButton = _G[dayButtonName.."EventButton"..i];
+ if ( curDayEventButton.eventIndex and curDayEventButton.eventIndex == eventIndex ) then
+ dayEventButton = curDayEventButton;
+ break;
+ end
+ end
+ if ( dayEventButton ) then
+ -- if we found the day event button then click it...
+ CalendarDayEventButton_Click(dayEventButton, true);
+ else
+ CalendarFrame_SetSelectedEvent();
+ --...otherwise this event is not visible on the calendar, only the picker, so we need to do the selection
+ -- work that would have otherwise happened by clicking the calendar event button
+ StaticPopup_Hide("CALENDAR_DELETE_EVENT");
+ CalendarFrame_OpenEvent(dayButton, eventIndex);
+ end
+end
+
+function CalendarEventPickerButton_OnDoubleClick(self, button)
+ CalendarEventPickerButton_OnClick(self, button);
+ CalendarEventPickerCloseButton_OnClick();
+end
+
+
+-- CalendarTexturePickerFrame
+
+function CalendarTexturePickerFrame_OnLoad(self)
+ self.selectedTextureIndex = nil;
+ CalendarTexturePickerScrollFrame.update = CalendarTexturePickerScrollFrame_Update;
+ HybridScrollFrame_CreateButtons(CalendarTexturePickerScrollFrame, "CalendarTexturePickerButtonTemplate");
+end
+
+function CalendarTexturePickerFrame_Show(eventType)
+ if ( not eventType ) then
+ return;
+ end
+ if ( eventType ~= CalendarTexturePickerFrame.eventType) then
+ if ( not _CalendarFrame_CacheEventTextures(eventType) ) then
+ return;
+ end
+ -- new event type...reset the selected texture
+ CalendarTexturePickerFrame.selectedTextureIndex = nil;
+ CalendarTexturePickerFrame.eventType = eventType;
+ else
+ CalendarTexturePickerFrame.selectedTextureIndex = CalendarCreateEventFrame.selectedTextureIndex;
+ end
+ CalendarTexturePickerFrame:Show();
+ CalendarTexturePickerFrame_Update();
+end
+
+function CalendarTexturePickerFrame_Hide()
+ CalendarTexturePickerFrame.eventType = nil;
+ CalendarTexturePickerFrame.selectedTextureIndex = nil;
+ CalendarTexturePickerFrame:Hide();
+ -- clean up texture references
+ for i = 1, #CalendarTexturePickerScrollFrame.buttons do
+ _G[CalendarTexturePickerScrollFrame.buttons[i]:GetName().."Icon"]:SetTexture();
+ end
+end
+
+function CalendarTexturePickerFrame_Toggle(eventType)
+ if ( CalendarTexturePickerFrame:IsShown() ) then
+ CalendarTexturePickerFrame_Hide();
+ else
+ CalendarTexturePickerFrame_Show(eventType);
+ end
+end
+
+function CalendarTexturePickerFrame_Update()
+ if ( not CalendarTexturePickerFrame.eventType ) then
+ CalendarTexturePickerFrame_Hide();
+ return;
+ end
+
+ CalendarTexturePickerTitleFrame_Update();
+ CalendarTexturePickerScrollFrame_Update();
+end
+
+function CalendarTexturePickerTitleFrame_Update()
+ if ( CalendarTexturePickerFrame.eventType == CALENDAR_EVENTTYPE_RAID ) then
+ CalendarTitleFrame_SetText(CalendarTexturePickerTitleFrame, CALENDAR_TEXTURE_PICKER_TITLE_RAID);
+ else
+ CalendarTitleFrame_SetText(CalendarTexturePickerTitleFrame, CALENDAR_TEXTURE_PICKER_TITLE_DUNGEON);
+ end
+end
+
+function CalendarTexturePickerScrollFrame_OnLoad(self)
+ HybridScrollFrame_OnLoad(self);
+ -- register the addon loaded event for post-load fixups
+ self:RegisterEvent("ADDON_LOADED");
+ self:SetScript("OnEvent", CalendarTexturePickerScrollFrame_OnEvent);
+end
+
+function CalendarTexturePickerScrollFrame_OnEvent(self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local addonName = ...;
+ if ( not addonName or (addonName and addonName ~= "Blizzard_Calendar") ) then
+ return;
+ end
+
+ local scrollBar = self.scrollBar;
+ scrollBar.Show =
+ function (self)
+ local scrollFrame = self:GetParent();
+ local scrollBarWidth = self:GetWidth();
+ -- adjust scroll frame width
+ local scrollFrameWidth = scrollFrame.defaultWidth - scrollBarWidth;
+ scrollFrame:SetWidth(scrollFrameWidth);
+ scrollFrame.scrollChild:SetWidth(scrollFrameWidth);
+ -- adjust button width
+ local buttonWidth = scrollFrame.defaultButtonWidth - scrollBarWidth;
+ for _, button in next, scrollFrame.buttons do
+ button:SetWidth(buttonWidth);
+ end
+ getmetatable(self).__index.Show(self);
+ end
+ scrollBar.Hide =
+ function (self)
+ local scrollFrame = self:GetParent();
+ -- adjust scroll frame width
+ local scrollFrameWidth = scrollFrame.defaultWidth;
+ scrollFrame:SetWidth(scrollFrameWidth);
+ scrollFrame.scrollChild:SetWidth(scrollFrameWidth);
+ -- adjust button width
+ local buttonWidth = scrollFrame.defaultButtonWidth;
+ for _, button in next, scrollFrame.buttons do
+ button:SetWidth(buttonWidth);
+ end
+ getmetatable(self).__index.Hide(self);
+ end
+
+ self.update = CalendarTexturePickerScrollFrame_Update;
+ HybridScrollFrame_CreateButtons(self, "CalendarTexturePickerButtonTemplate");
+
+ local scrollBarWidth = scrollBar:GetWidth();
+ self.defaultWidth = self:GetWidth() + scrollBarWidth;
+ self.defaultButtonWidth = self.buttons[1]:GetWidth() + scrollBarWidth;
+
+ -- we don't need this event any more
+ self:UnregisterEvent(event);
+ end
+end
+
+function CalendarTexturePickerScrollFrame_Update()
+ local buttons = CalendarTexturePickerScrollFrame.buttons;
+ local numButtons = #buttons;
+ local buttonHeight = buttons[1]:GetHeight();
+ local displayedHeight = 0;
+
+ local button, buttonName, buttonIcon, buttonTitle;
+ local eventTex, textureIndex;
+ local selectedTextureIndex = CalendarTexturePickerFrame.selectedTextureIndex;
+ local eventType = CalendarTexturePickerFrame.eventType;
+ local numTextures = #CalendarEventTextureCache;
+ local offset = HybridScrollFrame_GetOffset(CalendarTexturePickerScrollFrame);
+ for i = 1, numButtons do
+ button = buttons[i];
+ buttonName = button:GetName();
+ textureIndex = i + offset;
+ eventTex = CalendarEventTextureCache[textureIndex];
+ if ( eventTex ) then
+ buttonIcon = _G[buttonName.."Icon"];
+ buttonTitle = _G[buttonName.."Title"];
+
+ if ( eventTex.textureIndex ) then
+ -- this is a texture
+
+ -- record the textureIndex in the button
+ button.textureIndex = eventTex.textureIndex;
+ -- set the selected dungeon
+ if ( selectedTextureIndex and button.textureIndex == selectedTextureIndex ) then
+ button:LockHighlight();
+ CalendarTexturePickerFrame.selectedTexture = button;
+ else
+ button:UnlockHighlight();
+ end
+
+ -- set the eventTex title
+ local name = eventTex.title;
+ buttonTitle:SetText(GetDungeonNameWithDifficulty(name, eventTex.difficultyName));
+ buttonTitle:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ buttonTitle:ClearAllPoints();
+ buttonTitle:SetPoint("LEFT", buttonIcon, "RIGHT");
+ buttonTitle:Show();
+ -- set the eventTex icon
+ buttonIcon:SetTexture();
+ local tcoords = CALENDAR_EVENTTYPE_TCOORDS[eventType];
+ buttonIcon:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ if ( eventTex.texture ~= "" ) then
+ buttonIcon:SetTexture(CALENDAR_EVENTTYPE_TEXTURE_PATHS[eventType]..eventTex.texture);
+ else
+ buttonIcon:SetTexture(CALENDAR_EVENTTYPE_TEXTURES[eventType]);
+ end
+ buttonIcon:Show();
+ -- make this button selectable
+ button:Enable();
+ elseif ( eventTex.expansionLevel and eventTex.expansionLevel >= 0 ) then
+ -- this is a header
+
+ -- record the textureIndex in the button
+ button.textureIndex = eventTex.textureIndex;
+
+ -- set the header title
+ buttonTitle:SetText(eventTex.title);
+ buttonTitle:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ buttonTitle:ClearAllPoints();
+ buttonTitle:SetPoint("LEFT", buttonIcon, "LEFT");
+ buttonTitle:Show();
+ -- hide the icon
+ buttonIcon:Hide();
+ -- make this button unselectable
+ button:Disable();
+ else
+ -- this is a blank space
+ buttonTitle:Hide();
+ buttonIcon:Hide();
+ button:Disable();
+ end
+
+ button:Show();
+ else
+ button.textureIndex = nil;
+ button:Hide();
+ end
+ displayedHeight = displayedHeight + buttonHeight;
+ end
+ local totalHeight = numTextures * buttonHeight;
+ HybridScrollFrame_Update(CalendarTexturePickerScrollFrame, totalHeight, displayedHeight);
+end
+
+function CalendarTexturePickerAcceptButton_OnClick(self)
+ CalendarCreateEventFrame.selectedTextureIndex = CalendarTexturePickerFrame.selectedTextureIndex;
+ if ( CalendarCreateEventFrame.selectedTextureIndex ) then
+ -- now that we've selected a texture, we can set the create event data
+ local eventType = CalendarTexturePickerFrame.eventType;
+ CalendarEventSetType(eventType);
+ CalendarEventSetTextureID(CalendarCreateEventFrame.selectedTextureIndex);
+ -- update the create event frame using our selection
+ UIDropDownMenu_SetSelectedID(CalendarCreateEventTypeDropDown, eventType);
+ CalendarCreateEventFrame.selectedEventType = eventType;
+ CalendarCreateEventTexture_Update();
+ CalendarTexturePickerFrame:Hide();
+
+ CalendarCreateEventCreateButton_Update();
+ end
+end
+
+function CalendarTexturePickerButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+end
+
+function CalendarTexturePickerButton_OnClick(self, button)
+ if ( CalendarTexturePickerFrame.selectedTexture ) then
+ CalendarTexturePickerFrame.selectedTexture:UnlockHighlight();
+ end
+ CalendarTexturePickerFrame.selectedTexture = self;
+ CalendarTexturePickerFrame.selectedTextureIndex = self.textureIndex;
+ self:LockHighlight();
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+function CalendarTexturePickerButton_OnDoubleClick(self, button)
+ CalendarTexturePickerButton_OnClick(self, button);
+ CalendarTexturePickerAcceptButton_OnClick(self);
+end
+
+
+-- Calendar Class Buttons
+
+function CalendarClassButtonContainer_Show(parent)
+ if ( CalendarClassButtonContainer:GetParent() ~= parent ) then
+ CalendarClassButtonContainer:SetParent(parent);
+ CalendarClassButtonContainer:ClearAllPoints();
+ CalendarClassButtonContainer:SetPoint("TOPLEFT", parent, "TOPRIGHT", -2, -30);
+ end
+ CalendarClassButtonContainer:Show();
+ _CalendarFrame_UpdateClassData();
+ CalendarClassButtonContainer_Update();
+end
+
+function CalendarClassButtonContainer_Hide()
+ CalendarClassButtonContainer:SetParent(nil);
+ CalendarClassButtonContainer:Hide();
+end
+
+function CalendarClassButtonContainer_Update()
+ if ( not CalendarClassButtonContainer:IsShown() ) then
+ return;
+ end
+
+ local isModal = CalendarFrame_GetModal();
+
+ local button, buttonName, buttonIcon, buttonCount;
+ local classData, count;
+ local totalCount = 0;
+ for i, class in ipairs(CLASS_SORT_ORDER) do
+ button = _G["CalendarClassButton"..i];
+ buttonName = button:GetName();
+ buttonCount = _G[buttonName.."Count"];
+ buttonIcon = button:GetNormalTexture();
+ -- set the count
+ classData = CalendarClassData[class];
+ count = classData.counts[CALENDAR_INVITESTATUS_CONFIRMED] +
+ classData.counts[CALENDAR_INVITESTATUS_ACCEPTED] +
+ classData.counts[CALENDAR_INVITESTATUS_SIGNEDUP];
+ buttonCount:SetText(count);
+ if ( count > 0 ) then
+ buttonCount:Show();
+ if ( isModal ) then
+ SetDesaturation(buttonIcon, true);
+ button:Disable();
+ else
+ SetDesaturation(buttonIcon, false);
+ button:Enable();
+ end
+ else
+ buttonCount:Hide();
+ SetDesaturation(buttonIcon, true);
+ button:Disable();
+ end
+ -- adjust the total
+ totalCount = totalCount + count;
+ end
+
+ -- set the total
+ CalendarClassTotalsText:SetText(totalCount);
+ CalendarClassTotalsButton_Update();
+end
+
+function CalendarClassButtonContainer_OnLoad(self)
+ local button, buttonName, buttonIcon;
+ local classData, tcoords;
+
+ for i, class in ipairs(CLASS_SORT_ORDER) do
+ -- create button
+ button = CreateFrame("Button", "CalendarClassButton"..i, self, "CalendarClassButtonTemplate");
+ if ( i == 1 ) then
+ button:SetPoint("TOPLEFT", self, "TOPLEFT");
+ else
+ button:SetPoint("TOPLEFT", "CalendarClassButton"..(i-1), "BOTTOMLEFT", 0, -12);
+ end
+ -- get class data
+ classData = CalendarClassData[class];
+ -- set texture
+ buttonIcon = button:GetNormalTexture();
+ buttonIcon:SetDrawLayer("BORDER");
+ tcoords = classData.tcoords;
+ buttonIcon:SetTexCoord(tcoords[1], tcoords[2], tcoords[3], tcoords[4]);
+ -- set class
+ button.class = class;
+ end
+ CalendarClassTotalsButton:SetPoint("TOPLEFT", "CalendarClassButton"..MAX_CLASSES, "BOTTOMLEFT", 0, -12);
+end
+
+function CalendarClassButton_OnLoad(self)
+ self:Disable();
+end
+
+function CalendarClassButton_OnEnter(self)
+ -- TODO: set detailed counts info
+ local classData = CalendarClassData[self.class];
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(classData.name, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+end
+--[[
+function CalendarClassTotalsButton_OnLoad(self)
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+end
+
+function CalendarClassTotalsButton_OnEvent(self, event, ...)
+ if ( self:IsShown() and event == "PARTY_MEMBERS_CHANGED" ) then
+ if ( CalendarEventGetNumInvites() > MAX_PARTY_MEMBERS + 1 and GetRealNumPartyMembers() >= 1 and GetRealNumRaidMembers() == 0 ) then
+ -- we don't have a good way of knowing in advance whether or not we need a raid to accomodate all our invites
+ -- so we're going to create a raid as soon as possible
+ ConvertToRaid();
+ end
+ CalendarClassTotalsButton_Update();
+ end
+end
+
+function CalendarClassTotalsButton_Update()
+ if ( CalendarFrame_GetModal() ) then
+ CalendarClassTotalsButton:Disable();
+ CalendarInviteToGroupDropDown:Hide();
+ CalendarClassTotalsButton:SetDisabledFontObject(GameFontDisableSmall);
+ CalendarClassTotalsButtonOnEnterDummy:Hide();
+ else
+ if ( CalendarClassButtonContainer:GetParent() == CalendarCreateEventFrame and
+ CalendarCreateEventFrame.mode == "edit" and
+ GetRealNumPartyMembers() == 0 and GetRealNumRaidMembers() == 0 ) then
+ CalendarClassTotalsButton:Enable();
+ CalendarClassTotalsButtonOnEnterDummy:Hide();
+ else
+ CalendarClassTotalsButton:Disable();
+ CalendarInviteToGroupDropDown:Hide();
+ CalendarClassTotalsButtonOnEnterDummy:Show();
+ end
+ CalendarClassTotalsButton:SetDisabledFontObject(GameFontGreenSmall);
+ end
+end
+
+function CalendarClassTotalsButton_OnClick(self)
+ ToggleDropDownMenu(1, nil, CalendarInviteToGroupDropDown, self, 0, 0);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+function CalendarClassTotalsButtonOnEnterDummy_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(CALENDAR_TOOLTIP_INVITE_TOTALS, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+end
+
+function CalendarClassTotalsButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if ( CalendarEventGetNumInvites() > MAX_PARTY_MEMBERS + 1 ) then
+ GameTooltip:SetText(CALENDAR_TOOLTIP_INVITEMEMBERS_BUTTON_RAID, nil, nil, nil, nil, 1);
+ else
+ GameTooltip:SetText(CALENDAR_TOOLTIP_INVITEMEMBERS_BUTTON_PARTY, nil, nil, nil, nil, 1);
+ end
+ GameTooltip:Show();
+end
+
+function CalendarInviteToGroupDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(CalendarInviteToGroupDropDown, CalendarInviteToGroupDropDown_Initialize, "MENU");
+ UIDropDownMenu_SetWidth(CalendarInviteToGroupDropDown, 100);
+end
+
+function CalendarInviteToGroupDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = CALENDAR_INVITE_CONFIRMED;
+ info.func = CalendarInviteToGroupDropDown_Confirmed_OnClick;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CALENDAR_INVITE_ALL;
+ info.func = CalendarInviteToGroupDropDown_All_OnClick;
+ UIDropDownMenu_AddButton(info);
+end
+
+function CalendarInviteToGroupDropDown_Confirmed_OnClick(self)
+ local name, level, className, classFilename, inviteStatus, modStatus;
+ local inviteCount = min(MAX_RAID_MEMBERS - GetRealNumRaidMembers(), CalendarEventGetNumInvites());
+ for i = 1, inviteCount do
+ name, level, className, classFilename, inviteStatus, modStatus = CalendarEventGetInvite(i);
+ if ( not UnitInParty(name) and not UnitInRaid(name) and
+ (inviteStatus == CALENDAR_INVITESTATUS_ACCEPTED or inviteStatus == CALENDAR_INVITESTATUS_CONFIRMED) ) then
+ InviteUnit(name);
+ end
+ end
+end
+
+function CalendarInviteToGroupDropDown_All_OnClick(self)
+ local inviteCount = min(MAX_RAID_MEMBERS - GetRealNumRaidMembers(), CalendarEventGetNumInvites());
+ for i = 1, inviteCount do
+ local name = CalendarEventGetInvite(i);
+ if ( not UnitInParty(name) and not UnitInRaid(name) ) then
+ InviteUnit(name);
+ end
+ end
+end
+--]]
+
+function CalendarClassTotalsButton_Update()
+ if ( CalendarFrame_GetModal() ) then
+ CalendarClassTotalsButton:Disable();
+ CalendarClassTotalsText:SetFontObject(GameFontDisableSmall);
+ else
+ CalendarClassTotalsButton:Enable();
+ CalendarClassTotalsText:SetFontObject(GameFontGreenSmall);
+ end
+end
+
+function CalendarClassTotalsButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(CALENDAR_TOOLTIP_INVITE_TOTALS, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+end
+
diff --git a/reference/AddOns/Blizzard_Calendar/Blizzard_Calendar.toc b/reference/AddOns/Blizzard_Calendar/Blizzard_Calendar.toc
new file mode 100644
index 0000000..0f1dfaf
--- /dev/null
+++ b/reference/AddOns/Blizzard_Calendar/Blizzard_Calendar.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard Calendar
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_Calendar.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_Calendar/Blizzard_Calendar.xml b/reference/AddOns/Blizzard_Calendar/Blizzard_Calendar.xml
new file mode 100644
index 0000000..5f82b6e
--- /dev/null
+++ b/reference/AddOns/Blizzard_Calendar/Blizzard_Calendar.xml
@@ -0,0 +1,1809 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.timer = 0;
+ self.fadeTime = 1.5;
+ self.fadein = true;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetAllPoints(CalendarFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 3);
+
+
+ self:ClearAllPoints();
+ self:SetPoint("TOPLEFT", CalendarDayButton1, "TOPLEFT");
+ self:SetPoint("BOTTOMRIGHT", CalendarDayButton42, "BOTTOMRIGHT");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 6);
+
+
+
+
+
+
+
+
+
+
+
+
+ self.scrollBarHideable = 1;
+ ScrollFrame_OnLoad(self);
+ ScrollFrame_OnScrollRangeChanged(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 6);
+
+
+
+
+
+
+
+
+
+
+
+
+ self.scrollBarHideable = 1;
+ ScrollFrame_OnLoad(self);
+ ScrollFrame_OnScrollRangeChanged(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 6);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(0.0, 0.0, 0.0, 0.9);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 6);
+
+
+
+
+
+
+
+
+
+
+
+
+ EditBox_HandleTabbing(self, CALENDAR_CREATEEVENTFRAME_TAB_LIST);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarCreateEventDescriptionEdit:SetFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ EditBox_HandleTabbing(self, CALENDAR_CREATEEVENTFRAME_TAB_LIST);
+
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent());
+ CalendarEventSetDescription(self:GetText());
+ CalendarCreateEventCreateButton_Update();
+
+
+
+ ScrollingEdit_OnUpdate(self, elapsed, self:GetParent());
+
+
+
+ if ( self:GetText() == CALENDAR_EVENT_DESCRIPTION ) then
+ self:HighlightText();
+ end
+
+
+ self:HighlightText(0, 0);
+ if ( self:GetText() == "" ) then
+ self:SetText(CALENDAR_EVENT_DESCRIPTION);
+ end
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(0.0, 0.0, 0.0, 0.9);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(CALENDAR_TOOLTIP_AUTOAPPROVE, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+ --GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, CALENDAR_TOOLTIP_AUTOAPPROVE, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(CALENDAR_TOOLTIP_LOCKEVENT, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+ --GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, CALENDAR_TOOLTIP_LOCKEVENT, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetText(CALENDAR_PLAYER_NAME);
+
+
+ if ( not AutoCompleteEditBox_OnTabPressed(self) ) then
+ EditBox_HandleTabbing(self, CALENDAR_CREATEEVENTFRAME_TAB_LIST);
+ end
+
+
+
+ if ( not AutoCompleteEditBox_OnEscapePressed(self) ) then
+ EditBox_ClearFocus(self);
+ end
+
+
+
+
+ if ( userInput ) then
+ local isGuildEvent = CalendarEventGetCalendarType() == "GUILD_EVENT";
+ if ( isGuildEvent ) then
+ self.autoCompleteParams = AUTOCOMPLETE_LIST.CALENDARGUILDEVENT;
+ else
+ self.autoCompleteParams = AUTOCOMPLETE_LIST.CALENDAREVENT;
+ end
+ AutoCompleteEditBox_OnTextChanged(self, userInput);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth() + 40);
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(CALENDAR_TOOLTIP_MASSINVITE, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+ --GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, CALENDAR_TOOLTIP_MASSINVITE, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarTitleFrame_SetText(self, CALENDAR_MASS_INVITE);
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 6);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( not CanEditGuildEvent() ) then
+ self:ClearFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( not CanEditGuildEvent() ) then
+ self:ClearFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarMassInviteFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarTitleFrame_SetText(self, CALENDAR_EVENT_PICKER_TITLE);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_Calendar/Blizzard_CalendarTemplates.xml b/reference/AddOns/Blizzard_Calendar/Blizzard_CalendarTemplates.xml
new file mode 100644
index 0000000..aad2640
--- /dev/null
+++ b/reference/AddOns/Blizzard_Calendar/Blizzard_CalendarTemplates.xml
@@ -0,0 +1,684 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarDayButtonMoreEventsButton_OnLoad(self);
+
+
+ CalendarDayButtonMoreEventsButton_OnEnter(self, motion);
+
+
+ CalendarDayButtonMoreEventsButton_OnLeave(self, motion);
+
+
+ CalendarDayButtonMoreEventsButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaiseFrameLevel(self);
+
+
+
+
+
+
+ CalendarDayButton_OnLoad(self);
+
+
+ CalendarDayButton_OnEnter(self, motion);
+
+
+ CalendarDayButton_OnLeave(self, motion);
+
+
+ CalendarDayButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarDayEventButton_OnLoad(self);
+
+
+ CalendarDayEventButton_OnEnter(self, motion);
+
+
+ CalendarDayEventButton_OnLeave(self, motion);
+
+
+ CalendarDayEventButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 6);
+
+
+
+
+
+
+
+
+
+
+
+ CalendarEventCloseButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarEventDescriptionScrollFrame_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarEventInviteSortButton_OnLoad(self);
+
+
+ CalendarEventInviteSortButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HybridScrollFrame_OnLoad(self);
+ self:GetParent().scrollFrame = self;
+
+
+
+
+
+
+
+
+
+
+
+ --[[
+ if ( self:GetParent().partyMode ) then
+ self.criterion = "party";
+ else
+ self.criterion = "name";
+ end
+ --]]
+ self.criterion = "name";
+ CalendarEventInviteSortButton_OnClick(self);
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarEventInviteSortButton_OnLoad(self);
+ self.criterion = "class";
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarEventInviteSortButton_OnLoad(self);
+ self.criterion = "status";
+
+
+
+
+
+
+
+ CalendarEventInviteList_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ CalendarEventInviteListButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarViewEventInviteListButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+ CalendarCreateEventInviteListButton_OnClick(self, button, down);
+
+
+
+
+
+
+ CalendarMassInviteArenaButton_OnLoad(self);
+
+
+ CalendarMassInviteArenaButton_OnClick(self, button, down);
+
+
+ CalendarMassInviteArenaButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+ CalendarFrame_PushModal(self);
+
+
+ CalendarFrame_PopModal(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() + 5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarEventPickerButton_OnLoad(self);
+
+
+ CalendarEventPickerButton_OnClick(self, button, down);
+
+
+ CalendarEventPickerCloseButton_OnClick(self, button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarTexturePickerButton_OnLoad(self);
+
+
+ CalendarTexturePickerButton_OnClick(self, button, down);
+
+
+ CalendarTexturePickerButton_OnDoubleClick(self, button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CalendarClassButton_OnLoad(self);
+
+
+ CalendarClassButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_Calendar/Localization.lua b/reference/AddOns/Blizzard_Calendar/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_Calendar/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_CombatLog/Blizzard_CombatLog.lua b/reference/AddOns/Blizzard_CombatLog/Blizzard_CombatLog.lua
new file mode 100644
index 0000000..bc982a5
--- /dev/null
+++ b/reference/AddOns/Blizzard_CombatLog/Blizzard_CombatLog.lua
@@ -0,0 +1,3717 @@
+--[[
+-- Blizzard Combat Log
+-- by Alexander Yoshi
+--
+-- This is a prototype combat log designed to serve the
+-- majority of needs for WoW players. The new and improved
+-- combat log event formatting should allow for the community
+-- to develop even better combat logs in the future.
+--
+-- Thanks to:
+-- Chris Heald & Xinhuan - Code Optimization Support
+--
+--]]
+
+-- Version
+-- Constant -- Incrementing this number will erase saved filter settings!!
+COMBATLOG_FILTER_VERSION = 4.1;
+-- Saved Variable
+Blizzard_CombatLog_Filter_Version = 0;
+
+-- Define the log
+COMBATLOG = ChatFrame2;
+
+-- BUFF / DEBUFF
+AURA_TYPE_BUFF = "BUFF";
+AURA_TYPE_DEBUFF = "DEBUFF"
+
+-- Message Limit
+COMBATLOG_LIMIT_PER_FRAME = 1;
+COMBATLOG_HIGHLIGHT_MULTIPLIER = 1.5;
+
+-- Default Colors
+COMBATLOG_DEFAULT_COLORS = {
+ -- Unit names
+ unitColoring = {
+ [COMBATLOG_FILTER_MINE] = {a=1.0,r=0.70,g=0.70,b=0.70}; --{a=1.0,r=0.14,g=1.00,b=0.15};
+ [COMBATLOG_FILTER_MY_PET] = {a=1.0,r=0.70,g=0.70,b=0.70}; --{a=1.0,r=0.14,g=0.80,b=0.15};
+ [COMBATLOG_FILTER_FRIENDLY_UNITS] = {a=1.0,r=0.34,g=0.64,b=1.00};
+ [COMBATLOG_FILTER_HOSTILE_UNITS] = {a=1.0,r=0.75,g=0.05,b=0.05};
+ [COMBATLOG_FILTER_HOSTILE_PLAYERS] = {a=1.0,r=0.75,g=0.05,b=0.05};
+ [COMBATLOG_FILTER_NEUTRAL_UNITS] = {a=1.0,r=0.75,g=0.05,b=0.05}; -- {a=1.0,r=0.80,g=0.80,b=0.14};
+ [COMBATLOG_FILTER_UNKNOWN_UNITS] = {a=1.0,r=0.75,g=0.75,b=0.75};
+ };
+ -- School coloring
+ schoolColoring = {
+ [SCHOOL_MASK_NONE] = {a=1.0,r=1.00,g=1.00,b=1.00};
+ [SCHOOL_MASK_PHYSICAL] = {a=1.0,r=1.00,g=1.00,b=0.00};
+ [SCHOOL_MASK_HOLY] = {a=1.0,r=1.00,g=0.90,b=0.50};
+ [SCHOOL_MASK_FIRE] = {a=1.0,r=1.00,g=0.50,b=0.00};
+ [SCHOOL_MASK_NATURE] = {a=1.0,r=0.30,g=1.00,b=0.30};
+ [SCHOOL_MASK_FROST] = {a=1.0,r=0.50,g=1.00,b=1.00};
+ [SCHOOL_MASK_SHADOW] = {a=1.0,r=0.50,g=0.50,b=1.00};
+ [SCHOOL_MASK_ARCANE] = {a=1.0,r=1.00,g=0.50,b=1.00};
+ };
+ -- Defaults
+ defaults = {
+ spell = {a=1.0,r=1.00,g=1.00,b=1.00};
+ damage = {a=1.0,r=1.00,g=1.00,b=0.00};
+ };
+ -- Line coloring
+ eventColoring = {
+ };
+
+ -- Highlighted events
+ highlightedEvents = {
+ ["PARTY_KILL"] = true;
+ };
+};
+COMBATLOG_DEFAULT_SETTINGS = {
+ -- Settings
+ fullText = true;
+ textMode = TEXT_MODE_A;
+ timestamp = false;
+ timestampFormat = TEXT_MODE_A_TIMESTAMP;
+ unitColoring = false;
+ sourceColoring = true;
+ destColoring = true;
+ lineColoring = true;
+ lineHighlighting = true;
+ abilityColoring = false;
+ abilityActorColoring = false;
+ abilitySchoolColoring = false;
+ abilityHighlighting = true;
+ actionColoring = false;
+ actionActorColoring = false;
+ actionHighlighting = false;
+ amountColoring = false;
+ amountActorColoring = false;
+ amountSchoolColoring = false;
+ amountHighlighting = true;
+ schoolNameColoring = false;
+ schoolNameActorColoring = false;
+ schoolNameHighlighting = true;
+ noMeleeSwingColoring = false;
+ missColoring = true;
+ braces = false;
+ unitBraces = true;
+ sourceBraces = true;
+ destBraces = true;
+ spellBraces = false;
+ itemBraces = true;
+ showHistory = true;
+ lineColorPriority = 1; -- 1 = source->dest->event, 2 = dest->source->event, 3 = event->source->dest
+ unitIcons = true;
+ hideBuffs = false;
+ hideDebuffs = false;
+ --unitTokens = true;
+};
+
+--
+-- Combat Log Icons
+--
+COMBATLOG_ICON_RAIDTARGET1 = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1.blp:0|t";
+COMBATLOG_ICON_RAIDTARGET2 = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_2.blp:0|t";
+COMBATLOG_ICON_RAIDTARGET3 = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_3.blp:0|t";
+COMBATLOG_ICON_RAIDTARGET4 = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_4.blp:0|t";
+COMBATLOG_ICON_RAIDTARGET5 = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_5.blp:0|t";
+COMBATLOG_ICON_RAIDTARGET6 = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_6.blp:0|t";
+COMBATLOG_ICON_RAIDTARGET7 = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_7.blp:0|t";
+COMBATLOG_ICON_RAIDTARGET8 = "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_8.blp:0|t";
+
+--
+-- Default Event List
+--
+COMBATLOG_EVENT_LIST = {
+ ["ENVIRONMENTAL_DAMAGE"] = true,
+ ["SWING_DAMAGE"] = true,
+ ["SWING_MISSED"] = true,
+ ["RANGE_DAMAGE"] = true,
+ ["RANGE_MISSED"] = true,
+ ["SPELL_CAST_START"] = false,
+ ["SPELL_CAST_SUCCESS"] = false,
+ ["SPELL_CAST_FAILED"] = false,
+ ["SPELL_MISSED"] = true,
+ ["SPELL_DAMAGE"] = true,
+ ["SPELL_HEAL"] = true,
+ ["SPELL_ENERGIZE"] = true,
+ ["SPELL_DRAIN"] = true,
+ ["SPELL_LEECH"] = true,
+ ["SPELL_SUMMON"] = true,
+ ["SPELL_RESURRECT"] = true,
+ ["SPELL_CREATE"] = true,
+ ["SPELL_INSTAKILL"] = true,
+ ["SPELL_INTERRUPT"] = true,
+ ["SPELL_EXTRA_ATTACKS"] = true,
+ ["SPELL_DURABILITY_DAMAGE"] = false,
+ ["SPELL_DURABILITY_DAMAGE_ALL"] = false,
+ ["SPELL_AURA_APPLIED"] = false,
+ ["SPELL_AURA_APPLIED_DOSE"] = false,
+ ["SPELL_AURA_REMOVED"] = false,
+ ["SPELL_AURA_REMOVED_DOSE"] = false,
+ ["SPELL_AURA_BROKEN"] = false,
+ ["SPELL_AURA_BROKEN_SPELL"] = false,
+ ["SPELL_AURA_REFRESH"] = false,
+ ["SPELL_DISPEL"] = true,
+ ["SPELL_STOLEN"] = true,
+ ["ENCHANT_APPLIED"] = true,
+ ["ENCHANT_REMOVED"] = true,
+ ["SPELL_PERIODIC_MISSED"] = true,
+ ["SPELL_PERIODIC_DAMAGE"] = true,
+ ["SPELL_PERIODIC_HEAL"] = true,
+ ["SPELL_PERIODIC_ENERGIZE"] = true,
+ ["SPELL_PERIODIC_DRAIN"] = true,
+ ["SPELL_PERIODIC_LEECH"] = true,
+ ["SPELL_DISPEL_FAILED"] = true,
+ ["DAMAGE_SHIELD"] = false,
+ ["DAMAGE_SHIELD_MISSED"] = false,
+ ["DAMAGE_SPLIT"] = false,
+ ["PARTY_KILL"] = true,
+ ["UNIT_DIED"] = true,
+ ["UNIT_DESTROYED"] = true,
+ ["SPELL_BUILDING_DAMAGE"] = true,
+ ["SPELL_BUILDING_HEAL"] = true,
+ ["UNIT_DISSIPATES"] = true,
+};
+
+COMBATLOG_FLAG_LIST = {
+ [COMBATLOG_FILTER_MINE] = true,
+ [COMBATLOG_FILTER_MY_PET] = true,
+ [COMBATLOG_FILTER_FRIENDLY_UNITS] = true,
+ [COMBATLOG_FILTER_HOSTILE_UNITS] = true,
+ [COMBATLOG_FILTER_HOSTILE_PLAYERS] = true,
+ [COMBATLOG_FILTER_NEUTRAL_UNITS] = true,
+ [COMBATLOG_FILTER_UNKNOWN_UNITS] = true,
+};
+
+EVENT_TEMPLATE_FORMATS = {
+ ["SPELL_AURA_BROKEN_SPELL"] = TEXT_MODE_A_STRING_3,
+ ["SPELL_CAST_START"] = TEXT_MODE_A_STRING_2,
+ ["SPELL_CAST_SUCCESS"] = TEXT_MODE_A_STRING_2
+};
+
+--
+-- Creates an empty filter
+--
+function Blizzard_CombatLog_InitializeFilters( settings )
+ settings.filters =
+ {
+ [1] = {
+ eventList = {};
+ };
+ };
+end
+
+--
+-- Generates a new event list from the COMBATLOG_EVENT_LIST global
+--
+-- I wish there was a better way built in to do this.
+--
+-- Returns:
+-- An array, indexed by the events, with a value of true
+--
+function Blizzard_CombatLog_GenerateFullEventList ( )
+ local eventList = {}
+ for event, v in pairs ( COMBATLOG_EVENT_LIST ) do
+ eventList[event] = true;
+ end
+ return eventList;
+end
+
+function Blizzard_CombatLog_GenerateFullFlagList(flag)
+ local flagList = {};
+ for k, v in pairs(COMBATLOG_FLAG_LIST) do
+ if ( flag ) then
+ flagList[k] = true
+ else
+ flagList[k] = false;
+ end
+ end
+ return flagList;
+end
+
+--
+-- Default CombatLog Filter
+-- This table is used to create new CombatLog filters
+--
+DEFAULT_COMBATLOG_FILTER_TEMPLATE = {
+ -- Descriptive Information
+ hasQuickButton = true;
+ quickButtonDisplay = {
+ solo = true;
+ party = true;
+ raid = true;
+ };
+
+ -- Default Color and Formatting Options
+ settings = CopyTable(COMBATLOG_DEFAULT_SETTINGS);
+
+ -- Coloring
+ colors = CopyTable(COMBATLOG_DEFAULT_COLORS);
+
+ -- The actual client filters
+ filters = {
+ [1] = {
+ eventList = Blizzard_CombatLog_GenerateFullEventList();
+ sourceFlags = {
+ [COMBATLOG_FILTER_MINE] = true,
+ [COMBATLOG_FILTER_MY_PET] = true;
+ };
+ destFlags = nil;
+ };
+ [2] = {
+ eventList = Blizzard_CombatLog_GenerateFullEventList();
+ sourceFlags = nil;
+ destFlags = {
+ [COMBATLOG_FILTER_MINE] = true,
+ [COMBATLOG_FILTER_MY_PET] = true;
+ };
+ };
+ };
+};
+
+
+local CombatLogUpdateFrame = CreateFrame("Frame", "CombatLogUpdateFrame", UIParent)
+local _G = getfenv(0)
+local bit_bor = _G.bit.bor
+local bit_band = _G.bit.band
+local tinsert = _G.tinsert
+local tremove = _G.tremove
+local math_floor = _G.math.floor
+local format = _G.format
+local gsub = _G.gsub
+local strsub = _G.strsub
+local strreplace = _G.strreplace;
+
+-- Make all the constants upvalues. This prevents the global environment lookup + table lookup each time we use one (and they're used a lot)
+local COMBATLOG_OBJECT_AFFILIATION_MINE = COMBATLOG_OBJECT_AFFILIATION_MINE
+local COMBATLOG_OBJECT_AFFILIATION_PARTY = COMBATLOG_OBJECT_AFFILIATION_PARTY
+local COMBATLOG_OBJECT_AFFILIATION_RAID = COMBATLOG_OBJECT_AFFILIATION_RAID
+local COMBATLOG_OBJECT_AFFILIATION_OUTSIDER = COMBATLOG_OBJECT_AFFILIATION_OUTSIDER
+local COMBATLOG_OBJECT_AFFILIATION_MASK = COMBATLOG_OBJECT_AFFILIATION_MASK
+local COMBATLOG_OBJECT_REACTION_FRIENDLY = COMBATLOG_OBJECT_REACTION_FRIENDLY
+local COMBATLOG_OBJECT_REACTION_NEUTRAL = COMBATLOG_OBJECT_REACTION_NEUTRAL
+local COMBATLOG_OBJECT_REACTION_HOSTILE = COMBATLOG_OBJECT_REACTION_HOSTILE
+local COMBATLOG_OBJECT_REACTION_MASK = COMBATLOG_OBJECT_REACTION_MASK
+local COMBATLOG_OBJECT_CONTROL_PLAYER = COMBATLOG_OBJECT_CONTROL_PLAYER
+local COMBATLOG_OBJECT_CONTROL_NPC = COMBATLOG_OBJECT_CONTROL_NPC
+local COMBATLOG_OBJECT_CONTROL_MASK = COMBATLOG_OBJECT_CONTROL_MASK
+local COMBATLOG_OBJECT_TYPE_PLAYER = COMBATLOG_OBJECT_TYPE_PLAYER
+local COMBATLOG_OBJECT_TYPE_NPC = COMBATLOG_OBJECT_TYPE_NPC
+local COMBATLOG_OBJECT_TYPE_PET = COMBATLOG_OBJECT_TYPE_PET
+local COMBATLOG_OBJECT_TYPE_GUARDIAN = COMBATLOG_OBJECT_TYPE_GUARDIAN
+local COMBATLOG_OBJECT_TYPE_OBJECT = COMBATLOG_OBJECT_TYPE_OBJECT
+local COMBATLOG_OBJECT_TYPE_MASK = COMBATLOG_OBJECT_TYPE_MASK
+local COMBATLOG_OBJECT_TARGET = COMBATLOG_OBJECT_TARGET
+local COMBATLOG_OBJECT_FOCUS = COMBATLOG_OBJECT_FOCUS
+local COMBATLOG_OBJECT_MAINTANK = COMBATLOG_OBJECT_MAINTANK
+local COMBATLOG_OBJECT_MAINASSIST = COMBATLOG_OBJECT_MAINASSIST
+local COMBATLOG_OBJECT_RAIDTARGET1 = COMBATLOG_OBJECT_RAIDTARGET1
+local COMBATLOG_OBJECT_RAIDTARGET2 = COMBATLOG_OBJECT_RAIDTARGET2
+local COMBATLOG_OBJECT_RAIDTARGET3 = COMBATLOG_OBJECT_RAIDTARGET3
+local COMBATLOG_OBJECT_RAIDTARGET4 = COMBATLOG_OBJECT_RAIDTARGET4
+local COMBATLOG_OBJECT_RAIDTARGET5 = COMBATLOG_OBJECT_RAIDTARGET5
+local COMBATLOG_OBJECT_RAIDTARGET6 = COMBATLOG_OBJECT_RAIDTARGET6
+local COMBATLOG_OBJECT_RAIDTARGET7 = COMBATLOG_OBJECT_RAIDTARGET7
+local COMBATLOG_OBJECT_RAIDTARGET8 = COMBATLOG_OBJECT_RAIDTARGET8
+local COMBATLOG_OBJECT_NONE = COMBATLOG_OBJECT_NONE
+local COMBATLOG_OBJECT_SPECIAL_MASK = COMBATLOG_OBJECT_SPECIAL_MASK
+local COMBATLOG_FILTER_ME = COMBATLOG_FILTER_ME
+local COMBATLOG_FILTER_MINE = COMBATLOG_FILTER_MINE
+local COMBATLOG_FILTER_MY_PET = COMBATLOG_FILTER_MY_PET
+local COMBATLOG_FILTER_FRIENDLY_UNITS = COMBATLOG_FILTER_FRIENDLY_UNITS
+local COMBATLOG_FILTER_HOSTILE_UNITS = COMBATLOG_FILTER_HOSTILE_UNITS
+local COMBATLOG_FILTER_HOSTILE_PLAYERS = COMBATLOG_FILTER_HOSTILE_PLAYERS
+local COMBATLOG_FILTER_NEUTRAL_UNITS = COMBATLOG_FILTER_NEUTRAL_UNITS
+local COMBATLOG_FILTER_UNKNOWN_UNITS = COMBATLOG_FILTER_UNKNOWN_UNITS
+local COMBATLOG_FILTER_EVERYTHING = COMBATLOG_FILTER_EVERYTHING
+local COMBATLOG = COMBATLOG
+local AURA_TYPE_BUFF = AURA_TYPE_BUFF
+local AURA_TYPE_DEBUFF = AURA_TYPE_DEBUFF
+local SPELL_POWER_MANA = SPELL_POWER_MANA
+local SPELL_POWER_RAGE = SPELL_POWER_RAGE
+local SPELL_POWER_FOCUS = SPELL_POWER_FOCUS
+local SPELL_POWER_ENERGY = SPELL_POWER_ENERGY
+local SPELL_POWER_HAPPINESS = SPELL_POWER_HAPPINESS
+local SPELL_POWER_RUNES = SPELL_POWER_RUNES
+local SPELL_POWER_RUNIC_POWER = SPELL_POWER_RUNIC_POWER
+local SCHOOL_MASK_NONE = SCHOOL_MASK_NONE
+local SCHOOL_MASK_PHYSICAL = SCHOOL_MASK_PHYSICAL
+local SCHOOL_MASK_HOLY = SCHOOL_MASK_HOLY
+local SCHOOL_MASK_FIRE = SCHOOL_MASK_FIRE
+local SCHOOL_MASK_NATURE = SCHOOL_MASK_NATURE
+local SCHOOL_MASK_FROST = SCHOOL_MASK_FROST
+local SCHOOL_MASK_SHADOW = SCHOOL_MASK_SHADOW
+local SCHOOL_MASK_ARCANE = SCHOOL_MASK_ARCANE
+local COMBATLOG_LIMIT_PER_FRAME = COMBATLOG_LIMIT_PER_FRAME
+local COMBATLOG_HIGHLIGHT_MULTIPLIER = COMBATLOG_HIGHLIGHT_MULTIPLIER
+local COMBATLOG_DEFAULT_COLORS = COMBATLOG_DEFAULT_COLORS
+local COMBATLOG_DEFAULT_SETTINGS = COMBATLOG_DEFAULT_SETTINGS
+local COMBATLOG_ICON_RAIDTARGET1 = COMBATLOG_ICON_RAIDTARGET1
+local COMBATLOG_ICON_RAIDTARGET2 = COMBATLOG_ICON_RAIDTARGET2
+local COMBATLOG_ICON_RAIDTARGET3 = COMBATLOG_ICON_RAIDTARGET3
+local COMBATLOG_ICON_RAIDTARGET4 = COMBATLOG_ICON_RAIDTARGET4
+local COMBATLOG_ICON_RAIDTARGET5 = COMBATLOG_ICON_RAIDTARGET5
+local COMBATLOG_ICON_RAIDTARGET6 = COMBATLOG_ICON_RAIDTARGET6
+local COMBATLOG_ICON_RAIDTARGET7 = COMBATLOG_ICON_RAIDTARGET7
+local COMBATLOG_ICON_RAIDTARGET8 = COMBATLOG_ICON_RAIDTARGET8
+local COMBATLOG_EVENT_LIST = COMBATLOG_EVENT_LIST
+
+local CombatLog_OnEvent -- for later
+local CombatLog_Object_IsA = CombatLog_Object_IsA
+
+
+-- Create a dummy CombatLogQuickButtonFrame for line 803 of FloatingChatFrame.lua. It causes inappropriate show/hide behavior. Instead, we'll use our own frame display handling.
+-- If there are more than 2 combat log frames, then the CombatLogQuickButtonFrame gets tied to the last frame tab's visibility status. Yuck! Let's just instead tie it to the combat log's tab.
+
+local CombatLogQuickButtonFrame, CombatLogQuickButtonFrameProgressBar, CombatLogQuickButtonFrameTexture
+_G.CombatLogQuickButtonFrame = CreateFrame("Frame", "CombatLogQuickButtonFrame", UIParent)
+
+local Blizzard_CombatLog_Update_QuickButtons
+local Blizzard_CombatLog_Filters
+local Blizzard_CombatLog_CurrentSettings
+local Blizzard_CombatLog_PreviousSettings
+
+
+--
+-- Persistant Variables
+--
+--
+-- Default Filters
+--
+Blizzard_CombatLog_Filter_Defaults = {
+ -- All of the filters
+ filters = {
+ [1] = {
+ -- Descriptive Information
+ name = QUICKBUTTON_NAME_SELF;
+ hasQuickButton = true;
+ quickButtonName = QUICKBUTTON_NAME_SELF;
+ quickButtonDisplay = {
+ solo = true;
+ party = true;
+ raid = true;
+ };
+ tooltip = QUICKBUTTON_NAME_SELF_TOOLTIP;
+
+ -- Default Color and Formatting Options
+ settings = CopyTable(COMBATLOG_DEFAULT_SETTINGS);
+
+ -- Coloring
+ colors = CopyTable(COMBATLOG_DEFAULT_COLORS);
+
+ -- The actual client filters
+ filters = {
+ [1] = {
+ eventList = {
+ ["ENVIRONMENTAL_DAMAGE"] = true,
+ ["SWING_DAMAGE"] = true,
+ ["SWING_MISSED"] = true,
+ ["RANGE_DAMAGE"] = true,
+ ["RANGE_MISSED"] = true,
+ --["SPELL_CAST_START"] = true,
+ --["SPELL_CAST_SUCCESS"] = true,
+ --["SPELL_CAST_FAILED"] = true,
+ ["SPELL_MISSED"] = true,
+ ["SPELL_DAMAGE"] = true,
+ ["SPELL_HEAL"] = true,
+ ["SPELL_ENERGIZE"] = true,
+ ["SPELL_DRAIN"] = true,
+ ["SPELL_LEECH"] = true,
+ ["SPELL_INSTAKILL"] = true,
+ ["SPELL_INTERRUPT"] = true,
+ ["SPELL_EXTRA_ATTACKS"] = true,
+ --["SPELL_DURABILITY_DAMAGE"] = true,
+ --["SPELL_DURABILITY_DAMAGE_ALL"] = true,
+ ["SPELL_AURA_APPLIED"] = true,
+ ["SPELL_AURA_APPLIED_DOSE"] = true,
+ ["SPELL_AURA_REMOVED"] = true,
+ ["SPELL_AURA_REMOVED_DOSE"] = true,
+ ["SPELL_AURA_BROKEN"] = true,
+ ["SPELL_AURA_BROKEN_SPELL"] = true,
+ ["SPELL_AURA_REFRESH"] = true,
+ ["SPELL_DISPEL"] = true,
+ ["SPELL_STOLEN"] = true,
+ ["ENCHANT_APPLIED"] = true,
+ ["ENCHANT_REMOVED"] = true,
+ ["SPELL_PERIODIC_MISSED"] = true,
+ ["SPELL_PERIODIC_DAMAGE"] = true,
+ ["SPELL_PERIODIC_HEAL"] = true,
+ ["SPELL_PERIODIC_ENERGIZE"] = true,
+ ["SPELL_PERIODIC_DRAIN"] = true,
+ ["SPELL_PERIODIC_LEECH"] = true,
+ ["SPELL_DISPEL_FAILED"] = true,
+ --["DAMAGE_SHIELD"] = true,
+ --["DAMAGE_SHIELD_MISSED"] = true,
+ --["DAMAGE_SPLIT"] = true,
+ ["PARTY_KILL"] = true,
+ ["UNIT_DIED"] = true,
+ ["UNIT_DESTROYED"] = true,
+ ["UNIT_DISSIPATES"] = true
+ };
+ sourceFlags = {
+ [COMBATLOG_FILTER_MINE] = true,
+ [COMBATLOG_FILTER_MY_PET] = true;
+ };
+ destFlags = nil;
+ };
+ [2] = {
+ eventList = {
+ --["ENVIRONMENTAL_DAMAGE"] = true,
+ ["SWING_DAMAGE"] = true,
+ ["SWING_MISSED"] = true,
+ ["RANGE_DAMAGE"] = true,
+ ["RANGE_MISSED"] = true,
+ --["SPELL_CAST_START"] = true,
+ --["SPELL_CAST_SUCCESS"] = true,
+ --["SPELL_CAST_FAILED"] = true,
+ ["SPELL_MISSED"] = true,
+ ["SPELL_DAMAGE"] = true,
+ ["SPELL_HEAL"] = true,
+ ["SPELL_ENERGIZE"] = true,
+ ["SPELL_DRAIN"] = true,
+ ["SPELL_LEECH"] = true,
+ ["SPELL_INSTAKILL"] = true,
+ ["SPELL_INTERRUPT"] = true,
+ ["SPELL_EXTRA_ATTACKS"] = true,
+ --["SPELL_DURABILITY_DAMAGE"] = true,
+ --["SPELL_DURABILITY_DAMAGE_ALL"] = true,
+ --["SPELL_AURA_APPLIED"] = true,
+ --["SPELL_AURA_APPLIED_DOSE"] = true,
+ --["SPELL_AURA_REMOVED"] = true,
+ --["SPELL_AURA_REMOVED_DOSE"] = true,
+ ["SPELL_DISPEL"] = true,
+ ["SPELL_STOLEN"] = true,
+ ["ENCHANT_APPLIED"] = true,
+ ["ENCHANT_REMOVED"] = true,
+ --["SPELL_PERIODIC_MISSED"] = true,
+ --["SPELL_PERIODIC_DAMAGE"] = true,
+ --["SPELL_PERIODIC_HEAL"] = true,
+ --["SPELL_PERIODIC_ENERGIZE"] = true,
+ --["SPELL_PERIODIC_DRAIN"] = true,
+ --["SPELL_PERIODIC_LEECH"] = true,
+ ["SPELL_DISPEL_FAILED"] = true,
+ --["DAMAGE_SHIELD"] = true,
+ --["DAMAGE_SHIELD_MISSED"] = true,
+ --["DAMAGE_SPLIT"] = true,
+ ["PARTY_KILL"] = true,
+ ["UNIT_DIED"] = true,
+ ["UNIT_DESTROYED"] = true,
+ ["UNIT_DISSIPATES"] = true
+ };
+ sourceFlags = nil;
+ destFlags = {
+ [COMBATLOG_FILTER_MINE] = true,
+ [COMBATLOG_FILTER_MY_PET] = true;
+ };
+ };
+ };
+ };
+ [2] = {
+ -- Descriptive Information
+ name = QUICKBUTTON_NAME_EVERYTHING;
+ hasQuickButton = true;
+ quickButtonName = QUICKBUTTON_NAME_EVERYTHING;
+ quickButtonDisplay = {
+ solo = true;
+ party = true;
+ raid = true;
+ };
+ tooltip = QUICKBUTTON_NAME_EVERYTHING_TOOLTIP;
+
+ -- Settings
+ settings = CopyTable(COMBATLOG_DEFAULT_SETTINGS);
+
+ -- Coloring
+ colors = CopyTable(COMBATLOG_DEFAULT_COLORS);
+
+ -- The actual client filters
+ filters = {
+ [1] = {
+ eventList = Blizzard_CombatLog_GenerateFullEventList();
+ sourceFlags = Blizzard_CombatLog_GenerateFullFlagList(true);
+ destFlags = nil;
+ };
+ [2] = {
+ eventList = Blizzard_CombatLog_GenerateFullEventList();
+ sourceFlags = nil;
+ destFlags = Blizzard_CombatLog_GenerateFullFlagList(true);
+ };
+ };
+ };
+ [3] = {
+ -- Descriptive Information
+ name = QUICKBUTTON_NAME_ME;
+ hasQuickButton = true;
+ quickButtonName = QUICKBUTTON_NAME_ME;
+ quickButtonDisplay = {
+ solo = true;
+ party = true;
+ raid = true;
+ };
+ tooltip = QUICKBUTTON_NAME_ME_TOOLTIP;
+
+ -- Settings
+ settings = CopyTable(COMBATLOG_DEFAULT_SETTINGS);
+
+ -- Coloring
+ colors = CopyTable(COMBATLOG_DEFAULT_COLORS);
+
+ -- The actual client filters
+ filters = {
+ [1] = {
+ eventList = Blizzard_CombatLog_GenerateFullEventList();
+ sourceFlags = Blizzard_CombatLog_GenerateFullFlagList(false);
+ destFlags = nil;
+ };
+ [2] = {
+ eventList = Blizzard_CombatLog_GenerateFullEventList();
+ sourceFlags = nil;
+ destFlags = {
+ [COMBATLOG_FILTER_MINE] = true,
+ [COMBATLOG_FILTER_MY_PET] = true;
+ };
+ };
+ };
+ };
+ [4] = {
+ -- Descriptive Information
+ name = QUICKBUTTON_NAME_KILLS;
+ hasQuickButton = false;
+ quickButtonName = QUICKBUTTON_NAME_KILLS;
+ quickButtonDisplay = {
+ solo = true;
+ party = true;
+ raid = true;
+ };
+ tooltip = QUICKBUTTON_NAME_KILLS_TOOLTIP;
+
+ -- Settings
+ settings = CopyTable(COMBATLOG_DEFAULT_SETTINGS);
+
+ -- Coloring
+ colors = CopyTable(COMBATLOG_DEFAULT_COLORS);
+
+ -- The actual client filters
+ filters = {
+ [1] = {
+ eventList = {
+ ["PARTY_KILL"] = true,
+ ["UNIT_DIED"] = true,
+ ["UNIT_DESTROYED"] = true,
+ ["UNIT_DISSIPATES"] = true
+ };
+ sourceFlags = Blizzard_CombatLog_GenerateFullFlagList(true);
+ destFlags = nil;
+ };
+ [2] = {
+ eventList = {
+ ["PARTY_KILL"] = true,
+ ["UNIT_DIED"] = true,
+ ["UNIT_DESTROYED"] = true,
+ ["UNIT_DISSIPATES"] = true
+ };
+ sourceFlags = nil;
+ destFlags = Blizzard_CombatLog_GenerateFullFlagList(true);
+ };
+ };
+ };
+ };
+
+ -- Current Filter
+ currentFilter = 1;
+};
+
+local Blizzard_CombatLog_Filters = Blizzard_CombatLog_Filter_Defaults;
+_G.Blizzard_CombatLog_Filters = Blizzard_CombatLog_Filters
+
+-- Combat Log Filter Resetting Code
+--
+-- args:
+-- config - the configuration array we are about to apply
+--
+function Blizzard_CombatLog_ApplyFilters(config)
+ if ( not config ) then
+ return;
+ end
+ CombatLogResetFilter()
+
+ -- Loop over all associated filters
+ local eventList;
+ for k,v in pairs(config.filters) do
+ local eList
+ -- Only use the first filter's eventList
+ eventList = config.filters[1].eventList;
+ if ( eventList ) then
+ for k2,v2 in pairs(eventList) do
+ if ( v2 == true ) then
+ eList = eList and (eList .. "," .. k2) or k2
+ end
+ end
+ end
+
+ local sourceFlags, destFlags;
+ if ( v.sourceFlags ) then
+ sourceFlags = 0;
+ for k2, v2 in pairs(v.sourceFlags) do
+ -- Support for GUIDs
+ if ( type (k2) == "string" ) then
+ sourceFlags = k2;
+ break;
+ end
+ -- Otherwise OR bits
+ if ( v2 ) then
+ sourceFlags = bit_bor(sourceFlags, k2);
+ end
+ end
+ end
+ if ( v.destFlags ) then
+ destFlags = 0;
+ for k2, v2 in pairs(v.destFlags) do
+ -- Support for GUIDs
+ if ( type (k2) == "string" ) then
+ destFlags = k2;
+ break;
+ end
+ -- Otherwise OR bits
+ if ( v2 ) then
+ destFlags = bit_bor(destFlags, k2);
+ end
+ end
+ end
+ if ( type(sourceFlags) == "string" and destFlags == 0 ) then
+ destFlags = nil;
+ end
+ if ( type(destFlags) == "string" and sourceFlags == 0 ) then
+ sourceFlags = nil;
+ end
+
+ -- This is a HACK!!! Need filters to be able to accept empty or zero sourceFlags or destFlags
+ if ( sourceFlags == 0 or destFlags == 0 ) then
+ CombatLogAddFilter("", COMBATLOG_FILTER_MINE, nil);
+ else
+ CombatLogAddFilter(eList, sourceFlags, destFlags);
+ end
+ end
+end
+
+--
+-- Combat Log Repopulation Code
+--
+
+-- Message Limit
+
+COMBATLOG_MESSAGE_LIMIT = 300;
+
+--
+-- Repopulate the combat log with message history
+--
+function Blizzard_CombatLog_Refilter()
+ local count = CombatLogGetNumEntries();
+
+ COMBATLOG:SetMaxLines(COMBATLOG_MESSAGE_LIMIT);
+
+ -- count should be between 1 and COMBATLOG_MESSAGE_LIMIT
+ count = max(1, min(count, COMBATLOG_MESSAGE_LIMIT));
+
+ CombatLogSetCurrentEntry(0);
+
+ -- Clear the combat log
+ COMBATLOG:Clear();
+
+ -- Moved setting the max value here, since we don't really need to reset the max every frame, do we?
+ -- We can't add events while refiltering (:AddFilter short circuits) so this should be safe optimization.
+ CombatLogQuickButtonFrameProgressBar:SetMinMaxValues(0, count);
+ CombatLogQuickButtonFrameProgressBar:SetValue(0);
+ CombatLogQuickButtonFrameProgressBar:Show();
+
+ -- Enable the distributed frame
+ CombatLogUpdateFrame.refiltering = true;
+ CombatLogUpdateFrame:SetScript("OnUpdate", Blizzard_CombatLog_RefilterUpdate)
+
+ Blizzard_CombatLog_RefilterUpdate()
+end
+
+--
+-- This is a single frame "step" in the refiltering process
+--
+function Blizzard_CombatLog_RefilterUpdate()
+ local valid = CombatLogGetCurrentEntry(); -- CombatLogAdvanceEntry(0);
+
+ -- Clear the combat log
+ local total = 0;
+ while (valid and total < COMBATLOG_LIMIT_PER_FRAME) do
+ -- Log to the window
+ local text, r, g, b, a = CombatLog_OnEvent(Blizzard_CombatLog_CurrentSettings, CombatLogGetCurrentEntry());
+ -- NOTE: be sure to pass in nil for the color id or the color id may override the r, g, b values for this message
+ COMBATLOG:AddMessage( text, r, g, b, nil, true );
+
+ -- count can be
+ -- positive to advance from oldest to newest
+ -- negative to advance from newest to oldest
+ valid = CombatLogAdvanceEntry(-1)
+ total = total + 1;
+ end
+
+ -- Show filtering progress bar
+ CombatLogQuickButtonFrameProgressBar:SetValue(CombatLogQuickButtonFrameProgressBar:GetValue() + total);
+
+ if ( not valid or (CombatLogQuickButtonFrameProgressBar:GetValue() >= COMBATLOG_MESSAGE_LIMIT) ) then
+ CombatLogUpdateFrame.refiltering = false
+ CombatLogUpdateFrame:SetScript("OnUpdate", nil)
+ CombatLogQuickButtonFrameProgressBar:Hide();
+ end
+end
+
+--
+-- Checks for an event over all filters
+--
+function Blizzard_CombatLog_HasEvent ( settings, ... )
+ -- If this actually happens, we have data corruption issues.
+ if ( not settings.filters ) then
+ settings.filters = {}
+ end
+ for _, filter in pairs (settings.filters) do
+ if ( filter.eventList ) then
+ for i = 1, select("#", ...) do
+ local event = select(i, ...)
+ if ( filter.eventList[event] == true ) then
+ return true
+ end
+ end
+ end
+ end
+end
+
+--
+-- Checks for an event over all filters
+--
+function Blizzard_CombatLog_EnableEvent ( settings, ... )
+ -- If this actually happens, we have data corruption issues.
+ if ( not settings.filters ) then
+ settings.filters = Blizzard_CombatLog_InitializeFilters( settings );
+ end
+ for _, filter in pairs (settings.filters) do
+ if ( not filter.eventList ) then
+ filter.eventList = {};
+ end
+
+ for i = 1, select("#", ...) do
+ filter.eventList[select(i, ...)] = true;
+ end
+ end
+end
+
+--
+-- Checks for an event over all filters
+--
+function Blizzard_CombatLog_DisableEvent ( settings, ... )
+ -- If this actually happens, we have data corruption issues.
+ if ( not settings.filters ) then
+ settings.filters = {}
+ end
+ for _, filter in pairs (settings.filters) do
+ if ( filter.eventList ) then
+ for i = 1, select("#", ...) do
+ filter.eventList[select(i, ...)] = false;
+ end
+ end
+ end
+end
+
+--
+-- Creates the action menu popup
+--
+do
+ local eventType
+ local actionMenu = {
+ [1] = {
+ text = "string.format(BLIZZARD_COMBAT_LOG_MENU_SPELL_HIDE, eventType)",
+ func = function () Blizzard_CombatLog_SpellMenuClick ("HIDE", nil, nil, eventType); end;
+ },
+ };
+ function Blizzard_CombatLog_CreateActionMenu(eventType_arg)
+ -- Update upvalues
+ eventType = eventType_arg
+ actionMenu[1].text = string.format(BLIZZARD_COMBAT_LOG_MENU_SPELL_HIDE, eventType_arg);
+ return actionMenu
+ end
+end
+
+--
+-- Creates the spell menu popup
+--
+do
+ local spellName, spellId, eventType
+ local spellMenu = {
+ [1] = {
+ text = "string.format(BLIZZARD_COMBAT_LOG_MENU_SPELL_LINK, spellName)",
+ func = function () Blizzard_CombatLog_SpellMenuClick ("LINK", spellName, spellId, eventType); end;
+ },
+ };
+ local spellMenu2 = {
+ [2] = {
+ text = "string.format(BLIZZARD_COMBAT_LOG_MENU_SPELL_HIDE, eventType)",
+ func = function () Blizzard_CombatLog_SpellMenuClick ("HIDE", spellName, spellId, eventType); end;
+ },
+ [3] = {
+ text = "------------------";
+ disabled = true;
+ },
+ };
+ function Blizzard_CombatLog_CreateSpellMenu(spellName_arg, spellId_arg, eventType_arg)
+ -- Update upvalues
+ spellName, spellId, eventType = spellName_arg, spellId_arg, eventType_arg;
+ -- Update menu text and filters
+ spellMenu[1].text = string.format(BLIZZARD_COMBAT_LOG_MENU_SPELL_LINK, spellName);
+ if ( eventType ) then
+ spellMenu2[2].text = string.format(BLIZZARD_COMBAT_LOG_MENU_SPELL_HIDE, eventType);
+ -- Copy the table references over
+ spellMenu[2] = spellMenu2[2];
+ if ( DEBUG ) then
+ spellMenu[3] = spellMenu2[3];
+ -- These 2 calls update the menus in their respective do-end blocks
+ spellMenu[4] = Blizzard_CombatLog_FormattingMenu(Blizzard_CombatLog_Filters.currentFilter);
+ spellMenu[5] = Blizzard_CombatLog_MessageTypesMenu(Blizzard_CombatLog_Filters.currentFilter);
+ end
+ else
+ -- Remove the table references, they are still stored in their various closures
+ spellMenu[2] = nil;
+ spellMenu[3] = nil;
+ spellMenu[4] = nil;
+ spellMenu[5] = nil;
+ end
+ return spellMenu;
+ end
+end
+
+--
+-- Temporary Menu
+--
+do
+ -- This big table currently only has one upvalue: Blizzard_CombatLog_CurrentSettings
+ local messageTypesMenu = {
+ text = "Message Types";
+ hasArrow = true;
+ menuList = {
+ [1] = {
+ text = "Melee";
+ hasArrow = true;
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SWING_DAMAGE", "SWING_MISSED"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SWING_DAMAGE", "SWING_MISSED" );
+ end;
+ menuList = {
+ [1] = {
+ text = "Damage";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SWING_DAMAGE");end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SWING_DAMAGE" );
+ end;
+ };
+ [2] = {
+ text = "Failure";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SWING_MISSED"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SWING_MISSED" );
+ end;
+ };
+ };
+ };
+ [2] = {
+ text = "Ranged";
+ hasArrow = true;
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "RANGE_DAMAGE", "RANGE_MISSED"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "RANGED_DAMAGE", "RANGED_MISSED" );
+ end;
+ menuList = {
+ [1] = {
+ text = "Damage";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "RANGE_DAMAGE"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "RANGE_DAMAGE" );
+ end;
+ };
+ [2] = {
+ text = "Failure";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "RANGE_MISSED"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "RANGE_MISSED" );
+ end;
+ };
+ };
+ };
+ [3] = {
+ text = "Spells";
+ hasArrow = true;
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_DAMAGE", "SPELL_MISSED", "SPELL_HEAL", "SPELL_ENERGIZE", "SPELL_DRAIN", "SPELL_LEECH", "SPELL_INTERRUPT", "SPELL_EXTRA_ATTACKS", "SPELL_CAST_START", "SPELL_CAST_SUCCESS", "SPELL_CAST_FAILED", "SPELL_INSTAKILL", "SPELL_DURABILITY_DAMAGE" ); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_DAMAGE", "SPELL_MISSED", "SPELL_HEAL", "SPELL_ENERGIZE", "SPELL_DRAIN", "SPELL_LEECH", "SPELL_INTERRUPT", "SPELL_EXTRA_ATTACKS", "SPELL_CAST_START", "SPELL_CAST_SUCCESS", "SPELL_CAST_FAILED", "SPELL_INSTAKILL", "SPELL_DURABILITY_DAMAGE" );
+ end;
+ menuList = {
+ [1] = {
+ text = "Damage";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_DAMAGE"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_DAMAGE" );
+ end;
+ };
+ [2] = {
+ text = "Failure";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_MISSED"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_MISSED" );
+ end;
+ };
+ [3] = {
+ text = "Heals";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_HEAL"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_HEAL" );
+ end;
+ };
+ [4] = {
+ text = "Power Gains";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_ENERGIZE"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_ENERGIZE" );
+ end;
+ };
+ [4] = {
+ text = "Drains";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_DRAIN", "SPELL_LEECH"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_DRAIN", "SPELL_LEECH" );
+ end;
+ };
+ [5] = {
+ text = "Interrupts";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_INTERRUPT"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_INTERRUPT" );
+ end;
+ };
+ [6] = {
+ text = "Extra Attacks";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_EXTRA_ATTACKS"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_EXTRA_ATTACKS" );
+ end;
+ };
+ [7] = {
+ text = "Casting";
+ hasArrow = true;
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_CAST_START", "SPELL_CAST_SUCCESS", "SPELL_CAST_FAILED"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_CAST_START", "SPELL_CAST_SUCCESS", "SPELL_CAST_FAILED");
+ end;
+ menuList = {
+ [1] = {
+ text = "Start";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_CAST_START"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_CAST_START" );
+ end;
+ };
+ [2] = {
+ text = "Success";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_CAST_SUCCESS"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_CAST_SUCCESS" );
+ end;
+ };
+ [3] = {
+ text = "Failed";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_CAST_FAILED"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_CAST_FAILED" );
+ end;
+ };
+ };
+ };
+ [8] = {
+ text = "Special";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_INSTAKILL", "SPELL_DURABILITY_DAMAGE"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_INSTAKILL", "SPELL_DURABILITY_DAMAGE" );
+ end;
+ };
+ };
+ };
+ [4] = {
+ text = "Auras";
+ hasArrow = true;
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_AURA_APPLIED", "SPELL_AURA_BROKEN", "SPELL_AURA_REFRESH", "SPELL_AURA_BROKEN_SPELL", "SPELL_AURA_APPLIED_DOSE", "SPELL_AURA_REMOVED", "SPELL_AURA_REMOVED_DOSE", "SPELL_DISPEL", "SPELL_STOLEN", "ENCHANT_APPLIED", "ENCHANT_REMOVED" ); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_AURA_APPLIED", "SPELL_AURA_BROKEN", "SPELL_AURA_REFRESH", "SPELL_AURA_BROKEN_SPELL", "SPELL_AURA_APPLIED_DOSE", "SPELL_AURA_REMOVED", "SPELL_AURA_REMOVED_DOSE", "SPELL_DISPEL", "SPELL_STOLEN", "ENCHANT_APPLIED", "ENCHANT_REMOVED" );
+ end;
+ menuList = {
+ [1] = {
+ text = "Applied";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_AURA_APPLIED", "SPELL_AURA_BROKEN", "SPELL_AURA_REFRESH", "SPELL_AURA_BROKEN_SPELL", "SPELL_AURA_APPLIED_DOSE"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_AURA_APPLIED", "SPELL_AURA_BROKEN", "SPELL_AURA_REFRESH", "SPELL_AURA_BROKEN_SPELL", "SPELL_AURA_APPLIED_DOSE", "ENCHANT_APPLIED" );
+ end;
+ };
+ [2] = {
+ text = "Removed";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_AURA_REMOVED", "SPELL_AURA_REMOVED_DOSE", "ENCHANT_REMOVED" ); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_AURA_REMOVED", "SPELL_AURA_REMOVED_DOSE" );
+ end;
+ };
+ [3] = {
+ text = "Dispelled";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_DISPEL"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_DISPEL" );
+ end;
+ };
+ [4] = {
+ text = "Stolen";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_STOLEN"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_STOLEN" );
+ end;
+ };
+ };
+ };
+ [5] = {
+ text = "Periodics";
+ hasArrow = true;
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_PERIODIC_DAMAGE", "SPELL_PERIODIC_MISSED", "SPELL_PERIODIC_DRAIN", "SPELL_PERIODIC_ENERGIZE", "SPELL_PERIODIC_HEAL", "SPELL_PERIODIC_LEECH" ); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_PERIODIC_DAMAGE", "SPELL_PERIODIC_MISSED", "SPELL_PERIODIC_DRAIN", "SPELL_PERIODIC_ENERGIZE", "SPELL_PERIODIC_HEAL", "SPELL_PERIODIC_LEECH" );
+ end;
+ menuList = {
+ [1] = {
+ text = "Damage";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_PERIODIC_DAMAGE"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_PERIODIC_DAMAGE" );
+ end;
+ };
+ [2] = {
+ text = "Failure";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_PERIODIC_MISSED" ); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_PERIODIC_MISSED" );
+ end;
+ };
+ [3] = {
+ text = "Heals";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_PERIODIC_HEAL"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_PERIODIC_HEAL" );
+ end;
+ };
+ [4] = {
+ text = "Other";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "SPELL_PERIODIC_DRAIN", "SPELL_PERIODIC_ENERGIZE", "SPELL_PERIODIC_LEECH"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "SPELL_PERIODIC_DRAIN", "SPELL_PERIODIC_ENERGIZE", "SPELL_PERIODIC_LEECH" );
+ end;
+ };
+ };
+ };
+ [6] = {
+ text = "Other";
+ hasArrow = true;
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "PARTY_KILL", "UNIT_DIED", "UNIT_DESTROYED", "UNIT_DISSIPATES", "DAMAGE_SPLIT", "ENVIRONMENTAL_DAMAGE" ); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "PARTY_KILL", "UNIT_DIED", "UNIT_DESTROYED", "UNIT_DISSIPATES", "DAMAGE_SPLIT", "ENVIRONMENTAL_DAMAGE" );
+ end;
+ menuList = {
+ [1] = {
+ text = "Kills";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "PARTY_KILL"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "PARTY_KILL" );
+ end;
+ };
+ [2] = {
+ text = "Deaths";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "UNIT_DIED", "UNIT_DESTROYED", "UNIT_DISSIPATES"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "UNIT_DIED", "UNIT_DESTROYED", "UNIT_DISSIPATES" );
+ end;
+ };
+ [3] = {
+ text = "Damage Split";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "DAMAGE_SPLIT"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "DAMAGE_SPLIT" );
+ end;
+ };
+ [4] = {
+ text = "Environmental Damage";
+ checked = function() return Blizzard_CombatLog_HasEvent (Blizzard_CombatLog_CurrentSettings, "ENVIRONMENTAL_DAMAGE"); end;
+ keepShownOnClick = true;
+ func = function ( self, arg1, arg2, checked )
+ Blizzard_CombatLog_MenuHelper ( checked, "ENVIRONMENTAL_DAMAGE" );
+ end;
+ };
+ };
+ };
+ };
+ };
+ -- functions I see do pass in arguments, update upvalues as necessary.
+ function Blizzard_CombatLog_MessageTypesMenu()
+ return messageTypesMenu;
+ end
+end
+
+--
+-- Temporary Menu
+--
+do
+ local filterId
+ local filter
+ local currentFilter
+ local formattingMenu = {
+ text = "Formatting";
+ hasArrow = true;
+ menuList = {
+ {
+ text = "Full Text";
+ checked = function() return filter.fullText; end;
+ func = function(self, arg1, arg2, checked)
+ filter.fullText = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Timestamp";
+ checked = function() return filter.timestamp; end;
+ func = function(self, arg1, arg2, checked)
+ filter.timestamp = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Unit Name Coloring";
+ checked = function() return filter.unitColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.unitColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Line Coloring";
+ checked = function() return filter.lineColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.lineColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Line Highlighting";
+ checked = function() return filter.lineHighlighting; end;
+ func = function(self, arg1, arg2, checked)
+ filter.lineHighlighting = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Ability Coloring";
+ checked = function() return filter.abilityColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.abilityColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Ability-by-School Coloring";
+ checked = function() return filter.abilitySchoolColoring; end;
+ --disabled = not filter.abilityColoring;
+ func = function(self, arg1, arg2, checked)
+ filter.abilitySchoolColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Ability-by-Actor Coloring";
+ checked = function() return filter.abilityActorColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.abilityActorColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Ability Highlighting";
+ checked = function() return filter.abilityHighlighting; end;
+ func = function(self, arg1, arg2, checked)
+ filter.abilityHighlighting = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Action Coloring";
+ checked = function() return filter.actionColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.actionColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Action-by-School Coloring";
+ checked = function() return filter.actionSchoolColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.actionSchoolColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Action-by-Actor Coloring";
+ checked = function() return filter.actionActorColoring; end;
+ --disabled = not filter.abilityColoring;
+ func = function(self, arg1, arg2, checked)
+ filter.actionActorColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Action Highlighting";
+ checked = function() return filter.actionHighlighting; end;
+ --disabled = not filter.abilityColoring;
+ func = function(self, arg1, arg2, checked)
+ filter.actionHighlighting = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Damage Coloring";
+ checked = function() return filter.amountColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.amountColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Damage-by-School Coloring";
+ checked = function() return filter.amountSchoolColoring; end;
+ --disabled = not filter.amountColoring;
+ func = function(self, arg1, arg2, checked)
+ filter.amountSchoolColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Damage-by-Actor Coloring";
+ checked = function() return filter.amountActorColoring; end;
+ --disabled = not filter.amountColoring;
+ func = function(self, arg1, arg2, checked)
+ filter.amountActorColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Damage Highlighting";
+ checked = function() return filter.amountHighlighting; end;
+ func = function(self, arg1, arg2, checked)
+ filter.amountHighlighting = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Color School Names";
+ checked = function() return filter.schoolNameColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.schoolNameColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "School Name Highlighting";
+ checked = function() return filter.schoolNameHighlighting; end;
+ func = function(self, arg1, arg2, checked)
+ filter.schoolNameHighlighting = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "White Swing Rule";
+ checked = function() return filter.noMeleeSwingColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.noMeleeSwingColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Misses Colored Rule";
+ checked = function() return filter.missColoring; end;
+ func = function(self, arg1, arg2, checked)
+ filter.missColoring = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Braces";
+ checked = function() return filter.braces; end;
+ func = function(self, arg1, arg2, checked)
+ filter.braces = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ },
+ {
+ text = "Refiltering";
+ checked = function() return filter.showHistory; end;
+ func = function(self, arg1, arg2, checked)
+ filter.showHistory = checked;
+ Blizzard_CombatLog_QuickButton_OnClick(currentFilter)
+ end;
+ keepShownOnClick = true;
+ tooltipTitle = "Refiltering";
+ tooltipText = "This clears the chat frame and refills it with the last 500 events.";
+ },
+ };
+ };
+ function Blizzard_CombatLog_FormattingMenu(filterId_arg)
+ -- Update upvalues
+ filterId = filterId_arg;
+ filter = Blizzard_CombatLog_Filters.filters[filterId].settings;
+ currentFilter = Blizzard_CombatLog_Filters.currentFilter;
+ return formattingMenu;
+ end
+end
+
+--
+-- Menu Option Helper Function
+--
+function Blizzard_CombatLog_MenuHelper ( checked, ... )
+ if ( not checked ) then
+ Blizzard_CombatLog_DisableEvent (Blizzard_CombatLog_CurrentSettings, ...);
+ else
+ Blizzard_CombatLog_EnableEvent (Blizzard_CombatLog_CurrentSettings, ...);
+ end
+ Blizzard_CombatLog_ApplyFilters(Blizzard_CombatLog_CurrentSettings);
+ if ( Blizzard_CombatLog_CurrentSettings.settings.showHistory ) then
+ Blizzard_CombatLog_Refilter();
+ end
+end;
+
+--
+-- Blizzard_CombatLog_CreateTabMenu
+--
+-- Creates a context sensitive menu based on the current quick button
+--
+-- args:
+-- settingsIndex - the filter settings to use
+--
+do
+ local filterId
+ local unitName, unitGUID, special
+ local tabMenu = {
+ [1] = {
+ text = BLIZZARD_COMBAT_LOG_MENU_EVERYTHING;
+ func = function () Blizzard_CombatLog_UnitMenuClick ("EVERYTHING", unitName, unitGUID, special); end;
+ },
+ [2] = {
+ text = BLIZZARD_COMBAT_LOG_MENU_SAVE;
+ func = function () Blizzard_CombatLog_UnitMenuClick ("SAVE", unitName, unitGUID, special); end;
+ },
+ [3] = {
+ text = BLIZZARD_COMBAT_LOG_MENU_RESET;
+ func = function () Blizzard_CombatLog_UnitMenuClick ("RESET", unitName, unitGUID, special); end;
+ },
+ [4] = {
+ text = "--------- Temporary Adjustments ---------";
+ disabled = true;
+ },
+ };
+ function Blizzard_CombatLog_CreateTabMenu ( filterId_arg )
+ -- Update upvalues
+ filterId = filterId_arg
+
+ -- Update menus
+ tabMenu[2].disabled = (Blizzard_CombatLog_PreviousSettings == Blizzard_CombatLog_CurrentSettings)
+ tabMenu[5] = Blizzard_CombatLog_FormattingMenu(filterId);
+ tabMenu[6] = Blizzard_CombatLog_MessageTypesMenu(filterId);
+ return tabMenu;
+ end
+end
+
+
+--
+-- Temporary Menu
+--
+do
+ function Blizzard_CombatLog_CreateUnitMenu(unitName, unitGUID, special)
+ local displayName = unitName;
+ if ( (unitGUID == UnitGUID("player")) and (_G["COMBAT_LOG_UNIT_YOU_ENABLED"] == "1") ) then
+ displayName = UNIT_YOU;
+ end
+ local unitMenu = {
+ [1] = {
+ text = string.format(BLIZZARD_COMBAT_LOG_MENU_BOTH, displayName); -- Dummy text
+ func = function () Blizzard_CombatLog_UnitMenuClick ("BOTH", unitName, unitGUID, special); end;
+ },
+ [2] = {
+ text = string.format(BLIZZARD_COMBAT_LOG_MENU_INCOMING, displayName);
+ func = function () Blizzard_CombatLog_UnitMenuClick ("INCOMING", unitName, unitGUID, special); end;
+ },
+ [3] = {
+ text = string.format(BLIZZARD_COMBAT_LOG_MENU_OUTGOING, displayName);
+ func = function () Blizzard_CombatLog_UnitMenuClick ("OUTGOING", unitName, unitGUID, special); end;
+ },
+ [4] = {
+ text = "------------------";
+ disabled = true;
+ },
+ [5] = {
+ text = BLIZZARD_COMBAT_LOG_MENU_EVERYTHING;
+ func = function () Blizzard_CombatLog_UnitMenuClick ("EVERYTHING", unitName, unitGUID, special); end;
+ },
+ [6] = {
+ text = BLIZZARD_COMBAT_LOG_MENU_SAVE;
+ func = function () Blizzard_CombatLog_UnitMenuClick ("SAVE", unitName, unitGUID, special); end;
+ disabled = not CanCreateFilters();
+ },
+ [7] = {
+ text = BLIZZARD_COMBAT_LOG_MENU_RESET;
+ func = function () Blizzard_CombatLog_UnitMenuClick ("RESET", unitName, unitGUID, special); end;
+ },
+ };
+ --[[
+ -- These 2 calls update the menus in their respective do-end blocks
+ unitMenu[9] = Blizzard_CombatLog_FormattingMenu(Blizzard_CombatLog_Filters.currentFilter);
+ unitMenu[10] = Blizzard_CombatLog_MessageTypesMenu(Blizzard_CombatLog_Filters.currentFilter);
+ ]]
+
+ if ( unitGUID ~= UnitGUID("player") ) then
+ table.insert(unitMenu, 4, {
+ text = string.format(BLIZZARD_COMBAT_LOG_MENU_OUTGOING_ME, displayName);
+ func = function () Blizzard_CombatLog_UnitMenuClick ("OUTGOING_ME", unitName, unitGUID, special); end;
+ } );
+ end
+ return unitMenu
+ end
+end
+-- Create additional filter dropdown list
+do
+ local menu = {};
+ function Blizzard_CombatLog_CreateFilterMenu()
+ local count = 1;
+ for index, value in pairs(menu) do
+ if ( not value ) then
+ value = {};
+ else
+ for k, v in pairs(value) do
+ value[k] = nil;
+ end
+ end
+ end
+ local selectedIndex = Blizzard_CombatLog_Filters.currentFilter;
+ local checked;
+ for index, value in ipairs(Blizzard_CombatLog_Filters.filters) do
+ if ( not value.onQuickBar ) then
+ if ( not menu[count] ) then
+ menu[count] = {};
+ end
+ menu[count].text = value.name;
+ menu[count].func = function () Blizzard_CombatLog_QuickButton_OnClick(index); end;
+ if ( selectedIndex == index ) then
+ checked = 1;
+ else
+ checked = nil;
+ end
+ menu[count].checked = checked;
+ count = count+1;
+ end
+ end
+ return menu;
+ end
+end
+--
+-- Handle mini menu clicks
+--
+-- args:
+-- event - "EVERYTHING" | "RESET" | "INCOMING" | "OUTGOING" | "BOTH"
+-- unitName - string for the units name
+-- unitGUID - unique global unit ID for the specific unit
+-- special - bit code for special filters, such as raid targets
+--
+function Blizzard_CombatLog_UnitMenuClick(event, unitName, unitGUID, unitFlags)
+
+-- ChatFrame1:AddMessage("Event: "..event.." N: "..tostring(unitName).." GUID: "..tostring(unitGUID).." Flags: "..tostring(unitFlags));
+--
+-- This code was for the context menus to support different formatting criteria
+--
+-- -- Apply the correct settings.
+-- if ( Blizzard_CombatLog_Filters.contextMenu[event] ) then
+-- Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.contextMenu[event]
+-- end
+
+ -- I'm not sure if we really want this feature for live
+ if ( event == "REVERT" ) then
+ local temp = Blizzard_CombatLog_CurrentSettings;
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_PreviousSettings;
+ Blizzard_CombatLog_PreviousSettings = temp;
+ temp = nil;
+
+ -- Apply the old filters
+ Blizzard_CombatLog_ApplyFilters(Blizzard_CombatLog_CurrentSettings);
+
+ elseif ( event == "SAVE" ) then
+ local dialog = StaticPopup_Show("COPY_COMBAT_FILTER");
+ dialog.data = Blizzard_CombatLog_CurrentSettings;
+
+ return;
+ elseif ( event == "RESET" ) then
+ Blizzard_CombatLog_PreviousSettings = Blizzard_CombatLog_CurrentSettings;
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[Blizzard_CombatLog_Filters.currentFilter];
+ Blizzard_CombatLog_ApplyFilters(Blizzard_CombatLog_CurrentSettings);
+ else
+ -- Copy the current settings
+ Blizzard_CombatLog_PreviousSettings = Blizzard_CombatLog_CurrentSettings;
+ Blizzard_CombatLog_CurrentSettings = {};
+
+ for k,v in pairs( Blizzard_CombatLog_PreviousSettings ) do
+ Blizzard_CombatLog_CurrentSettings[k] = v;
+ end
+
+
+ -- Erase the filter criteria
+ Blizzard_CombatLog_CurrentSettings.filters = {}; -- We want to be careful not to destroy the active data, so the user can reset
+
+ if ( event == "EVERYTHING" ) then
+ -- Reset all filtering.
+ CombatLogResetFilter()
+ --Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.contextMenu[event];
+ CombatLogAddFilter(nil, nil, nil)
+ tinsert ( Blizzard_CombatLog_CurrentSettings.filters, {} );
+ end
+ if ( event == "INCOMING" or event == "BOTH" ) then
+ if ( unitFlags ) then
+ tinsert ( Blizzard_CombatLog_CurrentSettings.filters, { destFlags = { [unitFlags] = true; } } );
+ else
+ tinsert ( Blizzard_CombatLog_CurrentSettings.filters, { destFlags = { [unitGUID] = true; } } );
+ end
+ end
+ if ( event == "OUTGOING" or event == "BOTH" ) then
+ if ( unitFlags ) then
+ tinsert ( Blizzard_CombatLog_CurrentSettings.filters, { sourceFlags = { [unitFlags] = true; } } );
+ else
+ tinsert ( Blizzard_CombatLog_CurrentSettings.filters, { sourceFlags = { [unitGUID] = true; } } );
+ end
+ end
+ if ( event == "OUTGOING_ME" ) then
+ if ( unitFlags ) then
+ tinsert ( Blizzard_CombatLog_CurrentSettings.filters, { sourceFlags = { [unitFlags] = true; }; destFlags = { [COMBATLOG_FILTER_MINE] = true; } } );
+ else
+ tinsert ( Blizzard_CombatLog_CurrentSettings.filters, { sourceFlags = { [unitGUID] = true; }; destFlags = { [COMBATLOG_FILTER_MINE] = true; } } );
+ end
+ end
+
+ -- If the context menu is not resetting, then we need to create an event list,
+ -- So that right click removal works when the user right clicks
+ --
+
+ -- Fill the event list
+ local fullEventList = Blizzard_CombatLog_GenerateFullEventList();
+
+ -- Insert to the active data
+ for k,v in pairs (Blizzard_CombatLog_CurrentSettings.filters) do
+ v.eventList = fullEventList;
+ end
+
+ -- Apply the generated filters
+ Blizzard_CombatLog_ApplyFilters(Blizzard_CombatLog_CurrentSettings);
+ -- Let the system know that this filter is temporary and unhighlight any quick buttons
+ Blizzard_CombatLog_CurrentSettings.isTemp = true;
+ Blizzard_CombatLog_Update_QuickButtons()
+ end
+
+ -- Reset the combat log text box! (Grats!)
+ Blizzard_CombatLog_Refilter();
+end
+
+--
+-- Shows a simplified version of the menu if you right click on the quick button
+--
+-- This function isn't used anywhere yet. The QuickButtons doesn't have a event handler for right click yet.
+function Blizzard_CombatLog_QuickButtonRightClick(event, filterId)
+
+ -- I'm not sure if we really want this feature for live
+ if ( event == "REVERT" ) then
+ local temp = Blizzard_CombatLog_CurrentSettings;
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_PreviousSettings;
+ Blizzard_CombatLog_PreviousSettings = temp;
+ temp = nil;
+
+ -- Apply the old filters
+ Blizzard_CombatLog_ApplyFilters(Blizzard_CombatLog_CurrentSettings);
+
+ elseif ( event == "RESET" ) then
+ Blizzard_CombatLog_PreviousSettings = Blizzard_CombatLog_CurrentSettings;
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[filterId];
+ --CombatLogAddFilter(nil, nil, COMBATLOG_FILTER_MINE)
+ --CombatLogAddFilter(nil, COMBATLOG_FILTER_MINE, nil)
+ else
+ -- Copy the current settings
+ Blizzard_CombatLog_PreviousSettings = Blizzard_CombatLog_CurrentSettings;
+
+ Blizzard_CombatLog_CurrentSettings = {};
+
+ for k,v in pairs( Blizzard_CombatLog_Filters.filters[filterId] ) do
+ Blizzard_CombatLog_CurrentSettings[k] = v;
+ end
+
+ -- Erase the filter criteria
+ Blizzard_CombatLog_CurrentSettings.filters = {}; -- We want to be careful not to destroy the active data, so the user can reset
+
+ if ( event == "EVERYTHING" ) then
+ CombatLogAddFilter(nil, nil, nil)
+ table.insert ( Blizzard_CombatLog_CurrentSettings.filters, {} );
+ end
+
+ -- If the context menu is not resetting, then we need to create an event list,
+ -- So that right click removal works when the user right clicks
+ --
+
+ -- Fill the event list
+ local fullEventList = Blizzard_CombatLog_GenerateFullEventList();
+
+ -- Insert to the active data
+ for k,v in pairs (Blizzard_CombatLog_CurrentSettings.filters) do
+ v.eventList = fullEventList;
+ end
+
+ -- Apply the generated filters
+ Blizzard_CombatLog_ApplyFilters(Blizzard_CombatLog_CurrentSettings);
+ end
+
+ -- Reset the combat log text box! (Grats!)
+ Blizzard_CombatLog_Refilter();
+
+end
+
+--
+-- Handle spell mini menu clicks
+-- args:
+-- action - "HIDE" | "LINK"
+-- spellName - Spell or ability's name
+-- spellId - Spell or ability's id (100, 520, 30000, etc)
+-- event - the event type that generated this message
+--
+function Blizzard_CombatLog_SpellMenuClick(action, spellName, spellId, eventType)
+ if ( action == "HIDE" ) then
+ for k,v in pairs (Blizzard_CombatLog_CurrentSettings.filters) do
+ if ( type (v.eventList) ~= "table" ) then
+ v.eventList = Blizzard_CombatLog_GenerateFullEventList();
+ end
+ v.eventList[eventType] = false;
+ end
+ elseif ( action == "LINK" ) then
+ if ( ChatEdit_GetActiveWindow() ) then
+ ChatEdit_InsertLink(GetSpellLink(spellId));
+ else
+ ChatFrame_OpenChat(GetSpellLink(spellId));
+ end
+ return;
+ end
+
+ -- Apply the newly reconstituted filters
+ Blizzard_CombatLog_ApplyFilters(Blizzard_CombatLog_CurrentSettings);
+
+ -- Reset the combat log text box! (Grats!)
+ Blizzard_CombatLog_Refilter();
+end
+
+--
+-- Temporary Settings
+--
+Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[1];
+Blizzard_CombatLog_PreviousSettings = Blizzard_CombatLog_CurrentSettings;
+local Blizzard_CombatLog_UnitTokens = {};
+
+--[[
+-- Converts 4 floats into FF code
+--
+--]]
+local function CombatLog_Color_FloatToText(r,g,b,a)
+ if ( type(r) == "table" ) then
+ r, g, b, a = r.r, r.g, r.b, r.a;
+ end
+ a = min(1, a or 1) * 255
+ r = min(1, r) * 255
+ g = min(1, g) * 255
+ b = min(1, b) * 255
+
+ -- local fmt = "%.2x";
+ return ("%.2x%.2x%.2x%.2x"):format(math_floor(a), math_floor(r), math_floor(g), math_floor(b))
+end
+_G.CombatLog_Color_FloatToText = CombatLog_Color_FloatToText
+
+
+--
+-- Gets the appropriate color for an event type
+--
+
+-- If this needs to return a new table per event (ie, the table gets modified), then just replace the "defaultColorArray" in the function with
+-- a new table creation.
+local defaultColorArray = {a=1.0,r=0.5,g=0.5,b=0.5}
+local function CombatLog_Color_ColorArrayByEventType( event )
+ return Blizzard_CombatLog_CurrentSettings.colors.eventColoring[event] or defaultColorArray
+end
+_G.CombatLog_Color_ColorArrayByEventType = CombatLog_Color_ColorArrayByEventType
+
+--
+-- Gets the appropriate color for a unit type
+--
+
+local function CombatLog_Color_ColorArrayByUnitType(unitFlags, settings)
+ local array = nil;
+ if ( not settings ) then
+ settings = Blizzard_CombatLog_CurrentSettings;
+ end
+ for mask,colorArray in pairs( settings.colors.unitColoring ) do
+ if ( CombatLog_Object_IsA (unitFlags, mask) )then
+ array = colorArray;
+ break;
+ end
+ end
+ return array or defaultColorArray
+end
+_G.CombatLog_Color_ColorArrayByUnitType = CombatLog_Color_ColorArrayByUnitType
+
+--
+-- Gets the appropriate color for a spell school
+--
+local function CombatLog_Color_ColorArrayBySchool(school, settings)
+ if ( not settings ) then
+ settings = Blizzard_CombatLog_CurrentSettings;
+ end
+ if ( not school ) then
+ return settings.colors.schoolColoring.default;
+ end
+
+ return settings.colors.schoolColoring[school] or defaultColorArray
+end
+_G.CombatLog_Color_ColorArrayBySchool = CombatLog_Color_ColorArrayBySchool
+
+--
+-- Gets the appropriate color for a spell school
+--
+
+local highlightColorTable = {}
+local function CombatLog_Color_HighlightColorArray(colorArray)
+ highlightColorTable.r = colorArray.r * COMBATLOG_HIGHLIGHT_MULTIPLIER;
+ highlightColorTable.g = colorArray.g * COMBATLOG_HIGHLIGHT_MULTIPLIER;
+ highlightColorTable.b = colorArray.b * COMBATLOG_HIGHLIGHT_MULTIPLIER;
+ highlightColorTable.a = colorArray.a;
+
+ return highlightColorTable
+end
+_G.CombatLog_Color_HighlightColorArray = CombatLog_Color_HighlightColorArray
+
+--
+-- Returns a string associated with a numeric power type
+--
+local function CombatLog_String_PowerType(powerType)
+ if ( not powerType ) then
+ return "";
+ elseif ( powerType == SPELL_POWER_MANA ) then
+ return MANA;
+ elseif ( powerType == SPELL_POWER_RAGE ) then
+ return RAGE;
+ elseif ( powerType == SPELL_POWER_ENERGY ) then
+ return ENERGY;
+ elseif ( powerType == SPELL_POWER_FOCUS ) then
+ return FOCUS;
+ elseif ( powerType == SPELL_POWER_HAPPINESS ) then
+ return HAPPINESS;
+ elseif ( powerType == SPELL_POWER_RUNES ) then
+ return RUNES;
+ elseif ( powerType == SPELL_POWER_RUNIC_POWER ) then
+ return RUNIC_POWER;
+ end
+end
+_G.CombatLog_String_PowerType = CombatLog_String_PowerType
+
+local SCHOOL_STRINGS = {
+ STRING_SCHOOL_PHYSICAL,
+ STRING_SCHOOL_HOLY,
+ STRING_SCHOOL_FIRE,
+ STRING_SCHOOL_NATURE,
+ STRING_SCHOOL_FROST,
+ STRING_SCHOOL_SHADOW,
+ STRING_SCHOOL_ARCANE
+}
+
+local SchoolStringTable = {
+ -- Single Schools
+ [SCHOOL_MASK_PHYSICAL] = STRING_SCHOOL_PHYSICAL,
+ [SCHOOL_MASK_HOLY] = STRING_SCHOOL_HOLY,
+ [SCHOOL_MASK_FIRE] = STRING_SCHOOL_FIRE,
+ [SCHOOL_MASK_NATURE] = STRING_SCHOOL_NATURE,
+ [SCHOOL_MASK_FROST] = STRING_SCHOOL_FROST,
+ [SCHOOL_MASK_SHADOW] = STRING_SCHOOL_SHADOW,
+ [SCHOOL_MASK_ARCANE] = STRING_SCHOOL_ARCANE,
+ -- Physical and a Magical
+ [SCHOOL_MASK_PHYSICAL + SCHOOL_MASK_FIRE] = STRING_SCHOOL_FLAMESTRIKE,
+ [SCHOOL_MASK_PHYSICAL + SCHOOL_MASK_FROST] = STRING_SCHOOL_FROSTSTRIKE,
+ [SCHOOL_MASK_PHYSICAL + SCHOOL_MASK_ARCANE] = STRING_SCHOOL_SPELLSTRIKE,
+ [SCHOOL_MASK_PHYSICAL + SCHOOL_MASK_NATURE] = STRING_SCHOOL_STORMSTRIKE,
+ [SCHOOL_MASK_PHYSICAL + SCHOOL_MASK_SHADOW] = STRING_SCHOOL_SHADOWSTRIKE,
+ [SCHOOL_MASK_PHYSICAL + SCHOOL_MASK_HOLY] = STRING_SCHOOL_HOLYSTRIKE,
+ -- Two Magical Schools
+ [SCHOOL_MASK_FIRE + SCHOOL_MASK_FROST] = STRING_SCHOOL_FROSTFIRE,
+ [SCHOOL_MASK_FIRE + SCHOOL_MASK_ARCANE] = STRING_SCHOOL_SPELLFIRE,
+ [SCHOOL_MASK_FIRE + SCHOOL_MASK_NATURE] = STRING_SCHOOL_FIRESTORM,
+ [SCHOOL_MASK_FIRE + SCHOOL_MASK_SHADOW] = STRING_SCHOOL_SHADOWFLAME,
+ [SCHOOL_MASK_FIRE + SCHOOL_MASK_HOLY] = STRING_SCHOOL_HOLYFIRE,
+ [SCHOOL_MASK_FROST + SCHOOL_MASK_ARCANE] = STRING_SCHOOL_SPELLFROST,
+ [SCHOOL_MASK_FROST + SCHOOL_MASK_NATURE] = STRING_SCHOOL_FROSTSTORM,
+ [SCHOOL_MASK_FROST + SCHOOL_MASK_SHADOW] = STRING_SCHOOL_SHADOWFROST,
+ [SCHOOL_MASK_FROST + SCHOOL_MASK_HOLY] = STRING_SCHOOL_HOLYFROST,
+ [SCHOOL_MASK_ARCANE + SCHOOL_MASK_NATURE] = STRING_SCHOOL_SPELLSTORM,
+ [SCHOOL_MASK_ARCANE + SCHOOL_MASK_SHADOW] = STRING_SCHOOL_SPELLSHADOW,
+ [SCHOOL_MASK_ARCANE + SCHOOL_MASK_HOLY] = STRING_SCHOOL_DIVINE,
+ [SCHOOL_MASK_NATURE + SCHOOL_MASK_SHADOW] = STRING_SCHOOL_SHADOWSTORM,
+ [SCHOOL_MASK_NATURE + SCHOOL_MASK_HOLY] = STRING_SCHOOL_HOLYSTORM,
+ [SCHOOL_MASK_SHADOW + SCHOOL_MASK_HOLY] = STRING_SCHOOL_SHADOWLIGHT,
+ -- Three or more schools
+ [SCHOOL_MASK_FIRE + SCHOOL_MASK_FROST + SCHOOL_MASK_NATURE] = STRING_SCHOOL_ELEMENTAL,
+ [SCHOOL_MASK_FIRE + SCHOOL_MASK_FROST + SCHOOL_MASK_ARCANE + SCHOOL_MASK_NATURE + SCHOOL_MASK_SHADOW] = STRING_SCHOOL_CHROMATIC,
+ [SCHOOL_MASK_FIRE + SCHOOL_MASK_FROST + SCHOOL_MASK_ARCANE + SCHOOL_MASK_NATURE + SCHOOL_MASK_SHADOW + SCHOOL_MASK_HOLY] = STRING_SCHOOL_MAGIC,
+ [SCHOOL_MASK_PHYSICAL + SCHOOL_MASK_FIRE + SCHOOL_MASK_FROST + SCHOOL_MASK_ARCANE + SCHOOL_MASK_NATURE + SCHOOL_MASK_SHADOW + SCHOOL_MASK_HOLY] = STRING_SCHOOL_CHAOS,
+};
+
+local function CombatLog_String_SchoolString(school)
+ if ( not school or school == SCHOOL_MASK_NONE ) then
+ return STRING_SCHOOL_UNKNOWN;
+ end
+
+ local schoolString = SchoolStringTable[school];
+ return schoolString or STRING_SCHOOL_UNKNOWN
+end
+_G.CombatLog_String_SchoolString = CombatLog_String_SchoolString
+
+local function CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill )
+ local resultStr;
+ -- Result String formatting
+ local useOverhealing = overhealing and overhealing > 0;
+ local useOverkill = overkill and overkill > 0;
+ local useAbsorbed = absorbed and absorbed > 0;
+ if ( resisted or blocked or critical or glancing or crushing or useOverhealing or useOverkill or useAbsorbed) then
+ resultStr = nil;
+
+ if ( resisted ) then
+ if ( resisted < 0 ) then --Its really a vulnerability
+ resultStr = format(TEXT_MODE_A_STRING_RESULT_VULNERABILITY, -resisted);
+ else
+ resultStr = format(TEXT_MODE_A_STRING_RESULT_RESIST, resisted);
+ end
+ end
+ if ( blocked ) then
+ if ( resultStr ) then
+ resultStr = resultStr.." "..format(TEXT_MODE_A_STRING_RESULT_BLOCK, blocked);
+ else
+ resultStr = format(TEXT_MODE_A_STRING_RESULT_BLOCK, blocked);
+ end
+ end
+ if ( useAbsorbed ) then
+ if ( resultStr ) then
+ resultStr = resultStr.." "..format(TEXT_MODE_A_STRING_RESULT_ABSORB, absorbed);
+ else
+ resultStr = format(TEXT_MODE_A_STRING_RESULT_ABSORB, absorbed);
+ end
+ end
+ if ( glancing ) then
+ if ( resultStr ) then
+ resultStr = resultStr.." "..TEXT_MODE_A_STRING_RESULT_GLANCING;
+ else
+ resultStr = TEXT_MODE_A_STRING_RESULT_GLANCING;
+ end
+ end
+ if ( crushing ) then
+ if ( resultStr ) then
+ resultStr = resultStr.." "..TEXT_MODE_A_STRING_RESULT_CRUSHING;
+ else
+ resultStr = TEXT_MODE_A_STRING_RESULT_CRUSHING;
+ end
+ end
+ if ( useOverhealing ) then
+ if ( resultStr ) then
+ resultStr = resultStr.." "..format(TEXT_MODE_A_STRING_RESULT_OVERHEALING, overhealing);
+ else
+ resultStr = format(TEXT_MODE_A_STRING_RESULT_OVERHEALING, overhealing);
+ end
+ end
+ if ( useOverkill ) then
+ if ( resultStr ) then
+ resultStr = resultStr.." "..format(TEXT_MODE_A_STRING_RESULT_OVERKILLING, overkill);
+ else
+ resultStr = format(TEXT_MODE_A_STRING_RESULT_OVERKILLING, overkill);
+ end
+ end
+ if ( critical ) then
+ local critString = TEXT_MODE_A_STRING_RESULT_CRITICAL;
+ if ( spellId ) then
+ critString = TEXT_MODE_A_STRING_RESULT_CRITICAL_SPELL;
+ end
+ if ( resultStr ) then
+ resultStr = resultStr.." "..critString;
+ else
+ resultStr = critString;
+ end
+ end
+ end
+
+ return resultStr;
+end
+_G.CombatLog_String_DamageResultString = CombatLog_String_DamageResultString
+
+--
+-- Get the appropriate raid icon for a unit
+--
+local function CombatLog_String_GetIcon ( unitFlags, direction )
+
+ -- Check for an appropriate icon for this unit
+ local raidTarget = bit_band(unitFlags, COMBATLOG_OBJECT_RAIDTARGET_MASK);
+ if ( raidTarget == 0 ) then
+ return "";
+ end
+
+ local iconString = "";
+ local icon = nil;
+ local iconBit = 0;
+
+ if ( raidTarget == COMBATLOG_OBJECT_RAIDTARGET1 ) then
+ icon = COMBATLOG_ICON_RAIDTARGET1;
+ iconBit = COMBATLOG_OBJECT_RAIDTARGET1;
+ elseif ( raidTarget == COMBATLOG_OBJECT_RAIDTARGET2 ) then
+ icon = COMBATLOG_ICON_RAIDTARGET2;
+ iconBit = COMBATLOG_OBJECT_RAIDTARGET2;
+ elseif ( raidTarget == COMBATLOG_OBJECT_RAIDTARGET3 ) then
+ icon = COMBATLOG_ICON_RAIDTARGET3;
+ iconBit = COMBATLOG_OBJECT_RAIDTARGET3;
+ elseif ( raidTarget == COMBATLOG_OBJECT_RAIDTARGET4 ) then
+ icon = COMBATLOG_ICON_RAIDTARGET4;
+ iconBit = COMBATLOG_OBJECT_RAIDTARGET4;
+ elseif ( raidTarget == COMBATLOG_OBJECT_RAIDTARGET5 ) then
+ icon = COMBATLOG_ICON_RAIDTARGET5;
+ iconBit = COMBATLOG_OBJECT_RAIDTARGET5;
+ elseif ( raidTarget == COMBATLOG_OBJECT_RAIDTARGET6 ) then
+ icon = COMBATLOG_ICON_RAIDTARGET6;
+ iconBit = COMBATLOG_OBJECT_RAIDTARGET6;
+ elseif ( raidTarget == COMBATLOG_OBJECT_RAIDTARGET7 ) then
+ icon = COMBATLOG_ICON_RAIDTARGET7;
+ iconBit = COMBATLOG_OBJECT_RAIDTARGET7;
+ elseif ( raidTarget == COMBATLOG_OBJECT_RAIDTARGET8 ) then
+ icon = COMBATLOG_ICON_RAIDTARGET8;
+ iconBit = COMBATLOG_OBJECT_RAIDTARGET8;
+ end
+
+ -- Insert the Raid Icon if it exists
+ if ( icon ) then
+ --
+ -- Insert a hyperlink for that icon
+
+ if ( direction == "source" ) then
+ iconString = format(TEXT_MODE_A_STRING_SOURCE_ICON, iconBit, icon);
+ else
+ iconString = format(TEXT_MODE_A_STRING_DEST_ICON, iconBit, icon);
+ end
+ end
+
+ return iconString;
+end
+_G.CombatLog_String_GetIcon = CombatLog_String_GetIcon
+
+--
+-- Obtains the appropriate unit token for a GUID
+--
+local function CombatLog_String_GetToken (unitGUID, unitName, unitFlags)
+ --
+ -- Code to display Defias Pillager (A), Defias Pillager (B), etc
+ --
+ --[[
+ local newName = TEXT_MODE_A_STRING_TOKEN_UNIT;
+ -- Use the local cache if possible
+ if ( Blizzard_CombatLog_UnitTokens[unitGUID] ) then
+ -- For unique creatures, hide the token
+ if ( Blizzard_CombatLog_UnitTokens[unitGUID] == unitName ) then
+ return unitName;
+ end
+ newName = strreplace ( newName, "$token", Blizzard_CombatLog_UnitTokens[unitGUID] );
+ newName = strreplace ( newName, "$unitName", unitName );
+ else
+ if ( not Blizzard_CombatLog_UnitTokens[unitName] or Blizzard_CombatLog_UnitTokens[unitName] > 26*26) then
+ Blizzard_CombatLog_UnitTokens[unitName] = 1;
+ Blizzard_CombatLog_UnitTokens[unitGUID] = unitName;
+ newName = unitName;
+ else
+ Blizzard_CombatLog_UnitTokens[unitName] = Blizzard_CombatLog_UnitTokens[unitName] + 1;
+ if ( Blizzard_CombatLog_UnitTokens[unitName] > 26 ) then
+ Blizzard_CombatLog_UnitTokens[unitGUID] =
+ string.char ( TEXT_MODE_A_STRING_TOKEN_BASE + math.floor(Blizzard_CombatLog_UnitTokens[unitName] / 26) )..
+ string.char ( TEXT_MODE_A_STRING_TOKEN_BASE + math.fmod(Blizzard_CombatLog_UnitTokens[unitName], 26) );
+ else
+ Blizzard_CombatLog_UnitTokens[unitGUID] = string.char ( TEXT_MODE_A_STRING_TOKEN_BASE + math.fmod(Blizzard_CombatLog_UnitTokens[unitName], 26) );
+ end
+
+ newName = strreplace ( newName, "$token", Blizzard_CombatLog_UnitTokens[unitGUID] );
+ newName = strreplace ( newName, "$unitName", unitName );
+ end
+ end
+ ]]
+
+ -- Shortcut since the above block is commented out.
+
+ -- newName = unitName;
+
+ return unitName;
+end
+_G.CombatLog_String_GetToken = CombatLog_String_GetToken
+
+--
+-- Gets the appropriate color for a unit type
+--
+--
+local function CombatLog_Color_ColorStringByUnitType(unitFlags)
+ local colorArray = CombatLog_Color_ColorArrayByUnitType(unitFlags);
+
+ return CombatLog_Color_FloatToText(colorArray.r, colorArray.g, colorArray.b, colorArray.a )
+end
+_G.CombatLog_Color_ColorStringByUnitType = CombatLog_Color_ColorStringByUnitType
+
+
+--[[
+-- Gets the appropriate color for a school
+--
+--]]
+local function CombatLog_Color_ColorStringBySchool(school)
+ local colorArray = CombatLog_Color_ColorArrayBySchool(school);
+
+ return CombatLog_Color_FloatToText(colorArray.r, colorArray.g, colorArray.b, colorArray.a )
+end
+_G.CombatLog_Color_ColorStringBySchool = CombatLog_Color_ColorStringBySchool
+
+--
+-- Gets the appropriate color for an event type
+--
+--
+local function CombatLog_Color_ColorStringByEventType(unitFlags)
+ local colorArray = CombatLog_Color_ColorArrayByEventType(unitFlags);
+
+ return CombatLog_Color_FloatToText(colorArray.r, colorArray.g, colorArray.b, colorArray.a )
+end
+_G.CombatLog_Color_ColorStringByEventType = CombatLog_Color_ColorStringByEventType
+
+
+--[[
+-- Handles events and dumps them to the specified frame.
+--]]
+
+-- Add settings as an arg
+
+local defaultCombatLogLineColor = { a = 1.00, r = 1.00, g = 1.00, b = 1.00 };
+
+function CombatLog_OnEvent(filterSettings, timestamp, event, sourceGUID, sourceName, sourceFlags, destGUID, destName, destFlags, ...)
+ -- [environmentalDamageType]
+ -- [spellName, spellRank, spellSchool]
+ -- [damage, school, [resisted, blocked, absorbed, crit, glancing, crushing]]
+
+ -- Upvalue this, we're gonna use it a lot
+ local settings = filterSettings.settings;
+
+ local lineColor = defaultCombatLogLineColor;
+ local sourceColor, destColor = nil, nil;
+
+ local braceColor = "FFFFFFFF";
+ local abilityColor = "FFFFFF00";
+
+ -- Processing variables
+ local textMode = settings.textMode;
+ local timestampEnabled = settings.timestamp;
+ local hideBuffs = settings.hideBuffs;
+ local hideDebuffs = settings.hideDebuffs;
+ local sourceEnabled = true;
+ local falseSource = false;
+ local destEnabled = true;
+ local spellEnabled = true;
+ local actionEnabled = true;
+ local valueEnabled = true;
+ local valueTypeEnabled = true;
+ local resultEnabled = true;
+ local powerTypeEnabled = true;
+ local itemEnabled = false;
+ local extraSpellEnabled = false;
+ local valueIsItem = false;
+ local schoolEnabled = true;
+
+ -- Get the initial string
+ local schoolString;
+ local resultStr;
+
+ local formatString = TEXT_MODE_A_STRING_1;
+ if ( EVENT_TEMPLATE_FORMATS[event] ) then
+ formatString = EVENT_TEMPLATE_FORMATS[event];
+ end
+
+ -- Replacements to do:
+ -- * Src, Dest, Action, Spell, Amount, Result
+
+ -- Spell standard order
+ local spellId, spellName, spellSchool;
+ local extraSpellId, extraSpellName, extraSpellSchool;
+
+ -- For Melee/Ranged swings and enchants
+ local nameIsNotSpell, extraNameIsNotSpell;
+
+ -- Damage standard order
+ local amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing, overhealing;
+ -- Miss argument order
+ local missType, amountMissed;
+ -- Aura arguments
+ local auraType; -- BUFF or DEBUFF
+
+ -- Enchant arguments
+ local itemId, itemName;
+
+ -- Special Spell values
+ local valueType = 1; -- 1 = School, 2 = Power Type
+ local extraAmount; -- Used for Drains and Leeches
+ local powerType; -- Used for energizes, drains and leeches
+ local environmentalType; -- Used for environmental damage
+ local message; -- Used for server spell messages
+ local originalEvent = event; -- Used for spell links
+
+ -- Generic disabling stuff
+ if ( not sourceName or CombatLog_Object_IsA(sourceFlags, COMBATLOG_OBJECT_NONE) ) then
+ sourceEnabled = false;
+ end
+ if ( not destName or CombatLog_Object_IsA(destFlags, COMBATLOG_OBJECT_NONE) ) then
+ destEnabled = false;
+ end
+
+ local subVal = strsub(event, 1, 5)
+
+ -- Swings
+ if ( subVal == "SWING" ) then
+ spellName = ACTION_SWING;
+ nameIsNotSpell = true;
+ end
+
+ -- Break out the arguments into variable
+ if ( event == "SWING_DAMAGE" ) then
+ -- Damage standard
+ amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = ...;
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ if ( not resultStr ) then
+ resultEnabled = false;
+ end
+
+ amount = amount - overkill;
+
+ elseif ( event == "SWING_MISSED" ) then
+ spellName = ACTION_SWING;
+
+ -- Miss type
+ missType, amountMissed = ...;
+
+ -- Result String
+ if( missType == "RESIST" or missType == "BLOCK" or missType == "ABSORB" ) then
+ resultStr = format(_G["TEXT_MODE_A_STRING_RESULT_"..missType], amountMissed);
+ else
+ resultStr = _G["ACTION_SWING_MISSED_"..missType];
+ end
+
+ -- Miss Type
+ if ( settings.fullText and missType ) then
+ event = format("%s_%s", event, missType);
+ end
+
+ -- Disable appropriate sections
+ nameIsNotSpell = true;
+ valueEnabled = false;
+ resultEnabled = true;
+
+ elseif ( subVal == "SPELL" ) then -- Spell standard arguments
+ spellId, spellName, spellSchool = ...;
+
+ if ( event == "SPELL_DAMAGE" or event == "SPELL_BUILDING_DAMAGE") then
+ -- Damage standard
+ amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = select(4, ...);
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+
+ amount = amount - overkill;
+ elseif ( event == "SPELL_MISSED" ) then
+ -- Miss type
+ missType, amountMissed = select(4, ...);
+
+ resultEnabled = true;
+ -- Result String
+ if( missType == "RESIST" or missType == "BLOCK" or missType == "ABSORB" ) then
+ if ( amountMissed ~= 0 ) then
+ resultStr = format(_G["TEXT_MODE_A_STRING_RESULT_"..missType], amountMissed);
+ else
+ resultEnabled = false;
+ end
+ else
+ resultStr = _G["ACTION_SWING_MISSED_"..missType];
+ end
+
+ -- Miss Event
+ if ( missType ) then
+ event = format("%s_%s", event, missType);
+ end
+
+ -- Disable appropriate sections
+ valueEnabled = false;
+ elseif ( event == "SPELL_HEAL" or event == "SPELL_BUILDING_HEAL") then
+ -- Did the heal crit?
+ amount, overhealing, absorbed, critical = select(4, ...);
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+
+ -- Temporary Spell School Hack
+ school = spellSchool;
+
+ -- Disable appropriate sections
+ valueEnabled = true;
+ valueTypeEnabled = true;
+
+ amount = amount - overhealing;
+ elseif ( event == "SPELL_ENERGIZE" ) then
+ -- Set value type to be a power type
+ valueType = 2;
+
+ -- Did the heal crit?
+ amount, powerType = select(4, ...);
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+
+ -- Disable appropriate sections
+ valueEnabled = true;
+ valueTypeEnabled = true;
+ elseif ( strsub(event, 1, 14) == "SPELL_PERIODIC" ) then
+
+ if ( event == "SPELL_PERIODIC_MISSED" ) then
+ -- Miss type
+ missType = select(4, ...);
+
+ -- Result String
+ if ( missType == "ABSORB" ) then
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, select(5,...), critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+ else
+ resultStr = _G["ACTION_SPELL_PERIODIC_MISSED_"..missType];
+ end
+
+ -- Miss Event
+ if ( settings.fullText and missType ) then
+ event = format("%s_%s", event, missType);
+ end
+
+ -- Disable appropriate sections
+ valueEnabled = false;
+ resultEnabled = true;
+ elseif ( event == "SPELL_PERIODIC_DAMAGE" ) then
+ -- Damage standard
+ amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = select(4, ...);
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ -- Disable appropriate sections
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+
+ amount = amount - overkill;
+ elseif ( event == "SPELL_PERIODIC_HEAL" ) then
+ -- Did the heal crit?
+ amount, overhealing, absorbed, critical = select(4, ...);
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+
+ -- Temporary Spell School Hack
+ school = spellSchool;
+
+ -- Disable appropriate sections
+ valueEnabled = true;
+ valueTypeEnabled = true;
+
+ amount = amount - overhealing;
+ elseif ( event == "SPELL_PERIODIC_DRAIN" ) then
+ -- Special attacks
+ amount, powerType, extraAmount = select(4, ...);
+
+ -- Set value type to be a power type
+ valueType = 2;
+
+ -- Result String
+ --resultStr = _G[textModeString .. "RESULT"];
+ --resultStr = strreplace(resultStr,"$resultString", _G["ACTION_"..event.."_RESULT"]);
+
+ -- Disable appropriate sections
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+ valueEnabled = true;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_PERIODIC_LEECH" ) then
+ -- Special attacks
+ amount, powerType, extraAmount = select(4, ...);
+
+ -- Set value type to be a power type
+ valueType = 2;
+
+ -- Result String
+ resultStr = format(_G["ACTION_SPELL_PERIODIC_LEECH_RESULT"], nil, nil, nil, nil, nil, nil, nil, CombatLog_String_PowerType(powerType), nil, extraAmount) --"($extraAmount $powerType Gained)"
+
+ -- Disable appropriate sections
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+ valueEnabled = true;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_PERIODIC_ENERGIZE" ) then
+ -- Set value type to be a power type
+ valueType = 2;
+
+ -- Did the heal crit?
+ amount, powerType = select(4, ...);
+
+ -- Parse the result string
+ --resultStr = _G[textModeString .. "RESULT"];
+ --resultStr = strreplace(resultStr,"$resultString", _G["ACTION_"..event.."_RESULT"]);
+
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+
+ -- Disable appropriate sections
+ valueEnabled = true;
+ valueTypeEnabled = true;
+ end
+ elseif ( event == "SPELL_CAST_START" ) then -- Spellcast
+ if ( not destName ) then
+ destEnabled = false;
+ end
+ if ( not sourceName and not settings.fullText ) then
+ sourceName = COMBATLOG_UNKNOWN_UNIT;
+ sourceEnabled = true;
+ falseSource = true;
+ end
+
+ -- Disable appropriate types
+ resultEnabled = false;
+ valueEnabled = false;
+ elseif ( event == "SPELL_CAST_SUCCESS" ) then
+ if ( not destName ) then
+ destEnabled = false;
+ end
+ if ( not sourceName and not settings.fullText ) then
+ sourceName = COMBATLOG_UNKNOWN_UNIT;
+ sourceEnabled = true;
+ falseSource = true;
+ end
+
+ -- Disable appropriate types
+ resultEnabled = false;
+ valueEnabled = false;
+ elseif ( event == "SPELL_CAST_FAILED" ) then
+ if ( not destName ) then
+ destEnabled = false;
+ end
+ -- Miss reason
+ missType = select(4, ...);
+
+ -- Result String
+ resultStr = format("(%s)", missType);
+ --resultStr = strreplace(_G[textModeString .. "RESULT"],"$resultString", missType);
+
+ -- Disable appropriate sections
+ valueEnabled = false;
+ destEnabled = false;
+
+ if ( not resultStr ) then
+ resultEnabled = false;
+ end
+ elseif ( event == "SPELL_DRAIN" ) then -- Special Spell effects
+ -- Special attacks
+ amount, powerType, extraAmount = select(4, ...);
+
+ -- Set value type to be a power type
+ valueType = 2;
+
+ -- Disable appropriate sections
+ if ( not resultStr ) then
+ resultEnabled = false;
+ end
+ valueEnabled = true;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_LEECH" ) then
+ -- Special attacks
+ amount, powerType, extraAmount = select(4, ...);
+
+ -- Set value type to be a power type
+ valueType = 2;
+
+ -- Result String
+ resultStr = format(_G["ACTION_SPELL_LEECH_RESULT"], nil, nil, nil, nil, nil, nil, nil, CombatLog_String_PowerType(powerType), nil, extraAmount)
+
+ -- Disable appropriate sections
+ if ( not resultStr ) then
+ resultEnabled = false;
+ end
+ valueEnabled = true;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_INTERRUPT" ) then
+ -- Spell interrupted
+ extraSpellId, extraSpellName, extraSpellSchool = select(4, ...);
+
+ -- Replace the value token with a spell token
+ if ( extraSpellId ) then
+ extraSpellEnabled = true;
+ end
+
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = false;
+ valueTypeEnabled = false;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_EXTRA_ATTACKS" ) then
+ -- Special attacks
+ amount = select(4, ...);
+
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = true;
+ valueTypeEnabled = false;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_SUMMON" ) then
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = false;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_RESURRECT" ) then
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = false;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_CREATE" ) then
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = false;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_INSTAKILL" ) then
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = false;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_DURABILITY_DAMAGE" ) then
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = false;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_DURABILITY_DAMAGE_ALL" ) then
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = false;
+ schoolEnabled = false;
+ elseif ( event == "SPELL_DISPEL_FAILED" ) then
+ -- Extra Spell standard
+ extraSpellId, extraSpellName, extraSpellSchool = select(4, ...);
+
+ -- Replace the value token with a spell token
+ if ( extraSpellId ) then
+ extraSpellEnabled = true;
+ end
+
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = false;
+ elseif ( event == "SPELL_DISPEL" or event == "SPELL_STOLEN" ) then
+ -- Extra Spell standard, Aura standard
+ extraSpellId, extraSpellName, extraSpellSchool, auraType = select(4, ...);
+
+ -- Event Type
+ event = format("%s_%s", event, auraType);
+
+ -- Replace the value token with a spell token
+ if ( extraSpellId ) then
+ extraSpellEnabled = true;
+ valueEnabled = true;
+ else
+ valueEnabled = false;
+ end
+
+ -- Disable appropriate sections
+ resultEnabled = false;
+ elseif ( event == "SPELL_AURA_BROKEN" or event == "SPELL_AURA_BROKEN_SPELL") then
+
+ -- Extra Spell standard, Aura standard
+ if(event == "SPELL_AURA_BROKEN") then
+ auraType = select(4, ...);
+ else
+ extraSpellId, extraSpellName, extraSpellSchool, auraType = select(4, ...);
+ end
+
+ -- Abort if buff/debuff is not set to true
+ if ( hideBuffs and auraType == AURA_TYPE_BUFF ) then
+ return;
+ elseif ( hideDebuffs and auraType == AURA_TYPE_DEBUFF ) then
+ return;
+ end
+
+ -- Event Type
+ event = format("%s_%s", event, auraType);
+
+ -- Replace the value token with a spell token
+ if ( extraSpellId ) then
+ extraSpellEnabled = true;
+ valueEnabled = true;
+ else
+ valueEnabled = false;
+ end
+
+ resultEnabled = false;
+ elseif ( event == "SPELL_AURA_APPLIED" or event == "SPELL_AURA_REMOVED" or event == "SPELL_AURA_REFRESH") then -- Aura Events
+ -- Aura standard
+ auraType = select(4, ...);
+
+ -- Abort if buff/debuff is not set to true
+ if ( hideBuffs and auraType == AURA_TYPE_BUFF ) then
+ return;
+ elseif ( hideDebuffs and auraType == AURA_TYPE_DEBUFF ) then
+ return;
+ end
+
+ formatString = TEXT_MODE_A_STRING_1;
+
+ -- Event Type
+ event = format("%s_%s", event, auraType);
+
+ resultEnabled = false;
+ valueEnabled = false;
+ elseif ( event == "SPELL_AURA_APPLIED_DOSE" or event == "SPELL_AURA_REMOVED_DOSE" ) then
+ -- Aura standard
+ auraType, amount = select(4, ...);
+
+ -- Abort if buff/debuff is not set to true
+ if ( hideBuffs and auraType == AURA_TYPE_BUFF ) then
+ return;
+ elseif ( hideDebuffs and auraType == AURA_TYPE_DEBUFF ) then
+ return;
+ end
+
+ -- Event Type
+ event = format("%s_%s", event, auraType);
+
+
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = true;
+ valueTypeEnabled = false;
+
+ end
+ elseif ( subVal == "RANGE" ) then
+ --spellName = ACTION_RANGED;
+ --nameIsNotSpell = true;
+
+ -- Shots are spells, technically
+ spellId, spellName, spellSchool = ...;
+ if ( event == "RANGE_DAMAGE" ) then
+ -- Damage standard
+ amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = select(4, ...);
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+
+ -- Disable appropriate sections
+ nameIsNotSpell = true;
+
+ amount = amount - overkill;
+ elseif ( event == "RANGE_MISSED" ) then
+ spellName = ACTION_RANGED;
+
+ -- Miss type
+ missType, amountMissed = select(4,...);
+
+ -- Result String
+ if( missType == "RESIST" or missType == "BLOCK" or missType == "ABSORB" ) then
+ resultStr = format(_G["TEXT_MODE_A_STRING_RESULT_"..missType], amountMissed);
+ else
+ resultStr = _G["ACTION_RANGE_MISSED_"..missType];
+ end
+
+ -- Miss Type
+ if ( settings.fullText and missType ) then
+ event = format("%s_%s", event, missType);
+ end
+
+ -- Disable appropriate sections
+ nameIsNotSpell = true;
+ valueEnabled = false;
+ resultEnabled = true;
+ end
+ elseif ( event == "DAMAGE_SHIELD" ) then -- Damage Shields
+ -- Spell standard, Damage standard
+ spellId, spellName, spellSchool, amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = ...;
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ -- Disable appropriate sections
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+
+ amount = amount - overkill;
+ elseif ( event == "DAMAGE_SHIELD_MISSED" ) then
+ -- Spell standard, Miss type
+ spellId, spellName, spellSchool, missType = ...;
+
+ -- Result String
+ resultStr = _G["ACTION_DAMAGE_SHIELD_MISSED_"..missType];
+
+ -- Miss Event
+ if ( settings.fullText and missType ) then
+ event = format("%s_%s", event, missType);
+ end
+
+ -- Disable appropriate sections
+ valueEnabled = false;
+ if ( not resultStr ) then
+ resultEnabled = false;
+ end
+ elseif ( event == "PARTY_KILL" ) then -- Unique Events
+ -- Disable appropriate sections
+ resultEnabled = false;
+ valueEnabled = false;
+ spellEnabled = false;
+ elseif ( event == "ENCHANT_APPLIED" ) then
+ -- Get the enchant name, item id and item name
+ spellName, itemId, itemName = ...;
+ nameIsNotSpell = true;
+
+ -- Disable appropriate sections
+ valueIsItem = true;
+ itemEnabled = true;
+ resultEnabled = false;
+ elseif ( event == "ENCHANT_REMOVED" ) then
+ -- Get the enchant name, item id and item name
+ spellName, itemId, itemName = ...;
+ nameIsNotSpell = true;
+
+ -- Disable appropriate sections
+ valueIsItem = true;
+ itemEnabled = true;
+ resultEnabled = false;
+ sourceEnabled = false;
+
+ elseif ( event == "UNIT_DIED" or event == "UNIT_DESTROYED" or event == "UNIT_DISSIPATES" ) then
+ -- Swap Source with Dest
+ sourceName = destName;
+ sourceGUID = destGUID;
+ sourceFlags = destFlags;
+
+ -- Disable appropriate sections
+ resultEnabled = false;
+ sourceEnabled = true;
+ destEnabled = false;
+ spellEnabled = false;
+ valueEnabled = false;
+ elseif ( event == "ENVIRONMENTAL_DAMAGE" ) then
+ --Environemental Type, Damage standard
+ environmentalType, amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = ...
+
+ -- Miss Event
+ spellName = _G["ACTION_ENVIRONMENTAL_DAMAGE_"..environmentalType];
+ spellSchool = school;
+ nameIsNotSpell = true;
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ -- Environmental Event
+ if ( settings.fullText and environmentalType ) then
+ event = "ENVIRONMENTAL_DAMAGE_"..environmentalType;
+ end
+
+ if ( not resultStr ) then
+ resultEnabled = false;
+ end
+
+ amount = amount - overkill;
+ elseif ( event == "DAMAGE_SPLIT" ) then
+ -- Spell Standard Arguments, Damage standard
+ spellId, spellName, spellSchool, amount, overkill, school, resisted, blocked, absorbed, critical, glancing, crushing = ...;
+
+ -- Parse the result string
+ resultStr = CombatLog_String_DamageResultString( resisted, blocked, absorbed, critical, glancing, crushing, overhealing, textMode, spellId, overkill );
+
+ if ( not resultStr ) then
+ resultEnabled = false
+ end
+
+ amount = amount - overkill;
+ end
+
+ -- Throw away all of the assembled strings and just grab a premade one
+ if ( settings.fullText ) then
+ local formatStringEvent = format("ACTION_%s_FULL_TEXT", event);
+
+ -- Get the base string
+ if ( _G[formatStringEvent] ) then
+ formatString = _G[formatStringEvent];
+ end
+
+ -- Set any special cases
+ if ( not sourceEnabled ) then
+ formatStringEvent = formatStringEvent.."_NO_SOURCE";
+ end
+ if ( not destEnabled ) then
+ formatStringEvent = formatStringEvent.."_NO_DEST";
+ end
+
+
+ if (event=="DAMAGE_SPLIT" and resultStr) then
+ if (amount == 0) then
+ formatStringEvent = "ACTION_DAMAGE_SPLIT_ABSORBED_FULL_TEXT";
+ else
+ formatStringEvent = "ACTION_DAMAGE_SPLIT_RESULT_FULL_TEXT";
+ end
+ end
+
+ -- Get the special cased string
+ if ( _G[formatStringEvent] ) then
+ formatString = _G[formatStringEvent];
+ end
+
+ sourceEnabled = true;
+ destEnabled = true;
+ spellEnabled = true;
+ valueEnabled = true;
+ end
+
+ -- Actor name construction.
+ --
+ local sourceNameStr = "";
+ local destNameStr = "";
+ local sourceIcon = "";
+ local destIcon = "";
+ local spellNameStr = spellName;
+ local extraSpellNameStr = extraSpellName;
+ local itemNameStr = itemName;
+ local actionEvent = "ACTION_"..event;
+ local actionStr = _G[actionEvent];
+ local timestampStr = timestamp;
+ local powerTypeString = "";
+
+ -- If this ever succeeds, the event string is missing.
+ --
+ if ( not actionStr ) then
+ actionStr = event;
+ end
+
+ -- Initialize the strings now
+ sourceNameStr, destNameStr = sourceName, destName;
+
+ -- Special changes for localization when not in full text mode
+ if ( not settings.fullText and COMBAT_LOG_UNIT_YOU_ENABLED == "1" ) then
+ -- Replace your name with "You";
+ if ( sourceName and CombatLog_Object_IsA(sourceFlags, COMBATLOG_FILTER_MINE) ) then
+ sourceNameStr = UNIT_YOU_SOURCE;
+ end
+ if ( destName and CombatLog_Object_IsA(destFlags, COMBATLOG_FILTER_MINE) ) then
+ destNameStr = UNIT_YOU_DEST;
+ end
+ -- Apply the possessive form to the source
+ if ( sourceName and spellName and _G[actionEvent.."_POSSESSIVE"] == "1" ) then
+ if ( sourceName and CombatLog_Object_IsA(sourceFlags, COMBATLOG_FILTER_MINE) ) then
+ sourceNameStr = UNIT_YOU_SOURCE_POSSESSIVE;
+ end
+ end
+ -- Apply the possessive form to the source
+ if ( destName and ( extraSpellName or itemName ) ) then
+ if ( destName and CombatLog_Object_IsA(destFlags, COMBATLOG_FILTER_MINE) ) then
+ destNameStr = UNIT_YOU_DEST_POSSESSIVE;
+ end
+ end
+
+ -- If its full text mode
+ else
+ -- Apply the possessive form to the source
+ if ( sourceName and spellName and _G[actionEvent.."_POSSESSIVE"] == "1" ) then
+ sourceNameStr = format(TEXT_MODE_A_STRING_POSSESSIVE, sourceNameStr);
+ end
+
+ -- Apply the possessive form to the dest if the dest has a spell
+ if ( ( extraSpellName or itemName ) and destName ) then
+ destNameStr = format(TEXT_MODE_A_STRING_POSSESSIVE, destNameStr);
+ end
+ end
+
+ -- Unit Tokens
+ if ( settings.unitTokens ) then
+ -- Apply the possessive form to the source
+ if ( sourceName ) then
+ sourceName = CombatLog_String_GetToken(sourceGUID, sourceName, sourceFlags);
+ end
+ if ( destName ) then
+ destName = CombatLog_String_GetToken(destGUID, destName, destFlags);
+ end
+ end
+
+ -- Unit Icons
+ if ( settings.unitIcons ) then
+ if ( sourceName ) then
+ sourceIcon = CombatLog_String_GetIcon(sourceFlags, "source");
+ end
+ if ( destName ) then
+ destIcon = CombatLog_String_GetIcon(destFlags, "dest");
+ end
+ end
+
+ -- Get the source color
+ if ( sourceName ) then
+ sourceColor = CombatLog_Color_ColorStringByUnitType( sourceFlags );
+ end
+
+ -- Get the dest color
+ if ( destName ) then
+ destColor = CombatLog_Color_ColorStringByUnitType( destFlags );
+ end
+
+ -- Whole line coloring
+ if ( settings.lineColoring ) then
+ if ( settings.lineColorPriority == 3 or ( not sourceName and not destName) ) then
+ lineColor = CombatLog_Color_ColorArrayByEventType( event, filterSettings );
+ else
+ if ( ( settings.lineColorPriority == 1 and sourceName ) or not destName ) then
+ lineColor = CombatLog_Color_ColorArrayByUnitType( sourceFlags, filterSettings );
+ elseif ( ( settings.lineColorPriority == 2 and destName ) or not sourceName ) then
+ lineColor = CombatLog_Color_ColorArrayByUnitType( destFlags, filterSettings );
+ else
+ lineColor = CombatLog_Color_ColorArrayByUnitType( sourceFlags, filterSettings );
+ end
+ end
+ end
+
+ -- Only replace if there's an amount
+ if ( amount ) then
+ local amountColor;
+
+ -- Color amount numbers
+ if ( settings.amountColoring ) then
+ -- To make white swings white
+ if ( settings.noMeleeSwingColoring and school == SCHOOL_MASK_PHYSICAL and not spellId ) then
+ -- Do nothing
+ elseif ( settings.amountActorColoring ) then
+ if ( sourceName ) then
+ amountColor = CombatLog_Color_ColorArrayByUnitType( sourceFlags, filterSettings );
+ elseif ( destName ) then
+ amountColor = CombatLog_Color_ColorArrayByUnitType( destFlags, filterSettings );
+ end
+ elseif ( settings.amountSchoolColoring ) then
+ amountColor = CombatLog_Color_ColorArrayBySchool(school, filterSettings);
+ else
+ amountColor = filterSettings.colors.defaults.damage;
+ end
+
+ end
+ -- Highlighting
+ if ( settings.amountHighlighting ) then
+ local colorArray;
+ if ( not amountColor ) then
+ colorArray = lineColor;
+ else
+ colorArray = amountColor;
+ end
+ amountColor = CombatLog_Color_HighlightColorArray (colorArray);
+ end
+ if ( amountColor ) then
+ amountColor = CombatLog_Color_FloatToText(amountColor);
+ amount = format("|c%s%s|r", amountColor, amount);
+ end
+
+ schoolString = CombatLog_String_SchoolString(school);
+ local schoolNameColor = nil;
+ -- Color school names
+ if ( settings.schoolNameColoring ) then
+ if ( settings.noMeleeSwingColoring and school == SCHOOL_MASK_PHYSICAL and not spellId ) then
+ elseif ( settings.schoolNameActorColoring ) then
+ if ( sourceName ) then
+ schoolNameColor = CombatLog_Color_ColorArrayByUnitType( sourceFlags, filterSettings );
+ elseif ( destName ) then
+ schoolNameColor = CombatLog_Color_ColorArrayByUnitType( destFlags, filterSettings );
+ end
+ else
+ schoolNameColor = CombatLog_Color_ColorArrayBySchool( school, filterSettings );
+ end
+ end
+ -- Highlighting
+ if ( settings.schoolNameHighlighting ) then
+ local colorArray;
+ if ( not schoolNameColor ) then
+ colorArray = lineColor;
+ else
+ colorArray = schoolNameColor;
+ end
+ schoolNameColor = CombatLog_Color_HighlightColorArray (colorArray);
+ end
+ if ( schoolNameColor ) then
+ schoolNameColor = CombatLog_Color_FloatToText(schoolNameColor);
+ schoolString = format("|c%s%s|r", schoolNameColor, schoolString);
+ end
+
+ end
+
+ -- Power Type
+ if ( powerType ) then
+ powerTypeString = CombatLog_String_PowerType(powerType);
+ end
+
+ -- Color source names
+ if ( settings.unitColoring ) then
+ if ( sourceName and settings.sourceColoring ) then
+ sourceNameStr = format("|c%s%s|r", sourceColor, sourceNameStr);
+ end
+ if ( destName and settings.destColoring ) then
+ destNameStr = format("|c%s%s|r", destColor, destNameStr);
+ end
+ end
+
+ -- If there's an action (always)
+ if ( actionStr ) then
+ local actionColor = nil;
+ -- Color ability names
+ if ( settings.actionColoring ) then
+
+ if ( settings.actionActorColoring ) then
+ if ( sourceName ) then
+ actionColor = CombatLog_Color_ColorArrayByUnitType( sourceFlags, filterSettings );
+ elseif ( destName ) then
+ actionColor = CombatLog_Color_ColorArrayByUnitType( destFlags, filterSettings );
+ end
+ elseif ( settings.actionSchoolColoring and spellSchool ) then
+ actionColor = CombatLog_Color_ColorArrayBySchool( spellSchool, filterSettings );
+ else
+ actionColor = CombatLog_Color_ColorArrayByEventType(event);
+ end
+ -- Special option to only color "Miss" if there's no damage
+ elseif ( settings.missColoring ) then
+
+ if ( event ~= "SWING_DAMAGE" and
+ event ~= "RANGE_DAMAGE" and
+ event ~= "SPELL_DAMAGE" and
+ event ~= "SPELL_PERIODIC_DAMAGE" ) then
+
+ local actionColor = nil;
+
+ if ( settings.actionActorColoring ) then
+ actionColor = CombatLog_Color_ColorArrayByUnitType( sourceFlags, filterSettings );
+ elseif ( settings.actionSchoolColoring ) then
+ actionColor = CombatLog_Color_ColorArrayBySchool( spellSchool, filterSettings );
+ else
+ actionColor = CombatLog_Color_ColorArrayByEventType(event);
+ end
+
+ end
+ end
+
+ -- Highlighting
+ if ( settings.actionHighlighting ) then
+ local colorArray;
+ if ( not actionColor ) then
+ colorArray = lineColor;
+ else
+ colorArray = actionColor;
+ end
+ actionColor = CombatLog_Color_HighlightColorArray (colorArray);
+ end
+
+ if ( actionColor ) then
+ actionColor = CombatLog_Color_FloatToText(actionColor);
+ actionStr = format("|c%s%s|r", actionColor, actionStr);
+ end
+
+ end
+ -- If there's a spell name
+ if ( spellName ) then
+ local abilityColor = nil;
+ -- Color ability names
+ if ( settings.abilityColoring ) then
+ if ( settings.abilityActorColoring ) then
+ abilityColor = CombatLog_Color_ColorArrayByUnitType( sourceFlags, filterSettings );
+ elseif ( settings.abilitySchoolColoring ) then
+ abilityColor = CombatLog_Color_ColorArrayBySchool( spellSchool, filterSettings );
+ else
+ if ( spellSchool ) then
+ abilityColor = filterSettings.colors.defaults.spell;
+ end
+ end
+ end
+
+ -- Highlight this color
+ if ( settings.abilityHighlighting ) then
+ local colorArray;
+ if ( not abilityColor ) then
+ colorArray = lineColor;
+ else
+ colorArray = abilityColor;
+ end
+ abilityColor = CombatLog_Color_HighlightColorArray (colorArray);
+ end
+ if ( abilityColor ) then
+ abilityColor = CombatLog_Color_FloatToText(abilityColor);
+ if ( itemId ) then
+ spellNameStr = spellName;
+ else
+ spellNameStr = format("|c%s%s|r", abilityColor, spellName);
+ end
+ end
+ end
+
+ -- If there's a spell name
+ if ( extraSpellName ) then
+ local abilityColor = nil;
+ -- Color ability names
+ if ( settings.abilityColoring ) then
+
+ if ( settings.abilitySchoolColoring ) then
+ abilityColor = CombatLog_Color_ColorArrayBySchool( extraSpellSchool, filterSettings );
+ else
+ if ( extraSpellSchool ) then
+ abilityColor = CombatLog_Color_ColorArrayBySchool( SCHOOL_MASK_HOLY, filterSettings );
+ else
+ abilityColor = CombatLog_Color_ColorArrayBySchool( nil, filterSettings );
+ end
+ end
+ end
+ -- Highlight this color
+ if ( settings.abilityHighlighting ) then
+ local colorArray;
+ if ( not abilityColor ) then
+ colorArray = lineColor;
+ else
+ colorArray = abilityColor;
+ end
+ abilityColor = CombatLog_Color_HighlightColorArray (colorArray);
+ end
+ if ( abilityColor ) then
+ abilityColor = CombatLog_Color_FloatToText(abilityColor);
+ extraSpellNameStr = format("|c%s%s|r", abilityColor, extraSpellName);
+ end
+ end
+
+ -- Whole line highlighting
+ if ( settings.lineHighlighting ) then
+ if ( filterSettings.colors.highlightedEvents[event] ) then
+ lineColor = CombatLog_Color_HighlightColorArray (lineColor);
+ end
+ end
+
+ -- Build braces
+ if ( settings.braces ) then
+ -- Unit specific braces
+ if ( settings.unitBraces ) then
+ if ( sourceName and settings.sourceBraces ) then
+ sourceNameStr = format(TEXT_MODE_A_STRING_BRACE_UNIT, braceColor, sourceNameStr, braceColor);
+ end
+
+ if ( destName and settings.destBraces ) then
+ destNameStr = format(TEXT_MODE_A_STRING_BRACE_UNIT, braceColor, destNameStr, braceColor);
+ end
+ end
+
+ -- Spell name braces
+ if ( spellName and settings.spellBraces ) then
+ if ( not itemId ) then
+ spellNameStr = format(TEXT_MODE_A_STRING_BRACE_SPELL, braceColor, spellNameStr, braceColor);
+ end
+ end
+ if ( extraSpellName and settings.spellBraces ) then
+ extraSpellNameStr = format(TEXT_MODE_A_STRING_BRACE_SPELL, braceColor, extraSpellNameStr, braceColor);
+ end
+
+ -- Build item braces
+ if ( itemName and settings.itemBraces ) then
+ itemNameStr = format(TEXT_MODE_A_STRING_BRACE_ITEM, braceColor, itemNameStr, braceColor);
+ end
+ end
+
+ local sourceString = "";
+ local spellString = "";
+ local actionString = "";
+ local destString = "";
+ local valueString = "";
+ local resultString = "";
+
+ if ( sourceEnabled and sourceName and falseSource ) then
+ sourceString = sourceName;
+ elseif ( sourceEnabled and sourceName ) then
+ sourceString = format(TEXT_MODE_A_STRING_SOURCE_UNIT, sourceIcon, sourceGUID, sourceName, sourceNameStr);
+ end
+
+ if ( spellName ) then
+ if ( nameIsNotSpell ) then
+ spellString = format(TEXT_MODE_A_STRING_ACTION, originalEvent, spellNameStr);
+ else
+ spellString = format(TEXT_MODE_A_STRING_SPELL, spellId, originalEvent, spellNameStr, spellId);
+ end
+ end
+
+ if ( actionString ) then
+ actionString = format(TEXT_MODE_A_STRING_ACTION, originalEvent, actionStr);
+ end
+
+ if ( destEnabled and destName ) then
+ destString = format(TEXT_MODE_A_STRING_DEST_UNIT, destIcon, destGUID, destName, destNameStr);
+ end
+
+ if ( valueEnabled ) then
+ if ( extraSpellEnabled and extraSpellNameStr ) then
+ if ( extraNameIsNotSpell ) then
+ valueString = extraSpellNameStr;
+ else
+ valueString = format(TEXT_MODE_A_STRING_SPELL_EXTRA, extraSpellId, originalEvent, extraSpellNameStr, spellId);
+ end
+ elseif ( valueIsItem and itemNameStr ) then
+ valueString = format(TEXT_MODE_A_STRING_ITEM, itemId, itemNameStr);
+ elseif ( amount ) then
+ if ( valueTypeEnabled ) then
+ if ( valueType == 1 and schoolString ) then
+ valueString = format(TEXT_MODE_A_STRING_VALUE_SCHOOL, amount, schoolString);
+ elseif ( valueType == 2 and powerTypeString ) then
+ valueString = format(TEXT_MODE_A_STRING_VALUE_TYPE, amount, powerTypeString);
+ end
+ end
+ if ( valueString == "" ) then
+ valueString = amount;
+ end
+ end
+ end
+
+ if ( resultEnabled and resultStr ) then
+ resultString = resultStr;
+ end
+
+ if ( not schoolString ) then
+ schoolString = "";
+ end
+ if ( not powerTypeString ) then
+ powerTypeString = "";
+ end
+ if ( not amount ) then
+ amount = "";
+ end
+
+ if ( sourceString == "" ) then
+ sourceString = UNKNOWN;
+ end
+
+ if ( destEnabled and destString == "" ) then
+ destString = UNKNOWN;
+ end
+
+ local finalString = format(formatString, sourceString, spellString, actionString, destString, valueString, resultString, schoolString, powerTypeString, amount, extraAmount);
+
+ finalString = gsub(finalString, " [ ]+", " " ); -- extra white spaces
+ finalString = gsub(finalString, " ([.,])", "%1" ); -- spaces before periods or comma
+ finalString = gsub(finalString, "^([ .,]+)", "" ); -- spaces, period or comma at the beginning of a line
+
+ if ( timestampEnabled and timestamp ) then
+ -- Replace the timestamp
+ finalString = format(TEXT_MODE_A_STRING_TIMESTAMP, date(settings.timestampFormat, timestamp), finalString);
+ end
+
+ -- NOTE: be sure to pass back nil for the color id or the color id may override the r, g, b values for this message line
+ return finalString, lineColor.r, lineColor.g, lineColor.b;
+end
+_G.CombatLog_OnEvent = CombatLog_OnEvent
+
+-- Process the event and add it to the combat log
+function CombatLog_AddEvent(...)
+ if ( DEBUG == true ) then
+ local info = ChatTypeInfo["COMBAT_MISC_INFO"];
+ local timestamp, event, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags = ...
+ local message = format("%s, %s, %s, 0x%x, %s, %s, 0x%x",
+ --date("%H:%M:%S", timestamp),
+ event,
+ srcGUID, srcName or "nil", srcFlags,
+ dstGUID, dstName or "nil", dstFlags);
+
+ for i = 9, select("#", ...) do
+ message = message..", "..(select(i, ...) or "nil");
+ end
+ ChatFrame1:AddMessage(message, info.r, info.g, info.b);
+ end
+ -- Add the messages
+ COMBATLOG:AddMessage(CombatLog_OnEvent(Blizzard_CombatLog_CurrentSettings, ... ));
+end
+
+--
+-- Overrides for the combat log
+--
+-- Save the original event handler
+local original_OnEvent = COMBATLOG:GetScript("OnEvent");
+COMBATLOG:SetScript("OnEvent",
+
+function(self, event, ...)
+ if ( event == "COMBAT_LOG_EVENT" ) then
+ CombatLog_AddEvent(...);
+ return;
+ elseif ( event == "COMBAT_LOG_EVENT_UNFILTERED") then
+ --[[
+ local timestamp, event, srcGUID, srcName, srcFlags, dstGUID, dstName, dstFlags = select(1, ...);
+ local message = string.format("%s, %s, %s, 0x%x, %s, %s, 0x%x",
+ --date("%H:%M:%S", timestamp),
+ event,
+ srcGUID, srcName or "nil", srcFlags,
+ dstGUID, dstName or "nil", dstFlags);
+
+ for i = 9, select("#", ...) do
+ message = message..", "..(select(i, ...) or "nil");
+ end
+ ChatFrame1:AddMessage(message);
+ --COMBATLOG:AddMessage(message);
+ ]]
+ return;
+ else
+ original_OnEvent(self, event, ...);
+ end
+ end
+);
+COMBATLOG:RegisterEvent("COMBAT_LOG_EVENT");
+--COMBATLOG:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED");
+
+--[[
+_G[COMBATLOG:GetName().."Tab"]:SetScript("OnDragStart",
+ function(self, event, ...)
+ local chatFrame = _G["ChatFrame"..this:GetID()];
+ if ( chatFrame == DEFAULT_CHAT_FRAME ) then
+ if (chatFrame.isLocked) then
+ return;
+ end
+ chatFrame:StartMoving();
+ MOVING_CHATFRAME = chatFrame;
+ return;
+ elseif ( chatFrame.isDocked ) then
+ FCF_UnDockFrame(chatFrame);
+ FCF_SetLocked(chatFrame, nil);
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ local x,y = chatTab:GetCenter();
+ if ( x and y ) then
+ x = x - (chatTab:GetWidth()/2);
+ y = y - (chatTab:GetHeight()/2);
+ chatTab:ClearAllPoints();
+ chatFrame:ClearAllPoints();
+ chatFrame:SetPoint("TOPLEFT", "UIParent", "BOTTOMLEFT", x, y - CombatLogQuickButtonFrame:GetHeight());
+ end
+ FCF_SetTabPosition(chatFrame, 0);
+ chatFrame:StartMoving();
+ MOVING_CHATFRAME = chatFrame;
+ end
+ SELECTED_CHAT_FRAME = chatFrame;
+ end
+);
+]]--
+
+--
+-- XML Function Overrides Part 2
+--
+
+--
+-- Attach the Combat Log Button Frame to the Combat Log
+--
+
+-- On Event
+function Blizzard_CombatLog_QuickButtonFrame_OnEvent(self, event, ...)
+ local arg1 = ...;
+ if ( event == "ADDON_LOADED" ) then
+ if ( arg1 == "Blizzard_CombatLog" ) then
+ Blizzard_CombatLog_Filters = _G.Blizzard_CombatLog_Filters or Blizzard_CombatLog_Filters
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[1];
+ _G.Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_CurrentSettings;
+
+ Blizzard_CombatLog_QuickButton_OnClick( Blizzard_CombatLog_Filters.currentFilter );
+ Blizzard_CombatLog_Refilter();
+ for k,v in pairs (Blizzard_CombatLog_UnitTokens) do
+ Blizzard_CombatLog_UnitTokens[k] = nil;
+ end
+ Blizzard_CombatLog_Update_QuickButtons();
+ --Hide the quick button frame if chatframe1 is selected and the combat log is docked
+ if ( COMBATLOG.isDocked and SELECTED_CHAT_FRAME == ChatFrame1 ) then
+ self:Hide();
+ end
+ end
+ end
+end
+
+
+-- BUG: Since we're futzing with the frame height, the combat log tab fades out on hover while other tabs remain faded in. This bug is in the stock version, as well.
+
+local function Blizzard_CombatLog_AdjustCombatLogHeight()
+ -- This prevents improper positioning of the frame due to the scale not yet being set.
+ -- This whole method of resizing the frame and extending the background to preserve visual continuity really screws with repositioning after
+ -- a reload. I'm not sure it's going to work well in the long run.
+ local uiScale = tonumber(GetCVar("uiScale"));
+ --if UIParent:GetScale() ~= uiScale then return end
+
+ local quickButtonHeight = CombatLogQuickButtonFrame:GetHeight();
+
+ if ( COMBATLOG.isDocked ) then
+ local oldPoint,relativeTo,relativePoint,xOfs,yOfs;
+ for i=1, COMBATLOG:GetNumPoints() do
+ oldPoint,relativeTo,relativePoint,xOfs,yOfs = COMBATLOG:GetPoint(i);
+ if ( oldPoint == "TOPLEFT" ) then
+ break;
+ end
+ end
+ COMBATLOG:SetPoint("TOPLEFT", relativeTo, relativePoint, xOfs/uiScale, -quickButtonHeight);
+ end
+
+ local yOffset = (3 + quickButtonHeight*uiScale) / uiScale;
+ local xOffset = 2 / uiScale;
+ local combatLogBackground = _G[COMBATLOG:GetName().."Background"];
+ combatLogBackground:SetPoint("TOPLEFT", COMBATLOG, "TOPLEFT", -xOffset, yOffset);
+ combatLogBackground:SetPoint("TOPRIGHT", COMBATLOG, "TOPRIGHT", xOffset, yOffset);
+end
+
+-- On Load
+local hooksSet = false
+function Blizzard_CombatLog_QuickButtonFrame_OnLoad(self)
+ self:RegisterEvent("ADDON_LOADED");
+
+ -- We're using the _Custom suffix to get around the show/hide bug in FloatingChatFrame.lua.
+ -- Once the fading is removed from FloatingChatFrame.lua these can do back to the non-custom values, and the dummy frame creation should be removed.
+ CombatLogQuickButtonFrame = _G.CombatLogQuickButtonFrame_Custom
+ CombatLogQuickButtonFrameProgressBar = _G.CombatLogQuickButtonFrame_CustomProgressBar
+ CombatLogQuickButtonFrameTexture = _G.CombatLogQuickButtonFrame_CustomTexture
+
+ -- Parent it to the tab so that we just inherit the tab's alpha. No need to do special fading for it.
+ CombatLogQuickButtonFrame:SetParent(COMBATLOG:GetName() .. "Tab");
+ CombatLogQuickButtonFrame:ClearAllPoints();
+ CombatLogQuickButtonFrame:SetPoint("BOTTOMLEFT", COMBATLOG, "TOPLEFT");
+ CombatLogQuickButtonFrame:SetPoint("BOTTOMRIGHT", COMBATLOG, "TOPRIGHT");
+ CombatLogQuickButtonFrameProgressBar:Hide();
+
+ -- Hook the frame's hide/show events so we can hide/show the quick buttons as appropriate.
+ local show, hide = COMBATLOG:GetScript("OnShow"), COMBATLOG:GetScript("OnHide")
+ COMBATLOG:SetScript("OnShow", function(self)
+ CombatLogQuickButtonFrame_Custom:Show()
+ --Blizzard_CombatLog_AdjustCombatLogHeight()
+ COMBATLOG:RegisterEvent("COMBAT_LOG_EVENT");
+ -- select a filter for the user only the first time it's shown
+ if ( not self.loaded ) then
+ Blizzard_CombatLog_QuickButton_OnClick(Blizzard_CombatLog_Filters.currentFilter);
+ self.loaded = true;
+ end
+ return show and show(self)
+ end)
+ COMBATLOG:SetScript("OnHide", function(self)
+ CombatLogQuickButtonFrame_Custom:Hide()
+ -- Blizzard_CombatLog_AdjustCombatLogHeight()
+ COMBATLOG:UnregisterEvent("COMBAT_LOG_EVENT");
+ return hide and hide(self)
+ end)
+
+ FCF_SetButtonSide(COMBATLOG, COMBATLOG.buttonSide, true);
+end
+
+local oldFCF_DockUpdate = FCF_DockUpdate;
+FCF_DockUpdate = function()
+ oldFCF_DockUpdate();
+ Blizzard_CombatLog_AdjustCombatLogHeight();
+end
+
+--
+-- Combat Log Global Functions
+--
+
+--[[
+--
+-- Returns the correct {} code for the combat log bit
+--
+-- args:
+-- bit - a bit exactly equal to a raid target icon.
+--]]
+local function Blizzard_CombatLog_BitToBraceCode(bit)
+ if ( bit == COMBATLOG_OBJECT_RAIDTARGET1 ) then
+ return "{"..strlower(RAID_TARGET_1).."}";
+ elseif ( bit == COMBATLOG_OBJECT_RAIDTARGET2 ) then
+ return "{"..strlower(RAID_TARGET_2).."}";
+ elseif ( bit == COMBATLOG_OBJECT_RAIDTARGET3 ) then
+ return "{"..strlower(RAID_TARGET_3).."}";
+ elseif ( bit == COMBATLOG_OBJECT_RAIDTARGET4 ) then
+ return "{"..strlower(RAID_TARGET_4).."}";
+ elseif ( bit == COMBATLOG_OBJECT_RAIDTARGET5 ) then
+ return "{"..strlower(RAID_TARGET_5).."}";
+ elseif ( bit == COMBATLOG_OBJECT_RAIDTARGET6 ) then
+ return "{"..strlower(RAID_TARGET_6).."}";
+ elseif ( bit == COMBATLOG_OBJECT_RAIDTARGET7 ) then
+ return "{"..strlower(RAID_TARGET_7).."}";
+ elseif ( bit == COMBATLOG_OBJECT_RAIDTARGET8 ) then
+ return "{"..strlower(RAID_TARGET_8).."}";
+ end
+ return "";
+end
+
+-- Override Hyperlink Handlers
+-- The SetItemRef() function hook is to be moved out into the core FrameXML.
+-- It is currently in the Constants.lua stub file to simulate being moved out to the core.
+--
+-- The reason is because Blizzard_CombatLog is a LoD addon and can be replaced by the user
+-- If the functionality of these new unit/icon/spell/action links is not in the core FrameXML
+-- file in ItemRef.lua, then every combat log addon that replaces Blizzard_CombatLog must
+-- provide the same functionality.
+-- Players may also get all sorts of errors on trying to click on these new linktypes before
+-- Blizzard_CombatLog gets loaded.
+
+-- Override Hyperlink Handlers
+-- This entire function hook should/must be directly integrated into ItemRef.lua
+-- The reason is because Blizzard_CombatLog is a LoD addon and can be replaced by the user
+-- If the functionality of these new unit/icon/spell/action links is not in the core FrameXML
+-- file in ItemRef.lua, then every combat log addon that replaces Blizzard_CombatLog must
+-- provide the same functionality.
+-- Players may also get all sorts of errors on trying to click on these new linktypes before
+-- Blizzard_CombatLog gets loaded.
+local oldSetItemRef = SetItemRef;
+function SetItemRef(link, text, button, chatFrame)
+
+ if ( strsub(link, 1, 4) == "unit") then
+ local _, guid, name = strsplit(":", link);
+
+ if ( IsModifiedClick("CHATLINK") ) then
+ ChatEdit_InsertLink (name);
+ return;
+ elseif( button == "RightButton") then
+ -- Show Popup Menu
+ EasyMenu(Blizzard_CombatLog_CreateUnitMenu(name, guid), CombatLogDropDown, "cursor", nil, nil, "MENU");
+ return;
+ end
+ elseif ( strsub(link, 1, 4) == "icon") then
+ local _, bit, direction = strsplit(":", link);
+ local texture = string.gsub(text,".*|h(.*)|h.*","%1");
+ -- Show Popup Menu
+ if( button == "RightButton") then
+ -- need to fix this to be actual texture
+ EasyMenu(Blizzard_CombatLog_CreateUnitMenu(Blizzard_CombatLog_BitToBraceCode(tonumber(bit)), nil, tonumber(bit)), CombatLogDropDown, "cursor", nil, nil, "MENU");
+ elseif ( IsModifiedClick("CHATLINK") ) then
+ ChatEdit_InsertLink (Blizzard_CombatLog_BitToBraceCode(tonumber(bit)));
+ end
+ return;
+ elseif ( strsub(link, 1,5) == "spell" ) then
+ local _, spellId, event = strsplit(":", link);
+ spellId = tonumber (spellId);
+
+ if ( IsModifiedClick("CHATLINK") ) then
+ if ( spellId > 0 ) then
+ if ( ChatEdit_InsertLink(GetSpellLink(spellId)) ) then
+ return;
+ end
+ else
+ return;
+ end
+ -- Show Popup Menu
+ elseif( button == "RightButton" and event ) then
+ EasyMenu(Blizzard_CombatLog_CreateSpellMenu(text, spellId, event), CombatLogDropDown, "cursor", nil, nil, "MENU");
+ return;
+ end
+ elseif ( strsub(link, 1,6) == "action" ) then
+ local _, event = strsplit(":", link);
+
+ -- Show Popup Menu
+ if( button == "RightButton") then
+ EasyMenu(Blizzard_CombatLog_CreateActionMenu(event), CombatLogDropDown, "cursor", nil, nil, "MENU");
+ end
+ return;
+ elseif ( strsub(link, 1, 4) == "item") then
+ if ( IsModifiedClick("CHATLINK") ) then
+ local name, link = GetItemInfo(text);
+ ChatEdit_InsertLink (link);
+ return;
+ end
+ end
+ oldSetItemRef(link, text, button, chatFrame);
+end
+
+function Blizzard_CombatLog_Update_QuickButtons()
+ local baseName = "CombatLogQuickButtonFrame";
+ local buttonName, button, textWidth;
+ local buttonIndex = 1;
+ -- subtract the width of the dropdown button
+ local clogleft, clogright = COMBATLOG:GetRight(), COMBATLOG:GetLeft();
+ local maxWidth;
+ if ( clogleft and clogright ) then
+ maxWidth = (COMBATLOG:GetRight()-COMBATLOG:GetLeft())-31; --Hacky hacky because GetWidth goes crazy when it is docked
+ else
+ maxWidth = COMBATLOG:GetWidth() - 31;
+ end
+
+ local totalWidth = 0;
+ local padding = 13;
+ local showMoreQuickButtons = true;
+ for index, filter in ipairs(_G.Blizzard_CombatLog_Filters.filters) do
+ buttonName = baseName.."Button"..buttonIndex;
+ button = _G[buttonName];
+ if ( ShowQuickButton(filter) and showMoreQuickButtons ) then
+ if ( not button ) then
+ button = CreateFrame("BUTTON", buttonName, CombatLogQuickButtonFrame, "CombatLogQuickButtonTemplate");
+ end
+ button:SetText(filter.name);
+ textWidth = button:GetTextWidth();
+ totalWidth = totalWidth + textWidth + padding;
+ if ( totalWidth <= maxWidth ) then
+ button:SetWidth(textWidth+padding);
+ button:SetID(index);
+ button:Show();
+ button.tooltip = filter.tooltip;
+ if ( buttonIndex > 1 ) then
+ button:SetPoint("LEFT", _G[baseName.."Button"..buttonIndex-1], "RIGHT", 3, 0);
+ else
+ button:SetPoint("LEFT", CombatLogQuickButtonFrame, "LEFT", 3, 0);
+ end
+ if ( Blizzard_CombatLog_Filters.currentFilter == index and (Blizzard_CombatLog_CurrentSettings and not Blizzard_CombatLog_CurrentSettings.isTemp) ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+ filter.onQuickBar = true;
+ else
+ -- Don't show anymore buttons if the maxwidth has been exceeded
+ showMoreQuickButtons = false;
+ button:Hide();
+ filter.onQuickBar = false;
+ end
+ buttonIndex = buttonIndex + 1;
+ else
+ filter.onQuickBar = false;
+ if ( button ) then
+ button:Hide();
+ end
+ end
+ end
+
+ -- Hide remaining buttons
+ repeat
+ button = _G[baseName.."Button"..buttonIndex];
+ if ( button ) then
+ button:Hide();
+ end
+ buttonIndex = buttonIndex+1;
+ until not button;
+end
+_G.Blizzard_CombatLog_Update_QuickButtons = Blizzard_CombatLog_Update_QuickButtons
+
+function Blizzard_CombatLog_QuickButton_OnClick(id)
+ Blizzard_CombatLog_Filters.currentFilter = id;
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[Blizzard_CombatLog_Filters.currentFilter];
+ Blizzard_CombatLog_ApplyFilters(Blizzard_CombatLog_CurrentSettings);
+ if ( Blizzard_CombatLog_CurrentSettings.settings.showHistory ) then
+ Blizzard_CombatLog_Refilter();
+ end
+ Blizzard_CombatLog_Update_QuickButtons();
+ PlaySound("UChatScrollButton");
+end
+
+function ShowQuickButton(filter)
+ if ( filter.hasQuickButton ) then
+ if ( GetNumRaidMembers() > 0 ) then
+ return filter.quickButtonDisplay.raid;
+ elseif ( GetNumPartyMembers() > 0 ) then
+ return filter.quickButtonDisplay.party;
+ else
+ return filter.quickButtonDisplay.solo;
+ end
+ else
+ return false;
+ end;
+end
+
+function Blizzard_CombatLog_RefreshGlobalLinks()
+ -- Have to do this because Blizzard_CombatLog_Filters is a reference to the _G.Blizzard_CombatLog_Filters
+ Blizzard_CombatLog_Filters = _G.Blizzard_CombatLog_Filters;
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[Blizzard_CombatLog_Filters.currentFilter];
+ _G.Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_CurrentSettings;
+end
diff --git a/reference/AddOns/Blizzard_CombatLog/Blizzard_CombatLog.toc b/reference/AddOns/Blizzard_CombatLog/Blizzard_CombatLog.toc
new file mode 100644
index 0000000..2e813d8
--- /dev/null
+++ b/reference/AddOns/Blizzard_CombatLog/Blizzard_CombatLog.toc
@@ -0,0 +1,7 @@
+## Interface: 30300
+## Title: Blizzard CombatLog
+## Secure: 1
+## LoadOnDemand: 1
+## SavedVariables: Blizzard_CombatLog_Filters, Blizzard_CombatLog_Filter_Version
+Blizzard_CombatLog.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_CombatLog/Blizzard_CombatLog.xml b/reference/AddOns/Blizzard_CombatLog/Blizzard_CombatLog.xml
new file mode 100644
index 0000000..9174d64
--- /dev/null
+++ b/reference/AddOns/Blizzard_CombatLog/Blizzard_CombatLog.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+ Blizzard_CombatLog_QuickButton_OnClick(self:GetID());
+
+
+ if (self.tooltip) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip_AddNewbieTip(self, self.tooltip, 1.0, 1.0, 1.0, nil, 1);
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ EasyMenu(Blizzard_CombatLog_CreateFilterMenu(), CombatLogDropDown, "cursor", nil, nil, "MENU");
+ PlaySound("UChatScrollButton");
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip_AddNewbieTip(self, ADDITIONAL_FILTERS, 1.0, 1.0, 1.0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_CombatLog/Localization.lua b/reference/AddOns/Blizzard_CombatLog/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_CombatLog/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_CombatText/Blizzard_CombatText.lua b/reference/AddOns/Blizzard_CombatText/Blizzard_CombatText.lua
new file mode 100644
index 0000000..62dec6f
--- /dev/null
+++ b/reference/AddOns/Blizzard_CombatText/Blizzard_CombatText.lua
@@ -0,0 +1,610 @@
+NUM_COMBAT_TEXT_LINES = 20;
+COMBAT_TEXT_SCROLLSPEED = 1.9;
+COMBAT_TEXT_FADEOUT_TIME = 1.3;
+COMBAT_TEXT_HEIGHT = 25;
+COMBAT_TEXT_CRIT_MAXHEIGHT = 60;
+COMBAT_TEXT_CRIT_MINHEIGHT = 30;
+COMBAT_TEXT_CRIT_SCALE_TIME = 0.05;
+COMBAT_TEXT_CRIT_SHRINKTIME = 0.2;
+COMBAT_TEXT_TO_ANIMATE = {};
+COMBAT_TEXT_STAGGER_RANGE = 20;
+COMBAT_TEXT_SPACING = 10;
+COMBAT_TEXT_MAX_OFFSET = 130;
+COMBAT_TEXT_LOW_HEALTH_THRESHOLD = 0.2;
+COMBAT_TEXT_LOW_MANA_THRESHOLD = 0.2;
+COMBAT_TEXT_LOCATIONS = {};
+COMBAT_TEXT_X_ADJUSTMENT = 80;
+COMBAT_TEXT_Y_SCALE = 1;
+COMBAT_TEXT_X_SCALE = 1;
+
+--[[
+List of COMBAT_TEXT_TYPE_INFO attributes
+======================================================
+r, g, b = [floats] -- The floating text color
+show = [nil, 1] -- Display this message type in the UI
+isStaggered = [nil, 1] -- Randomly stagger these messages from left to right
+var = [nil, 1] -- This messageType is shown if this variable resolves to "1"
+]]
+
+COMBAT_TEXT_TYPE_INFO = {};
+COMBAT_TEXT_TYPE_INFO["INTERRUPT"] = {r = 1, g = 1, b = 1};
+COMBAT_TEXT_TYPE_INFO["DAMAGE_CRIT"] = {r = 1, g = 0.1, b = 0.1, show = 1};
+COMBAT_TEXT_TYPE_INFO["DAMAGE"] = {r = 1, g = 0.1, b = 0.1, isStaggered = 1, show = 1};
+COMBAT_TEXT_TYPE_INFO["MISS"] = {r = 1, g = 0.1, b = 0.1, isStaggered = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["DODGE"] = {r = 1, g = 0.1, b = 0.1, isStaggered = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["PARRY"] = {r = 1, g = 0.1, b = 0.1, isStaggered = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["EVADE"] = {r = 1, g = 0.1, b = 0.1, isStaggered = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["IMMUNE"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["DEFLECT"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["REFLECT"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["RESIST"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_RESISTANCES"};
+COMBAT_TEXT_TYPE_INFO["BLOCK"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_RESISTANCES"};
+COMBAT_TEXT_TYPE_INFO["ABSORB"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_RESISTANCES"};
+COMBAT_TEXT_TYPE_INFO["SPELL_DAMAGE_CRIT"] = {r = 0.79, g = 0.3, b = 0.85, show = 1};
+COMBAT_TEXT_TYPE_INFO["SPELL_DAMAGE"] = {r = 0.79, g = 0.3, b = 0.85, show = 1};
+COMBAT_TEXT_TYPE_INFO["SPELL_MISS"] = {r = 1, g = 1, b = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_DODGE"] = {r = 1, g = 1, b = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_PARRY"] = {r = 1, g = 1, b = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_EVADE"] = {r = 1, g = 1, b = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_IMMUNE"] = {r = 1, g = 1, b = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_DEFLECT"] = {r = 1, g = 1, b = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_REFLECT"] = {r = 1, g = 1, b = 1, var = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_RESIST"] = {r = 0.79, g = 0.3, b = 0.85, var = "COMBAT_TEXT_SHOW_RESISTANCES"};
+COMBAT_TEXT_TYPE_INFO["SPELL_BLOCK"] = {r = 1, g = 1, b = 1, var = "COMBAT_TEXT_SHOW_RESISTANCES"};
+COMBAT_TEXT_TYPE_INFO["SPELL_ABSORB"] = {r = 0.79, g = 0.3, b = 0.85, var = "COMBAT_TEXT_SHOW_RESISTANCES"};
+COMBAT_TEXT_TYPE_INFO["PERIODIC_HEAL"] = {r = 0.1, g = 1, b = 0.1, show = 1};
+COMBAT_TEXT_TYPE_INFO["ENERGIZE"] = {r = 0.1, g = 0.1, b = 1, var = "COMBAT_TEXT_SHOW_ENERGIZE"};
+COMBAT_TEXT_TYPE_INFO["PERIODIC_ENERGIZE"] = {r = 0.1, g = 0.1, b = 1, var = "COMBAT_TEXT_SHOW_PERIODIC_ENERGIZE"};
+COMBAT_TEXT_TYPE_INFO["SPELL_CAST"] = {r = 0.1, g = 1, b = 0.1, show = 1};
+COMBAT_TEXT_TYPE_INFO["SPELL_AURA_END"] = {r = 0.1, g = 1, b = 0.1, var = "COMBAT_TEXT_SHOW_AURAS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_AURA_END_HARMFUL"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_AURAS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_AURA_START"] = {r = 0.1, g = 1, b = 0.1, var = "COMBAT_TEXT_SHOW_AURAS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_AURA_START_HARMFUL"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_AURAS"};
+COMBAT_TEXT_TYPE_INFO["SPELL_ACTIVE"] = {r = 1, g = 0.82, b = 0, var = "COMBAT_TEXT_SHOW_REACTIVES"};
+COMBAT_TEXT_TYPE_INFO["FACTION"] = {r = 0.1, g = 0.1, b = 1, var = "COMBAT_TEXT_SHOW_REPUTATION"};
+COMBAT_TEXT_TYPE_INFO["HEAL_CRIT"] = {r = 0.1, g = 1, b = 0.1, show = 1};
+COMBAT_TEXT_TYPE_INFO["HEAL"] = {r = 0.1, g = 1, b = 0.1, show = 1};
+COMBAT_TEXT_TYPE_INFO["DAMAGE_SHIELD"] = {r = 1, g = 1, b = 1};
+COMBAT_TEXT_TYPE_INFO["SPELL_DISPELLED"] = {r = 1, g = 1, b = 1};
+COMBAT_TEXT_TYPE_INFO["EXTRA_ATTACKS"] = {r = 1, g = 1, b = 1};
+COMBAT_TEXT_TYPE_INFO["SPLIT_DAMAGE"] = {r = 1, g = 1, b = 1, show = 1};
+COMBAT_TEXT_TYPE_INFO["HONOR_GAINED"] = {r = 0.1, g = 0.1, b = 1, var = "COMBAT_TEXT_SHOW_HONOR_GAINED"};
+COMBAT_TEXT_TYPE_INFO["HEALTH_LOW"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_LOW_HEALTH_MANA"};
+COMBAT_TEXT_TYPE_INFO["MANA_LOW"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_LOW_HEALTH_MANA"};
+COMBAT_TEXT_TYPE_INFO["ENTERING_COMBAT"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_COMBAT_STATE"};
+COMBAT_TEXT_TYPE_INFO["LEAVING_COMBAT"] = {r = 1, g = 0.1, b = 0.1, var = "COMBAT_TEXT_SHOW_COMBAT_STATE"};
+COMBAT_TEXT_TYPE_INFO["COMBO_POINTS"] = {r = 0.1, g = 0.1, b = 1, var = "COMBAT_TEXT_SHOW_COMBO_POINTS"};
+COMBAT_TEXT_TYPE_INFO["RUNE"] = {r = 0.1, g = 0.1, b = 1, var = "COMBAT_TEXT_SHOW_ENERGIZE"};
+COMBAT_TEXT_TYPE_INFO["PERIODIC_HEAL_ABSORB"] = {r = 0.1, g = 1, b = 0.1, show = 1};
+COMBAT_TEXT_TYPE_INFO["HEAL_CRIT_ABSORB"] = {r = 0.1, g = 1, b = 0.1, show = 1};
+COMBAT_TEXT_TYPE_INFO["HEAL_ABSORB"] = {r = 0.1, g = 1, b = 0.1, show = 1};
+
+COMBAT_TEXT_RUNE = {};
+COMBAT_TEXT_RUNE[1] = COMBAT_TEXT_RUNE_BLOOD;
+COMBAT_TEXT_RUNE[2] = COMBAT_TEXT_RUNE_UNHOLY;
+COMBAT_TEXT_RUNE[3] = COMBAT_TEXT_RUNE_FROST;
+
+function CombatText_OnLoad(self)
+ CombatText_UpdateDisplayedMessages();
+ CombatText.previousMana = {};
+ CombatText.xDir = 1;
+end
+
+function CombatText_OnEvent(self, event, ...)
+ if ( not self:IsVisible() ) then
+ CombatText_ClearAnimationList();
+ return;
+ end
+
+ local arg1, data, arg3 = ...;
+
+ -- Set up the messageType
+ local messageType, message;
+ -- Set the message data
+ local displayType;
+
+ if ( event == "UNIT_ENTERED_VEHICLE" ) then
+ local unit, showVehicle = ...;
+ if ( unit == "player" ) then
+ if ( showVehicle ) then
+ self.unit = "vehicle";
+ else
+ self.unit = "player";
+ end
+ CombatTextSetActiveUnit(self.unit);
+ end
+ return;
+ elseif ( event == "UNIT_EXITING_VEHICLE" ) then
+ if ( arg1 == "player" ) then
+ self.unit = "player";
+ CombatTextSetActiveUnit(self.unit);
+ end
+ return;
+ elseif ( event == "UNIT_HEALTH" ) then
+ if ( arg1 == self.unit ) then
+ if ( UnitHealth(self.unit)/UnitHealthMax(self.unit) <= COMBAT_TEXT_LOW_HEALTH_THRESHOLD ) then
+ if ( not CombatText.lowHealth ) then
+ messageType = "HEALTH_LOW";
+ CombatText.lowHealth = 1;
+ end
+ else
+ CombatText.lowHealth = nil;
+ end
+ end
+
+ -- Didn't meet any of the criteria so just return
+ if ( not messageType ) then
+ return;
+ end
+ elseif ( event == "UNIT_MANA" ) then
+ if ( arg1 == self.unit ) then
+ local powerType, powerToken = UnitPowerType(self.unit);
+ if ( powerToken == "MANA" and (UnitPower(self.unit) / UnitPowerMax(self.unit)) <= COMBAT_TEXT_LOW_MANA_THRESHOLD ) then
+ if ( not CombatText.lowMana ) then
+ messageType = "MANA_LOW";
+ CombatText.lowMana = 1;
+ end
+ else
+ CombatText.lowMana = nil;
+ end
+ end
+
+ -- Didn't meet any of the criteria so just return
+ if ( not messageType ) then
+ return;
+ end
+ elseif ( event == "PLAYER_REGEN_DISABLED" ) then
+ messageType = "ENTERING_COMBAT";
+ elseif ( event == "PLAYER_REGEN_ENABLED" ) then
+ messageType = "LEAVING_COMBAT";
+ elseif ( event == "UNIT_COMBO_POINTS" ) then
+ local unit = ...;
+ if ( unit == "player" ) then
+ local comboPoints = GetComboPoints("player", "target");
+ if ( comboPoints > 0 ) then
+ messageType = "COMBO_POINTS";
+ data = comboPoints;
+ -- Show message as a crit if max combo points
+ if ( comboPoints == MAX_COMBO_POINTS ) then
+ displayType = "crit";
+ end
+ else
+ return;
+ end
+ else
+ return;
+ end
+ elseif ( event == "COMBAT_TEXT_UPDATE" ) then
+ messageType = arg1;
+ elseif ( event == "RUNE_POWER_UPDATE" ) then
+ messageType = "RUNE";
+ else
+ messageType = event;
+ end
+
+ -- Process the messageType and format the message
+ --Check to see if there's a COMBAT_TEXT_TYPE_INFO associated with this combat message
+ local info = COMBAT_TEXT_TYPE_INFO[messageType];
+ if ( not info ) then
+ info = {r = 1, g =1, b = 1};
+ end
+ -- See if we should display the message or not
+ if ( not info.show ) then
+ -- When Resists aren't being shown, partial resists should display as Damage
+ if (info.var == "COMBAT_TEXT_SHOW_RESISTANCES" and arg3) then
+ messageType = "DAMAGE";
+ else
+ return;
+ end
+ end
+
+ local isStaggered = info.isStaggered;
+ if ( messageType == "" ) then
+
+ elseif ( messageType == "DAMAGE_CRIT" or messageType == "SPELL_DAMAGE_CRIT" ) then
+ displayType = "crit";
+ message = "-"..data;
+ elseif ( messageType == "DAMAGE" or messageType == "SPELL_DAMAGE" ) then
+ if (data == 0) then
+ return
+ end
+ message = "-"..data;
+ elseif ( messageType == "SPELL_CAST" ) then
+ message = "<"..data..">";
+ elseif ( messageType == "SPELL_AURA_START" ) then
+ message = "<"..data..">";
+ elseif ( messageType == "SPELL_AURA_START_HARMFUL" ) then
+ message = "<"..data..">";
+ elseif ( messageType == "SPELL_AURA_END" or messageType == "SPELL_AURA_END_HARMFUL" ) then
+ message = format(AURA_END, data);
+ elseif ( messageType == "HEAL" or messageType == "PERIODIC_HEAL") then
+ if ( COMBAT_TEXT_SHOW_FRIENDLY_NAMES == "1" and messageType == "HEAL" and UnitName(self.unit) ~= data ) then
+ message = "+"..arg3.." ["..data.."]";
+ else
+ message = "+"..arg3;
+ end
+ elseif ( messageType == "HEAL_ABSORB" or messageType == "PERIODIC_HEAL_ABSORB") then
+ if ( COMBAT_TEXT_SHOW_FRIENDLY_NAMES == "1" and messageType == "HEAL_ABSORB" and UnitName(self.unit) ~= data ) then
+ message = "+"..arg3.." ["..data.."] "..format(ABSORB_TRAILER, arg4);
+ else
+ message = "+"..arg3.." "..format(ABSORB_TRAILER, arg4);
+ end
+ elseif ( messageType == "HEAL_CRIT" ) then
+ displayType = "crit";
+ if ( COMBAT_TEXT_SHOW_FRIENDLY_NAMES == "1" and UnitName(self.unit) ~= data ) then
+ message = "+"..arg3.." ["..data.."]";
+ else
+ message = "+"..arg3;
+ end
+ elseif ( messageType == "HEAL_CRIT_ABSORB" ) then
+ displayType = "crit";
+ if ( COMBAT_TEXT_SHOW_FRIENDLY_NAMES == "1" and UnitName(self.unit) ~= data ) then
+ message = "+"..arg3.." ["..data.."] "..format(ABSORB_TRAILER, arg4);
+ else
+ message = "+"..arg3.." "..format(ABSORB_TRAILER, arg4);
+ end
+ elseif ( messageType == "ENERGIZE" or messageType == "PERIODIC_ENERGIZE") then
+ if ( tonumber(data) > 0 ) then
+ data = "+"..data;
+ end
+ if( arg3 == "MANA"
+ or arg3 == "RAGE"
+ or arg3 == "FOCUS"
+ or arg3 == "ENERGY"
+ or arg3 == "RUNIC_POWER") then
+ message = data.." ".._G[arg3];
+ info = PowerBarColor[arg3];
+ end
+ elseif ( messageType == "FACTION" ) then
+ if ( tonumber(arg3) > 0 ) then
+ arg3 = "+"..arg3;
+ end
+ message = "("..data.." "..arg3..")";
+ elseif ( messageType == "SPELL_MISS" ) then
+ message = COMBAT_TEXT_MISS;
+ elseif ( messageType == "SPELL_DODGE" ) then
+ message = COMBAT_TEXT_DODGE;
+ elseif ( messageType == "SPELL_PARRY" ) then
+ message = COMBAT_TEXT_PARRY;
+ elseif ( messageType == "SPELL_EVADE" ) then
+ message = COMBAT_TEXT_EVADE;
+ elseif ( messageType == "SPELL_IMMUNE" ) then
+ message = COMBAT_TEXT_IMMUNE;
+ elseif ( messageType == "SPELL_DEFLECT" ) then
+ message = COMBAT_TEXT_DEFLECT;
+ elseif ( messageType == "SPELL_REFLECT" ) then
+ message = COMBAT_TEXT_REFLECT;
+ elseif ( messageType == "BLOCK" or messageType == "SPELL_BLOCK" ) then
+ if ( arg3 ) then
+ -- Partial block
+ message = "-"..data.." "..format(BLOCK_TRAILER, arg3);
+ else
+ message = COMBAT_TEXT_BLOCK;
+ end
+ elseif ( messageType == "ABSORB" or messageType == "SPELL_ABSORB" ) then
+ if ( arg3 and data > 0 ) then
+ -- Partial absorb
+ message = "-"..data.." "..format(ABSORB_TRAILER, arg3);
+ else
+ message = COMBAT_TEXT_ABSORB;
+ end
+ elseif ( messageType == "RESIST" or messageType == "SPELL_RESIST" ) then
+ if ( arg3 ) then
+ -- Partial resist
+ message = "-"..data.." "..format(RESIST_TRAILER, arg3);
+ else
+ message = COMBAT_TEXT_RESIST;
+ end
+ elseif ( messageType == "HONOR_GAINED" ) then
+ if ( tonumber(data) > 0 ) then
+ data = "+"..data;
+ end
+ message = format(COMBAT_TEXT_HONOR_GAINED, data);
+ elseif ( messageType == "SPELL_ACTIVE" ) then
+ displayType = "crit";
+ message = "<"..data..">";
+ elseif ( messageType == "COMBO_POINTS" ) then
+ message = format(COMBAT_TEXT_COMBO_POINTS, data);
+ elseif ( messageType == "RUNE" ) then
+ if ( data == true ) then
+ local runeType = GetRuneType(arg1);
+ message = COMBAT_TEXT_RUNE[runeType];
+ -- Alex Brazie had me use these values. Feel free to correct them
+ if( runeType == 1 ) then
+ info.r = .75;
+ info.g = 0;
+ info.b = 0;
+ elseif( runeType == 2 ) then
+ info.r = .75;
+ info.g = 1;
+ info.b = 0;
+ elseif (runeType == 3 ) then
+ info.r = 0;
+ info.g = 1;
+ info.b = 1;
+ end
+ else
+ message = nil;
+ end
+ else
+ message = _G["COMBAT_TEXT_"..messageType];
+ if ( not message ) then
+ message = _G[messageType];
+ end
+ end
+
+ -- Add the message
+ if ( message ) then
+ CombatText_AddMessage(message, COMBAT_TEXT_SCROLL_FUNCTION, info.r, info.g, info.b, displayType, isStaggered);
+ end
+end
+
+function CombatText_OnUpdate(self, elapsed)
+ local lowestMessage = COMBAT_TEXT_LOCATIONS.startY;
+ local alpha, xPos, yPos;
+ for index, value in pairs(COMBAT_TEXT_TO_ANIMATE) do
+ if ( value.scrollTime >= COMBAT_TEXT_SCROLLSPEED ) then
+ CombatText_RemoveMessage(value);
+ else
+ value.scrollTime = value.scrollTime + elapsed;
+ -- Calculate x and y positions
+ xPos, yPos = value.scrollFunction(value);
+
+ -- Record Y position
+ value.yPos = yPos;
+
+ value:SetPoint("TOP", WorldFrame, "BOTTOM", xPos, yPos);
+ if ( value.scrollTime >= COMBAT_TEXT_FADEOUT_TIME ) then
+ alpha = 1-((value.scrollTime-COMBAT_TEXT_FADEOUT_TIME)/(COMBAT_TEXT_SCROLLSPEED-COMBAT_TEXT_FADEOUT_TIME));
+ alpha = max(alpha, 0);
+ value:SetAlpha(alpha);
+ end
+
+ -- Handle crit
+ if ( value.isCrit ) then
+ if ( value.scrollTime <= COMBAT_TEXT_CRIT_SCALE_TIME ) then
+ value:SetTextHeight(floor(COMBAT_TEXT_CRIT_MINHEIGHT+((COMBAT_TEXT_CRIT_MAXHEIGHT-COMBAT_TEXT_CRIT_MINHEIGHT)*value.scrollTime/COMBAT_TEXT_CRIT_SCALE_TIME)));
+ elseif ( value.scrollTime <= COMBAT_TEXT_CRIT_SHRINKTIME ) then
+ value:SetTextHeight(floor(COMBAT_TEXT_CRIT_MAXHEIGHT - ((COMBAT_TEXT_CRIT_MAXHEIGHT-COMBAT_TEXT_CRIT_MINHEIGHT)*(value.scrollTime - COMBAT_TEXT_CRIT_SCALE_TIME)/(COMBAT_TEXT_CRIT_SHRINKTIME - COMBAT_TEXT_CRIT_SCALE_TIME))));
+ else
+ value.isCrit = nil;
+ end
+ end
+ end
+ end
+
+ if ( (COMBAT_TEXT_Y_SCALE ~= WorldFrame:GetHeight() / 768) or (COMBAT_TEXT_X_SCALE ~= WorldFrame:GetWidth() / 1024) ) then
+ CombatText_UpdateDisplayedMessages();
+ end
+end
+
+function CombatText_AddMessage(message, scrollFunction, r, g, b, displayType, isStaggered)
+ local string, noStringsAvailable = CombatText_GetAvailableString();
+ if ( noStringsAvailable ) then
+ return;
+ end
+
+ string:SetText(message);
+ string:SetTextColor(r, g, b);
+ string.scrollTime = 0;
+ if ( displayType == "crit" ) then
+ string.scrollFunction = CombatText_StandardScroll;
+ else
+ string.scrollFunction = scrollFunction;
+ end
+
+ -- See which direction the message should flow
+ local yDir;
+ local lowestMessage;
+ local useXadjustment = 0;
+ if ( COMBAT_TEXT_LOCATIONS.startY < COMBAT_TEXT_LOCATIONS.endY ) then
+ -- Flowing up
+ lowestMessage = string:GetBottom();
+ -- Find lowest message to anchor to
+ for index, value in pairs(COMBAT_TEXT_TO_ANIMATE) do
+ if ( lowestMessage >= value.yPos - 16 - COMBAT_TEXT_SPACING) then
+ lowestMessage = value.yPos - 16 - COMBAT_TEXT_SPACING;
+ end
+ end
+ if ( lowestMessage < (COMBAT_TEXT_LOCATIONS.startY - COMBAT_TEXT_MAX_OFFSET) ) then
+ if ( displayType == "crit" ) then
+ lowestMessage = string:GetBottom();
+ else
+ COMBAT_TEXT_X_ADJUSTMENT = COMBAT_TEXT_X_ADJUSTMENT * -1;
+ useXadjustment = 1;
+ lowestMessage = COMBAT_TEXT_LOCATIONS.startY - COMBAT_TEXT_MAX_OFFSET;
+ end
+ end
+ else
+ -- Flowing down
+ lowestMessage = string:GetTop();
+ -- Find lowest message to anchor to
+ for index, value in pairs(COMBAT_TEXT_TO_ANIMATE) do
+ if ( lowestMessage <= value.yPos + 16 + COMBAT_TEXT_SPACING) then
+ lowestMessage = value.yPos + 16 + COMBAT_TEXT_SPACING;
+ end
+ end
+ if ( lowestMessage > (COMBAT_TEXT_LOCATIONS.startY + COMBAT_TEXT_MAX_OFFSET) ) then
+ if ( displayType == "crit" ) then
+ lowestMessage = string:GetTop();
+ else
+ COMBAT_TEXT_X_ADJUSTMENT = COMBAT_TEXT_X_ADJUSTMENT * -1;
+ useXadjustment = 1;
+ lowestMessage = COMBAT_TEXT_LOCATIONS.startY + COMBAT_TEXT_MAX_OFFSET;
+ end
+ end
+ end
+
+ -- Handle crits
+ if ( displayType == "crit" ) then
+ string.endY = COMBAT_TEXT_LOCATIONS.startY;
+ string.isCrit = 1;
+ string:SetTextHeight(COMBAT_TEXT_CRIT_MINHEIGHT);
+ elseif ( displayType == "sticky" ) then
+ string.endY = COMBAT_TEXT_LOCATIONS.startY;
+ string:SetTextHeight(COMBAT_TEXT_HEIGHT);
+ else
+ string.endY = COMBAT_TEXT_LOCATIONS.endY;
+ string:SetTextHeight(COMBAT_TEXT_HEIGHT);
+ end
+
+ -- Stagger the text if flagged
+ local staggerAmount = 0;
+ if ( isStaggered ) then
+ staggerAmount = random(0, COMBAT_TEXT_STAGGER_RANGE) - COMBAT_TEXT_STAGGER_RANGE/2;
+ end
+
+ -- Alternate x direction
+ CombatText.xDir = CombatText.xDir * -1;
+ if ( useXadjustment == 1 ) then
+ if ( COMBAT_TEXT_X_ADJUSTMENT > 0 ) then
+ CombatText.xDir = -1;
+ else
+ CombatText.xDir = 1;
+ end
+ end
+ string.xDir = CombatText.xDir;
+ string.startX = COMBAT_TEXT_LOCATIONS.startX + staggerAmount + (useXadjustment * COMBAT_TEXT_X_ADJUSTMENT);
+ string.startY = lowestMessage;
+ string.yPos = lowestMessage;
+ string:ClearAllPoints();
+ string:SetPoint("TOP", WorldFrame, "BOTTOM", string.startX, lowestMessage);
+ string:SetAlpha(1);
+ string:Show();
+ tinsert(COMBAT_TEXT_TO_ANIMATE, string);
+end
+
+function CombatText_RemoveMessage(string)
+ for index, value in pairs(COMBAT_TEXT_TO_ANIMATE) do
+ if ( value == string ) then
+ tremove(COMBAT_TEXT_TO_ANIMATE, index);
+ string:SetAlpha(0);
+ string:Hide();
+ string:SetPoint("TOP", WorldFrame, "BOTTOM", COMBAT_TEXT_LOCATIONS.startX, COMBAT_TEXT_LOCATIONS.startY);
+ break;
+ end
+ end
+end
+
+function CombatText_GetAvailableString()
+ local string;
+ for i=1, NUM_COMBAT_TEXT_LINES do
+ string = _G["CombatText"..i];
+ if ( not string:IsShown() ) then
+ return string;
+ end
+ end
+ return CombatText_GetOldestString(), 1;
+end
+
+function CombatText_GetOldestString()
+ local oldestString = COMBAT_TEXT_TO_ANIMATE[1];
+ CombatText_RemoveMessage(oldestString);
+ return oldestString;
+end
+
+function CombatText_ClearAnimationList()
+ local string;
+ for i=1, NUM_COMBAT_TEXT_LINES do
+ string = _G["CombatText"..i];
+ string:SetAlpha(0);
+ string:Hide();
+ string:SetPoint("TOP", WorldFrame, "BOTTOM", COMBAT_TEXT_LOCATIONS.startX, COMBAT_TEXT_LOCATIONS.startY);
+ end
+end
+
+function CombatText_UpdateDisplayedMessages()
+ -- Unregister events if combat text is disabled
+ if ( SHOW_COMBAT_TEXT == "0" ) then
+ CombatText:UnregisterEvent("COMBAT_TEXT_UPDATE");
+ CombatText:UnregisterEvent("UNIT_HEALTH");
+ CombatText:UnregisterEvent("UNIT_MANA");
+ CombatText:UnregisterEvent("PLAYER_REGEN_DISABLED");
+ CombatText:UnregisterEvent("PLAYER_REGEN_ENABLED");
+ CombatText:UnregisterEvent("UNIT_COMBO_POINTS");
+ CombatText:UnregisterEvent("RUNE_POWER_UPDATE");
+ CombatText:UnregisterEvent("UNIT_ENTERED_VEHICLE");
+ CombatText:UnregisterEvent("UNIT_EXITING_VEHICLE");
+ return;
+ end
+
+ -- set the unit to track
+ if ( UnitHasVehicleUI("player") ) then
+ CombatText.unit = "vehicle";
+ else
+ CombatText.unit = "player";
+ end
+ CombatTextSetActiveUnit(CombatText.unit);
+
+ -- register events
+ CombatText:RegisterEvent("COMBAT_TEXT_UPDATE");
+ CombatText:RegisterEvent("UNIT_HEALTH");
+ CombatText:RegisterEvent("UNIT_MANA");
+ CombatText:RegisterEvent("PLAYER_REGEN_DISABLED");
+ CombatText:RegisterEvent("PLAYER_REGEN_ENABLED");
+ CombatText:RegisterEvent("UNIT_COMBO_POINTS");
+ CombatText:RegisterEvent("RUNE_POWER_UPDATE");
+ CombatText:RegisterEvent("UNIT_ENTERED_VEHICLE");
+ CombatText:RegisterEvent("UNIT_EXITING_VEHICLE");
+
+ -- Get scale
+ COMBAT_TEXT_Y_SCALE = WorldFrame:GetHeight() / 768;
+ COMBAT_TEXT_X_SCALE = WorldFrame:GetWidth() / 1024;
+ COMBAT_TEXT_SPACING = 10 * COMBAT_TEXT_Y_SCALE;
+ COMBAT_TEXT_MAX_OFFSET = 130 * COMBAT_TEXT_Y_SCALE;
+ COMBAT_TEXT_X_ADJUSTMENT = 80 * COMBAT_TEXT_X_SCALE;
+
+ -- Update shown messages
+ for index, value in pairs(COMBAT_TEXT_TYPE_INFO) do
+ if ( value.var ) then
+ if ( _G[value.var] == "1" ) then
+ value.show = 1;
+ else
+ value.show = nil;
+ end
+ end
+ end
+ -- Update scrolldirection
+ if ( COMBAT_TEXT_FLOAT_MODE == "1" ) then
+ COMBAT_TEXT_SCROLL_FUNCTION = CombatText_StandardScroll;
+ COMBAT_TEXT_LOCATIONS = {
+ startX = 0,
+ startY = 384 * COMBAT_TEXT_Y_SCALE,
+ endX = 0,
+ endY = 609 * COMBAT_TEXT_Y_SCALE
+ };
+
+ elseif ( COMBAT_TEXT_FLOAT_MODE == "2" ) then
+ COMBAT_TEXT_SCROLL_FUNCTION = CombatText_StandardScroll;
+ COMBAT_TEXT_LOCATIONS = {
+ startX = 0,
+ startY = 384 * COMBAT_TEXT_Y_SCALE,
+ endX = 0,
+ endY = 159 * COMBAT_TEXT_Y_SCALE
+ };
+ else
+ COMBAT_TEXT_SCROLL_FUNCTION = CombatText_FountainScroll;
+ COMBAT_TEXT_LOCATIONS = {
+ startX = 0,
+ startY = 384 * COMBAT_TEXT_Y_SCALE,
+ endX = 0,
+ endY = 609 * COMBAT_TEXT_Y_SCALE
+ };
+ end
+ CombatText_ClearAnimationList();
+end
+
+function CombatText_StandardScroll(value)
+ -- Calculate x and y positions
+ local xPos = value.startX+((COMBAT_TEXT_LOCATIONS.endX - COMBAT_TEXT_LOCATIONS.startX)*value.scrollTime/COMBAT_TEXT_SCROLLSPEED);
+ local yPos = value.startY+((value.endY - COMBAT_TEXT_LOCATIONS.startY)*value.scrollTime/COMBAT_TEXT_SCROLLSPEED);
+ return xPos, yPos;
+end
+
+function CombatText_FountainScroll(value)
+ -- Calculate x and y positions
+ local radius = 150;
+ local xPos = value.startX-value.xDir*(radius*(1-cos(90*value.scrollTime/COMBAT_TEXT_SCROLLSPEED)));
+ local yPos = value.startY+radius*sin(90*value.scrollTime/COMBAT_TEXT_SCROLLSPEED);
+ return xPos, yPos;
+end
diff --git a/reference/AddOns/Blizzard_CombatText/Blizzard_CombatText.toc b/reference/AddOns/Blizzard_CombatText/Blizzard_CombatText.toc
new file mode 100644
index 0000000..38e2eea
--- /dev/null
+++ b/reference/AddOns/Blizzard_CombatText/Blizzard_CombatText.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard CombatText
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_CombatText.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_CombatText/Blizzard_CombatText.xml b/reference/AddOns/Blizzard_CombatText/Blizzard_CombatText.xml
new file mode 100644
index 0000000..352557f
--- /dev/null
+++ b/reference/AddOns/Blizzard_CombatText/Blizzard_CombatText.xml
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_CombatText/Localization.lua b/reference/AddOns/Blizzard_CombatText/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_CombatText/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_DebugTools/Blizzard_DebugTools.lua b/reference/AddOns/Blizzard_DebugTools/Blizzard_DebugTools.lua
new file mode 100644
index 0000000..8361bcd
--- /dev/null
+++ b/reference/AddOns/Blizzard_DebugTools/Blizzard_DebugTools.lua
@@ -0,0 +1,571 @@
+EVENT_TRACE_EVENT_HEIGHT = 16;
+EVENT_TRACE_MAX_ENTRIES = 1000;
+
+DEBUGLOCALS_LEVEL = 4;
+local _normalFontColor = { 1, .82, 0, 1 };
+
+EVENT_TRACE_SYSTEM_TIMES = {};
+EVENT_TRACE_SYSTEM_TIMES["System"] = true;
+EVENT_TRACE_SYSTEM_TIMES["Elapsed"] = true;
+
+EVENT_TRACE_EVENT_COLORS = {};
+EVENT_TRACE_EVENT_COLORS["System"] = _normalFontColor;
+EVENT_TRACE_EVENT_COLORS["Elapsed"] = { .6, .6, .6, 1 };
+
+local _EventTraceFrame;
+
+_framesSinceLast = 0;
+_timeSinceLast = 0;
+
+local _timer = CreateFrame("FRAME");
+_timer:SetScript("OnUpdate", function (self, elapsed) _framesSinceLast = _framesSinceLast + 1; _timeSinceLast = _timeSinceLast + elapsed; end);
+
+function EventTraceFrame_OnLoad (self)
+ self.buttons = {};
+ self.events = {};
+ self.times = {};
+ self.rawtimes = {};
+ self.args = { {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} };
+ self.ignoredEvents = {};
+ self.lastIndex = 0;
+ self.visibleButtons = 0;
+ _EventTraceFrame = self;
+ self:SetScript("OnSizeChanged", EventTraceFrame_OnSizeChanged);
+ EventTraceFrame_OnSizeChanged(self, self:GetWidth(), self:GetHeight());
+ self:EnableMouse(true);
+ self:EnableMouseWheel(true);
+ self:SetScript("OnMouseWheel", EventTraceFrame_OnMouseWheel);
+end
+
+local _workTable = {};
+function EventTraceFrame_OnEvent (self, event, ...)
+ if ( not self.ignoredEvents[event] ) then
+ if ( not self.ignoreElapsed and _framesSinceLast ~= 0 ) then
+ self.ignoreElapsed = true;
+ EventTraceFrame_OnEvent(self, "On Update");
+ self.ignoreElapsed = nil;
+ end
+
+ local nextIndex = self.lastIndex + 1;
+ if ( nextIndex > EVENT_TRACE_MAX_ENTRIES ) then
+ local staleIndex = nextIndex - EVENT_TRACE_MAX_ENTRIES;
+ self.events[staleIndex] = nil;
+ self.times[staleIndex] = nil;
+ self.rawtimes[staleIndex] = nil;
+ for k, v in next, self.args do
+ self.args[k][staleIndex] = nil;
+ end
+ end
+
+ if ( string.match(event, "Begin Capture") or string.match(event, "End Capture") ) then
+ self.times[nextIndex] = "System";
+ if ( self.eventsToCapture ) then
+ self.events[nextIndex] = string.format("%s (%s events)", event, tostring(self.eventsToCapture));
+ else
+ self.events[nextIndex] = event;
+ end
+ elseif ( event == "On Update" ) then
+ self.times[nextIndex] = "Elapsed";
+ self.events[nextIndex] = string.format(string.format("%.3f sec", _timeSinceLast) .. " - %d frame(s)", _framesSinceLast);
+ _timeSinceLast = 0;
+ _framesSinceLast = 0;
+ else
+ self.events[nextIndex] = event;
+ local seconds = GetTime();
+ local minutes = math.floor(math.floor(seconds) / 60);
+ local hours = math.floor(minutes / 60);
+ seconds = seconds - 60 * minutes;
+ minutes = minutes - 60 * hours;
+ hours = hours % 1000;
+ self.times[nextIndex] = string.format("%.2d:%.2d:%06.3f", hours, minutes, seconds);
+
+ local numArgs = select("#", ...);
+ for i=1, numArgs do
+ if ( not self.args[i] ) then
+ self.args[i] = {};
+ end
+ self.args[i][nextIndex] = select(i, ...);
+ end
+
+ if ( self.eventsToCapture ) then
+ self.eventsToCapture = self.eventsToCapture - 1;
+ end
+ end
+
+ self.rawtimes[nextIndex] = GetTime();
+ self.lastIndex = nextIndex;
+ EventTraceFrame_Update ();
+ if ( self.eventsToCapture and self.eventsToCapture <= 0 ) then
+ self.eventsToCapture = nil;
+ EventTraceFrame_StopEventCapture();
+ end
+ end
+end
+
+function EventTraceFrame_OnUpdate (self, elapsed)
+ EventTraceFrame_Update();
+end
+
+function EventTraceFrame_OnSizeChanged (self, width, height)
+ local numButtonsToDisplay = math.floor((height - 36)/EVENT_TRACE_EVENT_HEIGHT);
+ local numButtonsCreated = #self.buttons;
+
+ if ( numButtonsCreated < numButtonsToDisplay ) then
+ for i = numButtonsCreated + 1, numButtonsToDisplay do
+ local button = CreateFrame("BUTTON", "EventTraceFrameButton" .. i, self, "EventTraceEventTemplate");
+ button:SetPoint("BOTTOMLEFT", 12, (16 * (i - 1)) + 12);
+ button:SetPoint("RIGHT", -28, 0);
+ tinsert(self.buttons, button);
+ end
+ for i = self.visibleButtons + 1, numButtonsToDisplay do
+ self.buttons[i]:Show();
+ end
+ self.visibleButtons = numButtonsToDisplay;
+ EventTraceFrame_Update();
+ elseif ( self.visibleButtons < numButtonsToDisplay ) then
+ for i = self.visibleButtons + 1, numButtonsToDisplay do
+ self.buttons[i]:Show();
+ end
+ self.visibleButtons = numButtonsToDisplay;
+ EventTraceFrame_Update();
+ elseif ( numButtonsToDisplay < self.visibleButtons ) then
+ for i = numButtonsToDisplay + 1, self.visibleButtons do
+ self.buttons[i]:Hide();
+ end
+ self.visibleButtons = numButtonsToDisplay;
+ end
+end
+
+function EventTraceFrame_Update ()
+ local offset = 0;
+
+ local scrollBar = _G["EventTraceFrameScroll"];
+ local scrollBarValue = scrollBar:GetValue();
+ local minValue, maxValue = scrollBar:GetMinMaxValues();
+
+ local firstID = max(1, _EventTraceFrame.lastIndex - EVENT_TRACE_MAX_ENTRIES + 1);
+ local lastID = _EventTraceFrame.lastIndex or 1;
+
+ if ( firstID >= lastID ) then
+ scrollBar:SetMinMaxValues(firstID-1, lastID);
+ else
+ scrollBar:SetMinMaxValues(firstID, lastID);
+ end
+ if ( scrollBarValue < firstID ) then
+ scrollBar:SetValue(firstID);
+ scrollBarValue = firstID;
+ end
+
+ if ( scrollBarValue < 1 ) then
+ scrollBarValue = 1;
+ elseif ( not _EventTraceFrame.selectedEvent ) then
+ if ( scrollBarValue == maxValue ) then
+ scrollBar:SetValue(_EventTraceFrame.lastIndex);
+ end
+ end
+
+ for i = 1, _EventTraceFrame.visibleButtons do
+ local button = _EventTraceFrame.buttons[i];
+ if ( button ) then
+ local index = scrollBarValue - (i - 1);
+ local event = _EventTraceFrame.events[index];
+ if ( event ) then
+ local timeString = _EventTraceFrame.times[index]
+ button.index = index;
+ button.time:SetText(timeString);
+ button.event:SetText(event);
+ local color = EVENT_TRACE_EVENT_COLORS[event] or EVENT_TRACE_EVENT_COLORS[timeString];
+ if ( color ) then
+ button.time:SetTextColor(unpack(color));
+ button.event:SetTextColor(unpack(color));
+ else
+ button.time:SetTextColor(1, 1, 1, 1);
+ button.event:SetTextColor(1, 1, 1, 1);
+ end
+ button:Show();
+ if ( _EventTraceFrame.selectedEvent ) then
+ if ( index == _EventTraceFrame.selectedEvent ) then
+ EventTraceFrameEvent_DisplayTooltip(button);
+ button:GetHighlightTexture():SetVertexColor(.15, .25, 1, .35);
+ button:LockHighlight(true);
+ button.wasSelected = true;
+ elseif ( button.wasSelected ) then
+ button.wasSelected = nil;
+ button:GetHighlightTexture():SetVertexColor(.8, .8, 1, .15);
+ button:UnlockHighlight();
+ end
+ else
+ if ( button.wasSelected ) then
+ button.wasSelected = nil;
+ button:GetHighlightTexture():SetVertexColor(.8, .8, 1, .15);
+ button:UnlockHighlight();
+ end
+ if ( button:IsMouseOver() ) then
+ EventTraceFrameEvent_OnEnter(button);
+ end
+ end
+ else
+ button.index = index;
+ button:Hide();
+ end
+ end
+ end
+
+ EventTraceFrame_UpdateKeyboardStatus();
+end
+
+function EventTraceFrame_StartEventCapture ()
+ if ( _EventTraceFrame.started ) then -- Nothing to do?
+ return;
+ end
+
+ _EventTraceFrame.started = true;
+ _framesSinceLast = 0;
+ _timeSinceLast = 0;
+ _EventTraceFrame:RegisterAllEvents();
+ EventTraceFrame_OnEvent(_EventTraceFrame, "Begin Capture");
+end
+
+function EventTraceFrame_StopEventCapture ()
+ if ( not _EventTraceFrame.started ) then -- Nothing to do!
+ return;
+ end
+
+ _EventTraceFrame.started = false;
+ _framesSinceLast = 0;
+ _timeSinceLast = 0;
+ _EventTraceFrame:UnregisterAllEvents();
+ EventTraceFrame_OnEvent(_EventTraceFrame, "End Capture");
+end
+
+function EventTraceFrame_HandleSlashCmd (msg)
+ msg = strlower(msg);
+ if ( msg == "start" ) then
+ EventTraceFrame_StartEventCapture();
+ elseif ( msg == "stop" ) then
+ EventTraceFrame_StopEventCapture();
+ elseif ( tonumber(msg) and tonumber(msg) > 0 ) then
+ if ( not _EventTraceFrame.started ) then
+ _EventTraceFrame.eventsToCapture = tonumber(msg);
+ EventTraceFrame_StartEventCapture();
+ end
+ elseif ( msg == "" ) then
+ if ( not _EventTraceFrame:IsShown() ) then
+ _EventTraceFrame:Show();
+ if ( _EventTraceFrame.started == nil ) then
+ EventTraceFrame_StartEventCapture(); -- If this is the first time we're showing the window, start capturing events immediately.
+ end
+ else
+ _EventTraceFrame:Hide();
+ end
+ end
+end
+
+function EventTraceFrame_OnMouseWheel (self, delta)
+ local scrollBar = _G["EventTraceFrameScroll"];
+ local minVal, maxVal = scrollBar:GetMinMaxValues();
+ local currentValue = scrollBar:GetValue();
+
+ local newValue = currentValue - ( delta * 3 );
+ newValue = max(newValue, minVal);
+ newValue = min(newValue, maxVal);
+ if ( newValue ~= currentValue ) then
+ scrollBar:SetValue(newValue);
+ end
+end
+
+function EventTraceFrame_UpdateKeyboardStatus ()
+ if ( _EventTraceFrame.selectedEvent ) then
+ local focus = GetMouseFocus();
+ if ( focus == _EventTraceFrame or (focus and focus:GetParent() == _EventTraceFrame) ) then
+ _EventTraceFrame:EnableKeyboard(true);
+ return;
+ end
+ end
+ _EventTraceFrame:EnableKeyboard(false);
+end
+
+function EventTraceFrame_OnKeyUp (self, key)
+ if ( key == "ESCAPE" ) then
+ self.selectedEvent = nil;
+ EventTraceTooltip:Hide();
+ EventTraceFrame_Update();
+ end
+end
+
+local TIME_ENTRY_FORMAT = "Time:";
+local DETAILS_ENTRY_FORMAT = "Details:";
+local ARGUMENT_ENTRY_FORMAT = "arg %d:";
+
+local function EventTrace_FormatArgValue (val)
+ if ( type(val) == "string" ) then
+ return string.format('"%s"', val);
+ elseif ( type(val) == "number" ) then
+ return tostring(val);
+ elseif ( type(val) == "bool" ) then
+ return string.format('|cffaaaaff%s|r', tostring(val));
+ elseif ( type(val) == "table" or type(val) == "bool" ) then
+ return string.format('|cffffaaaa%s|r', tostring(val));
+ end
+end
+
+function EventTraceFrameEvent_DisplayTooltip (eventButton)
+ local index = eventButton.index;
+ if ( not index ) then
+ return;
+ end
+
+ local tooltip = _G["EventTraceTooltip"];
+ tooltip:SetOwner(eventButton, "ANCHOR_NONE");
+ tooltip:SetPoint("TOPLEFT", eventButton, "TOPRIGHT", 24, 2);
+ local timeString = _EventTraceFrame.times[index]
+ if ( EVENT_TRACE_SYSTEM_TIMES[timeString] ) then
+ tooltip:AddLine(timeString, 1, 1, 1);
+ tooltip:AddDoubleLine(string.format(TIME_ENTRY_FORMAT), _EventTraceFrame.rawtimes[index], 1, .82, 0, 1, 1, 1);
+ tooltip:AddDoubleLine(string.format(DETAILS_ENTRY_FORMAT), _EventTraceFrame.events[index], 1, .82, 0, 1, 1, 1);
+ else
+ tooltip:AddLine(_EventTraceFrame.events[index], 1, 1, 1);
+ tooltip:AddDoubleLine(string.format(TIME_ENTRY_FORMAT), _EventTraceFrame.rawtimes[index], 1, .82, 0, 1, 1, 1);
+ for k, v in ipairs(EventTraceFrame.args) do
+ if ( v[index] ) then
+ tooltip:AddDoubleLine(string.format(ARGUMENT_ENTRY_FORMAT, k), EventTrace_FormatArgValue(v[index]), 1, .82, 0, 1, 1, 1);
+ end
+ end
+ end
+ tooltip:Show();
+end
+
+function EventTraceFrameEvent_OnEnter (self)
+ if ( _EventTraceFrame.selectedEvent ) then
+ return;
+ else
+ EventTraceFrameEvent_DisplayTooltip(self);
+ end
+end
+
+function EventTraceFrameEvent_OnLeave (self)
+ if ( not _EventTraceFrame.selectedEvent ) then
+ EventTraceTooltip:Hide();
+ end
+end
+
+function EventTraceFrameEvent_OnClick (self)
+ if ( _EventTraceFrame.selectedEvent == self.index ) then
+ _EventTraceFrame.selectedEvent = nil;
+ else
+ _EventTraceFrame.selectedEvent = self.index;
+ end
+ EventTraceFrame_Update();
+end
+
+local ERROR_FORMAT = [[|cffffd200Message:|cffffffff %s
+|cffffd200Time:|cffffffff %s
+|cffffd200Count:|cffffffff %s
+|cffffd200Stack:|cffffffff %s
+|cffffd200Locals:|cffffffff %s]];
+
+local INDEX_ORDER_FORMAT = "%d / %d"
+
+local _ScriptErrorsFrame;
+
+function ScriptErrorsFrame_OnLoad (self)
+ self.title:SetText(LUA_ERROR);
+ self:RegisterForDrag("LeftButton");
+ self.seen = {};
+ self.order = {};
+ self.count = {};
+ self.messages = {};
+ self.times = {};
+ self.locals = {};
+ _ScriptErrorsFrame = self;
+end
+
+function ScriptErrorsFrame_OnShow (self)
+ ScriptErrorsFrame_Update();
+end
+
+function ScriptErrorsFrame_OnError (message, keepHidden)
+ local stack = debugstack(DEBUGLOCALS_LEVEL);
+
+ local messageStack = message..stack; -- Fix me later
+
+ if ( _ScriptErrorsFrame ) then
+ local index = _ScriptErrorsFrame.seen[messageStack];
+ if ( index ) then
+ _ScriptErrorsFrame.count[index] = _ScriptErrorsFrame.count[index] + 1;
+ _ScriptErrorsFrame.messages[index] = message;
+ _ScriptErrorsFrame.times[index] = date();
+ _ScriptErrorsFrame.locals[index] = debuglocals(DEBUGLOCALS_LEVEL);
+ else
+ tinsert(_ScriptErrorsFrame.order, stack);
+ index = #_ScriptErrorsFrame.order;
+ _ScriptErrorsFrame.count[index] = 1;
+ _ScriptErrorsFrame.messages[index] = message;
+ _ScriptErrorsFrame.times[index] = date();
+ _ScriptErrorsFrame.seen[messageStack] = index;
+ _ScriptErrorsFrame.locals[index] = debuglocals(DEBUGLOCALS_LEVEL);
+ end
+
+ if ( not _ScriptErrorsFrame:IsShown() and not keepHidden ) then
+ _ScriptErrorsFrame.index = index;
+ _ScriptErrorsFrame:Show();
+ else
+ ScriptErrorsFrame_Update();
+ end
+ end
+end
+
+function ScriptErrorsFrame_Update ()
+ local editBox = ScriptErrorsFrameScrollFrameText;
+ local index = _ScriptErrorsFrame.index;
+ if ( not index or not _ScriptErrorsFrame.order[index] ) then
+ index = #_ScriptErrorsFrame.order;
+ _ScriptErrorsFrame.index = index;
+ end
+
+ if ( index == 0 ) then
+ editBox:SetText("");
+ ScriptErrorsFrame_UpdateButtons();
+ return;
+ end
+
+ local text = string.format(
+ ERROR_FORMAT,
+ _ScriptErrorsFrame.messages[index],
+ _ScriptErrorsFrame.times[index],
+ _ScriptErrorsFrame.count[index],
+ _ScriptErrorsFrame.order[index],
+ _ScriptErrorsFrame.locals[index]
+ );
+
+ local parent = editBox:GetParent();
+ local prevText = editBox.text;
+ editBox.text = text;
+ if ( prevText ~= text ) then
+ editBox:SetText(text);
+ editBox:HighlightText(0);
+ editBox:SetCursorPosition(0);
+ else
+ ScrollingEdit_OnTextChanged(editBox, parent);
+ end
+ parent:SetVerticalScroll(0);
+
+ ScriptErrorsFrame_UpdateButtons();
+end
+
+function ScriptErrorsFrame_UpdateButtons ()
+ local index = _ScriptErrorsFrame.index;
+ local numErrors = #_ScriptErrorsFrame.order;
+ if ( index == 0 ) then
+ _ScriptErrorsFrame.next:Disable();
+ _ScriptErrorsFrame.previous:Disable();
+ else
+ if ( numErrors == 1 ) then
+ _ScriptErrorsFrame.next:Disable();
+ _ScriptErrorsFrame.previous:Disable();
+ elseif ( index == 1 ) then
+ _ScriptErrorsFrame.next:Enable();
+ _ScriptErrorsFrame.previous:Disable();
+ elseif ( index == numErrors ) then
+ _ScriptErrorsFrame.next:Disable();
+ _ScriptErrorsFrame.previous:Enable();
+ else
+ _ScriptErrorsFrame.next:Enable();
+ _ScriptErrorsFrame.previous:Enable();
+ end
+ end
+
+ _ScriptErrorsFrame.indexLabel:SetText(string.format(INDEX_ORDER_FORMAT, index, numErrors));
+end
+
+function ScriptErrorsFrame_DeleteError (index)
+ if ( _ScriptErrorsFrame.order[index] ) then
+ _ScriptErrorsFrame.seen[_ScriptErrorsFrame.messages[index] .. _ScriptErrorsFrame.order[index]] = nil;
+ tremove(_ScriptErrorsFrame.order, index);
+ tremove(_ScriptErrorsFrame.messages, index);
+ tremove(_ScriptErrorsFrame.times, index);
+ tremove(_ScriptErrorsFrame.count, index);
+ end
+end
+
+function ScriptErrorsFrameButton_OnClick (self)
+ local id = self:GetID();
+
+
+ if ( id == 1 ) then
+ _ScriptErrorsFrame.index = _ScriptErrorsFrame.index + 1;
+ else
+ _ScriptErrorsFrame.index = _ScriptErrorsFrame.index - 1;
+ end
+
+ ScriptErrorsFrame_Update();
+end
+
+--[[ function ScriptErrorsFrameDelete_OnClick (self);
+ local index = _ScriptErrorsFrame.index;
+ ScriptErrorsFrame_DeleteError(index);
+
+ local numErrors = #_ScriptErrorsFrame.order;
+ if ( numErrors == 0 ) then
+ _ScriptErrorsFrame.index = 0;
+ elseif ( index > numErrors ) then
+ _ScriptErrorsFrame.index = numErrors;
+ end
+
+ ScriptErrorsFrame_Update();
+end ]]
+
+function DebugTooltip_OnLoad(self)
+ self:SetFrameLevel(self:GetFrameLevel() + 2);
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+ self.statusBar2 = getglobal(self:GetName().."StatusBar2");
+ self.statusBar2Text = getglobal(self:GetName().."StatusBar2Text");
+end
+
+function FrameStackTooltip_Toggle (showHidden)
+ local tooltip = _G["FrameStackTooltip"];
+ if ( tooltip:IsVisible() ) then
+ tooltip:Hide();
+ else
+ tooltip:SetOwner(UIParent, "ANCHOR_NONE");
+ tooltip:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -CONTAINER_OFFSET_X - 13, CONTAINER_OFFSET_Y);
+ tooltip.default = 1;
+ tooltip.showHidden = showHidden;
+ tooltip:SetFrameStack(showHidden);
+ end
+end
+
+FRAMESTACK_UPDATE_TIME = .1
+local _timeSinceLast = 0
+function FrameStackTooltip_OnUpdate (self, elapsed)
+ _timeSinceLast = _timeSinceLast - elapsed;
+ if ( _timeSinceLast <= 0 ) then
+ _timeSinceLast = FRAMESTACK_UPDATE_TIME;
+ self:SetFrameStack(self.showHidden);
+ end
+end
+
+function FrameStackTooltip_OnShow (self)
+ local parent = self:GetParent() or UIParent;
+ local ps = parent:GetEffectiveScale();
+ local px, py = parent:GetCenter();
+ px, py = px * ps, py * ps;
+ local x, y = GetCursorPosition();
+ self:ClearAllPoints();
+ if (x > px) then
+ if (y > py) then
+ self:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", 20, 20);
+ else
+ self:SetPoint("TOPLEFT", parent, "TOPLEFT", 20, -20);
+ end
+ else
+ if (y > py) then
+ self:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", -20, 20);
+ else
+ self:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -20, -20);
+ end
+ end
+end
+
+FrameStackTooltip_OnEnter = FrameStackTooltip_OnShow;
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_DebugTools/Blizzard_DebugTools.toc b/reference/AddOns/Blizzard_DebugTools/Blizzard_DebugTools.toc
new file mode 100644
index 0000000..cda311d
--- /dev/null
+++ b/reference/AddOns/Blizzard_DebugTools/Blizzard_DebugTools.toc
@@ -0,0 +1,12 @@
+## Interface: 30300
+## Title: Blizzard UI Debug Tools
+## Notes: Tools for developing addons
+## Secure: 1
+## Author: Blizzard Entertainment
+## Special Thanks: Iriel, Kirov, Esamynn
+## Version: 1.0
+## LoadOnDemand: 1
+Dump.lua
+Blizzard_DebugTools.lua
+Blizzard_DebugTools.xml
+Localization.lua
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_DebugTools/Blizzard_DebugTools.xml b/reference/AddOns/Blizzard_DebugTools/Blizzard_DebugTools.xml
new file mode 100644
index 0000000..27e997b
--- /dev/null
+++ b/reference/AddOns/Blizzard_DebugTools/Blizzard_DebugTools.xml
@@ -0,0 +1,349 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetHighlightTexture():SetAlpha(.15);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForDrag("LeftButton");
+
+
+ local eventTraceFrame = _G["EventTraceFrame"];
+ eventTraceFrame.moving = true;
+ eventTraceFrame:StartMoving();
+
+
+ local eventTraceFrame = _G["EventTraceFrame"];
+ eventTraceFrame.moving = nil;
+ eventTraceFrame:StopMovingOrSizing();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 1);
+ self:SetValue(0);
+ self:SetValueStep(1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForDrag("LeftButton");
+
+
+ local frame = _G["ScriptErrorsFrame"];
+ frame.moving = true;
+ frame:StartMoving();
+
+
+ local frame = _G["ScriptErrorsFrame"];
+ frame.moving = nil;
+ frame:StopMovingOrSizing();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ScrollingEdit_OnUpdate(self, elapsed, self:GetParent());
+
+
+ self:HighlightText(0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_DebugTools/Dump.lua b/reference/AddOns/Blizzard_DebugTools/Dump.lua
new file mode 100644
index 0000000..56b1c0b
--- /dev/null
+++ b/reference/AddOns/Blizzard_DebugTools/Dump.lua
@@ -0,0 +1,408 @@
+------------------------------------------------------------------------------
+-- Dump.lua
+--
+-- Contributed by Iriel, Esamynn and Kirov from DevTools v1.11
+-- /dump Implementation
+--
+-- Globals: DevTools, SLASH_DEVTOOLSDUMP1, DevTools_Dump, DevTools_RunDump
+-- Globals: DEVTOOLS_MAX_ENTRY_CUTOFF, DEVTOOLS_LONG_STRING_CUTOFF
+-- Globals: DEVTOOLS_DEPTH_CUTOFF, DEVTOOLS_INDENT
+-- Globals: DEVTOOLS_USE_TABLE_CACHE, DEVTOOLS_USE_FUNCTION_CACHE
+-- Globals: DEVTOOLS_USE_USERDATA_CACHE
+---------------------------------------------------------------------------
+local DT = {};
+
+DEVTOOLS_MAX_ENTRY_CUTOFF = 30; -- Maximum table entries shown
+DEVTOOLS_LONG_STRING_CUTOFF = 200; -- Maximum string size shown
+DEVTOOLS_DEPTH_CUTOFF = 10; -- Maximum table depth
+DEVTOOLS_USE_TABLE_CACHE = true; -- Look up table names
+DEVTOOLS_USE_FUNCTION_CACHE = true;-- Look up function names
+DEVTOOLS_USE_USERDATA_CACHE = true;-- Look up userdata names
+DEVTOOLS_INDENT=' '; -- Indentation string
+
+local DEVTOOLS_TYPE_COLOR="|cff88ff88";
+local DEVTOOLS_TABLEREF_COLOR="|cffffcc00";
+local DEVTOOLS_CUTOFF_COLOR="|cffff0000";
+local DEVTOOLS_TABLEKEY_COLOR="|cff88ccff";
+
+local FORMATS = {};
+-- prefix type suffix
+FORMATS["opaqueTypeVal"] = "%s" .. DEVTOOLS_TYPE_COLOR .. "<%s>|r%s";
+-- prefix type name suffix
+FORMATS["opaqueTypeValName"] = "%s" .. DEVTOOLS_TYPE_COLOR .. "<%s %s>|r%s";
+-- type
+FORMATS["opaqueTypeKey"] = "<%s>";
+-- type name
+FORMATS["opaqueTypeKeyName"] = "<%s %s>";
+-- value
+FORMATS["bracketTableKey"] = "[%s]";
+-- prefix value
+FORMATS["tableKeyAssignPrefix"] = DEVTOOLS_TABLEKEY_COLOR .. "%s%s|r=";
+-- prefix cutoff
+FORMATS["tableEntriesSkipped"] = "%s" .. DEVTOOLS_CUTOFF_COLOR .. "|r";
+-- prefix suffix
+FORMATS["tableTooDeep"] = "%s" .. DEVTOOLS_CUTOFF_COLOR .. "|r%s";
+-- prefix value suffix
+FORMATS["simpleValue"] = "%s%s%s";
+-- prefix tablename suffix
+FORMATS["tableReference"] = "%s" .. DEVTOOLS_TABLEREF_COLOR .. "%s|r%s";
+
+-- Grab a copy various oft-used functions
+local rawget = rawget;
+local type = type;
+local string_len = string.len;
+local string_sub = string.sub;
+local string_gsub = string.gsub;
+local string_format = string.format;
+local string_match = string.match;
+
+local function WriteMessage(msg)
+ DEFAULT_CHAT_FRAME:AddMessage(msg);
+end
+
+local function prepSimple(val, context)
+ local valType = type(val);
+ if (valType == "nil") then
+ return "nil";
+ elseif (valType == "number") then
+ return val;
+ elseif (valType == "boolean") then
+ if (val) then
+ return "true";
+ else
+ return "false";
+ end
+ elseif (valType == "string") then
+ local l = string_len(val);
+ if ((l > DEVTOOLS_LONG_STRING_CUTOFF) and
+ (DEVTOOLS_LONG_STRING_CUTOFF > 0)) then
+ local more = l - DEVTOOLS_LONG_STRING_CUTOFF;
+ val = string_sub(val, 1, DEVTOOLS_LONG_STRING_CUTOFF);
+ return string_gsub(string_format("%q...+%s",val,more),"[|]", "||");
+ else
+ return string_gsub(string_format("%q",val),"[|]", "||");
+ end
+ elseif (valType == "function") then
+ local fName = context:GetFunctionName(val);
+ if (fName) then
+ return string_format(FORMATS.opaqueTypeKeyName, valType, fName);
+ else
+ return string_format(FORMATS.opaqueTypeKey, valType);
+ end
+ return string_format(FORMATS.opaqueTypeKey, valType);
+ elseif (valType == "userdata") then
+ local uName = context:GetUserdataName(val);
+ if (uName) then
+ return string_format(FORMATS.opaqueTypeKeyName, valType, uName);
+ else
+ return string_format(FORMATS.opaqueTypeKey, valType);
+ end
+ elseif (valType == 'table') then
+ local tName = context:GetTableName(val);
+ if (tName) then
+ return string_format(FORMATS.opaqueTypeKeyName, valType, tName);
+ else
+ return string_format(FORMATS.opaqueTypeKey, valType);
+ end
+ end
+ error("Bad type '" .. valType .. "' to prepSimple");
+end
+
+local function prepSimpleKey(val, context)
+ local valType = type(val);
+ if (valType == "string") then
+ local l = string_len(val);
+ if ((l <= DEVTOOLS_LONG_STRING_CUTOFF) or
+ (DEVTOOLS_LONG_STRING_CUTOFF <= 0)) then
+ if (string_match(val, "^[a-zA-Z_][a-zA-Z0-9_]*$")) then
+ return val;
+ end
+ end
+ end
+ return string_format(FORMATS.bracketTableKey, prepSimple(val, context));
+end
+
+local function DevTools_InitFunctionCache(context)
+ local ret = {};
+
+ for _,k in ipairs(DT.functionSymbols) do
+ local v = getglobal(k);
+ if (type(v) == 'function') then
+ ret[v] = '[' .. k .. ']';
+ end
+ end
+
+ for k,v in pairs(getfenv(0)) do
+ if (type(v) == 'function') then
+ if (not ret[v]) then
+ ret[v] = '[' .. k .. ']';
+ end
+ end
+ end
+
+ return ret;
+end
+
+local function DevTools_InitUserdataCache(context)
+ local ret = {};
+
+ for _,k in ipairs(DT.userdataSymbols) do
+ local v = getglobal(k);
+ if (type(v) == 'table') then
+ local u = rawget(v,0);
+ if (type(u) == 'userdata') then
+ ret[u] = k .. '[0]';
+ end
+ end
+ end
+
+ for k,v in pairs(getfenv(0)) do
+ if (type(v) == 'table') then
+ local u = rawget(v, 0);
+ if (type(u) == 'userdata') then
+ if (not ret[u]) then
+ ret[u] = k .. '[0]';
+ end
+ end
+ end
+ end
+
+ return ret;
+end
+
+local function DevTools_Cache_Nil(self, value, newName)
+ return nil;
+end
+
+local function DevTools_Cache_Function(self, value, newName)
+ if (not self.fCache) then
+ self.fCache = DevTools_InitFunctionCache(self);
+ end
+ local name = self.fCache[value];
+ if ((not name) and newName) then
+ self.fCache[value] = newName;
+ end
+ return name;
+end
+
+local function DevTools_Cache_Userdata(self, value, newName)
+ if (not self.uCache) then
+ self.uCache = DevTools_InitUserdataCache(self);
+ end
+ local name = self.uCache[value];
+ if ((not name) and newName) then
+ self.uCache[value] = newName;
+ end
+ return name;
+end
+
+local function DevTools_Cache_Table(self, value, newName)
+ if (not self.tCache) then
+ self.tCache = {};
+ end
+ local name = self.tCache[value];
+ if ((not name) and newName) then
+ self.tCache[value] = newName;
+ end
+ return name;
+end
+
+local function DevTools_Write(self, msg)
+ DEFAULT_CHAT_FRAME:AddMessage(msg);
+end
+
+local DevTools_DumpValue;
+
+local function DevTools_DumpTableContents(val, prefix, firstPrefix, context)
+ local showCount = 0;
+ local oldDepth = context.depth;
+ local oldKey = context.key;
+
+ -- Use this to set the cache name
+ context:GetTableName(val, oldKey or 'value');
+
+ local iter = pairs(val);
+ local nextK, nextV = iter(val, nil);
+
+ while (nextK) do
+ local k,v = nextK, nextV;
+ nextK, nextV = iter(val, k);
+
+ showCount = showCount + 1;
+ if ((showCount <= DEVTOOLS_MAX_ENTRY_CUTOFF) or
+ (DEVTOOLS_MAX_ENTRY_CUTOFF <= 0)) then
+ local prepKey = prepSimpleKey(k, context);
+ if (oldKey == nil) then
+ context.key = prepKey;
+ elseif (string_sub(prepKey, 1, 1) == "[") then
+ context.key = oldKey .. prepKey
+ else
+ context.key = oldKey .. "." .. prepKey
+ end
+ context.depth = oldDepth + 1;
+
+ local rp = string_format(FORMATS.tableKeyAssignPrefix, firstPrefix,
+ prepKey);
+ firstPrefix = prefix;
+ DevTools_DumpValue(v, prefix, rp,
+ (nextK and ",") or '',
+ context);
+ end
+ end
+ local cutoff = showCount - DEVTOOLS_MAX_ENTRY_CUTOFF;
+ if ((cutoff > 0) and (DEVTOOLS_MAX_ENTRY_CUTOFF > 0)) then
+ context:Write(string_format(FORMATS.tableEntriesSkipped,firstPrefix,
+ cutoff));
+ end
+ context.key = oldKey;
+ context.depth = oldDepth;
+ return (showCount > 0)
+end
+
+-- Return the specified value
+function DevTools_DumpValue(val, prefix, firstPrefix, suffix, context)
+ local valType = type(val);
+
+ if (valType == "userdata") then
+ local uName = context:GetUserdataName(val, 'value');
+ if (uName) then
+ context:Write(string_format(FORMATS.opaqueTypeValName,
+ firstPrefix, valType, uName, suffix));
+ else
+ context:Write(string_format(FORMATS.opaqueTypeVal,
+ firstPrefix, valType, suffix));
+ end
+ return;
+ elseif (valType == "function") then
+ local fName = context:GetFunctionName(val, 'value');
+ if (fName) then
+ context:Write(string_format(FORMATS.opaqueTypeValName,
+ firstPrefix, valType, fName, suffix));
+ else
+ context:Write(string_format(FORMATS.opaqueTypeVal,
+ firstPrefix, valType, suffix));
+ end
+ return;
+ elseif (valType ~= "table") then
+ context:Write(string_format(FORMATS.simpleValue,
+ firstPrefix,prepSimple(val, context),
+ suffix));
+ return;
+ end
+
+ local cacheName = context:GetTableName(val);
+ if (cacheName) then
+ context:Write(string_format(FORMATS.tableReference,
+ firstPrefix, cacheName, suffix));
+ return;
+ end
+
+ if ((context.depth >= DEVTOOLS_DEPTH_CUTOFF) and
+ (DEVTOOLS_DEPTH_CUTOFF > 0)) then
+ context:Write(string_format(FORMATS.tableTooDeep,
+ firstPrefix, suffix));
+ return;
+ end
+
+ firstPrefix = firstPrefix .. "{";
+ local oldPrefix = prefix;
+ prefix = prefix .. DEVTOOLS_INDENT;
+
+ context:Write(firstPrefix);
+ firstPrefix = prefix;
+ local anyContents = DevTools_DumpTableContents(val, prefix, firstPrefix,
+ context);
+ context:Write(oldPrefix .. "}" .. suffix);
+end
+
+local function Pick_Cache_Function(func, setting)
+ if (setting) then
+ return func;
+ else
+ return DevTools_Cache_Nil;
+ end
+end
+
+function DevTools_RunDump(value, context)
+ local prefix = "";
+ local firstPrefix = prefix;
+
+ local valType = type(value);
+ if (type(value) == 'table') then
+ local any =
+ DevTools_DumpTableContents(value, prefix, firstPrefix, context);
+ if (context.Result) then
+ return context:Result();
+ end
+ if (not any) then
+ context:Write("empty result");
+ end
+ return;
+ end
+
+ DevTools_DumpValue(value, '', '', '', context);
+ if (context.Result) then
+ return context:Result();
+ end
+end
+
+-- Dump the specified list of value
+function DevTools_Dump(value, startKey)
+ local context = {
+ depth = 0,
+ key = startKey,
+ };
+
+ context.GetTableName = Pick_Cache_Function(DevTools_Cache_Table,
+ DEVTOOLS_USE_TABLE_CACHE);
+ context.GetFunctionName = Pick_Cache_Function(DevTools_Cache_Function,
+ DEVTOOLS_USE_FUNCTION_CACHE);
+ context.GetUserdataName = Pick_Cache_Function(DevTools_Cache_Userdata,
+ DEVTOOLS_USE_USERDATA_CACHE);
+ context.Write = DevTools_Write;
+
+ DevTools_RunDump(value, context);
+end
+
+function DevTools_DumpCommand(msg, editBox)
+ forceinsecure();
+ if (string_match(msg,"^[A-Za-z_][A-Za-z0-9_]*$")) then
+ WriteMessage("Dump: " .. msg);
+ local val = _G[msg];
+ local tmp = {};
+ if (val == nil) then
+ local key = string_format(FORMATS.tableKeyAssignPrefix,
+ '', prepSimpleKey(msg, {}));
+ WriteMessage(key .. "nil,");
+ else
+ tmp[msg] = val;
+ end
+ DevTools_Dump(tmp);
+ return;
+ end
+
+ WriteMessage("Dump: value=" .. msg);
+ local func,err = loadstring("return " .. msg);
+ if (not func) then
+ WriteMessage("Dump: ERROR: " .. err);
+ else
+ DevTools_Dump({ func() }, "value");
+ end
+end
+
+DT.functionSymbols = {};
+DT.userdataSymbols = {};
+
+local funcSyms = DT.functionSymbols;
+local userSyms = DT.userdataSymbols;
+
+for k,v in pairs(getfenv(0)) do
+ if (type(v) == 'function') then
+ table.insert(funcSyms, k);
+ elseif (type(v) == 'table') then
+ if (type(rawget(v,0)) == 'userdata') then
+ table.insert(userSyms, k);
+ end
+ end
+end
+
diff --git a/reference/AddOns/Blizzard_DebugTools/Localization.lua b/reference/AddOns/Blizzard_DebugTools/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_DebugTools/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_GMChatUI/Blizzard_GMChatUI.lua b/reference/AddOns/Blizzard_GMChatUI/Blizzard_GMChatUI.lua
new file mode 100644
index 0000000..339b9c7
--- /dev/null
+++ b/reference/AddOns/Blizzard_GMChatUI/Blizzard_GMChatUI.lua
@@ -0,0 +1,181 @@
+local ListOfGMs = {};
+
+function GMChatFrame_IsGM(playerName)
+ return ListOfGMs[strlower(playerName)];
+end
+
+function GMChatFrame_OnLoad(self)
+ local name = self:GetName();
+ for index, value in pairs(CHAT_FRAME_TEXTURES) do
+ local object = _G[name..value];
+ local objectType = object:GetObjectType();
+ if ( objectType == "Button" ) then
+ object:GetNormalTexture():SetVertexColor(0, 0, 0);
+ object:GetHighlightTexture():SetVertexColor(0, 0, 0);
+ object:GetPushedTexture():SetVertexColor(0, 0, 0);
+ elseif ( objectType == "Texture" ) then
+ _G[name..value]:SetVertexColor(0,0,0);
+ else
+ --error("Unhandled object type");
+ end
+ object:SetAlpha(0.4);
+ end
+
+ self:RegisterEvent("CHAT_MSG_WHISPER");
+ self:RegisterEvent("CHAT_MSG_WHISPER_INFORM");
+ self:RegisterEvent("UPDATE_CHAT_COLOR");
+ self:RegisterEvent("UPDATE_CHAT_WINDOWS");
+ self.flashTimer = 0;
+ self.lastGM = {};
+
+ GMChatOpenLog:Enable();
+
+ self:SetClampRectInsets(-35, 0, 30, 0);
+
+ self:SetFont(DEFAULT_CHAT_FRAME:GetFont());
+end
+
+function GMChatFrame_OnEvent(self, event, ...)
+ local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 = ...;
+ if ( event == "CHAT_MSG_WHISPER" and arg6 == "GM" ) then
+ local info = ChatTypeInfo["WHISPER"];
+
+ local pflag = "|TInterface\\ChatFrame\\UI-ChatIcon-Blizz.blp:0:2:0:-3|t ";
+
+ -- Search for icon links and replace them with texture links.
+ local term;
+ for tag in string.gmatch(arg1, "%b{}") do
+ term = strlower(string.gsub(tag, "[{}]", ""));
+ if ( ICON_TAG_LIST[term] and ICON_LIST[ICON_TAG_LIST[term]] ) then
+ arg1 = string.gsub(arg1, tag, ICON_LIST[ICON_TAG_LIST[term]] .. "0|t");
+ end
+ end
+
+ local body = format(CHAT_WHISPER_GET, pflag.."|HplayerGM:"..arg2..":"..arg11.."|h".."["..arg2.."]".."|h")..arg1;
+
+ ListOfGMs[strlower(arg2)] = true;
+ self:AddMessage(body, info.r, info.g, info.b, info.id);
+
+ if ( self.lastGMForCVar ~= arg2 and GMChatFrame:IsShown() ) then
+ SetCVar("lastTalkedToGM", arg2);
+ end
+ self.lastGMForCVar = arg2;
+
+ if ( not GMChatFrame:IsShown() ) then
+ GMChatStatusFrame:Show();
+ GMChatStatusFrame_Pulse();
+ table.insert(self.lastGM,arg2);
+ PlaySound("GM_ChatWarning");
+
+ DEFAULT_CHAT_FRAME:AddMessage(pflag.."|HGMChat|h["..GM_CHAT_STATUS_READY_DESCRIPTION.."]|h", info.r, info.g, info.b, info.id);
+ DEFAULT_CHAT_FRAME:SetHyperlinksEnabled(true);
+ DEFAULT_CHAT_FRAME.overrideHyperlinksEnabled = true;
+ SetButtonPulse(HelpMicroButton, 3600, 1.0);
+ SetButtonPulse(GMChatOpenLog, 3600, 1.0);
+ else
+ ChatEdit_SetLastTellTarget(arg2);
+ end
+ elseif ( event == "CHAT_MSG_WHISPER_INFORM" and GMChatFrame_IsGM(arg2) ) then
+ local info = ChatTypeInfo["WHISPER_INFORM"];
+
+ local pflag = "|TInterface\\ChatFrame\\UI-ChatIcon-Blizz.blp:0:2:0:-3|t ";
+
+ -- Search for icon links and replace them with texture links.
+ local term;
+ for tag in string.gmatch(arg1, "%b{}") do
+ term = strlower(string.gsub(tag, "[{}]", ""));
+ if ( ICON_TAG_LIST[term] and ICON_LIST[ICON_TAG_LIST[term]] ) then
+ arg1 = string.gsub(arg1, tag, ICON_LIST[ICON_TAG_LIST[term]] .. "0|t");
+ end
+ end
+
+ local body = format(CHAT_WHISPER_INFORM_GET, pflag.."|HplayerGM:"..arg2..":"..arg11.."|h".."["..arg2.."]".."|h")..arg1;
+
+ self:AddMessage(body, info.r, info.g, info.b, info.id);
+ elseif ( event == "UPDATE_CHAT_COLOR" ) then
+ local arg1, arg2, arg3, arg4 = ...
+ local info = ChatTypeInfo[strupper(arg1)];
+ if ( info ) then
+ info.r = arg2;
+ info.g = arg3;
+ info.b = arg4;
+ self:UpdateColorByID(info.id, info.r, info.g, info.b);
+
+ if ( strupper(arg1) == "WHISPER" ) then
+ info = ChatTypeInfo["REPLY"];
+ if ( info ) then
+ info.r = arg2;
+ info.g = arg3;
+ info.b = arg4;
+ self:UpdateColorByID(info.id, info.r, info.g, info.b);
+ end
+ end
+ end
+ elseif ( event == "UPDATE_CHAT_WINDOWS" ) then
+ local _, fontSize= FCF_GetChatWindowInfo(1);
+ if ( fontSize > 0 ) then
+ local fontFile, unused, fontFlags = DEFAULT_CHAT_FRAME:GetFont();
+ self:SetFont(fontFile, fontSize, fontFlags);
+ end
+ end
+end
+
+function GMChatFrame_OnShow(self)
+ GMChatStatusFrame:Hide();
+ GMChatOpenLog:Disable();
+ for _,gmName in ipairs(self.lastGM) do
+ ChatEdit_SetLastTellTarget(gmName);
+ end
+ table.wipe(self.lastGM);
+ if ( self.lastGMForCVar ) then
+ SetCVar("lastTalkedToGM", self.lastGMForCVar);
+ end
+
+ SetButtonPulse(HelpMicroButton, 0, 1); --Stop the buttons from pulsing.
+ SetButtonPulse(GMChatOpenLog, 0, 1);
+
+ self:SetScript("OnUpdate", GMChatFrame_OnUpdate);
+end
+
+function GMChatFrame_OnHide(self)
+ GMChatOpenLog:Enable();
+ SetCVar("lastTalkedToGM", "");
+end
+
+function GMChatFrame_OnUpdate(self, elapsed)
+ if ( DEFAULT_CHAT_FRAME.isUninteractable ) then
+ DEFAULT_CHAT_FRAME:SetHyperlinksEnabled(false);
+ end
+ DEFAULT_CHAT_FRAME.overrideHyperlinksEnabled = false;
+
+ self:SetScript("OnUpdate", nil);
+end
+
+function GMChatFrame_Show()
+ GMChatFrame:Show();
+end
+
+function GMChatFrame_Close()
+ GMChatFrame:Hide();
+end
+
+function GMChatStatusFrame_OnClick()
+ GMChatFrame_Show();
+end
+
+local function GMChatStatusFrame_PulseFunc(self, elapsed)
+ return abs(sin(elapsed*180*450--[[<--Number of times to pulse here]]));
+end
+
+local GMChatStatusFrame_PulseTable = {
+ totalTime = 900,
+ updateFunc = "SetAlpha",
+ getPosFunc = GMChatStatusFrame_PulseFunc,
+}
+
+function GMChatStatusFrame_Pulse()
+ local pulse = GMChatStatusFramePulse;
+ pulse:Show();
+ pulse:SetAlpha(0);
+ SetUpAnimation(pulse, GMChatStatusFrame_PulseTable, pulse.Hide);
+end
diff --git a/reference/AddOns/Blizzard_GMChatUI/Blizzard_GMChatUI.toc b/reference/AddOns/Blizzard_GMChatUI/Blizzard_GMChatUI.toc
new file mode 100644
index 0000000..da33825
--- /dev/null
+++ b/reference/AddOns/Blizzard_GMChatUI/Blizzard_GMChatUI.toc
@@ -0,0 +1,7 @@
+## Interface: 30300
+## Title: Blizzard_GMChatUI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_GMChatUI.lua
+Blizzard_GMChatUI.xml
+Localization.lua
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_GMChatUI/Blizzard_GMChatUI.xml b/reference/AddOns/Blizzard_GMChatUI/Blizzard_GMChatUI.xml
new file mode 100644
index 0000000..669aa2a
--- /dev/null
+++ b/reference/AddOns/Blizzard_GMChatUI/Blizzard_GMChatUI.xml
@@ -0,0 +1,263 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForDrag("LeftButton");
+
+
+ GameTooltip:Hide();
+
+
+ GMChatFrame:StartMoving();
+
+
+ GMChatFrame:StopMovingOrSizing();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 40);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+
+ GMChatStatusFrame_OnClick();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GMChatStatusFrame_OnClick();
+
+
+
+
+
+
+ GetGMTicket();
+ TemporaryEnchantFrame:SetPoint("TOPRIGHT", self:GetParent(), "TOPRIGHT", -205, (-self:GetHeight()));
+
+
+ GetGMTicket();
+ TemporaryEnchantFrame:SetPoint("TOPRIGHT", "UIParent", "TOPRIGHT", -180, -13);
+
+
+
+
diff --git a/reference/AddOns/Blizzard_GMChatUI/Localization.lua b/reference/AddOns/Blizzard_GMChatUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_GMChatUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_GMSurveyUI/Blizzard_GMSurveyUI.lua b/reference/AddOns/Blizzard_GMSurveyUI/Blizzard_GMSurveyUI.lua
new file mode 100644
index 0000000..cb37a64
--- /dev/null
+++ b/reference/AddOns/Blizzard_GMSurveyUI/Blizzard_GMSurveyUI.lua
@@ -0,0 +1,225 @@
+MAX_RADIO_BUTTONS = 5;
+MAX_SURVEY_QUESTIONS = 10;
+MAX_SURVEY_ANSWERS = 12;
+GMSURVEY_NA_SPACING = 60;
+GMSURVEY_NA_SHORT_SPACING = 40;
+GMSURVEY_RATING_SPACING = 80;
+GMSURVEY_RATING_SHORT_SPACING = 25;
+
+UIPanelWindows["GMSurveyFrame"] = { area = "center", pushable = 0, whileDead = 1 };
+
+function GMSurveyFrame_Update()
+ GMSurveyFrame.numQuestions = 0;
+ local surveyQuestion;
+ local questionFrame, questionFrameText;
+ for i=1, MAX_SURVEY_QUESTIONS do
+ surveyQuestion = GMSurveyQuestion(i);
+ questionFrame = _G["GMSurveyQuestion"..i];
+ if ( surveyQuestion ) then
+ GMSurveyFrame.numQuestions = GMSurveyFrame.numQuestions + 1;
+ questionFrameText = _G["GMSurveyQuestion"..i.."Text"];
+ questionFrameText:SetText(surveyQuestion);
+ for j=1, MAX_SURVEY_ANSWERS do
+ local surveyAnswer = GMSurveyAnswer(i,j);
+ local answerFrame = _G["GMSurveyQuestion"..i.."RadioButton"..(j-1)];
+ if ( surveyAnswer ) then
+ _G["GMSurveyQuestion"..i.."RadioButton"..(j-1).."Score"]:SetText(surveyAnswer);
+ answerFrame:Show();
+ else
+ answerFrame:Hide();
+ end
+ end
+ GMSurveyQuestion_SpaceAnswers(questionFrame, i);
+ if ( i == 1 ) then
+ questionFrame:SetHeight(questionFrameText:GetHeight() + 100);
+ else
+ questionFrame:SetHeight(questionFrameText:GetHeight() + 55);
+ end
+ questionFrame:Show();
+ else
+ questionFrame:Hide();
+ end
+ end
+
+ if ( GMSurveyFrame.numQuestions == 0 ) then
+ -- Had no questions
+ return;
+ end
+ GMSurveyAdditionalCommentsText:SetPoint("TOPLEFT", "GMSurveyQuestion"..GMSurveyFrame.numQuestions, "BOTTOMLEFT", 10, -10);
+end
+
+function GMSurveyScrollFrame_OnLoad(self)
+ ScrollFrame_OnLoad(self);
+ self.scrollBarHideable = 1;
+
+ self:RegisterEvent("ADDON_LOADED");
+ self:SetScript("OnEvent", GMSurveyScrollFrame_OnEvent);
+end
+
+function GMSurveyScrollFrame_OnEvent(self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local addonName = ...;
+ if ( not addonName or (addonName and addonName ~= "Blizzard_GMSurveyUI") ) then
+ return;
+ end
+
+ -- expand and contract scroll frame contents depending on scroll bar visibility
+ local scrollBar = _G[self:GetName().."ScrollBar"];
+ scrollBar.Show =
+ function (self)
+ local scrollFrame = self:GetParent();
+ local scrollFrameParent = scrollFrame:GetParent();
+ local scrollBarOffset = scrollFrame.scrollBarWidth;
+ -- adjust scroll frame width
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollFrameParent, "BOTTOMRIGHT", -55 - scrollBarOffset, 48);
+ scrollFrame:GetScrollChild():SetWidth(scrollFrame:GetWidth());
+
+ getmetatable(self).__index.Show(self);
+ end
+ scrollBar.Hide =
+ function (self)
+ local scrollFrame = self:GetParent();
+ local scrollFrameParent = scrollFrame:GetParent();
+ -- adjust scroll frame width
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollFrameParent, "BOTTOMRIGHT", -55, 48);
+ scrollFrame:GetScrollChild():SetWidth(scrollFrame:GetWidth());
+
+ getmetatable(self).__index.Hide(self);
+ end
+
+ self.scrollBarWidth = 25; -- looks better than actual scroll bar width
+
+ -- force an update
+ ScrollFrame_OnScrollRangeChanged(self);
+
+ -- we don't need this event any more
+ self:UnregisterEvent(event)
+ end
+end
+
+function GMSurveyQuestion_OnLoad(self)
+ self:SetBackdropBorderColor(0.5,0.5,0.5);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+ local name = self:GetName();
+ self.radioButtons = {
+ [0] = _G[name.."RadioButton0"],
+ _G[name.."RadioButton1"],
+ _G[name.."RadioButton2"],
+ _G[name.."RadioButton3"],
+ _G[name.."RadioButton4"],
+ _G[name.."RadioButton5"],
+ _G[name.."RadioButton6"],
+ _G[name.."RadioButton7"],
+ _G[name.."RadioButton8"],
+ _G[name.."RadioButton9"],
+ _G[name.."RadioButton10"],
+ _G[name.."RadioButton11"],
+ };
+end
+
+function GMSurveyQuestion_SpaceAnswers(self, questionNumber)
+ local radioButtons = self.radioButtons;
+
+ if (questionNumber == 1) then
+ radioButtons[0]:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 30, 45);
+ radioButtons[1]:SetPoint("LEFT", radioButtons[0], "RIGHT", GMSURVEY_NA_SHORT_SPACING, 0);
+ for j=2, MAX_SURVEY_ANSWERS-1 do
+ radioButtons[j]:SetPoint("LEFT", radioButtons[j-1], "RIGHT", GMSURVEY_RATING_SHORT_SPACING, 0);
+ end
+ _G[radioButtons[1]:GetName().."NetPromoterLow"]:Show();
+ _G[radioButtons[11]:GetName().."NetPromoterHigh"]:Show();
+ else
+ radioButtons[0]:SetPoint("BOTTOMLEFT", self, "BOTTOMLEFT", 30, 5);
+ radioButtons[1]:SetPoint("LEFT", radioButtons[0], "RIGHT", GMSURVEY_NA_SPACING, 0);
+ for j=2, MAX_SURVEY_ANSWERS -1 do
+ radioButtons[j]:SetPoint("LEFT", radioButtons[j-1], "RIGHT", GMSURVEY_RATING_SPACING, 0);
+ end
+ _G[radioButtons[1]:GetName().."NetPromoterLow"]:Hide();
+ _G[radioButtons[11]:GetName().."NetPromoterHigh"]:Hide();
+ end
+end
+
+function GMSurveyQuestion_OnShow(self)
+ GMSurveyRadioButton_OnClick(self.radioButtons[0]);
+end
+
+function GMSurveyRadioButton_OnClick(self)
+ local owner = self:GetParent();
+ local id = self:GetID();
+ if ( id == owner.selectedRadioButton ) then
+ return;
+ else
+ owner.selectedRadioButton = id;
+ end
+ local radioButtons = owner.radioButtons;
+ local radioButton;
+ for i=0, #radioButtons do
+ radioButton = radioButtons[i];
+ if ( i == owner.selectedRadioButton ) then
+ radioButton:SetChecked(1);
+ radioButton:Disable();
+ else
+ radioButton:SetChecked(0);
+ radioButton:Enable();
+ end
+ end
+end
+
+function GMSurveyCommentScrollFrame_OnLoad(self)
+ self.scrollBarHideable = 1;
+
+ self:RegisterEvent("ADDON_LOADED");
+ self:SetScript("OnEvent", GMSurveyCommentScrollFrame_OnEvent);
+end
+
+function GMSurveyCommentScrollFrame_OnEvent(self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local addonName = ...;
+ if ( not addonName or (addonName and addonName ~= "Blizzard_GMSurveyUI") ) then
+ return;
+ end
+
+ -- expand and contract scroll frame contents depending on scroll bar visibility
+ local scrollBar = _G[self:GetName().."ScrollBar"];
+ scrollBar.Show =
+ function (self)
+ local scrollFrame = self:GetParent();
+ -- adjust scroll frame width
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollFrame:GetParent(), "BOTTOMRIGHT", -10 - self:GetWidth(), 5);
+ local scrollFrameWidth = scrollFrame:GetWidth();
+ scrollFrame:GetScrollChild():SetWidth(scrollFrameWidth);
+ -- adjust content width
+ GMSurveyFrameComment:SetWidth(scrollFrameWidth);
+ getmetatable(self).__index.Show(self);
+ end
+ scrollBar.Hide =
+ function (self)
+ local scrollFrame = self:GetParent();
+ -- adjust scroll frame width
+ scrollFrame:SetPoint("BOTTOMRIGHT", scrollFrame:GetParent(), "BOTTOMRIGHT", -10, 5);
+ local scrollFrameWidth = scrollFrame:GetWidth();
+ scrollFrame:GetScrollChild():SetWidth(scrollFrameWidth);
+ -- adjust content width
+ GMSurveyFrameComment:SetWidth(scrollFrameWidth);
+ getmetatable(self).__index.Hide(self);
+ end
+
+ -- force an update
+ ScrollFrame_OnScrollRangeChanged(self);
+
+ -- we don't need this event any more
+ self:UnregisterEvent(event)
+ end
+end
+
+function GMSurveySubmitButton_OnClick()
+ for i=1, GMSurveyFrame.numQuestions do
+ GMSurveyAnswerSubmit(i, _G["GMSurveyQuestion"..i].selectedRadioButton, "");
+ end
+ GMSurveyCommentSubmit(GMSurveyFrameComment:GetText());
+ GMSurveySubmit();
+ TicketStatusFrame.hasGMSurvey = false;
+ HideUIPanel(GMSurveyFrame);
+ UIErrorsFrame:AddMessage(GMSURVEY_SUBMITTED, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1.0);
+end
diff --git a/reference/AddOns/Blizzard_GMSurveyUI/Blizzard_GMSurveyUI.toc b/reference/AddOns/Blizzard_GMSurveyUI/Blizzard_GMSurveyUI.toc
new file mode 100644
index 0000000..c95d392
--- /dev/null
+++ b/reference/AddOns/Blizzard_GMSurveyUI/Blizzard_GMSurveyUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard GM Survey UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_GMSurveyUI.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_GMSurveyUI/Blizzard_GMSurveyUI.xml b/reference/AddOns/Blizzard_GMSurveyUI/Blizzard_GMSurveyUI.xml
new file mode 100644
index 0000000..43c320f
--- /dev/null
+++ b/reference/AddOns/Blizzard_GMSurveyUI/Blizzard_GMSurveyUI.xml
@@ -0,0 +1,778 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GMSurveyRadioButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GMSurveyQuestion_OnLoad(self);
+
+
+ GMSurveyQuestion_OnShow(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GMSurveyFrameComment:SetFocus();
+
+
+ GMSurveyFrameComment:SetFocus();
+
+
+
+
+
+
+
+
+
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent());
+
+
+
+ ScrollingEdit_OnUpdate(self, 0, self:GetParent());
+
+
+ GMSurveyFrameComment:SetText("");
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.5,0.5,0.5);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TicketStatusFrame.hasGMSurvey = false;
+ TicketStatusFrame:Hide();
+ HideUIPanel(GMSurveyFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TicketStatusFrame.hasGMSurvey = false;
+ TicketStatusFrame:Hide();
+ HideUIPanel(GMSurveyFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GMSurveyHeader:SetWidth(GMSurveyHeaderText:GetWidth() + 100);
+
+
+ GMSurveyFrame_Update();
+ GMSurveyScrollFrame:SetVerticalScroll(0);
+
+
+
+
diff --git a/reference/AddOns/Blizzard_GMSurveyUI/Localization.lua b/reference/AddOns/Blizzard_GMSurveyUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_GMSurveyUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_GlyphUI/Blizzard_GlyphUI.lua b/reference/AddOns/Blizzard_GlyphUI/Blizzard_GlyphUI.lua
new file mode 100644
index 0000000..260027f
--- /dev/null
+++ b/reference/AddOns/Blizzard_GlyphUI/Blizzard_GlyphUI.lua
@@ -0,0 +1,421 @@
+GLYPHTYPE_MAJOR = 1;
+GLYPHTYPE_MINOR = 2;
+
+GLYPH_MINOR = { r = 0, g = 0.25, b = 1};
+GLYPH_MAJOR = { r = 1, g = 0.25, b = 0};
+
+GLYPH_SLOTS = {};
+-- Empty Texture
+GLYPH_SLOTS[0] = { left = 0.78125, right = 0.91015625, top = 0.69921875, bottom = 0.828125 };
+-- Major Glyphs
+GLYPH_SLOTS[3] = { left = 0.392578125, right = 0.521484375, top = 0.87109375, bottom = 1 };
+GLYPH_SLOTS[1] = { left = 0, right = 0.12890625, top = 0.87109375, bottom = 1 };
+GLYPH_SLOTS[5] = { left = 0.26171875, right = 0.390625, top = 0.87109375, bottom = 1 };
+-- Minor Glyphs
+GLYPH_SLOTS[2] = { left = 0.130859375, right = 0.259765625, top = 0.87109375, bottom = 1 };
+GLYPH_SLOTS[6] = { left = 0.654296875, right = 0.783203125, top = 0.87109375, bottom = 1 };
+GLYPH_SLOTS[4] = { left = 0.5234375, right = 0.65234375, top = 0.87109375, bottom = 1 };
+
+NUM_GLYPH_SLOTS = 6;
+
+local slotAnimations = {};
+local TOPLEFT, TOP, TOPRIGHT, BOTTOMRIGHT, BOTTOM, BOTTOMLEFT = 3, 1, 5, 4, 2, 6;
+slotAnimations[TOPLEFT] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = -85, ["yStart"] = 17, ["yStop"] = 60};
+slotAnimations[TOP] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = -13, ["yStart"] = 17, ["yStop"] = 100};
+slotAnimations[TOPRIGHT] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = 59, ["yStart"] = 17, ["yStop"] = 60};
+slotAnimations[BOTTOM] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = -13, ["yStart"] = 17, ["yStop"] = -64};
+slotAnimations[BOTTOMLEFT] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = -87, ["yStart"] = 18, ["yStop"] = -27};
+slotAnimations[BOTTOMRIGHT] = {["point"] = "CENTER", ["xStart"] = -13, ["xStop"] = 61, ["yStart"] = 18, ["yStop"] = -27};
+
+local HIGHLIGHT_BASEALPHA = .4;
+
+
+function GlyphFrame_Toggle ()
+ TalentFrame_LoadUI();
+ if ( PlayerTalentFrame_ToggleGlyphFrame ) then
+ PlayerTalentFrame_ToggleGlyphFrame(GetActiveTalentGroup());
+ end
+end
+
+function GlyphFrame_Open ()
+ TalentFrame_LoadUI();
+ if ( PlayerTalentFrame_OpenGlyphFrame ) then
+ PlayerTalentFrame_OpenGlyphFrame(GetActiveTalentGroup());
+ end
+end
+
+
+function GlyphFrameGlyph_OnLoad (self)
+ local name = self:GetName();
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self.glyph = _G[name .. "Glyph"];
+ self.setting = _G[name .. "Setting"];
+ self.highlight = _G[name .. "Highlight"];
+ self.background = _G[name .. "Background"];
+ self.ring = _G[name .. "Ring"];
+ self.shine = _G[name .. "Shine"];
+ self.elapsed = 0;
+ self.tintElapsed = 0;
+ self.glyphType = nil;
+end
+
+function GlyphFrameGlyph_UpdateSlot (self)
+ local id = self:GetID();
+ local talentGroup = PlayerTalentFrame and PlayerTalentFrame.talentGroup;
+ local enabled, glyphType, glyphSpell, iconFilename = GetGlyphSocketInfo(id, talentGroup);
+
+ local isMinor = glyphType == 2;
+ if ( isMinor ) then
+ GlyphFrameGlyph_SetGlyphType(self, GLYPHTYPE_MINOR);
+ else
+ GlyphFrameGlyph_SetGlyphType(self, GLYPHTYPE_MAJOR);
+ end
+
+ self.elapsed = 0;
+ self.tintElapsed = 0;
+
+ local slotAnimation = slotAnimations[id];
+ if ( not enabled ) then
+ slotAnimation.glyph = nil;
+ if ( slotAnimation.sparkle ) then
+ slotAnimation.sparkle:StopAnimating();
+ slotAnimation.sparkle:Hide();
+ end
+ self.shine:Hide();
+ self.background:Hide();
+ self.glyph:Hide();
+ self.ring:Hide();
+ self.setting:SetTexture("Interface\\Spellbook\\UI-GlyphFrame-Locked");
+ self.setting:SetTexCoord(.1, .9, .1, .9);
+ elseif ( not glyphSpell ) then
+ slotAnimation.glyph = nil;
+ if ( slotAnimation.sparkle ) then
+ slotAnimation.sparkle:StopAnimating();
+ slotAnimation.sparkle:Hide();
+ end
+ self.spell = nil;
+ self.shine:Show();
+ self.background:Show();
+ self.background:SetTexCoord(GLYPH_SLOTS[0].left, GLYPH_SLOTS[0].right, GLYPH_SLOTS[0].top, GLYPH_SLOTS[0].bottom);
+ if ( not GlyphMatchesSocket(id) ) then
+ self.background:SetAlpha(1);
+ end
+ self.glyph:Hide();
+ self.ring:Show();
+ else
+ slotAnimation.glyph = true;
+ self.spell = glyphSpell;
+ self.shine:Show();
+ self.background:Show();
+ self.background:SetAlpha(1);
+ self.background:SetTexCoord(GLYPH_SLOTS[id].left, GLYPH_SLOTS[id].right, GLYPH_SLOTS[id].top, GLYPH_SLOTS[id].bottom);
+ self.glyph:Show();
+ if ( iconFilename ) then
+ self.glyph:SetTexture(iconFilename);
+ else
+ self.glyph:SetTexture("Interface\\Spellbook\\UI-Glyph-Rune1");
+ end
+ self.ring:Show();
+ end
+end
+
+function GlyphFrameGlyph_SetGlyphType (glyph, glyphType)
+ glyph.glyphType = glyphType;
+
+ glyph.setting:SetTexture("Interface\\Spellbook\\UI-GlyphFrame");
+ if ( glyphType == GLYPHTYPE_MAJOR ) then
+ glyph.glyph:SetVertexColor(GLYPH_MAJOR.r, GLYPH_MAJOR.g, GLYPH_MAJOR.b);
+ glyph.setting:SetWidth(108);
+ glyph.setting:SetHeight(108);
+ glyph.setting:SetTexCoord(0.740234375, 0.953125, 0.484375, 0.697265625);
+ glyph.highlight:SetWidth(108);
+ glyph.highlight:SetHeight(108);
+ glyph.highlight:SetTexCoord(0.740234375, 0.953125, 0.484375, 0.697265625);
+ glyph.ring:SetWidth(82);
+ glyph.ring:SetHeight(82);
+ glyph.ring:SetPoint("CENTER", glyph, "CENTER", 0, -1);
+ glyph.ring:SetTexCoord(0.767578125, 0.92578125, 0.32421875, 0.482421875);
+ glyph.shine:SetTexCoord(0.9609375, 1, 0.9609375, 1);
+ glyph.background:SetWidth(70);
+ glyph.background:SetHeight(70);
+ else
+ glyph.glyph:SetVertexColor(GLYPH_MINOR.r, GLYPH_MINOR.g, GLYPH_MINOR.b);
+ glyph.setting:SetWidth(86);
+ glyph.setting:SetHeight(86);
+ glyph.setting:SetTexCoord(0.765625, 0.927734375, 0.15625, 0.31640625);
+ glyph.highlight:SetWidth(86);
+ glyph.highlight:SetHeight(86);
+ glyph.highlight:SetTexCoord(0.765625, 0.927734375, 0.15625, 0.31640625);
+ glyph.ring:SetWidth(62);
+ glyph.ring:SetHeight(62);
+ glyph.ring:SetPoint("CENTER", glyph, "CENTER", 0, 1);
+ glyph.ring:SetTexCoord(0.787109375, 0.908203125, 0.033203125, 0.154296875);
+ glyph.shine:SetTexCoord(0.9609375, 1, 0.921875, 0.9609375);
+ glyph.background:SetWidth(64);
+ glyph.background:SetHeight(64);
+ end
+end
+
+function GlyphFrameGlyph_OnUpdate (self, elapsed)
+ local GLYPHFRAMEGLYPH_FINISHED = 6;
+ local GLYPHFRAMEGLYPH_START = 2;
+ local GLYPHFRAMEGLYPH_HOLD = 4;
+
+ local hasGlyph = self.glyph:IsShown();
+
+ if ( hasGlyph or self.elapsed > 0 ) then
+ self.elapsed = self.elapsed + elapsed;
+
+ elapsed = self.elapsed;
+ if ( elapsed >= GLYPHFRAMEGLYPH_FINISHED ) then
+ self.setting:SetAlpha(.6);
+ self.elapsed = 0;
+ elseif ( elapsed <= GLYPHFRAMEGLYPH_START ) then
+ self.setting:SetAlpha(.6 + (.4 * elapsed/GLYPHFRAMEGLYPH_START));
+ elseif ( elapsed >= GLYPHFRAMEGLYPH_HOLD ) then
+ self.setting:SetAlpha(1 - (.4 * (elapsed - GLYPHFRAMEGLYPH_HOLD) / (GLYPHFRAMEGLYPH_FINISHED - GLYPHFRAMEGLYPH_HOLD) ) );
+ end
+ elseif ( self.background:IsShown() ) then
+ self.setting:SetAlpha(.6);
+ else
+ self.setting:SetAlpha(.6);
+ end
+
+
+ local TINT_START, TINT_HOLD, TINT_FINISHED = .6, .8, 1.6;
+
+
+ local id = self:GetID();
+ if ( not hasGlyph and self.background:IsShown() and GlyphMatchesSocket(id) ) then
+ self.tintElapsed = self.tintElapsed + elapsed;
+
+ self.background:SetTexCoord(GLYPH_SLOTS[id].left, GLYPH_SLOTS[id].right, GLYPH_SLOTS[id].top, GLYPH_SLOTS[id].bottom);
+
+ local highlight = false;
+ if ( not self:IsMouseOver() ) then
+ self.highlight:Show();
+ highlight = true;
+ end
+
+ local alpha;
+ elapsed = self.tintElapsed;
+ if ( elapsed >= TINT_FINISHED ) then
+ alpha = 1;
+
+ self.tintElapsed = 0;
+ elseif ( elapsed <= TINT_START ) then
+ alpha = 1 - (.6 * elapsed/TINT_START);
+ elseif ( elapsed >= TINT_HOLD ) then
+ alpha = .4 + (.6 * (elapsed - TINT_HOLD) / (TINT_FINISHED - TINT_HOLD));
+ end
+
+ if ( alpha ) then
+ self.background:SetAlpha(alpha);
+ if ( highlight ) then
+ self.highlight:SetAlpha(HIGHLIGHT_BASEALPHA * alpha);
+ else
+ self.highlight:SetAlpha(HIGHLIGHT_BASEALPHA);
+ end
+ end
+ elseif ( not hasGlyph ) then
+ self.background:SetTexCoord(GLYPH_SLOTS[0].left, GLYPH_SLOTS[0].right, GLYPH_SLOTS[0].top, GLYPH_SLOTS[0].bottom);
+ self.background:SetAlpha(1);
+ end
+
+ if ( self.hasCursor and SpellIsTargeting() ) then
+ if ( GlyphMatchesSocket(self:GetID()) and self.background:IsShown() ) then
+ SetCursor("CAST_CURSOR");
+ else
+ SetCursor("CAST_ERROR_CURSOR");
+ end
+ end
+end
+
+function GlyphFrameGlyph_OnClick (self, button)
+ local id = self:GetID();
+ local talentGroup = PlayerTalentFrame and PlayerTalentFrame.talentGroup;
+
+ if ( IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow() ) then
+ local link = GetGlyphLink(id, talentGroup);
+ if ( link ) then
+ ChatEdit_InsertLink(link);
+ end
+ elseif ( button == "RightButton" ) then
+ if ( IsShiftKeyDown() and talentGroup == GetActiveTalentGroup() ) then
+ local glyphName;
+ local _, _, glyphSpell = GetGlyphSocketInfo(id, talentGroup);
+ if ( glyphSpell ) then
+ glyphName = GetSpellInfo(glyphSpell);
+ local dialog = StaticPopup_Show("CONFIRM_REMOVE_GLYPH", glyphName);
+ dialog.data = id;
+ end
+ end
+ elseif ( talentGroup == GetActiveTalentGroup() ) then
+ if ( self.glyph:IsShown() and GlyphMatchesSocket(id) ) then
+ local dialog = StaticPopup_Show("CONFIRM_GLYPH_PLACEMENT", id);
+ dialog.data = id;
+ else
+ PlaceGlyphInSocket(id);
+ end
+ end
+end
+
+function GlyphFrameGlyph_OnEnter (self)
+ self.hasCursor = true;
+ if ( self.background:IsShown() ) then
+ self.highlight:Show();
+ end
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetGlyph(self:GetID(), PlayerTalentFrame and PlayerTalentFrame.talentGroup);
+ GameTooltip:Show();
+end
+
+function GlyphFrameGlyph_OnLeave (self)
+ self.hasCursor = nil;
+ self.highlight:Hide();
+ GameTooltip:Hide();
+end
+
+local GLYPH_SPARKLE_SIZES = 3;
+local GLYPH_DURATION_MODIFIERS = { 1.25, 1.5, 1.8 };
+
+function GlyphFrame_OnUpdate (self, elapsed)
+ for i = 1, #slotAnimations do
+ local animation = slotAnimations[i];
+ if ( animation.glyph and not (animation.sparkle and animation.sparkle.animGroup:IsPlaying()) ) then
+ local sparkleSize = math.random(GLYPH_SPARKLE_SIZES);
+ GlyphFrame_StartSlotAnimation(i, sparkleSize * GLYPH_DURATION_MODIFIERS[sparkleSize], sparkleSize);
+ end
+ end
+end
+
+function GlyphFrame_PulseGlow ()
+ GlyphFrame.glow:Show();
+ GlyphFrame.glow.pulse:Play();
+end
+
+function GlyphFrame_OnShow (self)
+ GlyphFrame_Update();
+end
+
+function GlyphFrame_OnLoad (self)
+ local name = self:GetName();
+ self.background = _G[name .. "Background"];
+ self.sparkleFrame = SparkleFrame:New(self);
+ self:RegisterEvent("ADDON_LOADED");
+ self:RegisterEvent("GLYPH_ADDED");
+ self:RegisterEvent("GLYPH_REMOVED");
+ self:RegisterEvent("GLYPH_UPDATED");
+ self:RegisterEvent("USE_GLYPH");
+ self:RegisterEvent("PLAYER_LEVEL_UP");
+end
+
+function GlyphFrame_OnEnter (self)
+ if ( SpellIsTargeting() ) then
+ SetCursor("CAST_ERROR_CURSOR");
+ end
+end
+
+function GlyphFrame_OnLeave (self)
+
+end
+
+function GlyphFrame_OnEvent (self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local name = ...;
+ if ( name == "Blizzard_GlyphUI" and IsAddOnLoaded("Blizzard_TalentUI") or name == "Blizzard_TalentUI" ) then
+ self:ClearAllPoints();
+ self:SetParent(PlayerTalentFrame);
+ self:SetAllPoints();
+ -- make sure this shows up above the talent UI
+ local frameLevel = self:GetParent():GetFrameLevel() + 4;
+ self:SetFrameLevel(frameLevel);
+ PlayerTalentFrameCloseButton:SetFrameLevel(frameLevel + 1);
+ end
+ elseif ( event == "USE_GLYPH" or event == "PLAYER_LEVEL_UP" ) then
+ GlyphFrame_Update();
+ elseif ( event == "GLYPH_ADDED" or event == "GLYPH_REMOVED" or event == "GLYPH_UPDATED" ) then
+ local index = ...;
+ local glyph = _G["GlyphFrameGlyph" .. index];
+ if ( glyph and self:IsVisible() ) then
+ -- update the glyph
+ GlyphFrameGlyph_UpdateSlot(glyph);
+ -- play effects based on the event and glyph type
+ GlyphFrame_PulseGlow();
+ local glyphType = glyph.glyphType;
+ if ( event == "GLYPH_ADDED" or event == "GLYPH_UPDATED" ) then
+ if ( glyphType == GLYPHTYPE_MINOR ) then
+ PlaySound("Glyph_MinorCreate");
+ elseif ( glyphType == GLYPHTYPE_MAJOR ) then
+ PlaySound("Glyph_MajorCreate");
+ end
+ elseif ( event == "GLYPH_REMOVED" ) then
+ GlyphFrame_StopSlotAnimation(index);
+ if ( glyphType == GLYPHTYPE_MINOR ) then
+ PlaySound("Glyph_MinorDestroy");
+ elseif ( glyphType == GLYPHTYPE_MAJOR ) then
+ PlaySound("Glyph_MajorDestroy");
+ end
+ end
+ end
+
+ --Refresh tooltip!
+ if ( GameTooltip:IsOwned(glyph) ) then
+ GlyphFrameGlyph_OnEnter(glyph);
+ end
+ end
+end
+
+function GlyphFrame_Update ()
+ local isActiveTalentGroup =
+ PlayerTalentFrame and not PlayerTalentFrame.pet and
+ PlayerTalentFrame.talentGroup == GetActiveTalentGroup(PlayerTalentFrame.pet);
+ SetDesaturation(GlyphFrame.background, not isActiveTalentGroup);
+
+ for i = 1, NUM_GLYPH_SLOTS do
+ GlyphFrameGlyph_UpdateSlot(_G["GlyphFrameGlyph"..i]);
+ end
+end
+
+function GlyphFrame_StartSlotAnimation (slotID, duration, size)
+ local animation = slotAnimations[slotID];
+
+ -- init texture to animate
+ local sparkleName = "GlyphFrameSparkle"..slotID;
+ local sparkle = _G[sparkleName];
+ if ( not sparkle ) then
+ sparkle = GlyphFrame:CreateTexture(sparkleName, "OVERLAY", "GlyphSparkleTexture");
+ sparkle.slotID = slotID;
+ end
+ local template;
+ if ( size == 1 ) then
+ template = "SparkleTextureSmall";
+ elseif ( size == 2 ) then
+ template = "SparkleTextureKindaSmall";
+ else
+ template = "SparkleTextureNormal";
+ end
+ local sparkleDim = SparkleDimensions[template];
+ sparkle:SetHeight(sparkleDim.height);
+ sparkle:SetWidth(sparkleDim.width);
+ sparkle:SetPoint("CENTER", GlyphFrame, animation.point, animation.xStart, animation.yStart);
+ sparkle:Show();
+
+ -- init animation
+ local offsetX, offsetY = animation.xStop - animation.xStart, animation.yStop - animation.yStart;
+ local animGroupAnim = sparkle.animGroup.translate;
+ animGroupAnim:SetOffset(offsetX, offsetY);
+ animGroupAnim:SetDuration(duration);
+ animGroupAnim:Play();
+
+ animation.sparkle = sparkle;
+end
+
+function GlyphFrame_StopSlotAnimation (slotID)
+ local animation = slotAnimations[slotID];
+ if ( animation.sparkle ) then
+ animation.sparkle.animGroup:Stop();
+ animation.sparkle:Hide();
+ animation.sparkle = nil;
+ end
+end
diff --git a/reference/AddOns/Blizzard_GlyphUI/Blizzard_GlyphUI.toc b/reference/AddOns/Blizzard_GlyphUI/Blizzard_GlyphUI.toc
new file mode 100644
index 0000000..db2be70
--- /dev/null
+++ b/reference/AddOns/Blizzard_GlyphUI/Blizzard_GlyphUI.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## Title: Blizzard Glyph UI
+## Notes: Get some cool tats and mod your spells.
+## Secure: 1
+## Author: Blizzard Entertainment
+## Version: 1.0
+## LoadOnDemand: 1
+Blizzard_GlyphUI.xml
+Localization.lua
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_GlyphUI/Blizzard_GlyphUI.xml b/reference/AddOns/Blizzard_GlyphUI/Blizzard_GlyphUI.xml
new file mode 100644
index 0000000..ad2a997
--- /dev/null
+++ b/reference/AddOns/Blizzard_GlyphUI/Blizzard_GlyphUI.xml
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GlyphFrameGlyph_OnLoad(self);
+
+
+ GlyphFrameGlyph_UpdateSlot(self);
+
+
+ GlyphFrameGlyph_OnClick(self, button, down);
+
+
+ GlyphFrameGlyph_OnEnter(self, motion);
+
+
+ GlyphFrameGlyph_OnLeave(self, motion);
+
+
+ GlyphFrameGlyph_OnUpdate(self, elapsed);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():Hide();
+
+
+ self:GetParent():Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_GlyphUI/Localization.lua b/reference/AddOns/Blizzard_GlyphUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_GlyphUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_GuildBankUI/Blizzard_GuildBankUI.lua b/reference/AddOns/Blizzard_GuildBankUI/Blizzard_GuildBankUI.lua
new file mode 100644
index 0000000..d1c052a
--- /dev/null
+++ b/reference/AddOns/Blizzard_GuildBankUI/Blizzard_GuildBankUI.lua
@@ -0,0 +1,788 @@
+MAX_GUILDBANK_SLOTS_PER_TAB = 98;
+NUM_SLOTS_PER_GUILDBANK_GROUP = 14;
+NUM_GUILDBANK_ICONS_SHOWN = 0;
+NUM_GUILDBANK_ICONS_PER_ROW = 4;
+NUM_GUILDBANK_ICON_ROWS = 4;
+GUILDBANK_ICON_ROW_HEIGHT = 36;
+NUM_GUILDBANK_COLUMNS = 7;
+MAX_TRANSACTIONS_SHOWN = 21;
+GUILDBANK_TRANSACTION_HEIGHT = 13;
+
+UIPanelWindows["GuildBankFrame"] = { area = "doublewide", pushable = 0, width = 769 };
+
+--REMOVE ME!
+TABARDBACKGROUNDUPPER = "Textures\\GuildEmblems\\Background_%s_TU_U";
+TABARDBACKGROUNDLOWER = "Textures\\GuildEmblems\\Background_%s_TL_U";
+TABARDEMBLEMUPPER = "Textures\\GuildEmblems\\Emblem_%s_15_TU_U";
+TABARDEMBLEMLOWER = "Textures\\GuildEmblems\\Emblem_%s_15_TL_U";
+TABARDBORDERUPPER = "Textures\\GuildEmblems\\Border_%s_02_TU_U";
+TABARDBORDERLOWER = "Textures\\GuildEmblems\\Border_%s_02_TL_U";
+TABARDBACKGROUNDID = 1;
+TABARDEMBLEMID = 1;
+TABARDBORDERID = 1;
+
+GUILD_BANK_LOG_TIME_PREPEND = "|cff009999 ";
+
+function GuildBankFrame_ChangeBackground(id)
+ if ( id > 50 ) then
+ id = 1;
+ elseif ( id < 0 ) then
+ id = 50;
+ end
+ TABARDBACKGROUNDID = id;
+ GuildBankFrame_UpdateEmblem();
+end
+function GuildBankFrame_ChangeEmblem(id)
+ if ( id > 169 ) then
+ id = 1;
+ elseif ( id < 0 ) then
+ id = 169;
+ end
+ TABARDEMBLEMID = id;
+ GuildBankFrame_UpdateEmblem();
+end
+function GuildBankFrame_ChangeBorder(id)
+ if ( id > 9 ) then
+ id = 1;
+ elseif ( id < 0 ) then
+ id = 9;
+ end
+ TABARDBORDERID = id;
+ GuildBankFrame_UpdateEmblem();
+end
+
+function GuildBankFrame_UpdateEmblem()
+ local tabardBGID = TABARDBACKGROUNDID;
+ if ( tabardBGID < 10 ) then
+ tabardBGID = "0"..tabardBGID;
+ end
+ local tabardEmblemID = TABARDEMBLEMID;
+ if ( tabardEmblemID < 10 ) then
+ tabardEmblemID = "0"..tabardEmblemID;
+ end
+ local tabardBorderID = TABARDBORDERID;
+ if ( tabardBorderID < 10 ) then
+ tabardBorderID = "0"..tabardBorderID;
+ end
+ GuildBankEmblemBackgroundUL:SetTexture(format(TABARDBACKGROUNDUPPER, tabardBGID));
+ GuildBankEmblemBackgroundUR:SetTexture(format(TABARDBACKGROUNDUPPER, tabardBGID));
+ GuildBankEmblemBackgroundBL:SetTexture(format(TABARDBACKGROUNDLOWER, tabardBGID));
+ GuildBankEmblemBackgroundBR:SetTexture(format(TABARDBACKGROUNDLOWER, tabardBGID));
+
+ GuildBankEmblemUL:SetTexture(format(TABARDEMBLEMUPPER, tabardEmblemID));
+ GuildBankEmblemUR:SetTexture(format(TABARDEMBLEMUPPER, tabardEmblemID));
+ GuildBankEmblemBL:SetTexture(format(TABARDEMBLEMLOWER, tabardEmblemID));
+ GuildBankEmblemBR:SetTexture(format(TABARDEMBLEMLOWER, tabardEmblemID));
+
+ GuildBankEmblemBorderUL:SetTexture(format(TABARDBORDERUPPER, tabardBorderID));
+ GuildBankEmblemBorderUR:SetTexture(format(TABARDBORDERUPPER, tabardBorderID));
+ GuildBankEmblemBorderBL:SetTexture(format(TABARDBORDERLOWER, tabardBorderID));
+ GuildBankEmblemBorderBR:SetTexture(format(TABARDBORDERLOWER, tabardBorderID));
+end
+
+
+function GuildBankFrame_OnLoad(self)
+ NUM_GUILDBANK_ICONS_SHOWN = NUM_GUILDBANK_ICONS_PER_ROW * NUM_GUILDBANK_ICON_ROWS;
+ self:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED");
+ self:RegisterEvent("GUILDBANK_ITEM_LOCK_CHANGED");
+ self:RegisterEvent("GUILDBANK_UPDATE_TABS");
+ self:RegisterEvent("GUILDBANK_UPDATE_MONEY");
+ self:RegisterEvent("GUILDBANK_UPDATE_WITHDRAWMONEY");
+ self:RegisterEvent("GUILD_ROSTER_UPDATE");
+ self:RegisterEvent("GUILDBANKLOG_UPDATE");
+ self:RegisterEvent("GUILDTABARD_UPDATE");
+ self:RegisterEvent("GUILDBANK_UPDATE_TEXT");
+ self:RegisterEvent("GUILDBANK_TEXT_CHANGED");
+ self:RegisterEvent("PLAYER_MONEY");
+ -- Set the button id's
+ local index, column, button;
+ for i=1, MAX_GUILDBANK_SLOTS_PER_TAB do
+ index = mod(i, NUM_SLOTS_PER_GUILDBANK_GROUP);
+ if ( index == 0 ) then
+ index = NUM_SLOTS_PER_GUILDBANK_GROUP;
+ end
+ column = ceil((i-0.5)/NUM_SLOTS_PER_GUILDBANK_GROUP);
+ button = _G["GuildBankColumn"..column.."Button"..index];
+ button:SetID(i);
+ end
+ GuildBankFrame.mode = "bank";
+ GuildBankFrame.numTabs = 4;
+ GuildBankFrame_UpdateTabs();
+ GuildBankFrame_UpdateTabard();
+
+end
+
+function GuildBankFrame_OnEvent(self, event, ...)
+ if ( not GuildBankFrame:IsVisible() ) then
+ return;
+ end
+ if ( event == "GUILDBANKBAGSLOTS_CHANGED" or event =="GUILDBANK_ITEM_LOCK_CHANGED" ) then
+ GuildBankFrame_UpdateTabs();
+ GuildBankFrame_Update();
+ elseif ( event == "GUILDBANK_UPDATE_TABS" or event == "GUILD_ROSTER_UPDATE" ) then
+ if ( event == "GUILD_ROSTER_UPDATE" and not select(1, ...) and GuildBankFrame.noViewableTabs and GuildBankFrame.mode == "bank" ) then
+ -- if rank changed while at the bank tab and not having any viewable tabs, query for new item data
+ QueryGuildBankTab(GetCurrentGuildBankTab());
+ end
+
+ GuildBankFrame_SelectAvailableTab();
+
+ if ( GuildBankFrameBuyInfo:IsShown() ) then
+ GuildBankFrame_UpdateTabBuyingInfo();
+ end
+ if ( CanEditGuildTabInfo(GetCurrentGuildBankTab()) ) then
+ GuildBankInfoSaveButton:Show();
+ else
+ GuildBankInfoSaveButton:Hide();
+ end
+ elseif ( event == "GUILDBANKLOG_UPDATE" ) then
+ if ( GuildBankFrame.mode == "log" ) then
+ GuildBankFrame_UpdateLog();
+ else
+ GuildBankFrame_UpdateMoneyLog();
+ end
+ GuildBankLogScroll();
+ elseif ( event == "GUILDTABARD_UPDATE" ) then
+ GuildBankFrame_UpdateTabard();
+ elseif ( event == "GUILDBANK_UPDATE_MONEY" or event == "GUILDBANK_UPDATE_WITHDRAWMONEY" ) then
+ GuildBankFrame_UpdateWithdrawMoney();
+ elseif ( event == "GUILDBANK_UPDATE_TEXT" ) then
+ GuildBankFrame_UpdateTabInfo(...);
+ elseif ( event == "GUILDBANK_TEXT_CHANGED" ) then
+ local arg1 = ...
+ if ( GetCurrentGuildBankTab() == tonumber(arg1) ) then
+ QueryGuildBankText(arg1);
+ end
+ elseif ( event == "PLAYER_MONEY" ) then
+ if ( GuildBankFrameBuyInfo:IsShown() ) then
+ GuildBankFrame_UpdateTabBuyingInfo();
+ end
+ end
+end
+
+function GuildBankFrame_SelectAvailableTab()
+ --If the selected tab is notViewable then select the next available one
+ if ( IsTabViewable(GetCurrentGuildBankTab()) ) then
+ GuildBankFrame_UpdateTabs();
+ GuildBankFrame_Update();
+ else
+ if ( GuildBankFrame.nextAvailableTab ) then
+ GuildBankTab_OnClick(_G["GuildBankTab" .. GuildBankFrame.nextAvailableTab], "LeftButton", GuildBankFrame.nextAvailableTab);
+ else
+ GuildBankFrame_UpdateTabs();
+ GuildBankFrame_Update();
+ end
+ end
+end
+
+function GuildBankFrame_OnShow()
+ GuildBankFrameTab_OnClick(GuildBankFrameTab1, 1);
+ GuildBankFrame_UpdateTabard();
+ GuildBankFrame_SelectAvailableTab();
+ PlaySound("GuildVaultOpen");
+end
+
+function GuildBankFrame_Update()
+ --Figure out which mode you're in and which tab is selected
+ if ( GuildBankFrame.mode == "bank" ) then
+ -- Determine whether its the buy tab or not
+ GuildBankFrameLog:Hide();
+ GuildBankInfo:Hide();
+ local tab = GetCurrentGuildBankTab();
+ if ( GuildBankFrame.noViewableTabs ) then
+ GuildBankFrame_HideColumns();
+ GuildBankFrameBuyInfo:Hide();
+ GuildBankErrorMessage:SetText(NO_VIEWABLE_GUILDBANK_TABS);
+ GuildBankErrorMessage:Show();
+ elseif ( tab > GetNumGuildBankTabs() ) then
+ if ( IsGuildLeader() ) then
+ --Show buy screen
+ GuildBankFrame_HideColumns();
+ GuildBankFrameBuyInfo:Show();
+ GuildBankErrorMessage:Hide();
+ else
+ GuildBankFrame_HideColumns();
+ GuildBankFrameBuyInfo:Hide();
+ GuildBankErrorMessage:SetText(NO_GUILDBANK_TABS);
+ GuildBankErrorMessage:Show();
+ end
+ else
+ local _, _, _, canDeposit, numWithdrawals = GetGuildBankTabInfo(tab);
+ if ( not canDeposit and numWithdrawals == 0 ) then
+ GuildBankFrame_DesaturateColumns(1);
+ else
+ GuildBankFrame_DesaturateColumns(nil);
+ end
+ GuildBankFrame_ShowColumns()
+ GuildBankFrameBuyInfo:Hide();
+ GuildBankErrorMessage:Hide();
+ end
+
+ -- Update the tab items
+ local button, index, column;
+ local texture, itemCount, locked;
+ for i=1, MAX_GUILDBANK_SLOTS_PER_TAB do
+ index = mod(i, NUM_SLOTS_PER_GUILDBANK_GROUP);
+ if ( index == 0 ) then
+ index = NUM_SLOTS_PER_GUILDBANK_GROUP;
+ end
+ column = ceil((i-0.5)/NUM_SLOTS_PER_GUILDBANK_GROUP);
+ button = _G["GuildBankColumn"..column.."Button"..index];
+ button:SetID(i);
+ texture, itemCount, locked = GetGuildBankItemInfo(tab, i);
+ SetItemButtonTexture(button, texture);
+ SetItemButtonCount(button, itemCount);
+ SetItemButtonDesaturated(button, locked, 0.5, 0.5, 0.5);
+ end
+ MoneyFrame_Update("GuildBankMoneyFrame", GetGuildBankMoney());
+ if ( CanWithdrawGuildBankMoney() ) then
+ GuildBankFrameWithdrawButton:Enable();
+ else
+ GuildBankFrameWithdrawButton:Disable();
+ end
+ elseif ( GuildBankFrame.mode == "log" or GuildBankFrame.mode == "moneylog" ) then
+ GuildBankFrame_HideColumns();
+ GuildBankFrameBuyInfo:Hide();
+ GuildBankInfo:Hide();
+ if ( GuildBankFrame.noViewableTabs and GuildBankFrame.mode == "log" ) then
+ GuildBankErrorMessage:SetText(NO_VIEWABLE_GUILDBANK_LOGS);
+ GuildBankErrorMessage:Show();
+ GuildBankFrameLog:Hide();
+ else
+ GuildBankErrorMessage:Hide();
+ GuildBankFrameLog:Show();
+ end
+ elseif ( GuildBankFrame.mode == "tabinfo" ) then
+ GuildBankFrame_HideColumns();
+ GuildBankErrorMessage:Hide();
+ GuildBankFrameBuyInfo:Hide();
+ GuildBankFrameLog:Hide();
+ GuildBankInfo:Show();
+ end
+ --Update remaining money
+ GuildBankFrame_UpdateWithdrawMoney();
+end
+
+function GuildBankFrameTab_OnClick(tab, id, doNotUpdate)
+ PanelTemplates_SetTab(GuildBankFrame, id);
+ if ( id == 1 ) then
+ --Bank
+ GuildBankFrame.mode = "bank";
+ if ( not doNotUpdate ) then
+ QueryGuildBankTab(GetCurrentGuildBankTab());
+ end
+ elseif ( id == 2 ) then
+ --Log
+ GuildBankMessageFrame:Clear();
+ GuildBankTransactionsScrollFrame:Hide();
+ GuildBankFrame.mode = "log";
+ if ( not doNotUpdate ) then
+ QueryGuildBankLog(GetCurrentGuildBankTab());
+ end
+ GuildBankTransactionsScrollFrameScrollBar:SetValue(0);
+ elseif ( id == 3 ) then
+ --Money log
+ GuildBankMessageFrame:Clear();
+ GuildBankTransactionsScrollFrame:Hide();
+ GuildBankFrame.mode = "moneylog";
+ if ( not doNotUpdate ) then
+ QueryGuildBankLog(MAX_GUILDBANK_TABS + 1);
+ end
+ GuildBankTransactionsScrollFrameScrollBar:SetValue(0);
+ else
+ --Tab Info
+ GuildBankFrame.mode = "tabinfo";
+ if ( not doNotUpdate ) then
+ QueryGuildBankText(GetCurrentGuildBankTab());
+ end
+ end
+ --Call this to gray out tabs or activate them
+ GuildBankFrame_UpdateTabs();
+ if ( not doNotUpdate ) then
+ GuildBankFrame_Update();
+ end
+ PlaySound("igCharacterInfoTab");
+end
+
+function GuildBankFrame_UpdateTabBuyingInfo()
+ local tabCost = GetGuildBankTabCost();
+ local numTabs = GetNumGuildBankTabs();
+ GuildBankFrameBuyInfoNumTabsPurchasedText:SetText(format(NUM_GUILDBANK_TABS_PURCHASED, numTabs, MAX_GUILDBANK_TABS));
+ if ( not tabCost ) then
+ --You've bought all the tabs
+ GuildBankTab_OnClick(GuildBankTab1, "LeftButton", 1);
+ else
+ if( GetMoney() >= tabCost or (GetMoney() + GetGuildBankMoney()) >= tabCost ) then
+ SetMoneyFrameColor("GuildBankFrameTabCostMoneyFrame", "white");
+ GuildBankFramePurchaseButton:Enable();
+ else
+ SetMoneyFrameColor("GuildBankFrameTabCostMoneyFrame", "red");
+ GuildBankFramePurchaseButton:Disable();
+ end
+ GuildBankTab_OnClick(_G["GuildBankTab" .. numTabs+1], "LeftButton", numTabs+1);
+ MoneyFrame_Update("GuildBankFrameTabCostMoneyFrame", tabCost);
+ end
+end
+
+function GuildBankFrame_UpdateTabs()
+ local tab, iconTexture, tabButton;
+ local name, icon, isViewable, canDeposit, numWithdrawals, remainingWithdrawals;
+ local numTabs = GetNumGuildBankTabs();
+ local currentTab = GetCurrentGuildBankTab();
+ local tabToBuyIndex = numTabs+1;
+ local unviewableCount = 0;
+ local disableAll = nil;
+ local updateAgain = nil;
+ local isLocked, titleText;
+ local withdrawalText, withdrawalStackCount;
+ -- Disable and gray out all tabs if in the moneyLog since the tab is irrelevant
+ if ( GuildBankFrame.mode == "moneylog" ) then
+ disableAll = 1;
+ end
+ for i=1, MAX_GUILDBANK_TABS do
+ tab = _G["GuildBankTab"..i];
+ tabButton = _G["GuildBankTab"..i.."Button"];
+ name, icon, isViewable, canDeposit, numWithdrawals, remainingWithdrawals = GetGuildBankTabInfo(i);
+ iconTexture = _G["GuildBankTab"..i.."ButtonIconTexture"];
+ if ( not name or name == "" ) then
+ name = format(GUILDBANK_TAB_NUMBER, i);
+ end
+ if ( i == tabToBuyIndex and IsGuildLeader() ) then
+ iconTexture:SetTexture("Interface\\GuildBankFrame\\UI-GuildBankFrame-NewTab");
+ tabButton.tooltip = BUY_GUILDBANK_TAB;
+ tab:Show();
+
+ if ( disableAll or GuildBankFrame.mode == "log" or GuildBankFrame.mode == "tabinfo" ) then
+ tabButton:SetChecked(nil);
+ SetDesaturation(iconTexture, 1);
+ tabButton:SetButtonState("NORMAL");
+ tabButton:Disable();
+ if ( GuildBankFrame.mode == "log" and i == currentTab and numTabs > 0 ) then
+ SetCurrentGuildBankTab(1);
+ updateAgain = 1;
+ end
+ else
+ if ( i == currentTab ) then
+ tabButton:SetChecked(1);
+ tabButton:Disable();
+ SetDesaturation(iconTexture, nil);
+ titleText = BUY_GUILDBANK_TAB;
+ else
+ tabButton:SetChecked(nil);
+ tabButton:Enable();
+ SetDesaturation(iconTexture, nil);
+ end
+ end
+ elseif ( i >= tabToBuyIndex ) then
+ tab:Hide();
+ else
+ iconTexture:SetTexture(icon);
+ tab:Show();
+ if ( isViewable ) then
+ tabButton.tooltip = name;
+ if ( i == currentTab ) then
+ if ( disableAll ) then
+ tabButton:SetChecked(nil);
+ else
+ tabButton:SetChecked(1);
+ tabButton:Enable();
+ end
+ withdrawalText = name;
+ titleText = name;
+ else
+ tabButton:SetChecked(nil);
+ tabButton:Enable();
+ end
+ if ( disableAll ) then
+ tabButton:Disable();
+ SetDesaturation(iconTexture, 1);
+ else
+ SetDesaturation(iconTexture, nil);
+ end
+ else
+ unviewableCount = unviewableCount+1;
+ tabButton:Disable();
+ SetDesaturation(iconTexture, 1);
+ tabButton:SetChecked(nil);
+ end
+
+ end
+ if ( unviewableCount == numTabs and not IsGuildLeader() ) then
+ --Can't view any tabs so hide everything
+ GuildBankFrame.noViewableTabs = 1;
+ else
+ GuildBankFrame.noViewableTabs = nil;
+ end
+ if ( updateAgain ) then
+ GuildBankFrame_UpdateTabs();
+ end
+ end
+
+ -- Set Title
+ if ( GuildBankFrame.mode == "moneylog" ) then
+ titleText = GUILD_BANK_MONEY_LOG;
+ withdrawalText = nil;
+ elseif ( GuildBankFrame.mode == "log" ) then
+ if ( titleText ) then
+ titleText = format(GUILDBANK_LOG_TITLE_FORMAT, titleText);
+ end
+ elseif ( GuildBankFrame.mode == "tabinfo" ) then
+ withdrawalText = nil;
+ if ( titleText ) then
+ titleText = format(GUILDBANK_INFO_TITLE_FORMAT, titleText);
+ end
+ end
+ --Get selected tab info
+ name, icon, isViewable, canDeposit, numWithdrawals, remainingWithdrawals = GetGuildBankTabInfo(currentTab);
+ if ( titleText and (GuildBankFrame.mode ~= "moneylog" and titleText ~= BUY_GUILDBANK_TAB) ) then
+ local access;
+ if ( not canDeposit and numWithdrawals == 0 ) then
+ access = RED_FONT_COLOR_CODE.."("..GUILDBANK_TAB_LOCKED..")"..FONT_COLOR_CODE_CLOSE;
+ elseif ( not canDeposit ) then
+ access = RED_FONT_COLOR_CODE.."("..GUILDBANK_TAB_WITHDRAW_ONLY..")"..FONT_COLOR_CODE_CLOSE;
+ elseif ( numWithdrawals == 0 ) then
+ access = RED_FONT_COLOR_CODE.."("..GUILDBANK_TAB_DEPOSIT_ONLY..")"..FONT_COLOR_CODE_CLOSE;
+ else
+ access = GREEN_FONT_COLOR_CODE.."("..GUILDBANK_TAB_FULL_ACCESS..")"..FONT_COLOR_CODE_CLOSE;
+ end
+ titleText = titleText.." "..access;
+ end
+ if ( titleText ) then
+ GuildBankTabTitle:SetText(titleText);
+ GuildBankTabTitleBackground:SetWidth(GuildBankTabTitle:GetWidth()+20);
+
+ GuildBankTabTitle:Show();
+ GuildBankTabTitleBackground:Show();
+ GuildBankTabTitleBackgroundLeft:Show();
+ GuildBankTabTitleBackgroundRight:Show();
+ else
+ GuildBankTabTitle:Hide();
+ GuildBankTabTitleBackground:Hide();
+ GuildBankTabTitleBackgroundLeft:Hide();
+ GuildBankTabTitleBackgroundRight:Hide();
+ end
+ if ( withdrawalText ) then
+ local stackString;
+ if ( remainingWithdrawals > 0 ) then
+ stackString = format(STACKS, remainingWithdrawals);
+ elseif ( remainingWithdrawals == 0 ) then
+ stackString = NONE;
+ else
+ stackString = UNLIMITED;
+ end
+ GuildBankLimitLabel:SetText(format(GUILDBANK_REMAINING_MONEY, withdrawalText, stackString));
+ GuildBankTabLimitBackground:SetWidth(GuildBankLimitLabel:GetWidth()+20);
+ --If the tab name is too long then reanchor the withdraw box so it's not longer centered
+ if ( GuildBankLimitLabel:GetWidth() > 298 ) then
+ GuildBankTabLimitBackground:ClearAllPoints();
+ GuildBankTabLimitBackground:SetPoint("RIGHT", GuildBankFrameWithdrawButton, "LEFT", -14, -1);
+ else
+ GuildBankTabLimitBackground:ClearAllPoints();
+ GuildBankTabLimitBackground:SetPoint("TOP", "GuildBankFrame", "TOP", 6, -388);
+ end
+
+ GuildBankLimitLabel:Show();
+ GuildBankTabLimitBackground:Show();
+ GuildBankTabLimitBackgroundLeft:Show();
+ GuildBankTabLimitBackgroundRight:Show();
+ else
+ GuildBankLimitLabel:Hide();
+ GuildBankTabLimitBackground:Hide();
+ GuildBankTabLimitBackgroundLeft:Hide();
+ GuildBankTabLimitBackgroundRight:Hide();
+ end
+end
+
+function GuildBankTab_OnClick(self, mouseButton, currentTab)
+ if ( GuildBankInfo:IsShown() ) then
+ GuildBankInfoSaveButton:Click();
+ end
+ if ( not currentTab ) then
+ currentTab = self:GetParent():GetID();
+ end
+ SetCurrentGuildBankTab(currentTab);
+ GuildBankFrame_UpdateTabs();
+ if ( IsGuildLeader() and mouseButton == "RightButton" and currentTab ~= (GetNumGuildBankTabs() + 1) ) then
+ --Show the popup if it's a right click
+ GuildBankPopupFrame:Show();
+ GuildBankPopupFrame_Update(currentTab);
+ end
+ GuildBankFrame_Update();
+ if ( GuildBankFrameLog:IsShown() ) then
+ if ( GuildBankFrame.mode == "log" ) then
+ QueryGuildBankTab(currentTab); --Need this to get the number of withdrawals left for this tab
+ QueryGuildBankLog(currentTab);
+ GuildBankFrame_UpdateLog();
+ else
+ QueryGuildBankLog(MAX_GUILDBANK_TABS+1);
+ GuildBankFrame_UpdateMoneyLog();
+ end
+ elseif ( GuildBankInfo:IsShown() ) then
+ QueryGuildBankText(currentTab);
+ else
+ QueryGuildBankTab(currentTab);
+ end
+end
+
+function GuildBankFrame_HideColumns()
+ if ( not GuildBankColumn1:IsShown() ) then
+ return;
+ end
+ for i=1, NUM_GUILDBANK_COLUMNS do
+ _G["GuildBankColumn"..i]:Hide();
+ end
+end
+
+function GuildBankFrame_ShowColumns()
+ if ( GuildBankColumn1:IsShown() ) then
+ return;
+ end
+ for i=1, NUM_GUILDBANK_COLUMNS do
+ _G["GuildBankColumn"..i]:Show();
+ end
+end
+
+function GuildBankFrame_DesaturateColumns(isDesaturated)
+ for i=1, NUM_GUILDBANK_COLUMNS do
+ SetDesaturation(_G["GuildBankColumn"..i.."Background"], isDesaturated);
+ end
+end
+
+function GuildBankItemButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:RegisterForDrag("LeftButton");
+ self.SplitStack = function(button, split)
+ SplitGuildBankItem(GetCurrentGuildBankTab(), button:GetID(), split);
+ end
+ self.UpdateTooltip = GuildBankItemButton_OnEnter;
+end
+
+function GuildBankItemButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetGuildBankItem(GetCurrentGuildBankTab(), self:GetID());
+end
+
+function GuildBankFrame_UpdateLog()
+ local tab = GetCurrentGuildBankTab();
+ local numTransactions = GetNumGuildBankTransactions(tab);
+ local type, name, itemLink, count, tab1, tab2, year, month, day, hour;
+
+ local msg;
+ GuildBankMessageFrame:Clear();
+ for i=1, numTransactions, 1 do
+ type, name, itemLink, count, tab1, tab2, year, month, day, hour = GetGuildBankTransaction(tab, i);
+ if ( not name ) then
+ name = UNKNOWN;
+ end
+ name = NORMAL_FONT_COLOR_CODE..name..FONT_COLOR_CODE_CLOSE;
+ if ( type == "deposit" ) then
+ msg = format(GUILDBANK_DEPOSIT_FORMAT, name, itemLink);
+ if ( count > 1 ) then
+ msg = msg..format(GUILDBANK_LOG_QUANTITY, count);
+ end
+ elseif ( type == "withdraw" ) then
+ msg = format(GUILDBANK_WITHDRAW_FORMAT, name, itemLink);
+ if ( count > 1 ) then
+ msg = msg..format(GUILDBANK_LOG_QUANTITY, count);
+ end
+ elseif ( type == "move" ) then
+ msg = format(GUILDBANK_MOVE_FORMAT, name, itemLink, count, GetGuildBankTabInfo(tab1), GetGuildBankTabInfo(tab2));
+ end
+ if ( msg ) then
+ GuildBankMessageFrame:AddMessage( msg..GUILD_BANK_LOG_TIME_PREPEND..format(GUILD_BANK_LOG_TIME, RecentTimeDate(year, month, day, hour)) );
+ end
+ end
+ FauxScrollFrame_Update(GuildBankTransactionsScrollFrame, numTransactions, MAX_TRANSACTIONS_SHOWN, GUILDBANK_TRANSACTION_HEIGHT );
+end
+
+function GuildBankFrame_UpdateMoneyLog()
+ local numTransactions = GetNumGuildBankMoneyTransactions();
+ local type, name, amount, year, month, day, hour;
+ local msg;
+ local money;
+ GuildBankMessageFrame:Clear();
+ for i=1, numTransactions, 1 do
+ type, name, amount, year, month, day, hour = GetGuildBankMoneyTransaction(i);
+ if ( not name ) then
+ name = UNKNOWN;
+ end
+ name = NORMAL_FONT_COLOR_CODE..name..FONT_COLOR_CODE_CLOSE;
+ money = GetDenominationsFromCopper(amount);
+ if ( type == "deposit" ) then
+ msg = format(GUILDBANK_DEPOSIT_MONEY_FORMAT, name, money);
+ elseif ( type == "withdraw" ) then
+ msg = format(GUILDBANK_WITHDRAW_MONEY_FORMAT, name, money);
+ elseif ( type == "repair" ) then
+ msg = format(GUILDBANK_REPAIR_MONEY_FORMAT, name, money);
+ elseif ( type == "withdrawForTab" ) then
+ msg = format(GUILDBANK_WITHDRAWFORTAB_MONEY_FORMAT, name, money);
+ elseif ( type == "buyTab" ) then
+ msg = format(GUILDBANK_BUYTAB_MONEY_FORMAT, name, money);
+ end
+ GuildBankMessageFrame:AddMessage(msg..GUILD_BANK_LOG_TIME_PREPEND..format(GUILD_BANK_LOG_TIME, RecentTimeDate(year, month, day, hour)));
+ end
+ FauxScrollFrame_Update(GuildBankTransactionsScrollFrame, numTransactions, MAX_TRANSACTIONS_SHOWN, GUILDBANK_TRANSACTION_HEIGHT );
+end
+
+function GuildBankLogScroll()
+ local offset = FauxScrollFrame_GetOffset(GuildBankTransactionsScrollFrame);
+ local numTransactions = 0;
+ if ( GuildBankFrame.mode == "log" ) then
+ numTransactions = GetNumGuildBankTransactions(GetCurrentGuildBankTab());
+ elseif ( GuildBankFrame.mode == "moneylog" ) then
+ numTransactions = GetNumGuildBankMoneyTransactions();
+ end
+ GuildBankMessageFrame:SetScrollOffset(offset);
+ FauxScrollFrame_Update(GuildBankTransactionsScrollFrame, numTransactions, MAX_TRANSACTIONS_SHOWN, GUILDBANK_TRANSACTION_HEIGHT );
+end
+
+function IsTabViewable(tab)
+ GuildBankFrame.nextAvailableTab = nil;
+ local view = false;
+ for i=1, MAX_GUILDBANK_TABS do
+ local _, _, isViewable = GetGuildBankTabInfo(i);
+ if ( isViewable ) then
+ if ( not GuildBankFrame.nextAvailableTab ) then
+ GuildBankFrame.nextAvailableTab = i;
+ end
+ if ( i == tab ) then
+ view = true;
+ end
+ end
+ end
+ return view;
+end
+
+function GuildBankFrame_UpdateWithdrawMoney()
+ local withdrawLimit = GetGuildBankWithdrawMoney();
+ if ( withdrawLimit >= 0 ) then
+ local amount;
+ if ( (not CanGuildBankRepair() and not CanWithdrawGuildBankMoney()) or (CanGuildBankRepair() and not CanWithdrawGuildBankMoney()) ) then
+ amount = 0;
+ else
+ amount = GetGuildBankMoney();
+ end
+ withdrawLimit = min(withdrawLimit, amount);
+ MoneyFrame_Update("GuildBankWithdrawMoneyFrame", withdrawLimit);
+ GuildBankMoneyUnlimitedLabel:Hide();
+ GuildBankWithdrawMoneyFrame:Show();
+ else
+ GuildBankMoneyUnlimitedLabel:Show();
+ GuildBankWithdrawMoneyFrame:Hide();
+ end
+end
+
+function GuildBankFrame_UpdateTabard()
+ --Set the tabard images
+ local tabardBackgroundUpper, tabardBackgroundLower, tabardEmblemUpper, tabardEmblemLower, tabardBorderUpper, tabardBorderLower = GetGuildTabardFileNames();
+ if ( not tabardEmblemUpper ) then
+ tabardBackgroundUpper = "Textures\\GuildEmblems\\Background_49_TU_U";
+ tabardBackgroundLower = "Textures\\GuildEmblems\\Background_49_TL_U";
+ end
+ GuildBankEmblemBackgroundUL:SetTexture(tabardBackgroundUpper);
+ GuildBankEmblemBackgroundUR:SetTexture(tabardBackgroundUpper);
+ GuildBankEmblemBackgroundBL:SetTexture(tabardBackgroundLower);
+ GuildBankEmblemBackgroundBR:SetTexture(tabardBackgroundLower);
+
+ GuildBankEmblemUL:SetTexture(tabardEmblemUpper);
+ GuildBankEmblemUR:SetTexture(tabardEmblemUpper);
+ GuildBankEmblemBL:SetTexture(tabardEmblemLower);
+ GuildBankEmblemBR:SetTexture(tabardEmblemLower);
+
+ GuildBankEmblemBorderUL:SetTexture(tabardBorderUpper);
+ GuildBankEmblemBorderUR:SetTexture(tabardBorderUpper);
+ GuildBankEmblemBorderBL:SetTexture(tabardBorderLower);
+ GuildBankEmblemBorderBR:SetTexture(tabardBorderLower);
+end
+
+function GuildBankFrame_UpdateTabInfo(tab)
+ local text = GetGuildBankText(tab);
+ if ( text ) then
+ GuildBankTabInfoEditBox.text = text;
+ GuildBankTabInfoEditBox:SetText(text);
+ else
+ GuildBankTabInfoEditBox:SetText("");
+ end
+end
+
+--Popup functions
+function GuildBankPopupFrame_Update(tab)
+ local numguildBankIcons = GetNumMacroItemIcons();
+ local guildBankPopupIcon, guildBankPopupButton;
+ local guildBankPopupOffset = FauxScrollFrame_GetOffset(GuildBankPopupScrollFrame);
+ local index;
+
+ local _, tabTexture = GetGuildBankTabInfo(GetCurrentGuildBankTab());
+
+ -- Icon list
+ local texture;
+ for i=1, NUM_GUILDBANK_ICONS_SHOWN do
+ guildBankPopupIcon = _G["GuildBankPopupButton"..i.."Icon"];
+ guildBankPopupButton = _G["GuildBankPopupButton"..i];
+ index = (guildBankPopupOffset * NUM_GUILDBANK_ICONS_PER_ROW) + i;
+ texture = GetMacroItemIconInfo(index);
+ if ( index <= numguildBankIcons ) then
+ guildBankPopupIcon:SetTexture(texture);
+ guildBankPopupButton:Show();
+ else
+ guildBankPopupIcon:SetTexture("");
+ guildBankPopupButton:Hide();
+ end
+ if ( GuildBankPopupFrame.selectedIcon ) then
+ if ( index == GuildBankPopupFrame.selectedIcon ) then
+ guildBankPopupButton:SetChecked(1);
+ else
+ guildBankPopupButton:SetChecked(nil);
+ end
+ elseif ( tabTexture == texture ) then
+ guildBankPopupButton:SetChecked(1);
+ GuildBankPopupFrame.selectedIcon = index;
+ else
+ guildBankPopupButton:SetChecked(nil);
+ end
+ end
+ --Only do this if the player hasn't clicked on an icon or the icon is not visible
+ if ( not GuildBankPopupFrame.selectedIcon ) then
+ for i=1, numguildBankIcons do
+ texture = GetMacroItemIconInfo(i);
+ if ( tabTexture == texture ) then
+ GuildBankPopupFrame.selectedIcon = i;
+ break;
+ end
+ end
+ end
+
+ -- Scrollbar stuff
+ FauxScrollFrame_Update(GuildBankPopupScrollFrame, ceil(numguildBankIcons / NUM_GUILDBANK_ICONS_PER_ROW) , NUM_GUILDBANK_ICON_ROWS, GUILDBANK_ICON_ROW_HEIGHT );
+end
+
+function GuildBankPopupFrame_OnShow(self)
+ local name = GetGuildBankTabInfo(GetCurrentGuildBankTab());
+ if ( not name or name == "" ) then
+ name = format(GUILDBANK_TAB_NUMBER, GetCurrentGuildBankTab());
+ end
+ GuildBankPopupEditBox:SetText(name);
+ GuildBankPopupFrame.selectedIcon = nil;
+end
+
+function GuildBankPopupButton_OnClick(self, button)
+ local offset = FauxScrollFrame_GetOffset(GuildBankPopupScrollFrame);
+ local index = (offset * NUM_GUILDBANK_ICONS_PER_ROW)+self:GetID();
+ GuildBankPopupFrame.selectedIcon = index;
+ GuildBankPopupFrame_Update(GetCurrentGuildBankTab());
+end
+
+function GuildBankPopupOkayButton_OnClick(self)
+ local name = GuildBankPopupEditBox:GetText();
+ local tab = GetCurrentGuildBankTab();
+ if ( not name or name == "" ) then
+ name = format(GUILDBANK_TAB_NUMBER, tab);
+ end
+ SetGuildBankTabInfo(tab, name, GuildBankPopupFrame.selectedIcon);
+ GuildBankPopupFrame:Hide();
+end
+
+function GuildBankPopupFrame_CancelEdit()
+ GuildBankPopupFrame:Hide();
+end
+
diff --git a/reference/AddOns/Blizzard_GuildBankUI/Blizzard_GuildBankUI.toc b/reference/AddOns/Blizzard_GuildBankUI/Blizzard_GuildBankUI.toc
new file mode 100644
index 0000000..c5275e1
--- /dev/null
+++ b/reference/AddOns/Blizzard_GuildBankUI/Blizzard_GuildBankUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard Guild Bank UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_GuildBankUI.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_GuildBankUI/Blizzard_GuildBankUI.xml b/reference/AddOns/Blizzard_GuildBankUI/Blizzard_GuildBankUI.xml
new file mode 100644
index 0000000..547aad7
--- /dev/null
+++ b/reference/AddOns/Blizzard_GuildBankUI/Blizzard_GuildBankUI.xml
@@ -0,0 +1,1370 @@
+
+
+
+
+
+
+
+
+
+
+ if ( HandleModifiedItemClick(GetGuildBankItemLink(GetCurrentGuildBankTab(), self:GetID())) ) then
+ return;
+ end
+ if ( IsModifiedClick("SPLITSTACK") ) then
+ local texture, count, locked = GetGuildBankItemInfo(GetCurrentGuildBankTab(), self:GetID());
+ if ( not locked ) then
+ OpenStackSplitFrame(count, self, "BOTTOMLEFT", "TOPLEFT");
+ end
+ return;
+ end
+ local type, money = GetCursorInfo();
+ if ( type == "money" ) then
+ DepositGuildBankMoney(money);
+ ClearCursor();
+ elseif ( type == "guildbankmoney" ) then
+ DropCursorMoney();
+ ClearCursor();
+ else
+ if ( button == "RightButton" ) then
+ AutoStoreGuildBankItem(GetCurrentGuildBankTab(), self:GetID());
+ else
+ PickupGuildBankItem(GetCurrentGuildBankTab(), self:GetID());
+ end
+ end
+
+
+ GuildBankItemButton_OnLoad(self);
+
+
+ GuildBankItemButton_OnEnter(self, motion);
+
+
+ self.updateTooltip = nil;
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ if ( self.hasStackSplit and (self.hasStackSplit == 1) ) then
+ StackSplitFrame:Hide();
+ end
+
+
+ PickupGuildBankItem(GetCurrentGuildBankTab(), self:GetID());
+
+
+ PickupGuildBankItem(GetCurrentGuildBankTab(), self:GetID());
+
+
+ --GuildBankItemButton_OnUpdate(self, elapsed);
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ GuildBankItemButton_OnEnter(self);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ local currentTab = self:GetParent():GetID();
+ if ( GetCurrentGuildBankTab() ~= currentTab or button == "RightButton" ) then
+ PlaySound("GuildBankOpenBag");
+ end
+ GuildBankTab_OnClick(self, button, currentTab);
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GuildBankPopupButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self, "GUILDBANK");
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self, "GUILDBANKWITHDRAW");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ StaticPopup_Hide("GUILDBANK_WITHDRAW");
+ if(StaticPopup_Visible("GUILDBANK_DEPOSIT")) then
+ StaticPopup_Hide("GUILDBANK_DEPOSIT");
+ else
+ StaticPopup_Show("GUILDBANK_DEPOSIT");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ StaticPopup_Hide("GUILDBANK_DEPOSIT");
+ if(StaticPopup_Visible("GUILDBANK_WITHDRAW")) then
+ StaticPopup_Hide("GUILDBANK_WITHDRAW");
+ else
+ StaticPopup_Show("GUILDBANK_WITHDRAW");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText("", 1.0,1.0,1.0 );
+
+
+
+ GuildBankFrameTab_OnClick(self, self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText("", 1.0,1.0,1.0 );
+
+
+
+ GuildBankFrameTab_OnClick(self, self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText("", 1.0,1.0,1.0 );
+
+
+
+ GuildBankFrameTab_OnClick(self, self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText("", 1.0,1.0,1.0 );
+
+
+
+ GuildBankFrameTab_OnClick(self, self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ StaticPopup_Show("CONFIRM_BUY_GUILDBANK_TAB");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SetItemRef(link, text, button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, GUILDBANK_TRANSACTION_HEIGHT, GuildBankLogScroll)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(_G[self:GetName().."Text"]:GetWidth()+40);
+
+
+ if ( GuildBankTabInfoEditBox:GetText() ~= GuildBankTabInfoEditBox.text ) then
+ SetGuildBankText(GetCurrentGuildBankTab(), GuildBankTabInfoEditBox:GetText());
+ GuildBankTabInfoEditBox:ClearFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( CanEditGuildTabInfo(GetCurrentGuildBankTab()) ) then
+ GuildBankTabInfoEditBox:SetFocus();
+ else
+ GuildBankTabInfoEditBox:ClearFocus();
+ end
+
+
+ if ( CanEditGuildTabInfo(GetCurrentGuildBankTab()) ) then
+ GuildBankTabInfoEditBox:SetFocus();
+ else
+ GuildBankTabInfoEditBox:ClearFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent());
+ local currentTab = GetCurrentGuildBankTab();
+ if ( currentTab > GetNumGuildBankTabs() ) then
+ GuildBankInfoSaveButton:Hide();
+ elseif ( CanEditGuildTabInfo(currentTab) ) then
+ GuildBankInfoSaveButton:Show();
+ else
+ GuildBankInfoSaveButton:Hide();
+ end
+
+
+ ScrollingEdit_OnCursorChanged(self, x, y-10, w, h);
+
+
+ ScrollingEdit_OnUpdate(self, elapsed, self:GetParent());
+
+
+
+
+
+
+
+
+
+ GuildBankInfoSaveButton:Click();
+
+
+
+
+
+
+
+
+
+ GuildBankPopupFrame:Hide();
+ StaticPopup_Hide("GUILDBANK_WITHDRAW");
+ StaticPopup_Hide("GUILDBANK_DEPOSIT");
+ StaticPopup_Hide("CONFIRM_BUY_GUILDBANK_TAB");
+ CloseGuildBankFrame();
+ PlaySound("GuildVaultClose");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GuildBankPopupOkayButton:IsEnabled() ~= 0 ) then
+ GuildBankPopupOkayButton_OnClick(self);
+ end
+ GuildBankPopupEditBox:ClearFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, GUILDBANK_ICON_ROW_HEIGHT, GuildBankPopupFrame_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GuildBankPopupFrame_CancelEdit(self)
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GuildBankPopupOkayButton_OnClick(self);
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoTab");
+
+
+
+
diff --git a/reference/AddOns/Blizzard_GuildBankUI/Localization.lua b/reference/AddOns/Blizzard_GuildBankUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_GuildBankUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_InspectUI/Blizzard_InspectUI.lua b/reference/AddOns/Blizzard_InspectUI/Blizzard_InspectUI.lua
new file mode 100644
index 0000000..045148d
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/Blizzard_InspectUI.lua
@@ -0,0 +1,129 @@
+
+INSPECTFRAME_SUBFRAMES = { "InspectPaperDollFrame", "InspectPVPFrame", "InspectTalentFrame", "InspectTalentFrame", "InspectTalentFrame" };
+
+UIPanelWindows["InspectFrame"] = { area = "left", pushable = 0 };
+
+function InspectFrame_Show(unit)
+ HideUIPanel(InspectFrame);
+ if ( CanInspect(unit, true) ) then
+ NotifyInspect(unit);
+ InspectFrame.unit = unit;
+ InspectSwitchTabs(1);
+ ShowUIPanel(InspectFrame);
+ InspectFrame_UpdateTalentTab();
+ end
+end
+
+function InspectFrame_OnLoad(self)
+ self:RegisterEvent("PLAYER_TARGET_CHANGED");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("UNIT_NAME_UPDATE");
+ self:RegisterEvent("UNIT_PORTRAIT_UPDATE");
+ self.unit = nil;
+
+ -- Tab Handling code
+ PanelTemplates_SetNumTabs(self, 3);
+ PanelTemplates_SetTab(self, 1);
+end
+
+function InspectFrame_OnEvent(self, event, ...)
+ if ( not self:IsShown() ) then
+ return;
+ end
+ if ( event == "PLAYER_TARGET_CHANGED" or event == "PARTY_MEMBERS_CHANGED" ) then
+ if ( (event == "PLAYER_TARGET_CHANGED" and self.unit == "target") or
+ (event == "PARTY_MEMBERS_CHANGED" and self.unit ~= "target") ) then
+ if ( CanInspect(self.unit) ) then
+ InspectFrame_UnitChanged(self);
+ else
+ HideUIPanel(InspectFrame);
+ end
+ end
+ return;
+ elseif ( event == "UNIT_NAME_UPDATE" ) then
+ local arg1 = ...;
+ if ( arg1 == self.unit ) then
+ InspectNameText:SetText(UnitName(arg1));
+ end
+ return;
+ elseif ( event == "UNIT_PORTRAIT_UPDATE" ) then
+ local arg1 = ...;
+ if ( arg1 == self.unit ) then
+ SetPortraitTexture(InspectFramePortrait, arg1);
+ end
+ return;
+ end
+end
+
+function InspectFrame_UnitChanged(self)
+ local unit = self.unit;
+ NotifyInspect(unit);
+ InspectPaperDollFrame_OnShow(self);
+ SetPortraitTexture(InspectFramePortrait, unit);
+ InspectNameText:SetText(UnitName(unit));
+ InspectFrame_UpdateTalentTab();
+ if ( InspectPVPFrame:IsShown() ) then
+ InspectPVPFrame_OnShow();
+ end
+end
+
+function InspectFrame_OnShow(self)
+ if ( not self.unit ) then
+ return;
+ end
+ PlaySound("igCharacterInfoOpen");
+ SetPortraitTexture(InspectFramePortrait, self.unit);
+ InspectNameText:SetText(UnitName(self.unit));
+end
+
+function InspectFrame_OnHide(self)
+ self.unit = nil;
+ PlaySound("igCharacterInfoClose");
+
+ -- Clear the player being inspected
+ ClearInspectPlayer();
+
+ -- in the InspectTalentFrame_Update function, a default talent tab is selected smartly if there is no tab selected
+ -- it actually ends up feeling natural to have this behavior happen every time the frame is shown
+ PanelTemplates_SetTab(InspectTalentFrame, nil);
+end
+
+function InspectFrame_OnUpdate(self)
+ if ( not UnitIsVisible(self.unit) ) then
+ HideUIPanel(InspectFrame);
+ end
+end
+
+function InspectSwitchTabs(newID)
+ local newFrame = _G[INSPECTFRAME_SUBFRAMES[newID]];
+ local oldFrame = _G[INSPECTFRAME_SUBFRAMES[PanelTemplates_GetSelectedTab(InspectFrame)]];
+ if ( newFrame ) then
+ if ( oldFrame ) then
+ oldFrame:Hide();
+ end
+ PanelTemplates_SetTab(InspectFrame, newID);
+ ShowUIPanel(InspectFrame);
+ newFrame:Show();
+ end
+end
+
+function InspectFrameTab_OnClick(self)
+ PlaySound("igCharacterInfoTab");
+ InspectSwitchTabs(self:GetID());
+end
+
+function InspectFrame_UpdateTalentTab()
+ if ( not InspectFrame.unit ) then
+ return;
+ end
+ local level = UnitLevel(InspectFrame.unit);
+ if ( level > 0 and level < 10 ) then
+ PanelTemplates_DisableTab(InspectFrame, 3);
+ if ( PanelTemplates_GetSelectedTab(InspectFrame) == 3 ) then
+ InspectSwitchTabs(1);
+ end
+ else
+ PanelTemplates_EnableTab(InspectFrame, 3);
+ InspectTalentFrame_UpdateTabs();
+ end
+end
diff --git a/reference/AddOns/Blizzard_InspectUI/Blizzard_InspectUI.toc b/reference/AddOns/Blizzard_InspectUI/Blizzard_InspectUI.toc
new file mode 100644
index 0000000..c69d45a
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/Blizzard_InspectUI.toc
@@ -0,0 +1,9 @@
+## Interface: 30300
+## Title: Blizzard Inspect UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_InspectUI.xml
+InspectPaperDollFrame.xml
+InspectPVPFrame.xml
+InspectTalentFrame.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_InspectUI/Blizzard_InspectUI.xml b/reference/AddOns/Blizzard_InspectUI/Blizzard_InspectUI.xml
new file mode 100644
index 0000000..a2436c7
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/Blizzard_InspectUI.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(CHARACTER_INFO, 1.0,1.0,1.0 );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(PLAYER_V_PLAYER, 1.0,1.0,1.0 );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(TALENTS, 1.0,1.0,1.0 );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_InspectUI/InspectHonorFrame.lua b/reference/AddOns/Blizzard_InspectUI/InspectHonorFrame.lua
new file mode 100644
index 0000000..e725961
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/InspectHonorFrame.lua
@@ -0,0 +1,79 @@
+function InspectHonorFrame_OnLoad(self)
+ self:RegisterEvent("INSPECT_HONOR_UPDATE");
+end
+
+function InspectHonorFrame_OnEvent(self, event, ...)
+ if ( event == "INSPECT_HONOR_UPDATE" ) then
+ InspectHonorFrame_Update();
+ end
+end
+
+function InspectHonorFrame_OnShow()
+ if ( not HasInspectHonorData() ) then
+ RequestInspectHonorData();
+ else
+ InspectHonorFrame_Update();
+ end
+end
+
+function InspectHonorFrame_Update()
+
+ local todayHK, todayHonor, yesterdayHK, yesterdayHonor, lifetimeHK, lifetimeRank = GetInspectHonorData();
+
+ -- Yesterday's values
+ InspectHonorFrameYesterdayHKValue:SetText(yesterdayHK);
+ InspectHonorFrameYesterdayContributionValue:SetText(yesterdayHonor);
+
+ -- This week's values
+ --InspectHonorFrameThisWeekHKValue:SetText(thisweekHK);
+ --InspectHonorFrameThisWeekContributionValue:SetText(thisweekHonor);
+
+ -- Last Week's values
+ --InspectHonorFrameLastWeekHKValue:SetText(lastweekHK);
+ --InspectHonorFrameLastWeekContributionValue:SetText(lastweekHonor);
+ --InspectHonorFrameLastWeekStandingValue:SetText(lastweekStanding);
+
+ -- This session's values
+ InspectHonorFrameCurrentHKValue:SetText(todayHK);
+ --InspectHonorFrameCurrentDKValue:SetText(sessionDK);
+
+ -- Lifetime stats
+ InspectHonorFrameLifeTimeHKValue:SetText(lifetimeHK);
+ --InspectHonorFrameLifeTimeDKValue:SetText(lifetimeDK);
+ local rankName, rankNumber = GetPVPRankInfo(lifetimeRank);
+ if ( not rankName ) then
+ rankName = NONE;
+ end
+ InspectHonorFrameLifeTimeRankValue:SetText(rankName);
+
+ -- Set rank name and number
+ rankName, rankNumber = GetPVPRankInfo(UnitPVPRank("target"));
+ if ( not rankName ) then
+ rankName = NONE;
+ end
+
+ InspectHonorFrameCurrentPVPRank:SetText("("..RANK.." "..rankNumber..")");
+ InspectHonorFrameCurrentPVPRank:Show();
+ InspectHonorFrameCurrentPVPTitle:SetText(rankName);
+ InspectHonorFrameCurrentPVPTitle:Show();
+
+ -- Set icon
+ if ( rankNumber > 0 ) then
+ InspectHonorFramePvPIcon:SetTexture(format("%s%02d","Interface\\PvPRankBadges\\PvPRank",rankNumber));
+ InspectHonorFramePvPIcon:Show();
+ else
+ InspectHonorFramePvPIcon:Hide();
+ end
+
+ -- Set rank progress and bar color
+ local factionGroup, factionName = UnitFactionGroup("target");
+ if ( factionGroup == "Alliance" ) then
+ InspectHonorFrameProgressBar:SetStatusBarColor(0.05, 0.15, 0.36);
+ else
+ InspectHonorFrameProgressBar:SetStatusBarColor(0.63, 0.09, 0.09);
+ end
+ --InspectHonorFrameProgressBar:SetValue(GetInspectPVPRankProgress());
+
+ -- Recenter rank text
+ InspectHonorFrameCurrentPVPTitle:SetPoint("TOP", "InspectHonorFrame", "TOP", - InspectHonorFrameCurrentPVPRank:GetWidth()/2, -83);
+end
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_InspectUI/InspectHonorFrame.xml b/reference/AddOns/Blizzard_InspectUI/InspectHonorFrame.xml
new file mode 100644
index 0000000..aafa955
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/InspectHonorFrame.xml
@@ -0,0 +1,351 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(RANK, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_RANK, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(RANK_POSITION, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_RANK_POSITION, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_InspectUI/InspectPVPFrame.lua b/reference/AddOns/Blizzard_InspectUI/InspectPVPFrame.lua
new file mode 100644
index 0000000..4c1e74c
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/InspectPVPFrame.lua
@@ -0,0 +1,176 @@
+
+function InspectPVPFrame_OnLoad(self)
+ InspectPVPFrameLine1:SetAlpha(0.3);
+ InspectPVPHonorKillsLabel:SetVertexColor(0.6, 0.6, 0.6);
+ InspectPVPHonorHonorLabel:SetVertexColor(0.6, 0.6, 0.6);
+ InspectPVPHonorTodayLabel:SetVertexColor(0.6, 0.6, 0.6);
+ InspectPVPHonorYesterdayLabel:SetVertexColor(0.6, 0.6, 0.6);
+ InspectPVPHonorLifetimeLabel:SetVertexColor(0.6, 0.6, 0.6);
+
+ self:RegisterEvent("INSPECT_HONOR_UPDATE");
+end
+
+function InspectPVPFrame_OnEvent(self, event, ...)
+ if ( event == "INSPECT_HONOR_UPDATE" ) then
+ InspectPVPFrame_Update();
+ end
+end
+
+function InspectPVPFrame_OnShow()
+ InspectPVPFrame_Update();
+ if ( not HasInspectHonorData() ) then
+ RequestInspectHonorData();
+ else
+ InspectPVPFrame_Update();
+ end
+end
+
+function InspectPVPFrame_SetFaction()
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ InspectPVPFrameHonorIcon:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..factionGroup);
+ InspectPVPFrameHonorIcon:Show();
+ end
+end
+
+function InspectPVPFrame_Update()
+ for i=1, MAX_ARENA_TEAMS do
+ GetInspectArenaTeamData(i);
+ end
+ InspectPVPFrame_SetFaction();
+ InspectPVPHonor_Update();
+ InspectPVPTeam_Update();
+end
+
+function InspectPVPTeam_Update()
+ -- Display Elements
+ local button, buttonName, highlight, data, standard, emblem, border;
+ -- Data Elements
+ local teamName, teamSize, teamRating, teamPlayed, teamWins, teamLoss, playerPlayed, playerRating, playerPlayedPct, teamRank;
+ local background = {};
+ local borderColor = {};
+ local emblemColor = {};
+ local ARENA_TEAMS = {};
+ ARENA_TEAMS[1] = {size = 2};
+ ARENA_TEAMS[2] = {size = 3};
+ ARENA_TEAMS[3] = {size = 5};
+
+ -- Sort teams by size
+
+ local buttonIndex = 0;
+ for index, value in pairs(ARENA_TEAMS) do
+ for i=1, MAX_ARENA_TEAMS do
+ teamName, teamSize = GetInspectArenaTeamData(i);
+ if ( value.size == teamSize ) then
+ value.index = i;
+ end
+ end
+ end
+
+ -- fill out data
+ for index, value in pairs(ARENA_TEAMS) do
+ if ( value.index ) then
+ buttonIndex = buttonIndex + 1;
+ -- Pull Values
+ teamName, teamSize, teamRating, teamPlayed, teamWins, playerPlayed, playerRating, background.r, background.g, background.b, emblem, emblemColor.r, emblemColor.g, emblemColor.b, border, borderColor.r, borderColor.g, borderColor.b = GetInspectArenaTeamData(value.index);
+ teamLoss = teamPlayed - teamWins;
+ if ( teamPlayed ~= 0 ) then
+ playerPlayedPct = floor( ( playerPlayed / teamPlayed ) * 100 );
+ else
+ playerPlayedPct = floor( ( playerPlayed / 1 ) * 100 );
+ end
+
+ -- Set button elements to variables
+ button = _G["InspectPVPTeam"..buttonIndex];
+ buttonName = "InspectPVPTeam"..buttonIndex;
+ data = buttonName.."Data";
+ standard = buttonName.."Standard";
+
+ button:SetID(value.index);
+
+ -- Populate Data
+ _G[data.."TypeLabel"]:SetText(ARENA_THIS_SEASON);
+ _G[data.."Name"]:SetText(teamName);
+ _G[data.."Rating"]:SetText(teamRating);
+ _G[data.."Games"]:SetText(teamPlayed);
+ _G[data.."Wins"]:SetText(teamWins);
+ _G[data.."Loss"]:SetText(teamLoss);
+
+ _G[data.."Played"]:SetText(playerRating);
+ _G[data.."Played"]:SetVertexColor(1.0, 1.0, 1.0);
+ _G[data.."PlayedLabel"]:SetText(RATING);
+
+ -- Set TeamSize Banner
+ _G[standard.."Banner"]:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..teamSize);
+ _G[standard.."Banner"]:SetVertexColor(background.r, background.g, background.b);
+ _G[standard.."Border"]:SetVertexColor(borderColor.r, borderColor.g, borderColor.b);
+ _G[standard.."Emblem"]:SetVertexColor(emblemColor.r, emblemColor.g, emblemColor.b);
+ if ( border ~= -1 ) then
+ _G[standard.."Border"]:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..teamSize.."-Border-"..border);
+ end
+ if ( emblem ~= -1 ) then
+ _G[standard.."Emblem"]:SetTexture("Interface\\PVPFrame\\Icons\\PVP-Banner-Emblem-"..emblem);
+ end
+
+ -- Set visual elements
+ _G[data]:Show();
+ button:SetAlpha(1);
+ _G[buttonName.."Highlight"]:SetAlpha(1);
+ _G[buttonName.."Highlight"]:SetBackdropBorderColor(1.0, 0.82, 0);
+ _G[standard]:SetAlpha(1);
+ _G[standard.."Border"]:Show();
+ _G[standard.."Emblem"]:Show();
+ _G[buttonName.."Background"]:SetVertexColor(0, 0, 0);
+ _G[buttonName.."Background"]:SetAlpha(1);
+ _G[buttonName.."TeamType"]:Hide();
+
+ end
+ end
+
+ -- show unused teams
+ for index, value in pairs(ARENA_TEAMS) do
+ if ( not value.index ) then
+ -- Set button elements to variables
+ buttonIndex = buttonIndex + 1;
+ button = _G["InspectPVPTeam"..buttonIndex];
+ buttonName = "InspectPVPTeam"..buttonIndex;
+ data = buttonName.."Data";
+
+ -- Set standard type
+ _G[buttonName.."StandardBanner"]:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..value.size);
+
+ -- Hide or Show items
+ button:SetAlpha(0.4);
+ _G[data]:Hide();
+ _G[buttonName.."Background"]:SetVertexColor(0, 0, 0);
+ _G[buttonName.."Standard"]:SetAlpha(0.1);
+ _G[buttonName.."StandardBorder"]:Hide();
+ _G[buttonName.."StandardEmblem"]:Hide();
+ _G[buttonName.."TeamType"]:SetFormattedText(PVP_TEAMSIZE, value.size, value.size);
+ _G[buttonName.."TeamType"]:Show();
+ end
+ end
+end
+
+-- PVP Honor Data
+function InspectPVPHonor_Update()
+ local todayHK, todayHonor, yesterdayHK, yesterdayHonor, lifetimeHK, lifetimeRank = GetInspectHonorData();
+
+ -- Yesterday's values
+ InspectPVPHonorYesterdayKills:SetText(yesterdayHK);
+ InspectPVPHonorYesterdayHonor:SetText(yesterdayHonor);
+
+ -- Lifetime values
+ InspectPVPHonorLifetimeKills:SetText(lifetimeHK);
+ InspectPVPFrameHonorPoints:SetText("");
+ InspectPVPFrameArenaPoints:SetText("");
+
+ -- Hide Point Values
+ InspectPVPFrameHonorPoints:Hide();
+ InspectPVPFrameArenaPoints:Hide();
+
+ -- This session's values
+ InspectPVPHonorTodayKills:SetText(todayHK);
+ InspectPVPHonorTodayHonor:SetText(todayHonor);
+ InspectPVPHonorTodayHonor:SetHeight(14);
+end
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_InspectUI/InspectPVPFrame.xml b/reference/AddOns/Blizzard_InspectUI/InspectPVPFrame.xml
new file mode 100644
index 0000000..21e632f
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/InspectPVPFrame.xml
@@ -0,0 +1,479 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ GameTooltip:SetText(HONOR_POINTS, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(TOOLTIP_HONOR_POINTS, nil, nil, nil, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ GameTooltip:SetText(ARENA_POINTS, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(TOOLTIP_ARENA_POINTS, nil, nil, nil, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_InspectUI/InspectPaperDollFrame.lua b/reference/AddOns/Blizzard_InspectUI/InspectPaperDollFrame.lua
new file mode 100644
index 0000000..fe9228f
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/InspectPaperDollFrame.lua
@@ -0,0 +1,148 @@
+
+function InspectPaperDollFrame_OnLoad(self)
+ self:RegisterEvent("UNIT_MODEL_CHANGED");
+ self:RegisterEvent("UNIT_LEVEL");
+end
+
+function InspectModelFrame_OnUpdate(self, elapsedTime)
+ if ( InspectModelRotateLeftButton:GetButtonState() == "PUSHED" ) then
+ self.rotation = self.rotation + (elapsedTime * 2 * PI * ROTATIONS_PER_SECOND);
+ if ( self.rotation < 0 ) then
+ self.rotation = self.rotation + (2 * PI);
+ end
+ InspectModelFrame:SetRotation(self.rotation);
+ end
+ if ( InspectModelRotateRightButton:GetButtonState() == "PUSHED" ) then
+ self.rotation = self.rotation - (elapsedTime * 2 * PI * ROTATIONS_PER_SECOND);
+ if ( self.rotation > (2 * PI) ) then
+ self.rotation = self.rotation - (2 * PI);
+ end
+ InspectModelFrame:SetRotation(self.rotation);
+ end
+end
+
+function InspectModelFrame_OnLoad(self)
+ self.rotation = 0.61;
+ InspectModelFrame:SetRotation(self.rotation);
+ self:RegisterEvent("DISPLAY_SIZE_CHANGED");
+end
+
+function InspectModelRotateLeftButton_OnClick()
+ InspectModelFrame.rotation = InspectModelFrame.rotation - 0.03;
+ InspectModelFrame:SetRotation(InspectModelFrame.rotation);
+ PlaySound("igInventoryRotateCharacter");
+end
+
+function InspectModelRotateRightButton_OnClick()
+ InspectModelFrame.rotation = InspectModelFrame.rotation + 0.03;
+ InspectModelFrame:SetRotation(InspectModelFrame.rotation);
+ PlaySound("igInventoryRotateCharacter");
+end
+
+function InspectPaperDollFrame_OnEvent(self, event, unit)
+ if ( unit and unit == InspectFrame.unit ) then
+ if ( event == "UNIT_MODEL_CHANGED" ) then
+ InspectModelFrame:RefreshUnit();
+ elseif ( event == "UNIT_LEVEL" ) then
+ InspectPaperDollFrame_SetLevel();
+ end
+ return;
+ end
+end
+
+function InspectPaperDollFrame_SetLevel()
+ local unit, level = InspectFrame.unit, UnitLevel(InspectFrame.unit);
+
+ if ( level == -1 ) then
+ level = "??";
+ end
+
+ InspectLevelText:SetFormattedText(PLAYER_LEVEL,level, UnitRace(unit), UnitClass(unit));
+end
+
+function InspectPaperDollFrame_OnShow()
+ InspectModelFrame:SetUnit(InspectFrame.unit);
+ InspectPaperDollFrame_SetLevel();
+ InspectPaperDollItemSlotButton_Update(InspectHeadSlot);
+ InspectPaperDollItemSlotButton_Update(InspectNeckSlot);
+ InspectPaperDollItemSlotButton_Update(InspectShoulderSlot);
+ InspectPaperDollItemSlotButton_Update(InspectBackSlot);
+ InspectPaperDollItemSlotButton_Update(InspectChestSlot);
+ InspectPaperDollItemSlotButton_Update(InspectShirtSlot);
+ InspectPaperDollItemSlotButton_Update(InspectTabardSlot);
+ InspectPaperDollItemSlotButton_Update(InspectWristSlot);
+ InspectPaperDollItemSlotButton_Update(InspectHandsSlot);
+ InspectPaperDollItemSlotButton_Update(InspectWaistSlot);
+ InspectPaperDollItemSlotButton_Update(InspectLegsSlot);
+ InspectPaperDollItemSlotButton_Update(InspectFeetSlot);
+ InspectPaperDollItemSlotButton_Update(InspectFinger0Slot);
+ InspectPaperDollItemSlotButton_Update(InspectFinger1Slot);
+ InspectPaperDollItemSlotButton_Update(InspectTrinket0Slot);
+ InspectPaperDollItemSlotButton_Update(InspectTrinket1Slot);
+ InspectPaperDollItemSlotButton_Update(InspectMainHandSlot);
+ InspectPaperDollItemSlotButton_Update(InspectSecondaryHandSlot);
+ InspectPaperDollItemSlotButton_Update(InspectRangedSlot);
+end
+
+function InspectPaperDollItemSlotButton_OnLoad(self)
+ self:RegisterEvent("UNIT_INVENTORY_CHANGED");
+ local slotName = self:GetName();
+ local id;
+ local textureName;
+ local checkRelic;
+ id, textureName, checkRelic = GetInventorySlotInfo(strsub(slotName,8));
+ self:SetID(id);
+ local texture = _G[slotName.."IconTexture"];
+ texture:SetTexture(textureName);
+ self.backgroundTextureName = textureName;
+ self.checkRelic = checkRelic;
+end
+
+function InspectPaperDollItemSlotButton_OnEvent(self, event, ...)
+ if ( event == "UNIT_INVENTORY_CHANGED" ) then
+ local arg1 = ...;
+ if ( arg1 == InspectFrame.unit ) then
+ InspectPaperDollItemSlotButton_Update(self);
+ end
+ return;
+ end
+end
+
+function InspectPaperDollItemSlotButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( not GameTooltip:SetInventoryItem(InspectFrame.unit, self:GetID()) ) then
+ local text = _G[strupper(strsub(self:GetName(), 8))];
+ if ( self.checkRelic and UnitHasRelicSlot(InspectFrame.unit) ) then
+ text = _G["RELICSLOT"];
+ end
+ GameTooltip:SetText(text);
+ end
+ CursorUpdate(self);
+end
+
+function InspectPaperDollItemSlotButton_Update(button)
+ local unit = InspectFrame.unit;
+ local textureName = GetInventoryItemTexture(unit, button:GetID());
+ if ( textureName ) then
+ SetItemButtonTexture(button, textureName);
+ SetItemButtonCount(button, GetInventoryItemCount(unit, button:GetID()));
+ button.hasItem = 1;
+ else
+ local textureName = button.backgroundTextureName;
+ if ( button.checkRelic and UnitHasRelicSlot(unit) ) then
+ textureName = "Interface\\Paperdoll\\UI-PaperDoll-Slot-Relic.blp";
+ end
+ SetItemButtonTexture(button, textureName);
+ SetItemButtonCount(button, 0);
+ button.hasItem = nil;
+ end
+ if ( GameTooltip:IsOwned(button) ) then
+ if ( texture ) then
+ if ( not GameTooltip:SetInventoryItem(InspectFrame.unit, button:GetID()) ) then
+ GameTooltip:SetText(_G[strupper(strsub(button:GetName(), 8))]);
+ end
+ else
+ GameTooltip:Hide();
+ end
+ end
+end
diff --git a/reference/AddOns/Blizzard_InspectUI/InspectPaperDollFrame.xml b/reference/AddOns/Blizzard_InspectUI/InspectPaperDollFrame.xml
new file mode 100644
index 0000000..0436171
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/InspectPaperDollFrame.xml
@@ -0,0 +1,352 @@
+
+
+
+
+
+ InspectPaperDollItemSlotButton_OnLoad(self);
+
+
+ InspectPaperDollItemSlotButton_OnEvent(self, event, ...);
+
+
+ HandleModifiedItemClick(GetInventoryItemLink(InspectFrame.unit, self:GetID()));
+
+
+ CursorOnUpdate(self);
+ if ( GameTooltip:IsOwned(self) ) then
+ InspectPaperDollItemSlotButton_OnEnter(self);
+ end
+
+
+ InspectPaperDollItemSlotButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RefreshUnit();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_InspectUI/InspectTalentFrame.lua b/reference/AddOns/Blizzard_InspectUI/InspectTalentFrame.lua
new file mode 100644
index 0000000..29a9457
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/InspectTalentFrame.lua
@@ -0,0 +1,151 @@
+
+local talentSpecInfoCache = {};
+
+function InspectTalentFrameTalent_OnClick(self, button)
+ if ( IsModifiedClick("CHATLINK") ) then
+ local link = GetTalentLink(PanelTemplates_GetSelectedTab(InspectTalentFrame), self:GetID(),
+ InspectTalentFrame.inspect, InspectTalentFrame.pet, InspectTalentFrame.talentGroup);
+ if ( link ) then
+ ChatEdit_InsertLink(link);
+ end
+ end
+end
+
+function InspectTalentFrameTalent_OnEvent(self, event, ...)
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetTalent(PanelTemplates_GetSelectedTab(InspectTalentFrame), self:GetID(),
+ InspectTalentFrame.inspect, InspectTalentFrame.pet, InspectTalentFrame.talentGroup);
+ end
+end
+
+function InspectTalentFrameTalent_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetTalent(PanelTemplates_GetSelectedTab(InspectTalentFrame), self:GetID(),
+ InspectTalentFrame.inspect, InspectTalentFrame.pet, InspectTalentFrame.talentGroup);
+end
+
+function InspectTalentFrame_UpdateTabs()
+ local numTabs = GetNumTalentTabs(InspectTalentFrame.inspect, InspectTalentFrame.pet);
+ local selectedTab = PanelTemplates_GetSelectedTab(InspectTalentFrame);
+ local tab;
+ for i = 1, MAX_TALENT_TABS do
+ tab = _G["InspectTalentFrameTab"..i];
+ if ( tab ) then
+ talentSpecInfoCache[i] = talentSpecInfoCache[i] or { };
+ if ( i <= numTabs ) then
+ local name, icon, pointsSpent, background, previewPointsSpent = GetTalentTabInfo(i, InspectTalentFrame.inspect, InspectTalentFrame.pet, InspectTalentFrame.talentGroup);
+ if ( i == selectedTab ) then
+ -- If tab is the selected tab set the points spent info
+ local displayPointsSpent = pointsSpent + previewPointsSpent;
+ InspectTalentFrameSpentPointsText:SetFormattedText(MASTERY_POINTS_SPENT, name, HIGHLIGHT_FONT_COLOR_CODE..displayPointsSpent..FONT_COLOR_CODE_CLOSE);
+ InspectTalentFrame.pointsSpent = pointsSpent;
+ InspectTalentFrame.previewPointsSpent = previewPointsSpent;
+ end
+ tab:SetText(name);
+ PanelTemplates_TabResize(tab, -10);
+ tab:Show();
+ else
+ tab:Hide();
+ talentSpecInfoCache[i].name = nil;
+ end
+ end
+ end
+end
+
+function InspectTalentFrame_Update()
+ -- update spec info first
+ TalentFrame_UpdateSpecInfoCache(talentSpecInfoCache, InspectTalentFrame.inspect, InspectTalentFrame.pet, InspectTalentFrame.talentGroup);
+
+ -- update tabs
+
+ -- select a tab if one is not already selected
+ if ( not PanelTemplates_GetSelectedTab(InspectTalentFrame) ) then
+ -- if there is a primary tab then we'll prefer that one
+ if ( talentSpecInfoCache.primaryTabIndex > 0 ) then
+ PanelTemplates_SetTab(InspectTalentFrame, talentSpecInfoCache.primaryTabIndex);
+ else
+ PanelTemplates_SetTab(InspectTalentFrame, DEFAULT_TALENT_TAB);
+ end
+ end
+ InspectTalentFrame_UpdateTabs();
+
+ -- update parent tabs
+ PanelTemplates_UpdateTabs(InspectFrame);
+end
+
+function InspectTalentFrame_Refresh()
+ InspectTalentFrame.talentGroup = GetActiveTalentGroup(InspectTalentFrame.inspect);
+ InspectTalentFrame.unit = InspectFrame.unit;
+ TalentFrame_Update(InspectTalentFrame);
+end
+
+function InspectTalentFrame_OnLoad(self)
+ self.updateFunction = InspectTalentFrame_Update;
+ self.inspect = true;
+ self.pet = false;
+ self.talentGroup = 1;
+
+ TalentFrame_Load(self);
+
+ local button;
+ for i = 1, MAX_NUM_TALENTS do
+ button = _G["InspectTalentFrameTalent"..i];
+ if ( button ) then
+ button:SetScript("OnClick", InspectTalentFrameTalent_OnClick);
+ button:SetScript("OnEvent", InspectTalentFrameTalent_OnEvent);
+ button:SetScript("OnEnter", InspectTalentFrameTalent_OnEnter);
+ end
+ end
+
+ -- setup tabs
+ PanelTemplates_SetNumTabs(self, MAX_TALENT_TABS);
+ PanelTemplates_UpdateTabs(self);
+end
+
+function InspectTalentFrame_OnShow()
+ InspectTalentFrame:RegisterEvent("INSPECT_TALENT_READY");
+ InspectTalentFrame_Refresh();
+end
+
+function InspectTalentFrame_OnHide()
+ InspectTalentFrame:UnregisterEvent("INSPECT_TALENT_READY");
+ wipe(talentSpecInfoCache);
+end
+
+function InspectTalentFrame_OnEvent(self, event, ...)
+ if ( event == "INSPECT_TALENT_READY" ) then
+ InspectTalentFrame_Refresh();
+ end
+end
+
+function InspectTalentFrameDownArrow_OnClick(self)
+ local parent = self:GetParent();
+ parent:SetValue(parent:GetValue() + (parent:GetHeight() / 2));
+ PlaySound("UChatScrollButton");
+ UIFrameFlashStop(InspectTalentFrameScrollButtonOverlay);
+end
+
+function InspectTalentFramePointsBar_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:AddLine(TALENT_POINTS);
+ local pointsColor;
+ for index, info in ipairs(talentSpecInfoCache) do
+ if ( info.name ) then
+ if ( talentSpecInfoCache.primaryTabIndex == index ) then
+ pointsColor = GREEN_FONT_COLOR;
+ else
+ pointsColor = HIGHLIGHT_FONT_COLOR;
+ end
+ GameTooltip:AddDoubleLine(
+ info.name,
+ info.pointsSpent,
+ HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b,
+ pointsColor.r, pointsColor.g, pointsColor.b,
+ 1
+ );
+ end
+ end
+
+ GameTooltip:Show();
+end
+
diff --git a/reference/AddOns/Blizzard_InspectUI/InspectTalentFrame.xml b/reference/AddOns/Blizzard_InspectUI/InspectTalentFrame.xml
new file mode 100644
index 0000000..9aeda87
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/InspectTalentFrame.xml
@@ -0,0 +1,453 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PanelTemplates_Tab_OnClick(self, InspectTalentFrame);
+ InspectTalentFrame_Update();
+ TalentFrame_Update(InspectTalentFrame);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+ PanelTemplates_Tab_OnClick(self, InspectTalentFrame);
+ InspectTalentFrame_Update();
+ TalentFrame_Update(InspectTalentFrame);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+ PanelTemplates_Tab_OnClick(self, InspectTalentFrame);
+ InspectTalentFrame_Update();
+ TalentFrame_Update(InspectTalentFrame);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_InspectUI/Localization.lua b/reference/AddOns/Blizzard_InspectUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_InspectUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_ItemSocketingUI/Blizzard_ItemSocketingUI.lua b/reference/AddOns/Blizzard_ItemSocketingUI/Blizzard_ItemSocketingUI.lua
new file mode 100644
index 0000000..8416448
--- /dev/null
+++ b/reference/AddOns/Blizzard_ItemSocketingUI/Blizzard_ItemSocketingUI.lua
@@ -0,0 +1,229 @@
+UIPanelWindows["ItemSocketingFrame"] = { area = "left", pushable = 0 };
+
+GEM_TYPE_INFO = {};
+GEM_TYPE_INFO["Yellow"] = {w=43, h=43, left=0, right=0.16796875, top=0.640625, bottom=0.80859375, r=0.97, g=0.82, b=0.29, CBLeft=0.5546875, CBRight=0.7578125, CBTop=0, CBBottom=0.20703125, OBLeft=0.7578125, OBRight=0.9921875, OBTop=0, OBBottom=0.22265625};
+GEM_TYPE_INFO["Red"] = {w=43, h=43, left=0.1796875, right=0.34375, top=0.640625, bottom=0.80859375, r=1, g=0.47, b=0.47, CBLeft=0.5546875, CBRight=0.7578125, CBTop=0.4765625, CBBottom=0.68359375, OBLeft=0.7578125, OBRight=0.9921875, OBTop=0.4765625, OBBottom=0.69921875};
+GEM_TYPE_INFO["Blue"] = {w=43, h=43, left=0.3515625, right=0.51953125, top=0.640625, bottom=0.80859375, r=0.47, g=0.67, b=1, CBLeft=0.5546875, CBRight=0.7578125, CBTop=0.23828125, CBBottom=0.4453125, OBLeft=0.7578125, OBRight=0.9921875, OBTop=0.23828125, OBBottom=0.4609375};
+GEM_TYPE_INFO["Meta"] = {w=57, h=52, left=0.171875, right=0.3984375, top=0.40234375, bottom=0.609375, r=1, g=1, b=1, CBLeft=0.5546875, CBRight=0.7578125, CBTop=0, CBBottom=0.20703125, OBLeft=0.7578125, OBRight=0.9921875, OBTop=0, OBBottom=0.22265625};
+GEM_TYPE_INFO["Socket"] = {w=57, h=52, left=0.171875, right=0.3984375, top=0.40234375, bottom=0.609375, r=1, g=1, b=1, CBLeft=0.5546875, CBRight=0.7578125, CBTop=0, CBBottom=0.20703125, OBLeft=0.7578125, OBRight=0.9921875, OBTop=0, OBBottom=0.22265625};
+
+ITEM_SOCKETING_DESCRIPTION_MIN_WIDTH = 240;
+
+function ItemSocketingFrame_OnLoad(self)
+ self:RegisterEvent("SOCKET_INFO_UPDATE");
+ self:RegisterEvent("SOCKET_INFO_CLOSE");
+ ItemSocketingScrollFrameScrollBarScrollUpButton:SetPoint("BOTTOM", ItemSocketingScrollFrameScrollBar, "TOP", 0, 1);
+ ItemSocketingScrollFrameScrollBarScrollDownButton:SetPoint("TOP", ItemSocketingScrollFrameScrollBar, "BOTTOM", 0, -3);
+ ItemSocketingScrollFrameTop:SetPoint("TOP", ItemSocketingScrollFrameScrollBarScrollUpButton, "TOP", -2, 3);
+ ItemSocketingScrollFrameScrollBar:SetPoint("TOPLEFT", ItemSocketingScrollFrame, "TOPRIGHT", 7.9999995231628, -18);
+ ItemSocketingScrollFrameScrollBar:SetHeight(221);
+ ItemSocketingDescription:SetMinimumWidth(ITEM_SOCKETING_DESCRIPTION_MIN_WIDTH, 1);
+end
+
+function ItemSocketingFrame_OnEvent(self, event, ...)
+ if ( event == "SOCKET_INFO_UPDATE" ) then
+ ItemSocketingFrame_Update();
+ ItemSocketingFrame_LoadUI();
+ if ( not ItemSocketingFrame:IsShown() ) then
+ ShowUIPanel(ItemSocketingFrame);
+ end
+ elseif ( event == "SOCKET_INFO_CLOSE" ) then
+ HideUIPanel(ItemSocketingFrame);
+ end
+end
+
+function ItemSocketingFrame_Update()
+ ItemSocketingFrame.destroyingGem = nil;
+ ItemSocketingFrame.itemIsRefundable = nil;
+ ItemSocketingFrame.itemIsBoundTradeable = nil;
+ if(GetSocketItemRefundable()) then
+ ItemSocketingFrame.itemIsRefundable = true;
+ elseif(GetSocketItemBoundTradeable()) then
+ ItemSocketingFrame.itemIsBoundTradeable = true;
+ end
+
+ local numSockets = GetNumSockets();
+ local name, icon, quality, gemMatchesSocket;
+ local socket, socketName;
+ local numNewGems = numSockets;
+ local closedBracket, openBracket;
+ local bracketsOpen, gemColor, gemBorder, gemColorText, gemInfo;
+ local numMatches = 0;
+ for i=1, MAX_NUM_SOCKETS do
+ socket = _G["ItemSocketingSocket"..i];
+ socketName = "ItemSocketingSocket"..i;
+ closedBracket = _G[socketName.."BracketFrameClosedBracket"];
+ openBracket = _G[socketName.."BracketFrameOpenBracket"];
+ if ( i <= numSockets ) then
+ -- See if there's a replacement gem and if not see if there's an existing gem
+ name, icon, gemMatchesSocket = GetNewSocketInfo(i);
+ bracketsOpen = 1;
+ if ( not name ) then
+ name, icon, gemMatchesSocket = GetExistingSocketInfo(i);
+ if ( icon ) then
+ bracketsOpen = nil;
+ end
+
+ -- Count down new gems if there's no name
+ numNewGems = numNewGems - 1;
+ elseif ( GetExistingSocketInfo(i) ) then
+ ItemSocketingFrame.destroyingGem = 1;
+ end
+ --Handle one color only right now
+ gemColor = GetSocketTypes(i);
+ if ( gemMatchesSocket ) then
+ local color = GEM_TYPE_INFO[gemColor];
+ AnimatedShine_Start(socket, color.r, color.g, color.b);
+ numMatches = numMatches + 1;
+ else
+ AnimatedShine_Stop(socket);
+ end
+ if ( bracketsOpen ) then
+ -- Show open brackets
+ closedBracket:Hide();
+ openBracket:Show();
+ else
+ -- Show closed brackets
+ closedBracket:Show();
+ openBracket:Hide();
+ end
+
+ if ( gemColor ~= "" ) then
+ gemInfo = GEM_TYPE_INFO[gemColor];
+ gemBorder = _G[socketName.."Background"]
+ gemBorder:SetWidth(gemInfo.w);
+ gemBorder:SetHeight(gemInfo.h);
+ gemBorder:SetTexCoord(gemInfo.left, gemInfo.right, gemInfo.top, gemInfo.bottom);
+ gemBorder:Show();
+ if ( gemColor == "Meta" ) then
+ -- Special stuff for meta gem sockets
+ SetDesaturation(openBracket, 1);
+ SetDesaturation(closedBracket, 1);
+ openBracket:SetTexCoord(gemInfo.OBLeft, gemInfo.OBRight, gemInfo.OBTop, gemInfo.OBBottom);
+ closedBracket:SetTexCoord(gemInfo.CBLeft, gemInfo.CBRight, gemInfo.CBTop, gemInfo.CBBottom);
+ else
+ SetDesaturation(openBracket, nil);
+ SetDesaturation(closedBracket, nil);
+ openBracket:SetTexCoord(gemInfo.OBLeft, gemInfo.OBRight, gemInfo.OBTop, gemInfo.OBBottom);
+ closedBracket:SetTexCoord(gemInfo.CBLeft, gemInfo.CBRight, gemInfo.CBTop, gemInfo.CBBottom);
+ end
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ gemColorText = _G[socketName.."Color"];
+ gemColorText:SetText(_G[strupper(gemColor) .. "_GEM"]);
+ gemColorText:Show();
+ else
+ _G[socketName.."Color"]:Hide();
+ end
+ else
+ gemBorder:Hide();
+ end
+
+ SetItemButtonTexture(socket, icon);
+ socket:Show();
+ else
+ socket:Hide();
+ end
+ end
+
+ -- Playsound if all sockets are matched
+ if ( numMatches == numsockets ) then
+ -- Will probably need a new sound
+ PlaySound("MapPing");
+ end
+
+ -- Position the sockets and show/hide the border graphics
+ if ( numSockets == 3 ) then
+ ItemSocketingSocket1Right:Hide();
+ ItemSocketingSocket2Left:Show();
+ ItemSocketingSocket2Right:Hide();
+ ItemSocketingSocket3Left:Show();
+ ItemSocketingSocket3Right:Show();
+ ItemSocketingSocket1:SetPoint("BOTTOM", ItemSocketingFrame, "BOTTOM", -75, 62);
+ elseif ( numSockets == 2 ) then
+ ItemSocketingSocket1Right:Hide();
+ ItemSocketingSocket2Left:Show();
+ ItemSocketingSocket2Right:Show();
+ ItemSocketingSocket1:SetPoint("BOTTOM", ItemSocketingFrame, "BOTTOM", -35, 62);
+ else
+ ItemSocketingSocket1:SetPoint("BOTTOM", ItemSocketingFrame, "BOTTOM", 0, 62);
+ ItemSocketingSocket1Right:Show();
+ end
+
+ -- Set portrait
+ name, icon, quality = GetSocketItemInfo();
+ SetPortraitToTexture("ItemSocketingFramePortrait", icon);
+
+ -- see if has a scrollbar and resize accordingly
+ local scrollBarOffset = 28;
+ if ( ItemSocketingScrollFrame:GetVerticalScrollRange() ~= 0 ) then
+ scrollBarOffset = 0;
+ end
+ ItemSocketingScrollFrame:SetWidth(269+scrollBarOffset);
+ ItemSocketingDescription:SetMinimumWidth(ITEM_SOCKETING_DESCRIPTION_MIN_WIDTH+scrollBarOffset, 1);
+ -- Owner needs to be set everytime since it is cleared everytime the tooltip is hidden
+ ItemSocketingDescription:SetOwner(ItemSocketingScrollChild, "ANCHOR_PRESERVE");
+ ItemSocketingDescription:SetSocketedItem();
+
+ -- Update socket button
+ if ( numNewGems == 0 ) then
+ ItemSocketingSocketButton_Disable();
+ else
+ ItemSocketingSocketButton_Enable();
+ end
+end
+
+function ItemSocketingSocketButton_OnScrollRangeChanged()
+
+ -- see if has a scrollbar and resize accordingly
+ local scrollBarOffset = 28;
+ if ( ItemSocketingScrollFrame:GetVerticalScrollRange() ~= 0 ) then
+ scrollBarOffset = 0;
+ end
+ ItemSocketingScrollFrame:SetWidth(269+scrollBarOffset);
+ ItemSocketingDescription:SetMinimumWidth(ITEM_SOCKETING_DESCRIPTION_MIN_WIDTH+scrollBarOffset, 1);
+
+ ItemSocketingDescription:SetSocketedItem();
+end
+
+function ItemSocketingSocketButton_OnEnter(self)
+ local newSocket = GetNewSocketInfo(self:GetID());
+ local existingSocket = GetExistingSocketInfo(self:GetID());
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( newSocket ) then
+ GameTooltip:SetSocketGem(self:GetID());
+ else
+ GameTooltip:SetExistingSocketGem(self:GetID());
+ end
+ if ( newSocket and existingSocket ) then
+ ShoppingTooltip1:SetOwner(GameTooltip, "ANCHOR_NONE");
+ ShoppingTooltip1:ClearAllPoints();
+ ShoppingTooltip1:SetPoint("TOPLEFT", "GameTooltip", "TOPRIGHT", 0, -10);
+ ShoppingTooltip1:SetExistingSocketGem(self:GetID(), 1);
+ ShoppingTooltip1:Show();
+ end
+end
+
+function ItemSocketingSocketButton_OnEvent(self, event, ...)
+ if ( event == "SOCKET_INFO_UPDATE" ) then
+ if ( GameTooltip:IsOwned(self) ) then
+ ItemSocketingSocketButton_OnEnter(self);
+ end
+ end
+end
+
+function ItemSocketingSocketButton_Disable()
+ ItemSocketingSocketButton.disabled = 1;
+ ItemSocketingSocketButton:Disable();
+ ItemSocketingSocketButtonLeft:SetTexture("Interface\\Buttons\\UI-Panel-Button-Disabled");
+ ItemSocketingSocketButtonMiddle:SetTexture("Interface\\Buttons\\UI-Panel-Button-Disabled");
+ ItemSocketingSocketButtonRight:SetTexture("Interface\\Buttons\\UI-Panel-Button-Disabled");
+end
+
+function ItemSocketingSocketButton_Enable()
+ ItemSocketingSocketButton.disabled = nil;
+ ItemSocketingSocketButton:Enable();
+ ItemSocketingSocketButtonLeft:SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
+ ItemSocketingSocketButtonMiddle:SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
+ ItemSocketingSocketButtonRight:SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
+end
diff --git a/reference/AddOns/Blizzard_ItemSocketingUI/Blizzard_ItemSocketingUI.toc b/reference/AddOns/Blizzard_ItemSocketingUI/Blizzard_ItemSocketingUI.toc
new file mode 100644
index 0000000..b2aa69f
--- /dev/null
+++ b/reference/AddOns/Blizzard_ItemSocketingUI/Blizzard_ItemSocketingUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard Item Socketing UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_ItemSocketingUI.xml
+Localization.lua
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_ItemSocketingUI/Blizzard_ItemSocketingUI.xml b/reference/AddOns/Blizzard_ItemSocketingUI/Blizzard_ItemSocketingUI.xml
new file mode 100644
index 0000000..e484972
--- /dev/null
+++ b/reference/AddOns/Blizzard_ItemSocketingUI/Blizzard_ItemSocketingUI.xml
@@ -0,0 +1,461 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForDrag("LeftButton");
+ self:RegisterEvent("SOCKET_INFO_UPDATE");
+
+
+ ItemSocketingSocketButton_OnEvent(self, event, ...);
+
+
+ if ( IsModifiedClick() ) then
+ local link = GetNewSocketLink(self:GetID()) or
+ GetExistingSocketLink(self:GetID());
+ HandleModifiedItemClick(link);
+ else
+ StaticPopup_Hide("DELETE_ITEM");
+ StaticPopup_Hide("DELETE_GOOD_ITEM");
+ ClickSocketButton(self:GetID());
+ end
+
+
+ StaticPopup_Hide("DELETE_ITEM");
+ StaticPopup_Hide("DELETE_GOOD_ITEM");
+ ClickSocketButton(self:GetID());
+
+
+ StaticPopup_Hide("DELETE_ITEM");
+ StaticPopup_Hide("DELETE_GOOD_ITEM");
+ ClickSocketButton(self:GetID());
+
+
+ ItemSocketingSocketButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+ ShoppingTooltip1:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.scrollBarHideable = 1;
+ ScrollFrame_OnLoad(self);
+ ScrollFrame_OnScrollRangeChanged(self, 0, 0);
+
+
+ ScrollFrame_OnScrollRangeChanged(self, 0, yrange);
+ ItemSocketingSocketButton_OnScrollRangeChanged(self);
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdrop(nil);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if( ItemSocketingFrame.itemIsRefundable) then
+ local dialog = StaticPopup_Show("END_REFUND");
+ if(dialog) then
+ dialog.data = 2;
+ end
+ elseif ( ItemSocketingFrame.itemIsBoundTradeable ) then
+ local dialog = StaticPopup_Show("END_BOUND_TRADEABLE", nil, nil, "gem");
+ elseif ( ItemSocketingFrame.destroyingGem ) then
+ StaticPopup_Show("CONFIRM_ACCEPT_SOCKETS");
+ else
+ AcceptSockets();
+ PlaySound("JewelcraftingFinalize");
+ end
+
+
+ if ( not self.disabled ) then
+ _G[self:GetName().."Left"]:SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
+ _G[self:GetName().."Middle"]:SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
+ _G[self:GetName().."Right"]:SetTexture("Interface\\Buttons\\UI-Panel-Button-Down");
+ end
+
+
+ if ( not self.disabled ) then
+ _G[self:GetName().."Left"]:SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
+ _G[self:GetName().."Middle"]:SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
+ _G[self:GetName().."Right"]:SetTexture("Interface\\Buttons\\UI-Panel-Button-Up");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoOpen");
+
+
+
+ PlaySound("igCharacterInfoClose");
+ StaticPopup_Hide("CONFIRM_ACCEPT_SOCKETS");
+ CloseSocketInfo();
+
+
+
+
diff --git a/reference/AddOns/Blizzard_ItemSocketingUI/Localization.lua b/reference/AddOns/Blizzard_ItemSocketingUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_ItemSocketingUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_MacroUI/Blizzard_MacroUI.lua b/reference/AddOns/Blizzard_MacroUI/Blizzard_MacroUI.lua
new file mode 100644
index 0000000..9a3cc11
--- /dev/null
+++ b/reference/AddOns/Blizzard_MacroUI/Blizzard_MacroUI.lua
@@ -0,0 +1,353 @@
+MAX_ACCOUNT_MACROS = 36;
+MAX_CHARACTER_MACROS = 18;
+NUM_MACROS_PER_ROW = 6;
+NUM_MACRO_ICONS_SHOWN = 20;
+NUM_ICONS_PER_ROW = 5;
+NUM_ICON_ROWS = 4;
+MACRO_ICON_ROW_HEIGHT = 36;
+
+UIPanelWindows["MacroFrame"] = { area = "left", pushable = 5, whileDead = 1 };
+
+function MacroFrame_Show()
+ ShowUIPanel(MacroFrame);
+end
+
+function MacroFrame_OnLoad(self)
+ MacroFrame_SetAccountMacros();
+ PanelTemplates_SetNumTabs(MacroFrame, 2);
+ PanelTemplates_SetTab(MacroFrame, 1);
+end
+
+function MacroFrame_OnShow(self)
+ MacroFrame_Update();
+ PlaySound("igCharacterInfoOpen");
+ UpdateMicroButtons();
+end
+
+function MacroFrame_OnHide(self)
+ MacroPopupFrame:Hide();
+ MacroFrame_SaveMacro();
+ --SaveMacros();
+ PlaySound("igCharacterInfoClose");
+ UpdateMicroButtons();
+end
+
+function MacroFrame_SetAccountMacros()
+ MacroFrame.macroBase = 0;
+ MacroFrame.macroMax = MAX_ACCOUNT_MACROS;
+ local numAccountMacros, numCharacterMacros = GetNumMacros();
+ if ( numAccountMacros > 0 ) then
+ MacroFrame_SelectMacro(MacroFrame.macroBase + 1);
+ else
+ MacroFrame_SelectMacro(nil);
+ end
+end
+
+function MacroFrame_SetCharacterMacros()
+ MacroFrame.macroBase = MAX_ACCOUNT_MACROS;
+ MacroFrame.macroMax = MAX_CHARACTER_MACROS;
+ local numAccountMacros, numCharacterMacros = GetNumMacros();
+ if ( numCharacterMacros > 0 ) then
+ MacroFrame_SelectMacro(MacroFrame.macroBase + 1);
+ else
+ MacroFrame_SelectMacro(nil);
+ end
+end
+
+function MacroFrame_Update()
+ local numMacros;
+ local numAccountMacros, numCharacterMacros = GetNumMacros();
+ local macroButtonName, macroButton, macroIcon, macroName;
+ local name, texture, body;
+ local selectedName, selectedBody, selectedIcon;
+
+ if ( MacroFrame.macroBase == 0 ) then
+ numMacros = numAccountMacros;
+ else
+ numMacros = numCharacterMacros;
+ end
+
+ -- Macro List
+ local maxMacroButtons = max(MAX_ACCOUNT_MACROS, MAX_CHARACTER_MACROS);
+ for i=1, maxMacroButtons do
+ macroButtonName = "MacroButton"..i;
+ macroButton = _G[macroButtonName];
+ macroIcon = _G[macroButtonName.."Icon"];
+ macroName = _G[macroButtonName.."Name"];
+ if ( i <= MacroFrame.macroMax ) then
+ if ( i <= numMacros ) then
+ name, texture, body = GetMacroInfo(MacroFrame.macroBase + i);
+ macroIcon:SetTexture(texture);
+ macroName:SetText(name);
+ macroButton:Enable();
+ -- Highlight Selected Macro
+ if ( MacroFrame.selectedMacro and (i == (MacroFrame.selectedMacro - MacroFrame.macroBase)) ) then
+ macroButton:SetChecked(1);
+ MacroFrameSelectedMacroName:SetText(name);
+ MacroFrameText:SetText(body);
+ MacroFrameSelectedMacroButton:SetID(i);
+ MacroFrameSelectedMacroButtonIcon:SetTexture(texture);
+ MacroPopupFrame.selectedIconTexture = texture;
+ else
+ macroButton:SetChecked(0);
+ end
+ else
+ macroButton:SetChecked(0);
+ macroIcon:SetTexture("");
+ macroName:SetText("");
+ macroButton:Disable();
+ end
+ macroButton:Show();
+ else
+ macroButton:Hide();
+ end
+ end
+
+ -- Macro Details
+ if ( MacroFrame.selectedMacro ~= nil ) then
+ MacroFrame_ShowDetails();
+ MacroDeleteButton:Enable();
+ else
+ MacroFrame_HideDetails();
+ MacroDeleteButton:Disable();
+ end
+
+ --Update New Button
+ if ( numMacros < MacroFrame.macroMax ) then
+ MacroNewButton:Enable();
+ else
+ MacroNewButton:Disable();
+ end
+
+ -- Disable Buttons
+ if ( MacroPopupFrame:IsShown() ) then
+ MacroEditButton:Disable();
+ MacroDeleteButton:Disable();
+ else
+ MacroEditButton:Enable();
+ MacroDeleteButton:Enable();
+ end
+
+ if ( not MacroFrame.selectedMacro ) then
+ MacroDeleteButton:Disable();
+ end
+end
+
+function MacroFrame_AddMacroLine(line)
+ if ( MacroFrameText:IsVisible() ) then
+ MacroFrameText:SetText(MacroFrameText:GetText()..line);
+ end
+end
+
+function MacroButton_OnClick(self, button)
+ MacroFrame_SaveMacro();
+ MacroFrame_SelectMacro(MacroFrame.macroBase + self:GetID());
+ MacroFrame_Update();
+ MacroPopupFrame:Hide();
+ MacroFrameText:ClearFocus();
+end
+
+function MacroFrame_SelectMacro(id)
+ MacroFrame.selectedMacro = id;
+end
+
+function MacroFrame_DeleteMacro()
+ local selectedMacro = MacroFrame.selectedMacro;
+ DeleteMacro(selectedMacro);
+ -- the order of the return values (account macros, character macros) matches up with the IDs of the tabs
+ local numMacros = select(PanelTemplates_GetSelectedTab(MacroFrame), GetNumMacros());
+ if ( selectedMacro > numMacros + MacroFrame.macroBase) then
+ selectedMacro = selectedMacro - 1;
+ end
+ if ( selectedMacro <= MacroFrame.macroBase ) then
+ MacroFrame.selectedMacro = nil;
+ else
+ MacroFrame.selectedMacro = selectedMacro;
+ end
+ MacroFrame_Update();
+ MacroFrameText:ClearFocus();
+end
+
+function MacroNewButton_OnClick(self, button)
+ MacroFrame_SaveMacro();
+ MacroPopupFrame.mode = "new";
+ MacroPopupFrame:Show();
+end
+
+function MacroEditButton_OnClick(self, button)
+ MacroFrame_SaveMacro();
+ MacroPopupFrame.mode = "edit";
+ MacroPopupFrame:Show();
+end
+
+function MacroFrame_HideDetails()
+ MacroEditButton:Hide();
+ MacroFrameCharLimitText:Hide();
+ MacroFrameText:Hide();
+ MacroFrameSelectedMacroName:Hide();
+ MacroFrameSelectedMacroBackground:Hide();
+ MacroFrameSelectedMacroButton:Hide();
+end
+
+function MacroFrame_ShowDetails()
+ MacroEditButton:Show();
+ MacroFrameCharLimitText:Show();
+ MacroFrameEnterMacroText:Show();
+ MacroFrameText:Show();
+ MacroFrameSelectedMacroName:Show();
+ MacroFrameSelectedMacroBackground:Show();
+ MacroFrameSelectedMacroButton:Show();
+end
+
+function MacroButtonContainer_OnLoad(self)
+ local button;
+ local maxMacroButtons = max(MAX_ACCOUNT_MACROS, MAX_CHARACTER_MACROS);
+ for i=1, maxMacroButtons do
+ button = CreateFrame("CheckButton", "MacroButton"..i, self, "MacroButtonTemplate");
+ button:SetID(i);
+ if ( i == 1 ) then
+ button:SetPoint("TOPLEFT", self, "TOPLEFT", 6, -6);
+ elseif ( mod(i, NUM_MACROS_PER_ROW) == 1 ) then
+ button:SetPoint("TOP", "MacroButton"..(i-NUM_MACROS_PER_ROW), "BOTTOM", 0, -10);
+ else
+ button:SetPoint("LEFT", "MacroButton"..(i-1), "RIGHT", 13, 0);
+ end
+ end
+end
+
+function MacroPopupFrame_OnShow(self)
+ MacroPopupEditBox:SetFocus();
+
+ PlaySound("igCharacterInfoOpen");
+ MacroPopupFrame_Update(self);
+ MacroPopupOkayButton_Update();
+
+ if ( self.mode == "new" ) then
+ MacroFrameText:Hide();
+ MacroPopupButton_SelectTexture(1);
+ end
+
+ -- Disable Buttons
+ MacroEditButton:Disable();
+ MacroDeleteButton:Disable();
+ MacroNewButton:Disable();
+ MacroFrameTab1:Disable();
+ MacroFrameTab2:Disable();
+end
+
+function MacroPopupFrame_OnHide(self)
+ if ( self.mode == "new" ) then
+ MacroFrameText:Show();
+ MacroFrameText:SetFocus();
+ end
+
+ -- Enable Buttons
+ MacroEditButton:Enable();
+ MacroDeleteButton:Enable();
+ local numMacros;
+ local numAccountMacros, numCharacterMacros = GetNumMacros();
+ if ( MacroFrame.macroBase == 0 ) then
+ numMacros = numAccountMacros;
+ else
+ numMacros = numCharacterMacros;
+ end
+ if ( numMacros < MacroFrame.macroMax ) then
+ MacroNewButton:Enable();
+ end
+ -- Enable tabs
+ PanelTemplates_UpdateTabs(MacroFrame);
+end
+
+function MacroPopupFrame_Update(self)
+ self = self or MacroPopupFrame;
+ local numMacroIcons = GetNumMacroIcons();
+ local macroPopupIcon, macroPopupButton;
+ local macroPopupOffset = FauxScrollFrame_GetOffset(MacroPopupScrollFrame);
+ local index;
+
+ -- Determine whether we're creating a new macro or editing an existing one
+ if ( self.mode == "new" ) then
+ MacroPopupEditBox:SetText("");
+ elseif ( self.mode == "edit" ) then
+ local name, texture, body = GetMacroInfo(MacroFrame.selectedMacro);
+ MacroPopupEditBox:SetText(name);
+ end
+
+ -- Icon list
+ local texture;
+ for i=1, NUM_MACRO_ICONS_SHOWN do
+ macroPopupIcon = _G["MacroPopupButton"..i.."Icon"];
+ macroPopupButton = _G["MacroPopupButton"..i];
+ index = (macroPopupOffset * NUM_ICONS_PER_ROW) + i;
+ texture = GetMacroIconInfo(index);
+ if ( index <= numMacroIcons ) then
+ macroPopupIcon:SetTexture(texture);
+ macroPopupButton:Show();
+ else
+ macroPopupIcon:SetTexture("");
+ macroPopupButton:Hide();
+ end
+ if ( MacroPopupFrame.selectedIcon and (index == MacroPopupFrame.selectedIcon) ) then
+ macroPopupButton:SetChecked(1);
+ elseif ( MacroPopupFrame.selectedIconTexture == texture ) then
+ macroPopupButton:SetChecked(1);
+ else
+ macroPopupButton:SetChecked(nil);
+ end
+ end
+
+ -- Scrollbar stuff
+ FauxScrollFrame_Update(MacroPopupScrollFrame, ceil(numMacroIcons / NUM_ICONS_PER_ROW) , NUM_ICON_ROWS, MACRO_ICON_ROW_HEIGHT );
+end
+
+function MacroPopupFrame_CancelEdit()
+ MacroPopupFrame:Hide();
+ MacroFrame_Update();
+ MacroPopupFrame.selectedIcon = nil;
+end
+
+function MacroPopupOkayButton_Update()
+ if ( (strlen(MacroPopupEditBox:GetText()) > 0) and MacroPopupFrame.selectedIcon ) then
+ MacroPopupOkayButton:Enable();
+ else
+ MacroPopupOkayButton:Disable();
+ end
+ if ( MacroPopupFrame.mode == "edit" and (strlen(MacroPopupEditBox:GetText()) > 0) ) then
+ MacroPopupOkayButton:Enable();
+ end
+end
+
+function MacroPopupButton_SelectTexture(selectedIcon)
+ MacroPopupFrame.selectedIcon = selectedIcon;
+ -- Clear out selected texture
+ MacroPopupFrame.selectedIconTexture = nil;
+ MacroFrameSelectedMacroButtonIcon:SetTexture(GetMacroIconInfo(MacroPopupFrame.selectedIcon));
+ MacroPopupOkayButton_Update();
+ local mode = MacroPopupFrame.mode;
+ MacroPopupFrame.mode = nil;
+ MacroPopupFrame_Update(MacroPopupFrame);
+ MacroPopupFrame.mode = mode;
+end
+
+function MacroPopupButton_OnClick(self, button)
+ MacroPopupButton_SelectTexture(self:GetID() + (FauxScrollFrame_GetOffset(MacroPopupScrollFrame) * NUM_ICONS_PER_ROW));
+end
+
+function MacroPopupOkayButton_OnClick(self, button)
+ local index = 1
+ if ( MacroPopupFrame.mode == "new" ) then
+ index = CreateMacro(MacroPopupEditBox:GetText(), MacroPopupFrame.selectedIcon, nil, (MacroFrame.macroBase > 0));
+ elseif ( MacroPopupFrame.mode == "edit" ) then
+ index = EditMacro(MacroFrame.selectedMacro, MacroPopupEditBox:GetText(), MacroPopupFrame.selectedIcon);
+ end
+ MacroPopupFrame:Hide();
+ MacroFrame_SelectMacro(index);
+ MacroFrame_Update();
+end
+
+function MacroFrame_SaveMacro()
+ if ( MacroFrame.textChanged and MacroFrame.selectedMacro ) then
+ EditMacro(MacroFrame.selectedMacro, nil, nil, MacroFrameText:GetText());
+ MacroFrame.textChanged = nil;
+ end
+end
diff --git a/reference/AddOns/Blizzard_MacroUI/Blizzard_MacroUI.toc b/reference/AddOns/Blizzard_MacroUI/Blizzard_MacroUI.toc
new file mode 100644
index 0000000..7ab2186
--- /dev/null
+++ b/reference/AddOns/Blizzard_MacroUI/Blizzard_MacroUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard Macro UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_MacroUI.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_MacroUI/Blizzard_MacroUI.xml b/reference/AddOns/Blizzard_MacroUI/Blizzard_MacroUI.xml
new file mode 100644
index 0000000..1571e35
--- /dev/null
+++ b/reference/AddOns/Blizzard_MacroUI/Blizzard_MacroUI.xml
@@ -0,0 +1,840 @@
+
+
+
+
+
+ self:RegisterForDrag("LeftButton");
+
+
+ MacroButton_OnClick(self, button, down);
+
+
+ PickupMacro(MacroFrame.macroBase + self:GetID());
+
+
+
+
+
+
+ MacroPopupButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetChecked(nil);
+ PickupMacro(MacroFrame.selectedMacro);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MacroFrame.textChanged = 1;
+ if ( MacroPopupFrame.mode == "new" ) then
+ MacroPopupFrame:Hide();
+ end
+ MacroFrameCharLimitText:SetFormattedText(MACROFRAME_CHAR_LIMIT, MacroFrameText:GetNumLetters());
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent());
+
+
+
+ ScrollingEdit_OnUpdate(self, elapsed, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MacroFrameText:SetFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PanelTemplates_TabResize(self, -15);
+ _G[self:GetName().."HighlightTexture"]:SetWidth(self:GetTextWidth() + 31);
+
+
+ PanelTemplates_SetTab(MacroFrame, self:GetID());
+ MacroFrame_SaveMacro();
+ MacroFrame_SetAccountMacros();
+ MacroFrame_Update();
+ MacroButtonScrollFrame:SetVerticalScroll(0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFormattedText(CHARACTER_SPECIFIC_MACROS, UnitName("player"));
+ _G[self:GetName().."HighlightTexture"]:SetWidth(self:GetTextWidth() + 31);
+ PanelTemplates_TabResize(self, -15, nil, 150);
+
+
+ PanelTemplates_SetTab(MacroFrame, self:GetID());
+ MacroFrame_SaveMacro();
+ MacroFrame_SetCharacterMacros();
+ MacroFrame_Update();
+ MacroButtonScrollFrame:SetVerticalScroll(0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MacroFrame_DeleteMacro();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MacroPopupOkayButton_Update();
+ MacroFrameSelectedMacroName:SetText(self:GetText());
+
+
+
+ if ( MacroPopupOkayButton:IsEnabled() ~= 0 ) then
+ MacroPopupOkayButton_OnClick(MacroPopupOkayButton);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, MACRO_ICON_ROW_HEIGHT, MacroPopupFrame_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MacroPopupFrame_CancelEdit();
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MacroPopupOkayButton_OnClick();
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_MacroUI/Localization.lua b/reference/AddOns/Blizzard_MacroUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_MacroUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_RaidUI/Blizzard_RaidUI.lua b/reference/AddOns/Blizzard_RaidUI/Blizzard_RaidUI.lua
new file mode 100644
index 0000000..87cb47e
--- /dev/null
+++ b/reference/AddOns/Blizzard_RaidUI/Blizzard_RaidUI.lua
@@ -0,0 +1,1516 @@
+MAX_RAID_GROUPS = 8;
+RAID_RANGE_ALPHA = 0.5;
+MOVING_RAID_MEMBER = nil;
+TARGET_RAID_SLOT = nil;
+RAID_SUBGROUP_LISTS = {};
+NUM_RAID_PULLOUT_FRAMES = 0;
+RAID_PULLOUT_BUTTON_HEIGHT = 33;
+MOVING_RAID_PULLOUT = nil;
+RAID_PULLOUT_POSITIONS = {};
+RAID_SINGLE_POSITIONS = {};
+MAX_RAID_AURAS = 4;
+
+RAID_CLASS_BUTTONS = { };
+do
+ -- fill in the table
+ for index, value in ipairs(CLASS_SORT_ORDER) do
+ RAID_CLASS_BUTTONS[value] = { button = index, coords = CLASS_ICON_TCOORDS[value] };
+ end
+ RAID_CLASS_BUTTONS["PETS"] = { button = 11, coords = {0, 1, 0, 1} };
+ RAID_CLASS_BUTTONS["MAINTANK"] = { button = 12, coords = {0, 1, 0, 1} };
+ RAID_CLASS_BUTTONS["MAINASSIST"] = { button = 13, coords = {0, 1, 0, 1} };
+end
+MAX_RAID_CLASS_BUTTONS = MAX_CLASSES + 3;
+
+RAID_PULLOUT_SAVED_SETTINGS = {
+ ["showTarget"] = true,
+ ["showBuffs"] = true,
+ ["showTargetTarget"] = true,
+ ["showDebuffs"] = true,
+ ["showBG"] = true,
+};
+
+local getn = getn;
+local format = format;
+local next = next;
+local gsub = gsub;
+local tinsert = tinsert;
+local tremove = tremove;
+local tonumber = tonumber;
+local tostring = tostring;
+
+function RaidClassButton_OnLoad(self)
+ self:RegisterForDrag("LeftButton");
+ local id = self:GetID();
+ local icon = _G[self:GetName().."IconTexture"];
+ for index, value in pairs(RAID_CLASS_BUTTONS) do
+ if ( id == value.button ) then
+ self.class = index;
+ if ( index == "PETS" ) then
+ icon:SetTexture("Interface\\RaidFrame\\UI-RaidFrame-Pets");
+ elseif ( index == "MAINTANK" ) then
+ icon:SetTexture("Interface\\RaidFrame\\UI-RaidFrame-MainTank");
+ elseif ( index == "MAINASSIST" ) then
+ icon:SetTexture("Interface\\RaidFrame\\UI-RaidFrame-MainAssist");
+ else
+ icon:SetTexture("Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes");
+ end
+ icon:SetTexCoord(value.coords[1], value.coords[2], value.coords[3], value.coords[4]);
+
+ end
+ end
+ _G[self:GetName().."Count"]:SetTextHeight(9);
+end
+
+function RaidClassButton_Update()
+ -- Update Actual Count
+ local button, icon, count;
+ for index, value in pairs(RAID_CLASS_BUTTONS) do
+ button = _G["RaidClassButton"..value.button];
+ count = _G["RaidClassButton"..value.button.."Count"];
+ icon = _G["RaidClassButton"..value.button.."IconTexture"];
+
+ if ( index == "PETS" ) then
+ local petCount = 0;
+ for i, v in pairs(RAID_SUBGROUP_LISTS[index]) do
+ if ( UnitExists("raidpet"..RAID_SUBGROUP_LISTS[index][i]) ) then
+ petCount = petCount + 1;
+ end
+ end
+ button.count = petCount;
+ else
+ if ( RAID_SUBGROUP_LISTS[index] ) then
+ button.count = #RAID_SUBGROUP_LISTS[index];
+ end
+ end
+
+ if ( button.count > 0 ) then
+ SetItemButtonDesaturated(button, nil);
+ icon:SetAlpha(1);
+ count:SetText(button.count);
+ count:Show();
+ if ( index == "PETS" ) then
+ button.class = PETS;
+ button.fileName = index;
+ elseif ( index == "MAINTANK" ) then
+ button.class = MAINTANK;
+ button.fileName = index;
+ button.id = RAID_SUBGROUP_LISTS[index][1];
+ count:Hide();
+ elseif ( index == "MAINASSIST" ) then
+ button.class = MAINASSIST;
+ button.fileName = index;
+ button.id = RAID_SUBGROUP_LISTS[index][1];
+ count:Hide();
+ else
+ button.class, button.fileName = UnitClassBase("raid"..RAID_SUBGROUP_LISTS[index][1]);
+ end
+ button:Enable();
+ else
+ button:Disable();
+ icon:SetAlpha(0.5);
+ SetItemButtonDesaturated(button, 1);
+ count:Hide();
+ button.class = nil;
+ button.fileName = nil;
+ end
+ end
+end
+
+function RaidClassButton_OnEnter(self)
+ self.tooltip = format("%s%s (%d)%s", self.class, NORMAL_FONT_COLOR_CODE, self.count, FONT_COLOR_CODE_CLOSE);
+ GameTooltip_SetDefaultAnchor(GameTooltip, UIParent);
+ GameTooltip:SetText(self.tooltip, 1, 1, 1, 1, 1);
+ local classList;
+ if ( getn(RAID_SUBGROUP_LISTS[self.fileName]) > 0 ) then
+ local unit = "raid";
+ if ( self.fileName == "PETS" ) then
+ unit = "raidpet";
+ end
+ for index, value in pairs(RAID_SUBGROUP_LISTS[self.fileName]) do
+ if ( UnitExists(unit..value) ) then
+ if ( classList ) then
+ classList = classList..", "..UnitName(unit..value);
+ else
+ classList = UnitName(unit..value);
+ end
+ end
+ end
+ end
+ GameTooltip:AddLine(classList, 1, 1, 1);
+ GameTooltip:AddLine(TOOLTIP_RAID_CLASS_BUTTON, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+end
+
+function RaidGroupFrame_OnLoad()
+ RaidFrame:RegisterEvent("UNIT_PET");
+ RaidFrame:RegisterEvent("UNIT_NAME_UPDATE");
+ RaidFrame:RegisterEvent("UNIT_LEVEL");
+ RaidFrame:RegisterEvent("UNIT_HEALTH");
+ RaidFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
+ RaidFrame:RegisterEvent("VARIABLES_LOADED")
+ RaidFrame:SetScript("OnHide", RaidGroupFrame_OnHide);
+ RaidFrame:SetScript("OnEvent", RaidGroupFrame_OnEvent);
+ RaidFrame:SetScript("OnUpdate", RaidGroupFrame_OnUpdate);
+
+ RaidFrame.showRange = GetCVarBool("showRaidRange");
+end
+
+function RaidGroupFrame_OnHide()
+ -- If there's a selected button then call the onmouseup function on it when the frame is hidden
+ if ( MOVING_RAID_MEMBER ) then
+ RaidGroupButton_OnDragStop(MOVING_RAID_MEMBER);
+ end
+end
+
+function RaidGroupFrame_OnEvent(self, event, ...)
+ RaidFrame_OnEvent(self, event, ...);
+ if ( event == "UNIT_LEVEL" ) then
+ local arg1 = ...;
+ local id, found = gsub(arg1, "raid([0-9]+)", "%1");
+ if ( found == 1 ) then
+ RaidGroupFrame_UpdateLevel(id);
+ end
+ elseif ( event == "UNIT_HEALTH" ) then
+ local arg1 = "...";
+ local id, found = gsub(arg1, "raid([0-9]+)", "%1");
+ if ( found == 1 ) then
+ RaidGroupFrame_UpdateHealth(id);
+ end
+ elseif ( event == "UNIT_PET" or event == "UNIT_NAME_UPDATE" ) then
+ RaidClassButton_Update();
+ elseif ( event == "PLAYER_ENTERING_WORLD" ) then
+ RaidFrameReadyCheckButton_Update();
+ RaidFrameRaidBrowserButton_Update();
+ RaidPullout_RenewFrames();
+ elseif ( event == "VARIABLES_LOADED" ) then
+ RaidFrame.showRange = GetCVarBool("showRaidRange");
+ end
+end
+
+local raid_groupSlots;
+
+function RaidGroup_ResetSlotButtons()
+ if ( raid_groupSlots ) then
+ for i, group in next, raid_groupSlots do
+ for j, slot in next, group do
+ slot.button = nil;
+ end
+ end
+ else
+ raid_groupSlots = {};
+ for i=1, NUM_RAID_GROUPS do
+ raid_groupSlots[i] = {};
+ for j=1, MEMBERS_PER_RAID_GROUP do
+ raid_groupSlots[i][j] = _G["RaidGroup"..i.."Slot"..j];
+ raid_groupSlots[i][j].button = nil;
+ end
+ end
+ end
+end
+
+local raid_groupFrames;
+local classes;
+local raid_buttons;
+
+function RaidGroupFrame_Update()
+ -- Update raid group labels
+ if ( not raid_groupFrames ) then
+ raid_groupFrames = {};
+ for i=1, NUM_RAID_GROUPS do
+ raid_groupFrames[i] = _G["RaidGroup"..i];
+ end
+ end
+
+ if ( not classes ) then
+ classes = {};
+ for i=1, MAX_RAID_CLASS_BUTTONS do
+ classes[i] = _G["RaidClassButton"..i];
+ end
+ end
+
+
+ if ( GetNumRaidMembers() == 0 ) then
+ for i=1, NUM_RAID_GROUPS do
+ raid_groupFrames[i]:Hide()
+ end
+ for i=1, MAX_RAID_CLASS_BUTTONS do
+ classes[i]:Hide();
+ end
+ RaidFrameReadyCheckButton:Hide();
+ else
+ for i=1, NUM_RAID_GROUPS do
+ raid_groupFrames[i]:Show();
+ end
+ for i=1, MAX_RAID_CLASS_BUTTONS do
+ classes[i]:Show();
+ end
+ end
+
+ RaidFrameReadyCheckButton_Update();
+ RaidFrameRaidBrowserButton_Update();
+ if ( RaidFrameReadyCheckButton:IsShown() ) then
+ RaidFrameRaidInfoButton:SetPoint("LEFT", "RaidFrameReadyCheckButton", "RIGHT", 2, 0);
+ end
+
+
+ -- Reset group index counters;
+ for i=1, NUM_RAID_GROUPS do
+ raid_groupFrames[i].nextIndex = 1;
+ end
+ -- Clear out all the slots buttons
+ RaidGroup_ResetSlotButtons();
+
+ -- Clear out subgroup list
+ for i, j in next, RAID_SUBGROUP_LISTS do
+ RAID_SUBGROUP_LISTS[i] = nil;
+ end
+
+ for i=1, NUM_RAID_GROUPS do
+ if ( RAID_SUBGROUP_LISTS[i] ) then
+ for k, v in next, RAID_SUBGROUP_LISTS[i] do
+ RAID_SUBGROUP_LISTS[i][k] = nil;
+ end
+ else
+ RAID_SUBGROUP_LISTS[i] = {};
+ end
+ end
+
+ -- Use the class color list to clear out the class list
+ for index, value in pairs(RAID_CLASS_BUTTONS) do
+ if ( RAID_SUBGROUP_LISTS[index] ) then
+ for k, v in next, RAID_SUBGROUP_LISTS[index] do
+ RAID_SUBGROUP_LISTS[index][k] = nil;
+ end
+ else
+ RAID_SUBGROUP_LISTS[index] = {};
+ end
+ end
+
+ -- Fill out buttons
+ local numRaidMembers = GetNumRaidMembers();
+ local raidGroup, color;
+ local buttonFrameName, buttonName, buttonLevel, buttonClass, buttonRank;
+ local name, rank, subgroup, level, class, fileName, zone, online, isDead, role, loot, muted, unit;
+ local buttonCount;
+ local readyCheckStatus;
+ local button, subframes;
+
+ if ( not raid_buttons ) then
+ raid_buttons = {};
+ for i = 1, MAX_RAID_MEMBERS do
+ raid_buttons[i] = _G["RaidGroupButton"..i];
+ end
+ end
+
+ for i=1, MAX_RAID_MEMBERS do
+ button = raid_buttons[i];
+ if ( i <= numRaidMembers ) then
+ name, rank, subgroup, level, class, fileName, zone, online, isDead, role, loot = GetRaidRosterInfo(i);
+ unit = "raid"..i;
+ muted = GetMuteStatus(unit, "raid");
+ raidGroup = raid_groupFrames[subgroup];
+ readyCheckStatus = GetReadyCheckStatus(unit);
+ -- To prevent errors when the server hiccups
+ if ( raidGroup.nextIndex <= MEMBERS_PER_RAID_GROUP ) then
+ subframes = button.subframes;
+ if ( not subframes ) then
+ subframes = {};
+ subframes.name = _G["RaidGroupButton"..i.."Name"];
+ subframes.class = _G["RaidGroupButton"..i.."Class"];
+ subframes.level = _G["RaidGroupButton"..i.."Level"];
+ subframes.rank = _G["RaidGroupButton"..i.."Rank"];
+ subframes.role = _G["RaidGroupButton"..i.."Role"];
+ subframes.loot = _G["RaidGroupButton"..i.."Loot"];
+ subframes.rankTexture = _G["RaidGroupButton"..i.."RankTexture"];
+ --buttonMutedTexture = _G["RaidGroupButton"..i.."RankMuted"];
+ subframes.roleTexture = _G["RaidGroupButton"..i.."RoleTexture"];
+ subframes.lootTexture = _G["RaidGroupButton"..i.."LootTexture"];
+ subframes.readyCheck = _G["RaidGroupButton"..i.."ReadyCheck"];
+ button.subframes = subframes;
+ end
+
+ button.name = name;
+ button.class = fileName;
+
+ if ( level == 0 ) then
+ level = "";
+ end
+
+ if ( not name ) then
+ name = UNKNOWN;
+ end
+
+ -- Fill in subgroup list
+ tinsert(RAID_SUBGROUP_LISTS[subgroup], i);
+
+ -- Fill in class list
+ if ( fileName ) then
+ tinsert(RAID_SUBGROUP_LISTS[fileName], i);
+ --if ( UnitExists("raidpet"..i) ) then
+ if ( fileName == "HUNTER" or fileName == "WARLOCK" ) then
+ tinsert(RAID_SUBGROUP_LISTS["PETS"], i);
+ end
+ --end
+ end
+
+ -- Place Main Tank & Main Assist into a subgroup
+ if ( role ) then
+ tinsert(RAID_SUBGROUP_LISTS[role], i);
+ end
+
+ subframes.name:SetText(name);
+ if ( class ) then
+ subframes.class:SetText(class);
+ else
+ subframes.class:SetText("");
+ end
+ if ( level ) then
+ subframes.level:SetText(level);
+ else
+ subframes.level:SetText("");
+ end
+ if ( online ) then
+ if ( isDead ) then
+ subframes.name:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ subframes.class:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ subframes.level:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ else
+ color = RAID_CLASS_COLORS[fileName];
+ if ( color ) then
+ subframes.name:SetTextColor(color.r, color.g, color.b);
+ subframes.class:SetTextColor(color.r, color.g, color.b);
+ subframes.level:SetTextColor(color.r, color.g, color.b);
+ end
+ end
+ else
+ subframes.name:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ subframes.class:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ subframes.level:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+
+ --[[if ( muted ) then
+ buttonMutedTexture:Show();
+ else
+ buttonMutedTexture:Hide();
+ end]]
+
+ -- Sets the Leader/Assistant Icon
+ if ( rank == 2 ) then
+ subframes.rankTexture:SetTexture("Interface\\GroupFrame\\UI-Group-LeaderIcon");
+ elseif ( rank == 1 ) then
+ subframes.rankTexture:SetTexture("Interface\\GroupFrame\\UI-Group-AssistantIcon");
+ elseif ( (rank == 0 ) and ( muted == 2 ) ) then
+ subframes.rankTexture:SetTexture("Interface\\Common\\VoiceChat-Speaker");
+ else
+ subframes.rankTexture:SetTexture("");
+ end
+
+ -- Sets the Main Tank/Assist Icon
+ if ( role == "MAINTANK" ) then
+ subframes.roleTexture:SetTexture("Interface\\GroupFrame\\UI-Group-MainTankIcon");
+ elseif (role == "MAINASSIST" ) then
+ subframes.roleTexture:SetTexture("Interface\\GroupFrame\\UI-Group-MainAssistIcon");
+ else
+ subframes.roleTexture:SetTexture("");
+ end
+
+ -- Sets the Master Looter Icon
+ if ( loot ) then
+ subframes.lootTexture:SetTexture("Interface\\GroupFrame\\UI-Group-MasterLooter");
+ else
+ subframes.lootTexture:SetTexture("");
+ end
+
+ -- Resizes if there are all 3 visible
+ if ( ( rank > 0 ) and role and loot ) then
+ subframes.rank:SetWidth(10);
+ subframes.rank:SetHeight(10);
+ subframes.role:SetWidth(10);
+ subframes.role:SetHeight(10);
+ subframes.loot:SetWidth(9);
+ subframes.loot:SetHeight(9);
+ subframes.readyCheck:SetWidth(10);
+ subframes.readyCheck:SetHeight(10);
+ else
+ subframes.rank:SetWidth(11);
+ subframes.rank:SetHeight(11);
+ subframes.role:SetWidth(11);
+ subframes.role:SetHeight(11);
+ subframes.loot:SetWidth(11);
+ subframes.loot:SetHeight(11);
+ subframes.readyCheck:SetWidth(11);
+ subframes.readyCheck:SetHeight(11);
+ end
+
+ button.jobs = button.jobs or {};
+
+ for i, j in next, button.jobs do
+ button.jobs[i] = nil;
+ end
+
+ buttonCount = 0;
+
+ if ( rank > 0 or muted == 2 ) then
+ tinsert(button.jobs, subframes.rank);
+ buttonCount = buttonCount + 1;
+ else
+ subframes.rank:Hide();
+ end
+
+ if ( role ) then
+ tinsert(button.jobs, subframes.role);
+ buttonCount = buttonCount + 1;
+ else
+ subframes.role:Hide();
+ end
+
+ if ( loot ) then
+ tinsert(button.jobs, subframes.loot);
+ buttonCount = buttonCount + 1;
+ else
+ subframes.loot:Hide();
+ end
+
+ for i=1, buttonCount, 1 do
+ if ( i == 1 ) then
+ button.jobs[i]:SetPoint("LEFT", button, "LEFT", 2, 0);
+ else
+ button.jobs[i]:SetPoint("LEFT", button.jobs[i-1], "RIGHT", -1, 0);
+ end
+ button.jobs[i]:Show();
+ end
+
+ -- Sets the Ready Check Icon
+ if ( readyCheckStatus ) then
+ if ( readyCheckStatus == "ready" ) then
+ ReadyCheck_Confirm(subframes.readyCheck, 1);
+ elseif ( readyCheckStatus == "notready" ) then
+ ReadyCheck_Confirm(subframes.readyCheck, 0);
+ else -- "waiting"
+ ReadyCheck_Start(subframes.readyCheck);
+ end
+
+ -- hide the second job icon if there is one
+ if ( #button.jobs >= 2 ) then
+ button.jobs[2]:Hide();
+ end
+ else
+ subframes.readyCheck:Hide();
+ end
+
+ -- Save slot for future use
+ button.slot = raid_groupSlots[subgroup][raidGroup.nextIndex];
+
+ -- Anchor button to slot
+ if ( MOVING_RAID_MEMBER ~= button ) then
+ button:SetPoint("TOPLEFT", button.slot, "TOPLEFT", 0, 0);
+ end
+
+ -- Save the button's subgroup too
+ button.subgroup = subgroup;
+ -- Tell the slot what button is in it
+ button.slot.button = button:GetName();
+ raidGroup.nextIndex = raidGroup.nextIndex + 1;
+ button.voice = voice;
+ button.rank = rank;
+ button.role = role;
+ button.loot = loot;
+ button:SetID(i);
+ button:Show();
+ end
+ else
+ button:Hide();
+ end
+ end
+
+ -- Update Class Count Buttons
+ RaidClassButton_Update();
+end
+
+function RaidGroupFrame_UpdateLevel(id)
+ local unit = "raid"..id;
+ local buttonLevel = _G["RaidGroupButton"..id.."Level"];
+
+ buttonLevel:SetText(UnitLevel(unit));
+end
+
+function RaidGroupFrame_UpdateHealth(id)
+ local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(id);
+
+ local buttonName = _G["RaidGroupButton"..id.."Name"];
+ local buttonClass = _G["RaidGroupButton"..id.."Class"];
+ local buttonLevel = _G["RaidGroupButton"..id.."Level"];
+
+ local color;
+ if ( online ) then
+ if ( isDead ) then
+ buttonName:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ buttonClass:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ buttonLevel:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ else
+ color = RAID_CLASS_COLORS[fileName];
+ if ( color ) then
+ buttonName:SetTextColor(color.r, color.g, color.b);
+ buttonClass:SetTextColor(color.r, color.g, color.b);
+ buttonLevel:SetTextColor(color.r, color.g, color.b);
+ end
+ end
+ else
+ buttonName:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ buttonClass:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ buttonLevel:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+end
+
+function RaidGroupFrame_OnUpdate(elapsed)
+ if ( MOVING_RAID_MEMBER ) then
+ local button, slot;
+ TARGET_RAID_SLOT = nil;
+ for i=1, NUM_RAID_GROUPS do
+ for j=1, MEMBERS_PER_RAID_GROUP do
+ slot = _G["RaidGroup"..i.."Slot"..j];
+ if ( slot:IsMouseOver() ) then
+ slot:LockHighlight();
+ TARGET_RAID_SLOT = slot;
+ else
+ slot:UnlockHighlight();
+ end
+ end
+ end
+ end
+end
+
+function RaidGroupFrame_ReadyCheckFinished()
+ local numRaidMembers = GetNumRaidMembers();
+ local readyCheckFrame;
+ for i=1, numRaidMembers do
+ ReadyCheck_Finish(_G["RaidGroupButton"..i.."ReadyCheck"], 1.5, RaidGroupFrame_Update);
+ end
+end
+
+function RaidGroupButton_ShowMenu(self)
+ HideDropDownMenu(1);
+ if ( self.id and self.name ) then
+ FriendsDropDown.name = self.name;
+ FriendsDropDown.id = self.id;
+ FriendsDropDown.unit = self.unit;
+ FriendsDropDown.initialize = RaidFrameDropDown_Initialize;
+ FriendsDropDown.displayMode = "MENU";
+ ToggleDropDownMenu(1, nil, FriendsDropDown, "cursor");
+ end
+end
+
+function RaidGroupButton_OnLoad(self)
+ self:SetFrameLevel(self:GetFrameLevel() + 2);
+ self:RegisterForDrag("LeftButton");
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self.raidButton = self;
+
+ self.id = self:GetID();
+ self.unit = "raid"..self.id;
+end
+
+function RaidGroupButton_OnDragStart(raidButton)
+ if ( not IsRaidLeader() and not IsRaidOfficer() ) then
+ return;
+ end
+ local cursorX, cursorY = GetCursorPosition();
+ raidButton:StartMoving();
+ raidButton:ClearAllPoints();
+ raidButton:SetPoint("CENTER", nil, "BOTTOMLEFT", cursorX*GetScreenWidthScale(), cursorY*GetScreenHeightScale());
+ MOVING_RAID_MEMBER = raidButton;
+ SetRaidRosterSelection(raidButton.id);
+end
+
+function RaidGroupButton_OnDragStop(raidButton)
+ if ( not IsRaidLeader() and not IsRaidOfficer() ) then
+ return;
+ end
+
+ raidButton:StopMovingOrSizing();
+ MOVING_RAID_MEMBER = nil;
+ if ( TARGET_RAID_SLOT and TARGET_RAID_SLOT:GetParent():GetID() ~= raidButton.subgroup ) then
+ if (TARGET_RAID_SLOT.button) then
+ local button = _G[TARGET_RAID_SLOT.button];
+ --button:SetPoint("TOPLEFT", this, "TOPLEFT", 0, 0);
+ SwapRaidSubgroup(raidButton:GetID(), button:GetID());
+ else
+ local slot = TARGET_RAID_SLOT:GetParent():GetName().."Slot"..TARGET_RAID_SLOT:GetParent().nextIndex;
+ raidButton:ClearAllPoints();
+ raidButton:SetPoint("TOPLEFT", slot, "TOPLEFT", 0, 0);
+ TARGET_RAID_SLOT:UnlockHighlight();
+ SetRaidSubgroup(raidButton:GetID(), TARGET_RAID_SLOT:GetParent():GetID());
+ end
+ else
+ if ( TARGET_RAID_SLOT ) then
+ TARGET_RAID_SLOT:UnlockHighlight();
+ end
+ raidButton:ClearAllPoints();
+ raidButton:SetPoint("TOPLEFT", raidButton.slot, "TOPLEFT", 0, 0);
+ end
+end
+
+function RaidGroupButton_OnEnter(raidbutton)
+ if ( raidbutton.unit ) then
+ UnitFrame_UpdateTooltip(raidbutton);
+ end
+end
+
+function RaidFrameDropDown_Initialize(self)
+ UnitPopup_ShowMenu(UIDROPDOWNMENU_OPEN_MENU, "RAID", self.unit, self.name, self.id);
+end
+
+function RaidButton_OnClick(self, button)
+ SetRaidRosterSelection(self.index);
+ RaidFrame_Update();
+end
+
+-------------------- Pullout Button Functions --------------------
+function RaidPullout_OnEvent(self, event, ...)
+ if ( self:IsShown() ) then
+ if ( event == "RAID_ROSTER_UPDATE" or event == "UNIT_PET" or event == "UNIT_NAME_UPDATE" or
+ event == "READY_CHECK" or event == "READY_CHECK_CONFIRM" ) then
+ RaidPullout_Update(self);
+ elseif ( event == "READY_CHECK_FINISHED" ) then
+ RaidPullout_ReadyCheckFinished(self);
+ end
+ end
+end
+
+function RaidPullout_ReadyCheckFinished(pulloutFrame)
+ local pulloutButton;
+ for i=1, pulloutFrame.numPulloutButtons do
+ pulloutButton = pulloutFrame.buttons[i];
+ ReadyCheck_Finish(_G[pulloutButton:GetName().."ReadyCheck"], 1.5, RaidPullout_ReadyCheckFinishFunc, pulloutButton);
+ end
+end
+
+function RaidPullout_ReadyCheckFinishFunc(pulloutButton)
+ RefreshAuras(pulloutButton, pulloutButton.unit, MAX_RAID_AURAS, "Aura", true, pulloutButton:GetParent().showBuffs);
+end
+
+function RaidPullout_GeneratePulloutFrame(fileName, class)
+ -- Get a handle on a pullout frame
+ local pullOutFrame = RaidPullout_GetFrame(fileName);
+ if ( pullOutFrame ) then
+
+ pullOutFrame.filterID = fileName;
+ pullOutFrame.showBuffs = nil;
+
+ -- Set pullout name
+ if ( class ) then
+ pullOutFrame.class = class;
+ pullOutFrame.label:SetText(class);
+ elseif ( tonumber(fileName) ) then
+ pullOutFrame.label:SetText(GROUP.." "..fileName);
+ else
+ pullOutFrame.label:SetText("");
+ end
+
+ if ( fileName == "MAINTANK" or fileName == "MAINASSIST" ) then
+ pullOutFrame.showTarget = 1;
+ if ( fileName == "MAINTANK" ) then
+ pullOutFrame.showTargetTarget = 1;
+ else
+ pullOutFrame.showTargetTarget = nil;
+ end
+ else
+ pullOutFrame.showTargetTarget = nil;
+ pullOutFrame.showTarget = nil;
+ pullOutFrame.name = nil;
+ end
+
+ if ( RaidPullout_Update(pullOutFrame) ) then
+ return pullOutFrame;
+ end
+ end
+end
+
+function RaidPullout_UpdateTarget(pullOutFrame, pullOutButton, unit, which)
+ pullOutFrame = _G[pullOutFrame];
+ local statusBar = _G[pullOutButton..which];
+ local name = _G[pullOutButton..which.."Name"];
+ local frame = _G[pullOutButton..which.."Frame"];
+ if ( not pullOutFrame.showTarget ) then
+ pullOutFrame.showTargetTarget = nil;
+ end
+ if ( pullOutFrame["show"..which] ) then
+ if ( frame ) then
+ if ( ( not _G[pullOutFrame:GetName().."MenuBackdrop"]:IsShown() ) and which == "TargetTarget" ) then
+ frame:Hide();
+ else
+ frame:Show();
+ end
+ end
+ statusBar:Show();
+
+ local unitName = UnitName(unit);
+ if ( unitName and unitName ~= UNKNOWNOBJECT ) then
+ -- Init the Healthbars
+ local temp, class = UnitClass(unit);
+ name:SetText(unitName);
+ securecall("UnitFrameHealthBar_Initialize", unit, statusBar, nil, true);
+ securecall("UnitFrameHealthBar_Update", statusBar, unit);
+
+ -- If Unknown, turn the bar grey and fill it
+ if ( not class ) then
+ statusBar:SetMinMaxValues(0,1);
+ statusBar:SetValue(1);
+ statusBar:SetStatusBarColor(0.5, 0.5, 0.5, 1.0);
+ end
+
+ -- Color the name if the unit is a player
+ if ( UnitCanCooperate("player", unit) ) then
+ local color = RAID_CLASS_COLORS[class];
+ if ( color ) then
+ name:SetVertexColor(color.r, color.g, color.b);
+ end
+ else
+ name:SetVertexColor(1.0, 0.82, 0);
+ end
+
+ statusBar:SetStatusBarColor(UnitSelectionColor(unit));
+ name:Show();
+
+ else
+ statusBar:SetMinMaxValues(0,1);
+ statusBar:SetValue(1);
+ name:SetText("");
+ name:Hide();
+ statusBar:SetStatusBarColor(0.5, 0.5, 0.5, 1.0);
+ if ( which == "TargetTarget" ) then
+ statusBar:Hide();
+ if ( frame ) then
+ frame:Hide();
+ end
+ else
+ if ( frame ) then
+ frame:Show();
+ end
+ statusBar:Show();
+ end
+ end
+ else
+ statusBar:Hide();
+ name:Hide();
+ if ( frame ) then
+ frame:Hide();
+ end
+ end
+end
+
+function RaidPullout_OnUpdate(self, elapsed)
+ if ( _G[self:GetName().."Target"]:IsVisible() ) then
+ if ( not self.timer ) then
+ self.timer = .25;
+ elseif ( self.timer < 0 ) then
+ local parent = self:GetParent():GetName();
+ local frame = self:GetName();
+ RaidPullout_UpdateTarget(parent, frame, self.unit.."target", "Target");
+ if ( self:GetParent().showTargetTarget ) then
+ RaidPullout_UpdateTarget(parent, frame, self.unit.."targettarget", "TargetTarget");
+ end
+ self.timer = .25;
+ else
+ self.timer = self.timer - elapsed;
+ end
+ end
+ if ( RaidFrame.showRange ) then
+ if ( UnitIsConnected(self.unit) and not UnitInRange(self.unit) ) then
+ if ( self.healthbar:GetAlpha() == 1 ) then
+ _G[self:GetName().."Name"]:SetAlpha(RAID_RANGE_ALPHA);
+ self.healthbar:SetAlpha(RAID_RANGE_ALPHA);
+ self.manabar:SetAlpha(RAID_RANGE_ALPHA);
+ end
+ else
+ _G[self:GetName().."Name"]:SetAlpha(1);
+ self.healthbar:SetAlpha(1);
+ self.manabar:SetAlpha(1);
+ end
+ elseif ( self.healthbar:GetAlpha() ~= 1 ) then
+ _G[self:GetName().."Name"]:SetAlpha(1);
+ self.healthbar:SetAlpha(1);
+ self.manabar:SetAlpha(1);
+ end
+end
+
+function RaidPullout_Update(pullOutFrame)
+ local id, single;
+ local filterID = pullOutFrame.filterID;
+ local numPulloutEntries = 0;
+ if ( RAID_SUBGROUP_LISTS[filterID] ) then
+ numPulloutEntries = getn(RAID_SUBGROUP_LISTS[filterID]);
+ -- Hide the pullout if no entries
+ if ( numPulloutEntries == 0 ) then
+ pullOutFrame:Hide();
+ return nil;
+ end
+ else
+ numPulloutEntries = 1;
+ single = 1;
+ end
+ local pulloutList = RAID_SUBGROUP_LISTS[filterID];
+
+ -- Fill out the buttons
+ local pulloutButton, pulloutButtonName, color, unit, target;
+ local pulloutHealthBar, pulloutManaBar, pulloutThreatIndicator;
+ local pulloutClearButton;
+ if ( numPulloutEntries > pullOutFrame.numPulloutButtons ) then
+ local index = pullOutFrame.numPulloutButtons + 1;
+ local relative;
+ for i=index, numPulloutEntries do
+ pulloutButton = CreateFrame("Frame", pullOutFrame:GetName().."Button"..i, pullOutFrame, "RaidPulloutButtonTemplate");
+ if ( i == 1 ) then
+ pulloutButton:SetPoint("TOP", pullOutFrame, "TOP", 1, -10);
+ else
+ pulloutButton:SetPoint("TOP", pullOutFrame:GetName().."Button"..(i-1), "BOTTOM", 0, -8);
+ end
+ pullOutFrame.buttons[i] = pulloutButton;
+ end
+ pullOutFrame.numPulloutButtons = numPulloutEntries;
+ end
+ -- Populate Data
+ local name, rank, subgroup, level, class, fileName, zone, online, isDead, role;
+ local readyCheckStatus;
+ local debuff;
+ for i=1, pullOutFrame.numPulloutButtons do
+ pulloutButton = pullOutFrame.buttons[i];
+ if ( i <= numPulloutEntries ) then
+ pulloutButtonName = pulloutButton.nameLabel;
+ pulloutHealthBar = pulloutButton.healthbar;
+ pulloutManaBar = pulloutButton.manabar;
+ pulloutThreatIndicator = pulloutButton.threatIndicator;
+ if ( pulloutList ) then
+ id = pulloutList[i];
+ elseif ( single ) then
+ id = RaidPullout_MatchName(filterID);
+ end
+ -- Hide the pullout if no name
+ if ( single ) then
+ if ( not id ) then
+ pullOutFrame:Hide();
+ return nil;
+ end
+ end
+
+ name, rank, subgroup, level, class, fileName, zone, online, isDead, role = GetRaidRosterInfo(id);
+
+ pulloutButton:SetScript("OnUpdate", RaidPullout_OnUpdate);
+
+ if ( pullOutFrame.showTarget ) then
+ pulloutButton:SetHeight(40);
+ else
+ pulloutButton:SetHeight(25);
+ end
+
+ -- Set Unit Values
+ if ( filterID == "PETS" ) then
+ unit = "raidpet"..id;
+ if ( not UnitExists("raidpet"..id) ) then
+ online = nil;
+ end
+ else
+ unit = "raid"..id;
+ end
+
+ name = UnitName(unit);
+ pulloutButtonName:SetText(name);
+ pulloutButton.unit = unit;
+ pulloutButton.secondaryUnit = unit;
+
+ -- Set for tooltip support
+ pulloutClearButton = pulloutButton.clearButton;
+ SecureUnitButton_OnLoad(pulloutClearButton, unit, RaidPulloutButton_ShowMenu);
+ pullOutFrame.name = name;
+ pullOutFrame.single = single;
+ pulloutButton.raidIndex = id;
+
+ -- Setup status bars (health, mana, threat, etc)
+ RaidPulloutButton_UpdateSwapFrames(pulloutButton, unit)
+
+ local minVal, maxVal;
+ if ( online ) then
+ RaidPulloutButton_UpdateDead(pulloutButton, isDead, fileName);
+ else
+ -- Offline so set name grey and full alpha
+ if ( pulloutHealthBar:GetAlpha() ~= 1 ) then
+ pulloutButtonName:SetAlpha(1);
+ pulloutHealthBar:SetAlpha(1);
+ pulloutManaBar:SetAlpha(1);
+ end
+ pulloutButtonName:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+
+ RaidPulloutButton_UpdateVoice(pulloutButton);
+
+ -- Handle unit's target
+ RaidPullout_UpdateTarget(pullOutFrame:GetName(), pulloutButton:GetName(), pulloutButton.unit.."target", "Target");
+ RaidPullout_UpdateTarget(pullOutFrame:GetName(), pulloutButton:GetName(), pulloutButton.unit.."targettarget", "TargetTarget");
+
+ -- Handle ready check
+ readyCheckStatus = GetReadyCheckStatus(unit);
+ if ( readyCheckStatus ) then
+ if ( readyCheckStatus == "ready" ) then
+ ReadyCheck_Confirm(_G[pulloutButton:GetName().."ReadyCheck"], 1);
+ elseif ( readyCheckStatus == "notready" ) then
+ ReadyCheck_Confirm(_G[pulloutButton:GetName().."ReadyCheck"], 0);
+ else -- "waiting"
+ ReadyCheck_Start(_G[pulloutButton:GetName().."ReadyCheck"]);
+ end
+
+ -- hide auras while ready check is up
+ for i=1, MAX_RAID_AURAS do
+ _G[pulloutButton:GetName().."Aura"..i]:Hide();
+ end
+ else
+ _G[pulloutButton:GetName().."ReadyCheck"]:Hide();
+
+ -- Handle auras if ready check is hidden
+ RefreshAuras(pulloutButton, pulloutButton.unit, MAX_RAID_AURAS, "Aura", true, pullOutFrame.showBuffs);
+ end
+
+ --Handle vehicle indicator
+ if ( UnitHasVehicleUI(unit) ) then
+ pulloutButton.vehicleIndicator:Show();
+ else
+ pulloutButton.vehicleIndicator:Hide();
+ end
+
+ pulloutButton:RegisterEvent("PLAYER_ENTERING_WORLD");
+ pulloutButton:RegisterEvent("UNIT_HEALTH");
+ pulloutButton:RegisterEvent("UNIT_AURA");
+ pulloutButton:RegisterEvent("UNIT_NAME_UPDATE");
+ pulloutButton:RegisterEvent("VOICE_STATUS_UPDATE");
+ pulloutButton:RegisterEvent("VOICE_START");
+ pulloutButton:RegisterEvent("VOICE_STOP");
+ pulloutButton:RegisterEvent("UNIT_ENTERED_VEHICLE");
+ pulloutButton:RegisterEvent("UNIT_EXITED_VEHICLE");
+ pulloutButton:Show();
+ else
+ pulloutButton:UnregisterEvent("PLAYER_ENTERING_WORLD");
+ pulloutButton:UnregisterEvent("UNIT_HEALTH");
+ pulloutButton:UnregisterEvent("UNIT_AURA");
+ pulloutButton:UnregisterEvent("UNIT_NAME_UPDATE");
+ pulloutButton:UnregisterEvent("VOICE_STATUS_UPDATE");
+ pulloutButton:UnregisterEvent("VOICE_START");
+ pulloutButton:UnregisterEvent("VOICE_STOP");
+ pulloutButton:UnregisterEvent("UNIT_ENTERED_VEHICLE");
+ pulloutButton:UnregisterEvent("UNIT_EXITED_VEHICLE");
+ pulloutButton:Hide();
+ end
+ end
+
+ local buttonHeight = RAID_PULLOUT_BUTTON_HEIGHT;
+ local height;
+
+ if ( pullOutFrame.showTarget ) then
+ buttonHeight = buttonHeight + 15;
+ end
+
+ if ( pullOutFrame.showBG == false ) then
+ _G[pullOutFrame:GetName().."MenuBackdrop"]:Hide();
+ end
+
+ pullOutFrame:SetHeight( (numPulloutEntries * buttonHeight) + 14);
+ pullOutFrame:Show();
+ return 1;
+end
+
+function RaidPulloutButton_OnEvent(self, event, ...)
+ local speaker = self.speaker;
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ RaidPulloutButton_UpdateVoice(self);
+ elseif ( event == "UNIT_HEALTH" ) then
+ local arg1 = ...;
+ if ( arg1 == self.unit ) then
+ local name, rank, subgroup, level, class, fileName, zone, online, isDead = GetRaidRosterInfo(self.raidIndex);
+ if ( online ) then
+ RaidPulloutButton_UpdateDead(self, isDead, fileName);
+ end
+ end
+ elseif ( event == "UNIT_AURA" ) then
+ -- suppress while ready check is up
+ local arg1 = ...;
+ if ( arg1 == self.unit ) then
+ if ( not _G[self:GetName().."ReadyCheck"]:IsShown() ) then
+ RefreshAuras(self, self.unit, MAX_RAID_AURAS, "Aura", true, self:GetParent().showBuffs);
+ end
+ end
+ elseif ( event == "VOICE_START") then
+ local arg1 = ...;
+ if ( arg1 == (self.secondaryUnit or self.unit) ) then
+ speaker.timer = nil;
+ speaker:Show();
+ UIFrameFadeIn(speaker, 0.2, speaker:GetAlpha(), 1);
+ if ( not self.muted ) then
+ VoiceChat_Animate(speaker, 1);
+ end
+ end
+ elseif ( event == "VOICE_STOP" ) then
+ local arg1 = ...;
+ if ( arg1 == (self.secondaryUnit or self.unit) ) then
+ speaker.timer = VOICECHAT_DELAY;
+ VoiceChat_Animate(speaker, nil);
+ if ( self.muted ) then
+ speaker:Show();
+ else
+ UIFrameFadeOut(speaker, 0.2, speaker:GetAlpha(), 0);
+ end
+ end
+ elseif ( event == "VOICE_STATUS_UPDATE" ) then
+ RaidPulloutButton_UpdateVoice(self);
+ elseif (( event == "UNIT_ENTERED_VEHICLE" ) or ( event == "UNIT_EXITED_VEHICLE" )) then
+ local arg1 = ...;
+ if ( arg1 == (self.secondaryUnit or self.unit) ) then
+ if ( UnitHasVehicleUI(arg1) ) then
+ self.vehicleIndicator:Show();
+ else
+ self.vehicleIndicator:Hide();
+ end
+ RaidPulloutButton_UpdateSwapFrames(self, arg1);
+ end
+ end
+end
+
+function RaidPulloutButton_UpdateSwapFrames(self, unit)
+ if ( UnitTargetsVehicleInRaidUI(unit) ) then
+ local prefix, id = unit:match("([^%d]+)([%d]+)");
+ self.secondaryUnit = unit;
+ unit = prefix.."pet"..id;
+ self.unit = unit;
+ _G[self:GetName().."ClearButton"]:SetAttribute("unit", unit)
+ elseif ( self.secondaryUnit ) then
+ self.unit = self.secondaryUnit;
+ _G[self:GetName().."ClearButton"]:SetAttribute("unit", self.secondaryUnit);
+ self.secondaryUnit = nil;
+ end
+ securecall("UnitFrameHealthBar_Initialize", unit, self.healthbar, nil, true);
+ securecall("UnitFrameManaBar_Initialize", unit, self.manabar, nil);
+ securecall("UnitFrameThreatIndicator_Initialize", unit, self);
+ securecall("UnitFrameHealthBar_Update", self.healthbar, unit);
+ securecall("UnitFrameManaBar_Update", self.manabar, unit);
+ securecall("UnitFrame_UpdateThreatIndicator", self.threatIndicator, nil, unit);
+end
+
+function RaidPulloutButton_UpdateDead(button, isDead, class)
+ local unit;
+ local pulloutButtonName = button.nameLabel;
+ if ( isDead ) then
+ pulloutButtonName:SetVertexColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ else
+ if ( class == "PETS" ) then
+ class = UnitClass(gsub(button.unit, "raidpet", "raid"));
+ end
+ local color = RAID_CLASS_COLORS[class];
+ if ( color ) then
+ pulloutButtonName:SetVertexColor(color.r, color.g, color.b);
+ end
+ end
+end
+
+function RaidPulloutButton_UpdateVoice(pullOutButton)
+ local button = pullOutButton:GetName();
+ local icon = pullOutButton.speaker;
+ local muted = _G[button.."SpeakerMuted"];
+ local muteStatus = GetMuteStatus(UnitName((pullOutButton.secondaryUnit or pullOutButton.unit)), "raid");
+ local state = UnitIsTalking(UnitName(pullOutButton.secondaryUnit or pullOutButton.unit));
+ if ( muteStatus ) then
+ VoiceChat_Animate(icon, nil);
+ icon:SetAlpha(1);
+ icon:Show();
+ muted:Show();
+ else
+ if ( state ) then
+ VoiceChat_Animate(icon, 1);
+ icon:Show();
+ else
+ VoiceChat_Animate(icon, nil);
+ icon:Hide();
+ end
+ muted:Hide();
+ end
+ pullOutButton.muted = muteStatus;
+end
+
+function RaidPulloutButton_ShowMenu(self)
+ ToggleDropDownMenu(1, nil, _G[self:GetParent():GetParent():GetName().."DropDown"]);
+end
+
+function RaidPulloutButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:RegisterEvent("UNIT_NAME_UPDATE");
+ self:SetFrameLevel(self:GetFrameLevel() + 1);
+
+ self.showmenu = RaidPulloutButton_ShowMenu;
+end
+
+function RaidPulloutButton_OnDragStart(frame)
+ if ( not frame ) then
+ MOVING_RAID_PULLOUT = nil;
+ return;
+ end
+ local cursorX, cursorY = GetCursorPosition();
+ frame:SetFrameStrata("DIALOG");
+ frame:StartMoving();
+ frame:ClearAllPoints();
+ frame:SetPoint("TOP", nil, "BOTTOMLEFT", cursorX*GetScreenWidthScale(), cursorY*GetScreenHeightScale());
+ MOVING_RAID_PULLOUT = frame;
+end
+
+function RaidPulloutStopMoving(frame)
+ if ( not frame ) then
+ frame = MOVING_RAID_PULLOUT;
+ end
+ if ( frame ) then
+ frame:StopMovingOrSizing();
+ frame:SetFrameStrata("BACKGROUND");
+ frame:ClearAllPoints();
+
+ local x, _ = frame:GetCenter();
+ local y = frame:GetTop();
+ frame:SetPoint("TOP", nil, "BOTTOMLEFT", x, y);
+ ValidateFramePosition(frame, 25);
+ -- Save the end positions
+ RaidPullout_SaveFrames(frame);
+ end
+end
+
+function RaidPullout_SaveFrames(pullOutFrame)
+ local point, relativeTo, relativePoint, offsetX, offsetY = pullOutFrame:GetPoint();
+ local filterID = tostring(pullOutFrame.filterID);
+ local settings = {};
+ if ( pullOutFrame:IsShown() ) then
+ if ( pullOutFrame.single ) then
+ -- Check for an existing entry
+ for index, value in pairs(RAID_SINGLE_POSITIONS) do
+ if ( index > 19 ) then
+ tremove(RAID_SINGLE_POSITIONS, index);
+ end
+ if ( value["name"] == pullOutFrame.name ) then
+ tremove(RAID_SINGLE_POSITIONS, index);
+ end
+ end
+
+ -- Get its settings
+ for setting in next, RAID_PULLOUT_SAVED_SETTINGS do
+ if ( pullOutFrame[setting] ~= nil ) then
+ settings[setting] = pullOutFrame[setting];
+ end
+ end
+
+ -- Save its position and settings
+ tinsert(RAID_SINGLE_POSITIONS, 1, { point = point, relativePoint = relativePoint, x = offsetX, y = offsetY, name = pullOutFrame.filterID, ["settings"] = settings });
+ else
+ if ( not RAID_PULLOUT_POSITIONS[filterID] ) then
+ RAID_PULLOUT_POSITIONS[filterID] = {};
+ end
+ RAID_PULLOUT_POSITIONS[filterID].point = point;
+ RAID_PULLOUT_POSITIONS[filterID].relativePoint = relativePoint;
+ RAID_PULLOUT_POSITIONS[filterID].x = offsetX;
+ RAID_PULLOUT_POSITIONS[filterID].y = offsetY;
+ -- Save detail information such as name and class value
+ if ( pullOutFrame.id ) then
+ RAID_PULLOUT_POSITIONS[filterID].name = UnitName("raid"..pullOutFrame.id);
+ end
+ if ( pullOutFrame.class ) then
+ RAID_PULLOUT_POSITIONS[filterID].class = pullOutFrame.class;
+ end
+
+ for setting in next, RAID_PULLOUT_SAVED_SETTINGS do
+ if ( pullOutFrame[setting] ~= nil ) then
+ settings[setting] = pullOutFrame[setting];
+ end
+ end
+
+ RAID_PULLOUT_POSITIONS[filterID]["settings"] = settings;
+ end
+ end
+end
+
+function RaidPullout_RenewFrames()
+ local pullOutFrame;
+ for index, pullOut in pairs(RAID_PULLOUT_POSITIONS) do
+ if ( tonumber(index) ) then
+ pullOutFrame = RaidPullout_GeneratePulloutFrame(tonumber(index));
+ else
+ pullOutFrame = RaidPullout_GeneratePulloutFrame(index, pullOut["class"]);
+ end
+ if ( pullOutFrame ) then
+ if ( pullOut.x ) then
+ pullOutFrame:ClearAllPoints();
+ if ( not pullOut.point ) then
+ pullOut.point = "TOPLEFT";
+ pullOut.relativePoint = "TOPLEFT";
+ end
+ pullOutFrame:SetPoint(pullOut["point"], UIParent, pullOut["relativePoint"], pullOut["x"], pullOut["y"]);
+ end
+
+ if ( pullOut.settings ) then
+ for setting, value in next, pullOut.settings do
+ pullOutFrame[setting] = value;
+ end
+ end
+
+ RaidPullout_Update(pullOutFrame);
+ end
+ end
+ for index, pullOut in pairs(RAID_SINGLE_POSITIONS) do
+ if ( RaidPullout_MatchName(pullOut["name"]) ) then
+ pullOutFrame = RaidPullout_GeneratePulloutFrame(pullOut["name"], nil );
+ if ( pullOutFrame ) then
+ if ( pullOut.x ) then
+ pullOutFrame:ClearAllPoints();
+ if ( not pullOut.point ) then
+ pullOut.point = "TOPLEFT";
+ pullOut.relativePoint = "TOPLEFT";
+ end
+ pullOutFrame:SetPoint(pullOut["point"], UIParent, pullOut["relativePoint"], pullOut["x"], pullOut["y"]);
+ end
+
+ if ( pullOut.settings ) then
+ for setting, value in next, pullOut.settings do
+ pullOutFrame[setting] = value;
+ end
+ end
+
+ RaidPullout_Update(pullOutFrame);
+ end
+ end
+ end
+end
+
+function RaidPullout_MatchName(name)
+ if ( name ) then
+ for i=1, GetNumRaidMembers(), 1 do
+ if ( name == GetRaidRosterInfo(i) ) then
+ return i;
+ end
+ end
+ end
+end
+
+local raid_pullout_frames = {};
+
+function RaidPullout_GetFrame(filterID)
+ -- Grab an available pullout frame
+ local frame, freeFrame;
+ for i=1, NUM_RAID_PULLOUT_FRAMES do
+ frame = raid_pullout_frames[i]
+ -- if frame is visible see if its group id is already taken
+ if ( frame:IsShown() and filterID == frame.filterID ) then
+ return nil;
+ elseif ( not freeFrame and not frame:IsShown() ) then
+ freeFrame = frame;
+ end
+ end
+ if ( freeFrame ) then
+ return freeFrame;
+ end
+ NUM_RAID_PULLOUT_FRAMES = NUM_RAID_PULLOUT_FRAMES + 1;
+ frame = CreateFrame("Button", "RaidPullout"..NUM_RAID_PULLOUT_FRAMES, UIParent, "RaidPulloutFrameTemplate");
+ frame.numPulloutButtons = 0;
+ raid_pullout_frames[NUM_RAID_PULLOUT_FRAMES] = frame;
+ return frame;
+end
+
+function RaidPulloutDropDown_OnLoad(self)
+ self.raidPulloutDropDown = true;
+ UIDropDownMenu_Initialize(self, RaidPulloutDropDown_Initialize, "MENU");
+ UIDropDownMenu_SetAnchor(self, 0, 0, "TOPLEFT", self:GetParent():GetName(), "TOPRIGHT")
+end
+
+function RaidPulloutDropDown_Initialize()
+ if ( not UIDROPDOWNMENU_OPEN_MENU or not UIDROPDOWNMENU_OPEN_MENU.raidPulloutDropDown ) then
+ return;
+ end
+ local currentPullout = UIDROPDOWNMENU_OPEN_MENU:GetParent();
+ local unit, voice, muted, silenced, pvpType;
+ local info = UIDropDownMenu_CreateInfo();
+
+ if ( IsVoiceChatEnabled() ) then
+ -- Display the option to mute voice chat.
+ for i=1, currentPullout.numPulloutButtons do
+ local button = _G[currentPullout:GetName().."Button"..i];
+ if ( button:IsMouseOver() ) then
+ unit = (button.secondaryUnit or button.unit);
+ break;
+ end
+ end
+ if ( unit and currentPullout.filterID ~= "PETS" ) then
+ if ( UnitInBattleground("player") ) then
+ pvpType = "battleground";
+ else
+ pvpType = "raid";
+ end
+ voice = GetVoiceStatus(UnitName(unit), pvpType);
+ end
+ if ( voice ) then
+ -- Set a name header
+ if ( not UnitIsUnit(unit, "player") or IsRaidOfficer() ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = UnitName(unit);
+ info.isTitle = 1;
+ info.notCheckable = nil;
+ info.disabled = nil;
+ UIDropDownMenu_AddButton(info);
+
+ -- Set a mute option
+ muted = IsMuted(UnitName(unit));
+ if ( muted ) then
+ info.text = UNMUTE;
+ else
+ info.text = MUTE;
+ end
+ info.func = function()
+ AddOrDelMute(unit);
+ end;
+ info.checked = nil;
+ info.isTitle = nil;
+ info.notCheckable = nil;
+ info.disabled = nil;
+ UIDropDownMenu_AddButton(info);
+ end
+
+ -- Display the option to silence voice chat if RaidLeader.
+ if ( IsRaidOfficer() ) then
+ silenced = UnitIsSilenced(UnitName(unit), "raid");
+ if ( not silenced ) then
+ info.text = RAID_SILENCE;
+ info.func = function()
+ ChannelSilenceVoice("raid", UnitName(unit));
+ end;
+ else
+ info.text = RAID_UNSILENCE;
+ info.func = function()
+ ChannelUnSilenceVoice("raid", UnitName(unit));
+ end;
+ end
+ info.isTitle = nil;
+ info.notCheckable = nil;
+ info.disabled = nil;
+ UIDropDownMenu_AddButton(info);
+ end
+ if ( not UnitIsUnit(unit, "player") or IsRaidOfficer() ) then
+ -- spacer
+ info = UIDropDownMenu_CreateInfo();
+ info.isTitle = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+ end
+ end
+
+ -- Show target if it is allowed
+ info.text = SHOW_TARGET;
+ info.func = function()
+ if ( currentPullout.showTarget == 1 ) then
+ currentPullout.showTarget = nil;
+ else
+ currentPullout.showTarget = 1;
+ end
+ RaidPullout_Update(currentPullout);
+ RaidPullout_SaveFrames(currentPullout);
+ end;
+ info.checked = currentPullout.showTarget;
+ info.isTitle = nil;
+ info.disabled = nil;
+ info.notCheckable = nil;
+ UIDropDownMenu_AddButton(info);
+
+ if ( currentPullout.showTarget == 1 ) then
+ info.text = SHOW_TARGET_OF_TARGET_TEXT;
+ info.func = function()
+ if ( currentPullout.showTargetTarget == 1 ) then
+ currentPullout.showTargetTarget = nil;
+ else
+ currentPullout.showTargetTarget = 1;
+ end
+ RaidPullout_Update(currentPullout);
+ RaidPullout_SaveFrames(currentPullout);
+ end;
+ info.checked = currentPullout.showTargetTarget;
+ info.isTitle = nil;
+ info.disabled = nil;
+ info.notCheckable = nil;
+ UIDropDownMenu_AddButton(info);
+ end
+
+ -- Show buffs or debuffs they are exclusive for now
+ info.text = SHOW_BUFFS;
+ info.func = function()
+ currentPullout.showBuffs = 1;
+ RaidPullout_Update(currentPullout);
+ RaidPullout_SaveFrames(currentPullout);
+ end;
+ info.checked = currentPullout.showBuffs;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = SHOW_DEBUFFS;
+ info.func = function()
+ currentPullout.showBuffs = nil;
+ RaidPullout_Update(currentPullout);
+ RaidPullout_SaveFrames(currentPullout);
+ end;
+ info.checked = (not currentPullout.showBuffs);
+ info.isTitle = nil;
+ info.disabled = nil;
+ info.notCheckable = nil;
+ UIDropDownMenu_AddButton(info);
+
+ -- Hide background option
+ local backdrop = _G[currentPullout:GetName().."MenuBackdrop"];
+ info.text = HIDE_PULLOUT_BG;
+ info.func = function ()
+ currentPullout.showBG = (not backdrop:IsShown());
+ if ( backdrop:IsShown() ) then
+ backdrop:Hide();
+ else
+ backdrop:Show();
+ end
+ RaidPullout_SaveFrames(currentPullout);
+ end;
+ info.checked = (not backdrop:IsShown());
+ info.isTitle = nil;
+ info.disabled = nil;
+ info.notCheckable = nil;
+ UIDropDownMenu_AddButton(info);
+
+ -- Close option
+ info.text = CLOSE;
+ info.func = function()
+ if ( currentPullout.showTarget == 1 ) then
+ currentPullout.showTarget = nil;
+ end
+ if ( RAID_PULLOUT_POSITIONS[tostring(currentPullout.filterID)] ) then
+ RAID_PULLOUT_POSITIONS[tostring(currentPullout.filterID)] = nil;
+ end
+ for index, value in pairs(RAID_SINGLE_POSITIONS) do
+ if ( value["name"] == currentPullout.filterID ) then
+ tremove(RAID_SINGLE_POSITIONS, index);
+ end
+ end
+ currentPullout:Hide();
+ end;
+ info.checked = nil;
+ info.isTitle = nil;
+ info.disabled = nil;
+ info.notCheckable = nil;
+ UIDropDownMenu_AddButton(info);
+end
+
+function RaidFrameReadyCheckButton_Update()
+ if ( GetNumRaidMembers() > 0 and (IsRaidLeader() or IsRaidOfficer()) ) then
+ RaidFrameReadyCheckButton:Show();
+ else
+ RaidFrameReadyCheckButton:Hide();
+ end
+end
+
+function RaidFrameRaidBrowserButton_Update()
+ if ( GetNumRaidMembers() > 0 ) then
+ RaidFrameRaidBrowserButton:Show();
+ else
+ RaidFrameRaidBrowserButton:Hide();
+ end
+end
diff --git a/reference/AddOns/Blizzard_RaidUI/Blizzard_RaidUI.toc b/reference/AddOns/Blizzard_RaidUI/Blizzard_RaidUI.toc
new file mode 100644
index 0000000..3965a4d
--- /dev/null
+++ b/reference/AddOns/Blizzard_RaidUI/Blizzard_RaidUI.toc
@@ -0,0 +1,7 @@
+## Interface: 30300
+## Title: Blizzard Raid UI
+## Secure: 1
+## LoadOnDemand: 1
+## SavedVariablesPerCharacter: RAID_PULLOUT_POSITIONS, RAID_SINGLE_POSITIONS
+Blizzard_RaidUI.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_RaidUI/Blizzard_RaidUI.xml b/reference/AddOns/Blizzard_RaidUI/Blizzard_RaidUI.xml
new file mode 100644
index 0000000..73e07eb
--- /dev/null
+++ b/reference/AddOns/Blizzard_RaidUI/Blizzard_RaidUI.xml
@@ -0,0 +1,1223 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaidClassButton_OnLoad(self);
+
+
+ RaidPulloutButton_OnDragStart(RaidPullout_GeneratePulloutFrame(self.fileName, self.class));
+
+
+ --Do not pass self here. We want to stop the currently moving frame and not the class frame (which isn't actually moving)
+ RaidPulloutStopMoving();
+
+
+ RaidClassButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 1);
+ RaidGroupButton_OnLoad(self:GetParent());
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local rank = self:GetParent().rank;
+ local voice = self:GetParent().voice;
+ -- Sets the Leader/Assistant Tooltip
+ if ( rank ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if ( rank == 2 ) then
+ GameTooltip:SetText(RAID_LEADER, nil, nil, nil, nil, 1);
+ elseif ( rank == 1 ) then
+ GameTooltip:SetText(RAID_ASSISTANT, nil, nil, nil, nil, 1);
+ end
+ if ( voice == 2 ) then
+ GameToolTip:AddLine("("..MUTED..")", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ end
+ else
+ GameTooltip:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local role = self:GetParent().role;
+ -- Sets the Main Tank/Assist Tooltip
+ if ( role ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if ( role == "MAINTANK" ) then
+ GameTooltip:SetText(MAIN_TANK, nil, nil, nil, nil, 1);
+ elseif ( role == "MAINASSIST" ) then
+ GameTooltip:SetText(MAIN_ASSIST, nil, nil, nil, nil, 1);
+ end
+ else
+ GameTooltip:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -- Sets the Master Looter Tooltip
+ if ( self:GetParent().loot ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(MASTER_LOOTER, nil, nil, nil, nil, 1);
+ else
+ GameTooltip:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaiseFrameLevelByTwo(self);
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 1);
+ RaidGroupButton_OnLoad(self);
+
+
+ if ( button == "RightButton" ) then
+ RaidGroupButton_ShowMenu(self);
+ else
+ SecureUnitButton_OnClick(self, button);
+ end
+
+
+ if ( IsRaidLeader() or IsRaidOfficer() ) then
+ if ( IsShiftKeyDown() ) then
+ self.keypressed = "1";
+ RaidPulloutButton_OnDragStart(RaidPullout_GeneratePulloutFrame(self.name, nil));
+ else
+ RaidGroupButton_OnDragStart(self);
+ self.keypressed = nil;
+ end
+ else
+ RaidPulloutButton_OnDragStart(RaidPullout_GeneratePulloutFrame(self.name, nil));
+ end
+
+
+ if ( IsRaidLeader() or IsRaidOfficer() ) then
+ if ( self.keypressed ) then
+ RaidPulloutStopMoving();
+ else
+ RaidGroupButton_OnDragStop(self);
+ end
+ else
+ RaidPulloutStopMoving();
+ end
+
+
+ RaidGroupButton_OnEnter(self);
+ if ( RaidFrame:IsMouseOver() ) then
+ GameTooltip:AddLine("\n");
+ if ( IsRaidLeader() or IsRaidOfficer() ) then
+ GameTooltip:AddLine(TOOLTIP_RAID_SHIFT_TIP, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ else
+ GameTooltip:AddLine(TOOLTIP_RAID_DRAG_TIP, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ end
+ GameTooltip:Show();
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForDrag("LeftButton");
+
+
+ RaidPulloutButton_OnDragStart(RaidPullout_GeneratePulloutFrame(self:GetParent():GetID()));
+
+
+ RaidPulloutStopMoving();
+
+
+ RaidPulloutStopMoving();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Label"]:SetText(GROUP.." "..self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetCenter() > GetScreenWidth()/2 ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+
+ local filter;
+ if ( self:GetParent():GetParent().showBuffs ) then
+ if ( GetCVarBool("showCastableBuffs") ) then
+ filter = "HELPFUL|RAID";
+ else
+ filter = "HELPFUL";
+ end
+ else
+ if ( GetCVarBool("showDispelDebuffs") ) then
+ filter = "HARMFUL|RAID";
+ else
+ filter = "HARMFUL";
+ end
+ end
+ GameTooltip:SetUnitAura(self:GetParent().unit, self:GetID(), filter);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( UnitIsConnected(self.unit) ) then
+ UnitFrameHealthBar_OnValueChanged(self, value);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel()+2);
+
+
+ --UnitFrameHealthBar_OnValueChanged(self, value);
+
+
+ TargetUnit(self:GetParent().unit.."target");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel()-1);
+ self:SetBackdropBorderColor(0.5, 0.5, 0.5);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+ self:SetAlpha(0.7);
+
+
+ TargetUnit(self:GetParent().unit.."targettarget");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TargetUnit(self:GetParent():GetParent().unit.."targettarget");
+
+
+
+
+
+
+ --UnitFrameHealthBar_OnValueChanged(self, value);
+
+
+ TargetUnit(self:GetParent().unit.."targettarget");
+
+
+
+
+
+
+
+ RaidPulloutButton_OnLoad(self);
+
+
+ RaidGroupButton_OnEnter(self:GetParent());
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ VoiceChat_OnUpdate(self, elapsed);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaiseFrameLevelByTwo(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaidPulloutButton_OnEvent(self, event, ...);
+
+
+ local prefix = self:GetName();
+ self.healthbar = _G[prefix.."HealthBar"];
+ self.manabar = _G[prefix.."ManaBar"];
+ self.threatIndicator = _G[prefix.."ThreatIndicator"];
+ self.nameLabel = _G[prefix.."Name"];
+ self.clearButton = _G[prefix.."ClearButton"];
+ self.speaker = _G[prefix.."Speaker"];
+ self.vehicleIndicator = _G[prefix.."VehicleIndicator"];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaidPulloutDropDown_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.5, 0.5, 0.5);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+ self:SetAlpha(0.7);
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("RAID_ROSTER_UPDATE");
+ self:RegisterEvent("UNIT_PET");
+ self:RegisterEvent("UNIT_NAME_UPDATE");
+ self:RegisterEvent("READY_CHECK");
+ self:RegisterEvent("READY_CHECK_CONFIRM");
+ self:RegisterEvent("READY_CHECK_FINISHED");
+ self:RegisterForDrag("LeftButton");
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self.label = _G[self:GetName() .. "Name"];
+ self.buttons = {};
+
+
+ RaidPullout_OnEvent(self, event, ...);
+
+
+ self:SetFrameStrata("DIALOG");
+ self:StartMoving();
+
+
+ RaidPulloutStopMoving(self);
+
+
+ if (button == "RightButton") then
+ ToggleDropDownMenu(1, nil, _G[self:GetName().."DropDown"]);
+ end
+
+
+ self:StopMovingOrSizing();
+ self:SetFrameStrata("BACKGROUND");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ShowUIPanel(LFRParentFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DoReadyCheck();
+ PlaySound("UChatScrollButton");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_RaidUI/Localization.lua b/reference/AddOns/Blizzard_RaidUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_RaidUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_TalentUI/Blizzard_TalentUI.lua b/reference/AddOns/Blizzard_TalentUI/Blizzard_TalentUI.lua
new file mode 100644
index 0000000..18e2e24
--- /dev/null
+++ b/reference/AddOns/Blizzard_TalentUI/Blizzard_TalentUI.lua
@@ -0,0 +1,1043 @@
+
+StaticPopupDialogs["CONFIRM_LEARN_PREVIEW_TALENTS"] = {
+ text = CONFIRM_LEARN_PREVIEW_TALENTS,
+ button1 = YES,
+ button2 = NO,
+ OnAccept = function (self)
+ LearnPreviewTalents(PlayerTalentFrame.pet);
+ end,
+ OnCancel = function (self)
+ end,
+ hideOnEscape = 1,
+ timeout = 0,
+ exclusive = 1,
+}
+
+UIPanelWindows["PlayerTalentFrame"] = { area = "left", pushable = 6, whileDead = 1 };
+
+
+-- global constants
+GLYPH_TALENT_TAB = 4;
+
+
+-- speed references
+local next = next;
+local ipairs = ipairs;
+
+-- local data
+local specs = {
+ ["spec1"] = {
+ name = TALENT_SPEC_PRIMARY,
+ talentGroup = 1,
+ unit = "player",
+ pet = false,
+ tooltip = TALENT_SPEC_PRIMARY,
+ portraitUnit = "player",
+ defaultSpecTexture = "Interface\\Icons\\Ability_Marksmanship",
+ hasGlyphs = true,
+ glyphName = TALENT_SPEC_PRIMARY_GLYPH,
+ },
+ ["spec2"] = {
+ name = TALENT_SPEC_SECONDARY,
+ talentGroup = 2,
+ unit = "player",
+ pet = false,
+ tooltip = TALENT_SPEC_SECONDARY,
+ portraitUnit = "player",
+ defaultSpecTexture = "Interface\\Icons\\Ability_Marksmanship",
+ hasGlyphs = true,
+ glyphName = TALENT_SPEC_SECONDARY_GLYPH,
+ },
+ ["petspec1"] = {
+ name = TALENT_SPEC_PET_PRIMARY,
+ talentGroup = 1,
+ unit = "pet",
+ tooltip = TALENT_SPEC_PET_PRIMARY,
+ pet = true,
+ portraitUnit = "pet",
+ defaultSpecTexture = nil,
+ hasGlyphs = false,
+ glyphName = nil,
+ },
+};
+
+local specTabs = { }; -- filled in by PlayerSpecTab_OnLoad
+local numSpecTabs = 0;
+local selectedSpec = nil;
+local activeSpec = nil;
+
+
+-- cache talent info so we can quickly display cool stuff like the number of points spent in each tab
+local talentSpecInfoCache = {
+ ["spec1"] = { },
+ ["spec2"] = { },
+ ["petspec1"] = { },
+};
+-- cache talent tab widths so we can resize tabs to fit for localization
+local talentTabWidthCache = { };
+
+
+
+-- ACTIVESPEC_DISPLAYTYPE values:
+-- "BLUE", "GOLD_INSIDE", "GOLD_BACKGROUND"
+local ACTIVESPEC_DISPLAYTYPE = nil;
+
+-- SELECTEDSPEC_DISPLAYTYPE values:
+-- "BLUE", "GOLD_INSIDE", "PUSHED_OUT", "PUSHED_OUT_CHECKED"
+local SELECTEDSPEC_DISPLAYTYPE = "GOLD_INSIDE";
+local SELECTEDSPEC_OFFSETX;
+if ( SELECTEDSPEC_DISPLAYTYPE == "PUSHED_OUT" or SELECTEDSPEC_DISPLAYTYPE == "PUSHED_OUT_CHECKED" ) then
+ SELECTEDSPEC_OFFSETX = 5;
+else
+ SELECTEDSPEC_OFFSETX = 0;
+end
+
+
+-- PlayerTalentFrame
+
+function PlayerTalentFrame_Toggle(pet, suggestedTalentGroup)
+ local hidden;
+ local talentTabSelected = PanelTemplates_GetSelectedTab(PlayerTalentFrame) ~= GLYPH_TALENT_TAB;
+ if ( not PlayerTalentFrame:IsShown() ) then
+ ShowUIPanel(PlayerTalentFrame);
+ hidden = false;
+ else
+ local spec = selectedSpec and specs[selectedSpec];
+ if ( spec and talentTabSelected ) then
+ -- if a talent tab is selected then toggle the frame off
+ HideUIPanel(PlayerTalentFrame);
+ hidden = true;
+ else
+ hidden = false;
+ end
+ end
+ if ( not hidden ) then
+ -- open the spec with the requested talent group (or the current talent group if the selected
+ -- spec has one)
+ if ( selectedSpec ) then
+ local spec = specs[selectedSpec];
+ if ( spec.pet == pet ) then
+ suggestedTalentGroup = spec.talentGroup;
+ end
+ end
+ for _, index in ipairs(TALENT_SORT_ORDER) do
+ local spec = specs[index];
+ if ( spec.pet == pet and spec.talentGroup == suggestedTalentGroup ) then
+ PlayerSpecTab_OnClick(specTabs[index]);
+ if ( not talentTabSelected ) then
+ PlayerTalentTab_OnClick(_G["PlayerTalentFrameTab"..PlayerTalentTab_GetBestDefaultTab(index)]);
+ end
+ break;
+ end
+ end
+ end
+end
+
+function PlayerTalentFrame_Open(pet, talentGroup)
+ ShowUIPanel(PlayerTalentFrame);
+ -- open the spec with the requested talent group
+ for index, spec in next, specs do
+ if ( spec.pet == pet and spec.talentGroup == talentGroup ) then
+ PlayerSpecTab_OnClick(specTabs[index]);
+ break;
+ end
+ end
+end
+
+function PlayerTalentFrame_ToggleGlyphFrame(suggestedTalentGroup)
+ GlyphFrame_LoadUI();
+ if ( GlyphFrame ) then
+ local hidden;
+ if ( not PlayerTalentFrame:IsShown() ) then
+ ShowUIPanel(PlayerTalentFrame);
+ hidden = false;
+ else
+ local spec = selectedSpec and specs[selectedSpec];
+ if ( spec and spec.hasGlyphs and
+ PanelTemplates_GetSelectedTab(PlayerTalentFrame) == GLYPH_TALENT_TAB ) then
+ -- if the glyph tab is selected then toggle the frame off
+ HideUIPanel(PlayerTalentFrame);
+ hidden = true;
+ else
+ hidden = false;
+ end
+ end
+ if ( not hidden ) then
+ -- open the spec with the requested talent group (or the current talent group if the selected
+ -- spec has one)
+ if ( selectedSpec ) then
+ local spec = specs[selectedSpec];
+ if ( spec.hasGlyphs ) then
+ suggestedTalentGroup = spec.talentGroup;
+ end
+ end
+ for _, index in ipairs(TALENT_SORT_ORDER) do
+ local spec = specs[index];
+ if ( spec.hasGlyphs and spec.talentGroup == suggestedTalentGroup ) then
+ PlayerSpecTab_OnClick(specTabs[index]);
+ PlayerTalentTab_OnClick(_G["PlayerTalentFrameTab"..GLYPH_TALENT_TAB]);
+ break;
+ end
+ end
+ end
+ end
+end
+
+function PlayerTalentFrame_OpenGlyphFrame(talentGroup)
+ GlyphFrame_LoadUI();
+ if ( GlyphFrame ) then
+ ShowUIPanel(PlayerTalentFrame);
+ -- open the spec with the requested talent group
+ for index, spec in next, specs do
+ if ( spec.hasGlyphs and spec.talentGroup == talentGroup ) then
+ PlayerSpecTab_OnClick(specTabs[index]);
+ PlayerTalentTab_OnClick(_G["PlayerTalentFrameTab"..GLYPH_TALENT_TAB]);
+ break;
+ end
+ end
+ end
+end
+
+function PlayerTalentFrame_ShowGlyphFrame()
+ GlyphFrame_LoadUI();
+ if ( GlyphFrame ) then
+ -- set the title text of the GlyphFrame
+ if ( selectedSpec and specs[selectedSpec].glyphName and GetNumTalentGroups() > 1 ) then
+ GlyphFrameTitleText:SetText(specs[selectedSpec].glyphName);
+ else
+ GlyphFrameTitleText:SetText(GLYPHS);
+ end
+ -- show/update the glyph frame
+ if ( GlyphFrame:IsShown() ) then
+ GlyphFrame_Update();
+ else
+ GlyphFrame:Show();
+ end
+ -- don't forget to hide the scroll button overlay or it may show up on top of the GlyphFrame!
+ UIFrameFlashStop(PlayerTalentFrameScrollButtonOverlay);
+ end
+end
+
+function PlayerTalentFrame_HideGlyphFrame()
+ if ( not GlyphFrame or not GlyphFrame:IsShown() ) then
+ return;
+ end
+
+ GlyphFrame_LoadUI();
+ if ( GlyphFrame ) then
+ GlyphFrame:Hide();
+ end
+end
+
+
+function PlayerTalentFrame_OnLoad(self)
+ self:RegisterEvent("ADDON_LOADED");
+ self:RegisterEvent("PREVIEW_TALENT_POINTS_CHANGED");
+ self:RegisterEvent("PREVIEW_PET_TALENT_POINTS_CHANGED");
+ self:RegisterEvent("UNIT_PORTRAIT_UPDATE");
+ self:RegisterEvent("UNIT_PET");
+ self:RegisterEvent("PLAYER_LEVEL_UP");
+ self:RegisterEvent("PLAYER_TALENT_UPDATE");
+ self:RegisterEvent("PET_TALENT_UPDATE");
+ self:RegisterEvent("ACTIVE_TALENT_GROUP_CHANGED");
+ self.unit = "player";
+ self.inspect = false;
+ self.pet = false;
+ self.talentGroup = 1;
+ self.updateFunction = PlayerTalentFrame_Update;
+
+ TalentFrame_Load(self);
+
+ -- setup talent buttons
+ local button;
+ for i = 1, MAX_NUM_TALENTS do
+ button = _G["PlayerTalentFrameTalent"..i];
+ if ( button ) then
+ button:SetScript("OnClick", PlayerTalentFrameTalent_OnClick);
+ button:SetScript("OnEvent", PlayerTalentFrameTalent_OnEvent);
+ button:SetScript("OnEnter", PlayerTalentFrameTalent_OnEnter);
+ end
+ end
+
+ -- setup tabs
+ PanelTemplates_SetNumTabs(self, MAX_TALENT_TABS + 1); -- add one for the GLYPH_TALENT_TAB
+
+ -- initialize active spec as a fail safe
+ local activeTalentGroup = GetActiveTalentGroup();
+ local numTalentGroups = GetNumTalentGroups();
+ PlayerTalentFrame_UpdateActiveSpec(activeTalentGroup, numTalentGroups);
+
+ -- setup active spec highlight
+ if ( ACTIVESPEC_DISPLAYTYPE == "BLUE" ) then
+ PlayerTalentFrameActiveSpecTabHighlight:SetDrawLayer("OVERLAY");
+ PlayerTalentFrameActiveSpecTabHighlight:SetBlendMode("ADD");
+ PlayerTalentFrameActiveSpecTabHighlight:SetTexture("Interface\\Buttons\\UI-Button-Outline");
+ elseif ( ACTIVESPEC_DISPLAYTYPE == "GOLD_INSIDE" ) then
+ PlayerTalentFrameActiveSpecTabHighlight:SetDrawLayer("OVERLAY");
+ PlayerTalentFrameActiveSpecTabHighlight:SetBlendMode("ADD");
+ PlayerTalentFrameActiveSpecTabHighlight:SetTexture("Interface\\Buttons\\CheckButtonHilight");
+ elseif ( ACTIVESPEC_DISPLAYTYPE == "GOLD_BACKGROUND" ) then
+ PlayerTalentFrameActiveSpecTabHighlight:SetDrawLayer("BACKGROUND");
+ PlayerTalentFrameActiveSpecTabHighlight:SetWidth(74);
+ PlayerTalentFrameActiveSpecTabHighlight:SetHeight(86);
+ PlayerTalentFrameActiveSpecTabHighlight:SetTexture("Interface\\SpellBook\\SpellBook-SkillLineTab-Glow");
+ end
+end
+
+function PlayerTalentFrame_OnShow(self)
+ -- Stop buttons from flashing after skill up
+ SetButtonPulse(TalentMicroButton, 0, 1);
+
+ PlaySound("TalentScreenOpen");
+ UpdateMicroButtons();
+
+ if ( not selectedSpec ) then
+ -- if no spec was selected, try to select the active one
+ PlayerSpecTab_OnClick(activeSpec and specTabs[activeSpec] or specTabs[DEFAULT_TALENT_SPEC]);
+ else
+ PlayerTalentFrame_Refresh();
+ end
+
+ -- Set flag
+ if ( not GetCVarBool("talentFrameShown") ) then
+ SetCVar("talentFrameShown", 1);
+ UIFrameFlash(PlayerTalentFrameScrollButtonOverlay, 0.5, 0.5, 60);
+ end
+end
+
+function PlayerTalentFrame_OnHide()
+ UpdateMicroButtons();
+ PlaySound("TalentScreenClose");
+ UIFrameFlashStop(PlayerTalentFrameScrollButtonOverlay);
+ -- clear caches
+ for _, info in next, talentSpecInfoCache do
+ wipe(info);
+ end
+ wipe(talentTabWidthCache);
+end
+
+function PlayerTalentFrame_OnEvent(self, event, ...)
+ if ( event == "PLAYER_TALENT_UPDATE" or event == "PET_TALENT_UPDATE" ) then
+ PlayerTalentFrame_Refresh();
+ elseif ( event == "PREVIEW_TALENT_POINTS_CHANGED" ) then
+ --local talentIndex, tabIndex, groupIndex, points = ...;
+ if ( selectedSpec and not specs[selectedSpec].pet ) then
+ PlayerTalentFrame_Refresh();
+ end
+ elseif ( event == "PREVIEW_PET_TALENT_POINTS_CHANGED" ) then
+ --local talentIndex, tabIndex, groupIndex, points = ...;
+ if ( selectedSpec and specs[selectedSpec].pet ) then
+ PlayerTalentFrame_Refresh();
+ end
+ elseif ( event == "UNIT_PORTRAIT_UPDATE" ) then
+ local unit = ...;
+ -- update the talent frame's portrait
+ if ( unit == PlayerTalentFramePortrait.unit ) then
+ SetPortraitTexture(PlayerTalentFramePortrait, unit);
+ end
+ -- update spec tabs' portraits
+ for _, frame in next, specTabs do
+ if ( frame.usingPortraitTexture ) then
+ local spec = specs[frame.specIndex];
+ if ( unit == spec.unit and spec.portraitUnit ) then
+ SetPortraitTexture(frame:GetNormalTexture(), unit);
+ end
+ end
+ end
+ elseif ( event == "UNIT_PET" ) then
+ local summoner = ...;
+ if ( summoner == "player" ) then
+ if ( selectedSpec and specs[selectedSpec].pet ) then
+ -- if the selected spec is a pet spec...
+ local numTalentGroups = GetNumTalentGroups(false, true);
+ if ( numTalentGroups == 0 ) then
+ --...and a pet spec is not available, select the default spec
+ PlayerSpecTab_OnClick(activeSpec and specTabs[activeSpec] or specTabs[DEFAULT_TALENT_SPEC]);
+ return;
+ end
+ end
+ PlayerTalentFrame_Refresh();
+ end
+ elseif ( event == "PLAYER_LEVEL_UP" ) then
+ if ( selectedSpec and not specs[selectedSpec].pet ) then
+ local level = ...;
+ PlayerTalentFrame_Update(level);
+ end
+ elseif ( event == "ACTIVE_TALENT_GROUP_CHANGED" ) then
+ MainMenuBar_ToPlayerArt(MainMenuBarArtFrame);
+ end
+end
+
+function PlayerTalentFrame_Refresh()
+ local selectedTab = PanelTemplates_GetSelectedTab(PlayerTalentFrame);
+ if ( selectedTab == GLYPH_TALENT_TAB ) then
+ PlayerTalentFrame_ShowGlyphFrame();
+ else
+ PlayerTalentFrame_HideGlyphFrame();
+ end
+ TalentFrame_Update(PlayerTalentFrame);
+end
+
+function PlayerTalentFrame_Update(playerLevel)
+ local activeTalentGroup, numTalentGroups = GetActiveTalentGroup(false, false), GetNumTalentGroups(false, false);
+ local activePetTalentGroup, numPetTalentGroups = GetActiveTalentGroup(false, true), GetNumTalentGroups(false, true);
+
+ -- update specs
+ if ( not PlayerTalentFrame_UpdateSpecs(activeTalentGroup, numTalentGroups, activePetTalentGroup, numPetTalentGroups) ) then
+ -- the current spec is not selectable any more, discontinue updates
+ return;
+ end
+
+ -- update tabs
+ if ( not PlayerTalentFrame_UpdateTabs(playerLevel) ) then
+ -- the current spec is not selectable any more, discontinue updates
+ return;
+ end
+
+ -- set the frame portrait
+ SetPortraitTexture(PlayerTalentFramePortrait, PlayerTalentFrame.unit);
+
+ -- update active talent group stuff
+ PlayerTalentFrame_UpdateActiveSpec(activeTalentGroup, numTalentGroups);
+
+ -- update talent controls
+ PlayerTalentFrame_UpdateControls(activeTalentGroup, numTalentGroups);
+end
+
+function PlayerTalentFrame_UpdateActiveSpec(activeTalentGroup, numTalentGroups)
+ -- set the active spec
+ activeSpec = DEFAULT_TALENT_SPEC;
+ for index, spec in next, specs do
+ if ( not spec.pet and spec.talentGroup == activeTalentGroup ) then
+ activeSpec = index;
+ break;
+ end
+ end
+ -- make UI adjustments
+ local spec = selectedSpec and specs[selectedSpec];
+
+ local hasMultipleTalentGroups = numTalentGroups > 1;
+ if ( spec and hasMultipleTalentGroups ) then
+ PlayerTalentFrameTitleText:SetText(spec.name);
+ else
+ PlayerTalentFrameTitleText:SetText(TALENTS);
+ end
+
+ if ( selectedSpec == activeSpec and hasMultipleTalentGroups ) then
+ --PlayerTalentFrameActiveTalentGroupFrame:Show();
+ else
+ PlayerTalentFrameActiveTalentGroupFrame:Hide();
+ end
+end
+
+
+-- PlayerTalentFrameTalents
+
+function PlayerTalentFrameTalent_OnClick(self, button)
+ if ( IsModifiedClick("CHATLINK") ) then
+ local link = GetTalentLink(PanelTemplates_GetSelectedTab(PlayerTalentFrame), self:GetID(),
+ PlayerTalentFrame.inspect, PlayerTalentFrame.pet, PlayerTalentFrame.talentGroup, GetCVarBool("previewTalents"));
+ if ( link ) then
+ ChatEdit_InsertLink(link);
+ end
+ elseif ( selectedSpec and (activeSpec == selectedSpec or specs[selectedSpec].pet) ) then
+ -- only allow functionality if an active spec is selected
+ if ( button == "LeftButton" ) then
+ if ( GetCVarBool("previewTalents") ) then
+ AddPreviewTalentPoints(PanelTemplates_GetSelectedTab(PlayerTalentFrame), self:GetID(), 1, PlayerTalentFrame.pet, PlayerTalentFrame.talentGroup);
+ else
+ LearnTalent(PanelTemplates_GetSelectedTab(PlayerTalentFrame), self:GetID(), PlayerTalentFrame.pet, PlayerTalentFrame.talentGroup);
+ end
+ elseif ( button == "RightButton" ) then
+ if ( GetCVarBool("previewTalents") ) then
+ AddPreviewTalentPoints(PanelTemplates_GetSelectedTab(PlayerTalentFrame), self:GetID(), -1, PlayerTalentFrame.pet, PlayerTalentFrame.talentGroup);
+ end
+ end
+ end
+end
+
+function PlayerTalentFrameTalent_OnEvent(self, event, ...)
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetTalent(PanelTemplates_GetSelectedTab(PlayerTalentFrame), self:GetID(),
+ PlayerTalentFrame.inspect, PlayerTalentFrame.pet, PlayerTalentFrame.talentGroup, GetCVarBool("previewTalents"));
+ end
+end
+
+function PlayerTalentFrameTalent_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetTalent(PanelTemplates_GetSelectedTab(PlayerTalentFrame), self:GetID(),
+ PlayerTalentFrame.inspect, PlayerTalentFrame.pet, PlayerTalentFrame.talentGroup, GetCVarBool("previewTalents"));
+end
+
+
+-- Controls
+
+function PlayerTalentFrame_UpdateControls(activeTalentGroup, numTalentGroups)
+ local spec = selectedSpec and specs[selectedSpec];
+
+ local isActiveSpec = selectedSpec == activeSpec;
+
+ -- show the multi-spec status frame if this is not a pet spec or we have more than one talent group
+ local showStatusFrame = not spec.pet and numTalentGroups > 1;
+ -- show the activate button if we were going to show the status frame but this is not the active spec
+ local showActivateButton = showStatusFrame and not isActiveSpec;
+ if ( showActivateButton ) then
+ PlayerTalentFrameActivateButton:Show();
+ PlayerTalentFrameStatusFrame:Hide();
+ else
+ PlayerTalentFrameActivateButton:Hide();
+ if ( showStatusFrame ) then
+ PlayerTalentFrameStatusFrame:Show();
+ else
+ PlayerTalentFrameStatusFrame:Hide();
+ end
+ end
+
+ local preview = GetCVarBool("previewTalents");
+
+ -- enable the control bar if this is the active spec, preview is enabled, and preview points were spent
+ local talentPoints = GetUnspentTalentPoints(false, spec.pet, spec.talentGroup);
+ if ( (spec.pet or isActiveSpec) and talentPoints > 0 and preview ) then
+ PlayerTalentFramePreviewBar:Show();
+ -- enable accept/cancel buttons if preview talent points were spent
+ if ( GetGroupPreviewTalentPointsSpent(spec.pet, spec.talentGroup) > 0 ) then
+ PlayerTalentFrameLearnButton:Enable();
+ PlayerTalentFrameResetButton:Enable();
+ else
+ PlayerTalentFrameLearnButton:Disable();
+ PlayerTalentFrameResetButton:Disable();
+ end
+ -- squish all frames to make room for this bar
+ PlayerTalentFramePointsBar:SetPoint("BOTTOM", PlayerTalentFramePreviewBar, "TOP", 0, -4);
+ else
+ PlayerTalentFramePreviewBar:Hide();
+ -- unsquish frames since the bar is now hidden
+ PlayerTalentFramePointsBar:SetPoint("BOTTOM", PlayerTalentFrame, "BOTTOM", 0, 81);
+ end
+end
+
+function PlayerTalentFrameActivateButton_OnLoad(self)
+ self:SetWidth(self:GetTextWidth() + 40);
+end
+
+function PlayerTalentFrameActivateButton_OnClick(self)
+ if ( selectedSpec ) then
+ local talentGroup = specs[selectedSpec].talentGroup;
+ if ( talentGroup ) then
+ SetActiveTalentGroup(talentGroup);
+ end
+ end
+end
+
+function PlayerTalentFrameActivateButton_OnShow(self)
+ self:RegisterEvent("CURRENT_SPELL_CAST_CHANGED");
+ PlayerTalentFrameActivateButton_Update();
+end
+
+function PlayerTalentFrameActivateButton_OnHide(self)
+ self:UnregisterEvent("CURRENT_SPELL_CAST_CHANGED");
+end
+
+function PlayerTalentFrameActivateButton_OnEvent(self, event, ...)
+ PlayerTalentFrameActivateButton_Update();
+end
+
+function PlayerTalentFrameActivateButton_Update()
+ local spec = selectedSpec and specs[selectedSpec];
+ if ( spec and PlayerTalentFrameActivateButton:IsShown() ) then
+ -- if the activation spell is being cast currently, disable the activate button
+ if ( IsCurrentSpell(TALENT_ACTIVATION_SPELLS[spec.talentGroup]) ) then
+ PlayerTalentFrameActivateButton:Disable();
+ else
+ PlayerTalentFrameActivateButton:Enable();
+ end
+ end
+end
+
+function PlayerTalentFrameResetButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(TALENT_TOOLTIP_RESETTALENTGROUP);
+end
+
+function PlayerTalentFrameResetButton_OnClick(self)
+ ResetGroupPreviewTalentPoints(PlayerTalentFrame.pet, PlayerTalentFrame.talentGroup);
+end
+
+function PlayerTalentFrameLearnButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(TALENT_TOOLTIP_LEARNTALENTGROUP);
+end
+
+function PlayerTalentFrameLearnButton_OnClick(self)
+ StaticPopup_Show("CONFIRM_LEARN_PREVIEW_TALENTS");
+end
+
+
+-- PlayerTalentFrameDownArrow
+
+function PlayerTalentFrameDownArrow_OnClick(self, button)
+ local parent = self:GetParent();
+ parent:SetValue(parent:GetValue() + (parent:GetHeight() / 2));
+ PlaySound("UChatScrollButton");
+ UIFrameFlashStop(PlayerTalentFrameScrollButtonOverlay);
+end
+
+
+-- PlayerTalentFrameTab
+
+function PlayerTalentFrame_UpdateTabs(playerLevel)
+ local totalTabWidth = 0;
+
+ local firstShownTab;
+
+ -- setup talent tabs
+ local maxPointsSpent = 0;
+ local selectedTab = PanelTemplates_GetSelectedTab(PlayerTalentFrame);
+ local numTabs = GetNumTalentTabs(PlayerTalentFrame.inspect, PlayerTalentFrame.pet);
+ local tab;
+ for i = 1, MAX_TALENT_TABS do
+ -- clear cached widths
+ talentTabWidthCache[i] = 0;
+ tab = _G["PlayerTalentFrameTab"..i];
+ if ( tab ) then
+ if ( i <= numTabs ) then
+ local name, icon, pointsSpent, background, previewPointsSpent = GetTalentTabInfo(i, PlayerTalentFrame.inspect, PlayerTalentFrame.pet, PlayerTalentFrame.talentGroup);
+ if ( i == selectedTab ) then
+ -- If tab is the selected tab set the points spent info
+ local displayPointsSpent = pointsSpent + previewPointsSpent;
+ PlayerTalentFrameSpentPointsText:SetFormattedText(MASTERY_POINTS_SPENT, name, HIGHLIGHT_FONT_COLOR_CODE..displayPointsSpent..FONT_COLOR_CODE_CLOSE);
+ PlayerTalentFrame.pointsSpent = pointsSpent;
+ PlayerTalentFrame.previewPointsSpent = previewPointsSpent;
+ end
+ tab:SetText(name);
+ PanelTemplates_TabResize(tab, 0);
+ -- record the text width to see if we need to display a tooltip
+ tab.textWidth = tab:GetTextWidth();
+ -- record the tab widths for resizing later
+ talentTabWidthCache[i] = PanelTemplates_GetTabWidth(tab);
+ totalTabWidth = totalTabWidth + talentTabWidthCache[i];
+ tab:Show();
+ firstShownTab = firstShownTab or tab;
+ else
+ tab:Hide();
+ tab.textWidth = 0;
+ end
+ end
+ end
+
+ local spec = specs[selectedSpec];
+
+ -- setup glyph tabs, right now there is only one
+ playerLevel = playerLevel or UnitLevel("player");
+ local meetsGlyphLevel = playerLevel >= SHOW_INSCRIPTION_LEVEL;
+ tab = _G["PlayerTalentFrameTab"..GLYPH_TALENT_TAB];
+ if ( meetsGlyphLevel and spec.hasGlyphs ) then
+ tab:Show();
+ firstShownTab = firstShownTab or tab;
+ PanelTemplates_TabResize(tab, 0);
+ talentTabWidthCache[GLYPH_TALENT_TAB] = PanelTemplates_GetTabWidth(tab);
+ totalTabWidth = totalTabWidth + talentTabWidthCache[GLYPH_TALENT_TAB];
+ else
+ tab:Hide();
+ talentTabWidthCache[GLYPH_TALENT_TAB] = 0;
+ end
+ local numGlyphTabs = 1;
+
+ -- select the first shown tab if the selected tab does not exist for the selected spec
+ tab = _G["PlayerTalentFrameTab"..selectedTab];
+ if ( tab and not tab:IsShown() ) then
+ if ( firstShownTab ) then
+ PlayerTalentFrameTab_OnClick(firstShownTab);
+ end
+ return false;
+ end
+
+ -- readjust tab sizes to fit
+ local maxTotalTabWidth = PlayerTalentFrame:GetWidth();
+ while ( totalTabWidth >= maxTotalTabWidth ) do
+ -- progressively shave 10 pixels off of the largest tab until they all fit within the max width
+ local largestTab = 1;
+ for i = 2, #talentTabWidthCache do
+ if ( talentTabWidthCache[largestTab] < talentTabWidthCache[i] ) then
+ largestTab = i;
+ end
+ end
+ -- shave the width
+ talentTabWidthCache[largestTab] = talentTabWidthCache[largestTab] - 10;
+ -- apply the shaved width
+ tab = _G["PlayerTalentFrameTab"..largestTab];
+ PanelTemplates_TabResize(tab, 0, talentTabWidthCache[largestTab]);
+ -- now update the total width
+ totalTabWidth = totalTabWidth - 10;
+ end
+
+ -- update the tabs
+ PanelTemplates_SetNumTabs(PlayerTalentFrame, numTabs + numGlyphTabs);
+ PanelTemplates_UpdateTabs(PlayerTalentFrame);
+
+ return true;
+end
+
+function PlayerTalentFrameTab_OnLoad(self)
+ self:SetFrameLevel(self:GetFrameLevel() + 2);
+end
+
+function PlayerTalentFrameTab_OnClick(self)
+ local id = self:GetID();
+ PanelTemplates_SetTab(PlayerTalentFrame, id);
+ PlayerTalentFrame_Refresh();
+ PlaySound("igCharacterInfoTab");
+end
+
+function PlayerTalentFrameTab_OnEnter(self)
+ if ( self.textWidth and self.textWidth > self:GetFontString():GetWidth() ) then --We're ellipsizing.
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOM");
+ GameTooltip:SetText(self:GetText());
+ end
+end
+
+
+-- PlayerTalentTab
+
+function PlayerTalentTab_OnLoad(self)
+ PlayerTalentFrameTab_OnLoad(self);
+
+ self:RegisterEvent("PLAYER_LEVEL_UP");
+end
+
+function PlayerTalentTab_OnClick(self)
+ PlayerTalentFrameTab_OnClick(self);
+ for i=1, MAX_TALENT_TABS do
+ SetButtonPulse(_G["PlayerTalentFrameTab"..i], 0, 0);
+ end
+end
+
+function PlayerTalentTab_OnEvent(self, event, ...)
+ if ( UnitLevel("player") == (SHOW_TALENT_LEVEL - 1) and PanelTemplates_GetSelectedTab(PlayerTalentFrame) ~= self:GetID() ) then
+ SetButtonPulse(self, 60, 0.75);
+ end
+end
+
+function PlayerTalentTab_GetBestDefaultTab(specIndex)
+ if ( not specIndex ) then
+ return DEFAULT_TALENT_TAB;
+ end
+
+ local spec = specs[specIndex];
+ if ( not spec ) then
+ return DEFAULT_TALENT_TAB;
+ end
+
+ local specInfoCache = talentSpecInfoCache[specIndex];
+ TalentFrame_UpdateSpecInfoCache(specInfoCache, false, spec.pet, spec.talentGroup);
+ if ( specInfoCache.primaryTabIndex > 0 ) then
+ return talentSpecInfoCache[specIndex].primaryTabIndex;
+ else
+ return DEFAULT_TALENT_TAB;
+ end
+end
+
+
+-- PlayerGlyphTab
+
+function PlayerGlyphTab_OnLoad(self)
+ PlayerTalentFrameTab_OnLoad(self);
+
+ self:RegisterEvent("PLAYER_LEVEL_UP");
+ GLYPH_TALENT_TAB = self:GetID();
+ -- we can record the text width for the glyph tab now since it never changes
+ self.textWidth = self:GetTextWidth();
+end
+
+function PlayerGlyphTab_OnClick(self)
+ PlayerTalentFrameTab_OnClick(self);
+ SetButtonPulse(_G["PlayerTalentFrameTab"..GLYPH_TALENT_TAB], 0, 0);
+end
+
+function PlayerGlyphTab_OnEvent(self, event, ...)
+ if ( UnitLevel("player") == (SHOW_INSCRIPTION_LEVEL - 1) and PanelTemplates_GetSelectedTab(PlayerTalentFrame) ~= self:GetID() ) then
+ SetButtonPulse(self, 60, 0.75);
+ end
+end
+
+
+-- Specs
+
+-- PlayerTalentFrame_UpdateSpecs is a helper function for PlayerTalentFrame_Update.
+-- Returns true on a successful update, false otherwise. An update may fail if the currently
+-- selected tab is no longer selectable. In this case, the first selectable tab will be selected.
+function PlayerTalentFrame_UpdateSpecs(activeTalentGroup, numTalentGroups, activePetTalentGroup, numPetTalentGroups)
+ -- set the active spec highlight to be hidden initially, if a spec is the active one then it will
+ -- be shown in PlayerSpecTab_Update
+ PlayerTalentFrameActiveSpecTabHighlight:Hide();
+
+ -- update each of the spec tabs
+ local firstShownTab, lastShownTab;
+ local numShown = 0;
+ local offsetX = 0;
+ for i = 1, numSpecTabs do
+ local frame = _G["PlayerSpecTab"..i];
+ local specIndex = frame.specIndex;
+ local spec = specs[specIndex];
+ if ( PlayerSpecTab_Update(frame, activeTalentGroup, numTalentGroups, activePetTalentGroup, numPetTalentGroups) ) then
+ firstShownTab = firstShownTab or frame;
+ numShown = numShown + 1;
+ frame:ClearAllPoints();
+ -- set an offsetX fudge if we're the selected tab, otherwise use the previous offsetX
+ offsetX = specIndex == selectedSpec and SELECTEDSPEC_OFFSETX or offsetX;
+ if ( numShown == 1 ) then
+ --...start the first tab off at a base location
+ frame:SetPoint("TOPLEFT", frame:GetParent(), "TOPRIGHT", -32 + offsetX, -65);
+ -- we'll need to negate the offsetX after the first tab so all subsequent tabs offset
+ -- to their default positions
+ offsetX = -offsetX;
+ else
+ --...offset subsequent tabs from the previous one
+ if ( spec.pet ~= specs[lastShownTab.specIndex].pet ) then
+ frame:SetPoint("TOPLEFT", lastShownTab, "BOTTOMLEFT", 0 + offsetX, -39);
+ else
+ frame:SetPoint("TOPLEFT", lastShownTab, "BOTTOMLEFT", 0 + offsetX, -22);
+ end
+ end
+ lastShownTab = frame;
+ else
+ -- if the selected tab is not shown then clear out the selected spec
+ if ( specIndex == selectedSpec ) then
+ selectedSpec = nil;
+ end
+ end
+ end
+
+ if ( not selectedSpec ) then
+ if ( firstShownTab ) then
+ PlayerSpecTab_OnClick(firstShownTab);
+ end
+ return false;
+ end
+
+ if ( numShown == 1 and lastShownTab ) then
+ -- if we're only showing one tab, we might as well hide it since it doesn't need to be there
+ lastShownTab:Hide();
+ end
+
+ return true;
+end
+
+function PlayerSpecTab_Update(self, ...)
+ local activeTalentGroup, numTalentGroups, activePetTalentGroup, numPetTalentGroups = ...;
+
+ local specIndex = self.specIndex;
+ local spec = specs[specIndex];
+
+ -- determine whether or not we need to hide the tab
+ local canShow;
+ if ( spec.pet ) then
+ canShow = spec.talentGroup <= numPetTalentGroups;
+ else
+ canShow = spec.talentGroup <= numTalentGroups;
+ end
+ if ( not canShow ) then
+ self:Hide();
+ return false;
+ end
+
+ local isSelectedSpec = specIndex == selectedSpec;
+ local isActiveSpec = not spec.pet and spec.talentGroup == activeTalentGroup;
+ local normalTexture = self:GetNormalTexture();
+
+ -- set the background based on whether or not we're selected
+ if ( isSelectedSpec and (SELECTEDSPEC_DISPLAYTYPE == "PUSHED_OUT" or SELECTEDSPEC_DISPLAYTYPE == "PUSHED_OUT_CHECKED") ) then
+ local name = self:GetName();
+ local backgroundTexture = _G[name.."Background"];
+ backgroundTexture:SetTexture("Interface\\TalentFrame\\UI-TalentFrame-SpecTab");
+ backgroundTexture:SetPoint("TOPLEFT", self, "TOPLEFT", -13, 11);
+ if ( SELECTEDSPEC_DISPLAYTYPE == "PUSHED_OUT_CHECKED" ) then
+ self:GetCheckedTexture():Show();
+ else
+ self:GetCheckedTexture():Hide();
+ end
+ else
+ local name = self:GetName();
+ local backgroundTexture = _G[name.."Background"];
+ backgroundTexture:SetTexture("Interface\\SpellBook\\SpellBook-SkillLineTab");
+ backgroundTexture:SetPoint("TOPLEFT", self, "TOPLEFT", -3, 11);
+ end
+
+ -- update the active spec info
+ local hasMultipleTalentGroups = numTalentGroups > 1;
+ if ( isActiveSpec and hasMultipleTalentGroups ) then
+ PlayerTalentFrameActiveSpecTabHighlight:ClearAllPoints();
+ if ( ACTIVESPEC_DISPLAYTYPE == "BLUE" ) then
+ PlayerTalentFrameActiveSpecTabHighlight:SetParent(self);
+ PlayerTalentFrameActiveSpecTabHighlight:SetPoint("TOPLEFT", self, "TOPLEFT", -13, 14);
+ PlayerTalentFrameActiveSpecTabHighlight:SetPoint("BOTTOMRIGHT", self, "BOTTOMRIGHT", 15, -14);
+ PlayerTalentFrameActiveSpecTabHighlight:Show();
+ elseif ( ACTIVESPEC_DISPLAYTYPE == "GOLD_INSIDE" ) then
+ PlayerTalentFrameActiveSpecTabHighlight:SetParent(self);
+ PlayerTalentFrameActiveSpecTabHighlight:SetAllPoints(self);
+ PlayerTalentFrameActiveSpecTabHighlight:Show();
+ elseif ( ACTIVESPEC_DISPLAYTYPE == "GOLD_BACKGROUND" ) then
+ PlayerTalentFrameActiveSpecTabHighlight:SetParent(self);
+ PlayerTalentFrameActiveSpecTabHighlight:SetPoint("TOPLEFT", self, "TOPLEFT", -3, 20);
+ PlayerTalentFrameActiveSpecTabHighlight:Show();
+ else
+ PlayerTalentFrameActiveSpecTabHighlight:Hide();
+ end
+ end
+
+--[[
+ if ( not spec.pet ) then
+ SetDesaturation(normalTexture, not isActiveSpec);
+ end
+--]]
+
+ -- update the spec info cache
+ TalentFrame_UpdateSpecInfoCache(talentSpecInfoCache[specIndex], false, spec.pet, spec.talentGroup);
+
+ -- update spec tab icon
+ self.usingPortraitTexture = false;
+ if ( hasMultipleTalentGroups ) then
+ local specInfoCache = talentSpecInfoCache[specIndex];
+ local primaryTabIndex = specInfoCache.primaryTabIndex;
+ if ( primaryTabIndex > 0 ) then
+ -- the spec had a primary tab, set the icon to that tab's icon
+ normalTexture:SetTexture(specInfoCache[primaryTabIndex].icon);
+ else
+ if ( specInfoCache.numTabs > 1 and specInfoCache.totalPointsSpent > 0 ) then
+ -- the spec is only considered a hybrid if the spec had more than one tab and at least
+ -- one point was spent in one of the tabs
+ normalTexture:SetTexture(TALENT_HYBRID_ICON);
+ else
+ if ( spec.defaultSpecTexture ) then
+ -- the spec is probably untalented...set to the default spec texture if we have one
+ normalTexture:SetTexture(spec.defaultSpecTexture);
+ elseif ( spec.portraitUnit ) then
+ -- last check...if there is no default spec texture, try the portrait unit
+ SetPortraitTexture(normalTexture, spec.portraitUnit);
+ self.usingPortraitTexture = true;
+ end
+ end
+ end
+ else
+ if ( spec.portraitUnit ) then
+ -- set to the portrait texture if we only have one talent group
+ SetPortraitTexture(normalTexture, spec.portraitUnit);
+ self.usingPortraitTexture = true;
+ end
+ end
+--[[
+ -- update overlay icon
+ local name = self:GetName();
+ local overlayIcon = _G[name.."OverlayIcon"];
+ if ( overlayIcon ) then
+ if ( hasMultipleTalentGroups ) then
+ overlayIcon:Show();
+ else
+ overlayIcon:Hide();
+ end
+ end
+--]]
+ self:Show();
+ return true;
+end
+
+function PlayerSpecTab_Load(self, specIndex)
+ self.specIndex = specIndex;
+ specTabs[specIndex] = self;
+ numSpecTabs = numSpecTabs + 1;
+
+ -- set the spec's portrait
+ local spec = specs[self.specIndex];
+ if ( spec.portraitUnit ) then
+ SetPortraitTexture(self:GetNormalTexture(), spec.portraitUnit);
+ self.usingPortraitTexture = true;
+ else
+ self.usingPortraitTexture = false;
+ end
+
+ -- set the checked texture
+ if ( SELECTEDSPEC_DISPLAYTYPE == "BLUE" ) then
+ local checkedTexture = self:GetCheckedTexture();
+ checkedTexture:SetTexture("Interface\\Buttons\\UI-Button-Outline");
+ checkedTexture:SetWidth(64);
+ checkedTexture:SetHeight(64);
+ checkedTexture:ClearAllPoints();
+ checkedTexture:SetPoint("CENTER", self, "CENTER", 0, 0);
+ elseif ( SELECTEDSPEC_DISPLAYTYPE == "GOLD_INSIDE" ) then
+ local checkedTexture = self:GetCheckedTexture();
+ checkedTexture:SetTexture("Interface\\Buttons\\CheckButtonHilight");
+ end
+
+ local activeTalentGroup, numTalentGroups = GetActiveTalentGroup(false, false), GetNumTalentGroups(false, false);
+ local activePetTalentGroup, numPetTalentGroups = GetActiveTalentGroup(false, true), GetNumTalentGroups(false, true);
+ PlayerSpecTab_Update(self, activeTalentGroup, numTalentGroups, activePetTalentGroup, numPetTalentGroups);
+end
+
+function PlayerSpecTab_OnClick(self)
+ -- set all specs as unchecked initially
+ for _, frame in next, specTabs do
+ frame:SetChecked(nil);
+ end
+
+ -- check ourselves (before we wreck ourselves)
+ self:SetChecked(1);
+
+ -- update the selected to this spec
+ local specIndex = self.specIndex;
+ selectedSpec = specIndex;
+
+ -- set data on the talent frame
+ local spec = specs[specIndex];
+ PlayerTalentFrame.pet = spec.pet;
+ PlayerTalentFrame.unit = spec.unit;
+ PlayerTalentFrame.talentGroup = spec.talentGroup;
+
+ -- select a tab if one is not already selected
+ if ( not PanelTemplates_GetSelectedTab(PlayerTalentFrame) ) then
+ PanelTemplates_SetTab(PlayerTalentFrame, PlayerTalentTab_GetBestDefaultTab(specIndex));
+ end
+
+ -- update the talent frame
+ PlayerTalentFrame_Refresh();
+end
+
+function PlayerSpecTab_OnEnter(self)
+ local specIndex = self.specIndex;
+ local spec = specs[specIndex];
+ if ( spec.tooltip ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ -- name
+ if ( GetNumTalentGroups(false, true) <= 1 and GetNumTalentGroups(false, false) <= 1 ) then
+ -- set the tooltip to be the unit's name
+ GameTooltip:AddLine(UnitName(spec.unit), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ else
+ -- set the tooltip to be the spec name
+ GameTooltip:AddLine(spec.tooltip);
+ if ( self.specIndex == activeSpec ) then
+ -- add text to indicate that this spec is active
+ GameTooltip:AddLine(TALENT_ACTIVE_SPEC_STATUS, GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b);
+ end
+ end
+ -- points spent
+ local pointsColor;
+ for index, info in ipairs(talentSpecInfoCache[specIndex]) do
+ if ( info.name ) then
+ -- assign a special color to a tab that surpasses the max points spent threshold
+ if ( talentSpecInfoCache[specIndex].primaryTabIndex == index ) then
+ pointsColor = GREEN_FONT_COLOR;
+ else
+ pointsColor = HIGHLIGHT_FONT_COLOR;
+ end
+ GameTooltip:AddDoubleLine(
+ info.name,
+ info.pointsSpent,
+ HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b,
+ pointsColor.r, pointsColor.g, pointsColor.b,
+ 1
+ );
+ end
+ end
+ GameTooltip:Show();
+ end
+end
+
diff --git a/reference/AddOns/Blizzard_TalentUI/Blizzard_TalentUI.toc b/reference/AddOns/Blizzard_TalentUI/Blizzard_TalentUI.toc
new file mode 100644
index 0000000..37e1789
--- /dev/null
+++ b/reference/AddOns/Blizzard_TalentUI/Blizzard_TalentUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard Talent UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_TalentUI.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_TalentUI/Blizzard_TalentUI.xml b/reference/AddOns/Blizzard_TalentUI/Blizzard_TalentUI.xml
new file mode 100644
index 0000000..46bc3b8
--- /dev/null
+++ b/reference/AddOns/Blizzard_TalentUI/Blizzard_TalentUI.xml
@@ -0,0 +1,780 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoTab");
+ PlayerSpecTab_OnClick(self, button, down);
+
+
+ PlayerSpecTab_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+ PlayerTalentTab_OnLoad(self);
+
+
+ PlayerTalentTab_OnEvent(self, event, ...);
+
+
+ PlayerTalentTab_OnClick(self, button, down);
+
+
+ PlayerTalentFrameTab_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+ PlayerGlyphTab_OnLoad(self);
+
+
+ PlayerGlyphTab_OnEvent(self, event, ...);
+
+
+ PlayerGlyphTab_OnClick(self, button, down);
+
+
+ PlayerTalentFrameTab_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:RegisterEvent("PREVIEW_TALENT_POINTS_CHANGED");
+ self:RegisterEvent("PREVIEW_PET_TALENT_POINTS_CHANGED");
+ self:RegisterEvent("PLAYER_TALENT_UPDATE");
+ self:RegisterEvent("PET_TALENT_UPDATE");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlayerSpecTab_Load(self, "spec1");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlayerSpecTab_Load(self, "spec2");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlayerSpecTab_Load(self, "petspec1");
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_TalentUI/Localization.lua b/reference/AddOns/Blizzard_TalentUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_TalentUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_TimeManager/Blizzard_TimeManager.lua b/reference/AddOns/Blizzard_TimeManager/Blizzard_TimeManager.lua
new file mode 100644
index 0000000..87b161c
--- /dev/null
+++ b/reference/AddOns/Blizzard_TimeManager/Blizzard_TimeManager.lua
@@ -0,0 +1,768 @@
+
+-- speed optimizations (mostly so update functions are faster)
+local _G = getfenv(0);
+local date = _G.date;
+local abs = _G.abs;
+local min = _G.min;
+local max = _G.max;
+local floor = _G.floor;
+local mod = _G.mod;
+local tonumber = _G.tonumber;
+local gsub = _G.gsub;
+local GetCVar = _G.GetCVar;
+local SetCVar = _G.SetCVar;
+local GetGameTime = _G.GetGameTime;
+
+-- private data
+local SEC_TO_MINUTE_FACTOR = 1/60;
+local SEC_TO_HOUR_FACTOR = SEC_TO_MINUTE_FACTOR*SEC_TO_MINUTE_FACTOR;
+
+local WARNING_SOUND_TRIGGER_OFFSET = -2 * SEC_TO_MINUTE_FACTOR; -- play warning sound 2 sec before alarm sound
+
+local Settings = {
+ militaryTime = false;
+ localTime = false;
+
+ alarmHour = 12;
+ alarmMinute = 00;
+ alarmAM = true;
+ alarmMessage = "";
+ alarmEnabled = false;
+};
+
+local CVAR_USE_MILITARY_TIME = "timeMgrUseMilitaryTime";
+local CVAR_USE_LOCAL_TIME = "timeMgrUseLocalTime";
+local CVAR_ALARM_TIME = "timeMgrAlarmTime";
+local CVAR_ALARM_MESSAGE = "timeMgrAlarmMessage";
+local CVAR_ALARM_ENABLED = "timeMgrAlarmEnabled";
+
+
+-- public data
+MAX_TIMER_SEC = 99*3600 + 59*60 + 59; -- 99:59:59
+
+
+local function _TimeManager_GetCurrentMinutes(localTime)
+ local currTime;
+ if ( localTime ) then
+ local dateInfo = date("*t");
+ local hour, minute = dateInfo.hour, dateInfo.min;
+ currTime = minute + hour*60;
+ else
+ local hour, minute = GetGameTime();
+ currTime = minute + hour*60;
+ end
+ return currTime;
+end
+
+-- CVar helpers
+local function _TimeManager_Setting_SetBool(cvar, field, value)
+ if ( value ) then
+ SetCVar(cvar, "1");
+ else
+ SetCVar(cvar, "0");
+ end
+ Settings[field] = value;
+end
+
+local function _TimeManager_Setting_Set(cvar, field, value)
+ SetCVar(cvar, value);
+ Settings[field] = value;
+end
+
+local function _TimeManager_Setting_SetTime()
+ local alarmTime = GameTime_ComputeMinutes(Settings.alarmHour, Settings.alarmMinute, Settings.militaryTime, Settings.alarmAM);
+ SetCVar(CVAR_ALARM_TIME, alarmTime);
+end
+
+
+-- TimeManagerFrame
+
+function TimeManager_Toggle()
+ if ( TimeManagerFrame:IsShown() ) then
+ TimeManagerFrame:Hide();
+ else
+ TimeManagerFrame:Show();
+ end
+end
+
+function TimeManagerFrame_OnLoad(self)
+ Settings.militaryTime = GetCVar(CVAR_USE_MILITARY_TIME) == "1";
+ Settings.localTime = GetCVar(CVAR_USE_LOCAL_TIME) == "1";
+ local alarmTime = tonumber(GetCVar(CVAR_ALARM_TIME));
+ Settings.alarmHour = floor(alarmTime / 60);
+ Settings.alarmMinute = max(min(alarmTime - Settings.alarmHour*60, 59), 0);
+ Settings.alarmHour = max(min(Settings.alarmHour, 23), 0);
+ if ( not Settings.militaryTime ) then
+ if ( Settings.alarmHour == 0 ) then
+ Settings.alarmHour = 12;
+ Settings.alarmAM = true;
+ elseif ( Settings.alarmHour < 12 ) then
+ Settings.alarmAM = true;
+ elseif ( Settings.alarmHour == 12 ) then
+ Settings.alarmAM = false;
+ else
+ Settings.alarmHour = Settings.alarmHour - 12;
+ Settings.alarmAM = false;
+ end
+ end
+ Settings.alarmMessage = GetCVar(CVAR_ALARM_MESSAGE);
+ Settings.alarmEnabled = GetCVar(CVAR_ALARM_ENABLED) == "1";
+
+ self:SetFrameLevel(self:GetFrameLevel() + 2);
+
+ UIDropDownMenu_Initialize(TimeManagerAlarmHourDropDown, TimeManagerAlarmHourDropDown_Initialize);
+ UIDropDownMenu_SetWidth(TimeManagerAlarmHourDropDown, 30, 40);
+
+ UIDropDownMenu_Initialize(TimeManagerAlarmMinuteDropDown, TimeManagerAlarmMinuteDropDown_Initialize);
+ UIDropDownMenu_SetWidth(TimeManagerAlarmMinuteDropDown, 30, 40);
+
+ UIDropDownMenu_Initialize(TimeManagerAlarmAMPMDropDown, TimeManagerAlarmAMPMDropDown_Initialize);
+ -- some languages have ridonculously long am/pm strings (i'm looking at you French) so we may have to
+ -- readjust the ampm dropdown width plus do some reanchoring if the text is too wide
+ local maxAMPMWidth;
+ TimeManagerAMPMDummyText:SetText(TIMEMANAGER_AM);
+ maxAMPMWidth = TimeManagerAMPMDummyText:GetWidth();
+ TimeManagerAMPMDummyText:SetText(TIMEMANAGER_PM);
+ if ( maxAMPMWidth < TimeManagerAMPMDummyText:GetWidth() ) then
+ maxAMPMWidth = TimeManagerAMPMDummyText:GetWidth();
+ end
+ maxAMPMWidth = ceil(maxAMPMWidth);
+ if ( maxAMPMWidth > 40 ) then
+ UIDropDownMenu_SetWidth(TimeManagerAlarmAMPMDropDown, maxAMPMWidth + 20, 40);
+ TimeManagerAlarmAMPMDropDown:SetScript("OnShow", TimeManagerAlarmAMPMDropDown_OnShow);
+ TimeManagerAlarmAMPMDropDown:SetScript("OnHide", TimeManagerAlarmAMPMDropDown_OnHide);
+ else
+ UIDropDownMenu_SetWidth(TimeManagerAlarmAMPMDropDown, 40, 40);
+ end
+
+ TimeManager_Update();
+end
+
+function TimeManagerFrame_OnUpdate(self, elapsed)
+ TimeManager_UpdateTimeTicker();
+end
+
+function TimeManagerFrame_OnShow(self)
+ TimeManager_Update();
+ TimeManagerStopwatchCheck:SetChecked(StopwatchFrame:IsShown());
+ PlaySound("igCharacterInfoOpen");
+end
+
+function TimeManagerFrame_OnHide(self)
+ PlaySound("igCharacterInfoClose");
+end
+
+function TimeManagerCloseButton_OnClick()
+ TimeManagerFrame:Hide();
+end
+
+function TimeManagerStopwatchCheck_OnClick(self)
+ Stopwatch_Toggle();
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuQuit");
+ end
+end
+
+function TimeManagerAlarmHourDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+
+ local alarmHour = Settings.alarmHour;
+ local militaryTime = Settings.militaryTime;
+
+ local hourMin, hourMax;
+ if ( militaryTime ) then
+ hourMin = 0;
+ hourMax = 23;
+ else
+ hourMin = 1;
+ hourMax = 12;
+ end
+ for hour = hourMin, hourMax, 1 do
+ info.value = hour;
+ if ( militaryTime ) then
+ info.text = format(TIMEMANAGER_24HOUR, hour);
+ else
+ info.text = hour;
+ info.justifyH = "RIGHT";
+ end
+ info.func = TimeManagerAlarmHourDropDown_OnClick;
+ if ( hour == alarmHour ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(TimeManagerAlarmHourDropDown, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function TimeManagerAlarmMinuteDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+
+ local alarmMinute = Settings.alarmMinute;
+ for minute = 0, 55, 5 do
+ info.value = minute;
+ info.text = format(TIMEMANAGER_MINUTE, minute);
+ info.func = TimeManagerAlarmMinuteDropDown_OnClick;
+ if ( minute == alarmMinute ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(TimeManagerAlarmMinuteDropDown, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function TimeManagerAlarmAMPMDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+
+ local pm = (Settings.militaryTime and Settings.alarmHour >= 12) or not Settings.alarmAM;
+
+ info.value = 1;
+ info.text = TIMEMANAGER_AM;
+ info.func = TimeManagerAlarmAMPMDropDown_OnClick;
+ if ( not pm ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(TimeManagerAlarmAMPMDropDown, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+
+ info.value = 0;
+ info.text = TIMEMANAGER_PM;
+ info.func = TimeManagerAlarmAMPMDropDown_OnClick;
+ if ( pm ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(TimeManagerAlarmAMPMDropDown, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+end
+
+function TimeManagerAlarmHourDropDown_OnClick(self)
+ UIDropDownMenu_SetSelectedValue(TimeManagerAlarmHourDropDown, self.value);
+ local oldValue = Settings.alarmHour;
+ Settings.alarmHour = self.value;
+ if ( Settings.alarmHour ~= oldValue ) then
+ TimeManager_StartCheckingAlarm();
+ end
+ _TimeManager_Setting_SetTime();
+end
+
+function TimeManagerAlarmMinuteDropDown_OnClick(self)
+ UIDropDownMenu_SetSelectedValue(TimeManagerAlarmMinuteDropDown, self.value);
+ local oldValue = Settings.alarmMinute;
+ Settings.alarmMinute = self.value;
+ if ( Settings.alarmMinute ~= oldValue ) then
+ TimeManager_StartCheckingAlarm();
+ end
+ _TimeManager_Setting_SetTime();
+end
+
+function TimeManagerAlarmAMPMDropDown_OnClick(self)
+ UIDropDownMenu_SetSelectedValue(TimeManagerAlarmAMPMDropDown, self.value);
+ if ( self.value == 1 ) then
+ if ( not Settings.alarmAM ) then
+ Settings.alarmAM = true;
+ TimeManager_StartCheckingAlarm();
+ end
+ else
+ if ( Settings.alarmAM ) then
+ Settings.alarmAM = false;
+ TimeManager_StartCheckingAlarm();
+ end
+ end
+ _TimeManager_Setting_SetTime();
+end
+
+function TimeManagerAlarmAMPMDropDown_OnShow()
+ -- readjust the size of and reanchor TimeManagerAlarmAMPMDropDown and all frames below it
+ TimeManagerAlarmAMPMDropDown:SetPoint("TOPLEFT", TimeManagerAlarmHourDropDown, "BOTTOMLEFT", 0, 5);
+ TimeManagerAlarmMessageFrame:SetPoint("TOPLEFT", TimeManagerAlarmHourDropDown, "BOTTOMLEFT", 20, -23);
+ TimeManagerAlarmEnabledButton:SetPoint("CENTER", TimeManagerFrame, "CENTER", -20, -69);
+ TimeManagerMilitaryTimeCheck:SetPoint("TOPLEFT", TimeManagerFrame, "TOPLEFT", 174, -207);
+end
+
+function TimeManagerAlarmAMPMDropDown_OnHide()
+ -- readjust the size of and reanchor TimeManagerAlarmAMPMDropDown and all frames below it
+ TimeManagerAlarmAMPMDropDown:SetPoint("LEFT", TimeManagerAlarmHourDropDown, "RIGHT", -22, 0);
+ TimeManagerAlarmMessageFrame:SetPoint("TOPLEFT", TimeManagerAlarmHourDropDown, "BOTTOMLEFT", 20, 0);
+ TimeManagerAlarmEnabledButton:SetPoint("CENTER", TimeManagerFrame, "CENTER", -20, -50);
+ TimeManagerMilitaryTimeCheck:SetPoint("TOPLEFT", TimeManagerFrame, "TOPLEFT", 174, -207);
+end
+
+function TimeManager_Update()
+ TimeManager_UpdateTimeTicker();
+ TimeManager_UpdateAlarmTime();
+ TimeManagerAlarmEnabledButton_Update();
+ TimeManagerAlarmMessageEditBox:SetText(Settings.alarmMessage);
+ TimeManagerMilitaryTimeCheck:SetChecked(Settings.militaryTime);
+ TimeManagerLocalTimeCheck:SetChecked(Settings.localTime);
+end
+
+function TimeManager_UpdateAlarmTime()
+ UIDropDownMenu_SetSelectedValue(TimeManagerAlarmHourDropDown, Settings.alarmHour);
+ UIDropDownMenu_SetSelectedValue(TimeManagerAlarmMinuteDropDown, Settings.alarmMinute);
+ UIDropDownMenu_SetText(TimeManagerAlarmMinuteDropDown, format(TIMEMANAGER_MINUTE, Settings.alarmMinute));
+ if ( Settings.militaryTime ) then
+ TimeManagerAlarmAMPMDropDown:Hide();
+ UIDropDownMenu_SetText(TimeManagerAlarmHourDropDown, format(TIMEMANAGER_24HOUR, Settings.alarmHour));
+ else
+ TimeManagerAlarmAMPMDropDown:Show();
+ UIDropDownMenu_SetText(TimeManagerAlarmHourDropDown, Settings.alarmHour);
+ if ( Settings.alarmAM ) then
+ UIDropDownMenu_SetSelectedValue(TimeManagerAlarmAMPMDropDown, 1);
+ UIDropDownMenu_SetText(TimeManagerAlarmAMPMDropDown, TIMEMANAGER_AM);
+ else
+ UIDropDownMenu_SetSelectedValue(TimeManagerAlarmAMPMDropDown, 0);
+ UIDropDownMenu_SetText(TimeManagerAlarmAMPMDropDown, TIMEMANAGER_PM);
+ end
+ end
+end
+
+function TimeManager_UpdateTimeTicker()
+ TimeManagerFrameTicker:SetText(GameTime_GetTime(false));
+end
+
+function TimeManagerAlarmMessageEditBox_OnEnterPressed(self)
+ self:ClearFocus();
+end
+
+function TimeManagerAlarmMessageEditBox_OnEscapePressed(self)
+ self:ClearFocus();
+end
+
+function TimeManagerAlarmMessageEditBox_OnEditFocusLost(self)
+ _TimeManager_Setting_Set(CVAR_ALARM_MESSAGE, "alarmMessage", TimeManagerAlarmMessageEditBox:GetText());
+end
+
+function TimeManagerAlarmEnabledButton_Update()
+ if ( Settings.alarmEnabled ) then
+ TimeManagerAlarmEnabledButton:SetText(TIMEMANAGER_ALARM_ENABLED);
+ TimeManagerAlarmEnabledButton:SetNormalFontObject(GameFontNormal);
+ TimeManagerAlarmEnabledButton:SetNormalTexture("Interface\\Buttons\\UI-Panel-Button-Up");
+ TimeManagerAlarmEnabledButton:SetPushedTexture("Interface\\Buttons\\UI-Panel-Button-Down");
+ else
+ TimeManagerAlarmEnabledButton:SetText(TIMEMANAGER_ALARM_DISABLED);
+ TimeManagerAlarmEnabledButton:SetNormalFontObject(GameFontHighlight);
+ TimeManagerAlarmEnabledButton:SetNormalTexture("Interface\\Buttons\\UI-Panel-Button-Disabled");
+ TimeManagerAlarmEnabledButton:SetPushedTexture("Interface\\Buttons\\UI-Panel-Button-Disabled-Down");
+ end
+end
+
+function TimeManagerAlarmEnabledButton_OnClick(self)
+ _TimeManager_Setting_SetBool(CVAR_ALARM_ENABLED, "alarmEnabled", not Settings.alarmEnabled);
+ if ( Settings.alarmEnabled ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ TimeManager_StartCheckingAlarm();
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ if ( TimeManagerClockButton.alarmFiring ) then
+ TimeManager_TurnOffAlarm();
+ end
+ end
+ TimeManagerAlarmEnabledButton_Update();
+end
+
+function TimeManagerMilitaryTimeCheck_OnClick(self)
+ TimeManager_ToggleTimeFormat();
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+end
+
+function TimeManager_ToggleTimeFormat()
+ local alarmHour = Settings.alarmHour;
+ if ( Settings.militaryTime ) then
+ _TimeManager_Setting_SetBool(CVAR_USE_MILITARY_TIME, "militaryTime", false);
+ Settings.alarmHour, Settings.alarmAM = GameTime_ComputeStandardTime(Settings.alarmHour);
+ else
+ _TimeManager_Setting_SetBool(CVAR_USE_MILITARY_TIME, "militaryTime", true);
+ Settings.alarmHour = GameTime_ComputeMilitaryTime(Settings.alarmHour, Settings.alarmAM);
+ end
+ _TimeManager_Setting_SetTime();
+ TimeManager_UpdateAlarmTime();
+ -- TimeManagerFrame_OnUpdate will pick up the time ticker change
+ -- TimeManagerClockButton_OnUpdate will pick up the clock change
+ if ( CalendarFrame_UpdateTimeFormat ) then
+ -- update the Calendar's time format if it's available
+ CalendarFrame_UpdateTimeFormat();
+ end
+end
+
+function TimeManagerLocalTimeCheck_OnClick(self)
+ TimeManager_ToggleLocalTime();
+ -- since we're changing which time type we're checking, we need to check the alarm now
+ TimeManager_StartCheckingAlarm();
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+end
+
+function TimeManager_ToggleLocalTime()
+ _TimeManager_Setting_SetBool(CVAR_USE_LOCAL_TIME, "localTime", not Settings.localTime);
+ -- TimeManagerFrame_OnUpdate will pick up the time ticker change
+ -- TimeManagerClockButton_OnUpdate will pick up the clock change
+end
+
+-- TimeManagerClockButton
+
+function TimeManagerClockButton_Show()
+ TimeManagerClockButton:Show();
+end
+
+function TimeManagerClockButton_Hide()
+ TimeManagerClockButton:Hide();
+end
+
+function TimeManagerClockButton_OnLoad(self)
+ self:SetFrameLevel(self:GetFrameLevel() + 2);
+ TimeManagerClockButton_Update();
+ if ( Settings.alarmEnabled ) then
+ TimeManager_StartCheckingAlarm();
+ end
+ self:RegisterForClicks("AnyUp");
+end
+
+function TimeManagerClockButton_Update()
+ TimeManagerClockTicker:SetText(GameTime_GetTime(false));
+end
+
+function TimeManagerClockButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ TimeManagerClockButton:SetScript("OnUpdate", TimeManagerClockButton_OnUpdateWithTooltip);
+end
+
+function TimeManagerClockButton_OnLeave(self)
+ GameTooltip:Hide();
+ TimeManagerClockButton:SetScript("OnUpdate", TimeManagerClockButton_OnUpdate);
+end
+
+function TimeManagerClockButton_OnClick(self)
+ if ( self.alarmFiring ) then
+ PlaySound("igMainMenuQuit");
+ TimeManager_TurnOffAlarm();
+ else
+ TimeManager_Toggle();
+ end
+end
+
+function TimeManagerClockButton_OnUpdate(self, elapsed)
+ TimeManagerClockButton_Update();
+ if ( self.checkAlarm and Settings.alarmEnabled ) then
+ TimeManager_CheckAlarm(elapsed);
+ end
+end
+
+function TimeManagerClockButton_OnUpdateWithTooltip(self, elapsed)
+ TimeManagerClockButton_OnUpdate(self, elapsed);
+ TimeManagerClockButton_UpdateTooltip();
+end
+
+function TimeManager_ShouldCheckAlarm()
+ return TimeManagerClockButton.checkAlarm and Settings.alarmEnabled;
+end
+
+function TimeManager_StartCheckingAlarm()
+ TimeManagerClockButton.checkAlarm = true;
+
+ -- set the time to play the warning sound
+ local alarmTime = GameTime_ComputeMinutes(Settings.alarmHour, Settings.alarmMinute, Settings.militaryTime, Settings.alarmAM);
+ local warningTime = alarmTime + WARNING_SOUND_TRIGGER_OFFSET;
+ -- max minutes per day = 24*60 = 1440
+ if ( warningTime < 0 ) then
+ warningTime = warningTime + 1440;
+ elseif ( warningTime > 1440 ) then
+ warningTime = warningTime - 1440;
+ end
+ TimeManagerClockButton.warningTime = warningTime;
+ TimeManagerClockButton.checkAlarmWarning = true;
+ -- since game time isn't available in seconds, we have to keep track of the previous minute
+ -- in order to play our alarm warning sound at the right time
+ TimeManagerClockButton.currentMinute = _TimeManager_GetCurrentMinutes(Settings.localTime);
+ TimeManagerClockButton.currentMinuteCounter = 0;
+end
+
+function TimeManager_CheckAlarm(elapsed)
+ local currTime = _TimeManager_GetCurrentMinutes(Settings.localTime);
+ local alarmTime = GameTime_ComputeMinutes(Settings.alarmHour, Settings.alarmMinute, Settings.militaryTime, Settings.alarmAM);
+
+ -- check for the warning sound
+ local clockButton = TimeManagerClockButton;
+ if ( clockButton.checkAlarmWarning ) then
+ if ( clockButton.currentMinute ~= currTime ) then
+ clockButton.currentMinute = currTime;
+ clockButton.currentMinuteCounter = 0;
+ end
+ local secOffset = floor(clockButton.currentMinuteCounter) * SEC_TO_MINUTE_FACTOR;
+ if ( (currTime + secOffset) == clockButton.warningTime ) then
+ TimeManager_FireAlarmWarning();
+ end
+ clockButton.currentMinuteCounter = clockButton.currentMinuteCounter + elapsed;
+ end
+ -- check for the alarm sound
+ if ( currTime == alarmTime ) then
+ TimeManager_FireAlarm();
+ end
+end
+
+function TimeManager_FireAlarmWarning()
+ TimeManagerClockButton.checkAlarmWarning = false;
+
+ PlaySound("AlarmClockWarning1");
+end
+
+function TimeManager_FireAlarm()
+ TimeManagerClockButton.alarmFiring = true;
+ TimeManagerClockButton.checkAlarm = false;
+
+ -- do a bunch of crazy stuff to get the player's attention
+ if ( gsub(Settings.alarmMessage, "%s", "") ~= "" ) then
+ local info = ChatTypeInfo["SYSTEM"];
+ DEFAULT_CHAT_FRAME:AddMessage(Settings.alarmMessage, info.r, info.g, info.b, info.id);
+ RaidNotice_AddMessage(RaidWarningFrame, Settings.alarmMessage, ChatTypeInfo["RAID_WARNING"]);
+ end
+ PlaySound("AlarmClockWarning2");
+ UIFrameFlash(TimeManagerAlarmFiredTexture, 0.5, 0.5, -1);
+ -- show the clock if necessary, but record its current state so it can return to that state after
+ -- the player turns the alarm off
+ TimeManagerClockButton.prevShown = TimeManagerClockButton:IsShown();
+ TimeManagerClockButton:Show();
+end
+
+function TimeManager_TurnOffAlarm()
+ UIFrameFlashStop(TimeManagerAlarmFiredTexture);
+ if ( not TimeManagerClockButton.prevShown ) then
+ TimeManagerClockButton:Hide();
+ end
+
+ TimeManagerClockButton.alarmFiring = false;
+end
+
+function TimeManager_IsAlarmFiring()
+ return TimeManagerClockButton.alarmFiring;
+end
+
+function TimeManagerClockButton_UpdateTooltip()
+ GameTooltip:ClearLines();
+
+ if ( TimeManagerClockButton.alarmFiring ) then
+ if ( gsub(Settings.alarmMessage, "%s", "") ~= "" ) then
+ GameTooltip:AddLine(Settings.alarmMessage, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, 1);
+ GameTooltip:AddLine(" ");
+ end
+ GameTooltip:AddLine(TIMEMANAGER_ALARM_TOOLTIP_TURN_OFF);
+ else
+ GameTime_UpdateTooltip();
+ GameTooltip:AddLine(" ");
+ GameTooltip:AddLine(GAMETIME_TOOLTIP_TOGGLE_CLOCK);
+ end
+
+ -- readjust tooltip size
+ GameTooltip:Show();
+end
+
+-- StopwatchFrame
+
+function Stopwatch_Toggle()
+ if ( StopwatchFrame:IsShown() ) then
+ StopwatchFrame:Hide();
+ else
+ StopwatchFrame:Show();
+ end
+end
+
+function Stopwatch_StartCountdown(hour, minute, second)
+ local sec = 0;
+ if ( hour ) then
+ sec = hour * 3600;
+ end
+ if ( minute ) then
+ sec = sec + minute * 60;
+ end
+ if ( second ) then
+ sec = sec + second;
+ end
+ if ( sec == 0 ) then
+ Stopwatch_Toggle();
+ return;
+ end
+ if ( sec > MAX_TIMER_SEC ) then
+ StopwatchTicker.timer = MAX_TIMER_SEC;
+ elseif ( sec < 0 ) then
+ StopwatchTicker.timer = 0;
+ else
+ StopwatchTicker.timer = sec;
+ end
+ StopwatchTicker_Update();
+ StopwatchTicker.reverse = sec > 0;
+ StopwatchFrame:Show();
+end
+
+function Stopwatch_Play()
+ if ( StopwatchPlayPauseButton.playing ) then
+ return;
+ end
+ StopwatchPlayPauseButton.playing = true;
+ StopwatchTicker:SetScript("OnUpdate", StopwatchTicker_OnUpdate);
+ StopwatchPlayPauseButton:SetNormalTexture("Interface\\TimeManager\\PauseButton");
+end
+
+function Stopwatch_Pause()
+ if ( not StopwatchPlayPauseButton.playing ) then
+ return;
+ end
+ StopwatchPlayPauseButton.playing = false;
+ StopwatchTicker:SetScript("OnUpdate", nil);
+ StopwatchPlayPauseButton:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up");
+end
+
+function Stopwatch_IsPlaying()
+ return StopwatchPlayPauseButton.playing;
+end
+
+function Stopwatch_Clear()
+ StopwatchTicker.timer = 0;
+ StopwatchTicker.reverse = false;
+ StopwatchTicker:SetScript("OnUpdate", nil);
+ StopwatchTicker_Update();
+ StopwatchPlayPauseButton.playing = false;
+ StopwatchPlayPauseButton:SetNormalTexture("Interface\\Buttons\\UI-SpellbookIcon-NextPage-Up");
+end
+
+function Stopwatch_FinishCountdown()
+ Stopwatch_Clear();
+ PlaySound("AlarmClockWarning3");
+end
+
+function StopwatchCloseButton_OnClick()
+ PlaySound("igMainMenuQuit");
+ StopwatchFrame:Hide();
+end
+
+function StopwatchFrame_OnLoad(self)
+ self:RegisterEvent("ADDON_LOADED");
+ self:RegisterEvent("PLAYER_LOGOUT");
+ self:RegisterForDrag("LeftButton");
+ StopwatchTabFrame:SetAlpha(0);
+ Stopwatch_Clear();
+end
+
+function StopwatchFrame_OnEvent(self, event, ...)
+ if ( event == "ADDON_LOADED" ) then
+ local name = ...;
+ if ( name == "Blizzard_TimeManager" ) then
+ if ( not BlizzardStopwatchOptions ) then
+ BlizzardStopwatchOptions = {};
+ end
+
+ if ( BlizzardStopwatchOptions.position ) then
+ StopwatchFrame:ClearAllPoints();
+ StopwatchFrame:SetPoint("CENTER", "UIParent", "BOTTOMLEFT", BlizzardStopwatchOptions.position.x, BlizzardStopwatchOptions.position.y);
+ StopwatchFrame:SetUserPlaced(true);
+ else
+ StopwatchFrame:SetPoint("TOPRIGHT", "UIParent", "TOPRIGHT", -250, -300);
+ end
+ end
+ elseif ( event == "PLAYER_LOGOUT" ) then
+ if ( StopwatchFrame:IsUserPlaced() ) then
+ if ( not BlizzardStopwatchOptions.position ) then
+ BlizzardStopwatchOptions.position = {};
+ end
+ BlizzardStopwatchOptions.position.x, BlizzardStopwatchOptions.position.y = StopwatchFrame:GetCenter();
+ StopwatchFrame:SetUserPlaced(false);
+ else
+ BlizzardStopwatchOptions.position = nil;
+ end
+ end
+end
+
+function StopwatchFrame_OnUpdate(self)
+ if ( self.prevMouseIsOver ) then
+ if ( not self:IsMouseOver() ) then
+ UIFrameFadeOut(StopwatchTabFrame, CHAT_FRAME_FADE_TIME);
+ self.prevMouseIsOver = false;
+ end
+ else
+ if ( self:IsMouseOver() ) then
+ UIFrameFadeIn(StopwatchTabFrame, CHAT_FRAME_FADE_TIME);
+ self.prevMouseIsOver = true;
+ end
+ end
+end
+
+function StopwatchFrame_OnShow(self)
+ TimeManagerStopwatchCheck:SetChecked(1);
+end
+
+function StopwatchFrame_OnHide(self)
+ UIFrameFadeRemoveFrame(StopwatchTabFrame);
+ StopwatchTabFrame:SetAlpha(0);
+ self.prevMouseIsOver = false;
+ TimeManagerStopwatchCheck:SetChecked(nil);
+end
+
+function StopwatchFrame_OnMouseDown(self)
+ self:SetScript("OnUpdate", nil);
+end
+
+function StopwatchFrame_OnMouseUp(self)
+ self:SetScript("OnUpdate", StopwatchFrame_OnUpdate);
+end
+
+function StopwatchFrame_OnDragStart(self)
+ self:StartMoving();
+end
+
+function StopwatchFrame_OnDragStop(self)
+ StopwatchFrame_OnMouseUp(self); -- OnMouseUp won't fire if OnDragStart fired after OnMouseDown
+ self:StopMovingOrSizing();
+end
+
+function StopwatchTicker_OnUpdate(self, elapsed)
+ if ( self.reverse ) then
+ self.timer = self.timer - elapsed;
+ if ( self.timer <= 0 ) then
+ Stopwatch_FinishCountdown();
+ return;
+ end
+ else
+ self.timer = self.timer + elapsed;
+ end
+ StopwatchTicker_Update();
+end
+
+function StopwatchTicker_Update()
+ local timer = StopwatchTicker.timer;
+ local hour = min(floor(timer*SEC_TO_HOUR_FACTOR), 99);
+ local minute = mod(timer*SEC_TO_MINUTE_FACTOR, 60);
+ local second = mod(timer, 60);
+ StopwatchTickerHour:SetFormattedText(STOPWATCH_TIME_UNIT, hour);
+ StopwatchTickerMinute:SetFormattedText(STOPWATCH_TIME_UNIT, minute);
+ StopwatchTickerSecond:SetFormattedText(STOPWATCH_TIME_UNIT, second);
+end
+
+function StopwatchResetButton_OnClick()
+ Stopwatch_Clear();
+ PlaySound("igMainMenuOptionCheckBoxOff");
+end
+
+function StopwatchPlayPauseButton_OnClick(self)
+ if ( self.playing ) then
+ Stopwatch_Pause();
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ else
+ Stopwatch_Play();
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+end
+
diff --git a/reference/AddOns/Blizzard_TimeManager/Blizzard_TimeManager.toc b/reference/AddOns/Blizzard_TimeManager/Blizzard_TimeManager.toc
new file mode 100644
index 0000000..784ace8
--- /dev/null
+++ b/reference/AddOns/Blizzard_TimeManager/Blizzard_TimeManager.toc
@@ -0,0 +1,7 @@
+## Interface: 30300
+## Title: Blizzard Time Manager
+## Secure: 1
+## LoadOnDemand: 1
+## SavedVariablesPerCharacter: BlizzardStopwatchOptions
+Blizzard_TimeManager.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_TimeManager/Blizzard_TimeManager.xml b/reference/AddOns/Blizzard_TimeManager/Blizzard_TimeManager.xml
new file mode 100644
index 0000000..abfc786
--- /dev/null
+++ b/reference/AddOns/Blizzard_TimeManager/Blizzard_TimeManager.xml
@@ -0,0 +1,503 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(TIMEMANAGER_24HOURMODE);
+ TimeManagerMilitaryTimeCheckText:ClearAllPoints();
+ TimeManagerMilitaryTimeCheckText:SetPoint("RIGHT", self, "RIGHT", -self:GetWidth(), 0);
+ TimeManagerMilitaryTimeCheckText:SetFontObject(GameFontHighlightSmall);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(TIMEMANAGER_LOCALTIME);
+ TimeManagerLocalTimeCheckText:ClearAllPoints();
+ TimeManagerLocalTimeCheckText:SetPoint("RIGHT", self, "RIGHT", -self:GetWidth(), 0);
+ TimeManagerLocalTimeCheckText:SetFontObject(GameFontHighlightSmall);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_STOPWATCH_RESETBUTTON, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, nil, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_STOPWATCH_PLAYPAUSEBUTTON, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_TimeManager/Localization.lua b/reference/AddOns/Blizzard_TimeManager/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_TimeManager/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_TokenUI/Blizzard_TokenUI.lua b/reference/AddOns/Blizzard_TokenUI/Blizzard_TokenUI.lua
new file mode 100644
index 0000000..b66db06
--- /dev/null
+++ b/reference/AddOns/Blizzard_TokenUI/Blizzard_TokenUI.lua
@@ -0,0 +1,313 @@
+UIPanelWindows["TokenFrame"] = { area = "left", pushable = 1, whileDead = 1 };
+TOKEN_BUTTON_OFFSET = 3;
+MAX_WATCHED_TOKENS = 3;
+BACKPACK_TOKENFRAME_HEIGHT = 22;
+
+-- REMOVE ME!!!
+SlashCmdList["TOKENUI"] = function() ToggleCharacter("TokenFrame"); end;
+
+function TokenButton_OnLoad(self)
+ local name = self:GetName();
+ self.count = _G[name.."Count"];
+ self.name = _G[name.."Name"];
+ self.icon = _G[name.."Icon"];
+ self.check = _G[name.."Check"];
+ self.expandIcon = _G[name.."ExpandIcon"];
+ self.categoryLeft = _G[name.."CategoryLeft"];
+ self.categoryRight = _G[name.."CategoryRight"];
+ self.highlight = _G[name.."Highlight"];
+ self.stripe = _G[name.."Stripe"];
+end
+
+function TokenFrame_OnLoad()
+ TokenFrameContainerScrollBar.Show =
+ function (self)
+ TokenFrameContainer:SetWidth(299);
+ for _, button in next, _G["TokenFrameContainer"].buttons do
+ button:SetWidth(295);
+ end
+ getmetatable(self).__index.Show(self);
+ end
+
+ TokenFrameContainerScrollBar.Hide =
+ function (self)
+ TokenFrameContainer:SetWidth(313);
+ for _, button in next, TokenFrameContainer.buttons do
+ button:SetWidth(313);
+ end
+ getmetatable(self).__index.Hide(self);
+ end
+ TokenFrameContainer.update = TokenFrame_Update;
+ HybridScrollFrame_CreateButtons(TokenFrameContainer, "TokenButtonTemplate", 0, -2, "TOPLEFT", "TOPLEFT", 0, -TOKEN_BUTTON_OFFSET);
+ local buttons = TokenFrameContainer.buttons;
+ local numButtons = #buttons;
+ for i=1, numButtons do
+ if ( mod(i, 2) == 1 ) then
+ buttons[i].stripe:Hide();
+ end
+ end
+end
+
+function TokenFrame_OnShow(self)
+ SetButtonPulse(CharacterFrameTab5, 0, 1); --Stop the button pulse
+ TokenFrame_Update();
+end
+
+function TokenFrame_Update()
+
+ -- Setup the buttons
+ local scrollFrame = TokenFrameContainer;
+ local offset = HybridScrollFrame_GetOffset(scrollFrame);
+ local buttons = scrollFrame.buttons;
+ local numButtons = #buttons;
+ local numTokenTypes = GetCurrencyListSize();
+ local name, isHeader, isExpanded, isUnused, isWatched, count, extraCurrencyType, icon, itemID;
+ local button, index;
+ for i=1, numButtons do
+ index = offset+i;
+ name, isHeader, isExpanded, isUnused, isWatched, count, extraCurrencyType, icon, itemID = GetCurrencyListInfo(index);
+
+ button = buttons[i];
+ button.check:Hide();
+ if ( not name or name == "" ) then
+ button:Hide();
+ else
+ if ( isHeader ) then
+ button.categoryLeft:Show();
+ button.categoryRight:Show();
+ button.expandIcon:Show();
+ button.count:SetText("");
+ button.icon:SetTexture("");
+ if ( isExpanded ) then
+ button.expandIcon:SetTexCoord(0.5625, 1, 0, 0.4375);
+ else
+ button.expandIcon:SetTexCoord(0, 0.4375, 0, 0.4375);
+ end
+ button.highlight:SetTexture("Interface\\TokenFrame\\UI-TokenFrame-CategoryButton");
+ button.highlight:SetPoint("TOPLEFT", button, "TOPLEFT", 3, -2);
+ button.highlight:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", -3, 2);
+ button:SetText(name);
+ button.name:SetText("");
+ button.itemID = nil;
+ button.LinkButton:Hide();
+ else
+ button.categoryLeft:Hide();
+ button.categoryRight:Hide();
+ button.expandIcon:Hide();
+ button.count:SetText(count);
+ button.extraCurrencyType = extraCurrencyType;
+ if ( extraCurrencyType == 1 ) then --Arena points
+ button.icon:SetTexture("Interface\\PVPFrame\\PVP-ArenaPoints-Icon");
+ button.icon:SetTexCoord(0, 1, 0, 1);
+ elseif ( extraCurrencyType == 2 ) then --Honor points
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ button.icon:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..factionGroup);
+ button.icon:SetTexCoord( 0.03125, 0.59375, 0.03125, 0.59375 );
+ else
+ button.icon:Hide() --We don't know their faction yet!
+ button.icon:SetTexCoord(0, 1, 0, 1);
+ end
+ else
+ button.icon:SetTexture(icon);
+ button.icon:SetTexCoord(0, 1, 0, 1);
+ end
+ if ( isWatched ) then
+ button.check:Show();
+ end
+ button.highlight:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight");
+ button.highlight:SetPoint("TOPLEFT", button, "TOPLEFT", 0, 0);
+ button.highlight:SetPoint("BOTTOMRIGHT", button, "BOTTOMRIGHT", 0, 0);
+ --Gray out the text if the count is 0
+ if ( count == 0 ) then
+ button.count:SetFontObject("GameFontDisable");
+ button.name:SetFontObject("GameFontDisable");
+ else
+ button.count:SetFontObject("GameFontHighlight");
+ button.name:SetFontObject("GameFontHighlight");
+ end
+ button:SetText("");
+ button.name:SetText(name);
+ button.itemID = itemID;
+ button.LinkButton:Show();
+ end
+ --Manage highlight
+ if ( name == TokenFrame.selectedToken ) then
+ TokenFrame.selectedID = index;
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+
+ button.index = index;
+ button.isHeader = isHeader;
+ button.isExpanded = isExpanded;
+ button.isUnused = isUnused;
+ button.isWatched = isWatched;
+ button:Show();
+ end
+ end
+ local totalHeight = numTokenTypes * (button:GetHeight()+TOKEN_BUTTON_OFFSET);
+ local displayedHeight = #buttons * (button:GetHeight()+TOKEN_BUTTON_OFFSET);
+
+ HybridScrollFrame_Update(scrollFrame, totalHeight, displayedHeight);
+
+ if ( numTokenTypes == 0 ) then
+ CharacterFrameTab5:Hide();
+ else
+ CharacterFrameTab5:Show();
+ end
+end
+
+function TokenFramePopup_CloseIfHidden()
+ -- This handles the case where you close a category with the selected token popup shown
+ local numTokenTypes = GetCurrencyListSize();
+ local selectedFound;
+ for i=1, numTokenTypes do
+ if ( TokenFrame.selectedToken == GetCurrencyListInfo(i) ) then
+ selectedFound = 1;
+ end
+ end
+ if ( not selectedFound ) then
+ TokenFramePopup:Hide();
+ end
+end
+
+function BackpackTokenFrame_Update()
+ local watchButton;
+ local name, count, extraCurrencyType, icon;
+ for i=1, MAX_WATCHED_TOKENS do
+ name, count, extraCurrencyType, icon, itemID = GetBackpackCurrencyInfo(i);
+ -- Update watched tokens
+ if ( name ) then
+ watchButton = _G["BackpackTokenFrameToken"..i];
+ watchButton.extraCurrencyType = extraCurrencyType;
+ if ( extraCurrencyType == 1 ) then --Arena points
+ watchButton.icon:SetTexture("Interface\\PVPFrame\\PVP-ArenaPoints-Icon");
+ watchButton.icon:SetTexCoord(0, 1, 0, 1);
+ elseif ( extraCurrencyType == 2 ) then --Honor points
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ watchButton.icon:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..factionGroup);
+ watchButton.icon:SetTexCoord( 0.03125, 0.59375, 0.03125, 0.59375 );
+ else
+ watchButton.icon:SetTexCoord(0, 1, 0, 1);
+ end
+ else
+ watchButton.icon:SetTexture(icon);
+ watchButton.icon:SetTexCoord(0, 1, 0, 1);
+ end
+ if ( count <= 99999 ) then
+ watchButton.count:SetText(count);
+ else
+ watchButton.count:SetText("*");
+ end
+ watchButton:Show();
+ BackpackTokenFrame.shouldShow = 1;
+ BackpackTokenFrame.numWatchedTokens = i;
+ watchButton.itemID = itemID;
+ else
+ _G["BackpackTokenFrameToken"..i]:Hide();
+ if ( i == 1 ) then
+ BackpackTokenFrame.shouldShow = nil;
+ end
+ _G["BackpackTokenFrameToken"..i].itemID = nil;
+ end
+ end
+end
+
+function GetNumWatchedTokens()
+ if ( not BackpackTokenFrame.numWatchedTokens ) then
+ -- No count yet so get it
+ BackpackTokenFrame_Update();
+ end
+ return BackpackTokenFrame.numWatchedTokens or 0;
+end
+
+function BackpackTokenFrame_IsShown()
+ return BackpackTokenFrame.shouldShow;
+end
+
+function ManageBackpackTokenFrame(backpack)
+ if ( not backpack ) then
+ backpack = GetBackpackFrame();
+ end
+ if ( not backpack ) then
+ -- If still no backpack then we don't show the frame
+ BackpackTokenFrame:Hide();
+ return;
+ end
+ if ( BackpackTokenFrame_IsShown() ) then
+ BackpackTokenFrame:SetParent(backpack);
+ BackpackTokenFrame:SetPoint("BOTTOMLEFT", backpack, "BOTTOMLEFT", 9, 0);
+ backpack:SetHeight(BACKPACK_HEIGHT+BACKPACK_TOKENFRAME_HEIGHT);
+ BackpackTokenFrame:Show();
+ else
+ backpack:SetHeight(BACKPACK_HEIGHT);
+ BackpackTokenFrame:Hide();
+ end
+end
+
+function TokenButton_OnClick(self)
+ if ( self.isHeader ) then
+ if ( self.isExpanded ) then
+ ExpandCurrencyList(self.index, 0);
+ else
+ ExpandCurrencyList(self.index, 1);
+ end
+ else
+ TokenFrame.selectedToken = self.name:GetText();
+ if ( IsModifiedClick("TOKENWATCHTOGGLE") ) then
+ TokenFrame.selectedID = self.index;
+ if ( self.isWatched ) then
+ SetCurrencyBackpack(TokenFrame.selectedID, 0);
+ self.isWatched = false;
+ else
+ -- Set an error message if trying to show too many quests
+ if ( GetNumWatchedTokens() >= MAX_WATCHED_TOKENS ) then
+ UIErrorsFrame:AddMessage(format(TOO_MANY_WATCHED_TOKENS, MAX_WATCHED_TOKENS), 1.0, 0.1, 0.1, 1.0);
+ return;
+ end
+ SetCurrencyBackpack(TokenFrame.selectedID, 1);
+ self.isWatched = true;
+ end
+ if ( TokenFrame.selectedID == self.index ) then
+ TokenFrame_UpdatePopup(self);
+ end
+ BackpackTokenFrame_Update();
+ ManageBackpackTokenFrame();
+ else
+
+ if ( TokenFramePopup:IsShown() ) then
+ if ( TokenFrame.selectedID == self.index ) then
+ TokenFramePopup:Hide();
+ else
+ TokenFramePopup:Show();
+ end
+ else
+ TokenFramePopup:Show();
+ end
+ TokenFrame.selectedID = self.index;
+ TokenFrame_UpdatePopup(self);
+ end
+ end
+ TokenFrame_Update();
+ TokenFramePopup_CloseIfHidden();
+end
+
+function TokenFrame_UpdatePopup(button)
+ TokenFramePopupInactiveCheckBox:SetChecked(button.isUnused);
+ TokenFramePopupBackpackCheckBox:SetChecked(button.isWatched);
+end
+
+function TokenButtonLinkButton_OnClick(self, button)
+ if ( IsModifiedClick("CHATLINK") ) then
+ ChatEdit_InsertLink(select(2, GetItemInfo(self:GetParent().itemID)));
+ end
+end
+
+function BackpackTokenButton_OnClick(self, button)
+ if ( IsModifiedClick("CHATLINK") ) then
+ ChatEdit_InsertLink(select(2, GetItemInfo(self.itemID)));
+ end
+end
diff --git a/reference/AddOns/Blizzard_TokenUI/Blizzard_TokenUI.toc b/reference/AddOns/Blizzard_TokenUI/Blizzard_TokenUI.toc
new file mode 100644
index 0000000..594051a
--- /dev/null
+++ b/reference/AddOns/Blizzard_TokenUI/Blizzard_TokenUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard_TokenUI
+## Secure: 1
+Blizzard_TokenUI.lua
+Blizzard_TokenUI.xml
+Localization.lua
\ No newline at end of file
diff --git a/reference/AddOns/Blizzard_TokenUI/Blizzard_TokenUI.xml b/reference/AddOns/Blizzard_TokenUI/Blizzard_TokenUI.xml
new file mode 100644
index 0000000..89fba13
--- /dev/null
+++ b/reference/AddOns/Blizzard_TokenUI/Blizzard_TokenUI.xml
@@ -0,0 +1,504 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self:GetParent().extraCurrencyType == 1 ) then
+ GameTooltip:SetText(ARENA_POINTS, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(TOOLTIP_ARENA_POINTS, nil, nil, nil, 1);
+ GameTooltip:Show();
+ elseif ( self:GetParent().extraCurrencyType == 2 ) then
+ GameTooltip:SetText(HONOR_POINTS, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(TOOLTIP_HONOR_POINTS, nil, nil, nil, 1);
+ GameTooltip:Show();
+ else
+ GameTooltip:SetCurrencyToken(self:GetParent().index);
+ end
+
+
+ GameTooltip:Hide();
+
+
+ TokenButtonLinkButton_OnClick(self, button, down);
+
+
+
+
+
+
+ TokenButton_OnLoad(self);
+
+
+ TokenButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TokenFramePopup:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(UNUSED);
+ _G[self:GetName().."Text"]:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ SetCurrencyUnused(TokenFrame.selectedID, 1);
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ SetCurrencyUnused(TokenFrame.selectedID, 0);
+ end
+ TokenFrame_Update();
+ TokenFramePopup_CloseIfHidden();
+ BackpackTokenFrame_Update();
+ ManageBackpackTokenFrame();
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(TOKEN_MOVE_TO_UNUSED, nil, nil, nil, nil, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(SHOW_ON_BACKPACK);
+ _G[self:GetName().."Text"]:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+
+
+ if ( self:GetChecked() ) then
+ if ( GetNumWatchedTokens() >= MAX_WATCHED_TOKENS ) then
+ UIErrorsFrame:AddMessage(format(TOO_MANY_WATCHED_TOKENS, MAX_WATCHED_TOKENS), 1.0, 0.1, 0.1, 1.0);
+ self:SetChecked(false);
+ return;
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ SetCurrencyBackpack(TokenFrame.selectedID, 1);
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ SetCurrencyBackpack(TokenFrame.selectedID, 0);
+ end
+ TokenFrame_Update();
+ BackpackTokenFrame_Update();
+ ManageBackpackTokenFrame();
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(TOKEN_SHOW_ON_BACKPACK, nil, nil, nil, nil, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ self.icon = _G[name.."Icon"];
+ self.count = _G[name.."Count"];
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self.extraCurrencyType == 1 ) then
+ GameTooltip:SetText(ARENA_POINTS, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(TOOLTIP_ARENA_POINTS, nil, nil, nil, 1);
+ GameTooltip:Show();
+ elseif ( self.extraCurrencyType == 2 ) then
+ GameTooltip:SetText(HONOR_POINTS, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(TOOLTIP_HONOR_POINTS, nil, nil, nil, 1);
+ GameTooltip:Show();
+ else
+ GameTooltip:SetBackpackToken(self:GetID());
+ end
+
+
+ GameTooltip:Hide();
+
+
+ BackpackTokenButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_TokenUI/Localization.lua b/reference/AddOns/Blizzard_TokenUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_TokenUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_TradeSkillUI/Blizzard_TradeSkillUI.lua b/reference/AddOns/Blizzard_TradeSkillUI/Blizzard_TradeSkillUI.lua
new file mode 100644
index 0000000..964224b
--- /dev/null
+++ b/reference/AddOns/Blizzard_TradeSkillUI/Blizzard_TradeSkillUI.lua
@@ -0,0 +1,635 @@
+
+TRADE_SKILLS_DISPLAYED = 8;
+MAX_TRADE_SKILL_REAGENTS = 8;
+TRADE_SKILL_HEIGHT = 16;
+TRADE_SKILL_TEXT_WIDTH = 275;
+
+TradeSkillTypePrefix = {
+["optimal"] = " [+++] ",
+["medium"] = " [++] ",
+["easy"] = " [+] ",
+["trivial"] = " ",
+["header"] = " ",
+}
+
+TradeSkillTypeColor = { };
+TradeSkillTypeColor["optimal"] = { r = 1.00, g = 0.50, b = 0.25, font = GameFontNormalLeftOrange };
+TradeSkillTypeColor["medium"] = { r = 1.00, g = 1.00, b = 0.00, font = GameFontNormalLeftYellow };
+TradeSkillTypeColor["easy"] = { r = 0.25, g = 0.75, b = 0.25, font = GameFontNormalLeftLightGreen };
+TradeSkillTypeColor["trivial"] = { r = 0.50, g = 0.50, b = 0.50, font = GameFontNormalLeftGrey };
+TradeSkillTypeColor["header"] = { r = 1.00, g = 0.82, b = 0, font = GameFontNormalLeft };
+
+UIPanelWindows["TradeSkillFrame"] = { area = "left", pushable = 3, showFailedFunc = "TradeSkillFrame_ShowFailed" };
+
+CURRENT_TRADESKILL = "";
+
+
+function TradeSkillFrame_Show()
+ ShowUIPanel(TradeSkillFrame);
+ TradeSkillCreateButton:Disable();
+ TradeSkillCreateAllButton:Disable();
+ if ( GetTradeSkillSelectionIndex() == 0 ) then
+ TradeSkillFrame_SetSelection(GetFirstTradeSkill());
+ else
+ TradeSkillFrame_SetSelection(GetTradeSkillSelectionIndex());
+ end
+ FauxScrollFrame_SetOffset(TradeSkillListScrollFrame, 0);
+ TradeSkillListScrollFrameScrollBar:SetMinMaxValues(0, 0);
+ TradeSkillListScrollFrameScrollBar:SetValue(0);
+ SetPortraitTexture(TradeSkillFramePortrait, "player");
+ TradeSkillOnlyShowMakeable(TradeSkillFrameAvailableFilterCheckButton:GetChecked());
+ TradeSkillFrame_Update();
+
+ -- Moved to the bottom to prevent addons which hook it from blocking tradeskills
+ CloseDropDownMenus();
+end
+
+function TradeSkillFrame_Hide()
+ HideUIPanel(TradeSkillFrame);
+end
+
+function TradeSkillFrame_ShowFailed(self)
+ CloseTradeSkill();
+end
+
+function TradeSkillFrame_OnLoad(self)
+ self:RegisterEvent("TRADE_SKILL_UPDATE");
+ self:RegisterEvent("TRADE_SKILL_FILTER_UPDATE");
+ self:RegisterEvent("UNIT_PORTRAIT_UPDATE");
+ self:RegisterEvent("UPDATE_TRADESKILL_RECAST");
+end
+
+function TradeSkillFrame_OnEvent(self, event, ...)
+ if ( not TradeSkillFrame:IsShown() ) then
+ return;
+ end
+ if ( event == "TRADE_SKILL_UPDATE" or event == "TRADE_SKILL_FILTER_UPDATE" ) then
+ TradeSkillCreateButton:Disable();
+ TradeSkillCreateAllButton:Disable();
+ if ( (event ~= "TRADE_SKILL_FILTER_UPDATE") and (GetTradeSkillSelectionIndex() > 1) and (GetTradeSkillSelectionIndex() <= GetNumTradeSkills()) ) then
+ TradeSkillFrame_SetSelection(GetTradeSkillSelectionIndex());
+ else
+ TradeSkillFrame_SetSelection(GetFirstTradeSkill());
+ FauxScrollFrame_SetOffset(TradeSkillListScrollFrame, 0);
+ TradeSkillListScrollFrameScrollBar:SetValue(0);
+ end
+ TradeSkillFrame_Update();
+ elseif ( event == "UNIT_PORTRAIT_UPDATE" ) then
+ local arg1 = ...;
+ if ( arg1 == "player" ) then
+ SetPortraitTexture(TradeSkillFramePortrait, "player");
+ end
+ elseif ( event == "UPDATE_TRADESKILL_RECAST" ) then
+ TradeSkillInputBox:SetNumber(GetTradeskillRepeatCount());
+ end
+end
+
+function TradeSkillFrame_Update()
+ local numTradeSkills = GetNumTradeSkills();
+ local skillOffset = FauxScrollFrame_GetOffset(TradeSkillListScrollFrame);
+ local name, rank, maxRank = GetTradeSkillLine();
+
+ if ( CURRENT_TRADESKILL ~= name ) then
+ StopTradeSkillRepeat();
+ if ( CURRENT_TRADESKILL ~= "" ) then
+ -- To fix problem with switching between two tradeskills
+ UIDropDownMenu_Initialize(TradeSkillInvSlotDropDown, TradeSkillInvSlotDropDown_Initialize);
+ UIDropDownMenu_SetSelectedID(TradeSkillInvSlotDropDown, 1);
+
+ UIDropDownMenu_Initialize(TradeSkillSubClassDropDown, TradeSkillSubClassDropDown_Initialize);
+ UIDropDownMenu_SetSelectedID(TradeSkillSubClassDropDown, 1);
+ end
+ CURRENT_TRADESKILL = name;
+ end
+
+ -- If no tradeskills
+ if ( numTradeSkills == 0 ) then
+ TradeSkillFrameTitleText:SetFormattedText(TRADE_SKILL_TITLE, GetTradeSkillLine());
+ TradeSkillSkillName:Hide();
+-- TradeSkillSkillLineName:Hide();
+ TradeSkillSkillIcon:Hide();
+ TradeSkillRequirementLabel:Hide();
+ TradeSkillRequirementText:SetText("");
+ TradeSkillCollapseAllButton:Disable();
+ for i=1, MAX_TRADE_SKILL_REAGENTS, 1 do
+ _G["TradeSkillReagent"..i]:Hide();
+ end
+ else
+ TradeSkillSkillName:Show();
+-- TradeSkillSkillLineName:Show();
+ TradeSkillSkillIcon:Show();
+ TradeSkillCollapseAllButton:Enable();
+ end
+
+ if ( rank < 75 ) and ( not IsTradeSkillLinked() ) then
+ TradeSkillFrameEditBox:Hide();
+ SetTradeSkillItemNameFilter(""); --In case they are switching from an inspect WITH a filter directly to their own without.
+ else
+ TradeSkillFrameEditBox:Show();
+ end
+ -- ScrollFrame update
+ FauxScrollFrame_Update(TradeSkillListScrollFrame, numTradeSkills, TRADE_SKILLS_DISPLAYED, TRADE_SKILL_HEIGHT, nil, nil, nil, TradeSkillHighlightFrame, 293, 316 );
+
+ TradeSkillHighlightFrame:Hide();
+ local skillName, skillType, numAvailable, isExpanded, altVerb;
+ local skillIndex, skillButton, skillButtonText, skillButtonCount;
+ local nameWidth, countWidth;
+
+ local skillNamePrefix = " ";
+ for i=1, TRADE_SKILLS_DISPLAYED, 1 do
+ skillIndex = i + skillOffset;
+ skillName, skillType, numAvailable, isExpanded, altVerb = GetTradeSkillInfo(skillIndex);
+ skillButton = _G["TradeSkillSkill"..i];
+ skillButtonText = _G["TradeSkillSkill"..i.."Text"];
+ skillButtonCount = _G["TradeSkillSkill"..i.."Count"];
+ if ( skillIndex <= numTradeSkills ) then
+ -- Set button widths if scrollbar is shown or hidden
+ if ( TradeSkillListScrollFrame:IsShown() ) then
+ skillButton:SetWidth(293);
+ else
+ skillButton:SetWidth(323);
+ end
+ local color = TradeSkillTypeColor[skillType];
+ if ( color ) then
+ skillButton:SetNormalFontObject(color.font);
+ skillButtonCount:SetVertexColor(color.r, color.g, color.b);
+ skillButton.r = color.r;
+ skillButton.g = color.g;
+ skillButton.b = color.b;
+ end
+
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ skillNamePrefix = TradeSkillTypePrefix[skillType] or " ";
+ end
+
+ skillButton:SetID(skillIndex);
+ skillButton:Show();
+ -- Handle headers
+ if ( skillType == "header" ) then
+ skillButton:SetText(skillName);
+ skillButtonText:SetWidth(TRADE_SKILL_TEXT_WIDTH);
+ skillButtonCount:SetText("");
+ if ( isExpanded ) then
+ skillButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
+ else
+ skillButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
+ end
+ _G["TradeSkillSkill"..i.."Highlight"]:SetTexture("Interface\\Buttons\\UI-PlusButton-Hilight");
+ _G["TradeSkillSkill"..i]:UnlockHighlight();
+ else
+ if ( not skillName ) then
+ return;
+ end
+ skillButton:SetNormalTexture("");
+ _G["TradeSkillSkill"..i.."Highlight"]:SetTexture("");
+ if ( numAvailable <= 0 ) then
+ skillButton:SetText(skillNamePrefix..skillName);
+ skillButtonText:SetWidth(TRADE_SKILL_TEXT_WIDTH);
+ skillButtonCount:SetText(skillCountPrefix);
+ else
+ skillName = skillNamePrefix..skillName;
+ skillButtonCount:SetText("["..numAvailable.."]");
+ TradeSkillFrameDummyString:SetText(skillName);
+ nameWidth = TradeSkillFrameDummyString:GetWidth();
+ countWidth = skillButtonCount:GetWidth();
+ skillButtonText:SetText(skillName);
+ if ( nameWidth + 2 + countWidth > TRADE_SKILL_TEXT_WIDTH ) then
+ skillButtonText:SetWidth(TRADE_SKILL_TEXT_WIDTH-2-countWidth);
+ else
+ skillButtonText:SetWidth(0);
+ end
+ end
+
+ -- Place the highlight and lock the highlight state
+ if ( GetTradeSkillSelectionIndex() == skillIndex ) then
+ TradeSkillHighlightFrame:SetPoint("TOPLEFT", "TradeSkillSkill"..i, "TOPLEFT", 0, 0);
+ TradeSkillHighlightFrame:Show();
+ skillButtonCount:SetVertexColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ skillButton:LockHighlight();
+ skillButton.isHighlighted = true;
+ else
+ skillButton:UnlockHighlight();
+ skillButton.isHighlighted = false;
+ end
+ end
+
+ else
+ skillButton:Hide();
+ end
+ end
+
+ -- Set the expand/collapse all button texture
+ local numHeaders = 0;
+ local notExpanded = 0;
+ for i=1, numTradeSkills, 1 do
+ local skillName, skillType, numAvailable, isExpanded, altVerb = GetTradeSkillInfo(i);
+ if ( skillName and skillType == "header" ) then
+ numHeaders = numHeaders + 1;
+ if ( not isExpanded ) then
+ notExpanded = notExpanded + 1;
+ end
+ end
+ if ( GetTradeSkillSelectionIndex() == i ) then
+ -- Set the max makeable items for the create all button
+ TradeSkillFrame.numAvailable = math.abs(numAvailable);
+ end
+ end
+ -- If all headers are not expanded then show collapse button, otherwise show the expand button
+ if ( notExpanded ~= numHeaders ) then
+ TradeSkillCollapseAllButton.collapsed = nil;
+ TradeSkillCollapseAllButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
+ else
+ TradeSkillCollapseAllButton.collapsed = 1;
+ TradeSkillCollapseAllButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
+ end
+end
+
+function TradeSkillFrame_SetSelection(id)
+ local skillName, skillType, numAvailable, isExpanded, altVerb = GetTradeSkillInfo(id);
+ local creatable = 1;
+ if ( not skillName ) then
+ creatable = nil;
+ end
+ TradeSkillHighlightFrame:Show();
+ if ( skillType == "header" ) then
+ TradeSkillHighlightFrame:Hide();
+ if ( isExpanded ) then
+ CollapseTradeSkillSubClass(id);
+ else
+ ExpandTradeSkillSubClass(id);
+ end
+ return;
+ end
+ TradeSkillFrame.selectedSkill = id;
+ SelectTradeSkill(id);
+ if ( GetTradeSkillSelectionIndex() > GetNumTradeSkills() ) then
+ return;
+ end
+ local color = TradeSkillTypeColor[skillType];
+ if ( color ) then
+ TradeSkillHighlight:SetVertexColor(color.r, color.g, color.b);
+ end
+
+ -- General Info
+ local skillLineName, skillLineRank, skillLineMaxRank = GetTradeSkillLine();
+ TradeSkillFrameTitleText:SetFormattedText(TRADE_SKILL_TITLE, skillLineName);
+ -- Set statusbar info
+ TradeSkillRankFrame:SetStatusBarColor(0.0, 0.0, 1.0, 0.5);
+ TradeSkillRankFrameBackground:SetVertexColor(0.0, 0.0, 0.75, 0.5);
+ TradeSkillRankFrame:SetMinMaxValues(0, skillLineMaxRank);
+ TradeSkillRankFrame:SetValue(skillLineRank);
+ TradeSkillRankFrameSkillRank:SetText(skillLineRank.."/"..skillLineMaxRank);
+
+ TradeSkillSkillName:SetText(skillName);
+ if ( GetTradeSkillCooldown(id) ) then
+ TradeSkillSkillCooldown:SetText(COOLDOWN_REMAINING.." "..SecondsToTime(GetTradeSkillCooldown(id)));
+ else
+ TradeSkillSkillCooldown:SetText("");
+ end
+ TradeSkillSkillIcon:SetNormalTexture(GetTradeSkillIcon(id));
+ local minMade,maxMade = GetTradeSkillNumMade(id);
+ if ( maxMade > 1 ) then
+ if ( minMade == maxMade ) then
+ TradeSkillSkillIconCount:SetText(minMade);
+ else
+ TradeSkillSkillIconCount:SetText(minMade.."-"..maxMade);
+ end
+ if ( TradeSkillSkillIconCount:GetWidth() > 39 ) then
+ TradeSkillSkillIconCount:SetText("~"..floor((minMade + maxMade)/2));
+ end
+ else
+ TradeSkillSkillIconCount:SetText("");
+ end
+
+ -- Reagents
+
+ local numReagents = GetTradeSkillNumReagents(id);
+ if(numReagents > 0) then
+ TradeSkillReagentLabel:Show();
+ else
+ TradeSkillReagentLabel:Hide();
+ end
+ for i=1, numReagents, 1 do
+ local reagentName, reagentTexture, reagentCount, playerReagentCount = GetTradeSkillReagentInfo(id, i);
+ local reagent = _G["TradeSkillReagent"..i]
+ local name = _G["TradeSkillReagent"..i.."Name"];
+ local count = _G["TradeSkillReagent"..i.."Count"];
+ if ( not reagentName or not reagentTexture ) then
+ reagent:Hide();
+ else
+ reagent:Show();
+ SetItemButtonTexture(reagent, reagentTexture);
+ name:SetText(reagentName);
+ -- Grayout items
+ if ( playerReagentCount < reagentCount ) then
+ SetItemButtonTextureVertexColor(reagent, 0.5, 0.5, 0.5);
+ name:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ creatable = nil;
+ else
+ SetItemButtonTextureVertexColor(reagent, 1.0, 1.0, 1.0);
+ name:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ end
+ if ( playerReagentCount >= 100 ) then
+ playerReagentCount = "*";
+ end
+ count:SetText(playerReagentCount.." /"..reagentCount);
+ end
+ end
+ -- Place reagent label
+ local reagentToAnchorTo = numReagents;
+ if ( (numReagents > 0) and (mod(numReagents, 2) == 0) ) then
+ reagentToAnchorTo = reagentToAnchorTo - 1;
+ end
+
+ for i=numReagents + 1, MAX_TRADE_SKILL_REAGENTS, 1 do
+ _G["TradeSkillReagent"..i]:Hide();
+ end
+
+ local spellFocus = BuildColoredListString(GetTradeSkillTools(id));
+ if ( spellFocus ) then
+ TradeSkillRequirementLabel:Show();
+ TradeSkillRequirementText:SetText(spellFocus);
+ else
+ TradeSkillRequirementLabel:Hide();
+ TradeSkillRequirementText:SetText("");
+ end
+
+ if ( creatable ) then
+ TradeSkillCreateButton:Enable();
+ TradeSkillCreateAllButton:Enable();
+ else
+ TradeSkillCreateButton:Disable();
+ TradeSkillCreateAllButton:Disable();
+ end
+
+ if ( GetTradeSkillDescription(id) ) then
+ TradeSkillDescription:SetText(GetTradeSkillDescription(id))
+ TradeSkillReagentLabel:SetPoint("TOPLEFT", "TradeSkillDescription", "BOTTOMLEFT", 0, -10);
+ else
+ TradeSkillDescription:SetText(" ");
+ TradeSkillReagentLabel:SetPoint("TOPLEFT", "TradeSkillDescription", "TOPLEFT", 0, 0);
+ end
+ -- Reset the number of items to be created
+ TradeSkillInputBox:SetNumber(GetTradeskillRepeatCount());
+
+ --Hide inapplicable buttons if we are inspecting. Otherwise show them
+ if ( IsTradeSkillLinked() ) then
+ TradeSkillCreateButton:Hide();
+ TradeSkillCreateAllButton:Hide();
+ TradeSkillDecrementButton:Hide();
+ TradeSkillInputBox:Hide();
+ TradeSkillIncrementButton:Hide();
+ TradeSkillLinkButton:Hide();
+ TradeSkillFrameBottomLeftTexture:SetTexture([[Interface\PaperDollInfoFrame\SkillFrame-BotLeft]]);
+ TradeSkillFrameBottomRightTexture:SetTexture([[Interface\PaperDollInfoFrame\SkillFrame-BotRight]]);
+ else
+ --Change button names and show/hide them depending on if this tradeskill creates an item or casts something
+ if ( not altVerb ) then
+ --Its an item with 'Create'
+ TradeSkillCreateAllButton:Show();
+ TradeSkillDecrementButton:Show();
+ TradeSkillInputBox:Show();
+ TradeSkillIncrementButton:Show();
+
+ TradeSkillFrameBottomLeftTexture:SetTexture([[Interface\TradeSkillFrame\UI-TradeSkill-BotLeft]]);
+ TradeSkillFrameBottomRightTexture:SetTexture([[Interface\ClassTrainerFrame\UI-ClassTrainer-BotRight]])
+ else
+ --Its something else
+ TradeSkillCreateAllButton:Hide();
+ TradeSkillDecrementButton:Hide();
+ TradeSkillInputBox:Hide();
+ TradeSkillIncrementButton:Hide();
+
+ TradeSkillFrameBottomLeftTexture:SetTexture([[Interface\ClassTrainerFrame\UI-ClassTrainer-BotLeft]]);
+ TradeSkillFrameBottomRightTexture:SetTexture([[Interface\ClassTrainerFrame\UI-ClassTrainer-BotRight]]);
+ end
+ if ( GetTradeSkillListLink() ) then
+ TradeSkillLinkButton:Show();
+ else
+ TradeSkillLinkButton:Hide();
+ end
+ TradeSkillCreateButton:SetText(altVerb or CREATE);
+ TradeSkillCreateButton:Show();
+ end
+end
+
+function TradeSkillSkillButton_OnClick(self, button)
+ if ( button == "LeftButton" ) then
+ TradeSkillFrame_SetSelection(self:GetID());
+ TradeSkillFrame_Update();
+ end
+end
+
+function TradeSkillFilter_OnTextChanged(self)
+ local text = self:GetText();
+
+ if ( text == SEARCH ) then
+ SetTradeSkillItemNameFilter("");
+ return;
+ end
+
+ local minLevel, maxLevel;
+ local approxLevel = strmatch(text, "^~(%d+)");
+ if ( approxLevel ) then
+ minLevel = approxLevel - 2;
+ maxLevel = approxLevel + 2;
+ else
+ minLevel, maxLevel = strmatch(text, "^(%d+)%s*-*%s*(%d*)$");
+ end
+ if ( minLevel ) then
+ if ( maxLevel == "" or maxLevel < minLevel ) then
+ maxLevel = minLevel;
+ end
+ SetTradeSkillItemNameFilter(nil);
+ SetTradeSkillItemLevelFilter(minLevel, maxLevel);
+ else
+ SetTradeSkillItemLevelFilter(0, 0);
+ SetTradeSkillItemNameFilter(text);
+ end
+end
+
+function TradeSkillCollapseAllButton_OnClick(self)
+ if (self.collapsed) then
+ self.collapsed = nil;
+ ExpandTradeSkillSubClass(0);
+ else
+ self.collapsed = 1;
+ TradeSkillListScrollFrameScrollBar:SetValue(0);
+ CollapseTradeSkillSubClass(0);
+ end
+end
+
+function TradeSkillSubClassDropDown_OnLoad(self)
+ SetTradeSkillSubClassFilter(0, 1, 1);
+ UIDropDownMenu_Initialize(self, TradeSkillSubClassDropDown_Initialize);
+ UIDropDownMenu_SetWidth(self, 120);
+ UIDropDownMenu_SetSelectedID(self, 1);
+end
+
+function TradeSkillSubClassDropDown_Initialize()
+ TradeSkillFilterFrame_LoadSubClasses(GetTradeSkillSubClasses());
+end
+
+function TradeSkillFilterFrame_LoadSubClasses(...)
+ local selectedID = UIDropDownMenu_GetSelectedID(TradeSkillSubClassDropDown);
+ local numSubClasses = select("#", ...);
+ local allChecked = GetTradeSkillSubClassFilter(0);
+
+ -- the first button in the list is going to be an "all subclasses" button
+ local info = UIDropDownMenu_CreateInfo();
+ info.text = ALL_SUBCLASSES;
+ info.func = TradeSkillSubClassDropDownButton_OnClick;
+ -- select this button if nothing else was selected
+ info.checked = allChecked and (selectedID == nil or selectedID == 1);
+ UIDropDownMenu_AddButton(info);
+ if ( info.checked ) then
+ UIDropDownMenu_SetText(TradeSkillSubClassDropDown, ALL_SUBCLASSES);
+ end
+
+ local checked;
+ for i=1, select("#", ...), 1 do
+ -- if there are no filters then don't check any individual subclasses
+ if ( allChecked ) then
+ checked = nil;
+ else
+ checked = GetTradeSkillSubClassFilter(i);
+ if ( checked ) then
+ UIDropDownMenu_SetText(TradeSkillSubClassDropDown, select(i, ...));
+ end
+ end
+ info.text = select(i, ...);
+ info.func = TradeSkillSubClassDropDownButton_OnClick;
+ info.checked = checked;
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function TradeSkillInvSlotDropDown_OnLoad(self)
+ SetTradeSkillInvSlotFilter(0, 1, 1);
+ UIDropDownMenu_Initialize(self, TradeSkillInvSlotDropDown_Initialize);
+ UIDropDownMenu_SetWidth(self, 120);
+ UIDropDownMenu_SetSelectedID(self, 1);
+end
+
+function TradeSkillInvSlotDropDown_Initialize()
+ TradeSkillFilterFrame_LoadInvSlots(GetTradeSkillInvSlots());
+end
+
+function TradeSkillFilterFrame_LoadInvSlots(...)
+ UIDropDownMenu_SetSelectedID(TradeSkillInvSlotDropDown, nil);
+ local allChecked = GetTradeSkillInvSlotFilter(0);
+ local info = UIDropDownMenu_CreateInfo();
+ local filterCount = select("#", ...);
+ info.text = ALL_INVENTORY_SLOTS;
+ info.func = TradeSkillInvSlotDropDownButton_OnClick;
+ info.checked = allChecked;
+ UIDropDownMenu_AddButton(info);
+ local checked;
+ for i=1, filterCount, 1 do
+ if ( allChecked and filterCount > 1 ) then
+ checked = nil;
+ UIDropDownMenu_SetText(TradeSkillInvSlotDropDown, ALL_INVENTORY_SLOTS);
+ else
+ checked = GetTradeSkillInvSlotFilter(i);
+ if ( checked ) then
+ UIDropDownMenu_SetText(TradeSkillInvSlotDropDown, select(i, ...));
+ end
+ end
+ info.text = select(i, ...);
+ info.func = TradeSkillInvSlotDropDownButton_OnClick;
+ info.checked = checked;
+
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function TradeSkillFilterFrame_InvSlotName(...)
+ for i=1, select("#", ...), 1 do
+ if ( GetTradeSkillInvSlotFilter(i) ) then
+ return select(i, ...);
+ end
+ end
+end
+
+function TradeSkillSubClassDropDownButton_OnClick(self)
+ UIDropDownMenu_SetSelectedID(TradeSkillSubClassDropDown, self:GetID());
+ SetTradeSkillSubClassFilter(self:GetID() - 1, 1, 1);
+ if ( self:GetID() ~= 1 ) then
+ if ( TradeSkillFilterFrame_InvSlotName(GetTradeSkillInvSlots()) ~= TradeSkillInvSlotDropDown.selected ) then
+ SetTradeSkillInvSlotFilter(0, 1, 1);
+ UIDropDownMenu_SetSelectedID(TradeSkillInvSlotDropDown, 1);
+ UIDropDownMenu_SetText(TradeSkillInvSlotDropDown, ALL_INVENTORY_SLOTS);
+ end
+ end
+ TradeSkillListScrollFrameScrollBar:SetValue(0);
+ FauxScrollFrame_SetOffset(TradeSkillListScrollFrame, 0);
+ TradeSkillFrame_Update();
+end
+
+function TradeSkillInvSlotDropDownButton_OnClick(self)
+ UIDropDownMenu_SetSelectedID(TradeSkillInvSlotDropDown, self:GetID());
+ SetTradeSkillInvSlotFilter(self:GetID() - 1, 1, 1);
+ TradeSkillInvSlotDropDown.selected = TradeSkillFilterFrame_InvSlotName(GetTradeSkillInvSlots());
+ TradeSkillListScrollFrameScrollBar:SetValue(0);
+ FauxScrollFrame_SetOffset(TradeSkillListScrollFrame, 0);
+ TradeSkillFrame_Update();
+end
+
+function TradeSkillFrameIncrement_OnClick()
+ if ( TradeSkillInputBox:GetNumber() < 100 ) then
+ TradeSkillInputBox:SetNumber(TradeSkillInputBox:GetNumber() + 1);
+ end
+end
+
+function TradeSkillFrameDecrement_OnClick()
+ if ( TradeSkillInputBox:GetNumber() > 0 ) then
+ TradeSkillInputBox:SetNumber(TradeSkillInputBox:GetNumber() - 1);
+ end
+end
+
+function TradeSkillItem_OnEnter(self)
+ if ( TradeSkillFrame.selectedSkill ~= 0 ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetTradeSkillItem(TradeSkillFrame.selectedSkill);
+ end
+ CursorUpdate(self);
+end
+
+function TradeSkillFrame_PlaytimeUpdate()
+ if ( PartialPlayTime() ) then
+ TradeSkillCreateButton:Disable();
+ if (not TradeSkillCreateButtonMask:IsShown()) then
+ TradeSkillCreateButtonMask:Show();
+ TradeSkillCreateButtonMask.tooltip = format(PLAYTIME_TIRED_ABILITY, REQUIRED_REST_HOURS - floor(GetBillingTimeRested()/60));
+ end
+
+ TradeSkillCreateAllButton:Disable();
+ if (not TradeSkillCreateAllButtonMask:IsShown()) then
+ TradeSkillCreateAllButtonMask:Show();
+ TradeSkillCreateAllButtonMask.tooltip = format(PLAYTIME_TIRED_ABILITY, REQUIRED_REST_HOURS - floor(GetBillingTimeRested()/60));
+ end
+ elseif ( NoPlayTime() ) then
+ TradeSkillCreateButton:Disable();
+ if (not TradeSkillCreateButtonMask:IsShown()) then
+ TradeSkillCreateButtonMask:Show();
+ TradeSkillCreateButtonMask.tooltip = format(PLAYTIME_UNHEALTHY_ABILITY, REQUIRED_REST_HOURS - floor(GetBillingTimeRested()/60));
+ end
+
+ TradeSkillCreateAllButton:Disable();
+ if (not TradeSkillCreateAllButtonMask:IsShown()) then
+ TradeSkillCreateAllButtonMask:Show();
+ TradeSkillCreateAllButtonMask.tooltip = format(PLAYTIME_UNHEALTHY_ABILITY, REQUIRED_REST_HOURS - floor(GetBillingTimeRested()/60));
+ end
+ else
+ if (TradeSkillCreateButtonMask:IsShown() or TradeSkillCreateAllButtonMask:IsShown()) then
+ TradeSkillCreateButtonMask:Hide();
+ TradeSkillCreateButtonMask.tooltip = nil;
+
+ TradeSkillCreateAllButtonMask:Hide();
+ TradeSkillCreateAllButtonMask.tooltip = nil;
+
+ TradeSkillFrame_SetSelection(TradeSkillFrame.selectedSkill);
+ TradeSkillFrame_Update()
+ end
+ end
+end
diff --git a/reference/AddOns/Blizzard_TradeSkillUI/Blizzard_TradeSkillUI.toc b/reference/AddOns/Blizzard_TradeSkillUI/Blizzard_TradeSkillUI.toc
new file mode 100644
index 0000000..b4b0e5a
--- /dev/null
+++ b/reference/AddOns/Blizzard_TradeSkillUI/Blizzard_TradeSkillUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard Trade Skill UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_TradeSkillUI.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_TradeSkillUI/Blizzard_TradeSkillUI.xml b/reference/AddOns/Blizzard_TradeSkillUI/Blizzard_TradeSkillUI.xml
new file mode 100644
index 0000000..891a4bd
--- /dev/null
+++ b/reference/AddOns/Blizzard_TradeSkillUI/Blizzard_TradeSkillUI.xml
@@ -0,0 +1,989 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsModifiedClick() ) then
+ HandleModifiedItemClick(GetTradeSkillRecipeLink(self:GetID()));
+ else
+ TradeSkillSkillButton_OnClick(self, button);
+ end
+
+
+ _G[self:GetName().."Count"]:SetPoint("LEFT", self:GetName().."Text", "RIGHT", 2, 0);
+
+
+ _G[self:GetName().."Count"]:SetVertexColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+
+
+ if ( not self.isHighlighted ) then
+ _G[self:GetName().."Count"]:SetVertexColor(self.r, self.g, self.b);
+ end
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPLEFT");
+ GameTooltip:SetTradeSkillItem(TradeSkillFrame.selectedSkill, self:GetID());
+ CursorUpdate(self);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ CursorOnUpdate(self, elapsed);
+
+
+ HandleModifiedItemClick(GetTradeSkillReagentItemLink(TradeSkillFrame.selectedSkill, self:GetID()));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local link=GetTradeSkillListLink();
+ if (not ChatEdit_InsertLink(link) ) then
+ ChatEdit_GetLastActiveWindow():Show();
+ ChatEdit_InsertLink(link);
+ end
+
+
+ GameTooltip:SetOwner(self,"ANCHOR_TOPLEFT");
+ GameTooltip:SetText(LINK_TRADESKILL_TOOLTIP, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TradeSkillFrameAvailableFilterCheckButtonText:SetText(CRAFT_IS_MAKEABLE);
+
+
+ TradeSkillOnlyShowMakeable(self:GetChecked());
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(CRAFT_IS_MAKEABLE_TOOLTIP, nil, nil, nil, nil, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("SKILL_LINES_CHANGED");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetText(SEARCH);
+
+
+
+
+
+ self:HighlightText(0, 0);
+ if ( self:GetText() == "" ) then
+ self:SetText(SEARCH);
+ end
+
+
+ self:HighlightText();
+ if ( self:GetText() == SEARCH ) then
+ self:SetText("");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName()]:SetText(ALL);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, TRADE_SKILL_HEIGHT, TradeSkillFrame_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.hasItem = 1;
+
+
+ HandleModifiedItemClick(GetTradeSkillItemLink(TradeSkillFrame.selectedSkill));
+
+
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ TradeSkillItem_OnEnter(self);
+ end
+ CursorOnUpdate(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if (self.tooltip) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+ if ( (not PartialPlayTime()) and (not NoPlayTime()) ) then
+ DoTradeSkill(TradeSkillFrame.selectedSkill, TradeSkillInputBox:GetNumber());
+ TradeSkillInputBox:ClearFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if (self.tooltip) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+ if ( (not PartialPlayTime()) and (not NoPlayTime()) ) then
+ TradeSkillInputBox:SetNumber(TradeSkillFrame.numAvailable);
+ DoTradeSkill(TradeSkillFrame.selectedSkill, TradeSkillFrame.numAvailable);
+ TradeSkillInputBox:ClearFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TradeSkillFrameDecrement_OnClick();
+ TradeSkillInputBox:ClearFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetText() == "0" ) then
+ self:SetText("1");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TradeSkillFrameIncrement_OnClick();
+ TradeSkillInputBox:ClearFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TradeSkillInputBox:SetNumber(1);
+ PlaySound("igCharacterInfoOpen");
+
+
+ CloseTradeSkill();
+ PlaySound("igCharacterInfoClose");
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_TradeSkillUI/Localization.lua b/reference/AddOns/Blizzard_TradeSkillUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_TradeSkillUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.lua b/reference/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.lua
new file mode 100644
index 0000000..8e77612
--- /dev/null
+++ b/reference/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.lua
@@ -0,0 +1,503 @@
+
+CLASS_TRAINER_SKILLS_DISPLAYED = 11;
+CLASS_TRAINER_SKILL_SUBTEXT_WIDTH = 210
+CLASS_TRAINER_SKILL_NOSUBTEXT_WIDTH = 270
+CLASS_TRAINER_SKILL_HEIGHT = 16;
+MAX_LEARNABLE_PROFESSIONS = 2;
+
+-- Trainer Filter Default Values
+TRAINER_FILTER_AVAILABLE = 1;
+TRAINER_FILTER_UNAVAILABLE = 1;
+TRAINER_FILTER_USED = 0;
+
+
+UIPanelWindows["ClassTrainerFrame"] = { area = "left", pushable = 0 };
+
+StaticPopupDialogs["CONFIRM_PROFESSION"] = {
+ text = format(PROFESSION_CONFIRMATION1, "XXX"),
+ button1 = ACCEPT,
+ button2 = CANCEL,
+ OnAccept = function(self)
+ BuyTrainerService(ClassTrainerFrame.selectedService);
+ ClassTrainerFrame.showSkillDetails = 1;
+ ClassTrainerFrame.showDialog = nil;
+ ClassTrainer_SetSelection(GetTrainerSelectionIndex());
+ ClassTrainerFrame_Update();
+ end,
+ OnShow = function(self)
+ local cp1, cp2 = UnitCharacterPoints("player");
+ if ( cp2 < MAX_LEARNABLE_PROFESSIONS ) then
+ self.text:SetFormattedText(PROFESSION_CONFIRMATION2, GetTrainerServiceSkillLine(ClassTrainerFrame.selectedService));
+ else
+ self.text:SetFormattedText(PROFESSION_CONFIRMATION1, GetTrainerServiceSkillLine(ClassTrainerFrame.selectedService));
+ end
+ end,
+ showAlert = 1,
+ timeout = 0,
+ hideOnEscape = 1
+};
+
+function ClassTrainerFrame_Show()
+ ShowUIPanel(ClassTrainerFrame);
+ if ( not ClassTrainerFrame:IsShown() ) then
+ CloseTrainer();
+ return;
+ end
+
+ ClassTrainerTrainButton:Disable();
+ --Reset scrollbar
+ ClassTrainerListScrollFrameScrollBar:SetMinMaxValues(0, 0);
+
+ ClassTrainer_SelectFirstLearnableSkill();
+ ClassTrainerFrame_Update();
+ UpdateMicroButtons();
+end
+
+function ClassTrainerFrame_Hide()
+ HideUIPanel(ClassTrainerFrame);
+end
+
+function ClassTrainerFrame_OnLoad(self)
+ self:RegisterEvent("TRAINER_UPDATE");
+ self:RegisterEvent("TRAINER_DESCRIPTION_UPDATE");
+ ClassTrainerDetailScrollFrame.scrollBarHideable = 1;
+end
+
+function ClassTrainerFrame_OnEvent(self, event, ...)
+ if ( not self:IsShown() ) then
+ return;
+ end
+ if ( event == "TRAINER_UPDATE" ) then
+ ClassTrainer_SelectFirstLearnableSkill();
+ ClassTrainerFrame_Update();
+ elseif ( event == "TRAINER_DESCRIPTION_UPDATE" ) then
+ ClassTrainer_SetSelection(GetTrainerSelectionIndex());
+ end
+end
+
+function ClassTrainerFrame_Update()
+ SetPortraitTexture(ClassTrainerFramePortrait, "npc");
+ ClassTrainerNameText:SetText(UnitName("npc"));
+ ClassTrainerGreetingText:SetText(GetTrainerGreetingText());
+ local numTrainerServices = GetNumTrainerServices();
+ local skillOffset = FauxScrollFrame_GetOffset(ClassTrainerListScrollFrame);
+
+ -- If no spells then clear everything out
+ if ( numTrainerServices == 0 ) then
+ ClassTrainerCollapseAllButton:Disable();
+ else
+ ClassTrainerCollapseAllButton:Enable();
+ end
+
+ -- If selectedService is nil hide everything
+ if ( not ClassTrainerFrame.selectedService ) then
+ ClassTrainer_HideSkillDetails();
+ end
+
+ -- Change the setup depending on if its a class trainer or tradeskill trainer
+ if ( IsTradeskillTrainer() ) then
+ ClassTrainer_SetToTradeSkillTrainer();
+ else
+ ClassTrainer_SetToClassTrainer();
+ end
+
+ -- ScrollFrame update
+ FauxScrollFrame_Update(ClassTrainerListScrollFrame, numTrainerServices, CLASS_TRAINER_SKILLS_DISPLAYED, CLASS_TRAINER_SKILL_HEIGHT, nil, nil, nil, ClassTrainerSkillHighlightFrame, 293, 316 )
+
+ --ClassTrainerUsedButton:Show();
+ ClassTrainerMoneyFrame:Show();
+
+ local selected = GetTrainerSelectionIndex();
+
+ ClassTrainerSkillHighlightFrame:Hide();
+ -- Fill in the skill buttons
+ for i=1, CLASS_TRAINER_SKILLS_DISPLAYED, 1 do
+ local skillIndex = i + skillOffset;
+ local skillButton = _G["ClassTrainerSkill"..i];
+ local serviceName, serviceSubText, serviceType, isExpanded;
+ local moneyCost, cpCost1, cpCost2;
+ if ( skillIndex <= numTrainerServices ) then
+ serviceName, serviceSubText, serviceType, isExpanded = GetTrainerServiceInfo(skillIndex);
+ if ( not serviceName ) then
+ serviceName = UNKNOWN;
+ end
+ -- Set button widths if scrollbar is shown or hidden
+ if ( ClassTrainerListScrollFrame:IsShown() ) then
+ skillButton:SetWidth(293);
+ else
+ skillButton:SetWidth(313);
+ end
+ local skillSubText = _G["ClassTrainerSkill"..i.."SubText"];
+ local skillText = _G["ClassTrainerSkill"..i.."Text"];
+ -- Type stuff
+ if ( serviceType == "header" ) then
+ skillButton:SetText(serviceName);
+ skillButton:SetNormalFontObject(GameFontNormalLeft);
+ skillSubText:Hide();
+ skillText:SetWidth(CLASS_TRAINER_SKILL_NOSUBTEXT_WIDTH);
+ if ( isExpanded ) then
+ skillButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
+ else
+ skillButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
+ end
+ _G["ClassTrainerSkill"..i.."Highlight"]:SetTexture("Interface\\Buttons\\UI-PlusButton-Hilight");
+ else
+ skillButton:SetNormalTexture("");
+ _G["ClassTrainerSkill"..i.."Highlight"]:SetTexture("");
+ skillButton:SetText(" "..serviceName);
+ if ( serviceSubText and serviceSubText ~= "" ) then
+ skillSubText:SetFormattedText(PARENS_TEMPLATE, serviceSubText);
+ skillText:SetWidth(CLASS_TRAINER_SKILL_SUBTEXT_WIDTH);
+ skillSubText:ClearAllPoints();
+ skillSubText:SetPoint("RIGHT", skillButton, "RIGHT", -2, 0);
+ skillSubText:Show();
+ else
+ skillText:SetWidth(CLASS_TRAINER_SKILL_NOSUBTEXT_WIDTH);
+ skillSubText:Hide();
+ end
+
+ -- Cost Stuff
+ moneyCost, cpCost1, cpCost2 = GetTrainerServiceCost(skillIndex);
+ if ( serviceType == "available" ) then
+ skillButton:SetNormalFontObject(GameFontNormalLeftGreen);
+ ClassTrainer_SetSubTextColor(skillButton, 0, 0.6, 0);
+ skillButton.r = 0;
+ elseif ( serviceType == "used" ) then
+ skillButton:SetNormalFontObject(GameFontNormalLeftGrey);
+ ClassTrainer_SetSubTextColor(skillButton, 0.5, 0.5, 0.5);
+ else
+ skillButton:SetNormalFontObject(GameFontNormalLeftRed);
+ ClassTrainer_SetSubTextColor(skillButton, 0.6, 0, 0);
+ end
+ end
+ skillButton:SetID(skillIndex);
+ skillButton:Show();
+ -- Place the highlight and lock the highlight state
+ if ( ClassTrainerFrame.selectedService and selected == skillIndex ) then
+ ClassTrainerSkillHighlightFrame:SetPoint("TOPLEFT", "ClassTrainerSkill"..i, "TOPLEFT", 0, 0);
+ ClassTrainerSkillHighlightFrame:Show();
+ skillButton:LockHighlight();
+ ClassTrainer_SetSubTextColor(skillButton, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ if ( moneyCost and moneyCost > 0 ) then
+ ClassTrainerCostLabel:Show();
+ end
+ else
+ skillButton:UnlockHighlight();
+ end
+ else
+ skillButton:Hide();
+ end
+ end
+
+ -- Set the expand/collapse all button texture
+ local numHeaders = 0;
+ local notExpanded = 0;
+ local showDetails = nil;
+ -- Somewhat redundant loop, but cleaner than the alternatives
+ for i=1, numTrainerServices, 1 do
+ local serviceName, serviceSubText, serviceType, isExpanded = GetTrainerServiceInfo(i);
+ if ( serviceName and serviceType == "header" ) then
+ numHeaders = numHeaders + 1;
+ if ( not isExpanded ) then
+ notExpanded = notExpanded + 1;
+ end
+ end
+ -- Show details if selected skill is visible
+ if ( ClassTrainerFrame.selectedService and selected == i ) then
+ showDetails = 1;
+ end
+ end
+ -- Show skill details if the skill is visible
+ if ( showDetails ) then
+ ClassTrainer_ShowSkillDetails();
+ else
+ ClassTrainer_HideSkillDetails();
+ end
+ -- If all headers are not expanded then show collapse button, otherwise show the expand button
+ if ( notExpanded ~= numHeaders ) then
+ ClassTrainerCollapseAllButton.collapsed = nil;
+ ClassTrainerCollapseAllButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
+ else
+ ClassTrainerCollapseAllButton.collapsed = 1;
+ ClassTrainerCollapseAllButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
+ end
+end
+
+function ClassTrainer_SelectFirstLearnableSkill()
+ if ( GetNumTrainerServices() > 0 ) then
+ ClassTrainerFrame.showSkillDetails = 1;
+ local selectionIndex = GetTrainerSelectionIndex();
+ ClassTrainer_SetSelection(selectionIndex);
+ if ( selectionIndex and (selectionIndex <= GetNumTrainerServices() and selectionIndex >= 2)) then
+ ClassTrainerFrame_Update();
+ ClassTrainerListScrollFrameScrollBar:SetValue((selectionIndex-1)*CLASS_TRAINER_SKILL_HEIGHT);
+ end
+ else
+ ClassTrainerFrame.showSkillDetails = nil;
+ ClassTrainer_SetSelection(GetTrainerSelectionIndex());
+ ClassTrainerListScrollFrameScrollBar:SetValue(0);
+ end
+end
+
+function ClassTrainer_SetSelection(id)
+ -- General Info
+ if ( not id ) then
+ ClassTrainer_HideSkillDetails();
+ return;
+ end
+ local serviceName, serviceSubText, serviceType, isExpanded = GetTrainerServiceInfo(id);
+
+ ClassTrainerSkillHighlightFrame:Show();
+
+ if ( serviceType == "available" ) then
+ ClassTrainerSkillHighlight:SetVertexColor(0, 1.0, 0);
+ elseif ( serviceType == "used" ) then
+ ClassTrainerSkillHighlight:SetVertexColor(0.5, 0.5, 0.5);
+ elseif ( serviceType == "unavailable" ) then
+ ClassTrainerSkillHighlight:SetVertexColor(0.9, 0, 0);
+ else
+ -- Is header, so collapse or expand header
+ ClassTrainerSkillHighlightFrame:Hide();
+ if ( isExpanded ) then
+ CollapseTrainerSkillLine(id);
+ else
+ ExpandTrainerSkillLine(id);
+ end
+ return;
+ end
+
+ ClassTrainerSubSkillName:SetFormattedText(PARENS_TEMPLATE, serviceSubText);
+ ClassTrainerFrame.selectedService = id;
+ SelectTrainerService(id);
+ ClassTrainerSkillIcon:SetNormalTexture(GetTrainerServiceIcon(id));
+
+ if ( ClassTrainerFrame.showSkillDetails ) then
+ ClassTrainer_ShowSkillDetails();
+ else
+ ClassTrainer_HideSkillDetails();
+ return;
+ end
+
+ if ( not serviceName ) then
+ serviceName = UNKNOWN;
+ end
+ ClassTrainerSkillName:SetText(serviceName);
+ if ( not serviceSubText ) then
+ serviceSubText = "";
+ end
+ -- Build up the requirements string
+ local requirements = "";
+ -- Level Requirements
+ local reqLevel = GetTrainerServiceLevelReq(id);
+ local separator = "";
+ if ( reqLevel > 1 ) then
+ separator = ", ";
+ if ( UnitLevel("player") >= reqLevel ) then
+ requirements = requirements..format(TRAINER_REQ_LEVEL, reqLevel);
+ else
+ requirements = requirements..format(TRAINER_REQ_LEVEL_RED, reqLevel);
+ end
+ end
+ -- Skill Requirements
+ local skill, rank, hasReq = GetTrainerServiceSkillReq(id);
+ if ( skill ) then
+ if ( hasReq ) then
+ requirements = requirements..separator..format(TRAINER_REQ_SKILL_RANK, skill, rank );
+ else
+ requirements = requirements..separator..format(TRAINER_REQ_SKILL_RANK_RED, skill, rank );
+ end
+ separator = ", ";
+ end
+ -- Ability Requirements
+ local numRequirements = GetTrainerServiceNumAbilityReq(id);
+ local ability, abilityName, abilitySubText, abilityType;
+ if ( numRequirements > 0 ) then
+ for i=1, numRequirements, 1 do
+ ability, hasReq = GetTrainerServiceAbilityReq(id, i);
+ abilityName, abilitySubText, abilityType = GetTrainerServiceInfo(id);
+ if ( hasReq or (abilityType == "used") ) then
+ requirements = requirements..separator..format(TRAINER_REQ_ABILITY, ability );
+ else
+ requirements = requirements..separator..format(TRAINER_REQ_ABILITY_RED, ability );
+ end
+ separator = ", ";
+ end
+ end
+ -- Step Requirements
+ local step, met = GetTrainerServiceStepReq(id);
+ if ( step ) then
+ if ( met ) then
+ requirements = requirements..separator..format(TRAINER_REQ_ABILITY, step );
+ else
+ requirements = requirements..separator..format(TRAINER_REQ_ABILITY_RED, step );
+ end
+ end
+ if ( requirements ~= "" ) then
+ ClassTrainerSkillRequirements:SetText(REQUIRES_LABEL.." "..requirements);
+ else
+ ClassTrainerSkillRequirements:SetText("");
+ end
+ -- Money Frame and cost
+ local moneyCost, cpCost1, cpCost2 = GetTrainerServiceCost(id);
+ local cp1, cp2 = UnitCharacterPoints("player");
+ local unavailable, skillPointCost;
+ if ( moneyCost == 0 ) then
+ ClassTrainerDetailMoneyFrame:Hide();
+ ClassTrainerCostLabel:Hide();
+ ClassTrainerSkillDescription:SetPoint("TOPLEFT", "ClassTrainerCostLabel", "TOPLEFT", 0, 0);
+ else
+ ClassTrainerDetailMoneyFrame:Show();
+ ClassTrainerCostLabel:Show();
+ ClassTrainerSkillDescription:SetPoint("TOPLEFT", "ClassTrainerCostLabel", "BOTTOMLEFT", 0, -10);
+ if ( GetMoney() >= moneyCost ) then
+ SetMoneyFrameColor("ClassTrainerDetailMoneyFrame", "white");
+ else
+ SetMoneyFrameColor("ClassTrainerDetailMoneyFrame", "red");
+ unavailable = 1;
+ end
+ end
+
+ MoneyFrame_Update("ClassTrainerDetailMoneyFrame", moneyCost);
+ if ( cpCost2 > 0 ) then
+ ClassTrainerFrame.showDialog = 1;
+ if ( cp2 < cpCost2 and serviceType ~= "used" ) then
+ unavailable = 1;
+ end
+ elseif ( cpCost1 > 0 ) then
+ ClassTrainerFrame.showDialog = 1;
+ if ( cp1 < cpCost1 and serviceType ~= "used" ) then
+ unavailable = 1;
+ end
+ else
+ ClassTrainerFrame.showDialog = nil;
+ end
+ ClassTrainerSkillDescription:SetText( GetTrainerServiceDescription(id) );
+ if ( serviceType == "available" and not unavailable ) then
+ ClassTrainerTrainButton:Enable();
+ else
+ ClassTrainerTrainButton:Disable();
+ end
+
+ -- Close the confirmation dialog if you choose a different skill
+ if ( StaticPopup_Visible("CONFIRM_PROFESSION") ) then
+ StaticPopup_Hide("CONFIRM_PROFESSION");
+ end
+end
+
+function ClassTrainerSkillButton_OnClick(self, button)
+ if ( button == "LeftButton" ) then
+ ClassTrainerFrame.selectedService = self:GetID();
+ ClassTrainerFrame.showSkillDetails = 1;
+ ClassTrainer_SetSelection(self:GetID());
+ ClassTrainerFrame_Update();
+ end
+end
+
+function ClassTrainerTrainButton_OnClick(self, button)
+ if ( IsTradeskillTrainer() and ClassTrainerFrame.showDialog) then
+ StaticPopup_Show("CONFIRM_PROFESSION");
+ else
+ BuyTrainerService(ClassTrainerFrame.selectedService);
+ ClassTrainerFrame.showSkillDetails = 1;
+ ClassTrainer_SetSelection(ClassTrainerFrame.selectedService);
+ ClassTrainerFrame_Update();
+ end
+end
+
+function ClassTrainer_SetSubTextColor(button, r, g, b)
+ button.r = r;
+ button.g = g;
+ button.b = b;
+ _G[button:GetName().."SubText"]:SetTextColor(r, g, b);
+end
+
+function ClassTrainerCollapseAllButton_OnClick(self)
+ if (self.collapsed) then
+ self.collapsed = nil;
+ ExpandTrainerSkillLine(0);
+ else
+ self.collapsed = 1;
+ ClassTrainerListScrollFrameScrollBar:SetValue(0);
+ CollapseTrainerSkillLine(0);
+ end
+end
+
+function ClassTrainer_HideSkillDetails()
+ ClassTrainerFrame.showSkillDetails = nil;
+ ClassTrainerSkillName:Hide();
+ ClassTrainerSkillIcon:Hide();
+ ClassTrainerSkillRequirements:Hide();
+ ClassTrainerSkillDescription:Hide();
+ ClassTrainerDetailMoneyFrame:Hide();
+ ClassTrainerCostLabel:Hide();
+ ClassTrainerTrainButton:Disable();
+end
+
+function ClassTrainer_ShowSkillDetails()
+ ClassTrainerSkillName:Show();
+ ClassTrainerSkillIcon:Show();
+ ClassTrainerSkillRequirements:Show();
+ ClassTrainerSkillDescription:Show();
+ ClassTrainerDetailMoneyFrame:Show();
+ --ClassTrainerCostLabel:Show();
+end
+
+function ClassTrainer_SetToTradeSkillTrainer()
+ CLASS_TRAINER_SKILLS_DISPLAYED = 10;
+ ClassTrainerSkill11:Hide();
+ ClassTrainerListScrollFrame:SetHeight(168);
+ ClassTrainerDetailScrollFrame:SetHeight(135);
+ local cp1, cp2 = UnitCharacterPoints("player");
+ ClassTrainerHorizontalBarLeft:SetPoint("TOPLEFT", "ClassTrainerFrame", "TOPLEFT", 15, -259);
+end
+
+function ClassTrainer_SetToClassTrainer()
+ CLASS_TRAINER_SKILLS_DISPLAYED = 11;
+ ClassTrainerListScrollFrame:SetHeight(184);
+ ClassTrainerDetailScrollFrame:SetHeight(119);
+ ClassTrainerHorizontalBarLeft:SetPoint("TOPLEFT", "ClassTrainerFrame", "TOPLEFT", 15, -275);
+end
+
+-- Dropdown functions
+function ClassTrainerFrameFilterDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, ClassTrainerFrameFilterDropDown_Initialize);
+ UIDropDownMenu_SetText(self, FILTER);
+ UIDropDownMenu_SetWidth(self, 130);
+end
+
+function ClassTrainerFrameFilterDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+
+ -- Available button
+ info.text = GREEN_FONT_COLOR_CODE..AVAILABLE..FONT_COLOR_CODE_CLOSE;
+ info.value = "available";
+ info.func = ClassTrainerFrameFilterDropDown_OnClick;
+ info.checked = GetTrainerServiceTypeFilter("available");
+ info.keepShownOnClick = 1;
+ UIDropDownMenu_AddButton(info);
+
+ -- Unavailable button
+ info.text = RED_FONT_COLOR_CODE..UNAVAILABLE..FONT_COLOR_CODE_CLOSE;
+ info.value = "unavailable";
+ info.func = ClassTrainerFrameFilterDropDown_OnClick;
+ info.checked = GetTrainerServiceTypeFilter("unavailable");
+ info.keepShownOnClick = 1;
+ UIDropDownMenu_AddButton(info);
+
+ -- Unavailable button
+ info.text = GRAY_FONT_COLOR_CODE..USED..FONT_COLOR_CODE_CLOSE;
+ info.value = "used";
+ info.func = ClassTrainerFrameFilterDropDown_OnClick;
+ info.checked = GetTrainerServiceTypeFilter("used");
+ info.keepShownOnClick = 1;
+ UIDropDownMenu_AddButton(info);
+end
+
+function ClassTrainerFrameFilterDropDown_OnClick(self)
+ ClassTrainerListScrollFrameScrollBar:SetValue(0);
+ if ( UIDropDownMenuButton_GetChecked(self) ) then
+ SetTrainerServiceTypeFilter(self.value, 1);
+ else
+ SetTrainerServiceTypeFilter(self.value, 0);
+ end
+end
diff --git a/reference/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.toc b/reference/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.toc
new file mode 100644
index 0000000..3b06a47
--- /dev/null
+++ b/reference/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.toc
@@ -0,0 +1,6 @@
+## Interface: 30300
+## Title: Blizzard Trainer UI
+## Secure: 1
+## LoadOnDemand: 1
+Blizzard_TrainerUI.xml
+Localization.lua
diff --git a/reference/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.xml b/reference/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.xml
new file mode 100644
index 0000000..15f6af2
--- /dev/null
+++ b/reference/AddOns/Blizzard_TrainerUI/Blizzard_TrainerUI.xml
@@ -0,0 +1,526 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ClassTrainerExpandTabMiddle:SetWidth(self:GetTextWidth() + 24);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, CLASS_TRAINER_SKILL_HEIGHT, ClassTrainerFrame_Update)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetTrainerService(ClassTrainerFrame.selectedService);
+ GameTooltip:Show();
+
+
+
+ HandleModifiedItemClick(GetTrainerServiceItemLink(ClassTrainerFrame.selectedService));
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoOpen");
+
+
+ CloseTrainer();
+ UpdateMicroButtons();
+ PlaySound("igCharacterInfoClose");
+ if ( StaticPopup_Visible("CONFIRM_PROFESSION") ) then
+ StaticPopup_Hide("CONFIRM_PROFESSION");
+ end
+
+
+
+
+
diff --git a/reference/AddOns/Blizzard_TrainerUI/Localization.lua b/reference/AddOns/Blizzard_TrainerUI/Localization.lua
new file mode 100644
index 0000000..e7b2086
--- /dev/null
+++ b/reference/AddOns/Blizzard_TrainerUI/Localization.lua
@@ -0,0 +1 @@
+-- This file is executed at the end of addon load
diff --git a/reference/FrameXML/ActionBarFrame.xml b/reference/FrameXML/ActionBarFrame.xml
new file mode 100644
index 0000000..74debc4
--- /dev/null
+++ b/reference/FrameXML/ActionBarFrame.xml
@@ -0,0 +1,199 @@
+
+
+
+
+
+ ActionButton_OnLoad(self);
+
+
+ ActionButton_UpdateAction(self, name, value);
+
+
+ ActionButton_OnEvent(self, event, ...);
+
+
+ ActionButton_UpdateState(self, button, down);
+
+
+ if ( LOCK_ACTIONBAR ~= "1" or IsModifiedClick("PICKUPACTION") ) then
+ PickupAction(self.action);
+ ActionButton_UpdateState(self);
+ ActionButton_UpdateFlash(self);
+ end
+
+
+ PlaceAction(self.action);
+ ActionButton_UpdateState(self);
+ ActionButton_UpdateFlash(self);
+
+
+ ActionButton_SetTooltip(self);
+
+
+ GameTooltip:Hide();
+
+
+ ActionButton_OnUpdate(self, elapsed);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ActionBar_PageUp(self);
+ PlaySound("UChatScrollButton");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ActionBar_PageDown(self);
+ PlaySound("UChatScrollButton");
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/ActionButton.lua b/reference/FrameXML/ActionButton.lua
new file mode 100644
index 0000000..583367e
--- /dev/null
+++ b/reference/FrameXML/ActionButton.lua
@@ -0,0 +1,523 @@
+CURRENT_ACTIONBAR_PAGE = 1;
+NUM_ACTIONBAR_PAGES = 6;
+NUM_ACTIONBAR_BUTTONS = 12;
+ATTACK_BUTTON_FLASH_TIME = 0.4;
+
+BOTTOMLEFT_ACTIONBAR_PAGE = 6;
+BOTTOMRIGHT_ACTIONBAR_PAGE = 5;
+LEFT_ACTIONBAR_PAGE = 4;
+RIGHT_ACTIONBAR_PAGE = 3;
+RANGE_INDICATOR = "●";
+
+-- Table of actionbar pages and whether they're viewable or not
+VIEWABLE_ACTION_BAR_PAGES = {1, 1, 1, 1, 1, 1};
+
+function ActionButtonDown(id)
+ local button;
+ if ( VehicleMenuBar:IsShown() and id <= VEHICLE_MAX_ACTIONBUTTONS ) then
+ button = _G["VehicleMenuBarActionButton"..id];
+ elseif ( BonusActionBarFrame:IsShown() ) then
+ button = _G["BonusActionButton"..id];
+ else
+ button = _G["ActionButton"..id];
+ end
+ if ( button:GetButtonState() == "NORMAL" ) then
+ button:SetButtonState("PUSHED");
+ end
+end
+
+function ActionButtonUp(id)
+ local button;
+ if ( VehicleMenuBar:IsShown() and id <= VEHICLE_MAX_ACTIONBUTTONS ) then
+ button = _G["VehicleMenuBarActionButton"..id];
+ elseif ( BonusActionBarFrame:IsShown() ) then
+ button = _G["BonusActionButton"..id];
+ else
+ button = _G["ActionButton"..id];
+ end
+ if ( button:GetButtonState() == "PUSHED" ) then
+ button:SetButtonState("NORMAL");
+ SecureActionButton_OnClick(button, "LeftButton");
+ ActionButton_UpdateState(button);
+ end
+end
+
+function ActionBar_PageUp()
+ local nextPage;
+ for i=GetActionBarPage() + 1, NUM_ACTIONBAR_PAGES do
+ if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then
+ nextPage = i;
+ break;
+ end
+ end
+
+ if ( not nextPage ) then
+ nextPage = 1;
+ end
+ ChangeActionBarPage(nextPage);
+end
+
+function ActionBar_PageDown()
+ local prevPage;
+ for i=GetActionBarPage() - 1, 1, -1 do
+ if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then
+ prevPage = i;
+ break;
+ end
+ end
+
+ if ( not prevPage ) then
+ for i=NUM_ACTIONBAR_PAGES, 1, -1 do
+ if ( VIEWABLE_ACTION_BAR_PAGES[i] ) then
+ prevPage = i;
+ break;
+ end
+ end
+ end
+ ChangeActionBarPage(prevPage);
+end
+
+function ActionButton_OnLoad (self)
+ self.flashing = 0;
+ self.flashtime = 0;
+ self:SetAttribute("showgrid", 0);
+ self:SetAttribute("type", "action");
+ self:SetAttribute("checkselfcast", true);
+ self:SetAttribute("checkfocuscast", true);
+ self:SetAttribute("useparent-unit", true);
+ self:SetAttribute("useparent-actionpage", true);
+ self:RegisterForDrag("LeftButton", "RightButton");
+ self:RegisterForClicks("AnyUp");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("ACTIONBAR_SHOWGRID");
+ self:RegisterEvent("ACTIONBAR_HIDEGRID");
+ self:RegisterEvent("ACTIONBAR_PAGE_CHANGED");
+ self:RegisterEvent("ACTIONBAR_SLOT_CHANGED");
+ self:RegisterEvent("UPDATE_BINDINGS");
+ self:RegisterEvent("UPDATE_SHAPESHIFT_FORM");
+ ActionButton_UpdateAction(self);
+ ActionButton_UpdateHotkeys(self, self.buttonType);
+end
+
+function ActionButton_UpdateHotkeys (self, actionButtonType)
+ local id;
+ if ( not actionButtonType ) then
+ actionButtonType = "ACTIONBUTTON";
+ id = self:GetID();
+ else
+ if ( actionButtonType == "MULTICASTACTIONBUTTON" ) then
+ id = self.buttonIndex;
+ else
+ id = self:GetID();
+ end
+ end
+
+ local hotkey = _G[self:GetName().."HotKey"];
+ local key = GetBindingKey(actionButtonType..id) or
+ GetBindingKey("CLICK "..self:GetName()..":LeftButton");
+
+ local text = GetBindingText(key, "KEY_", 1);
+ if ( text == "" ) then
+ hotkey:SetText(RANGE_INDICATOR);
+ hotkey:SetPoint("TOPLEFT", self, "TOPLEFT", 1, -2);
+ hotkey:Hide();
+ else
+ hotkey:SetText(text);
+ hotkey:SetPoint("TOPLEFT", self, "TOPLEFT", -2, -2);
+ hotkey:Show();
+ end
+end
+
+function ActionButton_CalculateAction (self, button)
+ if ( not button ) then
+ button = SecureButton_GetEffectiveButton(self);
+ end
+ if ( self:GetID() > 0 ) then
+ local page = SecureButton_GetModifiedAttribute(self, "actionpage", button);
+ if ( not page ) then
+ page = GetActionBarPage();
+ if ( self.isBonus and (page == 1 or self.alwaysBonus) ) then
+ local offset = GetBonusBarOffset();
+ if ( offset == 0 and BonusActionBarFrame and BonusActionBarFrame.lastBonusBar ) then
+ offset = BonusActionBarFrame.lastBonusBar;
+ end
+ page = NUM_ACTIONBAR_PAGES + offset;
+ elseif ( self.buttonType == "MULTICASTACTIONBUTTON" ) then
+ page = NUM_ACTIONBAR_PAGES + GetMultiCastBarOffset();
+ end
+ end
+ return (self:GetID() + ((page - 1) * NUM_ACTIONBAR_BUTTONS));
+ else
+ return SecureButton_GetModifiedAttribute(self, "action", button) or 1;
+ end
+end
+
+function ActionButton_UpdateAction (self)
+ local action = ActionButton_CalculateAction(self);
+ if ( action ~= self.action ) then
+ self.action = action;
+ ActionButton_Update(self);
+ end
+end
+
+function ActionButton_Update (self)
+ local name = self:GetName();
+
+ local action = self.action;
+ local icon = _G[name.."Icon"];
+ local buttonCooldown = _G[name.."Cooldown"];
+ local texture = GetActionTexture(action);
+
+ if ( HasAction(action) ) then
+ if ( not self.eventsRegistered ) then
+ self:RegisterEvent("ACTIONBAR_UPDATE_STATE");
+ self:RegisterEvent("ACTIONBAR_UPDATE_USABLE");
+ self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
+ self:RegisterEvent("UPDATE_INVENTORY_ALERTS");
+ self:RegisterEvent("PLAYER_TARGET_CHANGED");
+ self:RegisterEvent("TRADE_SKILL_SHOW");
+ self:RegisterEvent("TRADE_SKILL_CLOSE");
+ self:RegisterEvent("PLAYER_ENTER_COMBAT");
+ self:RegisterEvent("PLAYER_LEAVE_COMBAT");
+ self:RegisterEvent("START_AUTOREPEAT_SPELL");
+ self:RegisterEvent("STOP_AUTOREPEAT_SPELL");
+ self:RegisterEvent("UNIT_ENTERED_VEHICLE");
+ self:RegisterEvent("UNIT_EXITED_VEHICLE");
+ self:RegisterEvent("COMPANION_UPDATE");
+ self:RegisterEvent("UNIT_INVENTORY_CHANGED");
+ self:RegisterEvent("LEARNED_SPELL_IN_TAB");
+ self.eventsRegistered = true;
+ end
+
+ if ( not self:GetAttribute("statehidden") ) then
+ self:Show();
+ end
+ ActionButton_UpdateState(self);
+ ActionButton_UpdateUsable(self);
+ ActionButton_UpdateCooldown(self);
+ ActionButton_UpdateFlash(self);
+ else
+ if ( self.eventsRegistered ) then
+ self:UnregisterEvent("ACTIONBAR_UPDATE_STATE");
+ self:UnregisterEvent("ACTIONBAR_UPDATE_USABLE");
+ self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
+ self:UnregisterEvent("UPDATE_INVENTORY_ALERTS");
+ self:UnregisterEvent("PLAYER_TARGET_CHANGED");
+ self:UnregisterEvent("TRADE_SKILL_SHOW");
+ self:UnregisterEvent("TRADE_SKILL_CLOSE");
+ self:UnregisterEvent("PLAYER_ENTER_COMBAT");
+ self:UnregisterEvent("PLAYER_LEAVE_COMBAT");
+ self:UnregisterEvent("START_AUTOREPEAT_SPELL");
+ self:UnregisterEvent("STOP_AUTOREPEAT_SPELL");
+ self:UnregisterEvent("UNIT_ENTERED_VEHICLE");
+ self:UnregisterEvent("UNIT_EXITED_VEHICLE");
+ self:UnregisterEvent("COMPANION_UPDATE");
+ self:UnregisterEvent("UNIT_INVENTORY_CHANGED");
+ self:UnregisterEvent("LEARNED_SPELL_IN_TAB");
+ self.eventsRegistered = nil;
+ end
+
+ if ( self:GetAttribute("showgrid") == 0 ) then
+ self:Hide();
+ else
+ buttonCooldown:Hide();
+ end
+ end
+
+ -- Add a green border if button is an equipped item
+ local border = _G[name.."Border"];
+ if ( IsEquippedAction(action) ) then
+ border:SetVertexColor(0, 1.0, 0, 0.35);
+ border:Show();
+ else
+ border:Hide();
+ end
+
+ -- Update Action Text
+ local actionName = _G[name.."Name"];
+ if ( not IsConsumableAction(action) and not IsStackableAction(action) ) then
+ actionName:SetText(GetActionText(action));
+ else
+ actionName:SetText("");
+ end
+
+ -- Update icon and hotkey text
+ if ( texture ) then
+ icon:SetTexture(texture);
+ icon:Show();
+ self.rangeTimer = -1;
+ self:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");
+ else
+ icon:Hide();
+ buttonCooldown:Hide();
+ self.rangeTimer = nil;
+ self:SetNormalTexture("Interface\\Buttons\\UI-Quickslot");
+ local hotkey = _G[name.."HotKey"];
+ if ( hotkey:GetText() == RANGE_INDICATOR ) then
+ hotkey:Hide();
+ else
+ hotkey:SetVertexColor(0.6, 0.6, 0.6);
+ end
+ end
+ ActionButton_UpdateCount(self);
+
+ -- Update tooltip
+ if ( GameTooltip:GetOwner() == self ) then
+ ActionButton_SetTooltip(self);
+ end
+
+ self.feedback_action = action;
+end
+
+function ActionButton_ShowGrid (button)
+ assert(button);
+
+ if ( issecure() ) then
+ button:SetAttribute("showgrid", button:GetAttribute("showgrid") + 1);
+ end
+
+ _G[button:GetName().."NormalTexture"]:SetVertexColor(1.0, 1.0, 1.0, 0.5);
+
+ if ( button:GetAttribute("showgrid") >= 1 and not button:GetAttribute("statehidden") ) then
+ button:Show();
+ end
+end
+
+function ActionButton_HideGrid (button)
+ assert(button);
+
+ local showgrid = button:GetAttribute("showgrid");
+
+ if ( issecure() ) then
+ if ( showgrid > 0 ) then
+ button:SetAttribute("showgrid", showgrid - 1);
+ end
+ end
+
+ if ( button:GetAttribute("showgrid") == 0 and not HasAction(button.action) ) then
+ button:Hide();
+ end
+end
+
+function ActionButton_UpdateState (button)
+ assert(button);
+
+ local action = button.action;
+ if ( IsCurrentAction(action) or IsAutoRepeatAction(action) ) then
+ button:SetChecked(1);
+ else
+ button:SetChecked(0);
+ end
+end
+
+function ActionButton_UpdateUsable (self)
+ local name = self:GetName();
+ local icon = _G[name.."Icon"];
+ local normalTexture = _G[name.."NormalTexture"];
+ local isUsable, notEnoughMana = IsUsableAction(self.action);
+ if ( isUsable ) then
+ icon:SetVertexColor(1.0, 1.0, 1.0);
+ normalTexture:SetVertexColor(1.0, 1.0, 1.0);
+ elseif ( notEnoughMana ) then
+ icon:SetVertexColor(0.5, 0.5, 1.0);
+ normalTexture:SetVertexColor(0.5, 0.5, 1.0);
+ else
+ icon:SetVertexColor(0.4, 0.4, 0.4);
+ normalTexture:SetVertexColor(1.0, 1.0, 1.0);
+ end
+end
+
+function ActionButton_UpdateCount (self)
+ local text = _G[self:GetName().."Count"];
+ local action = self.action;
+ if ( IsConsumableAction(action) or IsStackableAction(action) ) then
+ local count = GetActionCount(action);
+ if ( count > (self.maxDisplayCount or 9999 ) ) then
+ text:SetText("*");
+ else
+ text:SetText(count);
+ end
+ else
+ text:SetText("");
+ end
+end
+
+function ActionButton_UpdateCooldown (self)
+ local cooldown = _G[self:GetName().."Cooldown"];
+ local start, duration, enable = GetActionCooldown(self.action);
+ CooldownFrame_SetTimer(cooldown, start, duration, enable);
+end
+
+function ActionButton_OnEvent (self, event, ...)
+ local arg1 = ...;
+ if ((event == "UNIT_INVENTORY_CHANGED" and arg1 == "player") or event == "LEARNED_SPELL_IN_TAB") then
+ if ( GameTooltip:GetOwner() == self ) then
+ ActionButton_SetTooltip(self);
+ end
+ end
+ if ( event == "ACTIONBAR_SLOT_CHANGED" ) then
+ if ( arg1 == 0 or arg1 == tonumber(self.action) ) then
+ ActionButton_Update(self);
+ end
+ return;
+ end
+ if ( event == "PLAYER_ENTERING_WORLD" or event == "UPDATE_SHAPESHIFT_FORM" ) then
+ -- need to listen for UPDATE_SHAPESHIFT_FORM because attack icons change when the shapeshift form changes
+ ActionButton_Update(self);
+ return;
+ end
+ if ( event == "ACTIONBAR_PAGE_CHANGED" or event == "UPDATE_BONUS_ACTIONBAR" ) then
+ ActionButton_UpdateAction(self);
+ return;
+ end
+ if ( event == "ACTIONBAR_SHOWGRID" ) then
+ ActionButton_ShowGrid(self);
+ return;
+ end
+ if ( event == "ACTIONBAR_HIDEGRID" ) then
+ ActionButton_HideGrid(self);
+ return;
+ end
+ if ( event == "UPDATE_BINDINGS" ) then
+ ActionButton_UpdateHotkeys(self, self.buttonType);
+ return;
+ end
+
+ -- All event handlers below this line are only set when the button has an action
+
+ if ( event == "PLAYER_TARGET_CHANGED" ) then
+ self.rangeTimer = -1;
+ elseif ( (event == "ACTIONBAR_UPDATE_STATE") or
+ ((event == "UNIT_ENTERED_VEHICLE" or event == "UNIT_EXITED_VEHICLE") and (arg1 == "player")) or
+ ((event == "COMPANION_UPDATE") and (arg1 == "MOUNT")) ) then
+ ActionButton_UpdateState(self);
+ elseif ( event == "ACTIONBAR_UPDATE_USABLE" ) then
+ ActionButton_UpdateUsable(self);
+ elseif ( event == "ACTIONBAR_UPDATE_COOLDOWN" ) then
+ ActionButton_UpdateCooldown(self);
+ elseif ( event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE" ) then
+ ActionButton_UpdateState(self);
+ elseif ( event == "PLAYER_ENTER_COMBAT" ) then
+ if ( IsAttackAction(self.action) ) then
+ ActionButton_StartFlash(self);
+ end
+ elseif ( event == "PLAYER_LEAVE_COMBAT" ) then
+ if ( IsAttackAction(self.action) ) then
+ ActionButton_StopFlash(self);
+ end
+ elseif ( event == "START_AUTOREPEAT_SPELL" ) then
+ if ( IsAutoRepeatAction(self.action) ) then
+ ActionButton_StartFlash(self);
+ end
+ elseif ( event == "STOP_AUTOREPEAT_SPELL" ) then
+ if ( ActionButton_IsFlashing(self) and not IsAttackAction(self.action) ) then
+ ActionButton_StopFlash(self);
+ end
+ end
+end
+
+function ActionButton_SetTooltip (self)
+ if ( GetCVar("UberTooltips") == "1" ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ else
+ local parent = self:GetParent();
+ if ( parent == MultiBarBottomRight or parent == MultiBarRight or parent == MultiBarLeft ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+ end
+ if ( GameTooltip:SetAction(self.action) ) then
+ self.UpdateTooltip = ActionButton_SetTooltip;
+ else
+ self.UpdateTooltip = nil;
+ end
+end
+
+function ActionButton_OnUpdate (self, elapsed)
+ if ( ActionButton_IsFlashing(self) ) then
+ local flashtime = self.flashtime;
+ flashtime = flashtime - elapsed;
+
+ if ( flashtime <= 0 ) then
+ local overtime = -flashtime;
+ if ( overtime >= ATTACK_BUTTON_FLASH_TIME ) then
+ overtime = 0;
+ end
+ flashtime = ATTACK_BUTTON_FLASH_TIME - overtime;
+
+ local flashTexture = _G[self:GetName().."Flash"];
+ if ( flashTexture:IsShown() ) then
+ flashTexture:Hide();
+ else
+ flashTexture:Show();
+ end
+ end
+
+ self.flashtime = flashtime;
+ end
+
+ -- Handle range indicator
+ local rangeTimer = self.rangeTimer;
+ if ( rangeTimer ) then
+ rangeTimer = rangeTimer - elapsed;
+
+ if ( rangeTimer <= 0 ) then
+ local count = _G[self:GetName().."HotKey"];
+ local valid = IsActionInRange(self.action);
+ if ( count:GetText() == RANGE_INDICATOR ) then
+ if ( valid == 0 ) then
+ count:Show();
+ count:SetVertexColor(1.0, 0.1, 0.1);
+ elseif ( valid == 1 ) then
+ count:Show();
+ count:SetVertexColor(0.6, 0.6, 0.6);
+ else
+ count:Hide();
+ end
+ else
+ if ( valid == 0 ) then
+ count:SetVertexColor(1.0, 0.1, 0.1);
+ else
+ count:SetVertexColor(0.6, 0.6, 0.6);
+ end
+ end
+ rangeTimer = TOOLTIP_UPDATE_TIME;
+ end
+
+ self.rangeTimer = rangeTimer;
+ end
+end
+
+function ActionButton_GetPagedID (self)
+ return self.action;
+end
+
+function ActionButton_UpdateFlash (self)
+ local action = self.action;
+ if ( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) ) then
+ ActionButton_StartFlash(self);
+ else
+ ActionButton_StopFlash(self);
+ end
+end
+
+function ActionButton_StartFlash (self)
+ self.flashing = 1;
+ self.flashtime = 0;
+ ActionButton_UpdateState(self);
+end
+
+function ActionButton_StopFlash (self)
+ self.flashing = 0;
+ _G[self:GetName().."Flash"]:Hide();
+ ActionButton_UpdateState (self);
+end
+
+function ActionButton_IsFlashing (self)
+ if ( self.flashing == 1 ) then
+ return 1;
+ end
+
+ return nil;
+end
diff --git a/reference/FrameXML/ActionButtonTemplate.xml b/reference/FrameXML/ActionButtonTemplate.xml
new file mode 100644
index 0000000..81c796c
--- /dev/null
+++ b/reference/FrameXML/ActionButtonTemplate.xml
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/AlertFrames.lua b/reference/FrameXML/AlertFrames.lua
new file mode 100644
index 0000000..9a744c7
--- /dev/null
+++ b/reference/FrameXML/AlertFrames.lua
@@ -0,0 +1,271 @@
+MAX_ACHIEVEMENT_ALERTS = 2;
+
+function AlertFrame_OnLoad (self)
+ self:RegisterEvent("ACHIEVEMENT_EARNED");
+ self:RegisterEvent("LFG_COMPLETION_REWARD");
+end
+
+function AlertFrame_OnEvent (self, event, ...)
+ if ( event == "ACHIEVEMENT_EARNED" ) then
+ local id = ...;
+
+ if ( not AchievementFrame ) then
+ AchievementFrame_LoadUI();
+ end
+
+ AchievementAlertFrame_ShowAlert(id);
+ elseif ( event == "LFG_COMPLETION_REWARD" ) then
+ DungeonCompletionAlertFrame_ShowAlert();
+ end
+end
+
+function AlertFrame_FixAnchors()
+ AchievementAlertFrame_FixAnchors();
+ DungeonCompletionAlertFrame_FixAnchors();
+end
+
+function AlertFrame_AnimateIn(frame)
+ frame:Show();
+ frame.animIn:Play();
+ frame.glow.animIn:Play();
+ frame.shine.animIn:Play();
+ frame.waitAndAnimOut:Stop(); --Just in case it's already animating out, but we want to reinstate it.
+ if ( frame:IsMouseOver() ) then
+ frame.waitAndAnimOut.animOut:SetStartDelay(1);
+ else
+ frame.waitAndAnimOut.animOut:SetStartDelay(4.05);
+ frame.waitAndAnimOut:Play();
+ end
+end
+
+function AlertFrame_StopOutAnimation(frame)
+ frame.waitAndAnimOut:Stop();
+ frame.waitAndAnimOut.animOut:SetStartDelay(1);
+end
+
+function AlertFrame_ResumeOutAnimation(frame)
+ frame.waitAndAnimOut:Play();
+end
+
+-- [[ DungeonCompletionAlertFrame ]] --
+function DungeonCompletionAlertFrame_OnLoad (self)
+ self.glow = self.glowFrame.glow;
+end
+
+function DungeonCompletionAlertFrame_FixAnchors()
+ for i=MAX_ACHIEVEMENT_ALERTS, 1, -1 do
+ local frame = _G["AchievementAlertFrame"..i];
+ if ( frame and frame:IsShown() ) then
+ DungeonCompletionAlertFrame1:SetPoint("BOTTOM", frame, "TOP", 0, 10);
+ return;
+ end
+ end
+
+ for i=NUM_GROUP_LOOT_FRAMES, 1, -1 do
+ local frame = _G["GroupLootFrame"..i];
+ if ( frame and frame:IsShown() ) then
+ DungeonCompletionAlertFrame1:SetPoint("BOTTOM", frame, "TOP", 0, 10);
+ return;
+ end
+ end
+
+ DungeonCompletionAlertFrame1:SetPoint("BOTTOM", UIParent, "BOTTOM", 0, 128);
+end
+
+DUNGEON_COMPLETION_MAX_REWARDS = 1;
+function DungeonCompletionAlertFrame_ShowAlert()
+ PlaySound("LFG_Rewards");
+ local frame = DungeonCompletionAlertFrame1;
+ --For now we only have 1 dungeon alert frame. If you're completing more than one dungeon within ~5 seconds, tough luck.
+ local name, typeID, textureFilename, moneyBase, moneyVar, experienceBase, experienceVar, numStrangers, numRewards= GetLFGCompletionReward();
+
+
+ --Set up the rewards
+ local moneyAmount = moneyBase + moneyVar * numStrangers;
+ local experienceGained = experienceBase + experienceVar * numStrangers;
+
+ local rewardsOffset = 0;
+
+ if ( moneyAmount > 0 or experienceGained > 0 ) then --hasMiscReward ) then
+ SetPortraitToTexture(DungeonCompletionAlertFrame1Reward1.texture, "Interface\\Icons\\inv_misc_coin_02");
+ DungeonCompletionAlertFrame1Reward1.rewardID = 0;
+ DungeonCompletionAlertFrame1Reward1:Show();
+
+ rewardsOffset = 1;
+ end
+
+ for i = 1, numRewards do
+ local frameID = (i + rewardsOffset);
+ local reward = _G["DungeonCompletionAlertFrame1Reward"..frameID];
+ if ( not reward ) then
+ reward = CreateFrame("FRAME", "DungeonCompletionAlertFrame1Reward"..frameID, DungeonCompletionAlertFrame1, "DungeonCompletionAlertFrameRewardTemplate");
+ reward:SetID(frameID);
+ DUNGEON_COMPLETION_MAX_REWARDS = frameID;
+ end
+ DungeonCompletionAlertFrameReward_SetReward(reward, i);
+ end
+
+ local usedButtons = numRewards + rewardsOffset;
+ --Hide the unused ones
+ for i = usedButtons + 1, DUNGEON_COMPLETION_MAX_REWARDS do
+ _G["DungeonCompletionAlertFrame1Reward"..i]:Hide();
+ end
+
+ if ( usedButtons > 0 ) then
+ --Set up positions
+ local spacing = 36;
+ DungeonCompletionAlertFrame1Reward1:SetPoint("TOP", DungeonCompletionAlertFrame1, "TOP", -spacing/2 * usedButtons + 41, 0);
+ for i = 2, usedButtons do
+ _G["DungeonCompletionAlertFrame1Reward"..i]:SetPoint("CENTER", "DungeonCompletionAlertFrame1Reward"..(i - 1), "CENTER", spacing, 0);
+ end
+ end
+
+ --Set up the text and icons.
+
+ frame.instanceName:SetText(name);
+ if ( typeID == TYPEID_HEROIC_DIFFICULTY ) then
+ frame.heroicIcon:Show();
+ frame.instanceName:SetPoint("TOP", 33, -44);
+ else
+ frame.heroicIcon:Hide();
+ frame.instanceName:SetPoint("TOP", 25, -44);
+ end
+
+ frame.dungeonTexture:SetTexture("Interface\\LFGFrame\\LFGIcon-"..textureFilename);
+
+ AlertFrame_AnimateIn(frame)
+
+
+ AlertFrame_FixAnchors();
+end
+
+function DungeonCompletionAlertFrameReward_SetReward(frame, index)
+ local texturePath, quantity = GetLFGCompletionRewardItem(index);
+ SetPortraitToTexture(frame.texture, texturePath);
+ frame.rewardID = index;
+ frame:Show();
+end
+
+function DungeonCompletionAlertFrameReward_OnEnter(self)
+ AlertFrame_StopOutAnimation(self:GetParent());
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self.rewardID == 0 ) then
+ GameTooltip:AddLine(YOU_RECEIVED);
+ local name, typeID, textureFilename, moneyBase, moneyVar, experienceBase, experienceVar, numStrangers, numRewards = GetLFGCompletionReward();
+
+ local moneyAmount = moneyBase + moneyVar * numStrangers;
+ local experienceGained = experienceBase + experienceVar * numStrangers;
+
+ if ( experienceGained > 0 ) then
+ GameTooltip:AddLine(string.format(GAIN_EXPERIENCE, experienceGained));
+ end
+ if ( moneyAmount > 0 ) then
+ SetTooltipMoney(GameTooltip, moneyAmount, nil);
+ end
+ else
+ GameTooltip:SetLFGCompletionReward(self.rewardID);
+ end
+ GameTooltip:Show();
+end
+
+function DungeonCompletionAlertFrameReward_OnLeave(frame)
+ AlertFrame_ResumeOutAnimation(frame:GetParent());
+ GameTooltip:Hide();
+end
+
+-- [[ AchievementAlertFrame ]] --
+function AchievementAlertFrame_OnLoad (self)
+ self:RegisterForClicks("LeftButtonUp");
+end
+
+function AchievementAlertFrame_FixAnchors ()
+ -- Temporary (here's hoping) workaround so that achievement alerts are anchored to loot roll windows. Eventually we want one system to handle placement for both alerts.
+ if ( not AchievementAlertFrame1 ) then
+ -- We haven't displayed any achievement alerts yet, so there's nothing to reanchor (read: this got called by LootFrame.lua)
+ return;
+ end
+
+ for i=NUM_GROUP_LOOT_FRAMES, 1, -1 do
+ local frame = _G["GroupLootFrame"..i];
+ if ( frame and frame:IsShown() ) then
+ AchievementAlertFrame1:SetPoint("BOTTOM", frame, "TOP", 0, 10);
+ return;
+ end
+ end
+
+ AchievementAlertFrame1:SetPoint("BOTTOM", UIParent, "BOTTOM", 0, 128);
+end
+
+function AchievementAlertFrame_ShowAlert (achievementID)
+ local frame = AchievementAlertFrame_GetAlertFrame();
+ local _, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo(achievementID);
+ if ( not frame ) then
+ -- We ran out of frames! Bail!
+ return;
+ end
+
+ _G[frame:GetName() .. "Name"]:SetText(name);
+
+ local shield = _G[frame:GetName() .. "Shield"];
+ AchievementShield_SetPoints(points, shield.points, GameFontNormal, GameFontNormalSmall);
+ if ( points == 0 ) then
+ shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields-NoPoints]]);
+ else
+ shield.icon:SetTexture([[Interface\AchievementFrame\UI-Achievement-Shields]]);
+ end
+
+ _G[frame:GetName() .. "IconTexture"]:SetTexture(icon);
+
+ frame.id = achievementID;
+
+ AlertFrame_AnimateIn(frame);
+
+ AlertFrame_FixAnchors();
+end
+
+function AchievementAlertFrame_GetAlertFrame()
+ local name, frame, previousFrame;
+ for i=1, MAX_ACHIEVEMENT_ALERTS do
+ name = "AchievementAlertFrame"..i;
+ frame = _G[name];
+ if ( frame ) then
+ if ( not frame:IsShown() ) then
+ return frame;
+ end
+ else
+ frame = CreateFrame("Button", name, UIParent, "AchievementAlertFrameTemplate");
+ if ( not previousFrame ) then
+ frame:SetPoint("BOTTOM", UIParent, "BOTTOM", 0, 128);
+ else
+ frame:SetPoint("BOTTOM", previousFrame, "TOP", 0, -10);
+ end
+ return frame;
+ end
+ previousFrame = frame;
+ end
+ return nil;
+end
+
+function AchievementAlertFrame_OnClick (self)
+ local id = self.id;
+ if ( not id ) then
+ return;
+ end
+
+ CloseAllWindows();
+ ShowUIPanel(AchievementFrame);
+
+ local _, _, _, achCompleted = GetAchievementInfo(id);
+ if ( achCompleted and (ACHIEVEMENTUI_SELECTEDFILTER == AchievementFrameFilters[ACHIEVEMENT_FILTER_INCOMPLETE].func) ) then
+ AchievementFrame_SetFilter(ACHIEVEMENT_FILTER_ALL);
+ elseif ( (not achCompleted) and (ACHIEVEMENTUI_SELECTEDFILTER == AchievementFrameFilters[ACHIEVEMENT_FILTER_COMPLETE].func) ) then
+ AchievementFrame_SetFilter(ACHIEVEMENT_FILTER_ALL);
+ end
+
+ AchievementFrame_SelectAchievement(id)
+end
+
+function AchievementAlertFrame_OnHide (self)
+ AlertFrame_FixAnchors();
+end
\ No newline at end of file
diff --git a/reference/FrameXML/AlertFrames.xml b/reference/FrameXML/AlertFrames.xml
new file mode 100644
index 0000000..6b97a7e
--- /dev/null
+++ b/reference/FrameXML/AlertFrames.xml
@@ -0,0 +1,447 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetRegionParent():Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetRegionParent():Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ self.bling = _G[name .. "Bling"];
+ self.texture = _G[name .. "Texture"];
+ self.frame = _G[name .. "Overlay"];
+
+ self.Desaturate =
+ function (self)
+ self.bling:SetVertexColor(.6, .6, .6, 1);
+ self.frame:SetVertexColor(.75, .75, .75, 1);
+ self.texture:SetVertexColor(.55, .55, .55, 1);
+ end
+
+ self.Saturate =
+ function (self)
+ self.bling:SetVertexColor(1, 1, 1, 1);
+ self.frame:SetVertexColor(1, 1, 1, 1);
+ self.texture:SetVertexColor(1, 1, 1, 1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AchievementShield_OnLoad(self);
+
+
+
+
+
+
+ AchievementAlertFrame_OnLoad(self);
+
+
+ AchievementAlertFrame_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/AlternatePowerBar.lua b/reference/FrameXML/AlternatePowerBar.lua
new file mode 100644
index 0000000..2b6516a
--- /dev/null
+++ b/reference/FrameXML/AlternatePowerBar.lua
@@ -0,0 +1,69 @@
+ADDITIONAL_POWER_BAR_NAME = "MANA";
+ADDITIONAL_POWER_BAR_INDEX = 0;
+
+function AlternatePowerBar_OnLoad(self)
+ self.textLockable = 1;
+ self.cvar = "playerStatusText";
+ self.cvarLabel = "STATUS_TEXT_PLAYER";
+ AlternatePowerBar_Initialize(self);
+ TextStatusBar_Initialize(self);
+end
+
+function AlternatePowerBar_Initialize(self)
+ if ( not self.powerName ) then
+ self.powerName = ADDITIONAL_POWER_BAR_NAME;
+ self.powerIndex = ADDITIONAL_POWER_BAR_INDEX;
+ end
+
+ self:RegisterEvent("UNIT_"..self.powerName);
+ self:RegisterEvent("UNIT_MAX"..self.powerName);
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("UNIT_DISPLAYPOWER");
+
+ SetTextStatusBarText(self, _G[self:GetName().."Text"])
+
+ local info = PowerBarColor[self.powerName];
+ self:SetStatusBarColor(info.r, info.g, info.b);
+end
+
+function AlternatePowerBar_OnEvent(self, event, arg1)
+ local parent = self:GetParent();
+ if ( event == "UNIT_DISPLAYPOWER" ) then
+ AlternatePowerBar_UpdatePowerType(self);
+ elseif ( event=="PLAYER_ENTERING_WORLD" ) then
+ AlternatePowerBar_UpdateMaxValues(self);
+ AlternatePowerBar_UpdateValue(self);
+ AlternatePowerBar_UpdatePowerType(self);
+ elseif( (event == "UNIT_MAXMANA") and (arg1 == parent.unit) ) then
+ AlternatePowerBar_UpdateMaxValues(self);
+ elseif ( self:IsShown() ) then
+ if ( (event == "UNIT_MANA") and (arg1 == parent.unit) ) then
+ AlternatePowerBar_UpdateValue(self);
+ end
+ end
+end
+
+function AlternatePowerBar_OnUpdate(self, elapsed)
+ AlternatePowerBar_UpdateValue(self);
+end
+
+function AlternatePowerBar_UpdateValue(self)
+ local currmana = UnitPower(self:GetParent().unit,self.powerIndex);
+ self:SetValue(currmana);
+ self.value = currmana
+end
+
+function AlternatePowerBar_UpdateMaxValues(self)
+ local maxmana = UnitPowerMax(self:GetParent().unit,self.powerIndex);
+ self:SetMinMaxValues(0,maxmana);
+end
+
+function AlternatePowerBar_UpdatePowerType(self)
+ if ( (UnitPowerType(self:GetParent().unit) ~= self.powerIndex) and (UnitPowerMax(self:GetParent().unit,self.powerIndex) ~= 0) ) then
+ self.pauseUpdates = false;
+ self:Show();
+ else
+ self.pauseUpdates = true;
+ self:Hide();
+ end
+end
diff --git a/reference/FrameXML/AlternatePowerBar.xml b/reference/FrameXML/AlternatePowerBar.xml
new file mode 100644
index 0000000..87c8141
--- /dev/null
+++ b/reference/FrameXML/AlternatePowerBar.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AlternatePowerBar_OnEvent(self, event, ...);
+ TextStatusBar_OnEvent(self, event, ...);
+
+
+ AlternatePowerBar_OnUpdate(self, elapsed);
+
+
+ self:GetParent():Click(button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/AnimTimerFrame.xml b/reference/FrameXML/AnimTimerFrame.xml
new file mode 100644
index 0000000..114ddc1
--- /dev/null
+++ b/reference/FrameXML/AnimTimerFrame.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+ if ( IsInGuild() ) then
+ GuildRoster();
+ end
+
+
+
+
+
+
+ self:Play();
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/AnimationSystem.lua b/reference/FrameXML/AnimationSystem.lua
new file mode 100644
index 0000000..046f0e2
--- /dev/null
+++ b/reference/FrameXML/AnimationSystem.lua
@@ -0,0 +1,64 @@
+--[[ animTable = { --Note that only consistent data should be in here. These tables are meant to be shared across "sessions" of animations. Put changing data in the frame.
+ totalTime = number, --Time to complete the animation in seconds.
+ updateFunc = function, --The function called to do the actual change. Takes self, elapsed fraction. Usually frame.SetPoint, frame.SetAlpha, ect.
+ getPosFunc = function, --The function returning the data being passed into updateFunc. For example. might return .18 if updateFunc is frame.SetAlpha.
+--]]
+local AnimatingFrames = {};
+
+local AnimUpdateFrame = CreateFrame("Frame");
+
+local function Animation_UpdateFrame(self, animElapsed, animTable)
+ local totalTime = animTable.totalTime
+ if ( animElapsed and (animElapsed < totalTime)) then --Should be animating
+ local elapsedFraction = self.animReverse and (1-animElapsed/totalTime) or (animElapsed/totalTime);
+ animTable.updateFunc(self, animTable.getPosFunc(self, elapsedFraction));
+ else --Just finished animating
+ animTable.updateFunc(self, animTable.getPosFunc(self, self.animReverse and 0 or 1));
+ self.animating = false;
+
+ AnimatingFrames[self][animTable.updateFunc] = 0; --We use 0 instead of nil'ing out because we don't want to mess with 'next' (used in pairs)
+
+ if ( self.animPostFunc ) then
+ self.animPostFunc(self);
+ end
+
+ end
+end
+
+local totalElapsed = 0;
+local function Animation_OnUpdate(self, elapsed)
+ totalElapsed = totalElapsed + elapsed;
+ local isAnyFrameAnimating = false;
+ for frame, frameTable in pairs(AnimatingFrames) do
+ for frameTable, animTable in pairs(frameTable) do
+ if ( animTable ~= 0 ) then
+ Animation_UpdateFrame(frame, totalElapsed - frame.animStartTime, animTable);
+ isAnyFrameAnimating = true;
+ end
+ end
+ end
+ if ( not isAnyFrameAnimating ) then
+ table.wipe(AnimatingFrames);
+ AnimUpdateFrame:SetScript("OnUpdate", nil);
+ end
+end
+
+function SetUpAnimation(frame, animTable, postFunc, reverse)
+ if ( type(animTable.updateFunc) == "string" ) then
+ animTable.updateFunc = frame[animTable.updateFunc];
+ end
+ if ( not AnimatingFrames[frame] ) then
+ AnimatingFrames[frame] = {};
+ end
+
+ AnimatingFrames[frame][animTable.updateFunc] = animTable;
+
+ frame.animStartTime = totalElapsed;
+ frame.animReverse = reverse;
+ frame.animPostFunc = postFunc;
+ frame.animating = true;
+
+ animTable.updateFunc(frame, animTable.getPosFunc(frame, frame.animReverse and 1 or 0));
+
+ AnimUpdateFrame:SetScript("OnUpdate", Animation_OnUpdate);
+end
diff --git a/reference/FrameXML/ArenaFrame.lua b/reference/FrameXML/ArenaFrame.lua
new file mode 100644
index 0000000..959e819
--- /dev/null
+++ b/reference/FrameXML/ArenaFrame.lua
@@ -0,0 +1,125 @@
+MAX_ARENA_BATTLES = 6;
+NO_ARENA_SEASON = 0;
+function ArenaFrame_OnLoad (self)
+ self:RegisterEvent("BATTLEFIELDS_SHOW");
+ self:RegisterEvent("BATTLEFIELDS_CLOSED");
+ self:RegisterEvent("UPDATE_BATTLEFIELD_STATUS");
+ self:RegisterEvent("PARTY_LEADER_CHANGED");
+end
+
+function ArenaFrame_OnEvent (self, event, ...)
+ if ( IsBattlefieldArena() ) then
+ if ( event == "BATTLEFIELDS_SHOW" ) then
+ ShowUIPanel(ArenaFrame);
+ if ( ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0)) and IsPartyLeader() and GetCurrentArenaSeason()~=NO_ARENA_SEASON) then
+ if ( not ArenaFrame.selection ) then
+ ArenaFrame.selection = 1;
+ end
+ else
+ if ( (not ArenaFrame.selection) or (ArenaFrame.selection < 4) ) then
+ ArenaFrame.selection = 4;
+ end
+ end
+
+ if ( GetCurrentArenaSeason()==NO_ARENA_SEASON ) then
+ ArenaFrameZoneDescription:SetText(ARENA_MASTER_NO_SEASON_TEXT);
+ else
+ ArenaFrameZoneDescription:SetText(ARENA_MASTER_TEXT)
+ end
+
+ if ( not ArenaFrame:IsShown() ) then
+ CloseBattlefield();
+ return;
+ end
+ ArenaFrame_Update(self);
+ elseif ( event == "BATTLEFIELDS_CLOSED" ) then
+ HideUIPanel(ArenaFrame);
+ elseif ( event == "UPDATE_BATTLEFIELD_STATUS" ) then
+ ArenaFrame_Update(self);
+ end
+ if ( event == "PARTY_LEADER_CHANGED" ) then
+ ArenaFrame_Update(self);
+ end
+ end
+end
+
+function ArenaButton_OnClick(self)
+ local id = self:GetID();
+ _G["ArenaZone"..id]:LockHighlight();
+ ArenaFrame.selection = id;
+ ArenaFrame_Update();
+end
+
+function ArenaFrame_Update (self)
+ local ARENA_TEAMS = {};
+ ARENA_TEAMS[1] = {size = 2};
+ ARENA_TEAMS[2] = {size = 3};
+ ARENA_TEAMS[3] = {size = 5};
+
+ local button, battleType, teamSize;
+
+ for i=1, MAX_ARENA_BATTLES, 1 do
+ button = _G["ArenaZone"..i];
+ battleType = ARENA_RATED;
+ teamSize = i;
+ -- if buttons begin a second set of buttons for casual games, change text elements.
+ button:Enable();
+ if ( i > MAX_ARENA_TEAMS ) then
+ teamSize = teamSize - MAX_ARENA_TEAMS;
+ battleType = ARENA_CASUAL;
+ elseif ( GetCurrentArenaSeason()==NO_ARENA_SEASON ) then
+ button:Disable();
+ end
+ -- build text string to populate each element.
+ button:SetText(format(PVP_TEAMTYPE, ARENA_TEAMS[teamSize].size, ARENA_TEAMS[teamSize].size).." "..battleType);
+ -- Set selected instance
+ if ( i == ArenaFrame.selection ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+ end
+
+ if ( ArenaFrame.selection > MAX_ARENA_TEAMS ) then
+ ArenaFrameJoinButton:Enable();
+ else
+ ArenaFrameJoinButton:Disable();
+ end
+
+ if ( CanJoinBattlefieldAsGroup() ) then
+ if ( ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0)) and IsPartyLeader() and GetCurrentArenaSeason()~=NO_ARENA_SEASON) then
+ -- If this is true then can join as a group
+ ArenaFrameGroupJoinButton:Enable();
+ else
+ ArenaFrameGroupJoinButton:Disable();
+ end
+ ArenaFrameGroupJoinButton:Show();
+ else
+ ArenaFrameGroupJoinButton:Hide();
+ end
+
+ -- Enable or disable the group join button
+ if ( CanJoinBattlefieldAsGroup() ) then
+ if ( ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0)) and IsPartyLeader() ) then
+ -- If this is true then can join as a group
+ BattlefieldFrameGroupJoinButton:Enable();
+ else
+ BattlefieldFrameGroupJoinButton:Disable();
+ end
+ BattlefieldFrameGroupJoinButton:Show();
+ else
+ BattlefieldFrameGroupJoinButton:Hide();
+ end
+end
+
+function ArenaFrameJoinButton_OnClick(self)
+ local GROUPJOIN_BUTTONID = 2;
+ if ( ArenaFrame.selection < 4 ) then
+ JoinBattlefield(ArenaFrame.selection, 1, 1);
+ elseif ( ArenaFrame.selection > 3 and self:GetID() == GROUPJOIN_BUTTONID ) then
+ JoinBattlefield(ArenaFrame.selection - 3, 1);
+ else
+ JoinBattlefield(ArenaFrame.selection - 3);
+ end
+ HideUIPanel(ArenaFrame);
+end
diff --git a/reference/FrameXML/ArenaFrame.xml b/reference/FrameXML/ArenaFrame.xml
new file mode 100644
index 0000000..327f421
--- /dev/null
+++ b/reference/FrameXML/ArenaFrame.xml
@@ -0,0 +1,295 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Highlight"]:SetVertexColor(1.0, 0.82, 0);
+
+
+ ArenaButton_OnClick(self, button, down);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self)
+ GameTooltip:SetText(BATTLEFIELD_GROUP_JOIN, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_BATTLEFIELD_GROUP_JOIN, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoOpen");
+
+
+ CloseBattlefield();
+ PlaySound("igCharacterInfoClose");
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/ArenaRegistrarFrame.lua b/reference/FrameXML/ArenaRegistrarFrame.lua
new file mode 100644
index 0000000..c7b6d22
--- /dev/null
+++ b/reference/FrameXML/ArenaRegistrarFrame.lua
@@ -0,0 +1,214 @@
+MAX_TEAM_EMBLEMS = 102;
+MAX_TEAM_BORDERS = 6;
+
+local ARENA_TEAMSIZES = { 2, 3, 5 }
+
+function ArenaRegistrar_OnLoad (self)
+ self:RegisterEvent("PETITION_VENDOR_SHOW");
+ self:RegisterEvent("PETITION_VENDOR_CLOSED");
+ self:RegisterEvent("PETITION_VENDOR_UPDATE");
+end
+
+function ArenaRegistrar_OnEvent (self, event, ...)
+ if ( event == "PETITION_VENDOR_SHOW" ) then
+ ShowUIPanel(ArenaRegistrarFrame);
+ if ( not ArenaRegistrarFrame:IsShown() ) then
+ if ( not PVPBannerFrame:IsShown() ) then
+ ClosePetitionVendor();
+ end
+ end
+ elseif ( event == "PETITION_VENDOR_CLOSED" ) then
+ HideUIPanel(ArenaRegistrarFrame);
+ HideUIPanel(PVPBannerFrame);
+ elseif ( event == "PETITION_VENDOR_UPDATE" ) then
+ if ( HasFilledPetition() ) then
+ ArenaRegistrarButton4:Show();
+ ArenaRegistrarButton5:Show();
+ ArenaRegistrarButton6:Show();
+ RegistrationText:Show();
+ else
+ ArenaRegistrarButton4:Hide();
+ ArenaRegistrarButton5:Hide();
+ ArenaRegistrarButton6:Hide();
+ RegistrationText:Hide();
+ end
+ --If we clicked a button then show the appropriate purchase frame
+ if ( ArenaRegistrarPurchaseFrame.waitingForPetitionInfo ) then
+ ArenaRegistrar_UpdatePrice();
+ ArenaRegistrarPurchaseFrame.waitingForPetitionInfo = nil;
+ end
+ end
+end
+
+function ArenaRegistrar_OnShow (self)
+ self.dontClose = nil;
+ ArenaRegistrarFrame.bannerDesign = nil;
+ ArenaRegistrarGreetingFrame:Show();
+ ArenaRegistrarPurchaseFrame:Hide();
+ SetPortraitTexture(ArenaRegistrarFramePortrait, "NPC");
+ ArenaRegistrarFrameNpcNameText:SetText(UnitName("NPC"));
+ PlaySound("igQuestListOpen");
+end
+
+function ArenaRegistrar_ShowPurchaseFrame (self)
+ local id = self:GetID();
+ local teamSize = ARENA_TEAMSIZES[id];
+ ArenaRegistrarPurchaseFrame.id = id;
+ PVPBannerFrame.teamSize = teamSize;
+ if ( GetPetitionItemInfo(id) ) then
+ ArenaRegistrar_UpdatePrice();
+ else
+ -- Waiting for the callback
+ ArenaRegistrarPurchaseFrame.waitingForPetitionInfo = 1;
+ end
+end
+
+function ArenaRegistrar_UpdatePrice ()
+ local name, texture, price = GetPetitionItemInfo(ArenaRegistrarPurchaseFrame.id);
+ MoneyFrame_Update("ArenaRegistrarMoneyFrame", price);
+ ArenaRegistrarPurchaseFrame:Show();
+ ArenaRegistrarGreetingFrame:Hide();
+end
+
+function ArenaRegistrar_TurnInPetition (self)
+ local id = self:GetID();
+ local teamSize = ARENA_TEAMSIZES[id];
+
+ ArenaRegistrarFrame.bannerDesign = 1;
+ ArenaRegistrarFrame.dontClose = 1;
+ HideUIPanel(self:GetParent());
+ SetPortraitTexture(PVPBannerFramePortrait,"npc");
+ PVPBannerFrame.teamSize = teamSize;
+ ShowUIPanel(PVPBannerFrame);
+end
+
+function PVPBannerFrame_SetBannerColor ()
+ local r,g,b = ColorPickerFrame:GetColorRGB();
+ PVPBannerFrameStandardBanner.r, PVPBannerFrameStandardBanner.g, PVPBannerFrameStandardBanner.b = r, g, b;
+ PVPBannerFrameStandardBanner:SetVertexColor(r, g, b);
+end
+
+function PVPBannerFrame_SetEmblemColor ()
+ local r,g,b = ColorPickerFrame:GetColorRGB();
+ PVPBannerFrameStandardEmblem.r, PVPBannerFrameStandardEmblem.g, PVPBannerFrameStandardEmblem.b = r, g, b;
+ PVPBannerFrameStandardEmblem:SetVertexColor(r, g, b);
+end
+
+function PVPBannerFrame_SetBorderColor ()
+ local r,g,b = ColorPickerFrame:GetColorRGB();
+ PVPBannerFrameStandardBorder.r, PVPBannerFrameStandardBorder.g, PVPBannerFrameStandardBorder.b = r, g, b;
+ PVPBannerFrameStandardBorder:SetVertexColor(r, g, b);
+end
+
+function PVPBannerFrame_OnShow (self)
+ PVPBannerFrameStandardEmblem.id = random(MAX_TEAM_EMBLEMS);
+ PVPBannerFrameStandardBorder.id = random(MAX_TEAM_BORDERS);
+
+ local bannerColor = {r = 0, g = 0, b = 0};
+ local borderColor = {r = 0, g = 0, b = 0};
+ local emblemColor = {r = 0, g = 0, b = 0};
+
+ local Standard = {Banner = bannerColor, Border = borderColor, Emblem = emblemColor};
+
+ for index, value in pairs(Standard) do
+ for k, v in pairs(value) do
+ value[k] = random(100) / 100;
+ end
+ _G["PVPBannerFrameStandard"..index]:SetVertexColor(value.r, value.g, value.b);
+ end
+
+ PVPBannerFrameStandardEmblemWatermark:SetAlpha(0.4);
+ PVPBannerFrameStandardBanner:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..PVPBannerFrame.teamSize);
+ PVPBannerFrameStandardBorder:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..PVPBannerFrame.teamSize.."-Border-"..PVPBannerFrameStandardBorder.id);
+ PVPBannerFrameStandardEmblem:SetTexture("Interface\\PVPFrame\\Icons\\PVP-Banner-Emblem-"..PVPBannerFrameStandardEmblem.id);
+ PVPBannerFrameStandardEmblemWatermark:SetTexture("Interface\\PVPFrame\\Icons\\PVP-Banner-Emblem-"..PVPBannerFrameStandardEmblem.id);
+end
+
+function PVPBannerFrame_OpenColorPicker (button, texture)
+ local r,g,b = texture:GetVertexColor();
+ if ( texture == PVPBannerFrameStandardEmblem ) then
+ ColorPickerFrame.func = PVPBannerFrame_SetEmblemColor;
+ elseif ( texture == PVPBannerFrameStandardBanner ) then
+ ColorPickerFrame.func = PVPBannerFrame_SetBannerColor;
+ elseif ( texture == PVPBannerFrameStandardBorder ) then
+ ColorPickerFrame.func = PVPBannerFrame_SetBorderColor;
+ end
+ ColorPickerFrame:SetColorRGB(r, g, b);
+ ShowUIPanel(ColorPickerFrame);
+end
+
+function PVPBannerCustomization_Left (self)
+ local id = self:GetParent():GetID();
+
+ local texture;
+ if ( id == 1 ) then
+ texture = PVPBannerFrameStandardEmblem;
+ if ( texture.id == 1 ) then
+ texture.id = MAX_TEAM_EMBLEMS;
+ else
+ texture.id = texture.id - 1;
+ end
+ texture:SetTexture("Interface\\PVPFrame\\Icons\\PVP-Banner-Emblem-"..texture.id);
+ PVPBannerFrameStandardEmblemWatermark:SetTexture("Interface\\PVPFrame\\Icons\\PVP-Banner-Emblem-"..texture.id);
+ else
+ texture = PVPBannerFrameStandardBorder;
+ if ( texture.id == 1 ) then
+ texture.id = MAX_TEAM_BORDERS;
+ else
+ texture.id = texture.id - 1;
+ end
+ texture:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..PVPBannerFrame.teamSize.."-Border-"..texture.id);
+ end
+ PlaySound("gsCharacterCreationLook");
+end
+
+function PVPBannerCustomization_Right (self)
+ local id = self:GetParent():GetID();
+
+ local texture;
+ if ( id == 1 ) then
+ texture = PVPBannerFrameStandardEmblem;
+ if ( texture.id == MAX_TEAM_EMBLEMS ) then
+ texture.id = 1;
+ else
+ texture.id = texture.id + 1;
+ end
+ texture:SetTexture("Interface\\PVPFrame\\Icons\\PVP-Banner-Emblem-"..texture.id);
+ PVPBannerFrameStandardEmblemWatermark:SetTexture("Interface\\PVPFrame\\Icons\\PVP-Banner-Emblem-"..texture.id);
+ else
+ texture = PVPBannerFrameStandardBorder;
+ if ( texture.id == MAX_TEAM_BORDERS ) then
+ texture.id = 1;
+ else
+ texture.id = texture.id + 1;
+ end
+ texture:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..PVPBannerFrame.teamSize.."-Border-"..texture.id);
+ end
+ PlaySound("gsCharacterCreationLook");
+end
+
+function PVPBannerFrame_SaveBanner (self)
+ local teamSize, iconStyle, borderStyle;
+
+ local bgColor = {r = 0, g = 0, b = 0};
+ local borderColor = {r = 0, g = 0, b = 0};
+ local iconColor = {r = 0, g = 0, b = 0};
+
+ local color = {bgColor, borderColor, iconColor};
+
+ -- Get color values
+ bgColor.r, bgColor.g, bgColor.b = PVPBannerFrameStandardBanner:GetVertexColor();
+ borderColor.r, borderColor.g, borderColor.b = PVPBannerFrameStandardBorder:GetVertexColor();
+ iconColor.r, iconColor.g, iconColor.b = PVPBannerFrameStandardEmblem:GetVertexColor();
+
+ -- Get team size
+ teamSize = PVPBannerFrame.teamSize;
+ -- Get border style
+ borderStyle = PVPBannerFrameStandardBorder.id;
+
+ -- Get emblem style
+ iconStyle = PVPBannerFrameStandardEmblem.id;
+ TurnInArenaPetition(teamSize, bgColor.r, bgColor.g, bgColor.b, iconStyle, iconColor.r, iconColor.g, iconColor.b, borderStyle, borderColor.r, borderColor.g, borderColor.b);
+ HideUIPanel(self:GetParent());
+ ClosePetitionVendor();
+end
\ No newline at end of file
diff --git a/reference/FrameXML/ArenaRegistrarFrame.xml b/reference/FrameXML/ArenaRegistrarFrame.xml
new file mode 100644
index 0000000..c26e65b
--- /dev/null
+++ b/reference/FrameXML/ArenaRegistrarFrame.xml
@@ -0,0 +1,959 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(ArenaRegistrarFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(ArenaRegistrarFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BuyPetition(ArenaRegistrarPurchaseFrame.id, ArenaRegistrarFrameEditBox:GetText());
+ HideUIPanel(ArenaRegistrarFrame);
+ ChatEdit_FocusActiveWindow();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BuyPetition(ArenaRegistrarPurchaseFrame.id, ArenaRegistrarFrameEditBox:GetText());
+ HideUIPanel(ArenaRegistrarFrame);
+ ChatEdit_FocusActiveWindow();
+
+
+ HideUIPanel(ArenaRegistrarFrame);
+ ChatEdit_FocusActiveWindow();
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igQuestListClose");
+ if ( not self.dontClose ) then
+ ClosePetitionVendor();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPBannerCustomization_Left(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPBannerCustomization_Right(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPBannerFrameCustomization1Text:SetText(EMBLEM_SYMBOL);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPBannerFrameCustomization2Text:SetText(EMBLEM_BORDER);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPBannerFrame_OpenColorPicker(self, PVPBannerFrameStandardEmblem);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPBannerFrame_OpenColorPicker(self, PVPBannerFrameStandardBorder);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPBannerFrame_OpenColorPicker(self, PVPBannerFrameStandardBanner);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(ColorPickerFrame);
+ ClosePetitionVendor();
+
+
+
+
diff --git a/reference/FrameXML/AudioOptionsFrame.lua b/reference/FrameXML/AudioOptionsFrame.lua
new file mode 100644
index 0000000..db5376c
--- /dev/null
+++ b/reference/FrameXML/AudioOptionsFrame.lua
@@ -0,0 +1,87 @@
+-- if you change something here you probably want to change the glue version too
+
+function AudioOptionsFrame_Toggle ()
+ if ( AudioOptionsFrame:IsShown() ) then
+ AudioOptionsFrame:Hide();
+ else
+ AudioOptionsFrame:Show();
+ end
+end
+
+function AudioOptionsFrame_SetAllToDefaults ()
+ OptionsFrame_SetAllToDefaults(AudioOptionsFrame);
+
+ if ( AudioOptionsFrame.audioRestart ) then
+ AudioOptionsFrame_AudioRestart();
+ end
+end
+
+function AudioOptionsFrame_SetCurrentToDefaults ()
+ OptionsFrame_SetCurrentToDefaults(AudioOptionsFrame);
+
+ if ( AudioOptionsFrame.audioRestart ) then
+ AudioOptionsFrame_AudioRestart();
+ end
+end
+
+function AudioOptionsFrame_AudioRestart ()
+ AudioOptionsFrame.audioRestart = nil;
+ Sound_GameSystem_RestartSoundSystem();
+end
+
+function AudioOptionsFrame_OnLoad (self)
+ OptionsFrame_OnLoad(self);
+
+ AudioOptionsFrame:SetHeight(540);
+ AudioOptionsFrameCategoryFrame:SetHeight(449);
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+end
+
+function AudioOptionsFrame_OnEvent (self, event, ...)
+ if ( IsVoiceChatAllowedByServer() ) then
+ _G[self:GetName().."HeaderText"]:SetText(SOUNDOPTIONS_MENU);
+ else
+ _G[self:GetName().."HeaderText"]:SetText(VOICE_SOUND);
+ end
+end
+
+function AudioOptionsFrame_OnHide (self)
+ OptionsFrame_OnHide(self);
+
+ if ( AudioOptionsFrame.gameRestart ) then
+ StaticPopup_Show("CLIENT_RESTART_ALERT");
+ AudioOptionsFrame.gameRestart = nil;
+ elseif ( AudioOptionsFrame.logout ) then
+ StaticPopup_Show("CLIENT_LOGOUT_ALERT");
+ AudioOptionsFrame.logout = nil;
+ end
+end
+
+function AudioOptionsFrameCancel_OnClick (self, button)
+ OptionsFrameCancel_OnClick(AudioOptionsFrame);
+
+ if ( AudioOptionsFrame.audioRestart ) then
+ AudioOptionsFrame_AudioRestart();
+ end
+
+ AudioOptionsFrame.gameRestart = nil;
+ AudioOptionsFrame.logout = nil;
+
+ AudioOptionsFrame_Toggle();
+end
+
+function AudioOptionsFrameOkay_OnClick (self, button)
+ OptionsFrameOkay_OnClick(AudioOptionsFrame);
+
+ if ( AudioOptionsFrame.audioRestart ) then
+ AudioOptionsFrame_AudioRestart();
+ end
+
+ AudioOptionsFrame_Toggle();
+end
+
+function AudioOptionsFrameDefault_OnClick ()
+ OptionsFrameDefault_OnClick(AudioOptionsFrame);
+
+ StaticPopup_Show("CONFIRM_RESET_AUDIO_SETTINGS");
+end
diff --git a/reference/FrameXML/AudioOptionsFrame.xml b/reference/FrameXML/AudioOptionsFrame.xml
new file mode 100644
index 0000000..98e59dc
--- /dev/null
+++ b/reference/FrameXML/AudioOptionsFrame.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ AudioOptionsFrameDefault_OnClick(self, button);
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/AudioOptionsPanels.lua b/reference/FrameXML/AudioOptionsPanels.lua
new file mode 100644
index 0000000..7928327
--- /dev/null
+++ b/reference/FrameXML/AudioOptionsPanels.lua
@@ -0,0 +1,823 @@
+-- if you change something here you probably want to change the glue version too
+
+local VOICE_OPTIONS_BINDING_SUCCESS_FADE = 3;
+local VOICE_OPTIONS_BINDING_FAIL_FADE = 6;
+
+
+-- [[ Generic Audio Options Panel ]] --
+
+function AudioOptionsPanel_CheckButton_OnClick (checkButton)
+ local setting = "0";
+ if ( checkButton:GetChecked() ) then
+ if ( not checkButton.invert ) then
+ setting = "1"
+ end
+ elseif ( checkButton.invert ) then
+ setting = "1"
+ end
+
+ local prevValue = checkButton:GetValue();
+
+ checkButton:SetValue(setting);
+
+ if ( checkButton.restart and prevValue ~= setting ) then
+ AudioOptionsFrame_AudioRestart();
+ end
+
+ if ( checkButton.dependentControls ) then
+ if ( checkButton:GetChecked() ) then
+ for _, control in next, checkButton.dependentControls do
+ control:Enable();
+ end
+ else
+ for _, control in next, checkButton.dependentControls do
+ control:Disable();
+ end
+ end
+ end
+
+ if ( checkButton.setFunc ) then
+ checkButton.setFunc(setting);
+ end
+end
+
+
+local function AudioOptionsPanel_Okay (self)
+ for _, control in next, self.controls do
+ if ( control.value and control:GetValue() ~= control.value ) then
+ if ( control.restart ) then
+ AudioOptionsFrame.audioRestart = true;
+ end
+ control:SetValue(control.value);
+ end
+ end
+ MiniMapVoiceChat_Update();
+end
+
+local function AudioOptionsPanel_Cancel (self)
+ for _, control in next, self.controls do
+ if ( control.oldValue ) then
+ if ( control.value and control.value ~= control.oldValue ) then
+ if ( control.restart ) then
+ AudioOptionsFrame.audioRestart = true;
+ end
+ control:SetValue(control.oldValue);
+ end
+ elseif ( control.value ) then
+ if ( control:GetValue() ~= control.value ) then
+ if ( control.restart ) then
+ AudioOptionsFrame.audioRestart = true;
+ end
+ control:SetValue(control.value);
+ end
+ end
+ end
+end
+
+local function AudioOptionsPanel_Default (self)
+ for _, control in next, self.controls do
+ if ( control.defaultValue and control.value ~= control.defaultValue ) then
+ if ( control.restart ) then
+ AudioOptionsFrame.audioRestart = true;
+ end
+ control:SetValue(control.defaultValue);
+ control.value = control.defaultValue;
+ end
+ end
+ MiniMapVoiceChat_Update();
+end
+
+local function AudioOptionsPanel_Refresh (self)
+ for _, control in next, self.controls do
+ BlizzardOptionsPanel_RefreshControl(control);
+ -- record values so we can cancel back to this state
+ control.oldValue = control.value;
+ end
+end
+
+
+-- [[ Sound Options Panel ]] --
+
+SoundPanelOptions = {
+ Sound_EnableErrorSpeech = { text = "ENABLE_ERROR_SPEECH" },
+ Sound_EnableMusic = { text = "ENABLE_MUSIC" },
+ Sound_EnableAmbience = { text = "ENABLE_AMBIENCE" },
+ Sound_EnableSFX = { text = "ENABLE_SOUNDFX" },
+ Sound_EnableAllSound = { text = "ENABLE_SOUND" },
+ Sound_ListenerAtCharacter = { text = "ENABLE_SOUND_AT_CHARACTER" },
+ Sound_EnableEmoteSounds = { text = "ENABLE_EMOTE_SOUNDS" },
+ Sound_EnablePetSounds = { text = "ENABLE_PET_SOUNDS" },
+ Sound_ZoneMusicNoDelay = { text = "ENABLE_MUSIC_LOOPING" },
+ Sound_EnableSoundWhenGameIsInBG = { text = "ENABLE_BGSOUND" },
+ Sound_EnableReverb = { text = "ENABLE_REVERB" },
+ Sound_EnableHardware = { text = "ENABLE_HARDWARE" },
+ Sound_EnableSoftwareHRTF = { text = "ENABLE_SOFTWARE_HRTF" },
+ Sound_EnableDSPEffects = { text = "ENABLE_DSP_EFFECTS" },
+ Sound_SFXVolume = { text = "SOUND_VOLUME", minValue = 0, maxValue = 1, valueStep = 0.1, },
+ Sound_MusicVolume = { text = "MUSIC_VOLUME", minValue = 0, maxValue = 1, valueStep = 0.1, },
+ Sound_AmbienceVolume = { text = "AMBIENCE_VOLUME", minValue = 0, maxValue = 1, valueStep = 0.1, },
+ Sound_MasterVolume = { text = "MASTER_VOLUME", minValue = 0, maxValue = 1, valueStep = SOUND_MASTERVOLUME_STEP, },
+ Sound_NumChannels = { text = "SOUND_CHANNELS", minValue = 32, maxValue = 64, valueStep = 32, },
+ Sound_OutputQuality = { text = "SOUND_QUALITY", minValue = 0, maxValue = 2, valueStep = 1 },
+}
+
+function AudioOptionsSoundPanel_OnLoad (self)
+ self.name = SOUND_LABEL;
+ self.options = SoundPanelOptions;
+ BlizzardOptionsPanel_OnLoad(self, AudioOptionsPanel_Okay, AudioOptionsPanel_Cancel, AudioOptionsPanel_Default, AudioOptionsPanel_Refresh);
+ OptionsFrame_AddCategory(AudioOptionsFrame, self);
+end
+
+function AudioOptionsSoundPanelHardwareDropDown_OnLoad (self)
+ self.cvar = "Sound_OutputDriverIndex";
+
+ local selectedDriverIndex = BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+ local deviceName = Sound_GameSystem_GetOutputDriverNameByIndex(selectedDriverIndex);
+ self.defaultValue = BlizzardOptionsPanel_GetCVarDefaultSafe(self.cvar);
+ self.value = selectedDriverIndex;
+ self.newValue = selectedDriverIndex;
+ self.restart = true;
+
+ UIDropDownMenu_SetWidth(self, 136);
+ UIDropDownMenu_SetSelectedValue(self, selectedDriverIndex);
+ UIDropDownMenu_Initialize(self, AudioOptionsSoundPanelHardwareDropDown_Initialize);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ BlizzardOptionsPanel_SetCVarSafe(self.cvar, value);
+ end
+ self.GetValue =
+ function (self)
+ return BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+ end
+ self.RefreshValue =
+ function (self)
+ local selectedDriverIndex = BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+ local deviceName = Sound_GameSystem_GetOutputDriverNameByIndex(selectedDriverIndex);
+ self.value = selectedDriverIndex;
+ self.newValue = selectedDriverIndex;
+
+ UIDropDownMenu_SetSelectedValue(self, selectedDriverIndex);
+ UIDropDownMenu_Initialize(self, AudioOptionsSoundPanelHardwareDropDown_Initialize);
+ end
+end
+
+function AudioOptionsSoundPanelHardwareDropDown_Initialize(self)
+ local selectedValue = UIDropDownMenu_GetSelectedValue(self);
+ local num = Sound_GameSystem_GetNumOutputDrivers();
+ local info = UIDropDownMenu_CreateInfo();
+ for index=0,num-1,1 do
+ info.text = Sound_GameSystem_GetOutputDriverNameByIndex(index);
+ info.value = index;
+ info.checked = nil;
+ if (selectedValue and index == selectedValue) then
+ UIDropDownMenu_SetText(self, info.text);
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.func = AudioOptionsSoundPanelHardwareDropDown_OnClick;
+
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function AudioOptionsSoundPanelHardwareDropDown_OnClick(self)
+ local value = self.value;
+ local dropdown = AudioOptionsSoundPanelHardwareDropDown;
+ UIDropDownMenu_SetSelectedValue(dropdown, value);
+
+ local prevValue = dropdown:GetValue();
+ dropdown:SetValue(value);
+ if ( dropdown.restart and prevValue ~= value ) then
+ AudioOptionsFrame_AudioRestart();
+ end
+end
+
+
+-- [[ Voice Options Panel ]] --
+
+VoicePanelOptions = {
+ EnableVoiceChat = { text = "ENABLE_VOICECHAT" },
+ EnableMicrophone = { text = "ENABLE_MICROPHONE" },
+ OutboundChatVolume = { text = "VOICE_INPUT_VOLUME", minValue = 0.25, maxValue = 2.5, valueStep = 0.05 },
+ InboundChatVolume = { text = "VOICE_OUTPUT_VOLUME", minValue = 0, maxValue = 1, valueStep = 0.01 },
+ ChatSoundVolume = { text = "", minValue = 0, maxValue = 1, valueStep = 0.01, tooltip = OPTION_TOOLTIP_VOICE_SOUND },
+ ChatMusicVolume = { text = "", minValue = 0, maxValue = 1, valueStep = 0.01, tooltip = OPTION_TOOLTIP_VOICE_MUSIC },
+ ChatAmbienceVolume = { text = "", minValue = 0, maxValue = 1, valueStep = 0.01, tooltip = OPTION_TOOLTIP_VOICE_AMBIENCE },
+ PushToTalkSound = { text = "PUSHTOTALK_SOUND_TEXT" },
+ VoiceActivationSensitivity = { text = "VOICE_ACTIVATION_SENSITIVITY", minValue = 0, maxValue = 1, valueStep = 0.02 },
+}
+
+local AudioOptionsVoicePanelDisableList =
+{
+ AudioOptionsVoicePanelChatMode1Label = NORMAL_FONT_COLOR,
+ AudioOptionsVoicePanelAudioLabel = NORMAL_FONT_COLOR,
+ AudioOptionsVoicePanelAudioDescription = HIGHLIGHT_FONT_COLOR,
+ AudioOptionsVoicePanelAudioOff = HIGHLIGHT_FONT_COLOR,
+ AudioOptionsVoicePanelAudioNormal = HIGHLIGHT_FONT_COLOR,
+ AudioOptionsVoicePanelSpeakerVolumeLabel = NORMAL_FONT_COLOR,
+ AudioOptionsVoicePanelSoundFadeLabel = NORMAL_FONT_COLOR,
+ AudioOptionsVoicePanelMusicFadeLabel = NORMAL_FONT_COLOR,
+ AudioOptionsVoicePanelAmbienceFadeLabel = NORMAL_FONT_COLOR,
+};
+
+local AudioOptionsVoicePanelFrameMicrophoneList =
+{
+ AudioOptionsVoicePanelMicrophoneVolumeLabel = NORMAL_FONT_COLOR,
+ AudioOptionsVoicePanelMicTestText = NORMAL_FONT_COLOR,
+ PlayLoopbackSoundButtonTexture = NORMAL_FONT_COLOR,
+ RecordLoopbackSoundButtonTexture = RED_FONT_COLOR,
+};
+
+function AudioOptionsVoicePanel_Refresh (self)
+ AudioOptionsPanel_Refresh(self);
+ AudioOptionsVoicePanelEnableVoice_UpdateControls(GetCVar(AudioOptionsVoicePanelEnableVoice.cvar));
+ AudioOptionsVoicePanelBindingType_Update(GetCVar(AudioOptionsVoicePanelChatModeDropDown.cvar));
+ AudioOptionsVoicePanelKeyBindingButton_Refresh();
+ AudioOptionsVoicePanelKeyBindingButton_SetTooltip();
+end
+
+function AudioOptionsVoicePanel_OnLoad (self)
+ self.name = VOICE_LABEL;
+ self.options = VoicePanelOptions;
+ BlizzardOptionsPanel_OnLoad(self, AudioOptionsPanel_Okay, AudioOptionsPanel_Cancel, AudioOptionsPanel_Default, AudioOptionsVoicePanel_Refresh);
+ self:SetScript("OnEvent", AudioOptionsVoicePanel_OnEvent);
+end
+
+function AudioOptionsVoicePanel_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ if ( IsVoiceChatAllowedByServer() ) then
+ OptionsFrame_AddCategory(AudioOptionsFrame, self);
+ BlizzardOptionsPanel_OnEvent(self, event, ...);
+ end
+ self:UnregisterEvent(event);
+ end
+end
+
+function AudioOptionsVoicePanel_OnShow (self)
+ VoiceChatTalkers:SetAlpha(1);
+ VoiceChatTalkers.optionsLock = true;
+end
+
+function AudioOptionsVoicePanel_OnHide (self)
+ AudioOptionsVoicePanelKeyBindingButton_CancelBinding();
+ VoiceChatTalkers.optionsLock = nil;
+ if ( VoiceChatTalkers_CanHide() ) then
+ VoiceChatTalkers_FadeOut();
+ end
+end
+
+function AudioOptionsVoicePanelEnableVoice_UpdateControls (value)
+ local voiceChatEnabled = value == "1";
+ if ( VoiceIsDisabledByClient() ) then
+ --Comsat is disabled either because the computer is way old (No SSE) or another copy of WoW is running.
+ BlizzardOptionsPanel_SetCVarSafe("EnableVoiceChat", 0);
+ voiceChatEnabled = false;
+ AudioOptionsVoicePanelEnableVoice:Hide();
+ AudioOptionsVoicePanelDisabledMessage:Show();
+ elseif ( not AudioOptionsVoicePanelEnableVoice:IsShown() ) then
+ --Pretty certain this won't be changing dynamically, but better safe than sorry.
+ AudioOptionsVoicePanelEnableVoice:Show();
+ AudioOptionsVoicePanelDisabledMessage:Hide();
+ end
+ if ( voiceChatEnabled ) then
+ UIDropDownMenu_EnableDropDown(AudioOptionsVoicePanelOutputDeviceDropDown);
+ UIDropDownMenu_EnableDropDown(AudioOptionsVoicePanelChatModeDropDown);
+
+ AudioOptionsVoicePanelChatMode1KeyBindingButton:Enable();
+
+ for index, value in pairs(AudioOptionsVoicePanelDisableList) do
+ _G[index]:SetVertexColor(value.r, value.g, value.b);
+ end
+
+ BlizzardOptionsPanel_Slider_Enable(AudioOptionsVoicePanelVoiceActivateSlider);
+ BlizzardOptionsPanel_Slider_Enable(AudioOptionsVoicePanelSpeakerVolume);
+ BlizzardOptionsPanel_Slider_Enable(AudioOptionsVoicePanelSoundFade);
+ BlizzardOptionsPanel_Slider_Enable(AudioOptionsVoicePanelMusicFade);
+ BlizzardOptionsPanel_Slider_Enable(AudioOptionsVoicePanelAmbienceFade);
+
+ AudioOptionsVoicePanelEnableMicrophone:Enable();
+ AudioOptionsVoicePanelPushToTalkSound:Enable();
+ AudioOptionsVoicePanelEnableMicrophone_UpdateControls(AudioOptionsVoicePanelEnableMicrophone:GetChecked());
+
+ if ( ChannelPullout:IsShown() ) then
+ ChannelPullout_ToggleDisplay();
+ end
+ else
+ UIDropDownMenu_DisableDropDown(AudioOptionsVoicePanelOutputDeviceDropDown);
+ UIDropDownMenu_DisableDropDown(AudioOptionsVoicePanelChatModeDropDown);
+
+ AudioOptionsVoicePanelChatMode1KeyBindingButton:Disable();
+
+ for index, value in pairs(AudioOptionsVoicePanelDisableList) do
+ _G[index]:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+
+ BlizzardOptionsPanel_Slider_Disable(AudioOptionsVoicePanelVoiceActivateSlider);
+ BlizzardOptionsPanel_Slider_Disable(AudioOptionsVoicePanelSpeakerVolume);
+ BlizzardOptionsPanel_Slider_Disable(AudioOptionsVoicePanelSoundFade);
+ BlizzardOptionsPanel_Slider_Disable(AudioOptionsVoicePanelMusicFade);
+ BlizzardOptionsPanel_Slider_Disable(AudioOptionsVoicePanelAmbienceFade);
+
+ AudioOptionsVoicePanelEnableMicrophone:Disable();
+ AudioOptionsVoicePanelPushToTalkSound:Disable();
+ AudioOptionsVoicePanelEnableMicrophone_UpdateControls(AudioOptionsVoicePanelEnableMicrophone:GetChecked());
+
+ if ( ChannelPullout:IsShown() ) then
+ ChannelPullout_ToggleDisplay();
+ end
+ end
+end
+
+function AudioOptionsVoicePanel_DisableMicrophoneControls ()
+ UIDropDownMenu_DisableDropDown(AudioOptionsVoicePanelInputDeviceDropDown);
+ RecordLoopbackSoundButton:Disable();
+ PlayLoopbackSoundButton:Disable();
+ VoiceChat_StopRecordingLoopbackSound();
+ VoiceChat_StopPlayingLoopbackSound();
+
+ for index in pairs(AudioOptionsVoicePanelFrameMicrophoneList) do
+ _G[index]:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+
+ BlizzardOptionsPanel_Slider_Disable(AudioOptionsVoicePanelMicrophoneVolume);
+end
+
+function AudioOptionsVoicePanel_EnableMicrophoneControls ()
+ UIDropDownMenu_EnableDropDown(AudioOptionsVoicePanelInputDeviceDropDown);
+ RecordLoopbackSoundButton:Enable();
+ PlayLoopbackSoundButton:Enable();
+
+ for index, value in pairs(AudioOptionsVoicePanelFrameMicrophoneList) do
+ _G[index]:SetVertexColor(value.r, value.g, value.b);
+ end
+
+ BlizzardOptionsPanel_Slider_Enable(AudioOptionsVoicePanelMicrophoneVolume);
+end
+
+function AudioOptionsVoicePanelEnableMicrophone_UpdateControls (value)
+ if ( not AudioOptionsVoicePanelEnableVoice:GetChecked() or
+ not value or value == "0" or
+ VoiceIsDisabledByClient() ) then
+ --If VoiceChat is disabled, the microphone controls should be too.
+ AudioOptionsVoicePanel_DisableMicrophoneControls();
+ else
+ AudioOptionsVoicePanel_EnableMicrophoneControls();
+ end
+end
+
+function AudioOptionsVoicePanelBindingType_Update (value)
+ local mode = tonumber(value) + 1;
+ if ( mode == 1 ) then
+ AudioOptionsVoicePanelChatMode1:Show();
+ AudioOptionsVoicePanelChatMode2:Hide();
+ else
+ AudioOptionsVoicePanelChatMode1:Hide();
+ AudioOptionsVoicePanelChatMode2:Show();
+ end
+end
+
+function AudioOptionsVoicePanelKeyBindingButton_Refresh ()
+ PUSH_TO_TALK_BUTTON = BlizzardOptionsPanel_GetCVarSafe("PushToTalkButton");
+ local bindingText = GetBindingText(PUSH_TO_TALK_BUTTON, "KEY_");
+ AudioOptionsVoicePanelChatMode1KeyBindingButtonHiddenText:SetText(bindingText);
+ AudioOptionsVoicePanelChatMode1KeyBindingButton:SetText(bindingText);
+end
+
+function AudioOptionsVoicePanelKeyBindingButton_SetTooltip ()
+ local textWidth = AudioOptionsVoicePanelChatMode1KeyBindingButtonHiddenText:GetWidth();
+ if ( textWidth > 135 ) then
+ AudioOptionsVoicePanelChatMode1KeyBindingButton.tooltip = AudioOptionsVoicePanelChatMode1KeyBindingButtonHiddenText:GetText();
+ else
+ AudioOptionsVoicePanelChatMode1KeyBindingButton.tooltip = nil;
+ end
+end
+
+function AudioOptionsVoicePanelKeyBindingButton_OnEnter (self)
+ if ( self.tooltip ) then
+ GameTooltip:SetOwner(self);
+ GameTooltip:SetText(self.tooltip);
+ GameTooltip:Show();
+ end
+end
+
+function AudioOptionsVoicePanelKeyBindingButton_OnKeyUp (self, key)
+ if ( self.buttonPressed ) then
+ AudioOptionsVoicePanelKeyBindingButton_BindButton(self);
+ end
+end
+
+function AudioOptionsVoicePanelKeyBindingButton_OnKeyDown (self, key)
+ if ( GetBindingFromClick(key) == "SCREENSHOT" ) then
+ RunBinding("SCREENSHOT");
+ return;
+ end
+ if ( self.buttonPressed ) then
+ if ( key == "UNKNOWN" ) then
+ return;
+ end
+
+ if ( key == "LSHIFT" or key == "RSHIFT" or key == "LCTRL" or key == "RCTRL" or key == "LALT" or key == "RALT" ) then
+ if ( PUSH_TO_TALK_MODIFIER == "" ) then
+ PUSH_TO_TALK_MODIFIER = key;
+ else
+ PUSH_TO_TALK_MODIFIER = PUSH_TO_TALK_MODIFIER.."-"..key;
+ end
+ return;
+ elseif ( PUSH_TO_TALK_BUTTON ~= "" ) then
+ AudioOptionsVoicePanelBindingOutputText:SetText(ERROR_CANNOT_BIND);
+ AudioOptionsVoicePanelBindingOutputTextConflict:SetText("");
+ AudioOptionsVoicePanelBindingOutput:SetAlpha(1.0);
+ AudioOptionsVoicePanelBindingOutput.fade = VOICE_OPTIONS_BINDING_FAIL_FADE;
+ self:UnlockHighlight();
+ self.buttonPressed = nil;
+ return;
+ end
+
+ if ( PUSH_TO_TALK_MODIFIER == "" ) then
+ PUSH_TO_TALK_BUTTON = key;
+ else
+ PUSH_TO_TALK_BUTTON = PUSH_TO_TALK_MODIFIER.."-"..key;
+ end
+ end
+
+end
+
+function AudioOptionsVoicePanelKeyBindingButton_CancelBinding ()
+ local self = AudioOptionsVoicePanelChatMode1KeyBindingButton;
+ self:UnlockHighlight();
+ self.buttonPressed = nil;
+ AudioOptionsVoicePanelBindingOutputText:SetText("");
+ AudioOptionsVoicePanelBindingOutputTextConflict:SetText("");
+ self:SetScript("OnKeyDown", nil);
+ self:SetScript("OnKeyUp", nil);
+ AudioOptionsVoicePanelBindingOutput:SetAlpha(1.0)
+ AudioOptionsVoicePanelBindingOutput.fade = 0;
+ UIFrameFadeIn(AudioOptionsVoicePanelBindingOutput, 0);
+ PUSH_TO_TALK_BUTTON = "";
+ PUSH_TO_TALK_MODIFIER = "";
+end
+
+function AudioOptionsVoicePanelKeyBindingButton_OnClick (self, button)
+ if ( button == "UNKNOWN" ) then
+ return;
+ end
+ if ( not IsShiftKeyDown() and not IsControlKeyDown() and not IsAltKeyDown() ) then
+ if ( button == "LeftButton" or button == "RightButton" ) then
+ if ( self.buttonPressed ) then
+ AudioOptionsVoicePanelKeyBindingButton_CancelBinding(self);
+ else
+ self:LockHighlight();
+ self.buttonPressed = 1;
+ AudioOptionsVoicePanelBindingOutputText:SetText(CAN_BIND_PTT);
+ self:SetScript("OnKeyDown", AudioOptionsVoicePanelKeyBindingButton_OnKeyDown);
+ self:SetScript("OnKeyUp", AudioOptionsVoicePanelKeyBindingButton_OnKeyUp);
+ AudioOptionsVoicePanelBindingOutput:SetAlpha(1.0)
+ AudioOptionsVoicePanelBindingOutput.fade = 0;
+ UIFrameFadeIn(AudioOptionsVoicePanelBindingOutput, 0);
+ AudioOptionsVoicePanelBindingOutputTextConflict:SetText("");
+ PUSH_TO_TALK_BUTTON = "";
+ PUSH_TO_TALK_MODIFIER = "";
+ end
+ return;
+ end
+ end
+
+ if ( self.buttonPressed ) then
+ if ( PUSH_TO_TALK_BUTTON ~= "" ) then
+ AudioOptionsVoicePanelBindingOutputText:SetText(ERROR_CANNOT_BIND);
+ AudioOptionsVoicePanelBindingOutput:SetAlpha(1.0);
+ AudioOptionsVoicePanelBindingOutput.fade = VOICE_OPTIONS_BINDING_FAIL_FADE;
+ AudioOptionsVoicePanelBindingOutputText:SetVertexColor(1, 1, 1);
+ AudioOptionsVoicePanelBindingOutputTextConflict:SetText("");
+ self:UnlockHighlight();
+ self.buttonPressed = nil;
+ return;
+ end
+
+ if ( PUSH_TO_TALK_MODIFIER == "" ) then
+ PUSH_TO_TALK_BUTTON = button;
+ else
+ PUSH_TO_TALK_BUTTON = PUSH_TO_TALK_MODIFIER.."-"..button;
+ end
+ AudioOptionsVoicePanelKeyBindingButton_BindButton(self);
+ end
+end
+
+function AudioOptionsVoicePanelKeyBindingButton_BindButton (self)
+ if ( PUSH_TO_TALK_BUTTON == "" and PUSH_TO_TALK_MODIFIER ~= "" ) then
+ PUSH_TO_TALK_BUTTON = PUSH_TO_TALK_MODIFIER;
+ end
+ if ( PUSH_TO_TALK_BUTTON ~= "" ) then
+ BlizzardOptionsPanel_SetCVarSafe("PushToTalkButton", PUSH_TO_TALK_BUTTON);
+ local bindingText = GetBindingText(PUSH_TO_TALK_BUTTON, "KEY_");
+ self:SetText(bindingText);
+ AudioOptionsVoicePanelChatMode1KeyBindingButtonHiddenText:SetText(bindingText);
+
+ self:UnlockHighlight();
+ self.buttonPressed = nil;
+
+ local currentbinding = GetBindingByKey(PUSH_TO_TALK_BUTTON);
+ if ( currentbinding ) then
+ UIErrorsFrame:AddMessage(format(ALREADY_BOUND, GetBindingText(currentbinding, "BINDING_NAME_")), 1.0, 1.0, 0.0, 1.0);
+ AudioOptionsVoicePanelBindingOutputTextConflict:SetText(format(ALREADY_BOUND, GetBindingText(currentbinding, "BINDING_NAME_")));
+ else
+ AudioOptionsVoicePanelBindingOutputTextConflict:SetText("");
+ end
+
+ AudioOptionsVoicePanelBindingOutputText:SetText(PTT_BOUND);
+ AudioOptionsVoicePanelBindingOutput:SetAlpha(1.0);
+ AudioOptionsVoicePanelBindingOutput.fade = VOICE_OPTIONS_BINDING_SUCCESS_FADE;
+ self:SetScript("OnKeyDown", nil);
+ self:SetScript("OnKeyUp", nil);
+ end
+ AudioOptionsVoicePanelKeyBindingButton_SetTooltip();
+ if ( GameTooltip:GetOwner() == self ) then
+ AudioOptionsVoicePanelKeyBindingButton_OnEnter(self);
+ end
+end
+
+function AudioOptionsVoicePanelBindingOutput_OnUpdate(self, elapsed)
+ if ( self.fade and self.fade > 0 ) then
+ self:SetAlpha(self.fade);
+ self.fade = self.fade - elapsed;
+ if ( self.fade < 0 ) then
+ self.fade = 0;
+ self:SetAlpha(0);
+ end
+ end
+end
+
+function AudioOptionsVoicePanel_SetOutputDevice(deviceIndex)
+ VoiceSelectOutputDevice(VoiceEnumerateOutputDevices(deviceIndex));
+end
+
+function AudioOptionsVoicePanel_SetInputDevice(deviceIndex)
+ VoiceSelectCaptureDevice(VoiceEnumerateCaptureDevices(deviceIndex));
+end
+
+function AudioOptionsVoicePanelInputDeviceDropDown_OnLoad (self)
+ UIDropDownMenu_SetWidth(self, 140);
+
+ self.cvar = "Sound_VoiceChatInputDriverIndex";
+
+ local selectedDriverIndex = BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+
+ self.defaultValue = BlizzardOptionsPanel_GetCVarDefaultSafe(self.cvar);
+ self.value = selectedDriverIndex;
+ self.nextValue = selectedDriverIndex;
+ self.restart = true;
+
+ UIDropDownMenu_SetSelectedValue(self, selectedDriverIndex);
+ UIDropDownMenu_Initialize(self, AudioOptionsVoicePanelInputDeviceDropDown_Initialize);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ AudioOptionsVoicePanel_SetInputDevice(value);
+ BlizzardOptionsPanel_SetCVarSafe(self.cvar, value);
+ end
+ self.GetValue =
+ function (self)
+ return BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+ end
+ self.RefreshValue =
+ function (self)
+ local selectedDriverIndex = BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+
+ self.value = selectedDriverIndex;
+ self.newValue = selectedDriverIndex;
+
+ UIDropDownMenu_SetSelectedValue(self, selectedDriverIndex);
+ UIDropDownMenu_Initialize(self, AudioOptionsVoicePanelInputDeviceDropDown_Initialize);
+ end
+end
+
+function AudioOptionsVoicePanelInputDeviceDropDown_Initialize(self)
+ local selectedValue = UIDropDownMenu_GetSelectedValue(self);
+ local num = Sound_ChatSystem_GetNumInputDrivers();
+ local info = UIDropDownMenu_CreateInfo();
+ for index=0,num-1,1 do
+ info.text = Sound_ChatSystem_GetInputDriverNameByIndex(index);
+ info.value = index;
+ if (selectedValue and index == selectedValue) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ else
+ info.checked = nil;
+ end
+ info.func = AudioOptionsVoicePanelInputDeviceDropDown_OnClick;
+
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function AudioOptionsVoicePanelInputDeviceDropDown_OnClick(self)
+ local value = self.value;
+ local dropdown = AudioOptionsVoicePanelInputDeviceDropDown;
+ UIDropDownMenu_SetSelectedValue(dropdown, value);
+ dropdown:SetValue(value);
+end
+
+--==============================
+--
+-- Record Loopback functions
+--
+--==============================
+
+function RecordLoopbackSoundButton_OnUpdate (self)
+ if ( self.clicked ) then
+ if ( not AudioOptionsVoicePanelEnableVoice:GetChecked() or
+ not AudioOptionsVoicePanelEnableMicrophone:GetChecked() ) then
+ -- NOTE: add VoiceIsDisabledByClient() if turning voice on and off ever happens dynamically
+ RecordLoopbackSoundButton:Disable();
+ RecordLoopbackSoundButtonTexture:SetVertexColor(0.5, 0.5, 0.5);
+ else
+ local isRecording = VoiceChat_IsRecordingLoopbackSound();
+ if ( isRecording == 0 ) then
+ RecordLoopbackSoundButton:Enable();
+ RecordLoopbackSoundButtonTexture:SetVertexColor(1, 0, 0);
+ self.clicked = nil;
+ else
+ RecordLoopbackSoundButton:Disable();
+ RecordLoopbackSoundButtonTexture:SetVertexColor(0.5, 0.5, 0.5);
+ end
+ end
+ end
+end
+
+--==============================
+--
+-- VU Meter functions
+--
+--==============================
+
+function LoopbackVUMeter_OnLoad (self)
+ self:SetMinMaxValues(0, 100);
+ self:SetValue(0);
+end
+
+function LoopbackVUMeter_OnUpdate (self, elapsed)
+ local isRecording = VoiceChat_IsRecordingLoopbackSound();
+ local isPlaying = VoiceChat_IsPlayingLoopbackSound();
+ if ( isRecording == 0 and isPlaying == 0 ) then
+ self:SetValue(0);
+ else
+ local volume = VoiceChat_GetCurrentMicrophoneSignalLevel();
+ self:SetValue(volume);
+ end
+end
+
+function AudioOptionsVoicePanelChatModeDropDown_OnLoad (self)
+ UIDropDownMenu_SetWidth(self, 140);
+
+ self.cvar = "VoiceChatMode";
+
+ local voiceChatMode = BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+
+ self.tooltip = _G["OPTION_TOOLTIP_VOICE_TYPE"..(voiceChatMode+1)];
+ self.defaultValue = BlizzardOptionsPanel_GetCVarDefaultSafe(self.cvar);
+ self.value = voiceChatMode;
+ self.newValue = voiceChatMode;
+ self.restart = true;
+
+ UIDropDownMenu_SetSelectedValue(self, voiceChatMode);
+ UIDropDownMenu_Initialize(self, AudioOptionsVoicePanelChatModeDropDown_Initialize);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ BlizzardOptionsPanel_SetCVarSafe(self.cvar, value);
+ AudioOptionsVoicePanelBindingType_Update(value);
+ SetSelfMuteState();
+ end
+ self.GetValue =
+ function (self)
+ return BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+ end
+ self.RefreshValue =
+ function (self)
+ local voiceChatMode = BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+
+ self.tooltip = _G["OPTION_TOOLTIP_VOICE_TYPE"..(voiceChatMode+1)];
+ self.value = voiceChatMode;
+ self.newValue = voiceChatMode;
+
+ UIDropDownMenu_SetSelectedValue(self, voiceChatMode);
+ UIDropDownMenu_Initialize(self, AudioOptionsVoicePanelChatModeDropDown_Initialize);
+ end
+end
+
+function AudioOptionsVoicePanelChatModeDropDown_Initialize(self)
+ local selectedValue = UIDropDownMenu_GetSelectedValue(self);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = PUSH_TO_TALK;
+ info.func = AudioOptionsVoicePanelChatModeDropDown_OnClick;
+ info.value = 0;
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = PUSH_TO_TALK;
+ info.tooltipText = OPTION_TOOLTIP_VOICE_TYPE1;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = VOICE_ACTIVATED;
+ info.func = AudioOptionsVoicePanelChatModeDropDown_OnClick;
+ info.value = 1;
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = VOICE_ACTIVATED;
+ info.tooltipText = OPTION_TOOLTIP_VOICE_TYPE2;
+ UIDropDownMenu_AddButton(info);
+end
+
+function AudioOptionsVoicePanelChatModeDropDown_OnClick(self)
+ local value = self.value;
+ local dropdown = AudioOptionsVoicePanelChatModeDropDown;
+ UIDropDownMenu_SetSelectedValue(dropdown, value);
+ dropdown.tooltip = _G["OPTION_TOOLTIP_VOICE_TYPE"..(value+1)];
+ dropdown:SetValue(value);
+end
+
+function AudioOptionsVoicePanelOutputDeviceDropDown_OnLoad (self)
+ UIDropDownMenu_SetWidth(self, 140);
+
+ self.cvar = "Sound_VoiceChatOutputDriverIndex";
+
+ local selectedDriverIndex = BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+
+ self.defaultValue = BlizzardOptionsPanel_GetCVarDefaultSafe(self.cvar);
+ self.value = selectedDriverIndex;
+ self.nextValue = selectedDriverIndex;
+ self.restart = true;
+
+ UIDropDownMenu_SetSelectedValue(self, selectedDriverIndex);
+ UIDropDownMenu_Initialize(self, AudioOptionsVoicePanelOutputDeviceDropDown_Initialize);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ AudioOptionsVoicePanel_SetOutputDevice(value);
+ BlizzardOptionsPanel_SetCVarSafe("Sound_VoiceChatOutputDriverIndex", value);
+ end
+ self.GetValue =
+ function (self)
+ return BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+ end
+ self.RefreshValue =
+ function (self)
+ local selectedDriverIndex = BlizzardOptionsPanel_GetCVarSafe(self.cvar);
+
+ self.value = selectedDriverIndex;
+ self.nextValue = selectedDriverIndex;
+
+ UIDropDownMenu_SetSelectedValue(self, selectedDriverIndex);
+ UIDropDownMenu_Initialize(self, AudioOptionsVoicePanelOutputDeviceDropDown_Initialize);
+ end
+end
+
+function AudioOptionsVoicePanelOutputDeviceDropDown_Initialize(self)
+ local selectedValue = UIDropDownMenu_GetSelectedValue(self);
+ local num = Sound_ChatSystem_GetNumOutputDrivers();
+ local info = UIDropDownMenu_CreateInfo();
+ if ( num == 0 ) then
+ UIDropDownMenu_SetText(self, "");
+ else
+ for index=0,num-1,1 do
+ info.text = Sound_ChatSystem_GetOutputDriverNameByIndex(index);
+ info.value = index;
+ if (selectedValue and index == selectedValue) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(self, info.text);
+ else
+ info.checked = nil;
+ end
+ info.func = AudioOptionsVoicePanelOutputDeviceDropDown_OnClick;
+
+ UIDropDownMenu_AddButton(info);
+ end
+ end
+end
+
+function AudioOptionsVoicePanelOutputDeviceDropDown_OnClick(self)
+ local value = self.value;
+ local dropdown = AudioOptionsVoicePanelOutputDeviceDropDown;
+ UIDropDownMenu_SetSelectedValue(dropdown, value);
+ dropdown:SetValue(value);
+end
+
+function AudioOptionsVoicePanelOutputDeviceDropDown_OnEvent(self, event, ...)
+ if ( event == "VOICE_CHAT_ENABLED_UPDATE" ) then
+ UIDropDownMenu_Initialize(self, AudioOptionsVoicePanelOutputDeviceDropDown_Initialize);
+ end
+end
diff --git a/reference/FrameXML/AudioOptionsPanels.xml b/reference/FrameXML/AudioOptionsPanels.xml
new file mode 100644
index 0000000..c699f91
--- /dev/null
+++ b/reference/FrameXML/AudioOptionsPanels.xml
@@ -0,0 +1,1326 @@
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ AudioOptionsPanel_CheckButton_OnClick(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableAllSound";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.15, 0.15, 0.15);
+ _G[self:GetName().."Title"]:SetText(PLAYBACK);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableSFX";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableErrorSpeech";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(AudioOptionsSoundPanelSoundEffects, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableEmoteSounds";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(AudioOptionsSoundPanelSoundEffects, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnablePetSounds";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(AudioOptionsSoundPanelSoundEffects, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableMusic";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_ZoneMusicNoDelay";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(AudioOptionsSoundPanelMusic, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableAmbience";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableSoundWhenGameIsInBG";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableReverb";
+ self.restart = true;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableSoftwareHRTF";
+ self.restart = true;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableDSPEffects";
+ self.restart = true;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "Sound_OutputQuality";
+ self.restart = true;
+ _G[self:GetName().."Text"]:SetFontObject("GameFontNormalSmall");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ local prevValue = self.value;
+ BlizzardOptionsPanel_Slider_OnValueChanged(self, value);
+ if (self:GetParent():IsShown() and self.restart and prevValue and prevValue ~= value) then
+ AudioOptionsFrame_AudioRestart();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.15, 0.15, 0.15);
+ _G[self:GetName().."Title"]:SetText(HARDWARE);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ AudioOptionsSoundPanelHardwareDropDown_OnLoad(self);
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(OPTION_TOOLTIP_SOUND_OUTPUT, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "Sound_NumChannels";
+ self.restart = true;
+ _G[self:GetName().."Text"]:SetFontObject("GameFontNormalSmall");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ local prevValue = self.value;
+ self.value = value;
+ BlizzardOptionsPanel_SetCVarSafe(self.cvar, value);
+ if (self:GetParent():IsShown() and self.restart and prevValue and prevValue ~= value) then
+ AudioOptionsFrame_AudioRestart();
+ end
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "Sound_EnableHardware";
+ self.restart = true;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.15, 0.15, 0.15);
+ _G[self:GetName().."Title"]:SetText(VOLUME);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ _G[name.."Low"]:Hide();
+ _G[name.."High"]:Hide();
+ self.label = _G[name .. "Label"];
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "Sound_MasterVolume";
+ _G[name.."Text"]:SetFontObject("GameFontNormalSmall");
+ _G[name.."Text"]:SetPoint("BOTTOM", self, "TOP", 0, 4);
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ self.value = value;
+ BlizzardOptionsPanel_SetCVarSafe(self.cvar, value);
+ self.label:SetText(tostring(ceil(value * 100)).."%");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ local label = _G[name.."Low"];
+ label:ClearAllPoints();
+ label:SetPoint("BOTTOMLEFT", "$parent", "TOPLEFT", -2, 4);
+ label = _G[name.."High"];
+ label:ClearAllPoints();
+ label:SetPoint("BOTTOMRIGHT", "$parent", "TOPRIGHT", 4, 4);
+ _G[name.."Text"]:Hide();
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "Sound_SFXVolume";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ _G[name.."Low"]:Hide()
+ _G[name.."High"]:Hide();
+ _G[name.."Text"]:Hide();
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "Sound_MusicVolume";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ _G[name.."Low"]:Hide();
+ _G[name.."High"]:Hide();
+ _G[name.."Text"]:Hide();
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "Sound_AmbienceVolume";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(_G[self:GetName().."Text"]:GetWidth());
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(VOICECHAT_DISABLED_TEXT, nil, nil, nil, nil, 1);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "EnableVoiceChat";
+ self.setFunc = AudioOptionsVoicePanelEnableVoice_UpdateControls;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.15, 0.15, 0.15);
+ _G[self:GetName().."Title"]:SetText(VOICE_TALKING);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "EnableMicrophone";
+ self.setFunc = AudioOptionsVoicePanelEnableMicrophone_UpdateControls;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ AudioOptionsVoicePanelInputDeviceDropDown_OnLoad(self);
+
+
+ if ( UIDropDownMenu_IsEnabled(self) ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(OPTION_TOOLTIP_VOICE_INPUT, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ local label = _G[name.."Low"];
+ label:Hide();
+ label = _G[name.."High"];
+ label:Hide();
+ self.label = _G[name.."Label"];
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "OutboundChatVolume";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ self.value = value;
+ BlizzardOptionsPanel_SetCVarSafe(self.cvar, value);
+ local min, max = self:GetMinMaxValues();
+ value, max = (value - min), (max - min);
+ self.label:SetText(tostring(ceil((value/max) * 100)).."%");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RecordLoopbackSoundButtonTexture:SetVertexColor(1, 0, 0);
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(VOICE_MIC_TEST_RECORD, nil, nil, nil, nil, 1);
+ _G[self:GetName().."Texture"]:SetVertexColor(1, 1, 1);
+
+
+ _G[self:GetName().."Texture"]:SetVertexColor(0.5, 0.5, 0.5);
+ PlaySound("gsTitleOptionExit");
+ VoiceChat_RecordLoopbackSound(5);
+ self.clicked = 1;
+
+
+
+ _G[self:GetName().."Texture"]:SetVertexColor(1, 0, 0);
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Texture"]:SetVertexColor(NORMAL_FONT_COLOR.r , NORMAL_FONT_COLOR.g , NORMAL_FONT_COLOR.b);
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(VOICE_MIC_TEST_PLAY, nil, nil, nil, nil, 1);
+ _G[self:GetName().."Texture"]:SetVertexColor(1, 1, 1);
+
+
+ PlaySound("gsTitleOptionExit");
+ VoiceChat_StopRecordingLoopbackSound();
+ VoiceChat_PlayLoopbackSound();
+
+
+ _G[self:GetName().."Texture"]:SetVertexColor(NORMAL_FONT_COLOR.r , NORMAL_FONT_COLOR.g , NORMAL_FONT_COLOR.b);
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.15, 0.15, 0.15, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ AudioOptionsVoicePanelChatModeDropDown_OnLoad(self);
+
+
+ if ( UIDropDownMenu_IsEnabled(self) and self.tooltip ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("AnyUp");
+ self:SetScript("OnKeyUp", nil);
+ self:SetScript("OnKeyDown", nil);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "PushToTalkSound";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "VoiceActivationSensitivity";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+ self.value = value;
+ BlizzardOptionsPanel_SetCVarSafe(self.cvar, value);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.15, 0.15, 0.15);
+ _G[self:GetName().."Title"]:SetText(VOICE_LISTENING);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ AudioOptionsVoicePanelOutputDeviceDropDown_OnLoad(self);
+ self:RegisterEvent("VOICE_CHAT_ENABLED_UPDATE");
+
+
+ if ( UIDropDownMenu_IsEnabled(self) ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(OPTION_TOOLTIP_VOICE_OUTPUT, nil, nil, nil, nil, 1);
+ GameTooltip:Show();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ local label = _G[name.."Low"];
+ label:Hide();
+ label = _G[name.."High"];
+ label:Hide();
+ self.label = _G[name.."Label"];
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "InboundChatVolume";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ self.value = value;
+ BlizzardOptionsPanel_SetCVarSafe(self.cvar, value);
+ local min, max = self:GetMinMaxValues();
+ value, max = (value - min), (max - min);
+ self.label:SetText(tostring(ceil((value/max) * 100)).."%");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ local label = _G[name.."Low"];
+ label:Hide();
+ label = _G[name.."High"];
+ label:Hide();
+ self.label = _G[name.."Label"];
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "ChatSoundVolume";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ local label = _G[name.."Low"];
+ label:Hide();
+ label = _G[name.."High"];
+ label:Hide();
+ self.label = _G[name.."Label"];
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "ChatMusicVolume";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ local label = _G[name.."Low"];
+ label:Hide();
+ label = _G[name.."High"];
+ label:Hide();
+ self.label = _G[name.."Label"];
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "ChatAmbienceVolume";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/AutoComplete.lua b/reference/FrameXML/AutoComplete.lua
new file mode 100644
index 0000000..7d200e0
--- /dev/null
+++ b/reference/FrameXML/AutoComplete.lua
@@ -0,0 +1,291 @@
+AUTOCOMPLETE_MAX_BUTTONS = 5;
+
+AUTOCOMPLETE_FLAG_NONE = 0x00000000;
+AUTOCOMPLETE_FLAG_IN_GROUP = 0x00000001;
+AUTOCOMPLETE_FLAG_IN_GUILD = 0x00000002;
+AUTOCOMPLETE_FLAG_FRIEND = 0x00000004;
+AUTOCOMPLETE_FLAG_BNET = 0x00000008;
+AUTOCOMPLETE_FLAG_INTERACTED_WITH = 0x00000010;
+AUTOCOMPLETE_FLAG_ONLINE = 0x00000020;
+AUTOCOMPLETE_FLAG_ALL = 0xffffffff;
+
+AUTOCOMPLETE_LIST_TEMPLATES = {
+ ALL = {
+ include = AUTOCOMPLETE_FLAG_ALL,
+ exclude = AUTOCOMPLETE_FLAG_NONE,
+ },
+ ALL_CHARS = {
+ include = AUTOCOMPLETE_FLAG_ALL,
+ exclude = AUTOCOMPLETE_FLAG_BNET,
+ },
+ ONLINE = {
+ include = AUTOCOMPLETE_FLAG_ONLINE,
+ exclude = AUTOCOMPLETE_FLAG_NONE,
+ },
+ ONLINE_NOT_IN_GROUP = {
+ include = AUTOCOMPLETE_FLAG_ONLINE,
+ exclude = bit.bor(AUTOCOMPLETE_FLAG_IN_GROUP,AUTOCOMPLETE_FLAG_BNET),
+ },
+ ONLINE_NOT_IN_GUILD = {
+ include = AUTOCOMPLETE_FLAG_ONLINE,
+ exclude = bit.bor(AUTOCOMPLETE_FLAG_IN_GUILD,AUTOCOMPLETE_FLAG_BNET),
+ },
+ NOT_FRIEND = {
+ include = AUTOCOMPLETE_FLAG_ALL,
+ exclude = bit.bor(AUTOCOMPLETE_FLAG_FRIEND,AUTOCOMPLETE_FLAG_BNET);
+ },
+ IN_GROUP = {
+ include = AUTOCOMPLETE_FLAG_IN_GROUP,
+ exclude = AUTOCOMPLETE_FLAG_BNET,
+ },
+ IN_GUILD = {
+ include = AUTOCOMPLETE_FLAG_IN_GUILD,
+ exclude = AUTOCOMPLETE_FLAG_BNET,
+ },
+ FRIEND = {
+ include = AUTOCOMPLETE_FLAG_FRIEND,
+ exclude = AUTOCOMPLETE_FLAG_BNET,
+ },
+ FRIEND_NOT_GUILD = {
+ include = AUTOCOMPLETE_FLAG_FRIEND,
+ exclude = bit.bor(AUTOCOMPLETE_FLAG_IN_GUILD,AUTOCOMPLETE_FLAG_BNET),
+ },
+ FRIEND_AND_GUILD = {
+ include = bit.bor(AUTOCOMPLETE_FLAG_FRIEND, AUTOCOMPLETE_FLAG_IN_GUILD),
+ exclude = AUTOCOMPLETE_FLAG_BNET,
+ },
+}
+
+AUTOCOMPLETE_LIST = {};
+local AUTOCOMPLETE_LIST = AUTOCOMPLETE_LIST;
+ AUTOCOMPLETE_LIST.ALL = AUTOCOMPLETE_LIST_TEMPLATES.ALL;
+ AUTOCOMPLETE_LIST.WHISPER = AUTOCOMPLETE_LIST_TEMPLATES.ONLINE;
+ AUTOCOMPLETE_LIST.INVITE = AUTOCOMPLETE_LIST_TEMPLATES.ONLINE_NOT_IN_GROUP;
+ AUTOCOMPLETE_LIST.UNINVITE = AUTOCOMPLETE_LIST_TEMPLATES.IN_GROUP;
+ AUTOCOMPLETE_LIST.PROMOTE = AUTOCOMPLETE_LIST_TEMPLATES.IN_GROUP;
+ AUTOCOMPLETE_LIST.TEAM_INVITE = AUTOCOMPLETE_LIST_TEMPLATES.ONLINE;
+ AUTOCOMPLETE_LIST.GUILD_INVITE = AUTOCOMPLETE_LIST_TEMPLATES.ONLINE_NOT_IN_GUILD;
+ AUTOCOMPLETE_LIST.GUILD_UNINVITE = AUTOCOMPLETE_LIST_TEMPLATES.IN_GUILD;
+ AUTOCOMPLETE_LIST.GUILD_PROMOTE = AUTOCOMPLETE_LIST_TEMPLATES.IN_GUILD;
+ AUTOCOMPLETE_LIST.GUILD_DEMOTE = AUTOCOMPLETE_LIST_TEMPLATES.IN_GUILD;
+ AUTOCOMPLETE_LIST.GUILD_LEADER = AUTOCOMPLETE_LIST_TEMPLATES.IN_GUILD;
+ AUTOCOMPLETE_LIST.ADDFRIEND = AUTOCOMPLETE_LIST_TEMPLATES.NOT_FRIEND;
+ AUTOCOMPLETE_LIST.REMOVEFRIEND = AUTOCOMPLETE_LIST_TEMPLATES.FRIEND;
+ AUTOCOMPLETE_LIST.CHANINVITE = AUTOCOMPLETE_LIST_TEMPLATES.ONLINE;
+ AUTOCOMPLETE_LIST.MAIL = AUTOCOMPLETE_LIST_TEMPLATES.ALL_CHARS;
+ AUTOCOMPLETE_LIST.CALENDARGUILDEVENT= AUTOCOMPLETE_LIST_TEMPLATES.FRIEND_NOT_GUILD;
+ AUTOCOMPLETE_LIST.CALENDAREVENT = AUTOCOMPLETE_LIST_TEMPLATES.FRIEND_AND_GUILD;
+
+AUTOCOMPLETE_SIMPLE_REGEX = "(.+)";
+AUTOCOMPLETE_SIMPLE_FORMAT_REGEX = "%1$s";
+
+AUTOCOMPLETE_DEFAULT_Y_OFFSET = 3;
+function AutoComplete_OnLoad(self)
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+ self.maxHeight = AUTOCOMPLETE_MAX_BUTTONS * AutoCompleteButton1:GetHeight();
+
+ AutoCompleteInstructions:SetText("|cffbbbbbb"..PRESS_TAB.."|r");
+end
+
+function AutoComplete_Update(parent, text, cursorPosition)
+ local self = AutoCompleteBox;
+ local attachPoint;
+ if ( not parent.autoCompleteParams ) then
+ return;
+ end
+ if ( not text or text == "" ) then
+ AutoComplete_HideIfAttachedTo(parent);
+ return;
+ end
+ if ( cursorPosition <= strlen(text) ) then
+ self:SetParent(parent);
+ if(self.parent ~= parent) then
+ AutoComplete_SetSelectedIndex(self, 0);
+ end
+
+ if ( parent:GetBottom() - self.maxHeight <= (AUTOCOMPLETE_DEFAULT_Y_OFFSET + 10) ) then --10 is a magic number from the offset of AutoCompleteButton1.
+ attachPoint = "ABOVE";
+ else
+ attachPoint = "BELOW";
+ end
+ if ( (self.parent ~= parent) or (self.attachPoint ~= attachPoint) ) then
+ if ( attachPoint == "ABOVE" ) then
+ self:ClearAllPoints();
+ self:SetPoint("BOTTOMLEFT", parent, "TOPLEFT", parent.autoCompleteXOffset or 0, parent.autoCompleteYOffset or -AUTOCOMPLETE_DEFAULT_Y_OFFSET);
+ elseif ( attachPoint == "BELOW" ) then
+ self:ClearAllPoints();
+ self:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", parent.autoCompleteXOffset or 0, parent.autoCompleteYOffset or AUTOCOMPLETE_DEFAULT_Y_OFFSET);
+ end
+ self.attachPoint = attachPoint;
+ end
+
+ self.parent = parent;
+ --We ask for one more result than we need so that we know whether or not results are continued
+ AutoComplete_UpdateResults(self,
+ GetAutoCompleteResults(text, parent.autoCompleteParams.include, parent.autoCompleteParams.exclude, AUTOCOMPLETE_MAX_BUTTONS+1, cursorPosition));
+ else
+ AutoComplete_HideIfAttachedTo(parent);
+ end
+end
+
+function AutoComplete_HideIfAttachedTo(parent)
+ local self = AutoCompleteBox;
+ if ( self.parent == parent ) then
+ self:Hide();
+ end
+end
+
+function AutoComplete_SetSelectedIndex(self, index)
+ self.selectedIndex = index;
+ for i=1, AUTOCOMPLETE_MAX_BUTTONS do
+ _G["AutoCompleteButton"..i]:UnlockHighlight();
+ end
+ if ( index ~= 0 ) then
+ _G["AutoCompleteButton"..index]:LockHighlight();
+ end
+end
+
+function AutoComplete_GetSelectedIndex(self)
+ return self.selectedIndex;
+end
+
+function AutoComplete_GetNumResults(self)
+ return self.numResults;
+end
+
+function AutoComplete_UpdateResults(self, ...)
+ local totalReturns = select("#", ...);
+ local numReturns = min(totalReturns, AUTOCOMPLETE_MAX_BUTTONS);
+ local maxWidth = 120;
+ for i=1, numReturns do
+ local button = _G["AutoCompleteButton"..i]
+ button:SetText(select(i, ...));
+ maxWidth = max(maxWidth, button:GetFontString():GetWidth()+30);
+ button:Enable();
+ button:Show();
+ end
+ for i = numReturns+1, AUTOCOMPLETE_MAX_BUTTONS do
+ _G["AutoCompleteButton"..i]:Hide();
+ end
+ if ( numReturns > 0 ) then
+ if ( not self:IsShown() ) then
+ AutoComplete_SetSelectedIndex(self, 0);
+ end
+ maxWidth = max(maxWidth, AutoCompleteInstructions:GetStringWidth()+30);
+ self:SetHeight(numReturns*AutoCompleteButton1:GetHeight()+35);
+ self:SetWidth(maxWidth);
+ self:Show();
+ else
+ self:Hide();
+ end
+ if ( totalReturns > AUTOCOMPLETE_MAX_BUTTONS ) then
+ local button = _G["AutoCompleteButton"..AUTOCOMPLETE_MAX_BUTTONS];
+ button:SetText(CONTINUED);
+ button:Disable();
+ self.numResults = numReturns - 1;
+ else
+ self.numResults = numReturns;
+ end
+end
+
+function AutoCompleteEditBox_OnTabPressed(editBox)
+ local autoComplete = AutoCompleteBox;
+ if ( autoComplete:IsShown() and autoComplete.parent == editBox ) then
+ local selectedIndex = AutoComplete_GetSelectedIndex(autoComplete);
+ local numReturns = AutoComplete_GetNumResults(autoComplete);
+ if ( IsShiftKeyDown() ) then
+ local nextNum = mod(selectedIndex - 1, numReturns);
+ if ( nextNum == 0 ) then
+ nextNum = numReturns;
+ end
+ AutoComplete_SetSelectedIndex(autoComplete, nextNum);
+ else
+ local nextNum = mod(selectedIndex + 1, numReturns);
+ if ( nextNum == 0 ) then
+ nextNum = numReturns;
+ end
+ AutoComplete_SetSelectedIndex(autoComplete, nextNum)
+ end
+ return true;
+ end
+ return false;
+end
+
+function AutoCompleteEditBox_OnEnterPressed(self)
+ local autoComplete = AutoCompleteBox;
+ if ( autoComplete:IsShown() and (autoComplete.parent == self) and (AutoComplete_GetSelectedIndex(autoComplete) ~= 0) ) then
+ AutoCompleteButton_OnClick(_G["AutoCompleteButton"..AutoComplete_GetSelectedIndex(autoComplete)]);
+ return true;
+ end
+ return false;
+end
+
+function AutoCompleteEditBox_OnTextChanged(self, userInput)
+ if ( userInput ) then
+ AutoComplete_Update(self, self:GetText(), self:GetUTF8CursorPosition());
+ end
+end
+
+function AutoCompleteEditBox_AddHighlightedText(editBox, text)
+ if ( not editBox.autoCompleteParams ) then
+ return;
+ end
+ local editBoxText = editBox:GetText();
+ local utf8Position = editBox:GetUTF8CursorPosition();
+ local nameToShow = GetAutoCompleteResults(text, editBox.autoCompleteParams.include, editBox.autoCompleteParams.exclude, 1, utf8Position);
+ if ( nameToShow ) then
+ --We're going to be setting the text programatically which will clear the userInput flag on the editBox. So we want to manually update the dropdown before we change the text.
+ AutoComplete_Update(editBox, editBoxText, utf8Position);
+
+ local newText = string.gsub(editBoxText, editBox.autoCompleteRegex or AUTOCOMPLETE_SIMPLE_REGEX,
+ --DEBUG FIXME - This likely won't work with X-server whispers.
+ string.format(editBox.autoCompleteFormatRegex or AUTOCOMPLETE_SIMPLE_FORMAT_REGEX, nameToShow,
+ string.match(editBoxText, editBox.autoCompleteRegex or AUTOCOMPLETE_SIMPLE_REGEX)),
+ 1)
+ editBox:SetText(newText);
+ editBox:HighlightText(strlen(editBoxText), strlen(newText)); --This won't work if there is more after the name, but we aren't enabling this for normal chat (yet). Please fix me when we do.
+ editBox:SetCursorPosition(strlen(editBoxText));
+ end
+end
+
+function AutoCompleteEditBox_OnChar(self)
+ if (self.addHighlightedText and self:GetUTF8CursorPosition() == strlenutf8(self:GetText())) then
+ AutoCompleteEditBox_AddHighlightedText(self, self:GetText());
+ end
+end
+
+function AutoCompleteEditBox_OnEditFocusLost(self)
+ AutoComplete_HideIfAttachedTo(self);
+end
+
+function AutoCompleteEditBox_OnEscapePressed(self)
+ local autoComplete = AutoCompleteBox;
+ if ( autoComplete:IsShown() and autoComplete.parent == self ) then
+ AutoComplete_HideIfAttachedTo(self);
+ return true;
+ end
+ return false;
+end
+
+function AutoCompleteButton_OnClick(self)
+ local autoComplete = self:GetParent();
+ local editBox = autoComplete.parent;
+ local editBoxText = editBox:GetText();
+
+ --The following is used to replace "/whisper ar message here" with "/whisper Arenai message here"
+ local newText = string.gsub(editBoxText, editBox.autoCompleteRegex or AUTOCOMPLETE_SIMPLE_REGEX,
+ string.format(editBox.autoCompleteFormatRegex or AUTOCOMPLETE_SIMPLE_FORMAT_REGEX, self:GetText(),
+ string.match(editBoxText, editBox.autoCompleteRegex or AUTOCOMPLETE_SIMPLE_REGEX)),
+ 1)
+
+ if ( editBox.addSpaceToAutoComplete ) then
+ newText = newText.." ";
+ end
+
+ editBox:SetText(newText);
+ --When we change the text, we move to the end, so we'll be consistent and move to the end if we don't change it as well.
+ editBox:SetCursorPosition(strlen(newText));
+ autoComplete:Hide();
+end
diff --git a/reference/FrameXML/AutoComplete.xml b/reference/FrameXML/AutoComplete.xml
new file mode 100644
index 0000000..cea56fa
--- /dev/null
+++ b/reference/FrameXML/AutoComplete.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetFontString():SetPoint("LEFT", self, "LEFT", 15, 0)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/BNConversations.lua b/reference/FrameXML/BNConversations.lua
new file mode 100644
index 0000000..2b6a76c
--- /dev/null
+++ b/reference/FrameXML/BNConversations.lua
@@ -0,0 +1,302 @@
+BN_CONVERSATION_INVITE_HEIGHT = 22;
+BN_CONVERSATION_INVITE_NUM_DISPLAYED = 7;
+BN_CONVERSATION_MAX_CHANNEL_MEMBERS = BNGetMaxPlayersInConversation();
+
+function BNConversationInviteDialog_OnLoad(self)
+ self:RegisterEvent("BN_CHAT_CHANNEL_CREATE_SUCCEEDED");
+ self:RegisterEvent("BN_CHAT_CHANNEL_CREATE_FAILED");
+ self:RegisterEvent("BN_FRIEND_ACCOUNT_ONLINE");
+ self:RegisterEvent("BN_FRIEND_ACCOUNT_OFFLINE");
+ -- special popup dialog settings
+ self.hideOnEscape = true;
+ self.exclusive = true;
+
+ BNConversationInvite_Reset();
+end
+
+function BNConversationInviteDialog_OnEvent(self, event, ...)
+ if ( event == "BN_CHAT_CHANNEL_CREATE_SUCCEEDED" ) then
+ local conversationID = ...;
+ BNConversationInvite_UnlockActions();
+ if ( PENDING_BN_WHISPER_TO_CONVERSATION_FRAME and
+ PENDING_BN_WHISPER_TO_CONVERSATION_FRAME.inUse ) then
+ FCF_RestoreChatsToFrame(DEFAULT_CHAT_FRAME, PENDING_BN_WHISPER_TO_CONVERSATION_FRAME);
+ FCF_SetTemporaryWindowType(PENDING_BN_WHISPER_TO_CONVERSATION_FRAME, "BN_CONVERSATION", conversationID);
+ end
+ elseif ( event == "BN_CHAT_CHANNEL_CREATE_FAILED" ) then
+ BNConversationInvite_UnlockActions();
+ elseif ( event == "BN_FRIEND_ACCOUNT_ONLINE" and self:IsShown() ) then
+ BNConversationInvite_Update();
+ elseif ( event == "BN_FRIEND_ACCOUNT_OFFLINE" and self:IsShown() ) then
+ local presenceID = ...;
+ BNConversationInvite_Unlock(presenceID);
+ BNConversationInvite_Deselect(presenceID);
+ end
+end
+
+function BNConversationInviteListCheckButton_OnClick(self, button)
+ local parent = self:GetParent();
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ BNConversationInvite_Select(parent.id);
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ BNConversationInvite_Deselect(parent.id);
+ end
+end
+
+function BNConversationInvite_SelectPlayers(conversationID)
+ BNConversationInvite_SetMode("invite", conversationID);
+
+ BNConversationInvite_Reset();
+
+ for i=1, BNGetNumConversationMembers(conversationID) do
+ local accountID, toonID, name = BNGetConversationMemberInfo(conversationID, i);
+ BNConversationInvite_Lock(accountID);
+ end
+
+ StaticPopupSpecial_Show(BNConversationInviteDialog);
+end
+
+function BNConversationInvite_NewConversation(selected1, selected2)
+ BNConversationInvite_SetMode("create");
+
+ BNConversationInvite_Reset();
+
+ if ( selected1 ) then
+ BNConversationInvite_Select(selected1);
+ BNConversationInvite_Lock(selected1);
+ end
+ if ( selected2 ) then
+ BNConversationInvite_Select(selected2);
+ BNConversationInvite_Lock(selected2);
+ end
+
+ StaticPopupSpecial_Show(BNConversationInviteDialog);
+end
+
+function BNConversationInvite_Reset()
+ BNConversationInviteDialog.inviteTargets = {}; --Probably better to eat the gc than table.wipe in this case.
+ BNConversationInviteDialog.lockedTargets = {};
+ BNConversationInviteDialog.triggeringChatFrame = nil;
+end
+
+function BNConversationInvite_SetMode(mode, target)
+ local frame = BNConversationInviteDialog;
+ frame.mode = mode;
+ frame.target = target;
+
+ if ( mode == "create" ) then
+ frame.instructionText:SetText(NEW_CONVERSATION_INSTRUCTIONS);
+ BNConversationInvite_SetMinMaxInvites(2, 2);
+ elseif ( mode == "invite" ) then
+ local maxInvites = BN_CONVERSATION_MAX_CHANNEL_MEMBERS - BNGetNumConversationMembers(target);
+ frame.instructionText:SetFormattedText(INVITE_CONVERSATION_INSTRUCTIONS, maxInvites);
+ BNConversationInvite_SetMinMaxInvites(1, maxInvites);
+ else
+ error("Unhandled invite type: "..tostring(mode));
+ end
+end
+
+function BNConversationInvite_SetMinMaxInvites(minInvites, maxInvites)
+ local frame = BNConversationInviteDialog;
+ frame.minInvites = minInvites;
+ frame.maxInvites = maxInvites;
+end
+
+function BNConversationInviteDialogInviteButton_OnClick(self, button)
+ local inviteTargets = BNConversationInviteDialog.inviteTargets;
+ if ( BNConversationInviteDialog.mode == "create" ) then
+ if ( BNCreateConversation(inviteTargets[1], inviteTargets[2]) ) then
+ BNConversationInvite_LockActions();
+ PENDING_BN_WHISPER_TO_CONVERSATION_FRAME = BNConversationInviteDialog.triggeringChatFrame;
+ end
+ elseif ( BNConversationInviteDialog.mode == "invite" ) then
+ for _, player in pairs(inviteTargets) do
+ BNInviteToConversation(BNConversationInviteDialog.target, player);
+ end
+ else
+ error("Unhandled invite type: "..tostring(BNConversationInviteDialog.mode))
+ end
+ StaticPopupSpecial_Hide(BNConversationInviteDialog);
+end
+
+function BNConversationInvite_LockActions()
+ BNConversationInviteDialog.actionsLocked = true;
+ BNConversationInvite_UpdateInviteButtonState();
+end
+
+function BNConversationInvite_UnlockActions()
+ BNConversationInviteDialog.actionsLocked = false;
+ BNConversationInvite_UpdateInviteButtonState();
+end
+
+function BNConversationInvite_UpdateInviteButtonState()
+ local dialog = BNConversationInviteDialog;
+ local button = BNConversationInviteDialogInviteButton;
+
+ if ( dialog.actionsLocked or #dialog.inviteTargets < dialog.minInvites ) then
+ button:Disable();
+ else
+ button:Enable();
+ end
+end
+
+function BNConversationInvite_Select(player)
+ local inviteTargets = BNConversationInviteDialog.inviteTargets;
+ if ( not tContains(inviteTargets, player) ) then
+ tinsert(inviteTargets, player);
+ end
+ BNConversationInvite_Update();
+end
+
+function BNConversationInvite_Deselect(player)
+ local inviteTargets = BNConversationInviteDialog.inviteTargets;
+ tDeleteItem(inviteTargets, player);
+ BNConversationInvite_Update();
+end
+
+function BNConversationInvite_Lock(player)
+ local lockedTargets = BNConversationInviteDialog.lockedTargets;
+ if ( not tContains(lockedTargets, player) ) then
+ tinsert(lockedTargets, player);
+ end
+ BNConversationInvite_Update();
+end
+
+function BNConversationInvite_Unlock(player)
+ local lockedTargets = BNConversationInviteDialog.lockedTargets;
+ tDeleteItem(lockedTargets, player);
+ BNConversationInvite_Update();
+end
+
+function BNConversationInvite_Update()
+ local _, numBNetOnline = BNGetNumFriends();
+
+ local offset = FauxScrollFrame_GetOffset(BNConversationInviteDialogListScrollFrame);
+
+ for i=1, BN_CONVERSATION_INVITE_NUM_DISPLAYED do
+ local index = i + offset;
+ local frame = _G["BNConversationInviteDialogListFriend"..i];
+ if ( index <= numBNetOnline ) then
+ local friendIndex = index;
+ local presenceID, givenName, surname = BNGetFriendInfo(friendIndex);
+ frame.name:SetFormattedText(BATTLENET_NAME_FORMAT, givenName, surname);
+ frame.id = presenceID;
+ frame:Show();
+ else
+ frame:Hide();
+ end
+
+ frame.checkButton:SetChecked(tContains(BNConversationInviteDialog.inviteTargets, frame.id));
+
+ if ( tContains(BNConversationInviteDialog.lockedTargets, frame.id) or
+ (#BNConversationInviteDialog.inviteTargets >= BNConversationInviteDialog.maxInvites and --Disable everything if we've checked the max amount
+ not frame.checkButton:GetChecked() ) ) then --Never disable a button that is already checked) then
+ frame.checkButton:Disable();
+ frame.name:SetFontObject("GameFontDisable");
+ else
+ frame.checkButton:Enable();
+ frame.name:SetFontObject("GameFontHighlight");
+ end
+
+ end
+
+ BNConversationInvite_UpdateInviteButtonState();
+ FauxScrollFrame_Update(BNConversationInviteDialogListScrollFrame, numBNetOnline, BN_CONVERSATION_INVITE_NUM_DISPLAYED, BN_CONVERSATION_INVITE_HEIGHT);
+end
+
+----Member list functions.
+function BNConversationButton_OnLoad(self)
+ self.chatFrame = _G["ChatFrame"..self:GetID()];
+ self.chatFrame.conversationButton = self;
+
+ BNConversationButton_UpdateAttachmentPoint(self);
+ BNConversationButton_UpdateTarget(self);
+
+ self:RegisterEvent("BN_CHAT_CHANNEL_LEFT");
+ self:RegisterEvent("BN_CHAT_CHANNEL_JOINED");
+end
+
+function BNConversationButton_OnClick(self, button)
+ if ( self.chatType == "BN_CONVERSATION" ) then
+ local frame = BNConversationInviteDialog;
+ if ( frame:IsShown() and frame.target == self.chatTarget ) then
+ StaticPopupSpecial_Hide(frame)
+ else
+ BNConversationInvite_SelectPlayers(self.chatTarget);
+ end
+ else
+ BNConversationInvite_NewConversation(BNet_GetPresenceID(self.chatTarget));
+ BNConversationInviteDialog.triggeringChatFrame = self.chatFrame;
+ end
+end
+
+function BNConversationButton_OnEvent(self, event, ...)
+ local arg1 = ...;
+ if ( event == "BN_CHAT_CHANNEL_LEFT" and arg1 == self.chatTarget ) then
+ BNConversationButton_UpdateEnabledState(self);
+ elseif ( event == "BN_CHAT_CHANNEL_JOINED" and arg1 == self.chatTarget ) then
+ BNConversationButton_UpdateEnabledState(self);
+ end
+end
+
+function BNConversationButton_UpdateEnabledState(self)
+ if ( self.chatType ~= "BN_CONVERSATION" or BNGetConversationInfo(self.chatTarget) ) then
+ self:Enable();
+ else
+ self:Disable();
+ end
+end
+
+function BNConversationButton_OnEnter(self, motion)
+ if ( self.chatType == "BN_CONVERSATION" ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ BNConversation_DisplayConversationTooltip(self.chatTarget);
+
+ GameTooltip:AddLine(" ");
+ GameTooltip:AddLine(CLICK_TO_INVITE_TO_CONVERSATION, nil, nil, nil, true);
+ GameTooltip:Show();
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:AddLine(CLICK_TO_START_CONVERSATION, nil, nil, nil, true);
+ GameTooltip:Show();
+ end
+end
+
+function BNConversation_DisplayConversationTooltip(conversationID)
+ local info = ChatTypeInfo["BN_CONVERSATION"];
+ GameTooltip:SetText(format(CONVERSATION_NAME, conversationID + MAX_WOW_CHAT_CHANNELS), info.r, info.g, info.b);
+
+ for i=1, BNGetNumConversationMembers(conversationID) do
+ local accountID, toonID, name = BNGetConversationMemberInfo(conversationID, i);
+ GameTooltip:AddLine(name, FRIENDS_BNET_NAME_COLOR.r, FRIENDS_BNET_NAME_COLOR.g, FRIENDS_BNET_NAME_COLOR.b);
+ end
+
+ GameTooltip:Show();
+end
+
+function BNConversationButton_OnLeave(self, motion)
+ if ( GameTooltip:GetOwner() == self ) then
+ GameTooltip:Hide();
+ end
+end
+
+function BNConversationButton_UpdateAttachmentPoint(self)
+ local chatFrame = self.chatFrame;
+
+ if ( chatFrame.isDocked ) then
+ self:SetPoint("BOTTOM", chatFrame.buttonFrame.upButton, "TOP", 0, 0);
+ else
+ self:SetPoint("BOTTOM", chatFrame.buttonFrame.minimizeButton, "TOP", 0, 0);
+ end
+end
+
+function BNConversationButton_UpdateTarget(self)
+ local chatFrame = self.chatFrame;
+ local chatTarget = tonumber(chatFrame.chatTarget) or chatFrame.chatTarget;
+
+ self.chatType = chatFrame.chatType;
+ self.chatTarget = chatTarget;
+ BNConversationButton_UpdateEnabledState(self);
+end
\ No newline at end of file
diff --git a/reference/FrameXML/BNConversations.xml b/reference/FrameXML/BNConversations.xml
new file mode 100644
index 0000000..c11b596
--- /dev/null
+++ b/reference/FrameXML/BNConversations.xml
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+
+
+
+ BNConversationButton_OnLoad(self);
+
+
+ BNConversationButton_OnEvent(self, event, ...);
+
+
+ BNConversationButton_OnClick(self, button);
+
+
+ BNConversationButton_OnEnter(self, motion);
+
+
+ BNConversationButton_OnLeave(self, motion);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BNConversationInviteListCheckButton_OnClick(self, button);
+
+
+
+
+
+
+ self.name:SetPoint("LEFT", self.checkButton, "RIGHT", 3, 2);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, BN_CONVERSATION_INVITE_HEIGHT, BNConversationInvite_Update)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopupSpecial_Hide(BNConversationInviteDialog);
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOpen");
+ BNConversationInvite_Update();
+
+
+ PlaySound("igMainMenuClose");
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/BNet.lua b/reference/FrameXML/BNet.lua
new file mode 100644
index 0000000..79403be
--- /dev/null
+++ b/reference/FrameXML/BNet.lua
@@ -0,0 +1,353 @@
+local BNToasts = { };
+local BNToastEvents = {
+ showToastOnline = { "BN_FRIEND_ACCOUNT_ONLINE" },
+ showToastOffline = { "BN_FRIEND_ACCOUNT_OFFLINE" },
+ showToastBroadcast = { "BN_CUSTOM_MESSAGE_CHANGED" },
+ showToastFriendRequest = { "BN_FRIEND_INVITE_ADDED", "BN_FRIEND_INVITE_LIST_INITIALIZED" },
+ showToastConversation = { "BN_CHAT_CHANNEL_JOINED" },
+};
+local BN_TOAST_TYPE_ONLINE = 1;
+local BN_TOAST_TYPE_OFFLINE = 2;
+local BN_TOAST_TYPE_BROADCAST = 3;
+local BN_TOAST_TYPE_PENDING_INVITES = 4;
+local BN_TOAST_TYPE_NEW_INVITE = 5;
+local BN_TOAST_TYPE_CONVERSATION = 6;
+BN_TOAST_TOP_OFFSET = 40;
+BN_TOAST_BOTTOM_OFFSET = -12;
+BN_TOAST_RIGHT_OFFSET = -1;
+BN_TOAST_LEFT_OFFSET = 1;
+BN_TOAST_TOP_BUFFER = 20; -- the minimum distance in pixels from the toast to the top edge of the screen
+BN_TOAST_MAX_LINE_WIDTH = 196;
+
+function BNet_OnLoad(self)
+ self:RegisterEvent("BN_TOON_NAME_UPDATED");
+ self:RegisterEvent("BN_NEW_PRESENCE");
+ self:RegisterEvent("BN_CONNECTED");
+ self:RegisterEvent("BN_DISCONNECTED");
+end
+
+function BNet_OnEvent(self, event, ...)
+ if ( event == "BN_CONNECTED" ) then
+ SynchronizeBNetStatus();
+ elseif ( event == "BN_DISCONNECTED" ) then
+ table.wipe(BNToasts);
+ end
+end
+
+function BNet_GetPresenceID(name)
+ return GetAutoCompletePresenceID(name);
+end
+
+-- BNET toast
+function BNToastFrame_OnEvent(self, event, arg1)
+ if ( event == "BN_FRIEND_ACCOUNT_ONLINE" ) then
+ BNToastFrame_AddToast(BN_TOAST_TYPE_ONLINE, arg1);
+ elseif ( event == "BN_FRIEND_ACCOUNT_OFFLINE" ) then
+ BNToastFrame_AddToast(BN_TOAST_TYPE_OFFLINE, arg1);
+ elseif ( event == "BN_CUSTOM_MESSAGE_CHANGED" ) then
+ if ( arg1 ) then
+ BNToastFrame_AddToast(BN_TOAST_TYPE_BROADCAST, arg1);
+ end
+ elseif ( event == "BN_FRIEND_INVITE_ADDED" ) then
+ BNToastFrame_AddToast(BN_TOAST_TYPE_NEW_INVITE);
+ elseif ( event == "BN_CHAT_CHANNEL_JOINED" ) then
+ BNToastFrame_AddToast(BN_TOAST_TYPE_CONVERSATION, arg1);
+ elseif ( event == "BN_FRIEND_INVITE_LIST_INITIALIZED" ) then
+ BNToastFrame_AddToast(BN_TOAST_TYPE_PENDING_INVITES, arg1);
+ elseif( event == "VARIABLES_LOADED" ) then
+ BNet_SetToastDuration(GetCVar("toastDuration"));
+ if ( GetCVarBool("showToastWindow") ) then
+ BNet_EnableToasts();
+ end
+ end
+end
+
+function BNet_EnableToasts()
+ local frame = BNToastFrame;
+ for cvar, events in pairs(BNToastEvents) do
+ if ( GetCVarBool(cvar) ) then
+ for _, event in pairs(events) do
+ frame:RegisterEvent(event);
+ end
+ end
+ end
+end
+
+function BNet_DisableToasts()
+ local frame = BNToastFrame;
+ frame:UnregisterAllEvents();
+ table.wipe(BNToasts);
+ frame:Hide();
+end
+
+function BNet_UpdateToastEvent(cvar, value)
+ if ( GetCVarBool("showToastWindow") ) then
+ local frame = BNToastFrame;
+ local events = BNToastEvents[cvar];
+ if ( value == "1" ) then
+ for _, event in pairs(events) do
+ frame:RegisterEvent(event);
+ end
+ else
+ for _, event in pairs(events) do
+ frame:UnregisterEvent(event);
+ end
+ end
+ end
+end
+
+function BNet_SetToastDuration(duration)
+ BNToastFrame.duration = duration;
+end
+
+function BNToastFrame_Show()
+ local toastType = BNToasts[1].toastType;
+ local toastData = BNToasts[1].toastData;
+ tremove(BNToasts, 1);
+ local topLine = BNToastFrameTopLine;
+ local bottomLine = BNToastFrameBottomLine;
+ if ( toastType == BN_TOAST_TYPE_NEW_INVITE ) then
+ BNToastFrameIconTexture:SetTexCoord(0.75, 1, 0, 0.5);
+ topLine:Hide();
+ bottomLine:Hide();
+ BNToastFrameDoubleLine:Show();
+ BNToastFrameDoubleLine:SetText(BN_TOAST_NEW_INVITE);
+ elseif ( toastType == BN_TOAST_TYPE_PENDING_INVITES ) then
+ BNToastFrameIconTexture:SetTexCoord(0.75, 1, 0, 0.5);
+ topLine:Hide();
+ bottomLine:Hide();
+ BNToastFrameDoubleLine:Show();
+ BNToastFrameDoubleLine:SetFormattedText(BN_TOAST_PENDING_INVITES, toastData);
+ elseif ( toastType == BN_TOAST_TYPE_ONLINE ) then
+ local presenceID, givenName, surname = BNGetFriendInfoByID(toastData);
+ -- don't display a toast if we didn't get the data in time
+ if ( not givenName or not surname ) then
+ return;
+ end
+ BNToastFrameIconTexture:SetTexCoord(0, 0.25, 0.5, 1);
+ topLine:Show();
+ topLine:SetFormattedText(BATTLENET_NAME_FORMAT, givenName, surname);
+ topLine:SetTextColor(FRIENDS_BNET_NAME_COLOR.r, FRIENDS_BNET_NAME_COLOR.g, FRIENDS_BNET_NAME_COLOR.b);
+ bottomLine:Show();
+ bottomLine:SetText(BN_TOAST_ONLINE);
+ bottomLine:SetTextColor(FRIENDS_GRAY_COLOR.r, FRIENDS_GRAY_COLOR.g, FRIENDS_GRAY_COLOR.b);
+ BNToastFrameDoubleLine:Hide();
+ elseif ( toastType == BN_TOAST_TYPE_OFFLINE ) then
+ local presenceID, givenName, surname = BNGetFriendInfoByID(toastData);
+ -- don't display a toast if we didn't get the data in time
+ if ( not givenName or not surname ) then
+ return;
+ end
+ BNToastFrameIconTexture:SetTexCoord(0, 0.25, 0.5, 1);
+ topLine:Show();
+ topLine:SetFormattedText(BATTLENET_NAME_FORMAT, givenName, surname);
+ topLine:SetTextColor(FRIENDS_BNET_NAME_COLOR.r, FRIENDS_BNET_NAME_COLOR.g, FRIENDS_BNET_NAME_COLOR.b);
+ bottomLine:Show();
+ bottomLine:SetText(BN_TOAST_OFFLINE);
+ bottomLine:SetTextColor(FRIENDS_GRAY_COLOR.r, FRIENDS_GRAY_COLOR.g, FRIENDS_GRAY_COLOR.b);
+ BNToastFrameDoubleLine:Hide();
+ elseif ( toastType == BN_TOAST_TYPE_CONVERSATION ) then
+ BNToastFrameIconTexture:SetTexCoord(0.5, 0.75, 0, 0.5);
+ topLine:Show();
+ topLine:SetText(BN_TOAST_CONVERSATION);
+ topLine:SetTextColor(FRIENDS_GRAY_COLOR.r, FRIENDS_GRAY_COLOR.g, FRIENDS_GRAY_COLOR.b);
+ bottomLine:Show();
+ bottomLine:SetText("["..string.format(CONVERSATION_NAME, MAX_WOW_CHAT_CHANNELS + toastData).."]");
+ bottomLine:SetTextColor(ChatTypeInfo["BN_CONVERSATION"].r, ChatTypeInfo["BN_CONVERSATION"].g, ChatTypeInfo["BN_CONVERSATION"].b);
+ BNToastFrameDoubleLine:Hide();
+ elseif ( toastType == BN_TOAST_TYPE_BROADCAST ) then
+ local presenceID, givenName, surname, toonName, toonID, client, isOnline, lastOnline, isAFK, isDND, messageText = BNGetFriendInfoByID(toastData);
+ if ( not messageText or messageText == "" ) then
+ return;
+ end
+ BNToastFrameIconTexture:SetTexCoord(0, 0.25, 0, 0.5);
+ topLine:Show();
+ topLine:SetFormattedText(BATTLENET_NAME_FORMAT, givenName, surname);
+ topLine:SetTextColor(FRIENDS_BNET_NAME_COLOR.r, FRIENDS_BNET_NAME_COLOR.g, FRIENDS_BNET_NAME_COLOR.b);
+ bottomLine:Show();
+ bottomLine:SetWidth(0);
+ bottomLine:SetText(messageText);
+ if ( bottomLine:GetWidth() > BN_TOAST_MAX_LINE_WIDTH ) then
+ bottomLine:SetWidth(BN_TOAST_MAX_LINE_WIDTH);
+ BNToastFrame.tooltip = messageText;
+ end
+ bottomLine:SetTextColor(FRIENDS_GRAY_COLOR.r, FRIENDS_GRAY_COLOR.g, FRIENDS_GRAY_COLOR.b);
+ BNToastFrameDoubleLine:Hide();
+ end
+
+ local frame = BNToastFrame;
+ BNToastFrame_UpdateAnchor(true);
+ frame:Show();
+ PlaySound(18019);
+ frame.toastType = toastType;
+ frame.toastData = toastData;
+ frame.animIn:Play();
+ BNToastFrameGlowFrame.glow.animIn:Play();
+ frame.waitAndAnimOut:Stop(); --Just in case it's already animating out, but we want to reinstate it.
+ if ( frame:IsMouseOver() ) then
+ frame.waitAndAnimOut.animOut:SetStartDelay(1);
+ else
+ frame.waitAndAnimOut.animOut:SetStartDelay(frame.duration);
+ frame.waitAndAnimOut:Play();
+ end
+end
+
+function BNToastFrame_Close()
+ BNToastFrame.tooltip = nil;
+ BNToastFrame:Hide();
+end
+
+function BNToastFrame_OnUpdate()
+ if ( next(BNToasts) and not BNToastFrame:IsShown() ) then
+ BNToastFrame_Show();
+ end
+end
+
+function BNToastFrame_AddToast(toastType, toastData)
+ local toast = { };
+ toast.toastType = toastType;
+ toast.toastData = toastData;
+ BNToastFrame_RemoveToast(toastType, toastData);
+ tinsert(BNToasts, toast);
+end
+
+function BNToastFrame_RemoveToast(toastType, toastData)
+ for i = 1, #BNToasts do
+ if ( BNToasts[i].toastType == toastType and BNToasts[i].toastData == toastData ) then
+ tremove(BNToasts, i);
+ break;
+ end
+ end
+end
+
+function BNToastFrame_UpdateAnchor(forceAnchor)
+ local chatFrame = DEFAULT_CHAT_FRAME;
+ local toastFrame = BNToastFrame;
+ local offscreen = chatFrame.buttonFrame:GetTop() + BNToastFrame:GetHeight() + BN_TOAST_TOP_OFFSET + BN_TOAST_TOP_BUFFER > GetScreenHeight();
+
+ if ( chatFrame.buttonSide ~= toastFrame.buttonSide ) then
+ forceAnchor = true;
+ end
+ if ( offscreen and toastFrame.topSide ) then
+ forceAnchor = true;
+ toastFrame.topSide = false;
+ elseif ( not offscreen and not toastFrame.topSide ) then
+ forceAnchor = true;
+ toastFrame.topSide = true;
+ end
+ if ( forceAnchor ) then
+ toastFrame:ClearAllPoints();
+ toastFrame.buttonSide = chatFrame.buttonSide;
+ local xOffset = BN_TOAST_LEFT_OFFSET;
+ if ( toastFrame.buttonSide == "right" ) then
+ xOffset = BN_TOAST_RIGHT_OFFSET;
+ end
+ if ( toastFrame.topSide ) then
+ toastFrame:SetPoint("BOTTOM"..toastFrame.buttonSide, chatFrame.buttonFrame, "TOP"..toastFrame.buttonSide, xOffset, BN_TOAST_TOP_OFFSET);
+ else
+ local yOffset = BN_TOAST_BOTTOM_OFFSET;
+ if ( GetCVar("chatStyle") == "im" ) then
+ yOffset = yOffset - 20;
+ end
+ toastFrame:SetPoint("TOP"..toastFrame.buttonSide, chatFrame.buttonFrame, "BOTTOM"..toastFrame.buttonSide, xOffset, yOffset);
+ end
+ end
+end
+
+function BNToastFrame_OnClick(self)
+ -- hide the tooltip if necessary
+ if ( BNToastFrame.tooltip and GameTooltip:GetOwner() == BNToastFrame ) then
+ GameTooltip:Hide();
+ end
+ BNToastFrame_Close();
+ local toastType = BNToastFrame.toastType;
+ local toastData = BNToastFrame.toastData;
+ if ( toastType == BN_TOAST_TYPE_NEW_INVITE or toastType == BN_TOAST_TYPE_PENDING_INVITES ) then
+ if ( not FriendsFrame:IsShown() ) then
+ ToggleFriendsFrame(1);
+ end
+ FriendsTabHeaderTab3:Click();
+ elseif ( toastType == BN_TOAST_TYPE_CONVERSATION ) then
+ -- clicking the toast should switch to the chat tab for this conversation, or if not found (usually if using in-line option) switch to any tab displaying conversations
+ local chatFrame = DEFAULT_CHAT_FRAME;
+ for _, frameName in pairs(CHAT_FRAMES) do
+ local frame = _G[frameName];
+ local channel = tostring(toastData);
+ if ( frame.chatType == "BN_CONVERSATION" and frame.chatTarget == channel ) then
+ chatFrame = frame;
+ break;
+ else
+ if ( frame:IsEventRegistered("CHAT_MSG_BN_CONVERSATION") ) then
+ chatFrame = frame;
+ end
+ end
+ end
+ _G[chatFrame:GetName().."Tab"]:Click();
+ --ChatFrame_OpenChat("/"..(toastData + MAX_WOW_CHAT_CHANNELS), chatFrame);
+ elseif ( toastType == BN_TOAST_TYPE_ONLINE or toastType == BN_TOAST_TYPE_BROADCAST ) then
+ local presenceID, givenName, surname = BNGetFriendInfoByID(toastData);
+ ChatFrame_SendTell(string.format(BATTLENET_NAME_FORMAT, givenName, surname));
+ end
+end
+
+function SynchronizeBNetStatus()
+ if ( BNFeaturesEnabledAndConnected() ) then
+ local wowAFK = (UnitIsAFK("player") == 1);
+ local wowDND = (UnitIsDND("player") == 1);
+ local _, _, _, bnetAFK, bnetDND = BNGetInfo();
+ if ( wowAFK ~= bnetAFK ) then
+ BNSetAFK(wowAFK);
+ end
+ if ( wowDND ~= bnetDND ) then
+ BNSetDND(wowDND);
+ end
+ end
+end
+
+function BNet_InitiateReport(presenceID, reportType)
+ local reportFrame = BNetReportFrame;
+ if ( reportFrame:IsShown() ) then
+ StaticPopupSpecial_Hide(reportFrame);
+ end
+ CloseDropDownMenus();
+ -- set up
+ local fullName;
+ if ( not presenceID ) then
+ -- invite
+ presenceID, givenName, surname = BNGetFriendInviteInfo(UIDROPDOWNMENU_MENU_VALUE);
+ fullName = string.format(BATTLENET_NAME_FORMAT, givenName, surname);
+ else
+ local _, givenName, surname, toonName = BNGetFriendInfoByID(presenceID);
+ if ( givenName and surname ) then
+ if ( toonName ) then
+ fullName = string.format(BATTLENET_NAME_FORMAT, givenName, surname).." ("..toonName..")";
+ else
+ fullName = string.format(BATTLENET_NAME_FORMAT, givenName, surname);
+ end
+ else
+ local _, toonName = BNGetToonInfo(presenceID);
+ fullName = toonName;
+ end
+ end
+ reportFrame.presenceID = presenceID;
+ reportFrame.type = reportType;
+ reportFrame.name = fullName;
+ BNetReportFrameCommentBox:SetText("");
+
+ if ( reportType == "SPAM" or reportType == "NAME" ) then
+ StaticPopup_Show("CONFIRM_BNET_REPORT", format(_G["BNET_REPORT_CONFIRM_"..reportType], fullName));
+ elseif ( reportType == "ABUSE" ) then
+ BNetReportFrameName:SetText(fullName);
+ StaticPopupSpecial_Show(reportFrame);
+ end
+end
+
+function BNet_ConfirmReport()
+ StaticPopup_Show("CONFIRM_BNET_REPORT", format(_G["BNET_REPORT_CONFIRM_"..BNetReportFrame.type], BNetReportFrame.name));
+end
+
+function BNet_SendReport()
+ local reportFrame = BNetReportFrame;
+ local comments = BNetReportFrameCommentBox:GetText();
+ BNReportPlayer(reportFrame.presenceID, reportFrame.type, comments);
+end
\ No newline at end of file
diff --git a/reference/FrameXML/BNet.xml b/reference/FrameXML/BNet.xml
new file mode 100644
index 0000000..ad65965
--- /dev/null
+++ b/reference/FrameXML/BNet.xml
@@ -0,0 +1,393 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BNToastFrame_Close();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AlertFrame_StopOutAnimation(BNToastFrame);
+ if ( BNToastFrame.tooltip ) then
+ GameTooltip:SetOwner(BNToastFrame, "ANCHOR_RIGHT");
+ GameTooltip:SetText(BNToastFrame.tooltip, FRIENDS_GRAY_COLOR.r, FRIENDS_GRAY_COLOR.g, FRIENDS_GRAY_COLOR.b, 1, 1);
+ GameTooltip:Show();
+ end
+
+
+ AlertFrame_ResumeOutAnimation(BNToastFrame);
+ if ( BNToastFrame.tooltip ) then
+ GameTooltip:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AlertFrame_StopOutAnimation(BNToastFrame);
+
+
+ AlertFrame_ResumeOutAnimation(BNToastFrame);
+
+
+
+
+
+
+
+ BNToastFrameDoubleLine:SetSpacing(3);
+ local frameLevel = BNToastFrameClickFrame:GetFrameLevel();
+ BNToastFrameCloseButton:SetFrameLevel(frameLevel + 1);
+ BNToastFrameGlowFrame:SetFrameLevel(frameLevel + 2);
+ self:RegisterEvent("VARIABLES_LOADED");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BNetReportFrameCommentBox:SetFocus();
+
+
+
+
+
+
+ local scrollBar = _G[self:GetName().."ScrollBar"];
+ scrollBar:SetFrameLevel(_G[self:GetName().."FocusButton"]:GetFrameLevel() + 2);
+ scrollBar:ClearAllPoints();
+ scrollBar:SetPoint("TOPLEFT", self, "TOPRIGHT", -18, -10);
+ scrollBar:SetPoint("BOTTOMLEFT", self, "BOTTOMRIGHT", -18, 8);
+ -- reposition the up and down buttons
+ _G[self:GetName().."ScrollBarScrollDownButton"]:SetPoint("TOP", scrollBar, "BOTTOM", 0, 4);
+ _G[self:GetName().."ScrollBarScrollUpButton"]:SetPoint("BOTTOM", scrollBar, "TOP", 0, -4);
+ -- make the scroll bar hideable and force it to start off hidden so positioning calculations can be done
+ -- as soon as it needs to be shown
+ self.scrollBarHideable = 1;
+ scrollBar:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent());
+ if ( self:GetText() ~= "" ) then
+ BNetReportFrameCommentBoxFill:Hide();
+ else
+ BNetReportFrameCommentBoxFill:Show();
+ end
+
+
+
+ ScrollingEdit_OnUpdate(self, elapsed, self:GetParent());
+
+
+ self:ClearFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopupSpecial_Hide(BNetReportFrame);
+
+
+
+
+
+
+ self.exclusive = true;
+ self.hideOnEscape = true;
+
+
+ PlaySound("igMainMenuOpen");
+
+
+ PlaySound("igMainMenuClose");
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/BankFrame.lua b/reference/FrameXML/BankFrame.lua
new file mode 100644
index 0000000..8301c05
--- /dev/null
+++ b/reference/FrameXML/BankFrame.lua
@@ -0,0 +1,270 @@
+function ButtonInventorySlot (self)
+ return BankButtonIDToInvSlotID(self:GetID(),self.isBag)
+end
+
+function BankFrameBaseButton_OnLoad (self)
+ self:RegisterForDrag("LeftButton");
+ self:RegisterForClicks("LeftButtonUp","RightButtonUp");
+ self.GetInventorySlot = ButtonInventorySlot;
+ self.UpdateTooltip = BankFrameItemButton_OnEnter;
+end
+
+function BankFrameItemButton_OnLoad (self)
+ BankFrameBaseButton_OnLoad (self);
+ self.SplitStack = function(button, split)
+ SplitContainerItem(BANK_CONTAINER, button:GetID(), split);
+ end
+end
+
+function BankFrameBagButton_OnLoad (self)
+ self.isBag = 1;
+ BankFrameBaseButton_OnLoad(self);
+end
+
+function BankFrameItemButton_OnEnter (self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( not GameTooltip:SetInventoryItem("player", self:GetInventorySlot()) ) then
+ if ( self.isBag ) then
+ GameTooltip:SetText(self.tooltipText);
+ end
+ end
+ CursorUpdate(self);
+end
+
+function BankFrameItemButton_Update (button)
+ local texture = _G[button:GetName().."IconTexture"];
+ local inventoryID = button:GetInventorySlot();
+ local textureName = GetInventoryItemTexture("player",inventoryID);
+ local slotName = button:GetName();
+ local id;
+ local slotTextureName;
+ button.hasItem = nil;
+
+ if( button.isBag ) then
+ id, slotTextureName = GetInventorySlotInfo(strsub(slotName,10));
+ else
+ local isQuestItem, questId, isActive = GetContainerItemQuestInfo(BANK_CONTAINER, button:GetID());
+ local questTexture = _G[button:GetName().."IconQuestTexture"];
+ if ( questId and not isActive ) then
+ questTexture:SetTexture(TEXTURE_ITEM_QUEST_BANG);
+ questTexture:Show();
+ elseif ( questId or isQuestItem ) then
+ questTexture:SetTexture(TEXTURE_ITEM_QUEST_BORDER);
+ questTexture:Show();
+ else
+ questTexture:Hide();
+ end
+ end
+
+ if ( textureName ) then
+ texture:SetTexture(textureName);
+ texture:Show();
+ SetItemButtonCount(button,GetInventoryItemCount("player",inventoryID));
+ button.hasItem = 1;
+ elseif ( slotTextureName and button.isBag ) then
+ texture:SetTexture(slotTextureName);
+ SetItemButtonCount(button,0);
+ texture:Show();
+ else
+ texture:Hide();
+ SetItemButtonCount(button,0);
+ end
+
+ BankFrameItemButton_UpdateLocked(button);
+ BankFrame_UpdateCooldown(BANK_CONTAINER, button);
+end
+
+function BankFrame_UpdateCooldown(container, button)
+ local cooldown = _G[button:GetName().."Cooldown"];
+ local start, duration, enable = GetContainerItemCooldown(container, button:GetID());
+ CooldownFrame_SetTimer(cooldown, start, duration, enable);
+ if ( duration > 0 and enable == 0 ) then
+ SetItemButtonTextureVertexColor(button, 0.4, 0.4, 0.4);
+ end
+end
+
+function BankFrameItemButton_UpdateLocked (button)
+ local inventoryID = button:GetInventorySlot();
+ if ( IsInventoryItemLocked(inventoryID) ) then
+ SetItemButtonDesaturated(button, 1, 0.5, 0.5, 0.5);
+ else
+ if ( button.isBag and ((button:GetID() - 4) > GetNumBankSlots()) ) then
+ return;
+ end
+ SetItemButtonDesaturated(button, nil, 0.5, 0.5, 0.5);
+ end
+end
+
+function BankFrame_OnLoad (self)
+ self:RegisterEvent("BANKFRAME_OPENED");
+ self:RegisterEvent("BANKFRAME_CLOSED");
+end
+
+function UpdateBagSlotStatus ()
+ local purchaseFrame = BankFramePurchaseInfo;
+ if( purchaseFrame == nil ) then
+ return;
+ end
+
+ local numSlots,full = GetNumBankSlots();
+ local button;
+ for i=1, NUM_BANKBAGSLOTS, 1 do
+ button = _G["BankFrameBag"..i];
+ if ( button ) then
+ if ( i <= numSlots ) then
+ SetItemButtonTextureVertexColor(button, 1.0,1.0,1.0);
+ button.tooltipText = BANK_BAG;
+ else
+ SetItemButtonTextureVertexColor(button, 1.0,0.1,0.1);
+ button.tooltipText = BANK_BAG_PURCHASE;
+ end
+ end
+ end
+
+ -- pass in # of current slots, returns cost of next slot
+ local cost = GetBankSlotCost(numSlots);
+ BankFrame.nextSlotCost = cost;
+ if( GetMoney() >= cost ) then
+ SetMoneyFrameColor("BankFrameDetailMoneyFrame", "white");
+ else
+ SetMoneyFrameColor("BankFrameDetailMoneyFrame", "red")
+ end
+ MoneyFrame_Update("BankFrameDetailMoneyFrame", cost);
+
+ if( full ) then
+ purchaseFrame:Hide();
+ else
+ purchaseFrame:Show();
+ end
+end
+
+function CloseBankBagFrames ()
+ for i=NUM_BAG_SLOTS+1, (NUM_BAG_SLOTS + NUM_BANKBAGSLOTS), 1 do
+ CloseBag(i);
+ end
+end
+
+function BankFrame_OnEvent (self, event, ...)
+ if ( event == "BANKFRAME_OPENED" ) then
+ BankFrameTitleText:SetText(UnitName("npc"));
+ SetPortraitTexture(BankPortraitTexture,"npc");
+ ShowUIPanel(self);
+ if ( not self:IsShown() ) then
+ CloseBankFrame();
+ end
+ elseif ( event == "BANKFRAME_CLOSED" ) then
+ HideUIPanel(self);
+ elseif ( event == "ITEM_LOCK_CHANGED" ) then
+ local bag, slot = ...;
+ if ( bag == BANK_CONTAINER ) then
+ if ( slot <= NUM_BANKGENERIC_SLOTS ) then
+ BankFrameItemButton_UpdateLocked(_G["BankFrameItem"..slot]);
+ else
+ BankFrameItemButton_UpdateLocked(_G["BankFrameBag"..(slot-NUM_BANKGENERIC_SLOTS)]);
+ end
+ end
+ elseif ( event == "PLAYERBANKSLOTS_CHANGED" ) then
+ local slot = ...;
+ if ( slot <= NUM_BANKGENERIC_SLOTS ) then
+ BankFrameItemButton_Update(_G["BankFrameItem"..slot]);
+ else
+ BankFrameItemButton_Update(_G["BankFrameBag"..(slot-NUM_BANKGENERIC_SLOTS)]);
+ end
+ elseif ( event == "PLAYER_MONEY" or event == "PLAYERBANKBAGSLOTS_CHANGED" ) then
+ UpdateBagSlotStatus();
+ end
+end
+
+function BankFrame_OnShow (self)
+ PlaySound("igMainMenuOpen");
+
+ self:RegisterEvent("ITEM_LOCK_CHANGED");
+ self:RegisterEvent("PLAYERBANKSLOTS_CHANGED");
+ self:RegisterEvent("PLAYERBANKBAGSLOTS_CHANGED");
+ self:RegisterEvent("PLAYER_MONEY");
+ self:RegisterEvent("BAG_UPDATE_COOLDOWN");
+
+ local button;
+ for i=1, NUM_BANKGENERIC_SLOTS, 1 do
+ button = _G["BankFrameItem"..i];
+ BankFrameItemButton_Update(button);
+ end
+
+ for i=1, NUM_BANKBAGSLOTS, 1 do
+ button = _G["BankFrameBag"..i];
+ BankFrameItemButton_Update(button);
+ end
+ UpdateBagSlotStatus();
+end
+
+function BankFrame_OnHide (self)
+ PlaySound("igMainMenuClose");
+
+ self:UnregisterEvent("ITEM_LOCK_CHANGED");
+ self:UnregisterEvent("PLAYERBANKSLOTS_CHANGED");
+ self:UnregisterEvent("PLAYERBANKBAGSLOTS_CHANGED");
+ self:UnregisterEvent("PLAYER_MONEY");
+
+ StaticPopup_Hide("CONFIRM_BUY_BANK_SLOT");
+ CloseBankBagFrames();
+ CloseBankFrame();
+ updateContainerFrameAnchors();
+end
+
+function BankFrameItemButtonGeneric_OnClick (self, button)
+ if ( button == "LeftButton" ) then
+ PickupContainerItem(BANK_CONTAINER, self:GetID());
+ else
+ UseContainerItem(BANK_CONTAINER, self:GetID());
+ end
+end
+
+function BankFrameItemButtonGeneric_OnModifiedClick (self, button)
+ if ( self.isBag ) then
+ return;
+ end
+ if ( HandleModifiedItemClick(GetContainerItemLink(BANK_CONTAINER, self:GetID())) ) then
+ return;
+ end
+ if ( IsModifiedClick("SPLITSTACK") ) then
+ local texture, itemCount, locked = GetContainerItemInfo(BANK_CONTAINER, self:GetID());
+ if ( not locked ) then
+ OpenStackSplitFrame(self.count, self, "BOTTOMLEFT", "TOPLEFT");
+ end
+ return;
+ end
+end
+
+function UpdateBagButtonHighlight (id)
+ local texture = _G["BankFrameBag"..(id - NUM_BAG_SLOTS).."HighlightFrameTexture"];
+ if ( not texture ) then
+ return;
+ end
+
+ local frame;
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ frame = _G["ContainerFrame"..i];
+ if ( ( frame:GetID() == id ) and frame:IsShown() ) then
+ texture:Show();
+ return;
+ end
+ end
+ texture:Hide();
+end
+
+function BankFrameItemButtonBag_OnClick (self, button)
+ local inventoryID = self:GetInventorySlot();
+ local hadItem = PutItemInBag(inventoryID);
+ local id = self:GetID();
+ if ( not hadItem ) then
+ -- open bag
+ ToggleBag(id);
+ end
+ UpdateBagButtonHighlight(id);
+end
+
+function BankFrameItemButtonBag_Pickup (self)
+ local inventoryID = self:GetInventorySlot();
+ PickupBagFromSlot(inventoryID);
+ UpdateBagButtonHighlight(self:GetID());
+end
diff --git a/reference/FrameXML/BankFrame.xml b/reference/FrameXML/BankFrame.xml
new file mode 100644
index 0000000..4d29ef0
--- /dev/null
+++ b/reference/FrameXML/BankFrame.xml
@@ -0,0 +1,575 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BankFrameItemButton_OnLoad(self);
+
+
+ BankFrameItemButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ if ( IsModifiedClick() ) then
+ BankFrameItemButtonGeneric_OnModifiedClick(self, button);
+ else
+ BankFrameItemButtonGeneric_OnClick(self, button);
+ end
+
+
+ BankFrameItemButtonGeneric_OnClick(self, "LeftButton");
+
+
+ BankFrameItemButtonGeneric_OnClick(self, "LeftButton");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BankFrameBagButton_OnLoad(self);
+
+
+ BankFrameItemButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ if ( IsModifiedClick("PICKUPACTION") ) then
+ BankFrameItemButtonBag_Pickup(self);
+ else
+ BankFrameItemButtonBag_OnClick(self, button);
+ end
+
+
+ BankFrameItemButtonBag_Pickup(self, button);
+
+
+ BankFrameItemButtonBag_OnClick(self, nil);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ StaticPopup_Show("CONFIRM_BUY_BANK_SLOT");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/BasicControls.xml b/reference/FrameXML/BasicControls.xml
new file mode 100644
index 0000000..7bdd8dd
--- /dev/null
+++ b/reference/FrameXML/BasicControls.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/BattlefieldFrame.lua b/reference/FrameXML/BattlefieldFrame.lua
new file mode 100644
index 0000000..23d75fa
--- /dev/null
+++ b/reference/FrameXML/BattlefieldFrame.lua
@@ -0,0 +1,807 @@
+-- MoonWell: returns display faction (opposite for traitors)
+local function MoonWell_GetDisplayFaction()
+ local f = UnitFactionGroup("player");
+ if MoonWell_IsTraitor and f then
+ return f == "Alliance" and "Horde" or "Alliance";
+ end
+ return f;
+end
+
+BATTLEFIELD_ZONES_DISPLAYED = 5;
+BATTLEFIELD_ZONES_HEIGHT = 20;
+BATTLEFIELD_SHUTDOWN_TIMER = 0;
+BATTLEFIELD_TIMER_THRESHOLDS = {600, 300, 60, 15};
+BATTLEFIELD_TIMER_THRESHOLD_INDEX = 1;
+PREVIOUS_BATTLEFIELD_MOD = 0;
+BATTLEFIELD_TIMER_DELAY = 3;
+BATTLEFIELD_MAP_WIDTH = 320;
+BATTLEFIELD_MAP_HEIGHT = 213;
+MAX_BATTLEFIELD_QUEUES = 2;
+MAX_WORLD_PVP_QUEUES = 1;
+CURRENT_BATTLEFIELD_QUEUES = {};
+PREVIOUS_BATTLEFIELD_QUEUES = {};
+
+local BATTLEFIELD_FRAME_FADE_TIME = 0.15
+
+function BattlefieldFrame_OnLoad (self)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("BATTLEFIELDS_SHOW");
+ self:RegisterEvent("BATTLEFIELDS_CLOSED");
+ self:RegisterEvent("UPDATE_BATTLEFIELD_STATUS");
+ self:RegisterEvent("PARTY_LEADER_CHANGED");
+ self:RegisterEvent("ZONE_CHANGED");
+ self:RegisterEvent("ZONE_CHANGED_NEW_AREA");
+
+ self:RegisterEvent("BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE");
+ self:RegisterEvent("BATTLEFIELD_MGR_QUEUE_INVITE");
+ self:RegisterEvent("BATTLEFIELD_MGR_ENTRY_INVITE");
+ self:RegisterEvent("BATTLEFIELD_MGR_EJECT_PENDING");
+ self:RegisterEvent("BATTLEFIELD_MGR_EJECTED");
+ self:RegisterEvent("BATTLEFIELD_MGR_ENTERED");
+
+ BattlefieldFrame.timerDelay = 0;
+end
+
+function BattlefieldFrame_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ MiniMapBattlefieldDropDown_OnLoad();
+ BattlefieldFrame_UpdateStatus(false, nil);
+ elseif ( event == "BATTLEFIELDS_SHOW" ) then
+ if ( not IsBattlefieldArena() ) then
+ ShowUIPanel(BattlefieldFrame);
+
+ -- Default to first available
+ SetSelectedBattlefield(0);
+
+ if ( not BattlefieldFrame:IsShown() ) then
+ CloseBattlefield();
+ return;
+ end
+ UpdateMicroButtons();
+ BattlefieldFrame_Update();
+ end
+ elseif ( event == "BATTLEFIELDS_CLOSED" ) then
+ HideUIPanel(BattlefieldFrame);
+ elseif ( event == "UPDATE_BATTLEFIELD_STATUS" or event == "ZONE_CHANGED_NEW_AREA" or event == "ZONE_CHANGED") then
+ local arg1 = ...
+ BattlefieldFrame_UpdateStatus(false, arg1);
+ BattlefieldFrame_Update();
+ elseif ( event == "BATTLEFIELD_MGR_QUEUE_REQUEST_RESPONSE" ) then
+ local battleID, accepted, warmup, inArea, loggingIn = ...;
+ if(not loggingIn) then
+ if(accepted) then
+ if(warmup) then
+ StaticPopup_Show("BFMGR_CONFIRM_WORLD_PVP_QUEUED_WARMUP", "Wintergrasp", nil, arg1);
+ elseif (inArea) then
+ StaticPopup_Show("BFMGR_EJECT_PENDING", "Wintergrasp", nil, arg1);
+ else
+ StaticPopup_Show("BFMGR_CONFIRM_WORLD_PVP_QUEUED", "Wintergrasp", nil, arg1);
+ end
+ else
+ StaticPopup_Show("BFMGR_DENY_WORLD_PVP_QUEUED", "Wintergrasp", nil, arg1);
+ end
+ end
+ BattlefieldFrame_UpdateStatus(false);
+ BattlefieldFrame_Update();
+ elseif ( event == "BATTLEFIELD_MGR_EJECT_PENDING" ) then
+ local battleID, remote = ...;
+ if(remote) then
+ local dialog = StaticPopup_Show("BFMGR_EJECT_PENDING_REMOTE", "Wintergrasp", nil, arg1);
+ else
+ local dialog = StaticPopup_Show("BFMGR_EJECT_PENDING", "Wintergrasp", nil, arg1);
+ end
+ BattlefieldFrame_UpdateStatus(false);
+ BattlefieldFrame_Update();
+ elseif ( event == "BATTLEFIELD_MGR_EJECTED" ) then
+ local battleID, playerExited, relocated, battleActive, lowLevel = ...;
+ StaticPopup_Hide("BFMGR_INVITED_TO_QUEUE");
+ StaticPopup_Hide("BFMGR_INVITED_TO_QUEUE_WARMUP");
+ StaticPopup_Hide("BFMGR_INVITED_TO_ENTER");
+ StaticPopup_Hide("BFMGR_EJECT_PENDING");
+ if(lowLevel) then
+ local dialog = StaticPopup_Show("BFMGR_PLAYER_LOW_LEVEL", "Wintergrasp", nil, arg1);
+ elseif (playerExited and battleActive and not relocated) then
+ local dialog = StaticPopup_Show("BFMGR_PLAYER_EXITED_BATTLE", "Wintergrasp", nil, arg1);
+ end
+ BattlefieldFrame_UpdateStatus(false);
+ BattlefieldFrame_Update();
+ elseif ( event == "BATTLEFIELD_MGR_QUEUE_INVITE" ) then
+ local battleID, warmup = ...;
+ if(warmup) then
+ local dialog = StaticPopup_Show("BFMGR_INVITED_TO_QUEUE_WARMUP", "Wintergrasp", nil, arg1);
+ else
+ local dialog = StaticPopup_Show("BFMGR_INVITED_TO_QUEUE", "Wintergrasp", nil, arg1);
+ end
+ StaticPopup_Hide("BFMGR_EJECT_PENDING");
+ BattlefieldFrame_UpdateStatus(false);
+ BattlefieldFrame_Update();
+ elseif ( event == "BATTLEFIELD_MGR_ENTRY_INVITE" ) then
+ local battleID = ...;
+ local dialog = StaticPopup_Show("BFMGR_INVITED_TO_ENTER", "Wintergrasp", nil, arg1);
+ StaticPopup_Hide("BFMGR_EJECT_PENDING");
+ BattlefieldFrame_UpdateStatus(false);
+ BattlefieldFrame_Update();
+ elseif ( event == "BATTLEFIELD_MGR_ENTERED" ) then
+ StaticPopup_Hide("BFMGR_INVITED_TO_QUEUE");
+ StaticPopup_Hide("BFMGR_INVITED_TO_QUEUE_WARMUP");
+ StaticPopup_Hide("BFMGR_INVITED_TO_ENTER");
+ StaticPopup_Hide("BFMGR_EJECT_PENDING");
+ BattlefieldFrame_UpdateStatus(false);
+ BattlefieldFrame_Update();
+ end
+
+ if ( event == "PARTY_LEADER_CHANGED" ) then
+ BattlefieldFrame_Update();
+ end
+end
+
+function BattlefieldTimerFrame_OnUpdate(self, elapsed)
+ local keepUpdating = false;
+ if ( BATTLEFIELD_SHUTDOWN_TIMER > 0 ) then
+ keepUpdating = true;
+ BattlefieldIconText:Hide();
+ else
+ local lowestExpiration = 0;
+ for i = 1, MAX_BATTLEFIELD_QUEUES do
+ local expiration = GetBattlefieldPortExpiration(i);
+ if ( expiration > 0 ) then
+ if( expiration < lowestExpiration or lowestExpiration == 0 ) then
+ lowestExpiration = expiration;
+ end
+
+ keepUpdating = true;
+ end
+ end
+
+ if( lowestExpiration > 0 and lowestExpiration <= 10 ) then
+ BattlefieldIconText:SetText(lowestExpiration);
+ BattlefieldIconText:Show();
+ else
+ BattlefieldIconText:Hide();
+ end
+ end
+
+ if ( not keepUpdating ) then
+ BattlefieldTimerFrame:SetScript("OnUpdate", nil);
+ return;
+ end
+
+ local frame = BattlefieldFrame
+
+ BATTLEFIELD_SHUTDOWN_TIMER = BATTLEFIELD_SHUTDOWN_TIMER - elapsed;
+ -- Set the time for the score frame
+ WorldStateScoreFrameTimer:SetFormattedText(SecondsToTimeAbbrev(BATTLEFIELD_SHUTDOWN_TIMER));
+ -- Check if I should send a message only once every 3 seconds (BATTLEFIELD_TIMER_DELAY)
+ frame.timerDelay = frame.timerDelay + elapsed;
+ if ( frame.timerDelay < BATTLEFIELD_TIMER_DELAY ) then
+ return;
+ else
+ frame.timerDelay = 0
+ end
+
+ local threshold = BATTLEFIELD_TIMER_THRESHOLDS[BATTLEFIELD_TIMER_THRESHOLD_INDEX];
+ if ( BATTLEFIELD_SHUTDOWN_TIMER > 0 ) then
+ if ( BATTLEFIELD_SHUTDOWN_TIMER < threshold and BATTLEFIELD_TIMER_THRESHOLD_INDEX ~= #BATTLEFIELD_TIMER_THRESHOLDS ) then
+ -- If timer past current threshold advance to the next one
+ BATTLEFIELD_TIMER_THRESHOLD_INDEX = BATTLEFIELD_TIMER_THRESHOLD_INDEX + 1;
+ else
+ -- See if time should be posted
+ local currentMod = floor(BATTLEFIELD_SHUTDOWN_TIMER/threshold);
+ if ( PREVIOUS_BATTLEFIELD_MOD ~= currentMod ) then
+ -- Print message
+ local info = ChatTypeInfo["SYSTEM"];
+ local string;
+ if ( GetBattlefieldWinner() ) then
+ local isArena = IsActiveBattlefieldArena();
+ if ( isArena ) then
+ string = format(ARENA_COMPLETE_MESSAGE, SecondsToTime(ceil(BATTLEFIELD_SHUTDOWN_TIMER/threshold) * threshold));
+ else
+ string = format(BATTLEGROUND_COMPLETE_MESSAGE, SecondsToTime(ceil(BATTLEFIELD_SHUTDOWN_TIMER/threshold) * threshold));
+ end
+ else
+ string = format(INSTANCE_SHUTDOWN_MESSAGE, SecondsToTime(ceil(BATTLEFIELD_SHUTDOWN_TIMER/threshold) * threshold));
+ end
+ DEFAULT_CHAT_FRAME:AddMessage(string, info.r, info.g, info.b, info.id);
+ PREVIOUS_BATTLEFIELD_MOD = currentMod;
+ end
+ end
+ else
+ BATTLEFIELD_SHUTDOWN_TIMER = 0;
+ end
+end
+
+function BattlefieldFrame_UpdateStatus(tooltipOnly, mapIndex)
+ local status, mapName, instanceID, queueID, levelRangeMin, levelRangeMax, teamSize, registeredMatch;
+ local numberQueues = 0;
+ local waitTime, timeInQueue;
+ local tooltip;
+ local showRightClickText;
+ BATTLEFIELD_SHUTDOWN_TIMER = 0;
+
+ -- Reset tooltip
+ MiniMapBattlefieldFrame.tooltip = nil;
+ MiniMapBattlefieldFrame.waitTime = {};
+ MiniMapBattlefieldFrame.status = nil;
+
+ -- Copy current queues into previous queues
+ if ( not tooltipOnly ) then
+ PREVIOUS_BATTLEFIELD_QUEUES = {};
+ for index, value in pairs(CURRENT_BATTLEFIELD_QUEUES) do
+ tinsert(PREVIOUS_BATTLEFIELD_QUEUES, value);
+ end
+ CURRENT_BATTLEFIELD_QUEUES = {};
+ end
+
+ if ( CanHearthAndResurrectFromArea() ) then
+ if ( not MiniMapBattlefieldFrame.inWorldPVPArea ) then
+ MiniMapBattlefieldFrame.inWorldPVPArea = true;
+ UIFrameFadeIn(MiniMapBattlefieldFrame, BATTLEFIELD_FRAME_FADE_TIME);
+ BattlegroundShineFadeIn();
+ end
+ else
+ MiniMapBattlefieldFrame.inWorldPVPArea = false;
+ end
+
+ for i=1, MAX_BATTLEFIELD_QUEUES do
+ status, mapName, instanceID, levelRangeMin, levelRangeMax, teamSize, registeredMatch = GetBattlefieldStatus(i);
+ if ( mapName ) then
+ if ( instanceID ~= 0 ) then
+ mapName = mapName.." "..instanceID;
+ end
+ if ( teamSize ~= 0 ) then
+ if ( registeredMatch ) then
+ mapName = ARENA_RATED_MATCH.." "..format(PVP_TEAMSIZE, teamSize, teamSize);
+ else
+ mapName = ARENA_CASUAL.." "..format(PVP_TEAMSIZE, teamSize, teamSize);
+ end
+ end
+ end
+ tooltip = nil;
+ MiniMapBattlefieldFrame_isArena();
+ if ( not tooltipOnly and (status ~= "confirm") ) then
+ StaticPopup_Hide("CONFIRM_BATTLEFIELD_ENTRY", i);
+ end
+
+ if ( status ~= "none" ) then
+ numberQueues = numberQueues+1;
+ if ( status == "queued" ) then
+ -- Update queue info show button on minimap
+ waitTime = GetBattlefieldEstimatedWaitTime(i);
+ timeInQueue = GetBattlefieldTimeWaited(i)/1000;
+ if ( waitTime == 0 ) then
+ waitTime = QUEUE_TIME_UNAVAILABLE;
+ elseif ( waitTime < 60000 ) then
+ waitTime = LESS_THAN_ONE_MINUTE;
+ else
+ waitTime = SecondsToTime(waitTime/1000, 1);
+ end
+ MiniMapBattlefieldFrame.waitTime[i] = waitTime;
+ tooltip = format(BATTLEFIELD_IN_QUEUE, mapName, waitTime, SecondsToTime(timeInQueue));
+
+ if ( not tooltipOnly ) then
+ if ( not IsAlreadyInQueue(mapName) ) then
+ UIFrameFadeIn(MiniMapBattlefieldFrame, BATTLEFIELD_FRAME_FADE_TIME);
+ BattlegroundShineFadeIn();
+ PlaySound("PVPENTERQUEUE");
+ end
+ tinsert(CURRENT_BATTLEFIELD_QUEUES, mapName);
+ end
+ showRightClickText = 1;
+ elseif ( status == "confirm" ) then
+ -- Have been accepted show enter battleground dialog
+ local seconds = SecondsToTime(GetBattlefieldPortExpiration(i));
+ if ( seconds ~= "" ) then
+ tooltip = format(BATTLEFIELD_QUEUE_CONFIRM, mapName, seconds);
+ else
+ tooltip = format(BATTLEFIELD_QUEUE_PENDING_REMOVAL, mapName);
+ end
+ if ( (i==mapIndex) and (not tooltipOnly) ) then
+ local dialog = StaticPopup_Show("CONFIRM_BATTLEFIELD_ENTRY", mapName, nil, i);
+ PlaySound("PVPTHROUGHQUEUE");
+ MiniMapBattlefieldFrame:Show();
+ end
+ showRightClickText = 1;
+ BattlefieldTimerFrame:SetScript("OnUpdate", BattlefieldTimerFrame_OnUpdate);
+ elseif ( status == "active" ) then
+ -- In the battleground
+ if ( teamSize ~= 0 ) then
+ tooltip = mapName;
+ else
+ tooltip = format(BATTLEFIELD_IN_BATTLEFIELD, mapName);
+ end
+ BATTLEFIELD_SHUTDOWN_TIMER = GetBattlefieldInstanceExpiration()/1000;
+ if ( BATTLEFIELD_SHUTDOWN_TIMER > 0 ) then
+ BattlefieldTimerFrame:SetScript("OnUpdate", BattlefieldTimerFrame_OnUpdate);
+ end
+ BATTLEFIELD_TIMER_THRESHOLD_INDEX = 1;
+ PREVIOUS_BATTLEFIELD_MOD = 0;
+ MiniMapBattlefieldFrame.status = status;
+ elseif ( status == "error" ) then
+ -- Should never happen haha
+ end
+ if ( tooltip ) then
+ if ( MiniMapBattlefieldFrame.tooltip ) then
+ MiniMapBattlefieldFrame.tooltip = MiniMapBattlefieldFrame.tooltip.."\n\n"..tooltip;
+ else
+ MiniMapBattlefieldFrame.tooltip = tooltip;
+ end
+ end
+ end
+ end
+
+ for i=1, MAX_WORLD_PVP_QUEUES do
+ status, mapName, queueID = GetWorldPVPQueueStatus(i);
+ if ( status ~= "none" ) then
+ numberQueues = numberQueues + 1;
+ end
+ if ( status == "queued" or status == "confirm" ) then
+ if ( status == "queued" ) then
+ tooltip = format(BATTLEFIELD_IN_QUEUE_SIMPLE, mapName);
+ elseif ( status == "confirm" ) then
+ tooltip = format(BATTLEFIELD_QUEUE_CONFIRM_SIMPLE, mapName);
+ end
+
+ if ( MiniMapBattlefieldFrame.tooltip ) then
+ MiniMapBattlefieldFrame.tooltip = MiniMapBattlefieldFrame.tooltip.."\n\n"..tooltip;
+ else
+ MiniMapBattlefieldFrame.tooltip = tooltip;
+ end
+ end
+ end
+
+ -- See if should add right click message
+ if ( MiniMapBattlefieldFrame.tooltip and showRightClickText ) then
+ MiniMapBattlefieldFrame.tooltip = MiniMapBattlefieldFrame.tooltip.."\n"..RIGHT_CLICK_MESSAGE;
+ elseif ( MiniMapBattlefieldFrame_isArena() ) then
+ MiniMapBattlefieldFrame.tooltip = MiniMapBattlefieldFrame.tooltip;
+ end
+
+ if ( not tooltipOnly ) then
+ MiniMapBattlefieldFrame_isArena();
+ if ( numberQueues == 0 and (not CanHearthAndResurrectFromArea()) ) then
+ -- Clear everything out
+ MiniMapBattlefieldFrame:Hide();
+ else
+ MiniMapBattlefieldFrame:Show();
+ end
+ end
+ BattlefieldFrame.numQueues = numberQueues;
+end
+
+function MiniMapBattlefieldFrame_isArena()
+ -- Set minimap icon here since it bugs out on login
+ local status, mapName, instanceID, levelRangeMin, levelRangeMax, teamSize, registeredMatch = GetBattlefieldStatus(1);
+ local isArena, isRegistered = IsActiveBattlefieldArena();
+ if ( registeredMatch or isRegistered ) then
+ MiniMapBattlefieldIcon:SetTexture("Interface\\PVPFrame\\PVP-ArenaPoints-Icon");
+ MiniMapBattlefieldIcon:SetWidth(19);
+ MiniMapBattlefieldIcon:SetHeight(19);
+ MiniMapBattlefieldIcon:SetPoint("CENTER", "MiniMapBattlefieldFrame", "CENTER", -1, 2);
+ elseif ( UnitFactionGroup("player") ) then
+ MiniMapBattlefieldIcon:SetTexture("Interface\\BattlefieldFrame\\Battleground-"..MoonWell_GetDisplayFaction());
+ MiniMapBattlefieldIcon:SetTexCoord(0, 1, 0, 1);
+ MiniMapBattlefieldIcon:SetWidth(32);
+ MiniMapBattlefieldIcon:SetHeight(32);
+ MiniMapBattlefieldIcon:SetPoint("CENTER", "MiniMapBattlefieldFrame", "CENTER", -1, 0);
+ end
+end
+
+function BattlefieldFrame_Update()
+ local zoneIndex;
+ local zoneOffset = FauxScrollFrame_GetOffset(BattlefieldListScrollFrame);
+ local playerLevel = UnitLevel("player");
+ local button, buttonStatus;
+ local instanceID;
+ local mapName, mapDescription, maxGroup = GetBattlefieldInfo();
+ local factionTexture = "Interface\\PVPFrame\\PVP-Currency-"..MoonWell_GetDisplayFaction();
+
+ if ( not mapName ) then
+ return;
+ end
+
+ -- Set title text
+ BattlefieldFrameFrameLabel:SetText(mapName);
+ -- Set the Join as Group text based on the limits of which instances can join as group.
+ if ( maxGroup and maxGroup == 5 ) then
+ BattlefieldFrameGroupJoinButton:SetText(JOIN_AS_PARTY);
+ else
+ BattlefieldFrameGroupJoinButton:SetText(JOIN_AS_GROUP);
+ end
+ -- Setup instance buttons
+ -- add one to battlefields because of the fake "first available" button
+ local numBattlefields = GetNumBattlefields() + 1;
+ for i=1, BATTLEFIELD_ZONES_DISPLAYED, 1 do
+ zoneIndex = zoneOffset + i;
+ button = _G["BattlefieldZone"..i];
+
+ if ( zoneIndex == 1 ) then
+ -- The first entry in the list is always "first available"
+ button:SetText(FIRST_AVAILABLE);
+ -- Set tooltip
+ button.title = FIRST_AVAILABLE;
+ button.tooltip = NEWBIE_TOOLTIP_FIRST_AVAILABLE;
+ button:Show();
+ elseif ( zoneIndex > numBattlefields ) then
+ button:Hide();
+ else
+ instanceID = GetBattlefieldInstanceInfo(zoneIndex - 1);
+ button:SetText(mapName.." "..instanceID);
+ -- Set tooltip
+ button.title = mapName.." "..instanceID;
+ button.tooltip = NEWBIE_TOOLTIP_ENTER_BATTLEGROUND;
+ button:Show();
+ end
+
+ -- Set queued status
+ button.status:Hide();
+ local queueStatus, queueMapName, queueInstanceID;
+ for i=1, MAX_BATTLEFIELD_QUEUES do
+ queueStatus, queueMapName, queueInstanceID = GetBattlefieldStatus(i);
+ if ( queueStatus ~= "none" and queueMapName.." "..queueInstanceID == button.title ) then
+ if ( queueStatus == "queued" ) then
+ button.status.texture:SetTexture(factionTexture);
+ button.status.texture:SetTexCoord(0.0, 1.0, 0.0, 1.0);
+ button.status.tooltip = BATTLEFIELD_QUEUE_STATUS;
+ button.status:Show();
+ elseif ( queueStatus == "confirm" ) then
+ button.status.texture:SetTexture("Interface\\CharacterFrame\\UI-StateIcon");
+ button.status.texture:SetTexCoord(0.45, 0.95, 0.0, 0.5);
+ button.status.tooltip = BATTLEFIELD_CONFIRM_STATUS;
+ button.status:Show();
+ end
+ elseif ( button.title == FIRST_AVAILABLE and queueMapName == mapName and queueInstanceID == 0 ) then
+ if ( queueStatus == "queued" ) then
+ button.status.texture:SetTexture(factionTexture);
+ button.status.texture:SetTexCoord(0.0, 1.0, 0.0, 1.0);
+ button.status.tooltip = BATTLEFIELD_QUEUE_STATUS;
+ button.status:Show();
+ end
+ end
+ end
+
+ -- Set selected instance
+ if ( zoneIndex == 1 and GetSelectedBattlefield() == 0 ) then
+ button:LockHighlight();
+ elseif ( zoneIndex - 1 == GetSelectedBattlefield() ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+ end
+
+ local mapName, mapDescription, maxGroup, canEnter, isHoliday, isRandom = GetBattlefieldInfo();
+
+ if ( isRandom or isHoliday ) then
+ BattlefieldFrame_UpdateRandomInfo();
+ BattlefieldFrameInfoScrollFrameChildFrameRewardsInfo:Show();
+ BattlefieldFrameInfoScrollFrameChildFrameDescription:Hide();
+ else
+ if ( mapDescription ~= BattlefieldFrameInfoScrollFrameChildFrameDescription:GetText() ) then
+ BattlefieldFrameInfoScrollFrameChildFrameDescription:SetText(mapDescription);
+ BattlefieldFrameInfoScrollFrame:SetVerticalScroll(0);
+ end
+
+ BattlefieldFrameInfoScrollFrameChildFrameRewardsInfo:Hide();
+ BattlefieldFrameInfoScrollFrameChildFrameDescription:Show();
+ end
+
+ -- Enable or disable the group join button
+ if ( CanJoinBattlefieldAsGroup() ) then
+ if ( ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0)) and IsPartyLeader() ) then
+ -- If this is true then can join as a group
+ BattlefieldFrameGroupJoinButton:Enable();
+ else
+ BattlefieldFrameGroupJoinButton:Disable();
+ end
+ BattlefieldFrameGroupJoinButton:Show();
+ else
+ BattlefieldFrameGroupJoinButton:Hide();
+ end
+
+ if ( BattlefieldFrame.numQueues ) then
+ if ( BattlefieldFrame.numQueues <= 3 ) then
+ BattlefieldFrameJoinButton:Enable();
+ else
+ BattlefieldFrameJoinButton:Disable();
+ end
+ end
+
+ FauxScrollFrame_Update(BattlefieldListScrollFrame, numBattlefields, BATTLEFIELD_ZONES_DISPLAYED, BATTLEFIELD_ZONES_HEIGHT, "BattlefieldZone", 293, 315);
+end
+
+function PVPQueue_UpdateRandomInfo(base, infoFunc)
+ local BGname, canEnter, isHoliday, isRandom = infoFunc();
+
+ local hasWin, lossHonor, winHonor, winArena, lossArena;
+
+ if ( isRandom ) then
+ hasWin, winHonor, winArena, lossHonor, lossArena = GetRandomBGHonorCurrencyBonuses();
+ base.title:SetText(RANDOM_BATTLEGROUND);
+ base.description:SetText(RANDOM_BATTLEGROUND_EXPLANATION);
+ else
+ base.title:SetText(BATTLEGROUND_HOLIDAY);
+ base.description:SetText(BATTLEGROUND_HOLIDAY_EXPLANATION);
+ hasWin, winHonor, winArena, lossHonor, lossArena = GetHolidayBGHonorCurrencyBonuses();
+ end
+
+ if (winHonor ~= 0) then
+ base.winReward.honorSymbol:Show();
+ base.winReward.honorAmount:Show();
+ base.winReward.honorAmount:SetText(winHonor);
+ else
+ base.winReward.honorSymbol:Hide();
+ base.winReward.honorAmount:Hide();
+ end
+
+ if (winArena ~= 0) then
+ base.winReward.arenaSymbol:Show();
+ base.winReward.arenaAmount:Show();
+ base.winReward.arenaAmount:SetText(winArena);
+ else
+ base.winReward.arenaSymbol:Hide();
+ base.winReward.arenaAmount:Hide();
+ end
+
+ if (lossHonor ~= 0) then
+ base.lossReward.honorSymbol:Show();
+ base.lossReward.honorAmount:Show();
+ base.lossReward.honorAmount:SetText(lossHonor);
+ else
+ base.lossReward.honorSymbol:Hide();
+ base.lossReward.honorAmount:Hide();
+ end
+
+ if (lossArena ~= 0) then
+ base.lossReward.arenaSymbol:Show();
+ base.lossReward.arenaAmount:Show();
+ base.lossReward.arenaAmount:SetText(lossArena);
+ else
+ base.lossReward.arenaSymbol:Hide();
+ base.lossReward.arenaAmount:Hide();
+ end
+
+ local englishFaction = MoonWell_GetDisplayFaction();
+ base.winReward.honorSymbol:SetTexture("Interface\\PVPFrame\\PVP-Currency-"..englishFaction);
+ base.lossReward.honorSymbol:SetTexture("Interface\\PVPFrame\\PVP-Currency-"..englishFaction);
+end
+
+function BattlefieldFrame_GetSelectedBattlegroundInfo()
+ local BGname, description, groupSize, canEnter, isHoliday, isRandom = GetBattlefieldInfo();
+ return BGname, canEnter, isHoliday, isRandom;
+end
+
+function BattlefieldFrame_UpdateRandomInfo()
+ PVPQueue_UpdateRandomInfo(BattlefieldFrameInfoScrollFrameChildFrameRewardsInfo, BattlefieldFrame_GetSelectedBattlegroundInfo);
+end
+
+function BattlefieldButton_OnClick(self)
+ local id = self:GetID();
+ SetSelectedBattlefield(FauxScrollFrame_GetOffset(BattlefieldListScrollFrame) + id - 1);
+ BattlefieldFrame_Update();
+end
+
+function BattlefieldFrameJoinButton_OnClick(self)
+ local GROUPJOIN_BUTTONID = 2;
+ local id = self:GetID();
+ if ( id == GROUPJOIN_BUTTONID ) then
+ JoinBattlefield(GetSelectedBattlefield(), 1);
+ else
+ JoinBattlefield(GetSelectedBattlefield());
+ end
+
+ HideUIPanel(BattlefieldFrame);
+end
+
+function MiniMapBattlefieldDropDown_OnLoad()
+ UIDropDownMenu_Initialize(MiniMapBattlefieldDropDown, MiniMapBattlefieldDropDown_Initialize, "MENU");
+end
+
+function MiniMapBattlefieldDropDown_Initialize()
+ local info;
+ local status, mapName, instanceID, queueID, levelRangeMin, levelRangeMax, teamSize, registeredMatch;
+ local numQueued = 0;
+ local numShown = 0;
+
+ local shownHearthAndRes;
+
+ for i=1, MAX_BATTLEFIELD_QUEUES do
+ status, mapName, instanceID, levelRangeMin, levelRangeMax, teamSize, registeredMatch = GetBattlefieldStatus(i);
+
+ -- Inserts a spacer if it's not the first option... to make it look nice.
+ if ( status ~= "none" ) then
+ numShown = numShown + 1;
+ if ( numShown > 1 ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.isTitle = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+ end
+
+ if ( status == "queued" or status == "confirm" ) then
+ numQueued = numQueued + 1;
+ -- Add a spacer if there were dropdown items before this
+
+ info = UIDropDownMenu_CreateInfo();
+ if ( teamSize ~= 0 ) then
+ if ( registeredMatch ) then
+ info.text = ARENA_RATED_MATCH.." "..format(PVP_TEAMSIZE, teamSize, teamSize);
+ else
+ info.text = ARENA_CASUAL.." "..format(PVP_TEAMSIZE, teamSize, teamSize);
+ end
+ else
+ info.text = mapName;
+ end
+ info.isTitle = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ if ( CanHearthAndResurrectFromArea() and not shownHearthAndRes and GetRealZoneText() == mapName ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = format(LEAVE_ZONE, GetRealZoneText());
+
+ info.func = HearthAndResurrectFromArea;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ shownHearthAndRes = true;
+ end
+
+ if ( status == "queued" ) then
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = LEAVE_QUEUE;
+ info.func = function (self, ...) AcceptBattlefieldPort(...) end;
+ info.arg1 = i;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ elseif ( status == "confirm" ) then
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = ENTER_BATTLE;
+ info.func = function (self, ...) AcceptBattlefieldPort(...) end;
+ info.arg1 = i;
+ info.arg2 = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ if ( teamSize == 0 ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = LEAVE_QUEUE;
+ info.func = function (self, ...) AcceptBattlefieldPort(...) end;
+ info.arg1 = i;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+
+ end
+
+ elseif ( status == "active" ) then
+
+ info = UIDropDownMenu_CreateInfo();
+ if ( teamSize ~= 0 ) then
+ info.text = mapName.." "..format(PVP_TEAMSIZE, teamSize, teamSize);
+ else
+ info.text = mapName;
+ end
+ info.isTitle = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ info = UIDropDownMenu_CreateInfo();
+ if ( IsActiveBattlefieldArena() ) then
+ info.text = LEAVE_ARENA;
+ else
+ info.text = LEAVE_BATTLEGROUND;
+ end
+ info.func = function (self, ...) LeaveBattlefield(...) end;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ end
+ end
+
+ for i=1, MAX_WORLD_PVP_QUEUES do
+ status, mapName, queueID = GetWorldPVPQueueStatus(i);
+
+ -- Inserts a spacer if it's not the first option... to make it look nice.
+ if ( status ~= "none" ) then
+ numShown = numShown + 1;
+ if ( numShown > 1 ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.isTitle = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+ end
+
+ if ( status == "queued" or status == "confirm" ) then
+ numQueued = numQueued + 1;
+ -- Add a spacer if there were dropdown items before this
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = mapName;
+ info.isTitle = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ if ( CanHearthAndResurrectFromArea() and not shownHearthAndRes and GetRealZoneText() == mapName ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = format(LEAVE_ZONE, GetRealZoneText());
+
+ info.func = HearthAndResurrectFromArea;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ shownHearthAndRes = true;
+ end
+
+ if ( status == "queued" ) then
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = LEAVE_QUEUE;
+ info.func = function (self, ...) BattlefieldMgrExitRequest(...) end;
+ info.arg1 = queueID;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ elseif ( status == "confirm" ) then
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = ENTER_BATTLE;
+ info.func = function (self, ...) BattlefieldMgrEntryInviteResponse(...) end;
+ info.arg1 = queueID;
+ info.arg2 = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = LEAVE_QUEUE;
+ info.func = function (self, ...) BattlefieldMgrEntryInviteResponse(...) end;
+ info.arg1 = i;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+ end
+ end
+
+ if ( CanHearthAndResurrectFromArea() and not shownHearthAndRes ) then
+ numShown = numShown + 1;
+ info = UIDropDownMenu_CreateInfo();
+ info.text = GetRealZoneText();
+ info.isTitle = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = format(LEAVE_ZONE, GetRealZoneText());
+
+ info.func = HearthAndResurrectFromArea;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+
+end
+
+function BattlegroundShineFadeIn()
+ -- Fade in the shine and then fade it out with the ComboPointShineFadeOut function
+ local fadeInfo = {};
+ fadeInfo.mode = "IN";
+ fadeInfo.timeToFade = 0.5;
+ fadeInfo.finishedFunc = BattlegroundShineFadeOut;
+ UIFrameFade(BattlegroundShine, fadeInfo);
+end
+
+--hack since a frame can't have a reference to itself in it
+function BattlegroundShineFadeOut()
+ UIFrameFadeOut(BattlegroundShine, 0.5);
+end
+
+function IsAlreadyInQueue(mapName)
+ local inQueue = nil;
+ for index,value in pairs(PREVIOUS_BATTLEFIELD_QUEUES) do
+ if ( value == mapName ) then
+ inQueue = 1;
+ end
+ end
+ return inQueue;
+end
diff --git a/reference/FrameXML/BattlefieldFrame.xml b/reference/FrameXML/BattlefieldFrame.xml
new file mode 100644
index 0000000..769af2c
--- /dev/null
+++ b/reference/FrameXML/BattlefieldFrame.xml
@@ -0,0 +1,653 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.scrollBarHideable = true;
+ ScrollFrame_OnLoad(self);
+ ScrollFrame_OnScrollRangeChanged(self);
+ local scrollBar = _G[self:GetName().."ScrollBar"];
+ self.scrollBarBackground:SetParent(scrollBar);
+ self.scrollBarArtTop:SetParent(scrollBar);
+ self.scrollBarArtBottom:SetParent(scrollBar);
+
+ self.defaultWidth = self:GetWidth();
+ local resizeFunc = function(scrollBar)
+ if ( scrollBar:IsShown() ) then
+ self:SetWidth(self.defaultWidth);
+ else
+ self:SetWidth(self.defaultWidth + scrollBar:GetWidth() + 7);
+ end
+ end
+
+ scrollBar:SetScript("OnHide", resizeFunc);
+ scrollBar:SetScript("OnShow", resizeFunc);
+
+ resizeFunc(scrollBar);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+ _G[self:GetName().."Highlight"]:SetVertexColor(1.0, 0.82, 0);
+
+
+ BattlefieldButton_OnClick(self, button, down);
+
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self)
+ GameTooltip:SetText(self.title, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(self.tooltip, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, BATTLEFIELD_ZONES_HEIGHT, BattlefieldFrame_Update)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self)
+ GameTooltip:SetText(BATTLEFIELD_GROUP_JOIN, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_BATTLEFIELD_GROUP_JOIN, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoOpen");
+ BattlefieldFrame_Update();
+
+
+ CloseBattlefield();
+ UpdateMicroButtons();
+ PlaySound("igCharacterInfoClose");
+
+
+
+
+
+
diff --git a/reference/FrameXML/Bindings.xml b/reference/FrameXML/Bindings.xml
new file mode 100644
index 0000000..008bf17
--- /dev/null
+++ b/reference/FrameXML/Bindings.xml
@@ -0,0 +1,1341 @@
+
+
+
+ if ( keystate == "down" ) then
+ MoveAndSteerStart();
+ else
+ MoveAndSteerStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ MoveForwardStart();
+ else
+ MoveForwardStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ MoveBackwardStart();
+ else
+ MoveBackwardStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ TurnLeftStart();
+ else
+ TurnLeftStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ TurnRightStart();
+ else
+ TurnRightStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ StrafeLeftStart();
+ else
+ StrafeLeftStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ StrafeRightStart();
+ else
+ StrafeRightStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ JumpOrAscendStart();
+ else
+ AscendStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ SitStandOrDescendStart();
+ else
+ DescendStop();
+ end
+
+
+ ToggleSheath();
+
+
+ ToggleAutoRun();
+
+
+ if ( keystate == "down" ) then
+ PitchUpStart();
+ else
+ PitchUpStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ PitchDownStart();
+ else
+ PitchDownStop();
+ end
+
+
+ ToggleRun();
+
+
+ FollowUnit("target");
+
+
+
+ ChatFrame_OpenChat("");
+
+
+ ChatFrame_OpenChat("/");
+
+
+ ChatFrame_ChatPageUp();
+
+
+ ChatFrame_ChatPageDown();
+
+
+ ChatFrame_ScrollToBottom();
+
+
+ ChatFrame_ReplyTell();
+
+
+ ChatFrame_ReplyTell2();
+
+
+ ChatFrame2:PageUp();
+
+
+ ChatFrame2:PageDown();
+
+
+ ChatFrame2:ScrollToBottom();
+
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(1);
+ else
+ ActionButtonUp(1);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(2);
+ else
+ ActionButtonUp(2);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(3);
+ else
+ ActionButtonUp(3);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(4);
+ else
+ ActionButtonUp(4);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(5);
+ else
+ ActionButtonUp(5);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(6);
+ else
+ ActionButtonUp(6);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(7);
+ else
+ ActionButtonUp(7);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(8);
+ else
+ ActionButtonUp(8);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(9);
+ else
+ ActionButtonUp(9);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(10);
+ else
+ ActionButtonUp(10);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(11);
+ else
+ ActionButtonUp(11);
+ end
+
+
+ if ( keystate == "down" ) then
+ ActionButtonDown(12);
+ else
+ ActionButtonUp(12);
+ end
+
+
+
+ ShapeshiftBar_ChangeForm(1)
+
+
+ ShapeshiftBar_ChangeForm(2)
+
+
+ ShapeshiftBar_ChangeForm(3)
+
+
+ ShapeshiftBar_ChangeForm(4)
+
+
+ ShapeshiftBar_ChangeForm(5)
+
+
+ ShapeshiftBar_ChangeForm(6)
+
+
+ ShapeshiftBar_ChangeForm(7)
+
+
+ ShapeshiftBar_ChangeForm(8)
+
+
+ ShapeshiftBar_ChangeForm(9)
+
+
+ ShapeshiftBar_ChangeForm(10)
+
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(1);
+ else
+ BonusActionButtonUp(1);
+ end
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(2);
+ else
+ BonusActionButtonUp(2);
+ end
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(3);
+ else
+ BonusActionButtonUp(3);
+ end
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(4);
+ else
+ BonusActionButtonUp(4);
+ end
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(5);
+ else
+ BonusActionButtonUp(5);
+ end
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(6);
+ else
+ BonusActionButtonUp(6);
+ end
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(7);
+ else
+ BonusActionButtonUp(7);
+ end
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(8);
+ else
+ BonusActionButtonUp(8);
+ end
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(9);
+ else
+ BonusActionButtonUp(9);
+ end
+
+
+ if ( keystate == "down" ) then
+ BonusActionButtonDown(10);
+ else
+ BonusActionButtonUp(10);
+ end
+
+
+
+ ChangeActionBarPage(1);
+
+
+ ChangeActionBarPage(2);
+
+
+ ChangeActionBarPage(3);
+
+
+ ChangeActionBarPage(4);
+
+
+ ChangeActionBarPage(5);
+
+
+ ChangeActionBarPage(6);
+
+
+ ActionBar_PageDown();
+
+
+ ActionBar_PageUp();
+
+
+ if ( LOCK_ACTIONBAR == "1" ) then
+ LOCK_ACTIONBAR = "0";
+ else
+ LOCK_ACTIONBAR = "1";
+ end
+
+
+ if ( GetCVar("autoSelfCast") == "1" ) then
+ SetCVar("autoSelfCast", "0");
+ else
+ SetCVar("autoSelfCast", "1");
+ end
+
+
+
+ if ( keystate == "up" ) then
+ MultiCastSummonSpellButtonUp(1);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(1);
+ else
+ MultiCastActionButtonUp(1);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(2);
+ else
+ MultiCastActionButtonUp(2);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(3);
+ else
+ MultiCastActionButtonUp(3);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(4);
+ else
+ MultiCastActionButtonUp(4);
+ end
+
+
+ if ( keystate == "up" ) then
+ MultiCastSummonSpellButtonUp(2);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(5);
+ else
+ MultiCastActionButtonUp(5);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(6);
+ else
+ MultiCastActionButtonUp(6);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(7);
+ else
+ MultiCastActionButtonUp(7);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(8);
+ else
+ MultiCastActionButtonUp(8);
+ end
+
+
+ if ( keystate == "up" ) then
+ MultiCastSummonSpellButtonUp(3);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(9);
+ else
+ MultiCastActionButtonUp(9);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(10);
+ else
+ MultiCastActionButtonUp(10);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(11);
+ else
+ MultiCastActionButtonUp(11);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiCastActionButtonDown(12);
+ else
+ MultiCastActionButtonUp(12);
+ end
+
+
+ if ( keystate == "up" ) then
+ MultiCastRecallSpellButtonUp(1);
+ end
+
+
+
+
+ TargetNearestEnemy();
+
+
+ TargetNearestEnemy(1); -- 1 (or "true") means reverse!
+
+
+ TargetNearestFriend();
+
+
+ TargetNearestFriend(1); -- 1 (or "true") means reverse!
+
+
+ TargetNearestEnemyPlayer();
+
+
+ TargetNearestEnemyPlayer(1); -- 1 (or "true") means reverse!
+
+
+ TargetNearestFriendPlayer();
+
+
+ TargetNearestFriendPlayer(1); -- 1 (or "true") means reverse!
+
+
+
+ if ( UnitIsUnit("player", "target") ) then
+ TargetUnit("pet", 1);
+ else
+ TargetUnit("player");
+ end
+
+
+ if ( UnitIsUnit("party1", "target") or UnitHasVehicleUI("party1") ) then
+ TargetUnit("partypet1");
+ else
+ TargetUnit("party1");
+ end
+
+
+ if ( UnitIsUnit("party2", "target") or UnitHasVehicleUI("party2") ) then
+ TargetUnit("partypet2");
+ else
+ TargetUnit("party2");
+ end
+
+
+ if ( UnitIsUnit("party3", "target") or UnitHasVehicleUI("party3") ) then
+ TargetUnit("partypet3");
+ else
+ TargetUnit("party3");
+ end
+
+
+ if ( UnitIsUnit("party4", "target") or UnitHasVehicleUI("party4") ) then
+ TargetUnit("partypet4");
+ else
+ TargetUnit("party4");
+ end
+
+
+ TargetUnit("pet");
+
+
+ TargetUnit("partypet1");
+
+
+ TargetUnit("partypet2");
+
+
+ TargetUnit("partypet3");
+
+
+ TargetUnit("partypet4");
+
+
+ TargetLastEnemy();
+
+
+ TargetLastTarget();
+
+
+ local SHOW_ENEMIES = GetCVarBool("nameplateShowEnemies");
+ local SHOW_FRIENDS = GetCVarBool("nameplateShowFriends");
+ if ( SHOW_ENEMIES and not SHOW_FRIENDS ) then
+ SetCVar("nameplateShowEnemies", 0);
+ else
+ SetCVar("nameplateShowEnemies", 1);
+ SetCVar("nameplateShowFriends", 0);
+ end
+
+
+ local SHOW_ENEMIES = GetCVarBool("nameplateShowEnemies");
+ local SHOW_FRIENDS = GetCVarBool("nameplateShowFriends");
+ if ( SHOW_FRIENDS and not SHOW_ENEMIES ) then
+ SetCVar("nameplateShowFriends", 0);
+ else
+ SetCVar("nameplateShowFriends", 1);
+ SetCVar("nameplateShowEnemies", 0);
+ end
+
+
+ local SHOW_ENEMIES = GetCVarBool("nameplateShowEnemies");
+ local SHOW_FRIENDS = GetCVarBool("nameplateShowFriends");
+ if ( not SHOW_ENEMIES and not SHOW_FRIENDS ) then
+ SetCVar("nameplateShowEnemies", 1);
+ SetCVar("nameplateShowFriends", 1);
+ else
+ SetCVar("nameplateShowEnemies", 0);
+ SetCVar("nameplateShowFriends", 0);
+ end
+
+
+ if ( not InteractUnit("mouseover") ) then
+ InteractUnit("target");
+ end
+
+
+ InteractUnit("target");
+
+
+ AssistUnit("target");
+
+
+ AttackTarget();
+
+
+ StartAttack();
+
+
+ PetAttack();
+
+
+ FocusUnit("target");
+
+
+ TargetUnit("focus");
+
+
+ TargetUnit("mouseover");
+
+
+ if ( #VOICECHAT_TALKERS > 0 ) then
+ VoiceChatTalkers.buttons[#VOICECHAT_TALKERS].button:Click();
+ end
+
+
+
+
+ ToggleCharacter("PaperDollFrame");
+
+
+ ToggleBackpack();
+
+
+ ToggleBag(4);
+
+
+ ToggleBag(3);
+
+
+ ToggleBag(2);
+
+
+ ToggleBag(1);
+
+
+ OpenAllBags();
+
+
+ ToggleKeyRing();
+
+
+ ToggleSpellBook(BOOKTYPE_SPELL);
+
+
+ ToggleSpellBook(BOOKTYPE_PET);
+
+
+ ToggleGlyphFrame();
+
+
+ ToggleTalentFrame();
+
+
+ TogglePVPFrame();
+
+
+ ToggleCharacter("PetPaperDollFrame");
+
+
+ ToggleCharacter("ReputationFrame");
+
+
+ ToggleCharacter("SkillFrame");
+
+
+ ToggleFrame(QuestLogFrame);
+
+
+ ToggleGameMenu();
+
+
+ ToggleMinimap();
+
+
+ ToggleFrame(WorldMapFrame);
+
+
+ if ( WorldMapFrame:IsShown() ) then
+ WorldMapFrame_ToggleWindowSize();
+ end
+
+
+ ToggleFriendsFrame();
+
+
+ ToggleFriendsFrame(1);
+
+
+ ToggleFriendsFrame(2);
+
+
+ ToggleFriendsFrame(3);
+
+
+ ToggleFriendsFrame(4);
+
+
+ ToggleFriendsFrame(5);
+
+
+ ToggleLFDParentFrame();
+
+
+ ToggleLFRParentFrame();
+
+
+ ToggleWorldStateScoreFrame();
+
+
+ ToggleBattlefieldMinimap();
+
+
+ ToggleMiniMapRotation();
+
+
+ ChannelPullout_ToggleDisplay();
+
+
+ ToggleAchievementFrame();
+
+
+ ToggleAchievementFrame(1);
+
+
+ ToggleCharacter("TokenFrame");
+
+
+
+
+ SpellStopCasting();
+
+
+ StopAttack();
+
+
+ Dismount();
+
+
+ Minimap_ZoomIn();
+
+
+ Minimap_ZoomOut();
+
+
+ Sound_ToggleMusic();
+
+
+ Sound_ToggleSound();
+
+
+ Sound_MasterVolumeUp();
+
+
+ Sound_MasterVolumeDown();
+
+
+ if ( GetCVar("VoiceChatSelfMute") == "0" ) then
+ SetCVar("VoiceChatSelfMute", 1);
+ else
+ SetCVar("VoiceChatSelfMute", 0);
+ end
+
+
+ if ( UIParent:IsShown() ) then
+ securecall("CloseMenus");
+ securecall("CloseAllWindows");
+ UIParent:Hide();
+ SetUIVisibility(false);
+ ActionStatus_DisplayMessage(format(UI_HIDDEN, GetBindingText(GetBindingKey("TOGGLEUI"), "KEY_")))
+ else
+ UIParent:Show();
+ SetUIVisibility(true);
+ end
+
+
+ ToggleFramerate();
+
+
+ TakeScreenshot();
+
+
+
+
+ ToggleStats();
+
+
+ ToggleTris();
+
+
+ TogglePortals();
+
+
+ ToggleCollision();
+
+
+ ToggleCollisionDisplay();
+
+
+ TogglePlayerBounds();
+
+
+ TogglePerformanceDisplay();
+
+
+ TogglePerformancePause();
+
+
+ TogglePerformanceValues();
+
+
+ ResetPerformanceValues();
+
+
+
+ ToggleCommentatorMode();
+
+
+
+
+ NextView();
+
+
+ PrevView();
+
+
+ CameraZoomIn(1.0);
+
+
+ CameraZoomOut(1.0);
+
+
+ SetView(1);
+
+
+ SetView(2);
+
+
+ SetView(3);
+
+
+ SetView(4);
+
+
+ SetView(5);
+
+
+ SaveView(1);
+
+
+ SaveView(2);
+
+
+ SaveView(3);
+
+
+ SaveView(4);
+
+
+ SaveView(5);
+
+
+ ResetView(1);
+
+
+ ResetView(2);
+
+
+ ResetView(3);
+
+
+ ResetView(4);
+
+
+ ResetView(5);
+
+
+ FlipCameraYaw(180);
+
+
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 1);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 1);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 2);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 2);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 3);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 3);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 4);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 4);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 5);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 5);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 6);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 6);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 7);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 7);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 8);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 8);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 9);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 9);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 10);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 10);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 11);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 11);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomLeft", 12);
+ else
+ MultiActionButtonUp("MultiBarBottomLeft", 12);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 1);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 1);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 2);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 2);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 3);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 3);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 4);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 4);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 5);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 5);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 6);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 6);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 7);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 7);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 8);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 8);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 9);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 9);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 10);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 10);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 11);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 11);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarBottomRight", 12);
+ else
+ MultiActionButtonUp("MultiBarBottomRight", 12);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 1);
+ else
+ MultiActionButtonUp("MultiBarRight", 1);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 2);
+ else
+ MultiActionButtonUp("MultiBarRight", 2);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 3);
+ else
+ MultiActionButtonUp("MultiBarRight", 3);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 4);
+ else
+ MultiActionButtonUp("MultiBarRight", 4);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 5);
+ else
+ MultiActionButtonUp("MultiBarRight", 5);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 6);
+ else
+ MultiActionButtonUp("MultiBarRight", 6);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 7);
+ else
+ MultiActionButtonUp("MultiBarRight", 7);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 8);
+ else
+ MultiActionButtonUp("MultiBarRight", 8);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 9);
+ else
+ MultiActionButtonUp("MultiBarRight", 9);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 10);
+ else
+ MultiActionButtonUp("MultiBarRight", 10);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 11);
+ else
+ MultiActionButtonUp("MultiBarRight", 11);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarRight", 12);
+ else
+ MultiActionButtonUp("MultiBarRight", 12);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 1);
+ else
+ MultiActionButtonUp("MultiBarLeft", 1);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 2);
+ else
+ MultiActionButtonUp("MultiBarLeft", 2);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 3);
+ else
+ MultiActionButtonUp("MultiBarLeft", 3);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 4);
+ else
+ MultiActionButtonUp("MultiBarLeft", 4);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 5);
+ else
+ MultiActionButtonUp("MultiBarLeft", 5);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 6);
+ else
+ MultiActionButtonUp("MultiBarLeft", 6);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 7);
+ else
+ MultiActionButtonUp("MultiBarLeft", 7);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 8);
+ else
+ MultiActionButtonUp("MultiBarLeft", 8);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 9);
+ else
+ MultiActionButtonUp("MultiBarLeft", 9);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 10);
+ else
+ MultiActionButtonUp("MultiBarLeft", 10);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 11);
+ else
+ MultiActionButtonUp("MultiBarLeft", 11);
+ end
+
+
+ if ( keystate == "down" ) then
+ MultiActionButtonDown("MultiBarLeft", 12);
+ else
+ MultiActionButtonUp("MultiBarLeft", 12);
+ end
+
+
+ SetRaidTargetIcon("target", 1);
+
+
+ SetRaidTargetIcon("target", 2);
+
+
+ SetRaidTargetIcon("target", 3);
+
+
+ SetRaidTargetIcon("target", 4);
+
+
+ SetRaidTargetIcon("target", 5);
+
+
+ SetRaidTargetIcon("target", 6);
+
+
+ SetRaidTargetIcon("target", 7);
+
+
+ SetRaidTargetIcon("target", 8);
+
+
+ SetRaidTarget("target", 0);
+
+
+
+ VehicleExit();
+
+
+ VehiclePrevSeat();
+
+
+ VehicleNextSeat();
+
+
+ if ( keystate == "down" ) then
+ VehicleAimUpStart();
+ else
+ VehicleAimUpStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ VehicleAimDownStart();
+ else
+ VehicleAimDownStop();
+ end
+
+
+ VehicleAimIncrement(0.1);
+
+
+ VehicleAimDecrement(0.1);
+
+
+ VehicleCameraZoomIn(1.0);
+
+
+ VehicleCameraZoomOut(1.0);
+
+
+
+
+ if ( keystate == "down" ) then
+ TurnOrActionStart();
+ else
+ TurnOrActionStop();
+ end
+
+
+ if ( keystate == "down" ) then
+ CameraOrSelectOrMoveStart();
+ else
+ CameraOrSelectOrMoveStop(IsModifiedClick("STICKYCAMERA"));
+ end
+
+
+
+
+ MusicPlayer_PlayPause();
+
+
+ MusicPlayer_NextTrack();
+
+
+ MusicPlayer_BackTrack();
+
+
+ MusicPlayer_VolumeUp();
+
+
+ MusicPlayer_VolumeDown();
+
+
+
+
+ MovieRecording_Toggle();
+
+
+ if(MovieRecording_IsRecording() or MovieRecording_IsCompressing()) then
+ MacOptionsCancelFrame:Show();
+ end
+
+
+ MovieRecording_SearchUncompressedMovie(true);
+
+
+ MovieRecording_ToggleGUI();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/BonusActionBarFrame.lua b/reference/FrameXML/BonusActionBarFrame.lua
new file mode 100644
index 0000000..82288e2
--- /dev/null
+++ b/reference/FrameXML/BonusActionBarFrame.lua
@@ -0,0 +1,294 @@
+BONUSACTIONBAR_SLIDETIME = 0.15;
+BONUSACTIONBAR_YPOS = 43;
+BONUSACTIONBAR_XPOS = 4;
+NUM_BONUS_ACTION_SLOTS = 12;
+NUM_SHAPESHIFT_SLOTS = 10;
+NUM_POSSESS_SLOTS = 2;
+POSSESS_CANCEL_SLOT = 2;
+
+function BonusActionBar_OnLoad (self)
+ self:RegisterEvent("UPDATE_BONUS_ACTIONBAR");
+ self:SetFrameLevel(self:GetFrameLevel() + 2);
+ self.mode = "none";
+ self.completed = 1;
+ self.lastBonusBar = 1;
+ if ( GetBonusBarOffset() > 0 and GetActionBarPage() == 1 ) then
+ ShowBonusActionBar();
+ end
+end
+
+function BonusActionBar_OnEvent (self, event, ...)
+ if ( event == "UPDATE_BONUS_ACTIONBAR" ) then
+ if ( GetBonusBarOffset() > 0 ) then
+ self.lastBonusBar = GetBonusBarOffset();
+ ShowBonusActionBar();
+ else
+ HideBonusActionBar();
+ end
+ end
+end
+
+function BonusActionBar_OnUpdate(self, elapsed)
+ local yPos;
+ if ( self.slideTimer and (self.slideTimer < self.timeToSlide) ) then
+ -- Animating
+ self.completed = nil;
+ if ( self.mode == "show" ) then
+ yPos = (self.slideTimer/self.timeToSlide) * BONUSACTIONBAR_YPOS;
+ self:SetPoint("TOPLEFT", self:GetParent(), "BOTTOMLEFT", BONUSACTIONBAR_XPOS, yPos);
+ self.state = "showing";
+ self:Show();
+ elseif ( self.mode == "hide" ) then
+ yPos = (1 - (self.slideTimer/self.timeToSlide)) * BONUSACTIONBAR_YPOS;
+ self:SetPoint("TOPLEFT", self:GetParent(), "BOTTOMLEFT", BONUSACTIONBAR_XPOS, yPos);
+ self.state = "hiding";
+ end
+ self.slideTimer = self.slideTimer + elapsed;
+ else
+ -- Animation complete
+ if ( self.completed == 1 ) then
+ return;
+ else
+ self.completed = 1;
+ end
+ if ( self.mode == "show" ) then
+ self:SetPoint("TOPLEFT", self:GetParent(), "BOTTOMLEFT", BONUSACTIONBAR_XPOS, BONUSACTIONBAR_YPOS);
+ self.state = "top";
+ PlaySound("igBonusBarOpen");
+ elseif ( self.mode == "hide" ) then
+ self:SetPoint("TOPLEFT", self:GetParent(), "BOTTOMLEFT", BONUSACTIONBAR_XPOS, 0);
+ self.state = "bottom";
+ self:Hide();
+ end
+ self.mode = "none";
+ end
+end
+
+function ShowBonusActionBar (override)
+ if (( (not MainMenuBar.busy) and (not UnitHasVehicleUI("player")) ) or override) then --Don't change while we're animating out MainMenuBar for vehicle UI
+ if ( (BonusActionBarFrame.mode ~= "show" and BonusActionBarFrame.state ~= "top") or (not UIParent:IsShown())) then
+ BonusActionBarFrame:Show();
+ if ( BonusActionBarFrame.completed ) then
+ BonusActionBarFrame.slideTimer = 0;
+ end
+ BonusActionBarFrame.timeToSlide = BONUSACTIONBAR_SLIDETIME;
+ BonusActionBarFrame.mode = "show";
+ end
+ end
+end
+
+function HideBonusActionBar (override)
+ if (( (not MainMenuBar.busy) and (not UnitHasVehicleUI("player")) ) or override) then --Don't change while we're animating out MainMenuBar for vehicle UI
+ if ( (BonusActionBarFrame:IsShown()) or (not UIParent:IsShown())) then
+ if ( BonusActionBarFrame.completed ) then
+ BonusActionBarFrame.slideTimer = 0;
+ end
+ BonusActionBarFrame.timeToSlide = BONUSACTIONBAR_SLIDETIME;
+ BonusActionBarFrame.mode = "hide";
+ end
+ end
+end
+
+function BonusActionButtonUp (id)
+ PetActionButtonUp(id);
+end
+
+function BonusActionButtonDown (id)
+ PetActionButtonDown(id);
+end
+
+function ShapeshiftBar_OnLoad (self)
+ ShapeshiftBar_Update();
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("UPDATE_SHAPESHIFT_FORMS");
+ self:RegisterEvent("UPDATE_SHAPESHIFT_USABLE");
+ self:RegisterEvent("UPDATE_SHAPESHIFT_COOLDOWN");
+ self:RegisterEvent("UPDATE_SHAPESHIFT_FORM");
+ self:RegisterEvent("UPDATE_INVENTORY_ALERTS"); -- Wha?? Still Wha...
+ self:RegisterEvent("ACTIONBAR_PAGE_CHANGED");
+end
+
+function ShapeshiftBar_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" or event == "UPDATE_SHAPESHIFT_FORMS" ) then
+ ShapeshiftBar_Update();
+ elseif ( event == "ACTIONBAR_PAGE_CHANGED" ) then
+ if ( GetBonusBarOffset() > 0 ) then
+ ShowBonusActionBar();
+ else
+ HideBonusActionBar();
+ end
+ else
+ ShapeshiftBar_UpdateState();
+ end
+end
+
+function ShapeshiftBar_Update ()
+ local numForms = GetNumShapeshiftForms();
+ if ( numForms > 0 ) then
+ --Setup the shapeshift bar to display the appropriate number of slots
+ if ( numForms == 1 ) then
+ ShapeshiftBarMiddle:Hide();
+ ShapeshiftBarRight:SetPoint("LEFT", "ShapeshiftBarLeft", "LEFT", 12, 0);
+ ShapeshiftButton1:SetPoint("BOTTOMLEFT", "ShapeshiftBarFrame", "BOTTOMLEFT", 12, 3);
+ elseif ( numForms == 2 ) then
+ ShapeshiftBarMiddle:Hide();
+ ShapeshiftBarRight:SetPoint("LEFT", "ShapeshiftBarLeft", "RIGHT", 0, 0);
+ else
+ ShapeshiftBarMiddle:Show();
+ ShapeshiftBarMiddle:SetPoint("LEFT", "ShapeshiftBarLeft", "RIGHT", 0, 0);
+ ShapeshiftBarMiddle:SetWidth(37 * (numForms-2));
+ ShapeshiftBarMiddle:SetTexCoord(0, numForms-2, 0, 1);
+ ShapeshiftBarRight:SetPoint("LEFT", "ShapeshiftBarMiddle", "RIGHT", 0, 0);
+ end
+
+ ShapeshiftBarFrame:Show();
+ else
+ ShapeshiftBarFrame:Hide();
+ end
+ ShapeshiftBar_UpdateState();
+ UIParent_ManageFramePositions();
+end
+
+function ShapeshiftBar_UpdateState ()
+ local numForms = GetNumShapeshiftForms();
+ local texture, name, isActive, isCastable;
+ local button, icon, cooldown;
+ local start, duration, enable;
+ for i=1, NUM_SHAPESHIFT_SLOTS do
+ button = _G["ShapeshiftButton"..i];
+ icon = _G["ShapeshiftButton"..i.."Icon"];
+ if ( i <= numForms ) then
+ texture, name, isActive, isCastable = GetShapeshiftFormInfo(i);
+ icon:SetTexture(texture);
+
+ --Cooldown stuffs
+ cooldown = _G["ShapeshiftButton"..i.."Cooldown"];
+ if ( texture ) then
+ cooldown:Show();
+ else
+ cooldown:Hide();
+ end
+ start, duration, enable = GetShapeshiftFormCooldown(i);
+ CooldownFrame_SetTimer(cooldown, start, duration, enable);
+
+ if ( isActive ) then
+ ShapeshiftBarFrame.lastSelected = button:GetID();
+ button:SetChecked(1);
+ else
+ button:SetChecked(0);
+ end
+
+ if ( isCastable ) then
+ icon:SetVertexColor(1.0, 1.0, 1.0);
+ else
+ icon:SetVertexColor(0.4, 0.4, 0.4);
+ end
+
+ button:Show();
+ else
+ button:Hide();
+ end
+ end
+end
+
+function ShapeshiftBar_ChangeForm (id)
+ ShapeshiftBarFrame.lastSelected = id;
+ CastShapeshiftForm(id);
+end
+
+function PossessBar_OnLoad (self)
+ PossessBar_Update();
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("UPDATE_BONUS_ACTIONBAR");
+ self:RegisterEvent("UNIT_AURA");
+ self:RegisterEvent("ACTIONBAR_PAGE_CHANGED");
+end
+
+function PossessBar_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" or event == "UPDATE_BONUS_ACTIONBAR" ) then
+ PossessBar_Update();
+ elseif ( event == "ACTIONBAR_PAGE_CHANGED" ) then
+ if ( GetBonusBarOffset() > 0 ) then
+ ShowBonusActionBar();
+ else
+ HideBonusActionBar();
+ end
+ end
+end
+
+function PossessBar_Update (override)
+ if ( (not MainMenuBar.busy and not UnitHasVehicleUI("player")) or override ) then --Don't change while we're animating out MainMenuBar for vehicle UI
+ if ( IsPossessBarVisible() ) then
+ PossessBarFrame:Show();
+ ShapeshiftBarFrame:Hide();
+ ShowPetActionBar(true);
+ else
+ PossessBarFrame:Hide();
+ if(GetNumShapeshiftForms() > 0) then
+ ShapeshiftBarFrame:Show();
+ ShowPetActionBar(true);
+ end
+ end
+ PossessBar_UpdateState();
+ UIParent_ManageFramePositions();
+ end
+end
+
+function PossessBar_UpdateState ()
+ local texture, name, enabled;
+ local button, background, icon, cooldown;
+
+ for i=1, NUM_POSSESS_SLOTS do
+ -- Possess Icon
+ button = _G["PossessButton"..i];
+ background = _G["PossessBackground"..i];
+ icon = _G["PossessButton"..i.."Icon"];
+ texture, name, enabled = GetPossessInfo(i);
+ icon:SetTexture(texture);
+
+ --Cooldown stuffs
+ cooldown = _G["PossessButton"..i.."Cooldown"];
+ cooldown:Hide();
+
+ button:SetChecked(nil);
+ icon:SetVertexColor(1.0, 1.0, 1.0);
+
+ if ( enabled ) then
+ button:Show();
+ background:Show();
+ else
+ button:Hide();
+ background:Hide();
+ end
+ end
+end
+
+function PossessButton_OnClick (self)
+ self:SetChecked(nil);
+
+ local id = self:GetID();
+ if ( id == POSSESS_CANCEL_SLOT ) then
+ if ( UnitControllingVehicle("player") and CanExitVehicle() ) then
+ VehicleExit();
+ else
+ local texture, name = GetPossessInfo(id);
+ CancelUnitBuff("player", name);
+ end
+ end
+end
+
+function PossessButton_OnEnter (self)
+ local id = self:GetID();
+
+ if ( GetCVar("UberTooltips") == "1" ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+
+ if ( id == POSSESS_CANCEL_SLOT ) then
+ GameTooltip:SetText(CANCEL);
+ else
+ GameTooltip:SetPossession(id);
+ end
+end
diff --git a/reference/FrameXML/BonusActionBarFrame.xml b/reference/FrameXML/BonusActionBarFrame.xml
new file mode 100644
index 0000000..bcaa722
--- /dev/null
+++ b/reference/FrameXML/BonusActionBarFrame.xml
@@ -0,0 +1,396 @@
+
+
+
+
+
+
+
+
+ self.isBonus = 1;
+ ActionButton_OnLoad(self);
+ self:RegisterEvent("UPDATE_BONUS_ACTIONBAR");
+ self:SetFrameLevel(self:GetFrameLevel() + 2);
+ local cooldown = _G[self:GetName().."Cooldown"];
+ cooldown:SetFrameLevel(cooldown:GetFrameLevel() + 2);
+
+
+
+
+
+
+
+
+
+ self:SetChecked(not self:GetChecked());
+ ShapeshiftBar_ChangeForm(self:GetID());
+
+
+ if ( GetCVarBool("UberTooltips") ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+ GameTooltip:SetShapeshift(self:GetID());
+
+
+
+
+
+
+
+
+
+
+ PossessButton_OnClick(self, button, down);
+
+
+ PossessButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/BuffFrame.lua b/reference/FrameXML/BuffFrame.lua
new file mode 100644
index 0000000..6302541
--- /dev/null
+++ b/reference/FrameXML/BuffFrame.lua
@@ -0,0 +1,550 @@
+BUFF_FLASH_TIME_ON = 0.75;
+BUFF_FLASH_TIME_OFF = 0.75;
+BUFF_MIN_ALPHA = 0.3;
+BUFF_WARNING_TIME = 31;
+BUFF_DURATION_WARNING_TIME = 60;
+BUFFS_PER_ROW = 8;
+BUFF_MAX_DISPLAY = 32;
+BUFF_ACTUAL_DISPLAY = 0;
+DEBUFF_MAX_DISPLAY = 16
+DEBUFF_ACTUAL_DISPLAY = 0;
+BUFF_ROW_SPACING = 0;
+CONSOLIDATED_BUFFS_PER_ROW = 4;
+CONSOLIDATED_BUFF_ROW_HEIGHT = 0;
+
+DebuffTypeColor = { };
+DebuffTypeColor["none"] = { r = 0.80, g = 0, b = 0 };
+DebuffTypeColor["Magic"] = { r = 0.20, g = 0.60, b = 1.00 };
+DebuffTypeColor["Curse"] = { r = 0.60, g = 0.00, b = 1.00 };
+DebuffTypeColor["Disease"] = { r = 0.60, g = 0.40, b = 0 };
+DebuffTypeColor["Poison"] = { r = 0.00, g = 0.60, b = 0 };
+DebuffTypeColor[""] = DebuffTypeColor["none"];
+
+DebuffTypeSymbol = { };
+DebuffTypeSymbol["Magic"] = DEBUFF_SYMBOL_MAGIC;
+DebuffTypeSymbol["Curse"] = DEBUFF_SYMBOL_CURSE;
+DebuffTypeSymbol["Disease"] = DEBUFF_SYMBOL_DISEASE;
+DebuffTypeSymbol["Poison"] = DEBUFF_SYMBOL_POISON;
+
+local consolidatedBuffs = { };
+
+function BuffFrame_OnLoad(self)
+ self.BuffFrameUpdateTime = 0;
+ self.BuffFrameFlashTime = 0;
+ self.BuffFrameFlashState = 1;
+ self.BuffAlphaValue = 1;
+ self:RegisterEvent("UNIT_AURA");
+ self.numEnchants = 0;
+ self.numConsolidated = 0;
+end
+
+function BuffFrame_OnEvent(self, event, ...)
+ local unit = ...;
+ if ( event == "UNIT_AURA" ) then
+ if ( unit == PlayerFrame.unit ) then
+ BuffFrame_Update();
+ end
+ end
+end
+
+function BuffFrame_OnUpdate(self, elapsed)
+ if ( self.BuffFrameUpdateTime > 0 ) then
+ self.BuffFrameUpdateTime = self.BuffFrameUpdateTime - elapsed;
+ else
+ self.BuffFrameUpdateTime = self.BuffFrameUpdateTime + TOOLTIP_UPDATE_TIME;
+ end
+
+ self.BuffFrameFlashTime = self.BuffFrameFlashTime - elapsed;
+ if ( self.BuffFrameFlashTime < 0 ) then
+ local overtime = -self.BuffFrameFlashTime;
+ if ( self.BuffFrameFlashState == 0 ) then
+ self.BuffFrameFlashState = 1;
+ self.BuffFrameFlashTime = BUFF_FLASH_TIME_ON;
+ else
+ self.BuffFrameFlashState = 0;
+ self.BuffFrameFlashTime = BUFF_FLASH_TIME_OFF;
+ end
+ if ( overtime < self.BuffFrameFlashTime ) then
+ self.BuffFrameFlashTime = self.BuffFrameFlashTime - overtime;
+ end
+ end
+
+ if ( self.BuffFrameFlashState == 1 ) then
+ self.BuffAlphaValue = (BUFF_FLASH_TIME_ON - self.BuffFrameFlashTime) / BUFF_FLASH_TIME_ON;
+ else
+ self.BuffAlphaValue = self.BuffFrameFlashTime / BUFF_FLASH_TIME_ON;
+ end
+ self.BuffAlphaValue = (self.BuffAlphaValue * (1 - BUFF_MIN_ALPHA)) + BUFF_MIN_ALPHA;
+end
+
+function BuffFrame_Update()
+ -- Handle Buffs
+ BUFF_ACTUAL_DISPLAY = 0;
+ ConsolidatedBuffs.pauseUpdate = true;
+ table.wipe(consolidatedBuffs);
+ for i=1, BUFF_MAX_DISPLAY do
+ if ( AuraButton_Update("BuffButton", i, "HELPFUL") ) then
+ BUFF_ACTUAL_DISPLAY = BUFF_ACTUAL_DISPLAY + 1;
+ end
+ end
+ BuffFrame.numConsolidated = #consolidatedBuffs;
+ if ( BuffFrame.numConsolidated > 0 ) then
+ ConsolidatedBuffsCount:SetText(BuffFrame.numConsolidated);
+ if ( not ConsolidatedBuffs:IsShown() ) then
+ ConsolidatedBuffs:Show();
+ end
+ else
+ BuffFrame.numConsolidated = 0;
+ ConsolidatedBuffs:Hide();
+ end
+ BuffFrame_UpdateAllBuffAnchors();
+ ConsolidatedBuffs.pauseUpdate = false;
+
+ -- Handle debuffs
+ DEBUFF_ACTUAL_DISPLAY = 0;
+ for i=1, DEBUFF_MAX_DISPLAY do
+ if ( AuraButton_Update("DebuffButton", i, "HARMFUL") ) then
+ DEBUFF_ACTUAL_DISPLAY = DEBUFF_ACTUAL_DISPLAY + 1;
+ end
+ end
+end
+
+function BuffFrame_UpdatePositions()
+ if ( SHOW_BUFF_DURATIONS == "1" ) then
+ BUFF_ROW_SPACING = 15;
+ CONSOLIDATED_BUFF_ROW_HEIGHT = 31;
+ else
+ BUFF_ROW_SPACING = 5;
+ CONSOLIDATED_BUFF_ROW_HEIGHT = 24;
+ end
+ BuffFrame_Update();
+end
+
+function AuraButton_Update(buttonName, index, filter)
+ local unit = PlayerFrame.unit;
+ local name, rank, texture, count, debuffType, duration, expirationTime, _, _, shouldConsolidate = UnitAura(unit, index, filter);
+
+ local buffName = buttonName..index;
+ local buff = _G[buffName];
+
+ if ( not name ) then
+ -- No buff so hide it if it exists
+ if ( buff ) then
+ buff:Hide();
+ buff.duration:Hide();
+ end
+ return nil;
+ else
+ local helpful = (filter == "HELPFUL");
+
+ -- If button doesn't exist make it
+ if ( not buff ) then
+ if ( helpful ) then
+ buff = CreateFrame("Button", buffName, BuffFrame, "BuffButtonTemplate");
+ else
+ buff = CreateFrame("Button", buffName, BuffFrame, "DebuffButtonTemplate");
+ end
+ buff.parent = BuffFrame;
+ end
+ -- Setup Buff
+ buff:SetID(index);
+ buff.unit = unit;
+ buff.filter = filter;
+ buff:SetAlpha(1.0);
+ buff.exitTime = nil;
+ buff.consolidated = nil;
+ buff:Show();
+ -- Set filter-specific attributes
+ if ( not helpful ) then
+ -- Anchor Debuffs
+ DebuffButton_UpdateAnchors(buttonName, index);
+
+ -- Set color of debuff border based on dispel class.
+ local debuffSlot = _G[buffName.."Border"];
+ if ( debuffSlot ) then
+ local color;
+ if ( debuffType ) then
+ color = DebuffTypeColor[debuffType];
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ buff.symbol:Show();
+ buff.symbol:SetText(DebuffTypeSymbol[debuffType] or "");
+ else
+ buff.symbol:Hide();
+ end
+ else
+ buff.symbol:Hide();
+ color = DebuffTypeColor["none"];
+ end
+ debuffSlot:SetVertexColor(color.r, color.g, color.b);
+ end
+ end
+
+ if ( duration > 0 and expirationTime ) then
+ if ( SHOW_BUFF_DURATIONS == "1" ) then
+ buff.duration:Show();
+ else
+ buff.duration:Hide();
+ end
+
+ if ( not buff.timeLeft ) then
+ buff.timeLeft = expirationTime - GetTime();
+ buff:SetScript("OnUpdate", AuraButton_OnUpdate);
+ else
+ buff.timeLeft = expirationTime - GetTime();
+ end
+ else
+ buff.duration:Hide();
+ if ( buff.timeLeft ) then
+ buff:SetScript("OnUpdate", nil);
+ end
+ buff.timeLeft = nil;
+ end
+
+ -- Set Texture
+ local icon = _G[buffName.."Icon"];
+ icon:SetTexture(texture);
+
+ -- Set the number of applications of an aura
+ if ( count > 1 ) then
+ buff.count:SetText(count);
+ buff.count:Show();
+ else
+ buff.count:Hide();
+ end
+
+ -- Refresh tooltip
+ if ( GameTooltip:IsOwned(buff) ) then
+ GameTooltip:SetUnitAura(PlayerFrame.unit, index, filter);
+ end
+
+ if ( CONSOLIDATE_BUFFS == "1" and shouldConsolidate ) then
+ if ( buff.timeLeft and duration > 30 ) then
+ buff.exitTime = expirationTime - max(10, duration / 10);
+ end
+ buff.expirationTime = expirationTime;
+ buff.consolidated = true;
+ table.insert(consolidatedBuffs, buff);
+ end
+ end
+ return 1;
+end
+
+function AuraButton_OnUpdate(self, elapsed)
+ local index = self:GetID();
+ if ( self.timeLeft < BUFF_WARNING_TIME ) then
+ self:SetAlpha(BuffFrame.BuffAlphaValue);
+ else
+ self:SetAlpha(1.0);
+ end
+
+ -- Update duration
+ securecall("AuraButton_UpdateDuration", self, self.timeLeft); -- Taint issue with SecondsToTimeAbbrev
+ self.timeLeft = max(self.timeLeft - elapsed, 0);
+
+ if ( BuffFrame.BuffFrameUpdateTime > 0 ) then
+ return;
+ end
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetUnitAura(PlayerFrame.unit, index, self.filter);
+ end
+end
+
+function AuraButton_UpdateDuration(auraButton, timeLeft)
+ local duration = auraButton.duration;
+ if ( SHOW_BUFF_DURATIONS == "1" and timeLeft ) then
+ duration:SetFormattedText(SecondsToTimeAbbrev(timeLeft));
+ if ( timeLeft < BUFF_DURATION_WARNING_TIME ) then
+ duration:SetVertexColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ else
+ duration:SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+ duration:Show();
+ else
+ duration:Hide();
+ end
+end
+
+function BuffButton_OnLoad(self)
+ self:RegisterForClicks("RightButtonUp");
+end
+
+function BuffButton_OnClick(self)
+ CancelUnitBuff(self.unit, self:GetID(), self.filter);
+end
+
+function BuffFrame_UpdateAllBuffAnchors()
+ local buff, previousBuff, aboveBuff;
+ local numBuffs = 0;
+ local slack = BuffFrame.numEnchants
+ if ( BuffFrame.numConsolidated > 0 ) then
+ slack = slack + 1; -- one icon for all consolidated buffs
+ end
+
+ for i = 1, BUFF_ACTUAL_DISPLAY do
+ buff = _G["BuffButton"..i];
+ if ( buff.consolidated ) then
+ if ( buff.parent == BuffFrame ) then
+ buff:SetParent(ConsolidatedBuffsContainer);
+ buff.parent = ConsolidatedBuffsContainer;
+ end
+ else
+ numBuffs = numBuffs + 1;
+ index = numBuffs + slack;
+ if ( buff.parent ~= BuffFrame ) then
+ buff.count:SetFontObject(NumberFontNormal);
+ buff:SetParent(BuffFrame);
+ buff.parent = BuffFrame;
+ end
+ buff:ClearAllPoints();
+ if ( (index > 1) and (mod(index, BUFFS_PER_ROW) == 1) ) then
+ -- New row
+ if ( index == BUFFS_PER_ROW+1 ) then
+ buff:SetPoint("TOP", ConsolidatedBuffs, "BOTTOM", 0, -BUFF_ROW_SPACING);
+ else
+ buff:SetPoint("TOP", aboveBuff, "BOTTOM", 0, -BUFF_ROW_SPACING);
+ end
+ aboveBuff = buff;
+ elseif ( index == 1 ) then
+ buff:SetPoint("TOPRIGHT", BuffFrame, "TOPRIGHT", 0, 0);
+ else
+ if ( numBuffs == 1 ) then
+ if ( BuffFrame.numEnchants > 0 ) then
+ buff:SetPoint("TOPRIGHT", "TemporaryEnchantFrame", "TOPLEFT", -5, 0);
+ else
+ buff:SetPoint("TOPRIGHT", ConsolidatedBuffs, "TOPLEFT", -5, 0);
+ end
+ else
+ buff:SetPoint("RIGHT", previousBuff, "LEFT", -5, 0);
+ end
+ end
+ previousBuff = buff;
+ end
+ end
+
+ if ( ConsolidatedBuffsTooltip:IsShown() ) then
+ ConsolidatedBuffs_UpdateAllAnchors();
+ end
+end
+
+function ConsolidatedBuffs_UpdateAllAnchors()
+ local buff, previousBuff, aboveBuff;
+ local numBuffs = 0;
+
+ for _, buff in pairs(consolidatedBuffs) do
+ numBuffs = numBuffs + 1;
+ if ( buff.parent == BuffFrame ) then
+ buff:SetParent(ConsolidatedBuffsContainer);
+ buff.parent = ConsolidatedBuffsContainer;
+ end
+ buff:ClearAllPoints();
+ if ( (numBuffs > 1) and (mod(numBuffs, CONSOLIDATED_BUFFS_PER_ROW) == 1) ) then
+ -- new row
+ buff:SetPoint("TOP", aboveBuff, "BOTTOM", 0, -BUFF_ROW_SPACING);
+ aboveBuff = buff;
+ elseif ( numBuffs == 1 ) then
+ buff:SetPoint("TOPLEFT", ConsolidatedBuffsContainer, "TOPLEFT", 0, 0);
+ aboveBuff = buff;
+ else
+ buff:SetPoint("LEFT", previousBuff, "RIGHT", 7, 0);
+ end
+ previousBuff = buff;
+ end
+ ConsolidatedBuffsTooltip:SetWidth(min(numBuffs * 24 + 18, 114));
+ ConsolidatedBuffsTooltip:SetHeight(floor((numBuffs + 3) / 4 ) * CONSOLIDATED_BUFF_ROW_HEIGHT + 16);
+end
+
+function DebuffButton_UpdateAnchors(buttonName, index)
+ local numBuffs = BUFF_ACTUAL_DISPLAY + BuffFrame.numEnchants;
+ if ( BuffFrame.numConsolidated > 0 ) then
+ numBuffs = numBuffs - BuffFrame.numConsolidated + 1;
+ end
+ local rows = ceil(numBuffs/BUFFS_PER_ROW);
+ local buff = _G[buttonName..index];
+ local buffHeight = TempEnchant1:GetHeight();
+
+ -- Position debuffs
+ if ( (index > 1) and (mod(index, BUFFS_PER_ROW) == 1) ) then
+ -- New row
+ buff:SetPoint("TOP", _G[buttonName..(index-BUFFS_PER_ROW)], "BOTTOM", 0, -BUFF_ROW_SPACING);
+ elseif ( index == 1 ) then
+ if ( rows < 2 ) then
+ buff:SetPoint("TOPRIGHT", ConsolidatedBuffs, "BOTTOMRIGHT", 0, -1*((2*BUFF_ROW_SPACING)+buffHeight));
+ else
+ buff:SetPoint("TOPRIGHT", ConsolidatedBuffs, "BOTTOMRIGHT", 0, -rows*(BUFF_ROW_SPACING+buffHeight));
+ end
+ else
+ buff:SetPoint("RIGHT", _G[buttonName..(index-1)], "LEFT", -5, 0);
+ end
+end
+
+
+function TemporaryEnchantFrame_Hide()
+ if ( BuffFrame.numEnchants > 0 ) then
+ BuffFrame.numEnchants = 0;
+ BuffFrame_Update();
+ end
+ TempEnchant1:Hide();
+ TempEnchant1Duration:Hide();
+ TempEnchant2:Hide();
+ TempEnchant2Duration:Hide();
+ BuffFrame:SetPoint("TOPRIGHT", ConsolidatedBuffs, "TOPRIGHT", 0, 0);
+end
+
+function TemporaryEnchantFrame_OnUpdate(self, elapsed)
+ if ( not PlayerFrame.unit or PlayerFrame.unit ~= "player" ) then
+ -- don't show temporary enchants when the player isn't controlling himself
+ TemporaryEnchantFrame_Hide();
+ return;
+ end
+
+ local hasMainHandEnchant, mainHandExpiration, mainHandCharges, hasOffHandEnchant, offHandExpiration, offHandCharges = GetWeaponEnchantInfo();
+ if ( not hasMainHandEnchant and not hasOffHandEnchant ) then
+ -- No enchants, kick out early
+ TemporaryEnchantFrame_Hide();
+ return;
+ end
+
+ -- Has enchants
+ local enchantButton;
+ local textureName;
+ local buffAlphaValue;
+ local enchantIndex = 0;
+ if ( hasOffHandEnchant ) then
+ enchantIndex = enchantIndex + 1;
+ textureName = GetInventoryItemTexture("player", 17);
+ TempEnchant1:SetID(17);
+ TempEnchant1Icon:SetTexture(textureName);
+ TempEnchant1:Show();
+
+ -- Show buff durations if necessary
+ if ( offHandExpiration ) then
+ offHandExpiration = offHandExpiration/1000;
+ end
+ AuraButton_UpdateDuration(TempEnchant1, offHandExpiration);
+
+ -- Handle flashing
+ if ( offHandExpiration and offHandExpiration < BUFF_WARNING_TIME ) then
+ TempEnchant1:SetAlpha(BuffFrame.BuffAlphaValue);
+ else
+ TempEnchant1:SetAlpha(1.0);
+ end
+ end
+ if ( hasMainHandEnchant ) then
+ enchantIndex = enchantIndex + 1;
+ enchantButton = _G["TempEnchant"..enchantIndex];
+ textureName = GetInventoryItemTexture("player", 16);
+ enchantButton:SetID(16);
+ _G[enchantButton:GetName().."Icon"]:SetTexture(textureName);
+ enchantButton:Show();
+
+ -- Show buff durations if necessary
+ if ( mainHandExpiration ) then
+ mainHandExpiration = mainHandExpiration/1000;
+ end
+ AuraButton_UpdateDuration(enchantButton, mainHandExpiration);
+
+ -- Handle flashing
+ if ( mainHandExpiration and mainHandExpiration < BUFF_WARNING_TIME ) then
+ enchantButton:SetAlpha(BuffFrame.BuffAlphaValue);
+ else
+ enchantButton:SetAlpha(1.0);
+ end
+ end
+ --Hide unused enchants
+ for i=enchantIndex+1, 2 do
+ _G["TempEnchant"..i]:Hide();
+ _G["TempEnchant"..i.."Duration"]:Hide();
+ end
+
+ -- Position buff frame
+ TemporaryEnchantFrame:SetWidth(enchantIndex * 32);
+ if ( BuffFrame.numEnchants ~= enchantIndex ) then
+ BuffFrame.numEnchants = enchantIndex;
+ BuffFrame_Update();
+ end
+end
+
+function TempEnchantButton_OnLoad(self)
+ self:RegisterForClicks("RightButtonUp");
+end
+
+function TempEnchantButton_OnUpdate(self, elapsed)
+ -- Update duration
+ if ( GameTooltip:IsOwned(self) ) then
+ TempEnchantButton_OnEnter(self);
+ end
+end
+
+function TempEnchantButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT");
+ GameTooltip:SetInventoryItem("player", self:GetID());
+end
+
+function TempEnchantButton_OnClick(self, button)
+ if ( self:GetID() == 16 ) then
+ CancelItemTempEnchantment(1);
+ elseif ( self:GetID() == 17 ) then
+ CancelItemTempEnchantment(2);
+ end
+end
+
+function ConsolidatedBuffs_OnUpdate(self)
+ -- tooltip stuff
+ -- need 1-pixel outer padding because otherwise at certain resolutions OnEnter will trigger with IsMouseOver returning false
+ if ( self.mousedOver and not self:IsMouseOver(1, -1, -1, 1) ) then
+ self.mousedOver = nil;
+ if ( not ConsolidatedBuffsTooltip:IsMouseOver() ) then
+ ConsolidatedBuffsTooltip:Hide();
+ end
+ end
+
+ -- check exit times
+ if ( not ConsolidatedBuffs.pauseUpdate ) then
+ local needUpdate = false;
+ local timeNow = GetTime();
+ for buffIndex, buff in pairs(consolidatedBuffs) do
+ if ( buff.exitTime and buff.exitTime < timeNow ) then
+ buff.consolidated = false;
+ buff.timeLeft = buff.expirationTime - timeNow;
+ tremove(consolidatedBuffs, buffIndex);
+ needUpdate = true;
+ end
+ end
+ if ( needUpdate ) then
+ if ( #consolidatedBuffs == 0 ) then
+ BuffFrame.numConsolidated = 0;
+ ConsolidatedBuffs:Hide();
+ else
+ BuffFrame_UpdateAllBuffAnchors();
+ ConsolidatedBuffsCount:SetText(#consolidatedBuffs);
+ end
+ end
+ end
+end
+
+function ConsolidatedBuffs_OnShow()
+ ConsolidatedBuffsCount:SetText(BuffFrame.numConsolidated);
+ TemporaryEnchantFrame:SetPoint("TOPRIGHT", ConsolidatedBuffs, "TOPLEFT", -6, 0);
+ BuffFrame_UpdateAllBuffAnchors();
+end
+
+function ConsolidatedBuffs_OnEnter(self)
+ ConsolidatedBuffsTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT", 0, 0);
+ -- check expiration times
+ local timeNow = GetTime();
+ for buffIndex, buff in pairs(consolidatedBuffs) do
+ if ( buff.timeLeft ) then
+ buff.timeLeft = buff.expirationTime - timeNow;
+ end
+ end
+ ConsolidatedBuffs_UpdateAllAnchors();
+ ConsolidatedBuffsTooltip:Show();
+ ConsolidatedBuffs.mousedOver = true;
+end
+
+function ConsolidatedBuffs_OnHide(self)
+ self.mousedOver = nil;
+ ConsolidatedBuffsTooltip:Hide();
+ TemporaryEnchantFrame:SetPoint("TOPRIGHT", ConsolidatedBuffs, "TOPRIGHT", 0, 0);
+ BuffFrame_UpdateAllBuffAnchors();
+end
\ No newline at end of file
diff --git a/reference/FrameXML/BuffFrame.xml b/reference/FrameXML/BuffFrame.xml
new file mode 100644
index 0000000..bda0d73
--- /dev/null
+++ b/reference/FrameXML/BuffFrame.xml
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT");
+ GameTooltip:SetFrameLevel(self:GetFrameLevel() + 2);
+ GameTooltip:SetUnitAura(PlayerFrame.unit, self:GetID(), self.filter);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+ BuffButton_OnLoad(self);
+
+
+ BuffButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TempEnchantButton_OnLoad(self);
+
+
+ TempEnchantButton_OnUpdate(self, elapsed);
+
+
+ TempEnchantButton_OnClick(self, button, down);
+
+
+ TempEnchantButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ConsolidatedBuffsIcon:SetTexture("Interface\\Buttons\\BuffConsolidation");
+ ConsolidatedBuffsIcon:SetTexCoord(0, 0.5, 0, 1);
+ ConsolidatedBuffsIcon:ClearAllPoints();
+ ConsolidatedBuffsIcon:SetPoint("CENTER");
+ ConsolidatedBuffsIcon:SetWidth(64);
+ ConsolidatedBuffsIcon:SetHeight(64);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+ ConsolidatedBuffsContainer:SetScale(0.66);
+
+
+ self.mousedOver = true;
+
+
+ if ( self.mousedOver and not ConsolidatedBuffs.mousedOver and not self:IsMouseOver() ) then
+ self.mousedOver = nil;
+ self:Hide();
+ end
+
+
+ self.mousedOver = nil;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/CastingBarFrame.lua b/reference/FrameXML/CastingBarFrame.lua
new file mode 100644
index 0000000..125d2a2
--- /dev/null
+++ b/reference/FrameXML/CastingBarFrame.lua
@@ -0,0 +1,340 @@
+CASTING_BAR_ALPHA_STEP = 0.05;
+CASTING_BAR_FLASH_STEP = 0.2;
+CASTING_BAR_HOLD_TIME = 1;
+
+function CastingBarFrame_OnLoad (self, unit, showTradeSkills, showShield)
+ self:RegisterEvent("UNIT_SPELLCAST_START");
+ self:RegisterEvent("UNIT_SPELLCAST_STOP");
+ self:RegisterEvent("UNIT_SPELLCAST_FAILED");
+ self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED");
+ self:RegisterEvent("UNIT_SPELLCAST_DELAYED");
+ self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_START");
+ self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_UPDATE");
+ self:RegisterEvent("UNIT_SPELLCAST_CHANNEL_STOP");
+ self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTIBLE");
+ self:RegisterEvent("UNIT_SPELLCAST_NOT_INTERRUPTIBLE");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+ self.unit = unit;
+ self.showTradeSkills = showTradeSkills;
+ self.showShield = showShield;
+ self.casting = nil;
+ self.channeling = nil;
+ self.holdTime = 0;
+ self.showCastbar = true;
+
+ local barIcon = _G[self:GetName().."Icon"];
+ if ( barIcon ) then
+ barIcon:Hide();
+ end
+end
+
+function CastingBarFrame_OnShow (self)
+ if ( self.casting ) then
+ local _, _, _, _, startTime = UnitCastingInfo(self.unit);
+ if ( startTime ) then
+ self.value = (GetTime() - (startTime / 1000));
+ end
+ else
+ local _, _, _, _, _, endTime = UnitChannelInfo(self.unit);
+ if ( endTime ) then
+ self.value = ((endTime / 1000) - GetTime());
+ end
+ end
+end
+
+function CastingBarFrame_OnEvent (self, event, ...)
+ local arg1 = ...;
+
+ local unit = self.unit;
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ local nameChannel = UnitChannelInfo(unit);
+ local nameSpell = UnitCastingInfo(unit);
+ if ( nameChannel ) then
+ event = "UNIT_SPELLCAST_CHANNEL_START";
+ arg1 = unit;
+ elseif ( nameSpell ) then
+ event = "UNIT_SPELLCAST_START";
+ arg1 = unit;
+ else
+ CastingBarFrame_FinishSpell(self);
+ end
+ end
+
+ if ( arg1 ~= unit ) then
+ return;
+ end
+
+ local selfName = self:GetName();
+ local barSpark = _G[selfName.."Spark"];
+ local barText = _G[selfName.."Text"];
+ local barFlash = _G[selfName.."Flash"];
+ local barIcon = _G[selfName.."Icon"];
+ local barBorder = _G[selfName.."Border"];
+ local barBorderShield = _G[selfName.."BorderShield"];
+ if ( event == "UNIT_SPELLCAST_START" ) then
+ local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill, castID, notInterruptible = UnitCastingInfo(unit);
+ if ( not name or (not self.showTradeSkills and isTradeSkill)) then
+ self:Hide();
+ return;
+ end
+
+ self:SetStatusBarColor(1.0, 0.7, 0.0);
+ if ( barSpark ) then
+ barSpark:Show();
+ end
+ self.value = (GetTime() - (startTime / 1000));
+ self.maxValue = (endTime - startTime) / 1000;
+ self:SetMinMaxValues(0, self.maxValue);
+ self:SetValue(self.value);
+ if ( barText ) then
+ barText:SetText(text);
+ end
+ if ( barIcon ) then
+ barIcon:SetTexture(texture);
+ end
+ self:SetAlpha(1.0);
+ self.holdTime = 0;
+ self.casting = 1;
+ self.castID = castID;
+ self.channeling = nil;
+ self.fadeOut = nil;
+ if ( barBorderShield ) then
+ if ( self.showShield and notInterruptible ) then
+ barBorderShield:Show();
+ if ( barBorder ) then
+ barBorder:Hide();
+ end
+ else
+ barBorderShield:Hide();
+ if ( barBorder ) then
+ barBorder:Show();
+ end
+ end
+ end
+ if ( self.showCastbar ) then
+ self:Show();
+ end
+
+ elseif ( event == "UNIT_SPELLCAST_STOP" or event == "UNIT_SPELLCAST_CHANNEL_STOP") then
+ if ( not self:IsVisible() ) then
+ self:Hide();
+ end
+ if ( (self.casting and event == "UNIT_SPELLCAST_STOP" and select(4, ...) == self.castID) or
+ (self.channeling and event == "UNIT_SPELLCAST_CHANNEL_STOP") ) then
+ if ( barSpark ) then
+ barSpark:Hide();
+ end
+ if ( barFlash ) then
+ barFlash:SetAlpha(0.0);
+ barFlash:Show();
+ end
+ self:SetValue(self.maxValue);
+ if ( event == "UNIT_SPELLCAST_STOP" ) then
+ self.casting = nil;
+ self:SetStatusBarColor(0.0, 1.0, 0.0);
+ else
+ self.channeling = nil;
+ end
+ self.flash = 1;
+ self.fadeOut = 1;
+ self.holdTime = 0;
+ end
+ elseif ( event == "UNIT_SPELLCAST_FAILED" or event == "UNIT_SPELLCAST_INTERRUPTED" ) then
+ if ( self:IsShown() and
+ (self.casting and select(4, ...) == self.castID) and not self.fadeOut ) then
+ self:SetValue(self.maxValue);
+ self:SetStatusBarColor(1.0, 0.0, 0.0);
+ if ( barSpark ) then
+ barSpark:Hide();
+ end
+ if ( barText ) then
+ if ( event == "UNIT_SPELLCAST_FAILED" ) then
+ barText:SetText(FAILED);
+ else
+ barText:SetText(INTERRUPTED);
+ end
+ end
+ self.casting = nil;
+ self.channeling = nil;
+ self.fadeOut = 1;
+ self.holdTime = GetTime() + CASTING_BAR_HOLD_TIME;
+ end
+ elseif ( event == "UNIT_SPELLCAST_DELAYED" ) then
+ if ( self:IsShown() ) then
+ local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill = UnitCastingInfo(unit);
+ if ( not name or (not self.showTradeSkills and isTradeSkill)) then
+ -- if there is no name, there is no bar
+ self:Hide();
+ return;
+ end
+ self.value = (GetTime() - (startTime / 1000));
+ self.maxValue = (endTime - startTime) / 1000;
+ self:SetMinMaxValues(0, self.maxValue);
+ if ( not self.casting ) then
+ self:SetStatusBarColor(1.0, 0.7, 0.0);
+ if ( barSpark ) then
+ barSpark:Show();
+ end
+ if ( barFlash ) then
+ barFlash:SetAlpha(0.0);
+ barFlash:Hide();
+ end
+ self.casting = 1;
+ self.channeling = nil;
+ self.flash = 0;
+ self.fadeOut = 0;
+ end
+ end
+ elseif ( event == "UNIT_SPELLCAST_CHANNEL_START" ) then
+ local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill, notInterruptible = UnitChannelInfo(unit);
+ if ( not name or (not self.showTradeSkills and isTradeSkill)) then
+ -- if there is no name, there is no bar
+ self:Hide();
+ return;
+ end
+
+ self:SetStatusBarColor(0.0, 1.0, 0.0);
+ self.value = ((endTime / 1000) - GetTime());
+ self.maxValue = (endTime - startTime) / 1000;
+ self:SetMinMaxValues(0, self.maxValue);
+ self:SetValue(self.value);
+ if ( barText ) then
+ barText:SetText(text);
+ end
+ if ( barIcon ) then
+ barIcon:SetTexture(texture);
+ end
+ if ( barSpark ) then
+ barSpark:Hide();
+ end
+ self:SetAlpha(1.0);
+ self.holdTime = 0;
+ self.casting = nil;
+ self.channeling = 1;
+ self.fadeOut = nil;
+ if ( barBorderShield ) then
+ if ( self.showShield and notInterruptible ) then
+ barBorderShield:Show();
+ if ( barBorder ) then
+ barBorder:Hide();
+ end
+ else
+ barBorderShield:Hide();
+ if ( barBorder ) then
+ barBorder:Show();
+ end
+ end
+ end
+ if ( self.showCastbar ) then
+ self:Show();
+ end
+ elseif ( event == "UNIT_SPELLCAST_CHANNEL_UPDATE" ) then
+ if ( self:IsShown() ) then
+ local name, nameSubtext, text, texture, startTime, endTime, isTradeSkill = UnitChannelInfo(unit);
+ if ( not name or (not self.showTradeSkills and isTradeSkill)) then
+ -- if there is no name, there is no bar
+ self:Hide();
+ return;
+ end
+ self.value = ((endTime / 1000) - GetTime());
+ self.maxValue = (endTime - startTime) / 1000;
+ self:SetMinMaxValues(0, self.maxValue);
+ self:SetValue(self.value);
+ end
+ elseif ( self.showShield and event == "UNIT_SPELLCAST_INTERRUPTIBLE" ) then
+ if ( barBorderShield ) then
+ barBorderShield:Hide();
+ if ( barBorder ) then
+ barBorder:Show();
+ end
+ end
+ elseif ( self.showShield and event == "UNIT_SPELLCAST_NOT_INTERRUPTIBLE" ) then
+ if ( barBorderShield ) then
+ barBorderShield:Show();
+ if ( barBorder ) then
+ barBorder:Hide();
+ end
+ end
+ end
+end
+
+function CastingBarFrame_OnUpdate (self, elapsed)
+ local barSpark = _G[self:GetName().."Spark"];
+ local barFlash = _G[self:GetName().."Flash"];
+
+ if ( self.casting ) then
+ self.value = self.value + elapsed;
+ if ( self.value >= self.maxValue ) then
+ self:SetValue(self.maxValue);
+ CastingBarFrame_FinishSpell(self, barSpark, barFlash);
+ return;
+ end
+ self:SetValue(self.value);
+ if ( barFlash ) then
+ barFlash:Hide();
+ end
+ if ( barSpark ) then
+ local sparkPosition = (self.value / self.maxValue) * self:GetWidth();
+ barSpark:SetPoint("CENTER", self, "LEFT", sparkPosition, 2);
+ end
+ elseif ( self.channeling ) then
+ self.value = self.value - elapsed;
+ if ( self.value <= 0 ) then
+ CastingBarFrame_FinishSpell(self, barSpark, barFlash);
+ return;
+ end
+ self:SetValue(self.value);
+ if ( barFlash ) then
+ barFlash:Hide();
+ end
+ elseif ( GetTime() < self.holdTime ) then
+ return;
+ elseif ( self.flash ) then
+ local alpha = 0;
+ if ( barFlash ) then
+ alpha = barFlash:GetAlpha() + CASTING_BAR_FLASH_STEP;
+ end
+ if ( alpha < 1 ) then
+ if ( barFlash ) then
+ barFlash:SetAlpha(alpha);
+ end
+ else
+ if ( barFlash ) then
+ barFlash:SetAlpha(1.0);
+ end
+ self.flash = nil;
+ end
+ elseif ( self.fadeOut ) then
+ local alpha = self:GetAlpha() - CASTING_BAR_ALPHA_STEP;
+ if ( alpha > 0 ) then
+ self:SetAlpha(alpha);
+ else
+ self.fadeOut = nil;
+ self:Hide();
+ end
+ end
+end
+
+function CastingBarFrame_FinishSpell (self, barSpark, barFlash)
+ self:SetStatusBarColor(0.0, 1.0, 0.0);
+ if ( barSpark ) then
+ barSpark:Hide();
+ end
+ if ( barFlash ) then
+ barFlash:SetAlpha(0.0);
+ barFlash:Show();
+ end
+ self.flash = 1;
+ self.fadeOut = 1;
+ self.casting = nil;
+ self.channeling = nil;
+end
+
+function CastingBarFrame_UpdateIsShown(self)
+ if ( self.casting and self.showCastbar ) then
+ CastingBarFrame_OnEvent(self, "PLAYER_ENTERING_WORLD")
+ else
+ self:Hide();
+ end
+end
diff --git a/reference/FrameXML/CastingBarFrame.xml b/reference/FrameXML/CastingBarFrame.xml
new file mode 100644
index 0000000..2420568
--- /dev/null
+++ b/reference/FrameXML/CastingBarFrame.xml
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CastingBarFrame_OnLoad(self, "player", true, false);
+
+
+ CastingBarFrame_OnEvent(self, event, ...);
+
+
+ CastingBarFrame_OnUpdate(self, elapsed);
+
+
+ CastingBarFrame_OnShow(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/ChannelFrame.lua b/reference/FrameXML/ChannelFrame.lua
new file mode 100644
index 0000000..0028ea0
--- /dev/null
+++ b/reference/FrameXML/ChannelFrame.lua
@@ -0,0 +1,1262 @@
+MAX_CHANNEL_BUTTONS = 20;
+MAX_DISPLAY_CHANNEL_BUTTONS = 16;
+MAX_CHANNEL_MEMBER_BUTTONS = 22;
+CHANNEL_ROSTER_HEIGHT = 15;
+CHANNEL_FRAME_SCROLLBAR_OFFSET = 25;
+CHANNEL_TITLE_WIDTH = 135;
+CHANNEL_TITLE_OFFSET= 10;
+CHANNEL_HEADER_OFFSET = 5;
+CHAT_CHANNEL_TABBING = {};
+CHAT_CHANNEL_TABBING[1] = "ChannelFrameDaughterFrameChannelPassword";
+CHAT_CHANNEL_TABBING[2] = "ChannelFrameDaughterFrameChannelName";
+
+local rosterFrame;
+
+function ChannelFrame_OnLoad(self)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("PARTY_LEADER_CHANGED");
+ self:RegisterEvent("RAID_ROSTER_UPDATE");
+ self:RegisterEvent("CHANNEL_UI_UPDATE");
+ self:RegisterEvent("MUTELIST_UPDATE");
+ self:RegisterEvent("IGNORELIST_UPDATE");
+ self:RegisterEvent("CHANNEL_FLAGS_UPDATED");
+ self:RegisterEvent("CHANNEL_VOICE_UPDATE");
+ self:RegisterEvent("CHANNEL_COUNT_UPDATE");
+ self:RegisterEvent("CHANNEL_ROSTER_UPDATE");
+ FauxScrollFrame_SetOffset(ChannelRosterScrollFrame, 0);
+ ChannelFrame_Update();
+end
+
+function ChannelFrame_OnEvent(self, event, ...)
+ local arg1, arg2, arg3 = ...;
+ if ( event == "PLAYER_ENTERING_WORLD" or event == "CHANNEL_UI_UPDATE" or event == "PARTY_MEMBERS_CHANGED" or event == "PARTY_LEADER_CHANGED" or event == "RAID_ROSTER_UPDATE" ) then
+ ChannelFrame_Update();
+ elseif ( event == "CHANNEL_FLAGS_UPDATED" ) then
+ if ( arg1 == ChannelListDropDown.clicked ) then
+ ChannelList_ShowDropdown(arg1);
+ end
+ elseif ( event == "CHANNEL_VOICE_UPDATE" ) then
+ ChannelList_UpdateVoice(arg1, arg2, arg3);
+ elseif ( event == "CHANNEL_COUNT_UPDATE" ) then
+ ChannelList_CountUpdate(arg1, arg2);
+ elseif ( event == "CHANNEL_ROSTER_UPDATE" ) then
+ ChannelRoster_Update(arg1);
+ elseif ( event == "MUTELIST_UPDATE" or event == "IGNORELIST_UPDATE" ) then
+ ChannelRoster_Update(GetSelectedDisplayChannel());
+ end
+end
+
+function ChannelFrame_Update()
+ local id = GetSelectedDisplayChannel();
+ if ( not id ) then
+ id = GetActiveVoiceChannel();
+ end
+ ChannelList_Update();
+ ChannelList_UpdateHighlight(id);
+ ChannelRoster_Update(id);
+ --ChannelFrame_UpdateJoin();
+end
+
+function ChannelFrame_OnUpdate(self, elapsed)
+ if ( not ChannelFrame.updating ) then
+ return;
+ else
+ ChannelRoster_Update(ChannelFrame.updating);
+ ChannelFrame.updating = nil;
+ end
+end
+
+function ChannelFrame_UpdateJoin()
+ local id = GetSelectedDisplayChannel();
+ if ( id ) then
+ local name, header, collapsed, channelNumber, count, active, category, voiceEnabled, voiceActive = GetChannelDisplayInfo(id);
+ if ( category == "CHANNEL_CATEGORY_WORLD" and not active ) then
+ ChannelFrameJoinButton:Enable();
+ end
+ else
+ ChannelFrameJoinButton:Disable();
+ end
+end
+
+function ChannelFrame_New_OnClick()
+ if ( ChannelFrameDaughterFrame:IsShown() ) then
+ ChannelFrameDaughterFrame:Hide();
+ else
+ ChannelFrameDaughterFrameChannelNameLabel:SetText(CHANNEL_CHANNEL_NAME);
+ ChannelFrameDaughterFrameChannelPasswordLabel:SetText(PASSWORD);
+ ChannelFrameDaughterFrameChannelPasswordOptional:Show();
+ ChannelFrameDaughterFrameName:SetText(CHANNEL_NEW_CHANNEL);
+ --ChannelFrameDaughterFrameVoiceChat:SetChecked(1);
+ --ChannelFrameDaughterFrameVoiceChat:Show();
+ ChannelFrameDaughterFrame:Show();
+ PlaySound("UChatScrollButton");
+ end
+end
+
+function ChannelFrame_Join_OnClick()
+ if ( ChannelFrameDaughterFrame:IsShown() ) then
+ ChannelFrameDaughterFrame:Hide();
+ else
+ local selected = GetSelectedDisplayChannel();
+ local button;
+ if ( selected ) then
+ button = _G["ChannelButton"..selected];
+ end
+ if ( button and button.global ) then
+ JoinPermanentChannel(button.channel, nil, nil, 1);
+ else
+ ChannelFrameDaughterFrameChannelNameLabel:SetText(CHANNEL_CHANNEL_NAME);
+ ChannelFrameDaughterFrameChannelPasswordLabel:SetText(PASSWORD);
+ ChannelFrameDaughterFrameChannelPasswordOptional:Show();
+ ChannelFrameDaughterFrameName:SetText(CHANNEL_JOIN_CHANNEL);
+ --ChannelFrameDaughterFrameVoiceChat:Hide();
+ ChannelFrameDaughterFrame:Show();
+ end
+ end
+end
+
+function ChannelFrameDaughterFrame_Okay()
+ local name = ChannelFrameDaughterFrameChannelName:GetText();
+ local password = ChannelFrameDaughterFrameChannelPassword:GetText();
+ local zoneChannel, channelName = JoinPermanentChannel(name, password, DEFAULT_CHAT_FRAME:GetID(), 1);
+ if ( not zoneChannel ) then
+ local info = ChatTypeInfo["CHANNEL"];
+ DEFAULT_CHAT_FRAME:AddMessage(CHAT_INVALID_NAME_NOTICE, info.r, info.g, info.b, info.id);
+ ChannelFrameDaughterFrame:Hide();
+ return;
+ end
+ if ( channelName ) then
+ name = channelName;
+ end
+ local i = 1;
+ while ( DEFAULT_CHAT_FRAME.channelList[i] ) do
+ i = i + 1;
+ end
+ DEFAULT_CHAT_FRAME.channelList[i] = name;
+ DEFAULT_CHAT_FRAME.zoneChannelList[i] = zoneChannel;
+
+ -- Clear Out Values
+ ChannelFrameDaughterFrame:Hide();
+end
+
+function ChannelFrameDaughterFrame_Cancel(self)
+ self:GetParent():Hide();
+end
+
+function ChannelFrameDaughterFrame_OnHide()
+ ChannelFrameDaughterFrameChannelName:SetText("");
+ ChannelFrameDaughterFrameChannelPassword:SetText("");
+ PlaySound("UChatScrollButton");
+end
+
+--[ Channel List Functions ]--
+function ChannelList_Update()
+ -- Scroll Bar Handling --
+ local frameHeight = ChannelListScrollChildFrame:GetHeight();
+ local button, buttonName, buttonLines, buttonCollapsed, buttonSpeaker, hideVoice;
+ local name, header, collapsed, channelNumber, active, count, category, voiceEnabled, voiceActive;
+ local channelCount = GetNumDisplayChannels();
+ for i=1, MAX_CHANNEL_BUTTONS, 1 do
+ button = _G["ChannelButton"..i];
+ buttonName = _G["ChannelButton"..i.."Text"];
+ buttonLines = _G["ChannelButton"..i.."NormalTexture"];
+ buttonCollapsed = _G["ChannelButton"..i.."Collapsed"];
+ buttonSpeaker = _G["ChannelButton"..i.."SpeakerFrame"];
+ if ( i <= channelCount) then
+ name, header, collapsed, channelNumber, count, active, category, voiceEnabled, voiceActive = GetChannelDisplayInfo(i);
+ if ( IsVoiceChatEnabled() ) then
+ ChannelList_UpdateVoice(i, voiceEnabled, voiceActive);
+ else
+ ChannelList_UpdateVoice(i, nil, nil);
+ end
+ button.header = header;
+ button.collapsed = collapsed;
+ if ( header ) then
+ if ( button.channel ) then
+ button.channel = nil;
+ button.active = nil;
+ local point, rTo, rPoint, x, y = buttonName:GetPoint();
+ buttonName:SetPoint(point, rTo, rPoint, CHANNEL_HEADER_OFFSET, y);
+ buttonName:SetWidth(CHANNEL_TITLE_WIDTH + buttonSpeaker:GetWidth());
+ end
+
+ -- Set the collapsed Status
+ if ( collapsed ) then
+ buttonCollapsed:SetText("+");
+ else
+ buttonCollapsed:SetText("-");
+ end
+ -- Hide collapsed Status if there are no sub channels
+ if ( count ) then
+ buttonCollapsed:Show();
+ button:Enable();
+ else
+ buttonCollapsed:Hide();
+ button:Disable();
+ end
+ buttonLines:SetAlpha(1.0);
+ buttonName:SetText(NORMAL_FONT_COLOR_CODE..name..FONT_COLOR_CODE_CLOSE);
+ else
+ local point, rTo, rPoint, x, y = buttonName:GetPoint();
+ if ( not button.channel ) then
+ buttonName:SetPoint(point, rTo, rPoint, CHANNEL_TITLE_OFFSET, y);
+ buttonName:SetWidth(CHANNEL_TITLE_WIDTH - buttonSpeaker:GetWidth());
+ end
+ if ( not channelNumber ) then
+ channelNumber = "";
+ else
+ channelNumber = channelNumber..". ";
+ end
+ if ( active ) then
+ if ( count and category == "CHANNEL_CATEGORY_GROUP" ) then
+ buttonName:SetText(HIGHLIGHT_FONT_COLOR_CODE..channelNumber..name.." ("..count..")"..FONT_COLOR_CODE_CLOSE);
+ else
+ buttonName:SetText(HIGHLIGHT_FONT_COLOR_CODE..channelNumber..name..FONT_COLOR_CODE_CLOSE);
+ end
+ button:Enable();
+ else
+ buttonName:SetText(GRAY_FONT_COLOR_CODE..channelNumber..name..FONT_COLOR_CODE_CLOSE);
+ button:Disable();
+ end
+ if ( category == "CHANNEL_CATEGORY_WORLD" ) then
+ button.global = 1;
+ button.group = nil;
+ button.custom = nil;
+ elseif ( category == "CHANNEL_CATEGORY_GROUP" ) then
+ button.group = 1;
+ button.global = nil;
+ button.custom = nil;
+ elseif ( category == "CHANNEL_CATEGORY_CUSTOM" ) then
+ button.custom = 1;
+ button.group = nil;
+ button.global = nil;
+ else
+ button.custom = nil;
+ button.group = nil;
+ button.global = nil;
+ end
+ buttonCollapsed:Hide();
+ button.channel = name;
+ button.active = active;
+ buttonLines:SetAlpha(0.5);
+ channelNumber = nil;
+ end
+ button:Show();
+ else
+-- button.channel = nil;
+ button:Hide();
+ button.voiceEnabled = nil;
+ button.voiceActive = nil;
+ -- Scroll Bar Handling --
+ frameHeight = frameHeight - button:GetHeight();
+ end
+ end
+
+ -- Scroll Bar Handling --
+ ChannelListScrollChildFrame:SetHeight(frameHeight);
+ if ((ChannelListScrollFrameScrollBarScrollUpButton:IsEnabled() == 0) and (ChannelListScrollFrameScrollBarScrollDownButton:IsEnabled() == 0) ) then
+ ChannelListScrollFrame.scrolling = nil;
+ else
+ ChannelListScrollFrame.scrolling = 1;
+ end
+ ChannelList_SetScroll();
+end
+
+function ChannelList_CountUpdate(id, count)
+ local button = _G["ChannelButton"..id];
+ local name, header, collapsed, channelNumber, count, active, category, voiceEnabled, voiceActive = GetChannelDisplayInfo(id);
+ if ( category == "CHANNEL_CATEGORY_GROUP" ) then
+ if ( count ) then
+ button:SetText(HIGHLIGHT_FONT_COLOR_CODE..channelNumber..". "..name.." ("..count..")"..FONT_COLOR_CODE_CLOSE);
+ end
+ end
+ if ( id == GetSelectedDisplayChannel() ) then
+ ChannelRoster_Update(id);
+ end
+end
+
+function ChannelList_SetScroll()
+ local buttonWidth = 130;
+ if ( not ChannelListScrollFrame.scrolling ) then
+ ChannelMemberButton1:SetPoint("TOPLEFT", ChannelFrame, "TOPLEFT", 186, -75);
+ ChannelRoster:SetPoint("TOPLEFT", ChannelFrame, "TOP", 121, -79);
+ ChannelListScrollFrameScrollBar:Hide();
+ ChannelListScrollFrameTop:Hide();
+ ChannelListScrollFrameBottom:Hide();
+ buttonWidth = buttonWidth + 10;
+ else
+ ChannelMemberButton1:SetPoint("TOPLEFT", ChannelFrame, "TOPLEFT", 206, -75);
+ ChannelRoster:SetPoint("TOPLEFT", ChannelFrame, "TOP", 97, -77);
+ ChannelListScrollFrameScrollBar:Show();
+ ChannelListScrollFrameTop:Show();
+ ChannelListScrollFrameBottom:Show();
+ buttonWidth = buttonWidth - 10;
+ end
+end
+
+function ChannelRoster_SetScroll()
+ local buttonWidth = 145;
+ if ( not ChannelRosterScrollFrame.scrolling ) then
+ ChannelRosterScrollFrameScrollBar:Hide();
+ ChannelRosterScrollFrameTop:Hide();
+ ChannelRosterScrollFrameBottom:Hide();
+ buttonWidth = buttonWidth + 10;
+ else
+ ChannelRosterScrollFrameScrollBar:Show();
+ ChannelRosterScrollFrameTop:Show();
+ ChannelRosterScrollFrameBottom:Show();
+ buttonWidth = buttonWidth - 10;
+ end
+
+ for i=1, MAX_CHANNEL_MEMBER_BUTTONS do
+ _G["ChannelMemberButton"..i]:SetWidth(buttonWidth);
+ end
+end
+function ChannelList_UpdateVoice(id, enabled, active)
+ local speaker = _G["ChannelButton"..id.."SpeakerFrame"];
+ local speakerIcon = _G["ChannelButton"..id.."SpeakerFrameOn"];
+ local speakerFlash = _G["ChannelButton"..id.."SpeakerFrameFlash"];
+ local button = _G["ChannelButton" .. id];
+
+ if ( enabled ) then
+ button.voiceEnabled = true;
+ if ( active ) then
+ button.voiceActive = true;
+ ChannelFrame_Desaturate(speakerIcon, nil, 1, 1, 1, 0.75);
+ ChannelFrame_Desaturate(speakerFlash, nil, 1, 1, 1, 0.75);
+ else
+ button.voiceActive = nil;
+ ChannelFrame_Desaturate(speakerIcon, 1, nil, nil, nil, 0.5);
+ ChannelFrame_Desaturate(speakerFlash, 1, nil, nil, nil, 0.5);
+ end
+ speaker:Show()
+ speaker:SetFrameLevel(speaker:GetFrameLevel()+5);
+ speakerFlash:Show();
+ else
+ button.voiceEnabled = nil;
+ button.voiceActive = nil;
+ speaker:Hide();
+ end
+end
+
+function ChannelList_OnClick(self, button)
+ local id = self:GetID();
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+ ChannelListDropDown.clicked = nil;
+
+ if ( button == "LeftButton" ) then
+ HideDropDownMenu(1);
+ if ( self.header ) then
+ if ( self.collapsed ) then
+ ExpandChannelHeader(id);
+ else
+ CollapseChannelHeader(id);
+ end
+ else
+ ChannelList_UpdateHighlight(id);
+ if ( self.active ) then
+ ChannelFrame.updating = id;
+ SetSelectedDisplayChannel(id);
+ ChannelRoster_Update(id);
+ else
+ ChannelRoster_Update(0);
+ end
+ end
+ elseif ( button == "RightButton" ) then
+ if ( self.channel ) then
+ FauxScrollFrame_SetOffset(ChannelRosterScrollFrame, 0);
+ if ( self.global ) then
+ ChannelList_UpdateHighlight(id);
+ ChannelList_ShowDropdown(id);
+ end
+ if ( self.active ) then
+ ChannelFrame.updating = id;
+ GetNumChannelMembers(id);
+ ChannelList_UpdateHighlight(id);
+ ChannelListDropDown.clicked = id;
+ ChannelList_ShowDropdown(id);
+ end
+ end
+ end
+end
+
+function ChannelList_UpdateHighlight(id)
+ local button;
+ local channelCount = GetNumDisplayChannels();
+ for i=1, MAX_CHANNEL_BUTTONS, 1 do
+ button = _G["ChannelButton"..i];
+ if ( i <= channelCount ) then
+ if ( i == id ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+ end
+ end
+end
+
+local function ChannelListDropDown_StripSelf (self, func1, arg1)
+ func1(arg1);
+end
+
+--[ DropDown Functions ]--
+function ChannelListDropDown_Initialize()
+ local count = 0;
+ local info;
+ if ( not ChannelListDropDown.global ) then
+ if ( IsVoiceChatEnabled() ) then
+ -- Enable Voice Chat option if Voice Chat is enabled.
+ if ( not ChannelListDropDown.voice and IsDisplayChannelOwner() ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CHAT_VOICE_ON;
+ info.notCheckable = 1;
+ info.func = ChannelListDropDown_StripSelf
+ info.arg1 = DisplayChannelVoiceOn;
+ info.arg2 = ChannelListDropDown.id;
+ UIDropDownMenu_AddButton(info);
+ count = count + 1;
+ end
+ -- Voice Chat option if Voice Chat is enabled.
+ if ( ChannelListDropDown.voice and not ChannelListDropDown.voiceActive ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CHAT_VOICE;
+ info.notCheckable = 1;
+ info.func = ChannelListDropDown_StripSelf
+ info.arg1 = SetActiveVoiceChannel;
+ info.arg2 = ChannelListDropDown.id;
+ UIDropDownMenu_AddButton(info);
+ count = count + 1;
+
+ --[[ Disable Voice Chat option if Voice Chat is enabled and not a group channel.
+ if ( not ChannelListDropDown.group and IsDisplayChannelOwner() ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CHAT_VOICE_OFF;
+ info.notCheckable = 1;
+ info.func = SetActiveVoiceChannel;
+ info.arg1 = ChannelListDropDown.id;
+ UIDropDownMenu_AddButton(info);
+ count = count + 1;
+ end]]--
+ end
+ end
+
+ -- SET PASSWORD if it is a custom Channel and is owner
+ if ( ChannelListDropDown.custom and IsDisplayChannelOwner() ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CHAT_PASSWORD;
+ info.notCheckable = 1;
+ info.func = ChannelListDropDown_StripSelf
+ info.arg1 = ChannelListDropDown_SetPassword;
+ info.arg2 = ChannelListDropDown.channelName;
+ UIDropDownMenu_AddButton(info);
+ count = count + 1;
+ end
+
+ -- INVITE if it is a custom Channel and is owner
+ if ( ChannelListDropDown.custom and IsDisplayChannelModerator() ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = PARTY_INVITE;
+ info.notCheckable = 1;
+ info.func = ChannelListDropDown_StripSelf
+ info.arg1 = ChannelListDropDown_Invite;
+ info.arg2 = ChannelListDropDown.channelName;
+ UIDropDownMenu_AddButton(info);
+ count = count + 1;
+ end
+
+ end
+ -- JOIN if it is a Global Channel
+ if ( ChannelListDropDown.global and not ChannelListDropDown.active ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CHAT_JOIN;
+ info.notCheckable = 1;
+ info.func = ChannelListDropDown_StripSelf
+ info.arg1 = JoinPermanentChannel;
+ info.arg2 = ChannelListDropDown.channelName;
+ UIDropDownMenu_AddButton(info);
+ count = count + 1;
+ end
+
+ -- LEAVE Channel if not a group channel
+ if ( not ChannelListDropDown.group and ChannelListDropDown.active ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CHAT_LEAVE;
+ info.notCheckable = 1;
+ info.func = ChannelListDropDown_StripSelf
+ info.arg1 = LeaveChannelByName;
+ info.arg2 = ChannelListDropDown.channelName;
+ UIDropDownMenu_AddButton(info);
+ count = count + 1;
+ end
+
+ if ( count > 0 ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CANCEL;
+ info.notCheckable = 1;
+ info.func = ChannelListDropDown_HideDropDown;
+ UIDropDownMenu_AddButton(info);
+ end
+
+end
+
+function ChannelListDropDown_HideDropDown(self)
+ self:GetParent():Hide();
+end
+
+function ChannelListDropDown_SetPassword(name)
+ local dialog = StaticPopup_Show("CHANNEL_PASSWORD", name);
+ if ( dialog ) then
+ dialog.data = name;
+ end
+end
+
+function ChannelListDropDown_Invite(name)
+ local dialog = StaticPopup_Show("CHANNEL_INVITE", name);
+ if ( dialog ) then
+ dialog.data = name;
+ end
+end
+
+function ChannelList_ShowDropdown(id)
+ local name, header, collapsed, channelNumber, count, active, category, voice, voiceActive;
+ name, header, collapsed, channelNumber, count, active, category, voice, voiceActive = GetChannelDisplayInfo(id);
+ HideDropDownMenu(1);
+ local button = _G["ChannelButton"..id];
+ ChannelListDropDown.global = button.global;
+ ChannelListDropDown.group = button.group;
+ ChannelListDropDown.custom = button.custom;
+ ChannelListDropDown.initialize = ChannelListDropDown_Initialize;
+ ChannelListDropDown.displayMode = "MENU";
+ ChannelListDropDown.id = id;
+ ChannelListDropDown.voice = voice;
+ ChannelListDropDown.voiceActive = voiceActive;
+ ChannelListDropDown.active = active;
+ ChannelListDropDown.channelName = name;
+ ToggleDropDownMenu(1, nil, ChannelListDropDown, "cursor");
+end
+
+function ChannelListButton_OnDragStart (button)
+ local name, index, spoof = ChannelPulloutRoster_GetActiveSession()
+ if ( ( button and button.channel and button.voiceEnabled ) and ( not spoof and name == button.channel ) ) then
+ CHANNELPULLOUT_OPTIONS.displayActive = true;
+ elseif ( button.channel and button.voiceEnabled ) then
+ CHANNELPULLOUT_OPTIONS.displayActive = nil;
+ CHANNELPULLOUT_OPTIONS.name = button.channel;
+ CHANNELPULLOUT_OPTIONS.session = ChannelPulloutRoster_GetSessionIDByName(button.channel);
+ else
+ return;
+ end
+
+ if ( not ChannelPullout:IsShown() ) then
+ ChannelPullout_ToggleDisplay();
+ end
+
+ ChannelPulloutRoster_OnEvent(rosterFrame or ChannelPulloutRoster);
+
+ ChannelPulloutTab:StartMoving();
+ ChannelPulloutTab:ClearAllPoints();
+ local x, y = GetCursorPosition();
+ x, y = x / UIParent:GetScale(), y / UIParent:GetScale();
+ ChannelPulloutTab:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x, y)
+ ChannelPulloutTab.dragging = true;
+end
+
+function ChannelListButton_OnDragStop (button)
+ ChannelPulloutTab:StopMovingOrSizing();
+ ChannelPulloutTab.dragging = nil;
+end
+
+--[ Channel Roster Functions ]--
+function ChannelRoster_Update(id)
+ if ( (not id) or (type(id) ~= "number") ) then
+ id = GetSelectedDisplayChannel();
+ end
+ if ( not id ) then
+ id = 0;
+ end
+ local channel, header, collapsed, channelNumber, count, active, category = GetChannelDisplayInfo(id);
+ local button, buttonName, buttonRank, buttonRankTexture, buttonVoice, buttonVoiceMuted, newWidth, nameWidth;
+
+ if ( count ) then
+ if ( category == "CHANNEL_CATEGORY_GROUP" ) then
+ ChannelRosterChannelCount:SetText("("..count..")");
+ else
+ ChannelRosterChannelCount:SetText("");
+ end
+ -- ScrollFrame stuff
+ if ( count > MAX_CHANNEL_MEMBER_BUTTONS ) then
+ ChannelRosterScrollFrame.scrolling = 1;
+ else
+ ChannelRosterScrollFrame.scrolling = nil;
+ end
+ if ( channel ) then
+ ChannelRosterHiddenText:SetText(channel);
+ ChannelRosterChannelName:SetText(channel);
+ --Set the width of the title bar.
+ nameWidth = ChannelRosterHiddenText:GetWidth();
+ if ( ChannelListScrollFrame.scrolling ) then
+ newWidth = CHANNEL_TITLE_WIDTH - CHANNEL_FRAME_SCROLLBAR_OFFSET;
+ else
+ newWidth = CHANNEL_TITLE_WIDTH;
+ end
+ if ( nameWidth > newWidth) then
+ nameWidth = newWidth;
+ end
+
+ ChannelRosterChannelName:SetHeight(13);
+ ChannelRosterChannelName:SetWidth(nameWidth);
+ end
+ else
+ ChannelRosterScrollFrame.scrolling = nil;
+ ChannelRosterChannelName:SetText("");
+ ChannelRosterChannelCount:SetText("");
+ count = 0;
+ end
+ local rosterOffset = FauxScrollFrame_GetOffset(ChannelRosterScrollFrame);
+ local name, owner, moderator, muted, active, enabled;
+ local rosterIndex;
+ for i=1, MAX_CHANNEL_MEMBER_BUTTONS do
+ rosterIndex = rosterOffset + i;
+ button = _G["ChannelMemberButton"..i];
+ if ( rosterIndex <= count ) then
+ buttonName = _G["ChannelMemberButton"..i.."Name"];
+ buttonRank = _G["ChannelMemberButton"..i.."Rank"];
+ buttonRankTexture = _G["ChannelMemberButton"..i.."RankTexture"];
+ buttonVoice = _G["ChannelMemberButton"..i.."SpeakerFrame"];
+ buttonVoiceMuted = _G["ChannelMemberButton"..i.."SpeakerFrameMuted"];
+ name, owner, moderator, muted, active, enabled = GetChannelRosterInfo(id, rosterIndex);
+ buttonName:SetText(name);
+ button.name = name;
+ if ( owner or moderator ) then
+ -- Sets the Leader/Assistant Icon
+ if ( owner ) then
+ buttonRankTexture:SetTexture("Interface\\GroupFrame\\UI-Group-LeaderIcon");
+ elseif ( moderator ) then
+ buttonRankTexture:SetTexture("Interface\\GroupFrame\\UI-Group-AssistantIcon");
+ end
+ buttonRank:Show();
+ else
+ buttonRank:Hide();
+ end
+ if ( IsVoiceChatEnabled() ) then
+ ChannelRoster_UpdateVoice(i, enabled, active, muted);
+ else
+ ChannelRoster_UpdateVoice(i, nil, nil, nil);
+ end
+
+ button:SetID(rosterIndex);
+ button:Show();
+ else
+ button:Hide();
+ end
+ end
+ ChannelRoster_SetScroll();
+ FauxScrollFrame_Update(ChannelRosterScrollFrame, count, MAX_CHANNEL_MEMBER_BUTTONS, CHANNEL_ROSTER_HEIGHT );
+end
+
+function ChannelRoster_UpdateVoice(id, enabled, active, muted)
+ local speaker = _G["ChannelMemberButton"..id.."SpeakerFrame"];
+ local speakerIcon = _G["ChannelMemberButton"..id.."SpeakerFrameOn"];
+ local speakerFlash = _G["ChannelMemberButton"..id.."SpeakerFrameFlash"];
+ local speakerMuted = _G["ChannelMemberButton"..id.."SpeakerFrameMuted"];
+
+ if ( enabled ) then
+ if ( active ) then
+ ChannelFrame_Desaturate(speakerIcon, nil, 1, 1, 1, 0.75);
+ ChannelFrame_Desaturate(speakerFlash, nil, 1, 1, 1, 0.75);
+ else
+ ChannelFrame_Desaturate(speakerIcon, 1, nil, nil, nil, 0.25);
+ ChannelFrame_Desaturate(speakerFlash, 1, nil, nil, nil, 0.25);
+ end
+ if ( muted ) then
+ speakerMuted:Show();
+ else
+ speakerMuted:Hide();
+ end
+ speaker:Show()
+ speakerFlash:Show();
+ else
+ speaker:Hide();
+ end
+end
+
+function ChannelRoster_OnClick(self, button)
+ if ( button == "RightButton" ) then
+ ChannelRosterFrame_ShowDropdown(self:GetID());
+ end
+end
+
+--[ DropDown Functions ]--
+function ChannelRosterDropDown_Initialize()
+ UnitPopup_ShowMenu(UIDROPDOWNMENU_OPEN_MENU, "CHAT_ROSTER", nil, ChannelRosterDropDown.name);
+end
+
+function ChannelRosterFrame_ShowDropdown(id)
+ HideDropDownMenu(1);
+ local channelID = GetSelectedDisplayChannel();
+ local channelName, header, collapsed, channelNumber, count, active, category;
+ local name, owner, moderator, muted, voiceEnabled;
+ channelName, header, collapsed, channelNumber, count, active, category = GetChannelDisplayInfo(channelID);
+ name, owner, moderator, muted, voiceEnabled = GetChannelRosterInfo(channelID, id);
+ ChannelRosterDropDown.initialize = ChannelRosterDropDown_Initialize;
+ ChannelRosterDropDown.displayMode = "MENU";
+ ChannelRosterDropDown.name = name;
+ ChannelRosterDropDown.owner = owner;
+ ChannelRosterDropDown.moderator = moderator;
+ ChannelRosterDropDown.channelName = channelName;
+ ChannelRosterDropDown.category = category;
+ ToggleDropDownMenu(1, nil, ChannelRosterDropDown, "cursor");
+end
+
+--[ Utility Functions ]--
+function ChannelFrame_Desaturate(texture, desaturate, r, g, b, a)
+ local shaderSupported = texture:SetDesaturated(desaturate);
+ if ( not desaturate ) then
+ r = 1.0;
+ g = 1.0;
+ b = 1.0;
+ elseif ( not r and not shaderSupported ) then
+ r = 0.5;
+ g = 0.5;
+ b = 0.5;
+ end
+ texture:SetVertexColor(r, g, b);
+ if ( a ) then
+ texture:SetAlpha(a);
+ end
+end
+
+--[[ Functions for the Channel Pullout window ]]--
+
+CHANNELPULLOUT_TAB_SHOW_DELAY = 0.2;
+CHANNELPULLOUT_TAB_FADE_TIME = 0.15;
+DEFAULT_CHANNELPULLOUT_TAB_ALPHA = 0.75;
+DEFAULT_CHANNELPULLOUT_ALPHA = 1;
+
+CHANNELPULLOUT_OPTIONS = {};
+CHANNELPULLOUT_MINSIZE = 5;
+CHANNELPULLOUT_MAXSIZE = 25;
+CHANNELPULLOUT_ROSTERFRAME_OFFSETY = 4;
+CHANNELPULLOUT_ROSTERPARENT_YPADDING = 14;
+
+CHANNELPULLOUT_FADEFRAMES = { "ChannelPulloutBackground", "ChannelPulloutCloseButton", "ChannelPulloutRosterScroll" };
+
+function ChannelPullout_OnLoad (self)
+ self:RegisterEvent("VARIABLES_LOADED");
+ self:SetScript("OnEvent", ChannelPullout_OnEvent);
+ RegisterForSave("CHANNELPULLOUT_OPTIONS");
+end
+
+function ChannelPullout_OnEvent (self)
+ if ( CHANNELPULLOUT_OPTIONS.display ) then
+ self:Show();
+ end
+end
+
+function ChannelPullout_OnUpdate (self, elapsed)
+ local ChannelPulloutTab = ChannelPulloutTab;
+ if ( self:IsMouseOver(45, -10, -5, 5) ) then
+ local xPos, yPos = GetCursorPosition();
+ -- If mouse is hovering don't show the tab until the elapsed time reaches the tab show delay
+ if ( self.hover ) then
+ if ( (self.oldX == xPos and self.oldy == yPos) ) then
+ self.hoverTime = self.hoverTime + elapsed;
+ else
+ self.hoverTime = 0;
+ self.oldX = xPos;
+ self.oldy = yPos;
+ end
+ if ( self.hoverTime > CHANNELPULLOUT_TAB_SHOW_DELAY or ChannelPulloutTab.dragging ) then
+ -- If the tab's alpha is less than the current default, then fade it in
+ if ( not self.hasBeenFaded and (ChannelPulloutTab.oldAlpha and ChannelPulloutTab.oldAlpha < DEFAULT_CHANNELPULLOUT_TAB_ALPHA) ) then
+ UIFrameFadeIn(ChannelPulloutTab, CHANNELPULLOUT_TAB_FADE_TIME, ChannelPulloutTab.oldAlpha, DEFAULT_CHANNELPULLOUT_TAB_ALPHA);
+ local frame;
+ for _, name in next, CHANNELPULLOUT_FADEFRAMES do
+ frame = _G[name];
+ if ( frame:IsShown() ) then
+ UIFrameFadeIn(frame, CHANNELPULLOUT_TAB_FADE_TIME, self.oldAlpha, DEFAULT_CHANNELPULLOUT_ALPHA);
+ end
+ end
+ -- Set the fact that the chatFrame has been faded so we don't try to fade it again
+ self.hasBeenFaded = 1;
+ end
+ end
+ else
+ -- Start hovering counter
+ self.hover = 1;
+ self.hoverTime = 0;
+ self.hasBeenFaded = nil;
+ CURSOR_OLD_X, CURSOR_OLD_Y = GetCursorPosition();
+ -- Remember the oldAlpha so we can return to it later
+ if ( not ChannelPulloutTab.oldAlpha ) then
+ ChannelPulloutTab.oldAlpha = ChannelPulloutTab:GetAlpha();
+ end
+
+ self.oldAlpha = ChannelPulloutBackground:GetAlpha();
+ end
+ else
+ -- If the tab's alpha was less than the current default, then fade it back out to the oldAlpha
+ if ( self.hasBeenFaded and ChannelPulloutTab.oldAlpha and ChannelPulloutTab.oldAlpha < DEFAULT_CHANNELPULLOUT_TAB_ALPHA ) then
+ UIFrameFadeOut(ChannelPulloutTab, CHANNELPULLOUT_TAB_FADE_TIME, DEFAULT_CHANNELPULLOUT_TAB_ALPHA, ChannelPulloutTab.oldAlpha);
+ local frame;
+ for _, name in next, CHANNELPULLOUT_FADEFRAMES do
+ frame = _G[name];
+ if ( frame:IsShown() ) then
+ UIFrameFadeOut(frame, CHANNELPULLOUT_TAB_FADE_TIME, DEFAULT_CHANNELPULLOUT_ALPHA, self.oldAlpha);
+ end
+ end
+ self.hover = nil;
+ self.hasBeenFaded = nil;
+ end
+ self.hoverTime = 0;
+ end
+end
+
+function ChannelPullout_ShowOpacity ()
+ OpacityFrame:ClearAllPoints();
+ OpacityFrame:SetPoint("TOPRIGHT", "ChannelPullout", "TOPLEFT", 0, 7);
+ OpacityFrame.opacityFunc = ChannelPullout_SetOpacity;
+ OpacityFrame.saveOpacityFunc = ChannelPullout_SaveOpacity;
+ OpacityFrame:Show();
+ OpacityFrameSlider:SetValue(CHANNELPULLOUT_OPTIONS.opacity or 0);
+end
+
+function ChannelPullout_SetOpacity(value)
+ local alpha = 1.0 - (value or OpacityFrameSlider:GetValue());
+ ChannelPulloutBackground:SetAlpha(alpha);
+ ChannelPulloutCloseButton:SetAlpha(alpha);
+end
+
+function ChannelPullout_SaveOpacity()
+ CHANNELPULLOUT_OPTIONS.opacity = OpacityFrameSlider:GetValue();
+ OpacityFrame.saveOpacityFunc = nil;
+end
+
+function ChannelPullout_ToggleDisplay ()
+ if ( ChannelPullout:IsShown() ) then
+ ChannelPullout:Hide();
+ ChannelPulloutTab:Hide();
+ CHANNELPULLOUT_OPTIONS.display = nil;
+ else
+ ChannelPullout:Show();
+ ChannelPulloutTab:Show();
+ CHANNELPULLOUT_OPTIONS.display = true;
+ end
+end
+
+function ChannelPulloutTab_OnClick (tab, button)
+ if ( button == "RightButton" ) then
+ ToggleDropDownMenu(1, nil, ChannelPulloutTabDropDown, tab:GetName(), 0, 0);
+ return;
+ end
+
+ CloseDropDownMenus();
+
+ if ( tab:GetButtonState() == "PUSHED" ) then
+ tab:StopMovingOrSizing();
+ elseif ( CHANNELPULLOUT_OPTIONS.locked ) then
+ return;
+ else
+ tab:StartMoving();
+ end
+
+ ValidateFramePosition(tab);
+end
+
+function ChannelPulloutTab_ReanchorLeft ()
+ -- Make sure that we're always anchoring the left side of the tab, otherwise resizing the tab moves the roster
+ local point = { ChannelPulloutTab:GetPoint() };
+ if ( string.match(point[1], "RIGHT") ) then
+ point[1] = string.gsub(point[1], "RIGHT", "LEFT");
+ point[4] = point[4] - ChannelPulloutTab:GetWidth();
+ ChannelPulloutTab:ClearAllPoints();
+ ChannelPulloutTab:SetPoint(unpack(point));
+ end
+end
+
+function ChannelPulloutTab_UpdateText (text)
+ ChannelPulloutTab_ReanchorLeft();
+ ChannelPulloutTabText:SetText(text or CHANNEL_ROSTER);
+ PanelTemplates_TabResize(ChannelPulloutTab, 0);
+end
+
+function ChannelPulloutTabDropDown_Initialize ()
+ local checked, name, index;
+ local info = UIDropDownMenu_CreateInfo();
+
+ if ( not rosterFrame ) then
+ return;
+ end
+
+ info.text = CHANNELS;
+ info.notCheckable = true;
+ info.isTitle = true;
+ UIDropDownMenu_AddButton(info, 1);
+
+ info = UIDropDownMenu_CreateInfo();
+
+ info.text = DISPLAY_ACTIVE_CHANNEL;
+ info.func = function ()
+ CHANNELPULLOUT_OPTIONS.displayActive = not CHANNELPULLOUT_OPTIONS.displayActive;
+ CHANNELPULLOUT_OPTIONS.name = nil;
+ CHANNELPULLOUT_OPTIONS.session = nil;
+ ChannelPulloutRoster_OnEvent(rosterFrame);
+ end
+ info.checked = CHANNELPULLOUT_OPTIONS.displayActive;
+ UIDropDownMenu_AddButton(info, 1);
+
+ for i = 1, GetNumVoiceSessions() do
+ name = GetVoiceSessionInfo(i);
+ info.text = name;
+ info.func = function (self)
+ CHANNELPULLOUT_OPTIONS.name = self.value;
+ CHANNELPULLOUT_OPTIONS.displayActive = nil;
+ ChannelPulloutRoster_OnEvent(rosterFrame);
+ end
+ info.checked = ( function () if ( ( not CHANNELPULLOUT_OPTIONS.displayActive ) and CHANNELPULLOUT_OPTIONS.name == name ) then return true end return false end )();
+ UIDropDownMenu_AddButton(info, 1);
+ end
+
+ info.checked = nil;
+ info.text = DISPLAY_OPTIONS;
+ info.notCheckable = true;
+ info.isTitle = true;
+ UIDropDownMenu_AddButton(info, 1);
+
+ info = UIDropDownMenu_CreateInfo();
+
+ info.text = LOCK_CHANNELPULLOUT_LABEL;
+ info.func = function() CHANNELPULLOUT_OPTIONS.locked = not CHANNELPULLOUT_OPTIONS.locked end;
+ info.checked = CHANNELPULLOUT_OPTIONS.locked
+ UIDropDownMenu_AddButton(info, 1);
+
+ info.text = CHANNELPULLOUT_OPACITY_LABEL;
+ info.func = ChannelPullout_ShowOpacity;
+ info.checked = nil;
+ UIDropDownMenu_AddButton(info, 1);
+end
+
+function ChannelPulloutRoster_OnLoad (self)
+ self:RegisterEvent("VARIABLES_LOADED")
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("VOICE_SESSIONS_UPDATE");
+ self:RegisterEvent("CHANNEL_ROSTER_UPDATE");
+ self:RegisterEvent("VOICE_CHANNEL_STATUS_UPDATE");
+ self:SetScript("OnEvent", ChannelPulloutRoster_OnEvent);
+ self.members = {};
+ self.scroll = _G[self:GetName() .. "Scroll"];
+ if ( self.scroll ) then
+ self.upBtn = _G[self.scroll:GetName() .. "UpBtn"];
+ self.downBtn = _G[self.scroll:GetName() .. "DownBtn"];
+ self.topBtn = _G[self.scroll:GetName() .. "TopBtn"];
+ self.bottomBtn = _G[self.scroll:GetName() .. "BottomBtn"];
+ end
+end
+
+function ChannelPulloutRoster_OnEvent (rosterFrame, event, ...)
+ ChannelPulloutRoster_GetSessionInfo(rosterFrame)
+ ChannelPulloutRoster_Populate(rosterFrame, "ChannelPulloutRosterButtonTemplate", #rosterFrame.members)
+ ChannelPulloutRoster_Update(rosterFrame);
+ ChannelPulloutRoster_UpdateScrollControls(rosterFrame);
+ ChannelPullout_SetOpacity(CHANNELPULLOUT_OPTIONS.opacity or 0);
+ if ( CHANNELPULLOUT_OPTIONS.display and not ChannelPullout:IsShown() ) then
+ ChannelPullout_ToggleDisplay();
+ end
+end
+
+function ChannelPulloutRoster_GetActiveSession ()
+ local name, active;
+ for i = 1, GetNumVoiceSessions() do
+ name, active = GetVoiceSessionInfo(i);
+ if ( active ) then
+ return name, i;
+ end
+ end
+
+ name = GetVoiceSessionInfo(1);
+ if ( name ) then
+ return name, 1, true;
+ end
+
+ return false;
+end
+
+function ChannelPulloutRoster_GetSessionIDByName (name)
+ for i = 1, GetNumVoiceSessions() do
+ if ( GetVoiceSessionInfo(i) == name ) then
+ return i;
+ end
+ end
+
+ return nil;
+end
+
+function ChannelPulloutRoster_GetSessionInfo (roster)
+ rosterFrame = roster or rosterFrame;
+
+ local index, name;
+ if ( CHANNELPULLOUT_OPTIONS.displayActive or ( not CHANNELPULLOUT_OPTIONS.session and not CHANNELPULLOUT_OPTIONS.name ) ) then
+ CHANNELPULLOUT_OPTIONS.displayActive = true;
+ name, index = ChannelPulloutRoster_GetActiveSession();
+ if ( index ) then
+ CHANNELPULLOUT_OPTIONS.session = index;
+ CHANNELPULLOUT_OPTIONS.name = name;
+ else
+ CHANNELPULLOUT_OPTIONS.name = CHANNEL_ROSTER;
+ CHANNELPULLOUT_OPTIONS.session = nil;
+ end
+ elseif ( CHANNELPULLOUT_OPTIONS.name ) then
+ CHANNELPULLOUT_OPTIONS.session = ChannelPulloutRoster_GetSessionIDByName(CHANNELPULLOUT_OPTIONS.name);
+ if ( not CHANNELPULLOUT_OPTIONS.session ) then
+ CHANNELPULLOUT_OPTIONS.name = CHANNEL_ROSTER;
+ end
+ end
+
+ ChannelPulloutTab_UpdateText(CHANNELPULLOUT_OPTIONS.name);
+
+ local numMembers = GetNumVoiceSessionMembersBySessionID(CHANNELPULLOUT_OPTIONS.session) or 0;
+ for i = 1, numMembers do
+ rosterFrame.members[i] = { GetVoiceSessionMemberInfoBySessionID(CHANNELPULLOUT_OPTIONS.session, i) };
+ end
+
+ if ( numMembers < #rosterFrame.members ) then
+ for i = #rosterFrame.members, numMembers + 1, -1 do
+ rosterFrame.members[i] = nil;
+ end
+ end
+
+ table.sort(rosterFrame.members, ChannelPulloutRoster_Sort);
+end
+
+function ChannelPulloutRoster_Populate (roster, templateName, maxButtons)
+ rosterFrame = roster or rosterFrame;
+ local button;
+ if ( not rosterFrame.buttons ) then
+ rosterFrame.buttons = {}
+ rosterFrame.freeButtons = {};
+ button = CreateFrame("BUTTON", rosterFrame:GetName() .. "Button1", rosterFrame, templateName);
+ button:SetPoint("TOPLEFT", rosterFrame);
+ button:SetPoint("TOPRIGHT", rosterFrame);
+ rosterFrame.buttonWidth = button:GetWidth();
+ rosterFrame.buttonHeight = button:GetHeight();
+ tinsert(rosterFrame.buttons, button);
+ end
+
+ maxButtons = maxButtons or math.floor(rosterFrame:GetHeight() / rosterFrame.buttonHeight);
+
+ if ( maxButtons > CHANNELPULLOUT_MAXSIZE ) then
+ maxButtons = CHANNELPULLOUT_MAXSIZE;
+ elseif ( maxButtons < CHANNELPULLOUT_MINSIZE ) then
+ maxButtons = CHANNELPULLOUT_MINSIZE;
+ end
+
+ if ( #rosterFrame.buttons > maxButtons ) then
+ for i = #rosterFrame.buttons, maxButtons + 1, -1 do
+ rosterFrame.buttons[i]:Hide();
+ tinsert(rosterFrame.freeButtons, 1, rosterFrame.buttons[i]);
+ rosterFrame.buttons[i] = nil;
+ end
+ elseif ( maxButtons > #rosterFrame.buttons and #rosterFrame.freeButtons > 0 ) then
+ for i = 1, #rosterFrame.freeButtons do
+ tinsert(rosterFrame.buttons, rosterFrame.freeButtons[1]);
+ tremove(rosterFrame.freeButtons, 1);
+ if ( maxButtons <= #rosterFrame.buttons ) then
+ break;
+ end
+ end
+ end
+
+ for i = #rosterFrame.buttons + 1, maxButtons do
+ button = CreateFrame("BUTTON", rosterFrame:GetName() .. "Button" .. i, rosterFrame, templateName);
+ button:SetPoint("TOP", rosterFrame.buttons[#rosterFrame.buttons], "BOTTOM");
+ button:SetPoint("LEFT", rosterFrame, "LEFT");
+ button:SetPoint("RIGHT", rosterFrame, "RIGHT");
+ tinsert(rosterFrame.buttons, button);
+ end
+
+ rosterFrame.buttonHeight = rosterFrame.buttons[1]:GetHeight();
+ rosterFrame:SetHeight((rosterFrame.buttonHeight * #rosterFrame.buttons) + CHANNELPULLOUT_ROSTERFRAME_OFFSETY)
+ rosterFrame:GetParent():SetHeight(rosterFrame:GetHeight() + CHANNELPULLOUT_ROSTERPARENT_YPADDING);
+ rosterFrame.offset = 0;
+end
+
+function ChannelPulloutRoster_Sort (memberOne, memberTwo)
+ local name, voiceActive, sessionActive, muted, squelched = 1, 2, 3, 4, 5
+
+ if ( memberOne[voiceActive] and memberTwo[voiceActive] ) then
+ --If they both have voice chat enabled...
+ if ( memberOne[sessionActive] and memberTwo[sessionActive] ) then
+ ---And they're both active in this session....
+ if ( ( memberOne[muted] or memberOne[squelched] ) and not ( memberTwo[muted] or memberTwo[squelched] ) ) then
+ --If memberOne is squelched or muted and memberTwo isn't, put memberTwo first.
+ return false;
+ elseif ( ( memberTwo[muted] or memberTwo[squelched] ) and not ( memberOne[muted] or memberOne[squelched] ) ) then
+ --If memberTwo is squelched or muted and memberOne isn't, then memberOne first.
+ return true;
+ else
+ ---And niether of them are muted or squelched, sort alphabetically.
+ return memberOne[name] < memberTwo[name];
+ end
+ elseif ( memberOne[sessionActive] and not memberTwo[sessionActive] ) then
+ --If memberOne is active in the session and memberTwo isn't, display memberOne first.
+ return true;
+ elseif ( memberTwo[sessionActive] and not memberOne[sessionActive] ) then
+ --Otherwise if memberTwo is active and memberOne isn't, display memberTwo first.
+ return false;
+ else
+ --If niether are active, sort alphabetically.
+ return memberOne[name] < memberTwo[name];
+ end
+ elseif ( memberOne[voiceActive] and not memberTwo[voiceActive] ) then
+ --If memberOne has voice chat on and memberTwo doesn't, display memberOne first.
+ return true;
+ elseif ( memberTwo[voiceActive] and not memberOne[voiceActive] ) then
+ --If memberTwo has voice chat on and memberOne doesn't, memberTwo first.
+ return false;
+ end
+
+ --Otherwise, sort alphabetically.
+ return memberOne[name] < memberTwo[name];
+end
+
+local CHANNEL_EMPTY_DATA = { UnitName("player"), false, false, false };
+function ChannelPulloutRoster_Update (roster)
+ rosterFrame = roster or rosterFrame;
+ if ( not rosterFrame or not rosterFrame.members or not rosterFrame.buttons ) then
+ return;
+ end
+
+ local name = 1;
+
+ if ( not CHANNELPULLOUT_OPTIONS.session ) then
+ CHANNEL_EMPTY_DATA[name] = GRAY_FONT_COLOR_CODE .. NO_VOICE_SESSIONS;
+ ChannelPulloutRoster_DrawButton(rosterFrame.buttons[1], CHANNEL_EMPTY_DATA);
+ for i = 2, #rosterFrame.buttons do
+ ChannelPulloutRoster_DrawButton(rosterFrame.buttons[i], nil);
+ end
+ return;
+ elseif ( #rosterFrame.members == 0 ) then
+ CHANNEL_EMPTY_DATA[name] = UnitName("player");
+ ChannelPulloutRoster_DrawButton(rosterFrame.buttons[1], CHANNEL_EMPTY_DATA);
+ for i = 2, #rosterFrame.buttons do
+ ChannelPulloutRoster_DrawButton(rosterFrame.buttons[i], nil);
+ end
+ return;
+ end
+
+ for i = 1, #rosterFrame.buttons do
+ ChannelPulloutRoster_DrawButton(rosterFrame.buttons[i], rosterFrame.members[i + (rosterFrame.offset or 0)]);
+ end
+end
+
+function ChannelPulloutRosterButton_OnEvent (button, event, arg1)
+ if ( event == "VOICE_PLATE_START" and arg1 == button.name:GetText() and CHANNELPULLOUT_OPTIONS.name == ChannelPulloutRoster_GetActiveSession() ) then
+ UIFrameFlash(_G[button:GetName().."SpeakerFlash"], 0.35, 0.35, -1);
+ elseif ( arg1 == button.name:GetText() ) then
+ UIFrameFlashStop(_G[button:GetName().."SpeakerFlash"]);
+ end
+end
+
+function ChannelPulloutRoster_DrawButton (button, data)
+ if ( not button ) then
+ return;
+ elseif ( not data ) then
+ button:Hide();
+ return;
+ end
+
+ local name, voiceActive, sessionActive, muted, squelched = 1, 2, 3, 4, 5
+
+ button.name:SetText(data[name]);
+
+ if ( data[voiceActive] ) then
+ button.speaker:Show();
+ else
+ button.speaker:Hide();
+ end
+
+ if ( data[sessionActive] ) then
+ ChannelFrame_Desaturate(_G[button.speaker:GetName().."On"], nil, 1, 1, 1, 0.75);
+ ChannelFrame_Desaturate(_G[button.speaker:GetName().."Flash"], nil, 1, 1, 1, 0.75);
+ _G[button.speaker:GetName().."Muted"]:SetVertexColor(1, 1, 1, 1);
+ else
+ ChannelFrame_Desaturate(_G[button.speaker:GetName().."On"], 1, nil, nil, nil, 0.25);
+ ChannelFrame_Desaturate(_G[button.speaker:GetName().."Flash"], 1, nil, nil, nil, 0.25);
+ _G[button.speaker:GetName().."Muted"]:SetVertexColor(1, 1, 1, .35);
+ end
+
+ if ( data[muted] or data[squelched] ) then
+ _G[button.speaker:GetName().."Muted"]:Show();
+ else
+ _G[button.speaker:GetName().."Muted"]:Hide();
+ end
+
+ button:Show();
+end
+
+function ChannelPulloutRoster_ScrollToTop (roster)
+ rosterFrame = roster or rosterFrame;
+ if ( not rosterFrame ) then
+ return;
+ end
+
+ rosterFrame.offset = 0;
+ ChannelPulloutRoster_Update(rosterFrame);
+ ChannelPulloutRoster_UpdateScrollControls(rosterFrame);
+end
+
+function ChannelPulloutRoster_ScrollToBottom (roster)
+ rosterFrame = roster or rosterFrame;
+ if ( not rosterFrame ) then
+ return;
+ end
+
+ rosterFrame.offset = #rosterFrame.members - #rosterFrame.buttons;
+ ChannelPulloutRoster_Update(rosterFrame);
+ ChannelPulloutRoster_UpdateScrollControls(rosterFrame);
+end
+
+function ChannelPulloutRoster_Scroll (roster, dir)
+ rosterFrame = roster or rosterFrame;
+ if ( not rosterFrame or not dir ) then
+ return;
+ end
+
+ -- We need to invert the delta we receive from mousewheels, and this function is designed to be used by ChannelPulloutRoster's OnMouseWheel, so we're doing this here!
+ dir = -dir
+
+ if ( ( rosterFrame.offset + dir ) >= 0 and ( rosterFrame.offset + dir ) <= ( #rosterFrame.members - #rosterFrame.buttons ) ) then
+ rosterFrame.offset = rosterFrame.offset + dir;
+ elseif ( rosterFrame.offset < 0 ) then
+ rosterFrame.offset = 0;
+ elseif ( rosterFrame.offset > ( #rosterFrame.members - #rosterFrame.buttons ) and ( #rosterFrame.members - #rosterFrame.buttons >= 0 ) ) then
+ rosterFrame.offset = #rosterFrame.members - #rosterFrame.buttons;
+ end
+
+ ChannelPulloutRoster_Update(rosterFrame);
+ ChannelPulloutRoster_UpdateScrollControls(rosterFrame);
+end
+
+function ChannelPulloutRoster_UpdateScrollControls (roster)
+ rosterFrame = roster or rosterFrame;
+ if (rosterFrame.offset <= 0) then
+ rosterFrame.upBtn:Disable();
+ else
+ rosterFrame.upBtn:Enable();
+ end
+
+ if ( rosterFrame.offset >= #rosterFrame.members - #rosterFrame.buttons ) then
+ rosterFrame.downBtn:Disable();
+ elseif ( ( rosterFrame.offset < #rosterFrame.members - #rosterFrame.buttons ) and #rosterFrame.members > #rosterFrame.buttons ) then
+ rosterFrame.downBtn:Enable();
+ end
+
+ if ( not ( rosterFrame.downBtn:IsEnabled() == 1 or rosterFrame.upBtn:IsEnabled() == 1 ) ) then
+ rosterFrame.scroll:Hide();
+ else
+ rosterFrame.scroll:Show();
+ end
+end
diff --git a/reference/FrameXML/ChannelFrame.xml b/reference/FrameXML/ChannelFrame.xml
new file mode 100644
index 0000000..34e4f28
--- /dev/null
+++ b/reference/FrameXML/ChannelFrame.xml
@@ -0,0 +1,1324 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaiseFrameLevel(self);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ VoiceChat_OnUpdate(self, elapsed);
+
+
+ SetActiveVoiceChannel(self:GetParent():GetID());
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:RegisterForDrag("LeftButton");
+
+
+ ChannelList_OnClick(self, button, down);
+
+
+ ChannelListButton_OnDragStart(self, button);
+
+
+ ChannelListButton_OnDragStop(self);
+
+
+ if ( self.voiceEnabled ) then
+ GameTooltip_AddNewbieTip(self, DISPLAY_CHANNEL_PULLOUT, 1.0, 1.0, 1.0, string.format(NEWBIE_TOOLTIP_DISPLAY_CHANNEL_PULLOUT, (self.name or UNKNOWN)), 1);
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local rank = self:GetParent().rank;
+ local voice = self:GetParent().voice;
+ -- Sets the Leader/Assistant Tooltip
+ if ( rank ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if ( rank == 2 ) then
+ GameTooltip:SetText(RAID_LEADER, nil, nil, nil, nil, 1);
+ elseif ( rank == 1 ) then
+ GameTooltip:SetText(RAID_ASSISTANT, nil, nil, nil, nil, 1);
+ end
+ if ( voice == 2 ) then
+ GameToolTip:AddLine("("..MUTED..")", HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ end
+ else
+ GameTooltip:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ VoiceChat_OnUpdate(self, elapsed);
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ if ( ChannelRosterScrollFrameScrollBar:IsShown() ) then
+ self:SetWidth(115);
+ else
+ self:SetWidth(135);
+ end
+
+
+ ChannelRoster_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local text = _G[self:GetName().."Text"];
+ text:SetText(VOICE_CHAT_PARTY_RAID);
+ text:SetPoint("LEFT", self, "RIGHT", 2, 1);
+
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self:SetChecked(GetCVar("autojoinPartyVoice"));
+ end
+
+
+ GameTooltip:SetOwner(self:GetParent(), "ANCHOR_RIGHT", -20);
+ GameTooltip:SetText(AUTO_JOIN_VOICE);
+ GameTooltip_AddNewbieTip(self, AUTO_JOIN_VOICE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_AUTO_JOIN_VOICE, 1);
+ GameTooltip:Show();
+
+
+
+ SetCVar("autojoinPartyVoice", self:GetChecked());
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local text = _G[self:GetName().."Text"];
+ text:SetText(VOICE_CHAT_BATTLEGROUND);
+ text:SetPoint("LEFT", self, "RIGHT", 2, 1);
+
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self:SetChecked(GetCVar("autojoinBGVoice"));
+ end
+
+
+ GameTooltip:SetOwner(self:GetParent(), "ANCHOR_RIGHT", -20);
+ GameTooltip:SetText(AUTO_JOIN_VOICE);
+ GameTooltip_AddNewbieTip(self, AUTO_JOIN_VOICE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_AUTO_JOIN_VOICE, 1);
+ GameTooltip:Show();
+
+
+
+ SetCVar("autojoinBGVoice", self:GetChecked());
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT", -20);
+ GameTooltip:SetText(AUTO_JOIN_VOICE);
+ GameTooltip_AddNewbieTip(self, AUTO_JOIN_VOICE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_AUTO_JOIN_VOICE, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, CHANNEL_ROSTER_HEIGHT, ChannelRoster_Update)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetText() ) then
+ ChannelFrameDaughterFrame_Okay(self);
+ else
+ ChannelFrameDaughterFrame_Cancel(self);
+ end
+
+
+
+ EditBox_HandleTabbing(self, CHAT_CHANNEL_TABBING);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ EditBox_HandleTabbing(self, CHAT_CHANNEL_TABBING);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( ChannelFrameDaughterFrame:IsShown() ) then
+ ChannelFrameDaughterFrame:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.speaker = _G[self:GetName() .. "Speaker"];
+ self.name = _G[self:GetName() .. "Name"];
+ self.name:SetPoint("TOPLEFT", "$parentSpeaker", "TOPRIGHT", 8, -1);
+ self:EnableMouseWheel();
+ self:RegisterEvent("VOICE_PLATE_START");
+ self:RegisterEvent("VOICE_PLATE_STOP");
+ self:SetScript("OnEvent", ChannelPulloutRosterButton_OnEvent);
+
+
+ ChannelPulloutRoster_Scroll(self:GetParent(), delta);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonUp");
+ self:RegisterForDrag("LeftButton");
+ self:SetAlpha(0);
+ UIDropDownMenu_Initialize(_G[self:GetName().."DropDown"], ChannelPulloutTabDropDown_Initialize, "MENU");
+
+
+ PanelTemplates_TabResize(self, 0);
+
+
+ ChannelPulloutTab_ReanchorLeft();
+ ChannelPulloutTab_OnClick(self, button);
+ PlaySound("UChatScrollButton");
+
+
+ GameTooltip_AddNewbieTip(self, CHANNELPULLOUT_OPTIONS_LABEL, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_CHANNELPULLOUT_OPTIONS, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.5, 0.5, 0.5, 0.5);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ ChannelPullout_ToggleDisplay(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChannelPulloutRoster_OnLoad(self);
+ self:EnableMouseWheel();
+ self.downArrow = _G[self:GetParent():GetName() .. "DownArrow"];
+ self.upArrow = _G[self:GetParent():GetName() .. "UpArrow"];
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChannelPulloutRoster_Scroll(self:GetParent():GetParent(), 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChannelPulloutRoster_Scroll(self:GetParent():GetParent(), -1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/CharacterFrame.lua b/reference/FrameXML/CharacterFrame.lua
new file mode 100644
index 0000000..e51b9d3
--- /dev/null
+++ b/reference/FrameXML/CharacterFrame.lua
@@ -0,0 +1,160 @@
+CHARACTERFRAME_SUBFRAMES = { "PaperDollFrame", "PetPaperDollFrame", "SkillFrame", "ReputationFrame", "TokenFrame" };
+local NUM_CHARACTERFRAME_TABS = 5;
+function ToggleCharacter (tab)
+ local subFrame = _G[tab];
+ if ( subFrame ) then
+ if (not subFrame.hidden) then
+ PanelTemplates_SetTab(CharacterFrame, subFrame:GetID());
+ if ( CharacterFrame:IsShown() ) then
+ if ( subFrame:IsShown() ) then
+ HideUIPanel(CharacterFrame);
+ else
+ PlaySound("igCharacterInfoTab");
+ CharacterFrame_ShowSubFrame(tab);
+ end
+ else
+ ShowUIPanel(CharacterFrame);
+ CharacterFrame_ShowSubFrame(tab);
+ end
+ end
+ end
+end
+
+function CharacterFrame_ShowSubFrame (frameName)
+ for index, value in pairs(CHARACTERFRAME_SUBFRAMES) do
+ if ( value == frameName ) then
+ _G[value]:Show()
+ else
+ _G[value]:Hide();
+ end
+ end
+end
+
+function CharacterFrameTab_OnClick (self, button)
+ local name = self:GetName();
+
+ if ( name == "CharacterFrameTab1" ) then
+ ToggleCharacter("PaperDollFrame");
+ elseif ( name == "CharacterFrameTab2" ) then
+ ToggleCharacter("PetPaperDollFrame");
+ elseif ( name == "CharacterFrameTab3" ) then
+ ToggleCharacter("ReputationFrame");
+ elseif ( name == "CharacterFrameTab4" ) then
+ ToggleCharacter("SkillFrame");
+ elseif ( name == "CharacterFrameTab5" ) then
+ ToggleCharacter("TokenFrame");
+ end
+ PlaySound("igCharacterInfoTab");
+end
+
+function CharacterFrame_OnLoad (self)
+ self:RegisterEvent("UNIT_NAME_UPDATE");
+ self:RegisterEvent("UNIT_PORTRAIT_UPDATE");
+ self:RegisterEvent("PLAYER_PVP_RANK_CHANGED");
+
+ SetTextStatusBarTextPrefix(PlayerFrameHealthBar, HEALTH);
+ SetTextStatusBarTextPrefix(PlayerFrameManaBar, MANA);
+ SetTextStatusBarTextPrefix(MainMenuExpBar, XP);
+ TextStatusBar_UpdateTextString(MainMenuExpBar);
+ -- Tab Handling code
+ PanelTemplates_SetNumTabs(self, 5);
+ PanelTemplates_SetTab(self, 1);
+end
+
+function CharacterFrame_OnEvent (self, event, ...)
+ if ( not self:IsShown() ) then
+ return;
+ end
+
+ local arg1 = ...;
+ if ( event == "UNIT_PORTRAIT_UPDATE" ) then
+ if ( arg1 == "player" ) then
+ SetPortraitTexture(CharacterFramePortrait, arg1);
+ end
+ return;
+ elseif ( event == "UNIT_NAME_UPDATE" ) then
+ if ( arg1 == "player" ) then
+ CharacterNameText:SetText(UnitPVPName(arg1));
+ end
+ return;
+ elseif ( event == "PLAYER_PVP_RANK_CHANGED" ) then
+ CharacterNameText:SetText(UnitPVPName("player"));
+ end
+end
+
+function CharacterFrame_OnShow (self)
+ PlaySound("igCharacterInfoOpen");
+ SetPortraitTexture(CharacterFramePortrait, "player");
+ CharacterNameText:SetText(UnitPVPName("player"));
+ UpdateMicroButtons();
+ PlayerFrameHealthBar.showNumeric = true;
+ PlayerFrameManaBar.showNumeric = true;
+ PlayerFrameAlternateManaBar.showNumeric = true;
+ MainMenuExpBar.showNumeric = true;
+ PetFrameHealthBar.showNumeric = true;
+ PetFrameManaBar.showNumeric = true;
+ ShowTextStatusBarText(PlayerFrameHealthBar);
+ ShowTextStatusBarText(PlayerFrameManaBar);
+ ShowTextStatusBarText(PlayerFrameAlternateManaBar);
+ ShowTextStatusBarText(MainMenuExpBar);
+ ShowTextStatusBarText(PetFrameHealthBar);
+ ShowTextStatusBarText(PetFrameManaBar);
+ ShowWatchedReputationBarText();
+
+ SetButtonPulse(CharacterMicroButton, 0, 1); --Stop the button pulse
+end
+
+function CharacterFrame_OnHide (self)
+ PlaySound("igCharacterInfoClose");
+ UpdateMicroButtons();
+ PlayerFrameHealthBar.showNumeric = nil;
+ PlayerFrameManaBar.showNumeric = nil;
+ PlayerFrameAlternateManaBar.showNumeric = nil;
+ MainMenuExpBar.showNumeric =nil;
+ PetFrameHealthBar.showNumeric = nil;
+ PetFrameManaBar.showNumeric = nil;
+ HideTextStatusBarText(PlayerFrameHealthBar);
+ HideTextStatusBarText(PlayerFrameManaBar);
+ HideTextStatusBarText(PlayerFrameAlternateManaBar);
+ HideTextStatusBarText(MainMenuExpBar);
+ HideTextStatusBarText(PetFrameHealthBar);
+ HideTextStatusBarText(PetFrameManaBar);
+ HideWatchedReputationBarText();
+end
+
+local function CompareFrameSize(frame1, frame2)
+ return frame1:GetWidth() > frame2:GetWidth();
+end
+local CharTabtable = {};
+function CharacterFrame_TabBoundsCheck(self)
+ if ( string.sub(self:GetName(), 1, 17) ~= "CharacterFrameTab" ) then
+ return;
+ end
+
+ local totalSize = 60;
+ for i=1, NUM_CHARACTERFRAME_TABS do
+ _G["CharacterFrameTab"..i.."Text"]:SetWidth(0);
+ PanelTemplates_TabResize(_G["CharacterFrameTab"..i], 0);
+ totalSize = totalSize + _G["CharacterFrameTab"..i]:GetWidth();
+ end
+
+ local diff = totalSize - 465
+
+ if ( diff > 0 and CharacterFrameTab5:IsShown() and CharacterFrameTab2:IsShown()) then
+ --Find the biggest tab
+ for i=1, NUM_CHARACTERFRAME_TABS do
+ CharTabtable[i]=_G["CharacterFrameTab"..i];
+ end
+ table.sort(CharTabtable, CompareFrameSize);
+
+ local i=1;
+ while ( diff > 0 and i <= NUM_CHARACTERFRAME_TABS) do
+ local tabText = _G[CharTabtable[i]:GetName().."Text"]
+ local change = min(10, diff);
+ tabText:SetWidth(tabText:GetWidth() - change);
+ diff = diff - change;
+ PanelTemplates_TabResize(CharTabtable[i], 0);
+ i = i+1;
+ end
+ end
+end
diff --git a/reference/FrameXML/CharacterFrame.xml b/reference/FrameXML/CharacterFrame.xml
new file mode 100644
index 0000000..2d4a8c4
--- /dev/null
+++ b/reference/FrameXML/CharacterFrame.xml
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 4);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(MicroButtonTooltipText(CHARACTER_INFO, "TOGGLECHARACTER0"), 1.0,1.0,1.0 );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(MicroButtonTooltipText(PETS, "TOGGLECHARACTER3"), 1.0,1.0,1.0 );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(MicroButtonTooltipText(REPUTATION, "TOGGLECHARACTER2"), 1.0,1.0,1.0 );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(MicroButtonTooltipText(SKILLS, "TOGGLECHARACTER1"), 1.0,1.0,1.0 );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(MicroButtonTooltipText(CURRENCY, "TOGGLECURRENCY"), 1.0,1.0,1.0 );
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/CharacterFrameTemplates.xml b/reference/FrameXML/CharacterFrameTemplates.xml
new file mode 100644
index 0000000..c1c6a70
--- /dev/null
+++ b/reference/FrameXML/CharacterFrameTemplates.xml
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 4);
+
+
+ PanelTemplates_Tab_OnClick(self, CharacterFrame);
+ CharacterFrameTab_OnClick(self, button);
+
+
+ PanelTemplates_TabResize(self, 0);
+ CharacterFrame_TabBoundsCheck(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/ChatConfigFrame.lua b/reference/FrameXML/ChatConfigFrame.lua
new file mode 100644
index 0000000..348d667
--- /dev/null
+++ b/reference/FrameXML/ChatConfigFrame.lua
@@ -0,0 +1,1893 @@
+COMBATLOG_FILTERS_TO_DISPLAY = 4;
+CHATCONFIG_FILTER_HEIGHT = 16;
+GRAY_CHECKED = 1;
+UNCHECKED_ENABLED = 2;
+UNCHECKED_DISABLED = 3;
+CHATCONFIG_SELECTED_FILTER = nil;
+CHATCONFIG_SELECTED_FILTER_FILTERS = nil;
+CHATCONFIG_SELECTED_FILTER_COLORS = nil;
+CHATCONFIG_SELECTED_FILTER_SETTINGS = nil;
+CHATCONFIG_SELECTED_FILTER_OLD_SETTINGS = nil;
+MAX_COMBATLOG_FILTERS = 20;
+CHATCONFIG_CHANNELS_MAXWIDTH = 145;
+
+--Chat options
+
+CHAT_CONFIG_CHAT_LEFT = {
+ [1] = {
+ type = "SAY",
+ checked = function () return IsListeningForMessageType("SAY"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "SAY"); end;
+ },
+ [2] = {
+ type = "EMOTE",
+ checked = function () return IsListeningForMessageType("EMOTE"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "EMOTE"); end;
+ },
+ [3] = {
+ type = "YELL",
+ checked = function () return IsListeningForMessageType("YELL"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "YELL"); end;
+ },
+ [4] = {
+ text = GUILD_CHAT,
+ type = "GUILD",
+ checked = function () return IsListeningForMessageType("GUILD"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "GUILD"); end;
+ },
+ [5] = {
+ text = OFFICER_CHAT,
+ type = "OFFICER",
+ checked = function () return IsListeningForMessageType("OFFICER"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "OFFICER"); end;
+ },
+ [6] = {
+ type = "GUILD_ACHIEVEMENT",
+ checked = function () return IsListeningForMessageType("GUILD_ACHIEVEMENT"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "GUILD_ACHIEVEMENT"); end;
+ },
+ [7] = {
+ type = "ACHIEVEMENT",
+ checked = function () return IsListeningForMessageType("ACHIEVEMENT"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "ACHIEVEMENT"); end;
+ },
+ [8] = {
+ type = "WHISPER",
+ checked = function () return IsListeningForMessageType("WHISPER"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "WHISPER"); end;
+ },
+ [9] = {
+ type = "BN_WHISPER",
+ noClassColor = 1,
+ checked = function () return IsListeningForMessageType("BN_WHISPER"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "BN_WHISPER"); end;
+ },
+ [10] = {
+ type = "PARTY",
+ checked = function () return IsListeningForMessageType("PARTY"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "PARTY"); end;
+ },
+ [11] = {
+ type = "PARTY_LEADER",
+ checked = function () return IsListeningForMessageType("PARTY_LEADER"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "PARTY_LEADER"); end;
+ },
+ [12] = {
+ type = "RAID",
+ checked = function () return IsListeningForMessageType("RAID"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "RAID"); end;
+ },
+ [13] = {
+ type = "RAID_LEADER",
+ checked = function () return IsListeningForMessageType("RAID_LEADER"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "RAID_LEADER"); end;
+ },
+ [14] = {
+ type = "RAID_WARNING",
+ checked = function () return IsListeningForMessageType("RAID_WARNING"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "RAID_WARNING"); end;
+ },
+ [15] = {
+ type = "BATTLEGROUND",
+ checked = function () return IsListeningForMessageType("BATTLEGROUND"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "BATTLEGROUND"); end;
+ },
+ [16] = {
+ type = "BATTLEGROUND_LEADER",
+ checked = function () return IsListeningForMessageType("BATTLEGROUND_LEADER"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "BATTLEGROUND_LEADER"); end;
+ },
+ [17] = {
+ type = "BN_CONVERSATION",
+ noClassColor = 1,
+ checked = function () return IsListeningForMessageType("BN_CONVERSATION"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "BN_CONVERSATION"); end;
+ },
+};
+
+CHAT_CONFIG_CHAT_CREATURE_LEFT = {
+ [1] = {
+ text = SAY;
+ type = "MONSTER_SAY",
+ checked = function () return IsListeningForMessageType("MONSTER_SAY"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "MONSTER_SAY"); end;
+ },
+ [2] = {
+ text = EMOTE;
+ type = "MONSTER_EMOTE",
+ checked = function () return IsListeningForMessageType("MONSTER_EMOTE"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "MONSTER_EMOTE"); end;
+ },
+ [3] = {
+ text = YELL;
+ type = "MONSTER_YELL",
+ checked = function () return IsListeningForMessageType("MONSTER_YELL"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "MONSTER_YELL"); end;
+ },
+ [4] = {
+ text = WHISPER;
+ type = "MONSTER_WHISPER",
+ checked = function () return IsListeningForMessageType("MONSTER_WHISPER"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "MONSTER_WHISPER"); end;
+ },
+ [5] = {
+ type = "MONSTER_BOSS_EMOTE",
+ checked = function () return IsListeningForMessageType("MONSTER_BOSS_EMOTE"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "MONSTER_BOSS_EMOTE"); end;
+ },
+ [6] = {
+ type = "MONSTER_BOSS_WHISPER",
+ checked = function () return IsListeningForMessageType("MONSTER_BOSS_WHISPER"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "MONSTER_BOSS_WHISPER"); end;
+ }
+};
+
+CHAT_CONFIG_OTHER_COMBAT = {
+ [1] = {
+ type = "COMBAT_XP_GAIN",
+ checked = function () return IsListeningForMessageType("COMBAT_XP_GAIN"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "COMBAT_XP_GAIN"); end;
+ },
+ [2] = {
+ type = "COMBAT_HONOR_GAIN",
+ checked = function () return IsListeningForMessageType("COMBAT_HONOR_GAIN"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "COMBAT_HONOR_GAIN"); end;
+ },
+ [3] = {
+ type = "COMBAT_FACTION_CHANGE",
+ checked = function () return IsListeningForMessageType("COMBAT_FACTION_CHANGE"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "COMBAT_FACTION_CHANGE"); end;
+ },
+ [4] = {
+ text = SKILLUPS,
+ type = "SKILL",
+ checked = function () return IsListeningForMessageType("SKILL"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "SKILL"); end;
+ },
+ [5] = {
+ text = ITEM_LOOT,
+ type = "LOOT",
+ checked = function () return IsListeningForMessageType("LOOT"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "LOOT"); end;
+ },
+ [6] = {
+ text = MONEY_LOOT,
+ type = "MONEY",
+ checked = function () return IsListeningForMessageType("MONEY"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "MONEY"); end;
+ },
+ [7] = {
+ type = "TRADESKILLS",
+ checked = function () return IsListeningForMessageType("TRADESKILLS"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "TRADESKILLS"); end;
+ },
+ [8] = {
+ type = "OPENING",
+ checked = function () return IsListeningForMessageType("OPENING"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "OPENING"); end;
+ },
+ [9] = {
+ type = "PET_INFO",
+ checked = function () return IsListeningForMessageType("PET_INFO"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "PET_INFO"); end;
+ },
+ [10] = {
+ type = "COMBAT_MISC_INFO",
+ checked = function () return IsListeningForMessageType("COMBAT_MISC_INFO"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "COMBAT_MISC_INFO"); end;
+ },
+};
+
+CHAT_CONFIG_OTHER_PVP = {
+ [1] = {
+ type = "BG_SYSTEM_HORDE",
+ checked = function () return IsListeningForMessageType("BG_HORDE"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "BG_HORDE"); end;
+ },
+ [2] = {
+ type = "BG_SYSTEM_ALLIANCE",
+ checked = function () return IsListeningForMessageType("BG_ALLIANCE"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "BG_ALLIANCE"); end;
+ },
+ [3] = {
+ type = "BG_SYSTEM_NEUTRAL",
+ checked = function () return IsListeningForMessageType("BG_NEUTRAL"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "BG_NEUTRAL"); end;
+ },
+}
+
+CHAT_CONFIG_OTHER_SYSTEM = {
+ [1] = {
+ text = SYSTEM_MESSAGES,
+ type = "SYSTEM",
+ checked = function () return IsListeningForMessageType("SYSTEM"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "SYSTEM"); end;
+ },
+ [2] = {
+ type = "ERRORS",
+ checked = function () return IsListeningForMessageType("ERRORS"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "ERRORS"); end;
+ },
+ [3] = {
+ type = "IGNORED",
+ checked = function () return IsListeningForMessageType("IGNORED"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "IGNORED"); end;
+ },
+ [4] = {
+ type = "CHANNEL",
+ checked = function () return IsListeningForMessageType("CHANNEL"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "CHANNEL"); end;
+ },
+ [5] = {
+ type = "TARGETICONS",
+ checked = function () return IsListeningForMessageType("TARGETICONS"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "TARGETICONS"); end;
+ },
+ [6] = {
+ type = "BN_INLINE_TOAST_ALERT",
+ checked = function () return IsListeningForMessageType("BN_INLINE_TOAST_ALERT"); end;
+ func = function (self, checked) ToggleChatMessageGroup(checked, "BN_INLINE_TOAST_ALERT"); end;
+ },
+}
+
+CHAT_CONFIG_CHANNEL_LIST = {};
+
+-- Combat Options
+COMBAT_CONFIG_MESSAGESOURCES_BY = {
+ [1] = {
+ text = function () return ( UsesGUID("SOURCE") and COMBATLOG_FILTER_STRING_CUSTOM_UNIT or COMBATLOG_FILTER_STRING_ME); end;
+ checked = function () return UsesGUID("SOURCE") or IsMessageDoneBy(COMBATLOG_FILTER_MINE); end;
+ disabled = function () return UsesGUID("SOURCE"); end;
+ func = function (self, checked) ToggleMessageSource(checked, COMBATLOG_FILTER_MINE); end;
+ tooltip = FILTER_BY_ME_COMBATLOG_TOOLTIP; --Don't need to change tooltip because if it is the dummy box, it is disabled which means no tooltip
+ },
+ [2] = {
+ text = COMBATLOG_FILTER_STRING_MY_PET,
+ checked = function () return IsMessageDoneBy(COMBATLOG_FILTER_MY_PET); end;
+ hidden = function () return UsesGUID("SOURCE"); end;
+ func = function (self, checked) ToggleMessageSource(checked, COMBATLOG_FILTER_MY_PET); end;
+ tooltip = FILTER_BY_PET_COMBATLOG_TOOLTIP;
+ },
+ [3] = {
+ text = COMBATLOG_FILTER_STRING_FRIENDLY_UNITS,
+ checked = function () return IsMessageDoneBy(COMBATLOG_FILTER_FRIENDLY_UNITS); end;
+ hidden = function () return UsesGUID("SOURCE"); end;
+ func = function (self, checked) ToggleMessageSource(checked, COMBATLOG_FILTER_FRIENDLY_UNITS); end;
+ tooltip = FILTER_BY_FRIENDS_COMBATLOG_TOOLTIP;
+ },
+ [4] = {
+ text = COMBATLOG_FILTER_STRING_HOSTILE_PLAYERS,
+ checked = function () return IsMessageDoneBy(COMBATLOG_FILTER_HOSTILE_PLAYERS); end;
+ hidden = function () return UsesGUID("SOURCE"); end;
+ func = function (self, checked) ToggleMessageSource(checked, COMBATLOG_FILTER_HOSTILE_PLAYERS); end;
+ tooltip = FILTER_BY_HOSTILE_PLAYERS_COMBATLOG_TOOLTIP;
+ },
+ [5] = {
+ text = COMBATLOG_FILTER_STRING_HOSTILE_UNITS,
+ checked = function () return IsMessageDoneBy(COMBATLOG_FILTER_HOSTILE_UNITS); end;
+ hidden = function () return UsesGUID("SOURCE"); end;
+ func = function (self, checked) ToggleMessageSource(checked, COMBATLOG_FILTER_HOSTILE_UNITS); end;
+ tooltip = FILTER_BY_ENEMIES_COMBATLOG_TOOLTIP;
+ },
+ [6] = {
+ text = COMBATLOG_FILTER_STRING_NEUTRAL_UNITS,
+ checked = function () return IsMessageDoneBy(COMBATLOG_FILTER_NEUTRAL_UNITS); end;
+ hidden = function () return UsesGUID("SOURCE"); end;
+ func = function (self, checked) ToggleMessageSource(checked, COMBATLOG_FILTER_NEUTRAL_UNITS); end;
+ tooltip = FILTER_BY_NEUTRAL_COMBATLOG_TOOLTIP;
+ },
+ [7] = {
+ text = COMBATLOG_FILTER_STRING_UNKNOWN_UNITS,
+ checked = function () return IsMessageDoneBy(COMBATLOG_FILTER_UNKNOWN_UNITS); end;
+ hidden = function () return UsesGUID("SOURCE"); end;
+ func = function (self, checked) ToggleMessageSource(checked, COMBATLOG_FILTER_UNKNOWN_UNITS); end;
+ tooltip = FILTER_BY_UNKNOWN_COMBATLOG_TOOLTIP;
+ },
+}
+
+COMBAT_CONFIG_MESSAGESOURCES_TO = {
+ [1] = {
+ text = function () return ( UsesGUID("DEST") and COMBATLOG_FILTER_STRING_CUSTOM_UNIT or COMBATLOG_FILTER_STRING_ME); end;
+ checked = function () return UsesGUID("DEST") or IsMessageDoneTo(COMBATLOG_FILTER_MINE); end;
+ disabled = function () return UsesGUID("DEST"); end;
+ func = function (self, checked) ToggleMessageDest(checked, COMBATLOG_FILTER_MINE); end;
+ tooltip = FILTER_TO_ME_COMBATLOG_TOOLTIP; --Don't need to change tooltip because if it is the dummy box, it is disabled which means no tooltip
+ },
+ [2] = {
+ text = COMBATLOG_FILTER_STRING_MY_PET,
+ checked = function () return IsMessageDoneTo(COMBATLOG_FILTER_MY_PET); end;
+ hidden = function () return UsesGUID("DEST"); end;
+ func = function (self, checked) ToggleMessageDest(checked, COMBATLOG_FILTER_MY_PET); end;
+ tooltip = FILTER_TO_PET_COMBATLOG_TOOLTIP;
+ },
+ [3] = {
+ text = COMBATLOG_FILTER_STRING_FRIENDLY_UNITS,
+ checked = function () return IsMessageDoneTo(COMBATLOG_FILTER_FRIENDLY_UNITS); end;
+ hidden = function () return UsesGUID("DEST"); end;
+ func = function (self, checked) ToggleMessageDest(checked, COMBATLOG_FILTER_FRIENDLY_UNITS); end;
+ tooltip = FILTER_TO_FRIENDS_COMBATLOG_TOOLTIP;
+ },
+ [4] = {
+ text = COMBATLOG_FILTER_STRING_HOSTILE_PLAYERS,
+ checked = function () return IsMessageDoneTo(COMBATLOG_FILTER_HOSTILE_PLAYERS); end;
+ hidden = function () return UsesGUID("DEST"); end;
+ func = function (self, checked) ToggleMessageDest(checked, COMBATLOG_FILTER_HOSTILE_PLAYERS); end;
+ tooltip = FILTER_TO_HOSTILE_PLAYERS_COMBATLOG_TOOLTIP;
+ },
+ [5] = {
+ text = COMBATLOG_FILTER_STRING_HOSTILE_UNITS,
+ checked = function () return IsMessageDoneTo(COMBATLOG_FILTER_HOSTILE_UNITS); end;
+ hidden = function () return UsesGUID("DEST"); end;
+ func = function (self, checked) ToggleMessageDest(checked, COMBATLOG_FILTER_HOSTILE_UNITS); end;
+ tooltip = FILTER_TO_HOSTILE_COMBATLOG_TOOLTIP;
+ },
+ [6] = {
+ text = COMBATLOG_FILTER_STRING_NEUTRAL_UNITS,
+ checked = function () return IsMessageDoneTo(COMBATLOG_FILTER_NEUTRAL_UNITS); end;
+ hidden = function () return UsesGUID("DEST"); end;
+ func = function (self, checked) ToggleMessageDest(checked, COMBATLOG_FILTER_NEUTRAL_UNITS); end;
+ tooltip = FILTER_TO_NEUTRAL_COMBATLOG_TOOLTIP;
+ },
+ [7] = {
+ text = COMBATLOG_FILTER_STRING_UNKNOWN_UNITS,
+ checked = function () return IsMessageDoneTo(COMBATLOG_FILTER_UNKNOWN_UNITS); end;
+ hidden = function () return UsesGUID("DEST"); end;
+ func = function (self, checked) ToggleMessageDest(checked, COMBATLOG_FILTER_UNKNOWN_UNITS); end;
+ tooltip = FILTER_TO_UNKNOWN_COMBATLOG_TOOLTIP;
+ },
+}
+
+COMBAT_CONFIG_MESSAGETYPES_LEFT = {
+ [1] = {
+ text = MELEE,
+ checked = function () return HasMessageTypeGroup(COMBAT_CONFIG_MESSAGETYPES_LEFT, 1) end;
+ func = function (self, checked) ToggleMessageTypeGroup(checked, CombatConfigMessageTypesLeft, 1) end;
+ tooltip = MELEE_COMBATLOG_TOOLTIP,
+ subTypes = {
+ [1] = {
+ text = DAMAGE,
+ type = "SWING_DAMAGE",
+ checked = function () return HasMessageType("SWING_DAMAGE"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SWING_DAMAGE") end;
+ tooltip = SWING_DAMAGE_COMBATLOG_TOOLTIP;
+ },
+ [2] = {
+ text = MISSES,
+ type = "SWING_MISSED",
+ checked = function () return HasMessageType("SWING_MISSED"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SWING_MISSED"); end;
+ tooltip = SWING_MISSED_COMBATLOG_TOOLTIP;
+ },
+ }
+ },
+ [2] = {
+ text = RANGED,
+ checked = function () return HasMessageTypeGroup(COMBAT_CONFIG_MESSAGETYPES_LEFT, 2) end;
+ func = function (self, checked) ToggleMessageTypeGroup(checked, CombatConfigMessageTypesLeft, 2) end;
+ tooltip = RANGED_COMBATLOG_TOOLTIP,
+ subTypes = {
+ [1] = {
+ text = DAMAGE,
+ type = "RANGE_DAMAGE",
+ checked = function () return HasMessageType("RANGE_DAMAGE"); end;
+ func = function (self, checked) ToggleMessageType(checked, "RANGE_DAMAGE"); end;
+ tooltip = RANGE_DAMAGE_COMBATLOG_TOOLTIP;
+ },
+ [2] = {
+ text = MISSES,
+ type = "RANGE_MISSED",
+ checked = function () return HasMessageType("RANGE_MISSED"); end;
+ func = function (self, checked) ToggleMessageType(checked, "RANGE_MISSED"); end;
+ tooltip = RANGE_MISSED_COMBATLOG_TOOLTIP;
+ },
+ }
+ },
+ [3] = {
+ text = AURAS,
+ checked = function () return HasMessageTypeGroup(COMBAT_CONFIG_MESSAGETYPES_LEFT, 3) end;
+ func = function (self, checked) ToggleMessageTypeGroup(checked, CombatConfigMessageTypesLeft, 3) end;
+ tooltip = AURAS_COMBATLOG_TOOLTIP,
+ subTypes = {
+ [1] = {
+ text = BENEFICIAL,
+ type = {"SPELL_AURA_APPLIED", "SPELL_AURA_APPLIED_DOSE", "SPELL_AURA_REMOVED", "SPELL_AURA_APPLIED_REMOVED_DOSE", "SPELL_AURA_REFRESH"};
+ checked = function () return not CHATCONFIG_SELECTED_FILTER_SETTINGS.hideBuffs end;
+ func = function (self, checked)
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.hideBuffs = false;
+ ToggleMessageType(checked, "SPELL_AURA_APPLIED", "SPELL_AURA_APPLIED_DOSE", "SPELL_AURA_REMOVED", "SPELL_AURA_APPLIED_REMOVED_DOSE", "SPELL_AURA_REFRESH");
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.hideBuffs = true;
+ -- Only stop listening for the messages if hideDebuffs is also true
+ if ( CHATCONFIG_SELECTED_FILTER_SETTINGS.hideDebuffs ) then
+ ToggleMessageType(checked, "SPELL_AURA_APPLIED", "SPELL_AURA_APPLIED_DOSE", "SPELL_AURA_REMOVED", "SPELL_AURA_APPLIED_REMOVED_DOSE", "SPELL_AURA_REFRESH");
+ end
+ end
+ end;
+ tooltip = BENEFICIAL_AURA_COMBATLOG_TOOLTIP;
+ },
+ [2] = {
+ text = HOSTILE,
+ type = {"SPELL_AURA_APPLIED", "SPELL_AURA_APPLIED_DOSE", "SPELL_AURA_REMOVED", "SPELL_AURA_APPLIED_REMOVED_DOSE"};
+ checked = function () return not CHATCONFIG_SELECTED_FILTER_SETTINGS.hideDebuffs end;
+ func = function (self, checked)
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.hideDebuffs = false;
+ ToggleMessageType(checked, "SPELL_AURA_APPLIED", "SPELL_AURA_APPLIED_DOSE", "SPELL_AURA_REMOVED", "SPELL_AURA_APPLIED_REMOVED_DOSE");
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.hideDebuffs = true;
+ -- Only stop listening for the messages if hideDebuffs is also true
+ if ( CHATCONFIG_SELECTED_FILTER_SETTINGS.hideBuffs ) then
+ ToggleMessageType(checked, "SPELL_AURA_APPLIED", "SPELL_AURA_APPLIED_DOSE", "SPELL_AURA_REMOVED", "SPELL_AURA_APPLIED_REMOVED_DOSE");
+ end
+ end
+ end;
+ tooltip = HARMFUL_AURA_COMBATLOG_TOOLTIP;
+ },
+ [3] = {
+ text = DISPELS,
+ type = {"SPELL_STOLEN", "SPELL_DISPEL_FAILED", "SPELL_DISPEL"};
+ checked = function () return HasMessageType("SPELL_STOLEN", "SPELL_DISPEL_FAILED", "SPELL_DISPEL"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_STOLEN", "SPELL_DISPEL_FAILED", "SPELL_DISPEL"); end;
+ tooltip = DISPEL_AURA_COMBATLOG_TOOLTIP;
+ },
+ [4] = {
+ text = ENCHANTS,
+ type = {"ENCHANT_APPLIED", "ENCHANT_REMOVED"};
+ checked = function () return HasMessageType("ENCHANT_APPLIED", "ENCHANT_REMOVED"); end;
+ func = function (self, checked) ToggleMessageType(checked, "ENCHANT_APPLIED", "ENCHANT_REMOVED"); end;
+ tooltip = ENCHANT_AURA_COMBATLOG_TOOLTIP;
+ },
+ }
+ },
+ [4] = {
+ text = PERIODIC,
+ checked = function () return HasMessageTypeGroup(COMBAT_CONFIG_MESSAGETYPES_LEFT, 4) end;
+ func = function (self, checked) ToggleMessageTypeGroup(checked, CombatConfigMessageTypesLeft, 4) end;
+ tooltip = SPELL_PERIODIC_COMBATLOG_TOOLTIP,
+ subTypes = {
+ [1] = {
+ text = DAMAGE,
+ type = "SPELL_PERIODIC_DAMAGE",
+ checked = function () return HasMessageType("SPELL_PERIODIC_DAMAGE"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_PERIODIC_DAMAGE"); end;
+ tooltip = SPELL_PERIODIC_DAMAGE_COMBATLOG_TOOLTIP,
+ },
+ [2] = {
+ text = MISSES,
+ type = "SPELL_PERIODIC_MISSED",
+ checked = function () return HasMessageType("SPELL_PERIODIC_MISSED"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_PERIODIC_MISSED"); end;
+ tooltip = SPELL_PERIODIC_MISSED_COMBATLOG_TOOLTIP,
+ },
+ [3] = {
+ text = HEALS,
+ type = "SPELL_PERIODIC_HEAL",
+ checked = function () return HasMessageType("SPELL_PERIODIC_HEAL"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_PERIODIC_HEAL"); end;
+ tooltip = SPELL_PERIODIC_HEAL_COMBATLOG_TOOLTIP,
+ },
+ [4] = {
+ text = OTHER,
+ type = {"SPELL_PERIODIC_ENERGIZE", "SPELL_PERIODIC_DRAIN","SPELL_PERIODIC_LEECH"};
+ checked = function () return HasMessageType("SPELL_PERIODIC_ENERGIZE", "SPELL_PERIODIC_DRAIN", "SPELL_PERIODIC_LEECH"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_PERIODIC_ENERGIZE", "SPELL_PERIODIC_DRAIN", "SPELL_PERIODIC_LEECH"); end;
+ tooltip = SPELL_PERIODIC_OTHER_COMBATLOG_TOOLTIP,
+ },
+ }
+ },
+
+};
+COMBAT_CONFIG_MESSAGETYPES_RIGHT = {
+ [1] = {
+ text = SPELLS,
+ checked = function () return HasMessageTypeGroup(COMBAT_CONFIG_MESSAGETYPES_RIGHT, 1) end;
+ func = function (self, checked) ToggleMessageTypeGroup(checked, CombatConfigMessageTypesRight, 1) end;
+ tooltip = SPELLS_COMBATLOG_TOOLTIP,
+ subTypes = {
+ [1] = {
+ text = DAMAGE,
+ type = "SPELL_DAMAGE",
+ checked = function () return HasMessageType("SPELL_DAMAGE"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_DAMAGE"); end;
+ tooltip = SPELL_DAMAGE_COMBATLOG_TOOLTIP,
+ },
+ [2] = {
+ text = MISSES,
+ type = "SPELL_MISSED",
+ checked = function () return HasMessageType("SPELL_MISSED"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_MISSED"); end;
+ tooltip = SPELL_MISSED_COMBATLOG_TOOLTIP,
+ },
+ [3] = {
+ text = HEALS,
+ type = "SPELL_HEAL",
+ checked = function () return HasMessageType("SPELL_HEAL"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_HEAL"); end;
+ tooltip = SPELL_HEAL_COMBATLOG_TOOLTIP,
+ },
+ [4] = {
+ text = POWER_GAINS,
+ type = "SPELL_ENERGIZE",
+ checked = function () return HasMessageType("SPELL_ENERGIZE"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_ENERGIZE"); end;
+ tooltip = POWER_GAINS_COMBATLOG_TOOLTIP,
+ },
+ [5] = {
+ text = DRAINS,
+ type = {"SPELL_DRAIN", "SPELL_LEECH"};
+ checked = function () return HasMessageType("SPELL_ENERGIZE"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_ENERGIZE"); end;
+ tooltip = SPELL_DRAIN_COMBATLOG_TOOLTIP,
+ },
+ [5] = {
+ text = INTERRUPTS,
+ type = {"SPELL_INTERRUPT"};
+ checked = function () return HasMessageType("SPELL_INTERRUPT"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_INTERRUPT"); end;
+ tooltip = SPELL_INTERRUPT_COMBATLOG_TOOLTIP,
+ },
+ [5] = {
+ text = SPECIAL,
+ type = {"SPELL_INSTAKILL"};
+ checked = function () return HasMessageType("SPELL_INSTAKILL"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_INSTAKILL"); end;
+ tooltip = SPELL_INSTAKILL_COMBATLOG_TOOLTIP,
+ },
+ [6] = {
+ text = EXTRA_ATTACKS,
+ type = {"SPELL_EXTRA_ATTACKS"};
+ checked = function () return HasMessageType("SPELL_EXTRA_ATTACKS"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_EXTRA_ATTACKS"); end;
+ tooltip = SPELL_EXTRA_ATTACKS_COMBATLOG_TOOLTIP,
+ },
+ [7] = {
+ text = SUMMONS,
+ type = {"SPELL_SUMMON"};
+ checked = function () return HasMessageType("SPELL_SUMMON"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_SUMMON"); end;
+ tooltip = SPELL_SUMMON_COMBATLOG_TOOLTIP,
+ },
+ [8] = {
+ text = RESURRECT,
+ type = {"SPELL_RESURRECT"};
+ checked = function () return HasMessageType("SPELL_RESURRECT"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_RESURRECT"); end;
+ tooltip = SPELL_RESURRECT_COMBATLOG_TOOLTIP,
+ },
+ [9] = {
+ text = BUILDING_DAMAGE,
+ type = {"SPELL_BUILDING_DAMAGE"};
+ checked = function () return HasMessageType("SPELL_BUILDING_DAMAGE"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_BUILDING_DAMAGE"); end;
+ tooltip = BUILDING_DAMAGE_COMBATLOG_TOOLTIP,
+ },
+ [10] = {
+ text = BUILDING_HEAL,
+ type = {"SPELL_BUILDING_HEAL"};
+ checked = function () return HasMessageType("SPELL_BUILDING_HEAL"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_BUILDING_HEAL"); end;
+ tooltip = BUILDING_HEAL_COMBATLOG_TOOLTIP,
+ },
+ }
+ },
+ [2] = {
+ text = SPELL_CASTING,
+ checked = function () return HasMessageTypeGroup(COMBAT_CONFIG_MESSAGETYPES_RIGHT, 2) end;
+ func = function (self, checked) ToggleMessageTypeGroup(checked, CombatConfigMessageTypesRight, 2) end;
+ tooltip = SPELL_CASTING_COMBATLOG_TOOLTIP,
+ subTypes = {
+ [1] = {
+ text = START,
+ type = "SPELL_CAST_START",
+ checked = function () return HasMessageType("SPELL_CAST_START"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_CAST_START"); end;
+ tooltip = SPELL_CAST_START_COMBATLOG_TOOLTIP,
+ },
+ [2] = {
+ text = SUCCESS,
+ type = "SPELL_CAST_SUCCESS",
+ checked = function () return HasMessageType("SPELL_CAST_SUCCESS"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_CAST_SUCCESS"); end;
+ tooltip = SPELL_CAST_SUCCESS_COMBATLOG_TOOLTIP,
+ },
+ [3] = {
+ text = FAILURES,
+ type = "SPELL_CAST_FAILED",
+ checked = function () return HasMessageType("SPELL_CAST_FAILED"); end;
+ func = function (self, checked) ToggleMessageType(checked, "SPELL_CAST_FAILED"); end;
+ tooltip = SPELL_CAST_FAILED_COMBATLOG_TOOLTIP,
+ },
+ }
+ },
+};
+COMBAT_CONFIG_MESSAGETYPES_MISC = {
+ [1] = {
+ text = DAMAGE_SHIELD,
+ checked = function () return HasMessageType("DAMAGE_SHIELD", "DAMAGE_SHIELD_MISSED"); end;
+ func = function (self, checked) ToggleMessageType(checked, "DAMAGE_SHIELD", "DAMAGE_SHIELD_MISSED"); end;
+ tooltip = DAMAGE_SHIELD_COMBATLOG_TOOLTIP,
+ },
+ [2] = {
+ text = ENVIRONMENTAL_DAMAGE,
+ checked = function () return HasMessageType("ENVIRONMENTAL_DAMAGE"); end;
+ func = function (self, checked) ToggleMessageType(checked, "ENVIRONMENTAL_DAMAGE"); end;
+ tooltip = ENVIRONMENTAL_DAMAGE_COMBATLOG_TOOLTIP,
+ },
+ [3] = {
+ text = KILLS,
+ checked = function () return HasMessageType("PARTY_KILL"); end;
+ func = function (self, checked) ToggleMessageType(checked, "PARTY_KILL"); end;
+ tooltip = KILLS_COMBATLOG_TOOLTIP,
+ },
+ [4] = {
+ text = DEATHS,
+ type = {"UNIT_DIED", "UNIT_DESTROYED", "UNIT_DISSIPATES"};
+ checked = function () return HasMessageType("UNIT_DIED", "UNIT_DESTROYED", "UNIT_DISSIPATES"); end;
+ func = function (self, checked) ToggleMessageType(checked, "UNIT_DIED", "UNIT_DESTROYED", "UNIT_DISSIPATES"); end;
+ tooltip = DEATHS_COMBATLOG_TOOLTIP,
+ },
+};
+COMBAT_CONFIG_UNIT_COLORS = {
+ [1] = {
+ text = COMBATLOG_FILTER_STRING_ME,
+ type = "COMBATLOG_FILTER_MINE",
+ },
+ [2] = {
+ text = COMBATLOG_FILTER_STRING_MY_PET,
+ type = "COMBATLOG_FILTER_MY_PET",
+ },
+ [3] = {
+ text = COMBATLOG_FILTER_STRING_FRIENDLY_UNITS,
+ type = "COMBATLOG_FILTER_FRIENDLY_UNITS",
+ },
+ [4] = {
+ text = COMBATLOG_FILTER_STRING_HOSTILE_UNITS,
+ type = "COMBATLOG_FILTER_HOSTILE_UNITS",
+ },
+ [5] = {
+ text = COMBATLOG_FILTER_STRING_HOSTILE_PLAYERS,
+ type = "COMBATLOG_FILTER_HOSTILE_PLAYERS",
+ },
+ [6] = {
+ text = COMBATLOG_FILTER_STRING_NEUTRAL_UNITS,
+ type = "COMBATLOG_FILTER_NEUTRAL_UNITS",
+ },
+ [7] = {
+ text = COMBATLOG_FILTER_STRING_UNKNOWN_UNITS,
+ type = "COMBATLOG_FILTER_UNKNOWN_UNITS",
+ },
+}
+
+function ChatConfigFrame_OnLoad(self)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+end
+
+function ChatConfigFrame_OnEvent(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ -- Chat Settings
+ ChatConfig_CreateCheckboxes(ChatConfigChatSettingsLeft, CHAT_CONFIG_CHAT_LEFT, "ChatConfigCheckBoxWithSwatchAndClassColorTemplate", PLAYER_MESSAGES);
+ ChatConfig_CreateCheckboxes(ChatConfigOtherSettingsCombat, CHAT_CONFIG_OTHER_COMBAT, "ChatConfigCheckBoxWithSwatchTemplate", COMBAT);
+ ChatConfig_CreateCheckboxes(ChatConfigOtherSettingsPVP, CHAT_CONFIG_OTHER_PVP, "ChatConfigCheckBoxWithSwatchTemplate", PVP);
+ ChatConfig_CreateCheckboxes(ChatConfigOtherSettingsSystem, CHAT_CONFIG_OTHER_SYSTEM, "ChatConfigCheckBoxWithSwatchTemplate", OTHER);
+ ChatConfig_CreateCheckboxes(ChatConfigOtherSettingsCreature, CHAT_CONFIG_CHAT_CREATURE_LEFT, "ChatConfigCheckBoxWithSwatchTemplate", CREATURE_MESSAGES);
+
+ -- CombatLog Settings
+ ChatConfig_CreateCheckboxes(CombatConfigMessageSourcesDoneBy, COMBAT_CONFIG_MESSAGESOURCES_BY, "ChatConfigCheckBoxTemplate", DONE_BY);
+ ChatConfig_CreateCheckboxes(CombatConfigMessageSourcesDoneTo, COMBAT_CONFIG_MESSAGESOURCES_TO, "ChatConfigCheckBoxTemplate", DONE_TO);
+ ChatConfig_CreateTieredCheckboxes(CombatConfigMessageTypesLeft, COMBAT_CONFIG_MESSAGETYPES_LEFT, "ChatConfigCheckButtonTemplate", "ChatConfigSmallCheckButtonTemplate");
+ ChatConfig_CreateTieredCheckboxes(CombatConfigMessageTypesRight, COMBAT_CONFIG_MESSAGETYPES_RIGHT, "ChatConfigCheckButtonTemplate", "ChatConfigSmallCheckButtonTemplate");
+ ChatConfig_CreateTieredCheckboxes(CombatConfigMessageTypesMisc, COMBAT_CONFIG_MESSAGETYPES_MISC, "ChatConfigSmallCheckButtonTemplate", "ChatConfigSmallCheckButtonTemplate");
+ ChatConfig_CreateColorSwatches(CombatConfigColorsUnitColors, COMBAT_CONFIG_UNIT_COLORS, "ChatConfigSwatchTemplate", UNIT_COLORS);
+
+ if ( COMBATLOG_FILTER_VERSION and COMBATLOG_FILTER_VERSION > Blizzard_CombatLog_Filter_Version ) then
+ CombatConfig_SetCombatFiltersToDefault();
+ Blizzard_CombatLog_Filter_Version = COMBATLOG_FILTER_VERSION;
+ end
+
+ -- Default selections
+ ChatConfigCategory_OnClick(ChatConfigCategoryFrameButton2);
+ ChatConfig_UpdateCombatTabs(1);
+ end
+end
+
+function ChatConfig_CreateCheckboxes(frame, checkBoxTable, checkBoxTemplate, title)
+ local checkBoxNameString = frame:GetName().."CheckBox";
+ local checkBoxName, checkBox, check;
+ local width, height;
+ local padding = 8;
+ local text;
+ local checkBoxFontString;
+
+ frame.checkBoxTable = checkBoxTable;
+ if ( title ) then
+ _G[frame:GetName().."Title"]:SetText(title);
+ end
+ for index, value in ipairs(checkBoxTable) do
+ --If no checkbox then create it
+ checkBoxName = checkBoxNameString..index;
+ checkBox = _G[checkBoxName];
+ if ( not checkBox ) then
+ checkBox = CreateFrame("Frame", checkBoxName, frame, checkBoxTemplate);
+ end
+ if ( not width ) then
+ width = checkBox:GetWidth();
+ height = checkBox:GetHeight();
+ end
+ if ( index > 1 ) then
+ checkBox:SetPoint("TOPLEFT", checkBoxNameString..(index-1), "BOTTOMLEFT", 0, 0);
+ else
+ checkBox:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -4);
+ end
+ if ( value.text ) then
+ text = value.text;
+ else
+ text = _G[value.type];
+ end
+ if ( value.noClassColor ) then
+ _G[checkBoxName.."ColorClasses"]:Hide();
+ end
+ checkBox.type = value.type;
+ checkBoxFontString = _G[checkBoxName.."CheckText"];
+ checkBoxFontString:SetText(text);
+ check = _G[checkBoxName.."Check"];
+ check.func = value.func;
+ check:SetID(index);
+ check.tooltip = value.tooltip;
+ if ( value.maxWidth ) then
+ checkBoxFontString:SetWidth(0);
+ if ( checkBoxFontString:GetWidth() > value.maxWidth ) then
+ checkBoxFontString:SetWidth(value.maxWidth);
+ check.tooltip = text;
+ check.tooltipStyle = 0;
+ end
+ end
+ end
+ --Set Parent frame dimensions
+ if ( #checkBoxTable > 0 ) then
+ frame:SetWidth(width+padding);
+ frame:SetHeight(#checkBoxTable*height+padding);
+ end
+end
+
+function ChatConfig_CreateTieredCheckboxes(frame, checkBoxTable, checkBoxTemplate, subCheckBoxTemplate, columns, spacing)
+ local checkBoxNameString = frame:GetName().."CheckBox";
+ local checkBoxName, checkBox, subCheckBoxName, subCheckBox, subCheckBoxNameString;
+ local width, height;
+ local padding = 8;
+ local count = 0;
+ local text, subText;
+ local yOffset;
+ local numColumns = 2;
+ local columnIndex = 1;
+ local itemsPerColumn;
+ if ( columns ) then
+ itemsPerColumn = ceil(#checkBoxTable/columns);
+ end
+ frame.checkBoxTable = checkBoxTable;
+ for index, value in ipairs(checkBoxTable) do
+ --If no checkbox then create it
+ checkBoxName = checkBoxNameString..index;
+ if ( not _G[checkBoxName] ) then
+ checkBox = CreateFrame("CheckButton", checkBoxName, frame, checkBoxTemplate);
+ if ( index > 1 ) then
+ if ( columns ) then
+ if ( mod(index, columns) == 1 ) then
+ checkBox:SetPoint("TOPLEFT", checkBoxNameString..(index-columns), "BOTTOMLEFT", 0, yOffset);
+ count = count+1;
+ else
+ checkBox:SetPoint("TOPLEFT", checkBoxNameString..(index-1), "TOPRIGHT", spacing, 0);
+ end
+ else
+ checkBox:SetPoint("TOPLEFT", checkBoxNameString..(index-1), "BOTTOMLEFT", 0, yOffset);
+ count = count+1;
+ end
+ else
+ checkBox:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -4);
+ count = count+1;
+ end
+ if ( value.text ) then
+ text = value.text;
+ else
+ text = _G[value.type];
+ end
+ _G[checkBoxName.."Text"]:SetText(text);
+ if ( value.subTypes ) then
+ subCheckBoxNameString = checkBoxName.."_";
+ for k, v in ipairs(value.subTypes) do
+ subCheckBoxName = subCheckBoxNameString..k;
+ if ( not _G[subCheckBoxName] ) then
+ subCheckBox = CreateFrame("CheckButton", subCheckBoxName, checkBox, subCheckBoxTemplate);
+ end
+ if ( k > 1 ) then
+ if ( mod(k, numColumns) == 0 ) then
+ subCheckBox:SetPoint("LEFT", subCheckBoxNameString..(k-1), "RIGHT", 60, 0);
+ else
+ subCheckBox:SetPoint("TOPLEFT", subCheckBoxNameString..(k-2), "BOTTOMLEFT", 0, 2);
+ end
+ else
+ subCheckBox:SetPoint("TOPLEFT", checkBox, "BOTTOMLEFT", 15, 2);
+ end
+ subCheckBox.func = v.func;
+ subCheckBox.tooltip = v.tooltip;
+ if ( v.text ) then
+ subText = v.text;
+ else
+ subText = _G[v.type];
+ end
+ _G[subCheckBoxName.."Text"]:SetText(subText);
+ count = count+0.6;
+ end
+ yOffset = -(22*ceil(#value.subTypes/numColumns) + 16);
+ else
+ yOffset = 0;
+ end
+ checkBox.func = value.func;
+ checkBox.tooltip = value.tooltip;
+ if ( not width ) then
+ width = checkBox:GetWidth();
+ height = checkBox:GetHeight();
+ end
+ end
+ end
+ --Set Parent frame dimensions
+ if ( count > 0 ) then
+ frame:SetWidth(width+padding);
+ frame:SetHeight(count*height+padding);
+ end
+end
+
+function ChatConfig_CreateColorSwatches(frame, swatchTable, swatchTemplate, title)
+ local nameString = frame:GetName().."Swatch";
+ local swatchName, swatch;
+ local width, height;
+ local padding = 8;
+ local count = 0;
+ local text;
+ frame.swatchTable = swatchTable;
+ if ( title ) then
+ _G[frame:GetName().."Title"]:SetText(title);
+ end
+ for index, value in ipairs(swatchTable) do
+ --If no checkbox then create it
+ swatchName = nameString..index;
+ if ( not _G[swatchName] ) then
+ swatch = CreateFrame("Frame", swatchName, frame, swatchTemplate);
+ if ( not width ) then
+ width = swatch:GetWidth();
+ height = swatch:GetHeight();
+ end
+ if ( index > 1 ) then
+ swatch:SetPoint("TOPLEFT", nameString..(index-1), "BOTTOMLEFT", 0, 0);
+ else
+ swatch:SetPoint("TOPLEFT", frame, "TOPLEFT", 4, -4);
+ end
+ if ( value.text ) then
+ text = value.text;
+ else
+ text = _G[value.type];
+ end
+ _G[swatchName.."Text"]:SetText(text);
+ count = count+1;
+ end
+ end
+ --Set Parent frame dimensions
+ if ( count > 0 ) then
+ frame:SetWidth(width+padding);
+ frame:SetHeight(count*height+padding);
+ end
+end
+
+function ChatConfig_UpdateCheckboxes(frame)
+ -- List of message types in current chat frame
+ if ( not FCF_GetCurrentChatFrame() ) then
+ return;
+ end
+ local height;
+ local checkBoxTable = frame.checkBoxTable;
+ local checkBoxNameString = frame:GetName().."CheckBox";
+ local checkBoxName, checkBox, baseName, colorSwatch;
+ local topnum, padding = 0, 8;
+ for index, value in ipairs(checkBoxTable) do
+ baseName = checkBoxNameString..index;
+ checkBox = _G[baseName.."Check"];
+ if ( checkBox ) then
+ if ( not height ) then
+ height = checkBox:GetParent():GetHeight();
+ end
+ if ( type(value.checked) == "function" ) then
+ checkBox:SetChecked(value.checked());
+ else
+ checkBox:SetChecked(value.checked);
+ end
+ if ( type(value.disabled) == "function" ) then
+ if( value.disabled() ) then
+ BlizzardOptionsPanel_CheckButton_Disable(checkBox);
+ else
+ BlizzardOptionsPanel_CheckButton_Enable(checkBox, true);
+ end
+ else
+ if ( value.disabled ) then
+ BlizzardOptionsPanel_CheckButton_Disable(checkBox);
+ else
+ BlizzardOptionsPanel_CheckButton_Enable(checkBox, true);
+ end
+ end
+ if ( type(value.hidden) == "function" ) then
+ if ( value.hidden() ) then
+ checkBox:GetParent():Hide();
+ else
+ checkBox:GetParent():Show();
+ topnum = index;
+ end
+ else
+ if ( value.hidden ) then
+ checkBox:GetParent():Hide();
+ else
+ checkBox:GetParent():Show();
+ topnum = index;
+ end
+ end
+ if ( type(value.text) == "function" ) then --Dynamic text, we should update it
+ _G[checkBoxNameString..index.."CheckText"]:SetText(value.text());
+ end
+
+ colorSwatch = _G[baseName.."ColorSwatch"];
+ if ( colorSwatch ) then
+ _G[baseName.."ColorSwatchNormalTexture"]:SetVertexColor(GetMessageTypeColor(value.type));
+ colorSwatch.type = value.type;
+ end
+
+ --Color class names
+ local colorClasses = _G[baseName.."ColorClasses"];
+ if ( colorClasses ) then
+ colorClasses:SetChecked(IsClassColoringMessageType(value.type));
+ end
+ end
+ frame:SetHeight( topnum * height + padding );
+ end
+ -- Hide remaining checkboxes
+ local count = #checkBoxTable+1;
+ repeat
+ checkBox = _G[checkBoxNameString..count];
+ if ( checkBox ) then
+ checkBox:Hide();
+ end
+ count = count+1;
+ until not checkBox;
+end
+
+function ChatConfig_UpdateSwatches(frame)
+ -- List of message types in current chat frame
+ if ( not FCF_GetCurrentChatFrame() ) then
+ return;
+ end
+ local table = frame.swatchTable;
+ local nameString = frame:GetName().."Swatch";
+ local checkBoxName, checkBox, baseName, colorSwatch;
+ for index, value in ipairs(table) do
+ baseName = nameString..index;
+ colorSwatch = _G[baseName.."ColorSwatch"];
+ if ( colorSwatch ) then
+ _G[baseName.."ColorSwatchNormalTexture"]:SetVertexColor(GetChatUnitColor(value.type));
+ colorSwatch.type = value.type;
+ end
+ end
+end
+
+function ChatConfig_UpdateTieredCheckboxFrame(frame)
+ -- List of message types in current chat frame
+ if ( not FCF_GetCurrentChatFrame() ) then
+ return;
+ end
+ for i=1, #frame.checkBoxTable do
+ ChatConfig_UpdateTieredCheckboxes(frame, i);
+ end
+end
+
+function ChatConfig_UpdateTieredCheckboxes(frame, index)
+ local group = frame.checkBoxTable[index];
+ local groupChecked;
+ local baseName = frame:GetName().."CheckBox"..index;
+ local checkBox = _G[baseName];
+ if ( checkBox ) then
+ groupChecked = group.checked;
+ if ( type(groupChecked) == "function" ) then
+ local checked = groupChecked();
+ checkBox:SetChecked(checked);
+ --Set checked so we can use it later
+ groupChecked = checked;
+ else
+ checkBox:SetChecked(groupChecked);
+ end
+ if ( type(group.disabled) == "function" ) then
+ if( group.disabled() ) then
+ checkBox:Disable();
+ else
+ checkBox:Enable();
+ end
+ else
+ if ( group.disabled ) then
+ checkBox:Disable();
+ else
+ checkBox:Enable();
+ end
+ end
+ end
+ local subCheckBox;
+ if ( group.subTypes ) then
+ for k, v in ipairs(group.subTypes) do
+ subCheckBox = _G[baseName.."_"..k];
+ if ( type(v.checked) == "function" ) then
+ subCheckBox:SetChecked(v.checked());
+ else
+ subCheckBox:SetChecked(v.checked);
+ end
+ if ( type(v.disabled) == "function" ) then
+ if( v.disabled() ) then
+ subCheckBox:Disable();
+ else
+ subCheckBox:Enable();
+ end
+ else
+ if ( v.disabled ) then
+ subCheckBox:Disable();
+ else
+ subCheckBox:Enable();
+ end
+ end
+
+ if ( groupChecked ) then
+ BlizzardOptionsPanel_CheckButton_Enable(subCheckBox, true);
+ else
+ BlizzardOptionsPanel_CheckButton_Disable(subCheckBox);
+ end
+ end
+ end
+end
+
+function CombatConfig_Colorize_Update()
+ if ( not CHATCONFIG_SELECTED_FILTER_SETTINGS ) then
+ return;
+ end
+
+ CombatConfigColorsColorizeUnitNameCheck:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.unitColoring);
+
+ -- Spell Names
+ CombatConfigColorsColorizeSpellNamesCheck:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.abilityColoring);
+ if ( CHATCONFIG_SELECTED_FILTER_SETTINGS.abilityColoring ) then
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigColorsColorizeSpellNamesSchoolColoring, true);
+ else
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigColorsColorizeSpellNamesSchoolColoring, true);
+ end
+ CombatConfigColorsColorizeSpellNamesSchoolColoring:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.abilitySchoolColoring);
+ CombatConfigColorsColorizeSpellNamesColorSwatchNormalTexture:SetVertexColor(GetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.defaults.spell));
+
+ -- Damage Number
+ CombatConfigColorsColorizeDamageNumberCheck:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.amountColoring);
+ if ( CHATCONFIG_SELECTED_FILTER_SETTINGS.amountColoring ) then
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigColorsColorizeDamageNumberSchoolColoring, true);
+ else
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigColorsColorizeDamageNumberSchoolColoring, true);
+ end
+ CombatConfigColorsColorizeDamageNumberSchoolColoring:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.amountSchoolColoring);
+ CombatConfigColorsColorizeDamageNumberColorSwatchNormalTexture:SetVertexColor(GetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.defaults.damage));
+
+ -- Damage School
+ CombatConfigColorsColorizeDamageSchoolCheck:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.schoolNameColoring);
+
+ -- Line Coloring
+ CombatConfigColorsColorizeEntireLineCheck:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.lineColoring);
+ if ( CHATCONFIG_SELECTED_FILTER_SETTINGS.lineColoring ) then
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigColorsColorizeEntireLineBySource, true);
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigColorsColorizeEntireLineByTarget, true);
+ else
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigColorsColorizeEntireLineBySource);
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigColorsColorizeEntireLineByTarget);
+ end
+ if ( CHATCONFIG_SELECTED_FILTER_SETTINGS.lineColorPriority == 1 ) then
+ CombatConfigColorsColorizeEntireLineBySource:SetChecked(1);
+ CombatConfigColorsColorizeEntireLineByTarget:SetChecked(nil);
+ else
+ CombatConfigColorsColorizeEntireLineBySource:SetChecked(nil);
+ CombatConfigColorsColorizeEntireLineByTarget:SetChecked(1);
+ end
+
+ -- Line Highlighting
+ CombatConfigColorsHighlightingLine:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.lineHighlighting);
+ CombatConfigColorsHighlightingAbility:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.abilityHighlighting);
+ CombatConfigColorsHighlightingDamage:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.amountHighlighting);
+ CombatConfigColorsHighlightingSchool:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.schoolNameHighlighting);
+
+
+ local text, r, g, b = CombatLog_OnEvent(CHATCONFIG_SELECTED_FILTER, 0, "SPELL_DAMAGE", 0x0000000000000001, UnitName("player"), 0x511, 0xF13000012B000820, EXAMPLE_TARGET_MONSTER, 0x10a28 ,116, EXAMPLE_SPELL_FROSTBOLT, SCHOOL_MASK_FROST, 27, SCHOOL_MASK_FROST, nil, nil, nil, 1, nil, nil);
+ CombatConfigColorsExampleString1:SetVertexColor(r, g, b);
+ CombatConfigColorsExampleString1:SetText(text);
+
+ text, r, g, b = CombatLog_OnEvent(CHATCONFIG_SELECTED_FILTER, 0, "SPELL_DAMAGE", 0xF13000024D002914, EXAMPLE_TARGET_MONSTER, 0x10a48, 0x0000000000000001, UnitName("player"), 0x511, 20793,EXAMPLE_SPELL_FIREBALL, SCHOOL_MASK_FIRE, 68, SCHOOL_MASK_FIRE, nil, nil, nil, nil, nil, nil);
+ CombatConfigColorsExampleString2:SetVertexColor(r, g, b);
+ CombatConfigColorsExampleString2:SetText(text);
+end
+
+function CombatConfig_Formatting_Update()
+ CombatConfigFormattingShowTimeStamp:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.timestamp);
+ CombatConfigFormattingShowBraces:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.braces);
+ if ( CHATCONFIG_SELECTED_FILTER_SETTINGS.braces ) then
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigFormattingUnitNames, true);
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigFormattingSpellNames, true);
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigFormattingItemNames, true);
+ else
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigFormattingUnitNames);
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigFormattingSpellNames);
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigFormattingItemNames);
+ end
+ CombatConfigFormattingUnitNames:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.unitBraces);
+ CombatConfigFormattingSpellNames:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.spellBraces);
+ CombatConfigFormattingItemNames:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.itemBraces);
+ CombatConfigFormattingFullText:SetChecked(CHATCONFIG_SELECTED_FILTER_SETTINGS.fullText);
+
+ local text, r, g, b = CombatLog_OnEvent(CHATCONFIG_SELECTED_FILTER, 0, "SPELL_DAMAGE", 0x0000000000000001, UnitName("player"), 0x511, 0xF13000012B000820, EXAMPLE_TARGET_MONSTER, 0x10a28 ,116, EXAMPLE_SPELL_FROSTBOLT, SCHOOL_MASK_FROST, 27, SCHOOL_MASK_FROST, nil, nil, nil, 1, nil, nil);
+ CombatConfigFormattingExampleString1:SetVertexColor(r, g, b);
+ CombatConfigFormattingExampleString1:SetText(text);
+
+ text, r, g, b = CombatLog_OnEvent(CHATCONFIG_SELECTED_FILTER, 0, "SPELL_DAMAGE", 0xF13000024D002914, EXAMPLE_TARGET_MONSTER, 0x10a48, 0x0000000000000001, UnitName("player"), 0x511, 20793,EXAMPLE_SPELL_FIREBALL, SCHOOL_MASK_FIRE, 68, SCHOOL_MASK_FIRE, nil, nil, nil, nil, nil, nil);
+ CombatConfigFormattingExampleString2:SetVertexColor(r, g, b);
+ CombatConfigFormattingExampleString2:SetText(text);
+end
+
+function CombatConfig_Settings_Update()
+ CombatConfigSettingsShowQuickButton:SetChecked(CHATCONFIG_SELECTED_FILTER.hasQuickButton);
+ if ( CHATCONFIG_SELECTED_FILTER.hasQuickButton ) then
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigSettingsSolo, true);
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigSettingsParty, true);
+ BlizzardOptionsPanel_CheckButton_Enable(CombatConfigSettingsRaid, true);
+ else
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigSettingsSolo);
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigSettingsParty);
+ BlizzardOptionsPanel_CheckButton_Disable(CombatConfigSettingsRaid);
+ end
+ CombatConfigSettingsSolo:SetChecked(CHATCONFIG_SELECTED_FILTER.quickButtonDisplay.solo);
+ CombatConfigSettingsParty:SetChecked(CHATCONFIG_SELECTED_FILTER.quickButtonDisplay.party);
+ CombatConfigSettingsRaid:SetChecked(CHATCONFIG_SELECTED_FILTER.quickButtonDisplay.raid);
+end
+
+function CombatConfig_SetFilterName(name)
+ CHATCONFIG_SELECTED_FILTER.name = name;
+ ChatConfig_UpdateFilterList();
+end
+
+function ToggleChatMessageGroup(checked, group)
+ if ( checked ) then
+ ChatFrame_AddMessageGroup(FCF_GetCurrentChatFrame(), group);
+ else
+ ChatFrame_RemoveMessageGroup(FCF_GetCurrentChatFrame(), group);
+ end
+end
+
+function ColorClassesCheckBox_OnClick(self, checked)
+ ToggleChatColorNamesByClassGroup(checked, self:GetParent().type);
+end
+
+function ToggleChatColorNamesByClassGroup(checked, group)
+ local info = ChatTypeGroup[group];
+ if ( info ) then
+ for key, value in pairs(info) do
+ SetChatColorNameByClass(strsub(value, 10), checked); --strsub gets rid of CHAT_MSG_
+ end
+ else
+ SetChatColorNameByClass(group, checked);
+ end
+end
+
+function ToggleChatChannel(checked, channel)
+ if ( checked ) then
+ ChatFrame_AddChannel(FCF_GetCurrentChatFrame(), channel);
+ else
+ ChatFrame_RemoveChannel(FCF_GetCurrentChatFrame(), channel);
+ end
+end
+
+function ToggleMessageSource(checked, filter)
+ if ( not CHATCONFIG_SELECTED_FILTER_FILTERS[1].sourceFlags ) then
+ CHATCONFIG_SELECTED_FILTER_FILTERS[1].sourceFlags = {};
+ end
+ local sourceFlags = CHATCONFIG_SELECTED_FILTER_FILTERS[1].sourceFlags;
+ if ( checked ) then
+ sourceFlags[filter] = true;
+ else
+ sourceFlags[filter] = false;
+ end
+end
+
+function ToggleMessageDest(checked, filter)
+ local destFlags;
+
+ if ( UsesGUID( "SOURCE" ) ) then
+ if ( not CHATCONFIG_SELECTED_FILTER_FILTERS[1].destFlags ) then
+ CHATCONFIG_SELECTED_FILTER_FILTERS[1].destFlags = {};
+ end
+ destFlags = CHATCONFIG_SELECTED_FILTER_FILTERS[1].destFlags;
+ else
+ if ( not CHATCONFIG_SELECTED_FILTER_FILTERS[2].destFlags ) then
+ CHATCONFIG_SELECTED_FILTER_FILTERS[2].destFlags = {};
+ end
+ destFlags = CHATCONFIG_SELECTED_FILTER_FILTERS[2].destFlags;
+ end
+ if ( checked ) then
+ destFlags[filter] = true;
+ else
+ destFlags[filter] = false;
+ end
+end
+
+
+-- Create parent is checked or unchecked if all children are unchecked
+function ToggleMessageTypeGroup(checked, frame, index)
+ local subTypes = frame.checkBoxTable[index].subTypes;
+ local eventList = CHATCONFIG_SELECTED_FILTER_FILTERS[1].eventList;
+ if ( subTypes ) then
+ local state;
+ if ( checked ) then
+ for k, v in ipairs(subTypes) do
+ state = GetMessageTypeState(v.type);
+ if ( state == GRAY_CHECKED or state == true ) then
+ if ( type(v.type) == "table" ) then
+ for k2, v2 in pairs(v.type) do
+ eventList[v2] = true;
+ end
+ else
+ eventList[v.type] = true;
+ end
+ else
+ if ( type(v.type) == "table" ) then
+ for k2, v2 in pairs(v.type) do
+ eventList[v2] = UNCHECKED_ENABLED;
+ end
+ else
+ eventList[v.type] = UNCHECKED_ENABLED;
+ end
+ end
+ end
+ else
+ for k, v in ipairs(subTypes) do
+ state = GetMessageTypeState(v.type);
+ if ( state == true or state == GRAY_CHECKED) then
+ if ( type(v.type) == "table" ) then
+ for k2, v2 in pairs(v.type) do
+ eventList[v2] = GRAY_CHECKED;
+ end
+ else
+ eventList[v.type] = GRAY_CHECKED;
+ end
+ else
+ if ( type(v.type) == "table" ) then
+ for k2, v2 in pairs(v.type) do
+ eventList[v2] = UNCHECKED_DISABLED;
+ end
+ else
+ eventList[v.type] = UNCHECKED_DISABLED;
+ end
+ end
+ end
+ end
+ end
+ ChatConfig_UpdateTieredCheckboxes(frame, index);
+end
+
+function ToggleMessageType(checked, ...)
+ local eventList = CHATCONFIG_SELECTED_FILTER_FILTERS[1].eventList;
+ for _, type in pairs ( {...} ) do
+ if ( checked ) then
+ eventList[type] = true;
+ else
+ eventList[type] = false;
+ end
+ end
+end
+
+function IsListeningForMessageType(messageType)
+ local messageTypeList = FCF_GetCurrentChatFrame().messageTypeList;
+ for index, value in pairs(messageTypeList) do
+ if ( value == messageType ) then
+ return true;
+ end
+ end
+ return false;
+end
+
+function IsClassColoringMessageType(messageType)
+ local groupInfo = ChatTypeGroup[messageType];
+ if ( groupInfo ) then
+ for key, value in pairs(groupInfo) do --If any of the sub-categories color by name, we'll consider the entire thing as colored by name.
+ local info = ChatTypeInfo[strsub(value, 10)];
+ if ( info and info.colorNameByClass ) then --strsub gets rid of CHAT_MSG_
+ return true;
+ end
+ end
+ return false;
+ else
+ local info = ChatTypeInfo[messageType];
+ return info and info.colorNameByClass;
+ end
+end
+
+COMBATCONFIG_COLORPICKER_FUNCTIONS = {
+ chatUnitColorSwatch = function()
+ SetChatUnitColor(CHAT_CONFIG_CURRENT_COLOR_SWATCH.type, ColorPickerFrame:GetColorRGB());
+ _G[CHAT_CONFIG_CURRENT_COLOR_SWATCH:GetName().."NormalTexture"]:SetVertexColor(ColorPickerFrame:GetColorRGB());
+ CombatConfig_Colorize_Update();
+ end;
+ chatUnitColorCancel = function()
+ SetChatUnitColor(CHAT_CONFIG_CURRENT_COLOR_SWATCH.type, ColorPicker_GetPreviousValues());
+ _G[CHAT_CONFIG_CURRENT_COLOR_SWATCH:GetName().."NormalTexture"]:SetVertexColor(ColorPicker_GetPreviousValues());
+ CombatConfig_Colorize_Update();
+ end;
+ spellColorSwatch = function()
+ SetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.defaults.spell, ColorPickerFrame:GetColorRGB());
+ _G[CHAT_CONFIG_CURRENT_COLOR_SWATCH:GetName().."NormalTexture"]:SetVertexColor(ColorPickerFrame:GetColorRGB());
+ CombatConfig_Colorize_Update();
+ end;
+ spellColorCancel = function()
+ SetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.defaults.spell, ColorPicker_GetPreviousValues());
+ _G[CHAT_CONFIG_CURRENT_COLOR_SWATCH:GetName().."NormalTexture"]:SetVertexColor(ColorPicker_GetPreviousValues());
+ CombatConfig_Colorize_Update();
+ end;
+ damageColorSwatch = function()
+ SetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.defaults.damage, ColorPickerFrame:GetColorRGB());
+ _G[CHAT_CONFIG_CURRENT_COLOR_SWATCH:GetName().."NormalTexture"]:SetVertexColor(ColorPickerFrame:GetColorRGB());
+ CombatConfig_Colorize_Update();
+ end;
+ damageColorCancel = function()
+ SetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.defaults.damage, ColorPicker_GetPreviousValues());
+ _G[CHAT_CONFIG_CURRENT_COLOR_SWATCH:GetName().."NormalTexture"]:SetVertexColor(ColorPicker_GetPreviousValues());
+ CombatConfig_Colorize_Update();
+ end;
+ messageTypeColorSwatch = function()
+ local messageTypes = ColorPickerFrame.extraInfo;
+ if ( messageTypes ) then
+ for index, value in pairs(messageTypes) do
+ ChangeChatColor(FCF_StripChatMsg(value), ColorPickerFrame:GetColorRGB());
+ end
+ else
+ ChangeChatColor(CHAT_CONFIG_CURRENT_COLOR_SWATCH.type, ColorPickerFrame:GetColorRGB());
+ end
+ _G[CHAT_CONFIG_CURRENT_COLOR_SWATCH:GetName().."NormalTexture"]:SetVertexColor(ColorPickerFrame:GetColorRGB());
+ CombatConfig_Colorize_Update();
+ end;
+ messageTypeColorCancel = function()
+ local messageTypes = ColorPickerFrame.extraInfo;
+ if ( messageTypes ) then
+ for index, value in pairs(messageTypes) do
+ ChangeChatColor(FCF_StripChatMsg(value), ColorPicker_GetPreviousValues());
+ end
+ else
+ ChangeChatColor(CHAT_CONFIG_CURRENT_COLOR_SWATCH.type, ColorPicker_GetPreviousValues());
+ end
+ _G[CHAT_CONFIG_CURRENT_COLOR_SWATCH:GetName().."NormalTexture"]:SetVertexColor(ColorPicker_GetPreviousValues());
+ CombatConfig_Colorize_Update();
+ end;
+}
+
+function ChatUnitColor_OpenColorPicker(self)
+ local info = UIDropDownMenu_CreateInfo();
+ info.r, info.g, info.b = GetChatUnitColor(self.type);
+ CHAT_CONFIG_CURRENT_COLOR_SWATCH = self;
+ info.swatchFunc = COMBATCONFIG_COLORPICKER_FUNCTIONS.chatUnitColorSwatch;
+ info.cancelFunc = COMBATCONFIG_COLORPICKER_FUNCTIONS.chatUnitColorCancel;
+ OpenColorPicker(info);
+end
+
+function SpellColor_OpenColorPicker(self)
+ local info = UIDropDownMenu_CreateInfo();
+ CHAT_CONFIG_CURRENT_COLOR_SWATCH = self;
+ info.r, info.g, info.b = GetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.defaults.spell);
+ info.swatchFunc = COMBATCONFIG_COLORPICKER_FUNCTIONS.spellColorSwatch;
+ info.cancelFunc = COMBATCONFIG_COLORPICKER_FUNCTIONS.spellColorCancel;
+ OpenColorPicker(info);
+end
+
+function DamageColor_OpenColorPicker(self)
+ local info = UIDropDownMenu_CreateInfo();
+ CHAT_CONFIG_CURRENT_COLOR_SWATCH = self;
+ info.r, info.g, info.b = GetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.defaults.damage);
+ info.swatchFunc = COMBATCONFIG_COLORPICKER_FUNCTIONS.damageColorSwatch;
+ info.cancelFunc = COMBATCONFIG_COLORPICKER_FUNCTIONS.damageColorCancel;
+ OpenColorPicker(info);
+end
+
+function MessageTypeColor_OpenColorPicker(self)
+ local info = UIDropDownMenu_CreateInfo();
+ local messageTypeTable;
+ info.r, info.g, info.b, messageTypeTable = GetMessageTypeColor(self.type);
+ CHAT_CONFIG_CURRENT_COLOR_SWATCH = self;
+ info.swatchFunc = COMBATCONFIG_COLORPICKER_FUNCTIONS.messageTypeColorSwatch;
+ info.cancelFunc = COMBATCONFIG_COLORPICKER_FUNCTIONS.messageTypeColorCancel;
+ info.extraInfo = nil;
+ if ( messageTypeTable ) then
+ info.extraInfo = messageTypeTable;
+ end
+ OpenColorPicker(info);
+end
+
+function GetMessageTypeColor(messageType)
+ local group = ChatTypeGroup[messageType];
+ local type;
+ if ( group ) then
+ type = group[1];
+ else
+ type = messageType;
+ end
+ local info = ChatTypeInfo[FCF_StripChatMsg(type)];
+
+ return info.r, info.g, info.b, group;
+end
+
+function GetChatUnitColor(type)
+ local color = CHATCONFIG_SELECTED_FILTER_COLORS.unitColoring[_G[type]];
+ return color.r, color.g, color.b;
+end
+
+function SetChatUnitColor(type, r, g, b)
+ SetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.unitColoring[_G[type]], r, g, b);
+end
+
+function GetSpellNameColor()
+ local color = CHATCONFIG_SELECTED_FILTER_COLORS.defaults.spell;
+ return color.r, color.g, color.b;
+end
+
+function SetSpellNameColor(r, g, b)
+ SetTableColor(CHATCONFIG_SELECTED_FILTER_COLORS.defaults.spell, r, g, b);
+end
+
+-- Convenience functions for pulling and putting rgb values into tables
+function GetTableColor(color)
+ return color.r, color.g, color.b;
+end
+
+function SetTableColor(color, r, g, b)
+ color.r = r;
+ color.g = g;
+ color.b = b;
+end
+
+
+CHAT_CONFIG_CATEGORIES = {
+ [1] = "ChatConfigChatSettings",
+ [2] = "ChatConfigCombatSettings",
+ [3] = "ChatConfigChannelSettings",
+ [4] = "ChatConfigOtherSettings",
+};
+
+function ChatConfigCategory_OnClick(self)
+ self:UnlockHighlight();
+ for index, value in ipairs(CHAT_CONFIG_CATEGORIES) do
+ if ( self:GetID() == index ) then
+ _G[value]:Show();
+ self:LockHighlight();
+ else
+ _G[value]:Hide();
+ _G["ChatConfigCategoryFrameButton"..index]:UnlockHighlight();
+ end
+ end
+end
+
+function CreateChatChannelList(self, ...)
+ if ( not FCF_GetCurrentChatFrame() ) then
+ return;
+ end
+ local channelList = FCF_GetCurrentChatFrame().channelList;
+ local zoneChannelList = FCF_GetCurrentChatFrame().zoneChannelList;
+ local channel, channelID, tag;
+ local checked;
+ local count = 1;
+ CHAT_CONFIG_CHANNEL_LIST = {};
+ for i=1, select("#", ...), 2 do
+ channelID = select(i, ...);
+ tag = "CHANNEL"..channelID;
+ channel = select(i+1, ...);
+ checked = nil;
+ if ( channelList ) then
+ for index, value in pairs(channelList) do
+ if ( value == channel ) then
+ checked = 1;
+ end
+ end
+ end
+ if ( zoneChannelList ) then
+ for index, value in pairs(zoneChannelList) do
+ if ( value == channel ) then
+ checked = 1;
+ end
+ end
+ end
+ CHAT_CONFIG_CHANNEL_LIST[count] = {};
+ CHAT_CONFIG_CHANNEL_LIST[count].text = channelID.."."..channel;
+ CHAT_CONFIG_CHANNEL_LIST[count].channelName = channel;
+ CHAT_CONFIG_CHANNEL_LIST[count].type = tag;
+ CHAT_CONFIG_CHANNEL_LIST[count].maxWidth = CHATCONFIG_CHANNELS_MAXWIDTH;
+ CHAT_CONFIG_CHANNEL_LIST[count].checked = checked;
+ CHAT_CONFIG_CHANNEL_LIST[count].func = function (self, checked)
+ ToggleChatChannel(checked, CHAT_CONFIG_CHANNEL_LIST[self:GetID()].channelName);
+ end;
+ count = count+1;
+ end
+end
+
+COMBAT_CONFIG_TABS = {
+ [1] = { text = MESSAGE_SOURCES, frame = "CombatConfigMessageSources" },
+ [2] = { text = MESSAGE_TYPES, frame = "CombatConfigMessageTypes" },
+ [3] = { text = COLORS, frame = "CombatConfigColors" },
+ [4] = { text = FORMATTING, frame = "CombatConfigFormatting" },
+ [5] = { text = SETTINGS, frame = "CombatConfigSettings" },
+};
+CHAT_CONFIG_COMBAT_TAB_NAME = "CombatConfigTab";
+function ChatConfigCombat_OnLoad()
+ -- Create tabs
+ local tab;
+ local tabName = CHAT_CONFIG_COMBAT_TAB_NAME;
+ local name, text;
+ for index, value in ipairs(COMBAT_CONFIG_TABS) do
+ name = tabName..index;
+ if ( not _G[name] ) then
+ tab = CreateFrame("BUTTON", name, ChatConfigBackgroundFrame, "ChatConfigTabTemplate");
+ if ( index > 1 ) then
+ tab:SetPoint("BOTTOMLEFT", _G[tabName..(index-1)], "BOTTOMRIGHT", -1, 0);
+ else
+ tab:SetPoint("BOTTOMLEFT", ChatConfigBackgroundFrame, "TOPLEFT", 2, -1);
+ end
+
+ text = _G[name.."Text"];
+ text:SetText(value.text);
+ tab:SetID(index);
+ PanelTemplates_TabResize(tab, 0);
+ end
+ end
+end
+
+function ChatConfig_UpdateFilterList()
+ local index;
+ local offset = FauxScrollFrame_GetOffset(ChatConfigCombatSettingsFiltersScrollFrame);
+ local button, buttonName, filter, text;
+ for i=1, COMBATLOG_FILTERS_TO_DISPLAY do
+ index = offset+i;
+ buttonName = "ChatConfigCombatSettingsFiltersButton"..i;
+ button = _G[buttonName];
+ if ( index <= #Blizzard_CombatLog_Filters.filters ) then
+ text = Blizzard_CombatLog_Filters.filters[index].name;
+ _G[buttonName.."NormalText"]:SetText(text);
+ button.name = text;
+ button:Show();
+ if ( index == ChatConfigCombatSettingsFilters.selectedFilter ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+ else
+ button:Hide();
+ end
+ end
+ if ( FauxScrollFrame_Update(ChatConfigCombatSettingsFiltersScrollFrame, #Blizzard_CombatLog_Filters.filters, COMBATLOG_FILTERS_TO_DISPLAY, CHATCONFIG_FILTER_HEIGHT ) ) then
+ ChatConfigCombatSettingsFiltersButton1:SetPoint("TOPRIGHT", ChatConfigCombatSettingsFilters, "TOPRIGHT", -29, -7);
+ else
+ ChatConfigCombatSettingsFiltersButton1:SetPoint("TOPRIGHT", ChatConfigCombatSettingsFilters, "TOPRIGHT", -5, -7);
+ end
+ -- Update the combat log quick buttons
+ Blizzard_CombatLog_Update_QuickButtons();
+end
+
+function ChatConfigFilter_OnClick(id)
+ if ( #Blizzard_CombatLog_Filters.filters > 0 ) then
+ ChatConfigCombatSettingsFilters.selectedFilter = id;
+ CHATCONFIG_SELECTED_FILTER = Blizzard_CombatLog_Filters.filters[ChatConfigCombatSettingsFilters.selectedFilter];
+ CHATCONFIG_SELECTED_FILTER_FILTERS = CHATCONFIG_SELECTED_FILTER.filters;
+ CHATCONFIG_SELECTED_FILTER_COLORS = CHATCONFIG_SELECTED_FILTER.colors;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS = CHATCONFIG_SELECTED_FILTER.settings;
+ end
+ ChatConfig_UpdateFilterList();
+ ChatConfig_UpdateCombatSettings();
+end
+
+function ChatConfig_UpdateCombatSettings()
+ if ( #Blizzard_CombatLog_Filters.filters == 0 ) then
+ ChatConfigCombatSettingsFiltersCopyFilterButton:Disable();
+ ChatConfigCombatSettingsFiltersDeleteButton:Disable();
+ ChatConfig_UpdateCombatTabs(0);
+ for index, value in ipairs(COMBAT_CONFIG_TABS) do
+ _G[value.frame]:Hide();
+ end
+ return;
+ elseif ( #Blizzard_CombatLog_Filters.filters == 1 ) then
+ -- Don't allow them to delete the last filter for now
+ ChatConfigCombatSettingsFiltersDeleteButton:Disable();
+ else
+ ChatConfigCombatSettingsFiltersCopyFilterButton:Enable();
+ ChatConfigCombatSettingsFiltersDeleteButton:Enable();
+ end
+ if ( CanCreateFilters() ) then
+ ChatConfigCombatSettingsFiltersAddFilterButton:Enable();
+ else
+ ChatConfigCombatSettingsFiltersAddFilterButton:Disable();
+ end
+
+ ChatConfig_UpdateCheckboxes(CombatConfigMessageSourcesDoneBy);
+ ChatConfig_UpdateCheckboxes(CombatConfigMessageSourcesDoneTo);
+
+ ChatConfig_UpdateTieredCheckboxFrame(CombatConfigMessageTypesLeft);
+ ChatConfig_UpdateTieredCheckboxFrame(CombatConfigMessageTypesRight);
+ ChatConfig_UpdateTieredCheckboxFrame(CombatConfigMessageTypesMisc);
+
+ ChatConfig_UpdateSwatches(CombatConfigColorsUnitColors);
+ CombatConfig_Colorize_Update();
+ CombatConfig_Formatting_Update();
+ CombatConfig_Settings_Update();
+
+ CombatConfigSettingsNameEditBox:SetText(CHATCONFIG_SELECTED_FILTER.name);
+end
+
+function ChatConfig_UpdateChatSettings()
+ ChatConfig_UpdateCheckboxes(ChatConfigChatSettingsLeft);
+ -- Only do this if the ChannelSettings table has been created. It gets created OnShow()
+ if ( ChatConfigChannelSettingsLeft.checkBoxTable ) then
+ ChatConfig_UpdateCheckboxes(ChatConfigChannelSettingsLeft);
+ end
+ ChatConfig_UpdateCheckboxes(ChatConfigOtherSettingsCombat);
+ ChatConfig_UpdateCheckboxes(ChatConfigOtherSettingsPVP);
+ ChatConfig_UpdateCheckboxes(ChatConfigOtherSettingsSystem);
+ ChatConfig_UpdateCheckboxes(ChatConfigOtherSettingsCreature);
+end
+
+function UsesGUID(direction)
+ if ( direction == "SOURCE" and CHATCONFIG_SELECTED_FILTER_FILTERS[1].sourceFlags ) then
+ for k,v in pairs( CHATCONFIG_SELECTED_FILTER_FILTERS[1].sourceFlags ) do
+ if ( type(k) == "string" ) then
+ return true;
+ end
+ end
+ end
+ if ( direction == "DEST" and CHATCONFIG_SELECTED_FILTER_FILTERS[1].destFlags ) then
+ for k,v in pairs( CHATCONFIG_SELECTED_FILTER_FILTERS[1].destFlags ) do
+ if ( type(k) == "string" ) then
+ return true;
+ end
+ end
+ end
+ return false;
+end
+
+function IsMessageDoneBy(filter)
+ local sourceFlags;
+ if ( not CHATCONFIG_SELECTED_FILTER_FILTERS[1].sourceFlags ) then
+ return true;
+ end
+ sourceFlags = CHATCONFIG_SELECTED_FILTER_FILTERS[1].sourceFlags;
+
+ return sourceFlags[filter];
+end
+
+function IsMessageDoneTo(filter)
+ local destFlags;
+
+ if ( UsesGUID( "SOURCE" ) or UsesGUID("DEST") ) then
+ if ( not CHATCONFIG_SELECTED_FILTER_FILTERS[1].destFlags ) then
+ return true;
+ end
+ destFlags = CHATCONFIG_SELECTED_FILTER_FILTERS[1].destFlags;
+ else
+
+ destFlags = Blizzard_CombatLog_Filters.filters[ChatConfigCombatSettingsFilters.selectedFilter].filters[2].destFlags;
+ end
+
+ return destFlags[filter];
+end
+
+function HasMessageTypeGroup(checkBoxList, index)
+ local subTypes = checkBoxList[index].subTypes;
+ if ( subTypes ) then
+ local state;
+ for k, v in ipairs(subTypes) do
+ state = GetMessageTypeState(v.type);
+ if ( state == GRAY_CHECKED or state == UNCHECKED_DISABLED ) then
+ return false;
+ elseif ( state ) then --also catches UNCHECKED_ENABLED
+ return true;
+ end
+ end
+ end
+ return false;
+end
+
+function HasMessageType(messageType)
+ -- Only look at the first messageType passed in since we're treating them as a unit
+ local isListening = GetMessageTypeState(messageType);
+ if ( isListening == UNCHECKED_ENABLED or isListening == UNCHECKED_DISABLED ) then
+ return false;
+ elseif ( isListening ) then
+ return true;
+ else
+ return false;
+ end
+end
+
+function GetMessageTypeState(messageType)
+ if ( type(messageType) == "table" ) then
+ return CHATCONFIG_SELECTED_FILTER_FILTERS[1].eventList[messageType[1]];
+ else
+ return CHATCONFIG_SELECTED_FILTER_FILTERS[1].eventList[messageType];
+ end
+end
+
+function ChatConfig_UpdateCombatTabs(selectedTabID)
+ local tab, text, frame;
+ for index, value in ipairs(COMBAT_CONFIG_TABS) do
+ tab = _G[CHAT_CONFIG_COMBAT_TAB_NAME..index];
+ text = _G[CHAT_CONFIG_COMBAT_TAB_NAME..index.."Text"];
+ frame = _G[value.frame];
+ if ( (not Blizzard_CombatLog_Filters) or #Blizzard_CombatLog_Filters.filters == 0 ) then
+ tab:SetAlpha(0.75);
+ text:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ elseif ( index == selectedTabID ) then
+ tab:SetAlpha(1.0);
+ text:SetVertexColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ frame:Show();
+ else
+ tab:SetAlpha(0.75);
+ text:SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ frame:Hide();
+ end
+
+ end
+end
+
+function ChatConfig_ShowCombatTabs()
+ for index, _ in ipairs(COMBAT_CONFIG_TABS) do
+ _G[CHAT_CONFIG_COMBAT_TAB_NAME..index]:Show();
+ end
+end
+
+function ChatConfig_HideCombatTabs()
+ for index, _ in ipairs(COMBAT_CONFIG_TABS) do
+ _G[CHAT_CONFIG_COMBAT_TAB_NAME..index]:Hide();
+ end
+end
+
+function CombatConfig_CreateCombatFilter(name, filter)
+ local newFilter;
+ if ( not filter ) then
+ newFilter = CopyTable(DEFAULT_COMBATLOG_FILTER_TEMPLATE);
+ else
+ newFilter = CopyTable(filter);
+ end
+ if ( not name or name == "" ) then
+ name = format(DEFAULT_COMBATLOG_FILTER_NAME, #Blizzard_CombatLog_Filters.filters);
+ end
+ newFilter.name = name;
+ newFilter.tooltip = "";
+ tinsert(Blizzard_CombatLog_Filters.filters, newFilter);
+ -- Scroll filters to top of list
+ ChatConfigCombatSettingsFiltersScrollFrameScrollBar:SetValue(0);
+ -- Select the new filter
+ ChatConfigFilter_OnClick(#Blizzard_CombatLog_Filters.filters);
+ -- If creating a filter when there wasn't any before then update the tabs with the first one selected
+ if ( #Blizzard_CombatLog_Filters.filters == 1 ) then
+ ChatConfig_UpdateCombatTabs(1);
+ end
+end
+
+function CombatConfig_DeleteCurrentCombatFilter()
+ -- Don't allow deletion of all filters
+ if ( #Blizzard_CombatLog_Filters.filters <= 1 ) then
+ return;
+ end
+ tremove(Blizzard_CombatLog_Filters.filters, ChatConfigCombatSettingsFilters.selectedFilter);
+ -- If the deleted filter comes before or is the selected filter, force the current filter to the first
+ if ( ChatConfigCombatSettingsFilters.selectedFilter <= Blizzard_CombatLog_Filters.currentFilter ) then
+ Blizzard_CombatLog_QuickButton_OnClick(1);
+ end
+
+ -- Scroll filters to top of list
+ ChatConfigCombatSettingsFiltersScrollFrameScrollBar:SetValue(0);
+ -- Select the first filter
+ ChatConfigFilter_OnClick(1);
+end
+
+function CombatConfig_SetCombatFiltersToDefault()
+ Blizzard_CombatLog_Filters = CopyTable(Blizzard_CombatLog_Filter_Defaults);
+ -- Have to call this because of the way the upvalues are setup in the combatlog
+ Blizzard_CombatLog_RefreshGlobalLinks();
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[1]
+ ChatConfig_UpdateFilterList();
+ ChatConfigFilter_OnClick(1);
+ ChatConfig_UpdateCombatTabs(1);
+end
+
+function ChatConfig_MoveFilterUp()
+ local selectedFilter = ChatConfigCombatSettingsFilters.selectedFilter;
+ if ( selectedFilter == 1 ) then
+ return;
+ end
+ local newIndex = selectedFilter-1;
+ tinsert(Blizzard_CombatLog_Filters.filters, newIndex, CHATCONFIG_SELECTED_FILTER);
+ tremove(Blizzard_CombatLog_Filters.filters, selectedFilter+1);
+ if ( selectedFilter == Blizzard_CombatLog_Filters.currentFilter ) then
+ Blizzard_CombatLog_Filters.currentFilter = newIndex;
+ elseif ( newIndex == Blizzard_CombatLog_Filters.currentFilter ) then
+ Blizzard_CombatLog_Filters.currentFilter = Blizzard_CombatLog_Filters.currentFilter+1;
+ end
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[Blizzard_CombatLog_Filters.currentFilter];
+ ChatConfigFilter_OnClick(newIndex);
+end
+
+function ChatConfig_MoveFilterDown()
+ local selectedFilter = ChatConfigCombatSettingsFilters.selectedFilter;
+ if ( selectedFilter >= #Blizzard_CombatLog_Filters.filters ) then
+ selectedFilter = #Blizzard_CombatLog_Filters.filters;
+ return;
+ end
+ local newIndex = selectedFilter+2;
+ tinsert(Blizzard_CombatLog_Filters.filters, newIndex, CHATCONFIG_SELECTED_FILTER);
+ tremove(Blizzard_CombatLog_Filters.filters, selectedFilter);
+ if ( selectedFilter == Blizzard_CombatLog_Filters.currentFilter ) then
+ Blizzard_CombatLog_Filters.currentFilter = selectedFilter+1;
+ elseif ( selectedFilter+1 == Blizzard_CombatLog_Filters.currentFilter ) then
+ Blizzard_CombatLog_Filters.currentFilter = selectedFilter;
+ end
+ Blizzard_CombatLog_CurrentSettings = Blizzard_CombatLog_Filters.filters[Blizzard_CombatLog_Filters.currentFilter];
+ ChatConfigFilter_OnClick(selectedFilter+1);
+end
+
+function ChatConfigCancel_OnClick()
+ -- Copy the old settings back in place
+ Blizzard_CombatLog_Filters = CopyTable(CHATCONFIG_SELECTED_FILTER_OLD_SETTINGS);
+ -- Have to call this because of the way the upvalues are setup in the combatlog
+ Blizzard_CombatLog_RefreshGlobalLinks();
+
+ CHATCONFIG_SELECTED_FILTER = Blizzard_CombatLog_Filters.filters[ChatConfigCombatSettingsFilters.selectedFilter];
+ -- Handle the case where the selected filter no longer exists!!!
+ if ( not CHATCONFIG_SELECTED_FILTER ) then
+ ChatConfigFilter_OnClick(1);
+ HideUIPanel(ChatConfigFrame);
+ return;
+ end
+
+ CHATCONFIG_SELECTED_FILTER_FILTERS = CHATCONFIG_SELECTED_FILTER.filters;
+ CHATCONFIG_SELECTED_FILTER_COLORS = CHATCONFIG_SELECTED_FILTER.colors;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS = CHATCONFIG_SELECTED_FILTER.settings;
+
+ HideUIPanel(ChatConfigFrame);
+end
+
+function CanCreateFilters()
+ if ( #Blizzard_CombatLog_Filters.filters == MAX_COMBATLOG_FILTERS ) then
+ return false;
+ end
+ return true;
+end
+
+function ChatConfigFrame_PlayCheckboxSound (checked)
+ if ( checked ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+end
diff --git a/reference/FrameXML/ChatConfigFrame.xml b/reference/FrameXML/ChatConfigFrame.xml
new file mode 100644
index 0000000..c972554
--- /dev/null
+++ b/reference/FrameXML/ChatConfigFrame.xml
@@ -0,0 +1,2051 @@
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Highlight"]:SetVertexColor(0.11, 0.325, 0.48);
+
+
+ ChatConfigCategory_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChatConfigFilter_OnClick(self:GetID()+FauxScrollFrame_GetOffset(ChatConfigCombatSettingsFiltersScrollFrame));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+ self:SetBackdropColor(0.27, 0.27, 0.27);
+
+ local fontStringOffset = 2;
+ self.classStrings = {};
+ tinsert(self.classStrings, self.firstClass);
+ for key, value in ipairs(CLASS_SORT_ORDER) do
+ local fontString = self.classStrings[key];
+ if ( not fontString ) then
+ fontString = self:CreateFontString(nil, "ARTWORK", "ClassColorLegendFontStringTemplate");
+ tinsert(self.classStrings, fontString);
+ fontString:SetPoint("TOPLEFT", self.classStrings[key - 1], "BOTTOMLEFT", 0, -fontStringOffset);
+ end
+ local classColor = RAID_CLASS_COLORS[value];
+ fontString:SetFormattedText("|cff%.2x%.2x%.2x%s|r\n", classColor.r*255, classColor.g*255, classColor.b*255, LOCALIZED_CLASS_NAMES_MALE[value]);
+ end
+
+ self:SetHeight((self.firstClass:GetHeight() + fontStringOffset) * #self.classStrings + self.header:GetHeight() + 31);
+
+
+
+
+
+
+
+
+
+ local checked = self:GetChecked();
+ if ( self.func ) then
+ self.func(self, checked);
+ end
+
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+ if (self.tooltip) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, (self.tooltipStyle or 1));
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MessageTypeColor_OpenColorPicker(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.func = ColorClassesCheckBox_OnClick;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChatUnitColor_OpenColorPicker(self, button, down);
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("UChatScrollButton");
+ ChatConfig_UpdateCombatTabs(self:GetID());
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsCombatLog(FCF_GetCurrentChatFrame()) ) then
+ ChatConfigCategoryFrameButton2:Show();
+ ChatConfigCategoryFrameButton3:SetPoint("TOPLEFT", ChatConfigCategoryFrameButton2, "BOTTOMLEFT", 0, -1);
+ ChatConfigCategoryFrameButton3:SetPoint("TOPRIGHT", ChatConfigCategoryFrameButton2, "BOTTOMRIGHT", 0, -1);
+ ChatConfigCategory_OnClick(ChatConfigCategoryFrameButton2);
+ else
+ ChatConfigCategoryFrameButton2:Hide();
+ ChatConfigCategoryFrameButton3:SetPoint("TOPLEFT", ChatConfigCategoryFrameButton1, "BOTTOMLEFT", 0, -1);
+ ChatConfigCategoryFrameButton3:SetPoint("TOPRIGHT", ChatConfigCategoryFrameButton1, "BOTTOMRIGHT", 0, -1);
+ ChatConfigCategory_OnClick(ChatConfigCategoryFrameButton1);
+ end
+ ChatConfigFrameHeaderText:SetText(format(CHATCONFIG_HEADER, FCF_GetCurrentChatFrame().name));
+ ChatConfigFrameHeader:SetWidth(ChatConfigFrameHeaderText:GetWidth()+200);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChatConfig_UpdateCheckboxes(ChatConfigChatSettingsLeft);
+ ChatConfigFrameDefaultButton:Show();
+ CombatLogDefaultButton:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -- Have to build it here since the channel list doesn't exist on load
+ CreateChatChannelList(self, GetChannelList());
+ ChatConfig_CreateCheckboxes(ChatConfigChannelSettingsLeft, CHAT_CONFIG_CHANNEL_LIST, "ChatConfigCheckBoxWithSwatchAndClassColorTemplate", CHANNELS);
+ ChatConfig_UpdateCheckboxes(ChatConfigChannelSettingsLeft);
+ ChatConfigFrameDefaultButton:Show();
+ CombatLogDefaultButton:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChatConfig_UpdateCheckboxes(ChatConfigOtherSettingsCombat);
+ ChatConfig_UpdateCheckboxes(ChatConfigOtherSettingsPVP);
+ ChatConfig_UpdateCheckboxes(ChatConfigOtherSettingsSystem);
+ ChatConfig_UpdateCheckboxes(ChatConfigOtherSettingsCreature);
+ ChatConfigFrameDefaultButton:Show();
+ CombatLogDefaultButton:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, CHATCONFIG_FILTER_HEIGHT, ChatConfig_UpdateFilterList);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("CONFIRM_COMBAT_FILTER_DELETE");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("CREATE_COMBAT_FILTER");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local dialog = StaticPopup_Show("COPY_COMBAT_FILTER");
+ dialog.data = CHATCONFIG_SELECTED_FILTER;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChatConfig_MoveFilterUp();
+ PlaySound("UChatScrollButton");
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip_AddNewbieTip(self, MOVE_FILTER_UP, 1.0, 1.0, 1.0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChatConfig_MoveFilterDown();
+ PlaySound("UChatScrollButton");
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip_AddNewbieTip(self, MOVE_FILTER_DOWN, 1.0, 1.0, 1.0);
+
+
+
+
+
+
+
+
+
+
+
+ ChatConfig_UpdateFilterList();
+ ChatConfigFilter_OnClick(1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(COMBATLOG_HIGHLIGHT_KILL);
+ self.tooltip = HIGHLIGHT_KILL_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.lineHighlighting = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.lineHighlighting = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(COMBATLOG_HIGHLIGHT_ABILITY);
+ self.tooltip = HIGHLIGHT_ABILITY_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.abilityHighlighting = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.abilityHighlighting = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(COMBATLOG_HIGHLIGHT_DAMAGE);
+ self.tooltip = HIGHLIGHT_DAMAGE_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.amountHighlighting = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.amountHighlighting = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(COMBATLOG_HIGHLIGHT_SCHOOL);
+ self.tooltip = HIGHLIGHT_SCHOOL_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.schoolNameHighlighting = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.schoolNameHighlighting = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(UNIT_NAMES);
+ self.tooltip = UNIT_NAMES_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.unitColoring = true;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.sourceColoring = true;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.destColoring = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.unitColoring = false;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.sourceColoring = false;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.destColoring = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(SPELL_NAMES);
+ self.tooltip = SPELL_NAMES_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.abilityColoring = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.abilityColoring = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(COLOR_BY_SCHOOL);
+ self.tooltip = SPELL_COLOR_BY_SCHOOL_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.abilitySchoolColoring = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.abilitySchoolColoring = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(DAMAGE_NUMBER);
+ self.tooltip = SPELL_DAMAGE_NUMBER_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.amountColoring = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.amountColoring = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(COLOR_BY_SCHOOL);
+ self.tooltip = SPELL_COLOR_BY_SCHOOL_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.amountSchoolColoring = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.amountSchoolColoring = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(DAMAGE_SCHOOL_TEXT);
+ self.tooltip = SPELL_DAMAGE_SCHOOL_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.schoolNameColoring = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.schoolNameColoring = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(ENTIRE_LINE);
+ self.tooltip = ENTIRE_LINE_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.lineColoring = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.lineColoring = false;
+ end
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(BY_SOURCE);
+ self.tooltip = BY_SOURCE_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked();
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.lineColorPriority = 1;
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(BY_TARGET);
+ self.tooltip = BY_TARGET_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked();
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.lineColorPriority = 2;
+ CombatConfig_Colorize_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+
+
+
+
+
+
+
+
+ ChatConfig_UpdateSwatches(CombatConfigColorsUnitColors);
+ CombatConfig_Colorize_Update();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(SHOW_TIMESTAMP);
+ self.tooltip = TIMESTAMP_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.timestamp = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.timestamp = false;
+ end
+ CombatConfig_Formatting_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(SHOW_BRACES);
+ self.tooltip = SHOW_BRACES_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.braces = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.braces = false;
+ end
+ CombatConfig_Formatting_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(UNIT_NAMES);
+ self.tooltip = UNIT_NAMES_SHOW_BRACES_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.unitBraces = true;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.sourceBraces = true;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.destBraces = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.unitBraces = false;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.sourceBraces = false;
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.destBraces = false;
+ end
+ CombatConfig_Formatting_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(SPELL_NAMES);
+ self.tooltip = SPELL_NAMES_SHOW_BRACES_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.spellBraces = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.spellBraces = false;
+ end
+ CombatConfig_Formatting_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(ITEM_NAMES);
+ self.tooltip = ITEM_NAMES_SHOW_BRACES_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.itemBraces = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.itemBraces = false;
+ end
+ CombatConfig_Formatting_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(USE_FULL_TEXT_MODE);
+ self.tooltip = FULL_TEXT_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.fullText = true;
+ else
+ CHATCONFIG_SELECTED_FILTER_SETTINGS.fullText = false;
+ end
+ CombatConfig_Formatting_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetText(CHATCONFIG_SELECTED_FILTER.name);
+
+
+ CombatConfig_SetFilterName(self:GetText());
+ self:HighlightText(0, -1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CombatConfig_SetFilterName(CombatConfigSettingsNameEditBox:GetText());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(SHOW_QUICK_BUTTON);
+ self.tooltip = QUICK_BUTTON_COMBATLOG_TOOLTIP;
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER.hasQuickButton = true;
+ else
+ CHATCONFIG_SELECTED_FILTER.hasQuickButton = false;
+ end
+ Blizzard_CombatLog_Update_QuickButtons();
+ CombatConfig_Settings_Update();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(SOLO);
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER.quickButtonDisplay.solo = true;
+ else
+ CHATCONFIG_SELECTED_FILTER.quickButtonDisplay.solo = false;
+ end
+ Blizzard_CombatLog_Update_QuickButtons();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(PARTY);
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER.quickButtonDisplay.party = true;
+ else
+ CHATCONFIG_SELECTED_FILTER.quickButtonDisplay.party = false;
+ end
+ Blizzard_CombatLog_Update_QuickButtons();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(RAID);
+
+
+ local checked = self:GetChecked()
+ if ( checked ) then
+ CHATCONFIG_SELECTED_FILTER.quickButtonDisplay.raid = true;
+ else
+ CHATCONFIG_SELECTED_FILTER.quickButtonDisplay.raid = false;
+ end
+ Blizzard_CombatLog_Update_QuickButtons();
+ ChatConfigFrame_PlayCheckboxSound(checked);
+
+
+
+
+
+
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("RAID_ROSTER_UPDATE");
+
+
+ if ( Blizzard_CombatLog_Update_QuickButtons ) then --The function is in an AddOn, so we want to make sure it is loaded before calling it.
+ Blizzard_CombatLog_Update_QuickButtons();
+ end
+
+
+
+
+
+
+
+
+ ChatConfigBackgroundFrame:SetPoint("TOPLEFT", ChatConfigCategoryFrame, "TOPRIGHT", 1, -135);
+ ChatConfig_ShowCombatTabs();
+ ChatConfigFrameDefaultButton:Hide();
+ CombatLogDefaultButton:Show();
+
+
+ ChatConfigBackgroundFrame:SetPoint("TOPLEFT", ChatConfigCategoryFrame, "TOPRIGHT", 1, 0);
+ ChatConfig_HideCombatTabs();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("RESET_CHAT");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("CONFIRM_COMBAT_FILTER_DEFAULTS");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChatConfigCancel_OnClick();
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(ChatConfigFrame);
+ if ( IsCombatLog(FCF_GetCurrentChatFrame()) ) then
+ Blizzard_CombatLog_RefreshGlobalLinks();
+ Blizzard_CombatLog_ApplyFilters(Blizzard_CombatLog_CurrentSettings);
+ Blizzard_CombatLog_Refilter();
+ end
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+
+ CHATCONFIG_SELECTED_FILTER_OLD_SETTINGS = CopyTable(Blizzard_CombatLog_Filters);
+
+
+
+
diff --git a/reference/FrameXML/ChatFrame.lua b/reference/FrameXML/ChatFrame.lua
new file mode 100644
index 0000000..56690c8
--- /dev/null
+++ b/reference/FrameXML/ChatFrame.lua
@@ -0,0 +1,4543 @@
+MESSAGE_SCROLLBUTTON_INITIAL_DELAY = 0;
+MESSAGE_SCROLLBUTTON_SCROLL_DELAY = 0.05;
+CHAT_BUTTON_FLASH_TIME = 0.5;
+CHAT_TELL_ALERT_TIME = 300;
+NUM_CHAT_WINDOWS = 10;
+DEFAULT_CHAT_FRAME = ChatFrame1;
+NUM_REMEMBERED_TELLS = 10;
+MAX_WOW_CHAT_CHANNELS = 10;
+
+CHAT_TIMESTAMP_FORMAT = nil; -- gets set from Interface Options
+CHAT_SHOW_IME = false;
+
+MAX_CHARACTER_NAME_BYTES = 48;
+
+--DEBUG FIXME FOR TESTING
+CHAT_OPTIONS = {
+ ONE_EDIT_AT_A_TIME = "old"
+};
+
+-- Table for event indexed chatFilters.
+-- Format ["CHAT_MSG_SYSTEM"] = { function1, function2, function3 }
+-- filter, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11 = function1 (self, event, ...) if filter then return true end return false, ... end
+local chatFilters = {};
+
+-- These hash tables are to improve performance of common lookups
+-- if you change what these tables point to (ie slash command, emote, chat)
+-- then you need to invalidate the entry in the hash table
+local hash_SecureCmdList = {}
+hash_SlashCmdList = {}
+hash_EmoteTokenList = {}
+hash_ChatTypeInfoList = {}
+
+ChatTypeInfo = { };
+ChatTypeInfo["SYSTEM"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["SAY"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["PARTY"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["RAID"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["GUILD"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["OFFICER"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["YELL"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["WHISPER"] = { sticky = 1, flashTab = true, flashTabOnGeneral = true };
+ChatTypeInfo["WHISPER_INFORM"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["REPLY"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["EMOTE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["TEXT_EMOTE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["MONSTER_SAY"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["MONSTER_PARTY"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["MONSTER_YELL"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["MONSTER_WHISPER"] = { sticky = 0, flashTab = true, flashTabOnGeneral = true };
+ChatTypeInfo["MONSTER_EMOTE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL_JOIN"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL_LEAVE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL_LIST"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL_NOTICE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL_NOTICE_USER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["TARGETICONS"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["AFK"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["DND"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["IGNORED"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["SKILL"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["LOOT"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["MONEY"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["OPENING"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["TRADESKILLS"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["PET_INFO"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["COMBAT_MISC_INFO"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["COMBAT_XP_GAIN"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["COMBAT_HONOR_GAIN"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["COMBAT_FACTION_CHANGE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BG_SYSTEM_NEUTRAL"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BG_SYSTEM_ALLIANCE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BG_SYSTEM_HORDE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["RAID_LEADER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["RAID_WARNING"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["RAID_BOSS_WHISPER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["RAID_BOSS_EMOTE"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["FILTERED"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BATTLEGROUND"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BATTLEGROUND_LEADER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["RESTRICTED"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL1"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL2"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL3"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL4"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL5"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL6"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL7"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL8"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL9"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["CHANNEL10"] = { sticky = 1, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["ACHIEVEMENT"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["GUILD_ACHIEVEMENT"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["PARTY_LEADER"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BN_WHISPER"] = { sticky = 1, flashTab = true, flashTabOnGeneral = true };
+ChatTypeInfo["BN_WHISPER_INFORM"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BN_CONVERSATION"] = { sticky = 1, flashTab = true, flashTabOnGeneral = false };
+ChatTypeInfo["BN_CONVERSATION_NOTICE"] = { sticky = 0, flashTab = true, flashTabOnGeneral = false };
+ChatTypeInfo["BN_CONVERSATION_LIST"] = { sticky = 0, flashTab = true, flashTabOnGeneral = false };
+ChatTypeInfo["BN_ALERT"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BN_BROADCAST"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BN_BROADCAST_INFORM"] = { sticky = 0, flashTab = false, flashTabOnGeneral = false };
+ChatTypeInfo["BN_INLINE_TOAST_ALERT"] = { sticky = 0, flashTab = true, flashTabOnGeneral = false };
+ChatTypeInfo["BN_INLINE_TOAST_BROADCAST"] = { sticky = 0, flashTab = true, flashTabOnGeneral = false };
+ChatTypeInfo["BN_INLINE_TOAST_BROADCAST_INFORM"] = { sticky = 0, flashTab = true, flashTabOnGeneral = false };
+ChatTypeInfo["BN_INLINE_TOAST_CONVERSATION"] = { sticky = 0, flashTab = true, flashTabOnGeneral = false };
+
+ChatTypeGroup = {};
+ChatTypeGroup["SYSTEM"] = {
+ "CHAT_MSG_SYSTEM",
+ "TIME_PLAYED_MSG",
+ "PLAYER_LEVEL_UP",
+ "CHARACTER_POINTS_CHANGED",
+};
+ChatTypeGroup["SAY"] = {
+ "CHAT_MSG_SAY",
+};
+ChatTypeGroup["EMOTE"] = {
+ "CHAT_MSG_EMOTE",
+ "CHAT_MSG_TEXT_EMOTE",
+};
+ChatTypeGroup["YELL"] = {
+ "CHAT_MSG_YELL",
+};
+ChatTypeGroup["WHISPER"] = {
+ "CHAT_MSG_WHISPER",
+ "CHAT_MSG_WHISPER_INFORM",
+ "CHAT_MSG_AFK",
+ "CHAT_MSG_DND",
+};
+ChatTypeGroup["PARTY"] = {
+ "CHAT_MSG_PARTY",
+ "CHAT_MSG_MONSTER_PARTY",
+};
+ChatTypeGroup["PARTY_LEADER"] = {
+ "CHAT_MSG_PARTY_LEADER",
+};
+ChatTypeGroup["RAID"] = {
+ "CHAT_MSG_RAID",
+};
+ChatTypeGroup["RAID_LEADER"] = {
+ "CHAT_MSG_RAID_LEADER",
+};
+ChatTypeGroup["RAID_WARNING"] = {
+ "CHAT_MSG_RAID_WARNING",
+};
+ChatTypeGroup["BATTLEGROUND"] = {
+ "CHAT_MSG_BATTLEGROUND",
+};
+ChatTypeGroup["BATTLEGROUND_LEADER"] = {
+ "CHAT_MSG_BATTLEGROUND_LEADER",
+};
+ChatTypeGroup["GUILD"] = {
+ "CHAT_MSG_GUILD",
+ "GUILD_MOTD",
+};
+ChatTypeGroup["OFFICER"] = {
+ "CHAT_MSG_OFFICER",
+};
+ChatTypeGroup["MONSTER_SAY"] = {
+ "CHAT_MSG_MONSTER_SAY",
+};
+ChatTypeGroup["MONSTER_YELL"] = {
+ "CHAT_MSG_MONSTER_YELL",
+};
+ChatTypeGroup["MONSTER_EMOTE"] = {
+ "CHAT_MSG_MONSTER_EMOTE",
+};
+ChatTypeGroup["MONSTER_WHISPER"] = {
+ "CHAT_MSG_MONSTER_WHISPER",
+};
+ChatTypeGroup["MONSTER_BOSS_EMOTE"] = {
+ "CHAT_MSG_RAID_BOSS_EMOTE",
+};
+ChatTypeGroup["MONSTER_BOSS_WHISPER"] = {
+ "CHAT_MSG_RAID_BOSS_WHISPER",
+};
+ChatTypeGroup["ERRORS"] = {
+ "CHAT_MSG_RESTRICTED",
+ "CHAT_MSG_FILTERED",
+};
+ChatTypeGroup["AFK"] = {
+ "CHAT_MSG_AFK",
+};
+ChatTypeGroup["DND"] = {
+ "CHAT_MSG_DND",
+};
+ChatTypeGroup["IGNORED"] = {
+ "CHAT_MSG_IGNORED",
+};
+ChatTypeGroup["BG_HORDE"] = {
+ "CHAT_MSG_BG_SYSTEM_HORDE",
+};
+ChatTypeGroup["BG_ALLIANCE"] = {
+ "CHAT_MSG_BG_SYSTEM_ALLIANCE",
+};
+ChatTypeGroup["BG_NEUTRAL"] = {
+ "CHAT_MSG_BG_SYSTEM_NEUTRAL",
+};
+ChatTypeGroup["COMBAT_XP_GAIN"] = {
+ "CHAT_MSG_COMBAT_XP_GAIN";
+}
+ChatTypeGroup["COMBAT_HONOR_GAIN"] = {
+ "CHAT_MSG_COMBAT_HONOR_GAIN";
+}
+ChatTypeGroup["COMBAT_FACTION_CHANGE"] = {
+ "CHAT_MSG_COMBAT_FACTION_CHANGE";
+};
+ChatTypeGroup["SKILL"] = {
+ "CHAT_MSG_SKILL",
+};
+ChatTypeGroup["LOOT"] = {
+ "CHAT_MSG_LOOT",
+};
+ChatTypeGroup["MONEY"] = {
+ "CHAT_MSG_MONEY",
+};
+ChatTypeGroup["OPENING"] = {
+ "CHAT_MSG_OPENING";
+};
+ChatTypeGroup["TRADESKILLS"] = {
+ "CHAT_MSG_TRADESKILLS";
+};
+ChatTypeGroup["PET_INFO"] = {
+ "CHAT_MSG_PET_INFO";
+};
+ChatTypeGroup["COMBAT_MISC_INFO"] = {
+ "CHAT_MSG_COMBAT_MISC_INFO";
+};
+ChatTypeGroup["ACHIEVEMENT"] = {
+ "CHAT_MSG_ACHIEVEMENT";
+};
+ChatTypeGroup["GUILD_ACHIEVEMENT"] = {
+ "CHAT_MSG_GUILD_ACHIEVEMENT";
+};
+ChatTypeGroup["CHANNEL"] = {
+ "CHAT_MSG_CHANNEL_JOIN",
+ "CHAT_MSG_CHANNEL_LEAVE",
+ "CHAT_MSG_CHANNEL_NOTICE",
+ "CHAT_MSG_CHANNEL_NOTICE_USER",
+ "CHAT_MSG_CHANNEL_LIST",
+};
+ChatTypeGroup["TARGETICONS"] = {
+ "CHAT_MSG_TARGETICONS"
+};
+ChatTypeGroup["BN_WHISPER"] = {
+ "CHAT_MSG_BN_WHISPER",
+ "CHAT_MSG_BN_WHISPER_INFORM",
+};
+ChatTypeGroup["BN_CONVERSATION"] = {
+ "CHAT_MSG_BN_CONVERSATION",
+ "CHAT_MSG_BN_CONVERSATION_NOTICE",
+ "CHAT_MSG_BN_CONVERSATION_LIST",
+};
+ChatTypeGroup["BN_INLINE_TOAST_ALERT"] = {
+ "CHAT_MSG_BN_INLINE_TOAST_ALERT",
+ "CHAT_MSG_BN_INLINE_TOAST_BROADCAST",
+ "CHAT_MSG_BN_INLINE_TOAST_BROADCAST_INFORM",
+ "CHAT_MSG_BN_INLINE_TOAST_CONVERSATION",
+};
+ChatTypeGroupInverted = {};
+for group, values in pairs(ChatTypeGroup) do
+ for _, value in pairs(values) do
+ ChatTypeGroupInverted[value] = group;
+ end
+end
+
+CHAT_CATEGORY_LIST = {
+ PARTY = { "PARTY_LEADER", "PARTY_GUIDE", "MONSTER_PARTY" },
+ RAID = { "RAID_LEADER", "RAID_WARNING" },
+ GUILD = { "GUILD_ACHIEVEMENT" },
+ WHISPER = { "WHISPER_INFORM", "AFK", "DND" },
+ CHANNEL = { "CHANNEL_JOIN", "CHANNEL_LEAVE", "CHANNEL_NOTICE", "CHANNEL_USER" },
+ BATTLEGROUND = { "BATTLEGROUND_LEADER" },
+ BN_WHISPER = { "BN_WHISPER_INFORM" },
+ BN_CONVERSATION = { "BN_CONVERSATION_NOTICE", "BN_CONVERSATION_LIST" },
+};
+
+CHAT_INVERTED_CATEGORY_LIST = {};
+for category, sublist in pairs(CHAT_CATEGORY_LIST) do
+ for _, item in pairs(sublist) do
+ CHAT_INVERTED_CATEGORY_LIST[item] = category;
+ end
+end
+
+function Chat_GetChatCategory(chatType)
+ return CHAT_INVERTED_CATEGORY_LIST[chatType] or chatType;
+end
+
+ChannelMenuChatTypeGroups = {};
+ChannelMenuChatTypeGroups[1] = "SAY";
+ChannelMenuChatTypeGroups[2] = "YELL";
+ChannelMenuChatTypeGroups[3] = "GUILD";
+ChannelMenuChatTypeGroups[4] = "WHISPER";
+ChannelMenuChatTypeGroups[5] = "PARTY";
+
+CombatLogMenuChatTypeGroups = {};
+CombatLogMenuChatTypeGroups[1] = "OPENING";
+CombatLogMenuChatTypeGroups[2] = "TRADESKILLS";
+CombatLogMenuChatTypeGroups[3] = "PET_INFO";
+CombatLogMenuChatTypeGroups[4] = "COMBAT_MISC_INFO";
+CombatLogMenuChatTypeGroups[5] = "COMBAT_XP_GAIN";
+CombatLogMenuChatTypeGroups[6] = "COMBAT_HONOR_GAIN";
+CombatLogMenuChatTypeGroups[7] = "COMBAT_FACTION_CHANGE";
+
+OtherMenuChatTypeGroups = {};
+OtherMenuChatTypeGroups[1] = "CREATURE";
+OtherMenuChatTypeGroups[2] = "SKILL";
+OtherMenuChatTypeGroups[3] = "LOOT";
+
+-- list of text emotes that we want to show on the Emote submenu (these have anims)
+EmoteList = {
+ "WAVE",
+ "BOW",
+ "DANCE",
+ "APPLAUD",
+ "BEG",
+ "CHICKEN",
+ "CRY",
+ "EAT",
+ "FLEX",
+ "KISS",
+ "LAUGH",
+ "POINT",
+ "ROAR",
+ "RUDE",
+ "SALUTE",
+ "SHY",
+ "TALK",
+ "STAND",
+ "SIT",
+ "SLEEP",
+ "KNEEL",
+};
+
+-- list of text emotes that we want to show on the Speech submenu (these have sounds)
+TextEmoteSpeechList = {
+ "HELPME",
+ "INCOMING",
+ "CHARGE",
+ "FLEE",
+ "ATTACKMYTARGET",
+ "OOM",
+ "FOLLOW",
+ "WAIT",
+ "HEALME",
+ "CHEER",
+ "OPENFIRE",
+ "RASP",
+ "HELLO",
+ "BYE",
+ "NOD",
+ "NO",
+ "THANK",
+ "WELCOME",
+ "CONGRATULATE",
+ "FLIRT",
+ "JOKE",
+ "TRAIN",
+};
+
+-- These are text emote tokens - add new ones at the bottom of the list!
+EMOTE1_TOKEN = "AGREE";
+EMOTE2_TOKEN = "AMAZE";
+EMOTE3_TOKEN = "ANGRY";
+EMOTE4_TOKEN = "APOLOGIZE";
+EMOTE5_TOKEN = "APPLAUD";
+EMOTE6_TOKEN = "BASHFUL";
+EMOTE7_TOKEN = "BECKON";
+EMOTE8_TOKEN = "BEG";
+EMOTE9_TOKEN = "BITE";
+EMOTE10_TOKEN = "BLEED";
+EMOTE11_TOKEN = "BLINK";
+EMOTE12_TOKEN = "BLUSH";
+EMOTE13_TOKEN = "BONK";
+EMOTE14_TOKEN = "BORED";
+EMOTE15_TOKEN = "BOUNCE";
+EMOTE16_TOKEN = "BRB";
+EMOTE17_TOKEN = "BOW";
+EMOTE18_TOKEN = "BURP";
+EMOTE19_TOKEN = "BYE";
+EMOTE20_TOKEN = "CACKLE";
+EMOTE21_TOKEN = "CHEER";
+EMOTE22_TOKEN = "CHICKEN";
+EMOTE23_TOKEN = "CHUCKLE";
+EMOTE24_TOKEN = "CLAP";
+EMOTE25_TOKEN = "CONFUSED";
+EMOTE26_TOKEN = "CONGRATULATE";
+EMOTE27_TOKEN = "UNUSED";
+EMOTE28_TOKEN = "COUGH";
+EMOTE29_TOKEN = "COWER";
+EMOTE30_TOKEN = "CRACK";
+EMOTE31_TOKEN = "CRINGE";
+EMOTE32_TOKEN = "CRY";
+EMOTE33_TOKEN = "CURIOUS";
+EMOTE34_TOKEN = "CURTSEY";
+EMOTE35_TOKEN = "DANCE";
+EMOTE36_TOKEN = "DRINK";
+EMOTE37_TOKEN = "DROOL";
+EMOTE38_TOKEN = "EAT";
+EMOTE39_TOKEN = "EYE";
+EMOTE40_TOKEN = "FART";
+EMOTE41_TOKEN = "FIDGET";
+EMOTE42_TOKEN = "FLEX";
+EMOTE43_TOKEN = "FROWN";
+EMOTE44_TOKEN = "GASP";
+EMOTE45_TOKEN = "GAZE";
+EMOTE46_TOKEN = "GIGGLE";
+EMOTE47_TOKEN = "GLARE";
+EMOTE48_TOKEN = "GLOAT";
+EMOTE49_TOKEN = "GREET";
+EMOTE50_TOKEN = "GRIN";
+EMOTE51_TOKEN = "GROAN";
+EMOTE52_TOKEN = "GROVEL";
+EMOTE53_TOKEN = "GUFFAW";
+EMOTE54_TOKEN = "HAIL";
+EMOTE55_TOKEN = "HAPPY";
+EMOTE56_TOKEN = "HELLO";
+EMOTE57_TOKEN = "HUG";
+EMOTE58_TOKEN = "HUNGRY";
+EMOTE59_TOKEN = "KISS";
+EMOTE60_TOKEN = "KNEEL";
+EMOTE61_TOKEN = "LAUGH";
+EMOTE62_TOKEN = "LAYDOWN";
+EMOTE63_TOKEN = "MASSAGE";
+EMOTE64_TOKEN = "MOAN";
+EMOTE65_TOKEN = "MOON";
+EMOTE66_TOKEN = "MOURN";
+EMOTE67_TOKEN = "NO";
+EMOTE68_TOKEN = "NOD";
+EMOTE69_TOKEN = "NOSEPICK";
+EMOTE70_TOKEN = "PANIC";
+EMOTE71_TOKEN = "PEER";
+EMOTE72_TOKEN = "PLEAD";
+EMOTE73_TOKEN = "POINT";
+EMOTE74_TOKEN = "POKE";
+EMOTE75_TOKEN = "PRAY";
+EMOTE76_TOKEN = "ROAR";
+EMOTE77_TOKEN = "ROFL";
+EMOTE78_TOKEN = "RUDE";
+EMOTE79_TOKEN = "SALUTE";
+EMOTE80_TOKEN = "SCRATCH";
+EMOTE81_TOKEN = "SEXY";
+EMOTE82_TOKEN = "SHAKE";
+EMOTE83_TOKEN = "SHOUT";
+EMOTE84_TOKEN = "SHRUG";
+EMOTE85_TOKEN = "SHY";
+EMOTE86_TOKEN = "SIGH";
+EMOTE87_TOKEN = "SIT";
+EMOTE88_TOKEN = "SLEEP";
+EMOTE89_TOKEN = "SNARL";
+EMOTE90_TOKEN = "SPIT";
+EMOTE91_TOKEN = "STARE";
+EMOTE92_TOKEN = "SURPRISED";
+EMOTE93_TOKEN = "SURRENDER";
+EMOTE94_TOKEN = "TALK";
+EMOTE95_TOKEN = "TALKEX";
+EMOTE96_TOKEN = "TALKQ";
+EMOTE97_TOKEN = "TAP";
+EMOTE98_TOKEN = "THANK";
+EMOTE99_TOKEN = "THREATEN";
+EMOTE100_TOKEN = "TIRED";
+EMOTE101_TOKEN = "VICTORY";
+EMOTE102_TOKEN = "WAVE";
+EMOTE103_TOKEN = "WELCOME";
+EMOTE104_TOKEN = "WHINE";
+EMOTE105_TOKEN = "WHISTLE";
+EMOTE106_TOKEN = "WORK";
+EMOTE107_TOKEN = "YAWN";
+EMOTE108_TOKEN = "BOGGLE";
+EMOTE109_TOKEN = "CALM";
+EMOTE110_TOKEN = "COLD";
+EMOTE111_TOKEN = "COMFORT";
+EMOTE112_TOKEN = "CUDDLE";
+EMOTE113_TOKEN = "DUCK";
+EMOTE114_TOKEN = "INSULT";
+EMOTE115_TOKEN = "INTRODUCE";
+EMOTE116_TOKEN = "JK";
+EMOTE117_TOKEN = "LICK";
+EMOTE118_TOKEN = "LISTEN";
+EMOTE119_TOKEN = "LOST";
+EMOTE120_TOKEN = "MOCK";
+EMOTE121_TOKEN = "PONDER";
+EMOTE122_TOKEN = "POUNCE";
+EMOTE123_TOKEN = "PRAISE";
+EMOTE124_TOKEN = "PURR";
+EMOTE125_TOKEN = "PUZZLE";
+EMOTE126_TOKEN = "RAISE";
+EMOTE127_TOKEN = "READY";
+EMOTE128_TOKEN = "SHIMMY";
+EMOTE129_TOKEN = "SHIVER";
+EMOTE130_TOKEN = "SHOO";
+EMOTE131_TOKEN = "SLAP";
+EMOTE132_TOKEN = "SMIRK";
+EMOTE133_TOKEN = "SNIFF";
+EMOTE134_TOKEN = "SNUB";
+EMOTE135_TOKEN = "SOOTHE";
+EMOTE136_TOKEN = "STINK";
+EMOTE137_TOKEN = "TAUNT";
+EMOTE138_TOKEN = "TEASE";
+EMOTE139_TOKEN = "THIRSTY";
+EMOTE140_TOKEN = "VETO";
+EMOTE141_TOKEN = "SNICKER";
+EMOTE142_TOKEN = "TICKLE";
+EMOTE143_TOKEN = "STAND";
+EMOTE144_TOKEN = "VIOLIN";
+EMOTE145_TOKEN = "SMILE";
+EMOTE146_TOKEN = "RASP";
+EMOTE147_TOKEN = "GROWL";
+EMOTE148_TOKEN = "BARK";
+EMOTE149_TOKEN = "PITY";
+EMOTE150_TOKEN = "SCARED";
+EMOTE151_TOKEN = "FLOP";
+EMOTE152_TOKEN = "LOVE";
+EMOTE153_TOKEN = "MOO";
+EMOTE154_TOKEN = "COMMEND";
+EMOTE155_TOKEN = "TRAIN";
+EMOTE156_TOKEN = "HELPME";
+EMOTE157_TOKEN = "INCOMING";
+EMOTE158_TOKEN = "OPENFIRE";
+EMOTE159_TOKEN = "CHARGE";
+EMOTE160_TOKEN = "FLEE";
+EMOTE161_TOKEN = "ATTACKMYTARGET";
+EMOTE162_TOKEN = "OOM";
+EMOTE163_TOKEN = "FOLLOW";
+EMOTE164_TOKEN = "WAIT";
+EMOTE165_TOKEN = "FLIRT";
+EMOTE166_TOKEN = "HEALME";
+EMOTE167_TOKEN = "JOKE";
+EMOTE168_TOKEN = "WINK";
+EMOTE169_TOKEN = "PAT";
+EMOTE170_TOKEN = "GOLFCLAP";
+EMOTE171_TOKEN = "MOUNTSPECIAL";
+EMOTE304_TOKEN = "INCOMING";
+EMOTE306_TOKEN = "FLEE";
+EMOTE368_TOKEN = "BLAME"
+EMOTE369_TOKEN = "BLANK"
+EMOTE370_TOKEN = "BRANDISH"
+EMOTE371_TOKEN = "BREATH"
+EMOTE372_TOKEN = "DISAGREE"
+EMOTE373_TOKEN = "DOUBT"
+EMOTE374_TOKEN = "EMBARRASS"
+EMOTE375_TOKEN = "ENCOURAGE"
+EMOTE376_TOKEN = "ENEMY"
+EMOTE377_TOKEN = "EYEBROW"
+EMOTE380_TOKEN = "HIGHFIVE"
+EMOTE381_TOKEN = "ABSENT"
+EMOTE382_TOKEN = "ARM"
+EMOTE383_TOKEN = "AWE"
+EMOTE384_TOKEN = "BACKPACK"
+EMOTE385_TOKEN = "BADFEELING"
+EMOTE386_TOKEN = "CHALLENGE"
+EMOTE387_TOKEN = "CHUG"
+EMOTE389_TOKEN = "DING"
+EMOTE390_TOKEN = "FACEPALM"
+EMOTE391_TOKEN = "FAINT"
+EMOTE392_TOKEN = "GO"
+EMOTE393_TOKEN = "GOING"
+EMOTE394_TOKEN = "GLOWER"
+EMOTE395_TOKEN = "HEADACHE"
+EMOTE396_TOKEN = "HICCUP"
+EMOTE398_TOKEN = "HISS"
+EMOTE399_TOKEN = "HOLDHAND"
+EMOTE401_TOKEN = "HURRY"
+EMOTE402_TOKEN = "IDEA"
+EMOTE403_TOKEN = "JEALOUS"
+EMOTE404_TOKEN = "LUCK"
+EMOTE405_TOKEN = "MAP"
+EMOTE406_TOKEN = "MERCY"
+EMOTE407_TOKEN = "MUTTER"
+EMOTE408_TOKEN = "NERVOUS"
+EMOTE409_TOKEN = "OFFER"
+EMOTE410_TOKEN = "PET"
+EMOTE411_TOKEN = "PINCH"
+EMOTE413_TOKEN = "PROUD"
+EMOTE414_TOKEN = "PROMISE"
+EMOTE415_TOKEN = "PULSE"
+EMOTE416_TOKEN = "PUNCH"
+EMOTE417_TOKEN = "POUT"
+EMOTE418_TOKEN = "REGRET"
+EMOTE420_TOKEN = "REVENGE"
+EMOTE421_TOKEN = "ROLLEYES"
+EMOTE422_TOKEN = "RUFFLE"
+EMOTE423_TOKEN = "SAD"
+EMOTE424_TOKEN = "SCOFF"
+EMOTE425_TOKEN = "SCOLD"
+EMOTE426_TOKEN = "SCOWL"
+EMOTE427_TOKEN = "SEARCH"
+EMOTE428_TOKEN = "SHAKEFIST"
+EMOTE429_TOKEN = "SHIFTY"
+EMOTE430_TOKEN = "SHUDDER"
+EMOTE431_TOKEN = "SIGNAL"
+EMOTE432_TOKEN = "SILENCE"
+EMOTE433_TOKEN = "SING"
+EMOTE434_TOKEN = "SMACK"
+EMOTE435_TOKEN = "SNEAK"
+EMOTE436_TOKEN = "SNEEZE"
+EMOTE437_TOKEN = "SNORT"
+EMOTE438_TOKEN = "SQUEAL"
+EMOTE440_TOKEN = "SUSPICIOUS"
+EMOTE441_TOKEN = "THINK"
+EMOTE442_TOKEN = "TRUCE"
+EMOTE443_TOKEN = "TWIDDLE"
+EMOTE444_TOKEN = "WARN"
+EMOTE445_TOKEN = "SNAP"
+EMOTE446_TOKEN = "CHARM"
+EMOTE447_TOKEN = "COVEREARS"
+EMOTE448_TOKEN = "CROSSARMS"
+EMOTE449_TOKEN = "LOOK"
+EMOTE450_TOKEN = "OBJECT"
+EMOTE451_TOKEN = "SWEAT"
+EMOTE452_TOKEN = "YW"
+local MAXEMOTEINDEX = 452;
+
+
+ICON_LIST = {
+ "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_1:",
+ "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_2:",
+ "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_3:",
+ "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_4:",
+ "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_5:",
+ "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_6:",
+ "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_7:",
+ "|TInterface\\TargetingFrame\\UI-RaidTargetingIcon_8:",
+}
+
+--Links tags from Global Strings to indicies for entries in ICON_LIST. This way addons can easily replace icons
+ICON_TAG_LIST =
+{
+ [strlower(ICON_TAG_RAID_TARGET_STAR1)] = 1,
+ [strlower(ICON_TAG_RAID_TARGET_STAR2)] = 1,
+ [strlower(ICON_TAG_RAID_TARGET_CIRCLE1)] = 2,
+ [strlower(ICON_TAG_RAID_TARGET_CIRCLE2)] = 2,
+ [strlower(ICON_TAG_RAID_TARGET_DIAMOND1)] = 3,
+ [strlower(ICON_TAG_RAID_TARGET_DIAMOND2)] = 3,
+ [strlower(ICON_TAG_RAID_TARGET_TRIANGLE1)] = 4,
+ [strlower(ICON_TAG_RAID_TARGET_TRIANGLE2)] = 4,
+ [strlower(ICON_TAG_RAID_TARGET_MOON1)] = 5,
+ [strlower(ICON_TAG_RAID_TARGET_MOON2)] = 5,
+ [strlower(ICON_TAG_RAID_TARGET_SQUARE1)] = 6,
+ [strlower(ICON_TAG_RAID_TARGET_SQUARE2)] = 6,
+ [strlower(ICON_TAG_RAID_TARGET_CROSS1)] = 7,
+ [strlower(ICON_TAG_RAID_TARGET_CROSS2)] = 7,
+ [strlower(ICON_TAG_RAID_TARGET_SKULL1)] = 8,
+ [strlower(ICON_TAG_RAID_TARGET_SKULL2)] = 8,
+ [strlower(RAID_TARGET_1)] = 1,
+ [strlower(RAID_TARGET_2)] = 2,
+ [strlower(RAID_TARGET_3)] = 3,
+ [strlower(RAID_TARGET_4)] = 4,
+ [strlower(RAID_TARGET_5)] = 5,
+ [strlower(RAID_TARGET_6)] = 6,
+ [strlower(RAID_TARGET_7)] = 7,
+ [strlower(RAID_TARGET_8)] = 8,
+}
+
+-- Arena Team Helper Function
+function ArenaTeam_GetTeamSizeID(teamsizearg)
+ local teamname, teamsize, id;
+ for i=1, MAX_ARENA_TEAMS do
+ teamname, teamsize = GetArenaTeam(i)
+ if ( teamsizearg == teamsize ) then
+ id = i;
+ end
+ end
+ return id;
+end
+
+--
+-- CastSequence support
+--
+
+local CastSequenceManager;
+local CastSequenceTable = {};
+local CastSequenceFreeList = {};
+
+local function CreateCanonicalActions(entry, ...)
+ entry.spells = {};
+ entry.spellNames = {};
+ entry.items = {};
+ for i=1, select("#", ...) do
+ local action = strlower(strtrim((select(i, ...))));
+ if ( GetItemInfo(action) or select(3, SecureCmdItemParse(action)) ) then
+ entry.items[i] = action;
+ entry.spells[i] = strlower(GetItemSpell(action) or "");
+ entry.spellNames[i] = entry.spells[i];
+ else
+ entry.spells[i] = action;
+ entry.spellNames[i] = gsub(action, "!*(.*)", "%1");
+ end
+ end
+end
+
+local function SetCastSequenceIndex(entry, index)
+ entry.index = index;
+ entry.pending = nil;
+end
+
+local function ResetCastSequence(sequence, entry)
+ SetCastSequenceIndex(entry, 1);
+ CastSequenceFreeList[sequence] = entry;
+ CastSequenceTable[sequence] = nil;
+end
+
+local function SetNextCastSequence(sequence, entry)
+ if ( entry.index == #entry.spells ) then
+ ResetCastSequence(sequence, entry);
+ else
+ SetCastSequenceIndex(entry, entry.index + 1);
+ end
+end
+
+local function CastSequenceManager_OnEvent(self, event, ...)
+
+ -- Reset all sequences when the player dies
+ if ( event == "PLAYER_DEAD" ) then
+ for sequence, entry in pairs(CastSequenceTable) do
+ ResetCastSequence(sequence, entry);
+ end
+ return;
+ end
+
+ -- Increment sequences for spells which succeed.
+ if ( event == "UNIT_SPELLCAST_SENT" or
+ event == "UNIT_SPELLCAST_SUCCEEDED" or
+ event == "UNIT_SPELLCAST_INTERRUPTED" or
+ event == "UNIT_SPELLCAST_FAILED" or
+ event == "UNIT_SPELLCAST_FAILED_QUIET" ) then
+ local unit, name, rank = ...;
+
+ if ( not name ) then
+ -- This was a server-side only spell affecting the player somehow, don't do anything with cast sequencing, just bail.
+ return;
+ end
+
+ if ( unit == "player" or unit == "pet" ) then
+ name, rank = strlower(name), strlower(rank);
+ local nameplus = name.."()";
+ local fullname = name.."("..rank..")";
+ for sequence, entry in pairs(CastSequenceTable) do
+ local entryName = entry.spellNames[entry.index];
+ if ( entryName == name or entryName == nameplus or entryName == fullname ) then
+ if ( event == "UNIT_SPELLCAST_SENT" ) then
+ entry.pending = 1;
+ else
+ entry.pending = nil;
+ if ( event == "UNIT_SPELLCAST_SUCCEEDED" ) then
+ SetNextCastSequence(sequence, entry);
+ end
+ end
+ end
+ end
+ end
+ return;
+ end
+
+ -- Handle reset events
+ local reset = "";
+ if ( event == "PLAYER_TARGET_CHANGED" ) then
+ reset = "target";
+ elseif ( event == "PLAYER_REGEN_ENABLED" ) then
+ reset = "combat";
+ end
+ for sequence, entry in pairs(CastSequenceTable) do
+ if ( strfind(entry.reset, reset, 1, true) ) then
+ ResetCastSequence(sequence, entry);
+ end
+ end
+end
+
+local function CastSequenceManager_OnUpdate(self, elapsed)
+ elapsed = self.elapsed + elapsed;
+ if ( elapsed < 1 ) then
+ self.elapsed = elapsed;
+ return;
+ end
+ for sequence, entry in pairs(CastSequenceTable) do
+ if ( entry.timeout ) then
+ if ( elapsed >= entry.timeout ) then
+ ResetCastSequence(sequence, entry);
+ else
+ entry.timeout = entry.timeout - elapsed;
+ end
+ end
+ end
+ self.elapsed = 0;
+end
+
+local function ExecuteCastSequence(sequence, target)
+ if ( not CastSequenceManager ) then
+ CastSequenceManager = CreateFrame("Frame");
+ CastSequenceManager.elapsed = 0;
+ CastSequenceManager:RegisterEvent("PLAYER_DEAD");
+ CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_SENT");
+ CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED");
+ CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED");
+ CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_FAILED");
+ CastSequenceManager:RegisterEvent("UNIT_SPELLCAST_FAILED_QUIET");
+ CastSequenceManager:RegisterEvent("PLAYER_TARGET_CHANGED");
+ CastSequenceManager:RegisterEvent("PLAYER_REGEN_ENABLED");
+ CastSequenceManager:SetScript("OnEvent", CastSequenceManager_OnEvent);
+ CastSequenceManager:SetScript("OnUpdate", CastSequenceManager_OnUpdate);
+ end
+
+ local entry = CastSequenceTable[sequence];
+ if ( not entry ) then
+ entry = CastSequenceFreeList[sequence];
+ if ( not entry ) then
+ local reset, spells = strmatch(sequence, "^reset=([^%s]+)%s*(.*)");
+ if ( not reset ) then
+ spells = sequence;
+ end
+ entry = {};
+ CreateCanonicalActions(entry, strsplit(",", spells));
+ entry.reset = strlower(reset or "");
+ end
+ CastSequenceTable[sequence] = entry;
+ entry.index = 1;
+ end
+
+ -- Don't do anything if this entry is still pending
+ if ( entry.pending ) then
+ return;
+ end
+
+ -- See if modified click restarts the sequence
+ if ( (IsShiftKeyDown() and strfind(entry.reset, "shift", 1, true)) or
+ (IsControlKeyDown() and strfind(entry.reset, "ctrl", 1, true)) or
+ (IsAltKeyDown() and strfind(entry.reset, "alt", 1, true)) ) then
+ SetCastSequenceIndex(entry, 1);
+ end
+
+ -- Reset the timeout each time the sequence is used
+ local timeout = strmatch(entry.reset, "(%d+)");
+ if ( timeout ) then
+ entry.timeout = CastSequenceManager.elapsed + tonumber(timeout);
+ end
+
+ -- Execute the sequence!
+ local item, spell = entry.items[entry.index], entry.spells[entry.index];
+ if ( item ) then
+ local name, bag, slot = SecureCmdItemParse(item);
+ if ( slot ) then
+ if ( name ) then
+ spell = strlower(GetItemSpell(name) or "");
+ else
+ spell = "";
+ end
+ entry.spellNames[entry.index] = spell;
+ end
+ if ( IsEquippableItem(name) and not IsEquippedItem(name) ) then
+ EquipItemByName(name);
+ else
+ SecureCmdUseItem(name, bag, slot, target);
+ end
+ else
+ CastSpellByName(spell, target);
+ end
+ if ( spell == "" ) then
+ SetNextCastSequence(sequence, entry);
+ end
+end
+
+function QueryCastSequence(sequence)
+ local index = 1;
+ local item, spell;
+ local entry = CastSequenceTable[sequence];
+ if ( entry ) then
+ if ( (IsShiftKeyDown() and strfind(entry.reset, "shift", 1, true)) or
+ (IsControlKeyDown() and strfind(entry.reset, "ctrl", 1, true)) or
+ (IsAltKeyDown() and strfind(entry.reset, "alt", 1, true)) ) then
+ index = 1;
+ else
+ index = entry.index;
+ end
+ item, spell = entry.items[index], entry.spells[index];
+ else
+ entry = CastSequenceFreeList[sequence];
+ if ( entry ) then
+ item, spell = entry.items[index], entry.spells[index];
+ else
+ local reset, spells = strmatch(sequence, "^reset=([^%s]+)%s*(.*)");
+ if ( not reset ) then
+ spells = sequence;
+ end
+ local action = strlower(strtrim((strsplit(",", spells))));
+ if ( GetItemInfo(action) or select(3, SecureCmdItemParse(action)) ) then
+ item, spell = action, strlower(GetItemSpell(action) or "");
+ else
+ item, spell = nil, action;
+ end
+ end
+ end
+ if ( item ) then
+ local name, bag, slot = SecureCmdItemParse(item);
+ if ( slot ) then
+ if ( name ) then
+ spell = strlower(GetItemSpell(name) or "");
+ else
+ spell = "";
+ end
+ end
+ end
+ return index, item, spell;
+end
+
+
+local CastRandomManager;
+local CastRandomTable = {};
+
+local function CastRandomManager_OnEvent(self, event, ...)
+ local unit, name, rank = ...;
+
+ if ( not name ) then
+ -- This was a server-side only spell affecting the player somehow, don't do anything with cast sequencing, just bail.
+ return;
+ end
+
+ if ( unit == "player" ) then
+ name, rank = strlower(name), strlower(rank);
+ local nameplus = name.."()";
+ local fullname = name.."("..rank..")";
+ for sequence, entry in pairs(CastRandomTable) do
+ if ( entry.pending and entry.value ) then
+ local entryName = strlower(entry.value);
+ if ( entryName == name or entryName == nameplus or entryName == fullname ) then
+ entry.pending = nil;
+ if ( event == "UNIT_SPELLCAST_SUCCEEDED" ) then
+ entry.value = nil;
+ end
+ end
+ end
+ end
+ end
+end
+
+local function ExecuteCastRandom(actions)
+ if ( not CastRandomManager ) then
+ CastRandomManager = CreateFrame("Frame");
+ CastRandomManager:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED");
+ CastRandomManager:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED");
+ CastRandomManager:RegisterEvent("UNIT_SPELLCAST_FAILED");
+ CastRandomManager:RegisterEvent("UNIT_SPELLCAST_FAILED_QUIET");
+ CastRandomManager:SetScript("OnEvent", CastRandomManager_OnEvent);
+ end
+
+ local entry = CastRandomTable[actions];
+ if ( not entry ) then
+ entry = {};
+ CreateCanonicalActions(entry, strsplit(",", actions));
+ CastRandomTable[actions] = entry;
+ end
+ if ( not entry.value ) then
+ entry.value = strtrim(GetRandomArgument(strsplit(",", actions)));
+ end
+ entry.pending = true;
+ return entry.value;
+end
+
+function GetRandomArgument(...)
+ return (select(random(select("#", ...)), ...));
+end
+
+-- Slash commands that are protected from tampering
+local SecureCmdList = { };
+
+function IsSecureCmd(command)
+ command = strupper(command);
+ -- first check the hash table
+ if ( hash_SecureCmdList[command] ) then
+ return true;
+ end
+
+ for index, value in pairs(SecureCmdList) do
+ local i = 1;
+ local cmdString = _G["SLASH_"..index..i];
+ while ( cmdString ) do
+ cmdString = strupper(cmdString);
+ if ( cmdString == command ) then
+ return true;
+ end
+ i = i + 1;
+ cmdString = _G["SLASH_"..index..i];
+ end
+ end
+end
+
+function SecureCmdItemParse(item)
+ if ( not item ) then
+ return nil, nil, nil;
+ end
+ local bag, slot = strmatch(item, "^(%d+)%s+(%d+)$");
+ if ( not bag ) then
+ slot = strmatch(item, "^(%d+)$");
+ end
+ if ( bag ) then
+ item = GetContainerItemLink(bag, slot);
+ elseif ( slot ) then
+ item = GetInventoryItemLink("player", slot);
+ end
+ return item, bag, slot;
+end
+
+function SecureCmdUseItem(name, bag, slot, target)
+ if ( bag ) then
+ UseContainerItem(bag, slot, target);
+ elseif ( slot ) then
+ UseInventoryItem(slot, target);
+ else
+ UseItemByName(name, target);
+ end
+end
+
+SecureCmdList["STARTATTACK"] = function(msg)
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target or target == "target" ) then
+ target = action;
+ end
+ StartAttack(target);
+ end
+end
+
+SecureCmdList["STOPATTACK"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ StopAttack();
+ end
+end
+
+SecureCmdList["CAST"] = function(msg)
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ local name, bag, slot = SecureCmdItemParse(action);
+ if ( slot or GetItemInfo(name) ) then
+ SecureCmdUseItem(name, bag, slot, target);
+ else
+ CastSpellByName(action, target);
+ end
+ end
+end
+SecureCmdList["USE"] = SecureCmdList["CAST"];
+
+SecureCmdList["CASTRANDOM"] = function(msg)
+ local actions, target = SecureCmdOptionParse(msg);
+ if ( actions ) then
+ local action = ExecuteCastRandom(actions);
+ local name, bag, slot = SecureCmdItemParse(action);
+ if ( slot or GetItemInfo(name) ) then
+ SecureCmdUseItem(name, bag, slot, target);
+ else
+ CastSpellByName(action, target);
+ end
+ end
+end
+SecureCmdList["USERANDOM"] = SecureCmdList["CASTRANDOM"];
+
+SecureCmdList["CASTSEQUENCE"] = function(msg)
+ local sequence, target = SecureCmdOptionParse(msg);
+ if ( sequence ) then
+ ExecuteCastSequence(sequence, target);
+ end
+end
+
+SecureCmdList["STOPCASTING"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ SpellStopCasting();
+ end
+end
+
+SecureCmdList["CANCELAURA"] = function(msg)
+ local spell = SecureCmdOptionParse(msg);
+ if ( spell ) then
+ local name, rank = strmatch(spell, "([^(]+)[(]([^)]+)[)]");
+ if ( not name ) then
+ name = spell;
+ end
+ CancelUnitBuff("player", name, rank);
+ end
+end
+
+SecureCmdList["CANCELFORM"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ CancelShapeshiftForm();
+ end
+end
+
+SecureCmdList["EQUIP"] = function(msg)
+ local item = SecureCmdOptionParse(msg);
+ if ( item ) then
+ EquipItemByName((SecureCmdItemParse(item)));
+ end
+end
+
+SecureCmdList["EQUIP_TO_SLOT"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ local slot, item = strmatch(action, "^(%d+)%s+(.*)");
+ if ( item ) then
+ if ( PaperDoll_IsEquippedSlot(slot) ) then
+ EquipItemByName(SecureCmdItemParse(item), slot);
+ else
+ -- user specified a bad slot number (slot that you can't equip an item to)
+ ChatFrame_DisplayUsageError(format(ERROR_SLASH_EQUIP_TO_SLOT, EQUIPPED_FIRST, EQUIPPED_LAST));
+ end
+ elseif ( slot ) then
+ -- user specified a slot but not an item
+ ChatFrame_DisplayUsageError(format(ERROR_SLASH_EQUIP_TO_SLOT, EQUIPPED_FIRST, EQUIPPED_LAST));
+ end
+ end
+end
+
+SecureCmdList["CHANGEACTIONBAR"] = function(msg)
+ local page = SecureCmdOptionParse(msg);
+ if ( page and page ~= "" ) then
+ page = tonumber(page);
+ if (page and page >= 1 and page <= NUM_ACTIONBAR_PAGES) then
+ ChangeActionBarPage(page);
+ else
+ ChatFrame_DisplayUsageError(format(ERROR_SLASH_CHANGEACTIONBAR, 1, NUM_ACTIONBAR_PAGES));
+ end
+ end
+end
+
+SecureCmdList["SWAPACTIONBAR"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ local a, b = strmatch(action, "(%d+)%s+(%d+)");
+ if ( a and b ) then
+ a = tonumber(a);
+ b = tonumber(b);
+ if ( ( a and a >= 1 and a <= NUM_ACTIONBAR_PAGES ) and ( b and b >= 1 and b <= NUM_ACTIONBAR_PAGES ) ) then
+ if ( GetActionBarPage() == a ) then
+ ChangeActionBarPage(b);
+ else
+ ChangeActionBarPage(a);
+ end
+ else
+ ChatFrame_DisplayUsageError(format(ERROR_SLASH_SWAPACTIONBAR, 1, NUM_ACTIONBAR_PAGES));
+ end
+ end
+ end
+end
+
+SecureCmdList["TARGET"] = function(msg)
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target or target == "target" ) then
+ target = action;
+ end
+ TargetUnit(target);
+ end
+end
+
+SecureCmdList["TARGET_EXACT"] = function(msg)
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target or target == "target" ) then
+ target = action;
+ end
+ TargetUnit(target, 1);
+ end
+end
+
+SecureCmdList["TARGET_NEAREST_ENEMY"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ TargetNearestEnemy(action);
+ end
+end
+
+SecureCmdList["TARGET_NEAREST_ENEMY_PLAYER"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ TargetNearestEnemyPlayer(action);
+ end
+end
+
+SecureCmdList["TARGET_NEAREST_FRIEND"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ TargetNearestFriend(action);
+ end
+end
+
+SecureCmdList["TARGET_NEAREST_FRIEND_PLAYER"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ TargetNearestFriendPlayer(action);
+ end
+end
+
+SecureCmdList["TARGET_NEAREST_PARTY"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ TargetNearestPartyMember(action);
+ end
+end
+
+SecureCmdList["TARGET_NEAREST_RAID"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ TargetNearestRaidMember(action);
+ end
+end
+
+SecureCmdList["CLEARTARGET"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ ClearTarget();
+ end
+end
+
+SecureCmdList["TARGET_LAST_TARGET"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ TargetLastTarget();
+ end
+end
+
+SecureCmdList["TARGET_LAST_ENEMY"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ TargetLastEnemy(action);
+ end
+end
+
+SecureCmdList["TARGET_LAST_FRIEND"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action ) then
+ TargetLastFriend(action);
+ end
+end
+
+SecureCmdList["ASSIST"] = function(msg)
+ if ( msg == "" ) then
+ AssistUnit();
+ else
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target ) then
+ target = action;
+ end
+ AssistUnit(target);
+ end
+ end
+end
+
+SecureCmdList["FOCUS"] = function(msg)
+ if ( msg == "" ) then
+ FocusUnit();
+ else
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target or target == "focus" ) then
+ target = action;
+ end
+ FocusUnit(target);
+ end
+ end
+end
+
+SecureCmdList["CLEARFOCUS"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ ClearFocus();
+ end
+end
+
+SecureCmdList["CLEARMAINTANK"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ ClearPartyAssignment("MAINTANK");
+ end
+end
+
+SecureCmdList["MAINTANKON"] = function(msg)
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target ) then
+ target = action;
+ end
+ if ( target == "" ) then
+ target = "target";
+ end
+ SetPartyAssignment("MAINTANK", target);
+ end
+end
+
+SecureCmdList["MAINTANKOFF"] = function(msg)
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target ) then
+ target = action;
+ end
+ if ( target == "" ) then
+ target = "target";
+ end
+ ClearPartyAssignment("MAINTANK", target);
+ end
+end
+
+SecureCmdList["CLEARMAINASSIST"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ ClearPartyAssignment("MAINASSIST");
+ end
+end
+
+SecureCmdList["MAINASSISTON"] = function(msg)
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target ) then
+ target = action;
+ end
+ if ( target == "" ) then
+ target = "target";
+ end
+ SetPartyAssignment("MAINASSIST", target);
+ end
+end
+
+SecureCmdList["MAINASSISTOFF"] = function(msg)
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target ) then
+ target = action;
+ end
+ if ( target == "" ) then
+ target = "target";
+ end
+ ClearPartyAssignment("MAINASSIST", target);
+ end
+end
+
+SecureCmdList["DUEL"] = function(msg)
+ StartDuel(msg)
+end
+
+SecureCmdList["DUEL_CANCEL"] = function(msg)
+ CancelDuel()
+end
+
+SecureCmdList["PET_ATTACK"] = function(msg)
+ local action, target = SecureCmdOptionParse(msg);
+ if ( action ) then
+ if ( not target or target == "pettarget" ) then
+ target = action;
+ end
+ PetAttack(target);
+ end
+end
+
+SecureCmdList["PET_FOLLOW"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ PetFollow();
+ end
+end
+
+SecureCmdList["PET_STAY"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ PetWait();
+ end
+end
+
+SecureCmdList["PET_PASSIVE"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ PetPassiveMode();
+ end
+end
+
+SecureCmdList["PET_DEFENSIVE"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ PetDefensiveMode();
+ end
+end
+
+SecureCmdList["PET_AGGRESSIVE"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ PetAggressiveMode();
+ end
+end
+
+SecureCmdList["PET_AUTOCASTON"] = function(msg)
+ local spell = SecureCmdOptionParse(msg);
+ if ( spell ) then
+ EnableSpellAutocast(spell);
+ end
+end
+
+SecureCmdList["PET_AUTOCASTOFF"] = function(msg)
+ local spell = SecureCmdOptionParse(msg);
+ if ( spell ) then
+ DisableSpellAutocast(spell);
+ end
+end
+
+SecureCmdList["PET_AUTOCASTTOGGLE"] = function(msg)
+ local spell = SecureCmdOptionParse(msg);
+ if ( spell ) then
+ ToggleSpellAutocast(spell);
+ end
+end
+
+SecureCmdList["STOPMACRO"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ StopMacro();
+ end
+end
+
+SecureCmdList["CLICK"] = function(msg)
+ local action = SecureCmdOptionParse(msg);
+ if ( action and action ~= "" ) then
+ local name, mouseButton, down = strmatch(action, "([^%s]+)%s+([^%s]+)%s*(.*)");
+ if ( not name ) then
+ name = action;
+ end
+ local button = GetClickFrame(name);
+ if ( button and button:IsObjectType("Button") ) then
+ button:Click(mouseButton, down);
+ end
+ end
+end
+
+-- Pre-populate the secure command hash table
+for index, value in pairs(SecureCmdList) do
+ local i = 1;
+ local cmdString = _G["SLASH_"..index..i];
+ while ( cmdString ) do
+ cmdString = strupper(cmdString);
+ hash_SecureCmdList[cmdString] = value; -- add to hash
+ i = i + 1;
+ cmdString = _G["SLASH_"..index..i];
+ end
+end
+
+-- Slash commands
+SlashCmdList = { };
+
+SlashCmdList["CONSOLE"] = function(msg)
+ ConsoleExec(msg);
+end
+
+SlashCmdList["CHATLOG"] = function(msg)
+ local info = ChatTypeInfo["SYSTEM"];
+ if ( LoggingChat() ) then
+ LoggingChat(false);
+ DEFAULT_CHAT_FRAME:AddMessage(CHATLOGDISABLED, info.r, info.g, info.b, info.id);
+ else
+ LoggingChat(true);
+ DEFAULT_CHAT_FRAME:AddMessage(CHATLOGENABLED, info.r, info.g, info.b, info.id);
+ end
+end
+
+SlashCmdList["COMBATLOG"] = function(msg)
+ local info = ChatTypeInfo["SYSTEM"];
+ if ( LoggingCombat() ) then
+ LoggingCombat(false);
+ DEFAULT_CHAT_FRAME:AddMessage(COMBATLOGDISABLED, info.r, info.g, info.b, info.id);
+ else
+ LoggingCombat(true);
+ DEFAULT_CHAT_FRAME:AddMessage(COMBATLOGENABLED, info.r, info.g, info.b, info.id);
+ end
+end
+
+SlashCmdList["INVITE"] = function(msg)
+ if(msg == "") then
+ msg = UnitName("target");
+ end
+ if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ InviteUnit(msg);
+end
+
+SlashCmdList["UNINVITE"] = function(msg)
+ if(msg == "") then
+ msg = UnitName("target");
+ end
+ UninviteUnit(msg);
+end
+
+SlashCmdList["PROMOTE"] = function(msg)
+ PromoteToLeader(msg);
+end
+
+SlashCmdList["REPLY"] = function(msg, editBox)
+ local lastTell = ChatEdit_GetLastTellTarget();
+ if ( lastTell ~= "" ) then
+ SendChatMessage(msg, "WHISPER", editBox.language, lastTell);
+ else
+ -- error message
+ end
+end
+
+SlashCmdList["HELP"] = function(msg)
+ ChatFrame_DisplayHelpText(DEFAULT_CHAT_FRAME);
+end
+
+SlashCmdList["MACROHELP"] = function(msg)
+ ChatFrame_DisplayMacroHelpText(DEFAULT_CHAT_FRAME);
+end
+
+SlashCmdList["TIME"] = function(msg)
+ ChatFrame_DisplayGameTime(DEFAULT_CHAT_FRAME);
+end
+
+SlashCmdList["PLAYED"] = function(msg)
+ RequestTimePlayed();
+end
+
+SlashCmdList["FOLLOW"] = function(msg)
+ FollowUnit(msg);
+end
+
+SlashCmdList["TRADE"] = function(msg)
+ InitiateTrade("target");
+end
+
+SlashCmdList["INSPECT"] = function(msg)
+ InspectUnit("target");
+end
+
+SlashCmdList["LOGOUT"] = function(msg)
+ Logout();
+end
+
+SlashCmdList["QUIT"] = function(msg)
+ Quit();
+end
+
+SlashCmdList["JOIN"] = function(msg)
+ local name = gsub(msg, "%s*([^%s]+).*", "%1");
+ local password = gsub(msg, "%s*([^%s]+)%s*(.*)", "%2");
+ if(strlen(name) <= 0) then
+ local joinhelp = CHAT_JOIN_HELP;
+ local info = ChatTypeInfo["SYSTEM"];
+ DEFAULT_CHAT_FRAME:AddMessage(joinhelp, info.r, info.g, info.b, info.id);
+ else
+ local zoneChannel, channelName = JoinPermanentChannel(name, password, DEFAULT_CHAT_FRAME:GetID(), 1);
+ if ( channelName ) then
+ name = channelName;
+ end
+ if ( not zoneChannel ) then
+ local info = ChatTypeInfo["CHANNEL"];
+ DEFAULT_CHAT_FRAME:AddMessage(CHAT_INVALID_NAME_NOTICE, info.r, info.g, info.b, info.id);
+ return;
+ end
+
+ local i = 1;
+ while ( DEFAULT_CHAT_FRAME.channelList[i] ) do
+ i = i + 1;
+ end
+ DEFAULT_CHAT_FRAME.channelList[i] = name;
+ DEFAULT_CHAT_FRAME.zoneChannelList[i] = zoneChannel;
+ end
+end
+
+SlashCmdList["LEAVE"] = function(msg)
+ local name = strmatch(msg, "%s*([^%s]+)");
+ if ( name ) then
+ local nameNum = tonumber(name);
+ if ( nameNum and nameNum > MAX_WOW_CHAT_CHANNELS ) then
+ BNLeaveConversation(nameNum - MAX_WOW_CHAT_CHANNELS);
+ else
+ LeaveChannelByName(name);
+ end
+ end
+
+end
+
+SlashCmdList["LIST_CHANNEL"] = function(msg)
+ local name = strmatch(msg, "%s*([^%s]+)");
+ if ( name ) then
+ local nameNum = tonumber(name);
+ if ( nameNum and nameNum > MAX_WOW_CHAT_CHANNELS ) then
+ BNListConversation(nameNum - MAX_WOW_CHAT_CHANNELS);
+ else
+ ListChannelByName(name);
+ end
+ else
+ ListChannels();
+ end
+end
+
+SlashCmdList["CHAT_HELP"] =
+ function(msg)
+ ChatFrame_DisplayChatHelp(DEFAULT_CHAT_FRAME)
+ end
+
+SlashCmdList["CHAT_PASSWORD"] =
+ function(msg)
+ local name = gsub(msg, "%s*([^%s]+).*", "%1");
+ local password = gsub(msg, "%s*([^%s]+)%s*(.*)", "%2");
+ SetChannelPassword(name, password);
+ end
+
+SlashCmdList["CHAT_OWNER"] =
+ function(msg)
+ local channel = gsub(msg, "%s*([^%s]+).*", "%1");
+ local newOwner = gsub(msg, "%s*([^%s]+)%s*(.*)", "%2");
+ if ( not channel or not newOwner ) then
+ return;
+ end
+ local newOwnerLen = strlen(newOwner);
+ if ( newOwnerLen > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ if ( strlen(channel) > 0 ) then
+ if ( newOwnerLen > 0 ) then
+ SetChannelOwner(channel, newOwner);
+ else
+ DisplayChannelOwner(channel);
+ end
+ end
+ end
+
+SlashCmdList["CHAT_MODERATOR"] =
+ function(msg)
+ local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
+ if ( not channel or not player ) then
+ return;
+ end
+ if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ ChannelModerator(channel, player);
+ end
+
+SlashCmdList["CHAT_UNMODERATOR"] =
+ function(msg)
+ local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
+ if ( not channel or not player ) then
+ return;
+ end
+ if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ if ( channel and player ) then
+ ChannelUnmoderator(channel, player);
+ end
+ end
+
+SlashCmdList["CHAT_MUTE"] =
+ function(msg)
+ local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
+ if ( not channel or not player ) then
+ return;
+ end
+ if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ if ( channel and player ) then
+ ChannelMute(channel, player);
+ end
+ end
+
+SlashCmdList["CHAT_UNMUTE"] =
+ function(msg)
+ local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
+ if ( not channel or not player ) then
+ return;
+ end
+ if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ if ( channel and player ) then
+ ChannelUnmute(channel, player);
+ end
+ end
+
+SlashCmdList["CHAT_CINVITE"] =
+ function(msg)
+ local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
+ if ( not channel or not player ) then
+ return;
+ end
+
+ if ( channel and player ) then
+ if ( tonumber(channel) and tonumber(channel) > MAX_WOW_CHAT_CHANNELS ) then
+ --We have a BNet conversation.
+ channel = tonumber(channel) - MAX_WOW_CHAT_CHANNELS;
+ if ( BNGetConversationInfo(channel) ) then
+ local presenceID = BNet_GetPresenceID(player);
+ if ( presenceID ) then
+ BNInviteToConversation(channel, presenceID);
+ end
+ end
+ else
+ if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ ChannelInvite(channel, player);
+ end
+ end
+ end
+
+SlashCmdList["CHAT_KICK"] =
+ function(msg)
+ local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
+ if ( not channel or not player ) then
+ return;
+ end
+ if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ if ( channel and player ) then
+ ChannelKick(channel, player);
+ end
+ end
+
+SlashCmdList["CHAT_BAN"] =
+ function(msg)
+ local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
+ if ( not channel or not player ) then
+ return;
+ end
+ if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ if ( channel and player ) then
+ ChannelBan(channel, player);
+ end
+ end
+
+SlashCmdList["CHAT_UNBAN"] =
+ function(msg)
+ local channel, player = strmatch(msg, "%s*([^%s]+)%s*(.*)");
+ if ( not channel or not player ) then
+ return;
+ end
+ if ( strlen(player) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ if ( channel and player ) then
+ ChannelUnban(channel, player);
+ end
+ end
+
+SlashCmdList["CHAT_ANNOUNCE"] =
+ function(msg)
+ local channel = strmatch(msg, "%s*([^%s]+)");
+ if ( channel ) then
+ ChannelToggleAnnouncements(channel);
+ end
+ end
+
+SlashCmdList["TEAM_INVITE"] = function(msg)
+ if ( msg ~= "" ) then
+ local team, name = strmatch(msg, "^(%d+)[%w+%d+]*%s+(.*)");
+ if ( team and name ) then
+ if ( strlen(name) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ team = tonumber(team);
+ if ( team ) then
+ local teamsizeID = ArenaTeam_GetTeamSizeID(team);
+ if ( teamsizeID ) then
+ ArenaTeamInviteByName(teamsizeID, name);
+ end
+ return;
+ end
+ end
+ end
+ ChatFrame_DisplayUsageError(ERROR_SLASH_TEAM_INVITE);
+end
+
+SlashCmdList["TEAM_QUIT"] = function(msg)
+ if ( msg ~= "" ) then
+ local team = strmatch(msg, "^(%d+)[%w+%d+]*");
+ if ( team ) then
+ team = tonumber(team);
+ if ( team ) then
+ local teamsizeID = ArenaTeam_GetTeamSizeID(team);
+ if ( teamsizeID ) then
+ ArenaTeamLeave(teamsizeID);
+ end
+ return;
+ end
+ end
+ end
+ ChatFrame_DisplayUsageError(ERROR_SLASH_TEAM_QUIT);
+end
+
+SlashCmdList["TEAM_UNINVITE"] = function(msg)
+ if ( msg ~= "" ) then
+ local team, name = strmatch(msg, "^(%d+)[%w+%d+]*%s+(.*)");
+ if ( team and name ) then
+ if ( strlen(name) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ team = tonumber(team);
+ if ( team ) then
+ local teamsizeID = ArenaTeam_GetTeamSizeID(team);
+ if ( teamsizeID ) then
+ ArenaTeamUninviteByName(teamsizeID, name);
+ end
+ return;
+ end
+ end
+ end
+ ChatFrame_DisplayUsageError(ERROR_SLASH_TEAM_UNINVITE);
+end
+
+SlashCmdList["TEAM_CAPTAIN"] = function(msg)
+ if ( msg ~= "" ) then
+ local team, name = strmatch(msg, "^(%d+)[%w+%d+]*%s+(.*)");
+ if ( team and name ) then
+ if ( strlen(name) > MAX_CHARACTER_NAME_BYTES ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ team = tonumber(team);
+ if ( team ) then
+ local teamsizeID = ArenaTeam_GetTeamSizeID(team);
+ if ( teamsizeID ) then
+ ArenaTeamSetLeaderByName(teamsizeID, name);
+ end
+ return;
+ end
+ end
+ end
+ ChatFrame_DisplayUsageError(ERROR_SLASH_TEAM_CAPTAIN);
+end
+
+SlashCmdList["TEAM_DISBAND"] = function(msg)
+ if ( msg ~= "" ) then
+ local team = strmatch(msg, "^(%d+)[%w+%d+]*");
+ if ( team ) then
+ team = tonumber(team);
+ if ( team ) then
+ local teamsizeID = ArenaTeam_GetTeamSizeID(team);
+ if ( teamsizeID ) then
+ local teamName, teamSize = GetArenaTeam(teamsizeID);
+ for i = 1, teamSize * 2 do
+ name, rank = GetArenaTeamRosterInfo(teamsizeID, i);
+ if ( rank == 0 ) then
+ if ( name == UnitName("player") ) then
+ local dialog = StaticPopup_Show("CONFIRM_TEAM_DISBAND", teamName);
+ if ( dialog ) then
+ dialog.data = teamsizeID;
+ end
+ end
+ break;
+ end
+ end
+ end
+ return;
+ end
+ end
+ end
+ ChatFrame_DisplayUsageError(ERROR_SLASH_TEAM_DISBAND);
+end
+
+SlashCmdList["GUILD_INVITE"] = function(msg)
+ if(msg == "") then
+ msg = UnitName("target");
+ end
+ if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ GuildInvite(msg);
+end
+
+SlashCmdList["GUILD_UNINVITE"] = function(msg)
+ if(msg == "") then
+ msg = UnitName("target");
+ end
+ if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ GuildUninvite(msg);
+end
+
+SlashCmdList["GUILD_PROMOTE"] = function(msg)
+ if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ GuildPromote(msg);
+end
+
+SlashCmdList["GUILD_DEMOTE"] = function(msg)
+ if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ GuildDemote(msg);
+end
+
+SlashCmdList["GUILD_LEADER"] = function(msg)
+ if( msg and (strlen(msg) > MAX_CHARACTER_NAME_BYTES) ) then
+ ChatFrame_DisplayUsageError(ERR_NAME_TOO_LONG2);
+ return;
+ end
+ GuildSetLeader(msg);
+end
+
+SlashCmdList["GUILD_MOTD"] = function(msg)
+ GuildSetMOTD(msg)
+end
+
+SlashCmdList["GUILD_LEAVE"] = function(msg)
+ GuildLeave();
+end
+
+SlashCmdList["GUILD_DISBAND"] = function(msg)
+ if ( IsGuildLeader() ) then
+ StaticPopup_Show("CONFIRM_GUILD_DISBAND");
+ end
+end
+
+SlashCmdList["GUILD_INFO"] = function(msg)
+ GuildInfo();
+end
+
+SlashCmdList["GUILD_ROSTER"] = function(msg)
+ if ( IsInGuild() ) then
+ PanelTemplates_SetTab(FriendsFrame, 3);
+ FriendsFrame_ShowSubFrame("GuildFrame");
+ ShowUIPanel(FriendsFrame);
+ end
+end
+
+--SlashCmdList["GUILD_HELP"] = function(msg)
+-- ChatFrame_DisplayGuildHelp(DEFAULT_CHAT_FRAME);
+--end
+
+SlashCmdList["CHAT_AFK"] = function(msg)
+ SendChatMessage(msg, "AFK");
+end
+
+SlashCmdList["CHAT_DND"] = function(msg)
+ SendChatMessage(msg, "DND");
+end
+
+SlashCmdList["WHO"] = function(msg)
+ if ( msg == "" ) then
+ msg = WhoFrame_GetDefaultWhoCommand();
+ ShowWhoPanel();
+ end
+ WhoFrameEditBox:SetText(msg);
+ SendWho(msg);
+end
+
+SlashCmdList["CHANNEL"] = function(msg, editBox)
+ SendChatMessage(msg, "CHANNEL", editBox.language, editBox:GetAttribute("channelTarget"));
+end
+
+SlashCmdList["FRIENDS"] = function(msg)
+ local player, note = strmatch(msg, "%s*([^%s]+)%s*(.*)");
+ if ( player ~= "" or UnitIsPlayer("target") ) then
+ AddOrRemoveFriend(player, note);
+ else
+ ToggleFriendsPanel();
+ end
+end
+
+SlashCmdList["REMOVEFRIEND"] = function(msg)
+ RemoveFriend(msg);
+end
+
+SlashCmdList["IGNORE"] = function(msg)
+ if ( msg ~= "" or UnitIsPlayer("target") ) then
+ local presenceID = BNet_GetPresenceID(msg);
+ if ( presenceID ) then
+ if ( BNIsFriend(presenceID) ) then
+ SendSystemMessage(ERR_CANNOT_IGNORE_BN_FRIEND);
+ else
+ BNSetToonBlocked(presenceID, not BNIsToonBlocked(presenceID));
+ end
+ else
+ AddOrDelIgnore(msg);
+ end
+ else
+ ToggleIgnorePanel();
+ end
+end
+
+SlashCmdList["UNIGNORE"] = function(msg)
+ if ( msg ~= "" or UnitIsPlayer("target") ) then
+ DelIgnore(msg);
+ else
+ ToggleIgnorePanel();
+ end
+end
+
+SlashCmdList["SCRIPT"] = function(msg)
+ RunScript(msg);
+end
+
+SlashCmdList["LOOT_FFA"] = function(msg)
+ SetLootMethod("freeforall");
+end
+
+SlashCmdList["LOOT_ROUNDROBIN"] = function(msg)
+ SetLootMethod("roundrobin");
+end
+
+SlashCmdList["LOOT_MASTER"] = function(msg)
+ SetLootMethod("master", msg);
+end
+
+SlashCmdList["LOOT_GROUP"] = function(msg)
+ SetLootMethod("group");
+end
+
+SlashCmdList["LOOT_NEEDBEFOREGREED"] = function(msg)
+ SetLootMethod("needbeforegreed");
+end
+
+SlashCmdList["LOOT_SETTHRESHOLD"] = function(msg)
+ if ( not msg ) then
+ local info = ChatTypeInfo["SYSTEM"];
+ DEFAULT_CHAT_FRAME:AddMessage(format(ERROR_SLASH_LOOT_SETTHRESHOLD, MIN_LOOT_THRESHOLD, MAX_LOOT_THRESHOLD), info.r, info.g, info.b, info.id);
+ return;
+ end
+
+ local MIN_LOOT_THRESHOLD = 2; -- "good" item quality
+ local MAX_LOOT_THRESHOLD = 6; -- "artifact" item quality
+
+ local threshold = strmatch(msg, "(%d+)");
+ threshold = tonumber(threshold);
+ if ( threshold and threshold >= MIN_LOOT_THRESHOLD and threshold <= MAX_LOOT_THRESHOLD ) then
+ -- try to match a threshold number first
+ SetLootThreshold(threshold);
+ else
+ msg = strupper(msg);
+ if ( msg == strupper(ITEM_QUALITY2_DESC) ) then
+ SetLootThreshold(2);
+ elseif ( msg == strupper(ITEM_QUALITY3_DESC) ) then
+ SetLootThreshold(3);
+ elseif ( msg == strupper(ITEM_QUALITY4_DESC) ) then
+ SetLootThreshold(4);
+ elseif ( msg == strupper(ITEM_QUALITY5_DESC) ) then
+ SetLootThreshold(5);
+ elseif ( msg == strupper(ITEM_QUALITY6_DESC) ) then
+ SetLootThreshold(6);
+ else
+ -- no matches found
+ local info = ChatTypeInfo["SYSTEM"];
+ DEFAULT_CHAT_FRAME:AddMessage(format(ERROR_SLASH_LOOT_SETTHRESHOLD, MIN_LOOT_THRESHOLD, MAX_LOOT_THRESHOLD), info.r, info.g, info.b, info.id);
+ end
+ end
+end
+
+SlashCmdList["RANDOM"] = function(msg)
+ local num1 = gsub(msg, "(%s*)(%d+)(.*)", "%2", 1);
+ local rest = gsub(msg, "(%s*)(%d+)(.*)", "%3", 1);
+ local num2 = "";
+ local numSubs;
+ if ( strlen(rest) > 0 ) then
+ num2, numSubs = gsub(msg, "(%s*)(%d+)([-%s]+)(%d+)(.*)", "%4", 1);
+ if ( numSubs == 0 ) then
+ num2 = "";
+ end
+ end
+ if ( num1 == "" and num2 == "" ) then
+ RandomRoll("1", "100");
+ elseif ( num2 == "" ) then
+ RandomRoll("1", num1);
+ else
+ RandomRoll(num1, num2);
+ end
+end
+
+SlashCmdList["MACRO"] = function(msg)
+ ShowMacroFrame();
+end
+
+SlashCmdList["PVP"] = function(msg)
+ TogglePVP();
+end
+
+SlashCmdList["RAID_INFO"] = function(msg)
+ RaidFrame.slashCommand = 1;
+ if ( ( GetNumSavedInstances() > 0 ) and not RaidInfoFrame:IsShown() ) then
+ ToggleFriendsFrame(5);
+ RaidInfoFrame:Show();
+ elseif ( not RaidFrame:IsShown() ) then
+ ToggleFriendsFrame(5);
+ end
+end
+
+SlashCmdList["READYCHECK"] = function(msg)
+ if ( ((IsRaidLeader() or IsRaidOfficer()) and GetNumRaidMembers() > 0) or (IsPartyLeader() and GetNumPartyMembers() > 0) ) then
+ DoReadyCheck();
+ end
+end
+
+--[[All of this information is obtainable through the armory now.
+SlashCmdList["SAVEGUILDROSTER"] = function(msg)
+ SaveGuildRoster();
+end]]
+
+SlashCmdList["DUNGEONS"] = function(msg)
+ ToggleLFDParentFrame();
+end
+
+SlashCmdList["RAIDBROWSER"] = function(msg)
+ ToggleLFRParentFrame();
+end
+
+SlashCmdList["BENCHMARK"] = function(msg)
+ SetTaxiBenchmarkMode(msg);
+end
+
+SlashCmdList["DISMOUNT"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ Dismount();
+ end
+end
+
+SlashCmdList["LEAVEVEHICLE"] = function(msg)
+ if ( SecureCmdOptionParse(msg) ) then
+ VehicleExit();
+ end
+end
+
+SlashCmdList["RESETCHAT"] = function(msg)
+ FCF_ResetAllWindows();
+end
+
+SlashCmdList["ENABLE_ADDONS"] = function(msg)
+ EnableAllAddOns();
+ ReloadUI();
+end
+
+SlashCmdList["DISABLE_ADDONS"] = function(msg)
+ DisableAllAddOns();
+ ReloadUI();
+end
+
+SlashCmdList["STOPWATCH"] = function(msg)
+ if ( not IsAddOnLoaded("Blizzard_TimeManager") ) then
+ UIParentLoadAddOn("Blizzard_TimeManager");
+ end
+ if ( StopwatchFrame ) then
+ local text = strmatch(msg, "%s*([^%s]+)%s*");
+ if ( text ) then
+ text = strlower(text);
+
+ -- in any of the following cases, the stopwatch will be shown
+ StopwatchFrame:Show();
+
+ -- try to match a command
+ local function MatchCommand(param, text)
+ local i, compare;
+ i = 1;
+ repeat
+ compare = _G[param..i];
+ if ( compare and compare == text ) then
+ return true;
+ end
+ i = i + 1;
+ until ( not compare );
+ return false;
+ end
+ if ( MatchCommand("SLASH_STOPWATCH_PARAM_PLAY", text) ) then
+ Stopwatch_Play();
+ return;
+ end
+ if ( MatchCommand("SLASH_STOPWATCH_PARAM_PAUSE", text) ) then
+ Stopwatch_Pause();
+ return;
+ end
+ if ( MatchCommand("SLASH_STOPWATCH_PARAM_STOP", text) ) then
+ Stopwatch_Clear();
+ return;
+ end
+ -- try to match a countdown
+ -- kinda ghetto, but hey, it's simple and it works =)
+ local hour, minute, second = strmatch(msg, "(%d+):(%d+):(%d+)");
+ if ( not hour ) then
+ minute, second = strmatch(msg, "(%d+):(%d+)");
+ if ( not minute ) then
+ second = strmatch(msg, "(%d+)");
+ end
+ end
+ Stopwatch_StartCountdown(tonumber(hour), tonumber(minute), tonumber(second));
+ else
+ Stopwatch_Toggle();
+ end
+ end
+end
+
+SlashCmdList["CALENDAR"] = function(msg)
+ if ( not IsAddOnLoaded("Blizzard_Calendar") ) then
+ UIParentLoadAddOn("Blizzard_Calendar");
+ end
+ if ( Calendar_Toggle ) then
+ Calendar_Toggle();
+ end
+end
+
+SlashCmdList["ACHIEVEMENTUI"] = function(msg)
+ ToggleAchievementFrame();
+end
+
+SlashCmdList["EQUIP_SET"] = function(msg)
+ local set = SecureCmdOptionParse(msg);
+ if ( set and set ~= "" ) then
+ EquipmentManager_EquipSet(set);
+ end
+end
+
+SlashCmdList["SET_TITLE"] = function(msg)
+ local name = SecureCmdOptionParse(msg);
+ if ( name and name ~= "") then
+ if(not SetTitleByName(name)) then
+ UIErrorsFrame:AddMessage(TITLE_DOESNT_EXIST, 1.0, 0.1, 0.1, 1.0);
+ end
+ else
+ SetCurrentTitle(-1)
+ end
+end
+
+SlashCmdList["USE_TALENT_SPEC"] = function(msg)
+ local group = SecureCmdOptionParse(msg);
+ if ( group ) then
+ local groupNumber = tonumber(group);
+ if ( groupNumber ) then
+ SetActiveTalentGroup(groupNumber);
+ end
+ end
+end
+
+-- easier method to turn on/off errors for macros
+SlashCmdList["UI_ERRORS_OFF"] = function(msg)
+ UIErrorsFrame:UnregisterEvent("UI_ERROR_MESSAGE");
+ SetCVar("Sound_EnableSFX", "0");
+end
+
+SlashCmdList["UI_ERRORS_ON"] = function(msg)
+ UIErrorsFrame:RegisterEvent("UI_ERROR_MESSAGE");
+ SetCVar("Sound_EnableSFX", "1");
+end
+
+SlashCmdList["FRAMESTACK"] = function(msg)
+ UIParentLoadAddOn("Blizzard_DebugTools");
+ if(msg == tostring(true)) then
+ FrameStackTooltip_Toggle(true);
+ else
+ FrameStackTooltip_Toggle();
+ end
+end
+
+SlashCmdList["EVENTTRACE"] = function(msg)
+ UIParentLoadAddOn("Blizzard_DebugTools");
+ EventTraceFrame_HandleSlashCmd(msg);
+end
+
+SlashCmdList["DUMP"] = function(msg)
+ UIParentLoadAddOn("Blizzard_DebugTools");
+ DevTools_DumpCommand(msg);
+end
+
+SlashCmdList["RELOAD"] = function(msg)
+ ConsoleExec("reloadui");
+end
+
+for index, value in pairs(ChatTypeInfo) do
+ value.r = 1.0;
+ value.g = 1.0;
+ value.b = 1.0;
+ value.id = GetChatTypeIndex(index);
+end
+
+-- ChatFrame functions
+function ChatFrame_OnLoad(self)
+ self.flashTimer = 0;
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("UPDATE_CHAT_COLOR");
+ self:RegisterEvent("UPDATE_CHAT_WINDOWS");
+ self:RegisterEvent("CHAT_MSG_CHANNEL");
+ self:RegisterEvent("ZONE_UNDER_ATTACK");
+ self:RegisterEvent("UPDATE_INSTANCE_INFO");
+ self:RegisterEvent("NEW_TITLE_EARNED");
+ self:RegisterEvent("OLD_TITLE_LOST");
+ self:RegisterEvent("UPDATE_CHAT_COLOR_NAME_BY_CLASS");
+ self:RegisterEvent("VARIABLES_LOADED");
+ self.tellTimer = GetTime();
+ self.channelList = {};
+ self.zoneChannelList = {};
+ self.messageTypeList = {};
+
+ self.defaultLanguage = GetDefaultLanguage(); --If PLAYER_ENTERING_WORLD hasn't been called yet, this is nil, but it'll be fixed whent he event is fired.
+end
+
+function ChatFrame_RegisterForMessages(self, ...)
+ local messageGroup;
+ local index = 1;
+ for i=1, select("#", ...) do
+ messageGroup = ChatTypeGroup[select(i, ...)];
+ if ( messageGroup ) then
+ self.messageTypeList[index] = select(i, ...);
+ for index, value in pairs(messageGroup) do
+ self:RegisterEvent(value);
+ end
+ index = index + 1;
+ end
+ end
+end
+
+function ChatFrame_RegisterForChannels(self, ...)
+ local index = 1;
+ for i=1, select("#", ...), 2 do
+ self.channelList[index], self.zoneChannelList[index] = select(i, ...);
+ index = index + 1;
+ end
+end
+
+function ChatFrame_AddMessageGroup(chatFrame, group)
+ local info = ChatTypeGroup[group];
+ if ( info ) then
+ local i = 1;
+ while ( chatFrame.messageTypeList[i] ) do
+ i = i + 1;
+ end
+ chatFrame.messageTypeList[i] = group;
+ for index, value in pairs(info) do
+ chatFrame:RegisterEvent(value);
+ end
+ AddChatWindowMessages(chatFrame:GetID(), group);
+ end
+end
+
+function ChatFrame_RemoveMessageGroup(chatFrame, group)
+ local info = ChatTypeGroup[group];
+ if ( info ) then
+ for index, value in pairs(chatFrame.messageTypeList) do
+ if ( strupper(value) == strupper(group) ) then
+ chatFrame.messageTypeList[index] = nil;
+ end
+ end
+ for index, value in pairs(info) do
+ chatFrame:UnregisterEvent(value);
+ end
+ RemoveChatWindowMessages(chatFrame:GetID(), group);
+ end
+end
+
+function ChatFrame_RemoveAllMessageGroups(chatFrame)
+ for index, value in pairs(chatFrame.messageTypeList) do
+ for eventIndex, eventValue in pairs(ChatTypeGroup[value]) do
+ chatFrame:UnregisterEvent(eventValue);
+ end
+ RemoveChatWindowMessages(chatFrame:GetID(), value);
+ end
+
+ chatFrame.messageTypeList = {};
+end
+
+function ChatFrame_AddChannel(chatFrame, channel)
+ local zoneChannel = AddChatWindowChannel(chatFrame:GetID(), channel);
+ if ( zoneChannel ) then
+ local i = 1;
+ while ( chatFrame.channelList[i] ) do
+ i = i + 1;
+ end
+ chatFrame.channelList[i] = channel;
+ chatFrame.zoneChannelList[i] = zoneChannel;
+ end
+end
+
+function ChatFrame_RemoveChannel(chatFrame, channel)
+ for index, value in pairs(chatFrame.channelList) do
+ if ( strupper(channel) == strupper(value) ) then
+ chatFrame.channelList[index] = nil;
+ chatFrame.zoneChannelList[index] = nil;
+ end
+ end
+ RemoveChatWindowChannel(chatFrame:GetID(), channel);
+end
+
+function ChatFrame_RemoveAllChannels(chatFrame)
+ for index, value in pairs(chatFrame.channelList) do
+ RemoveChatWindowChannel(chatFrame:GetID(), value);
+ end
+ chatFrame.channelList = {};
+ chatFrame.zoneChannelList = {};
+end
+
+function ChatFrame_AddPrivateMessageTarget(chatFrame, chatTarget)
+ ChatFrame_RemoveExcludePrivateMessageTarget(chatFrame, chatTarget);
+ if ( chatFrame.privateMessageList ) then
+ chatFrame.privateMessageList[strlower(chatTarget)] = true;
+ else
+ chatFrame.privateMessageList = { [strlower(chatTarget)] = true };
+ end
+end
+
+function ChatFrame_RemovePrivateMessageTarget(chatFrame, chatTarget)
+ if ( chatFrame.privateMessageList ) then
+ chatFrame.privateMessageList[strlower(chatTarget)] = nil;
+ end
+end
+
+function ChatFrame_ExcludePrivateMessageTarget(chatFrame, chatTarget)
+ ChatFrame_RemovePrivateMessageTarget(chatFrame, chatTarget);
+ if ( chatFrame.excludePrivateMessageList ) then
+ chatFrame.excludePrivateMessageList[strlower(chatTarget)] = true;
+ else
+ chatFrame.excludePrivateMessageList = { [strlower(chatTarget)] = true };
+ end
+end
+
+function ChatFrame_RemoveExcludePrivateMessageTarget(chatFrame, chatTarget)
+ if ( chatFrame.excludePrivateMessageList ) then
+ chatFrame.excludePrivateMessageList[strlower(chatTarget)] = nil;
+ end
+end
+
+function ChatFrame_ReceiveAllPrivateMessages(chatFrame)
+ chatFrame.privateMessageList = nil;
+ chatFrame.excludePrivateMessageList = nil;
+end
+
+function ChatFrame_AddBNConversationTarget(chatFrame, chatTarget)
+ ChatFrame_RemoveExcludeBNConversationTarget(chatFrame, chatTarget);
+ if ( chatFrame.bnConversationList ) then
+ chatFrame.bnConversationList[tonumber(chatTarget)] = true;
+ else
+ chatFrame.bnConversationList = { [tonumber(chatTarget)] = true };
+ end
+end
+
+function ChatFrame_RemoveBNConversationTarget(chatFrame, chatTarget)
+ if ( chatFrame.bnConversationList ) then
+ chatFrame.bnConversationList[tonumber(chatTarget)] = nil;
+ end
+end
+
+function ChatFrame_ExcludeBNConversationTarget(chatFrame, chatTarget)
+ ChatFrame_RemoveBNConversationTarget(chatFrame, chatTarget);
+ if ( chatFrame.excludeBNConversationList ) then
+ chatFrame.excludeBNConversationList[tonumber(chatTarget)] = true;
+ else
+ chatFrame.excludeBNConversationList = { [tonumber(chatTarget)] = true };
+ end
+end
+
+function ChatFrame_RemoveExcludeBNConversationTarget(chatFrame, chatTarget)
+ if ( chatFrame.excludeBNConversationList ) then
+ chatFrame.excludeBNConversationList[tonumber(chatTarget)] = nil;
+ end
+end
+
+function ChatFrame_ReceiveAllBNConversations(chatFrame)
+ chatFrame.bnConversationList = nil;
+ chatFrame.excludeBNConversationList = nil;
+end
+
+-- Set up a private editbox to handle macro execution
+do
+ local function GetDefaultChatEditBox(field)
+ return DEFAULT_CHAT_FRAME.editBox;
+ end
+
+ local editbox = CreateFrame("Editbox", "MacroEditBox");
+ editbox:RegisterEvent("EXECUTE_CHAT_LINE");
+ editbox:SetScript("OnEvent",
+ function(self,event,line)
+ if ( event == "EXECUTE_CHAT_LINE" ) then
+ local defaulteditbox = securecall(GetDefaultChatEditBox);
+ self:SetAttribute("chatType", defaulteditbox:GetAttribute("chatType"));
+ self:SetAttribute("tellTarget", defaulteditbox:GetAttribute("tellTarget"));
+ self:SetAttribute("channelTarget", defaulteditbox:GetAttribute("channelTarget"));
+ self:SetText(line);
+ ChatEdit_SendText(self);
+ end
+ end
+ );
+ editbox:Hide();
+end
+
+function ChatFrame_OnEvent(self, event, ...)
+ if ( ChatFrame_ConfigEventHandler(self, event, ...) ) then
+ return;
+ end
+ if ( ChatFrame_SystemEventHandler(self, event, ...) ) then
+ return
+ end
+ if ( ChatFrame_MessageEventHandler(self, event, ...) ) then
+ return
+ end
+end
+
+function ChatFrame_ConfigEventHandler(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.defaultLanguage = GetDefaultLanguage();
+ return true;
+ elseif ( event == "UPDATE_CHAT_WINDOWS" ) then
+ local name, fontSize, r, g, b, a, shown, locked = FCF_GetChatWindowInfo(self:GetID());
+ if ( fontSize > 0 ) then
+ local fontFile, unused, fontFlags = self:GetFont();
+ self:SetFont(fontFile, fontSize, fontFlags);
+ end
+ if ( shown and not self.minimized ) then
+ self:Show();
+ end
+ -- Do more stuff!!!
+ ChatFrame_RegisterForMessages(self, GetChatWindowMessages(self:GetID()));
+ ChatFrame_RegisterForChannels(self, GetChatWindowChannels(self:GetID()));
+ return true;
+ end
+
+ local arg1, arg2, arg3, arg4 = ...;
+ if ( event == "UPDATE_CHAT_COLOR" ) then
+ local info = ChatTypeInfo[strupper(arg1)];
+ if ( info ) then
+ info.r = arg2;
+ info.g = arg3;
+ info.b = arg4;
+ self:UpdateColorByID(info.id, info.r, info.g, info.b);
+
+ if ( strupper(arg1) == "WHISPER" ) then
+ info = ChatTypeInfo["REPLY"];
+ if ( info ) then
+ info.r = arg2;
+ info.g = arg3;
+ info.b = arg4;
+ self:UpdateColorByID(info.id, info.r, info.g, info.b);
+ end
+ end
+ end
+ return true;
+ elseif ( event == "UPDATE_CHAT_COLOR_NAME_BY_CLASS" ) then
+ local info = ChatTypeInfo[strupper(arg1)];
+ if ( info ) then
+ info.colorNameByClass = arg2;
+ if ( strupper(arg1) == "WHISPER" ) then
+ info = ChatTypeInfo["REPLY"];
+ if ( info ) then
+ info.colorNameByClass = arg2;
+ end
+ end
+ end
+ return true;
+ elseif ( event == "VARIABLES_LOADED" ) then
+ if ( GetCVarBool("chatMouseScroll") ) then
+ self:SetScript("OnMouseWheel", FloatingChatFrame_OnMouseScroll);
+ self:EnableMouseWheel(true);
+ end
+ self:UnregisterEvent("VARIABLES_LOADED");
+ return true;
+ end
+end
+
+function ChatFrame_SystemEventHandler(self, event, ...)
+ if ( event == "TIME_PLAYED_MSG" ) then
+ local arg1, arg2 = ...;
+ ChatFrame_DisplayTimePlayed(self, arg1, arg2);
+ return true;
+ elseif ( event == "PLAYER_LEVEL_UP" ) then
+ local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 = ...;
+ -- Level up
+ local info = ChatTypeInfo["SYSTEM"];
+
+ local string = format(LEVEL_UP, arg1);
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+
+ if ( arg3 > 0 ) then
+ string = format(LEVEL_UP_HEALTH_MANA, arg2, arg3);
+ else
+ string = format(LEVEL_UP_HEALTH, arg2);
+ end
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+
+ if ( arg4 > 0 ) then
+ string = format(LEVEL_UP_CHAR_POINTS, arg4);
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+ end
+
+ if ( arg5 > 0 ) then
+ string = format(LEVEL_UP_STAT, SPELL_STAT1_NAME, arg5);
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+ end
+ if ( arg6 > 0 ) then
+ string = format(LEVEL_UP_STAT, SPELL_STAT2_NAME, arg6);
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+ end
+ if ( arg7 > 0 ) then
+ string = format(LEVEL_UP_STAT, SPELL_STAT3_NAME, arg7);
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+ end
+ if ( arg8 > 0 ) then
+ string = format(LEVEL_UP_STAT, SPELL_STAT4_NAME, arg8);
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+ end
+ if ( arg9 > 0 ) then
+ string = format(LEVEL_UP_STAT, SPELL_STAT5_NAME, arg9);
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+ end
+ return true;
+ elseif ( event == "CHARACTER_POINTS_CHANGED" ) then
+ local arg1, arg2 = ...;
+ local info = ChatTypeInfo["SYSTEM"];
+ if ( arg2 > 0 ) then
+ local cp1, cp2 = UnitCharacterPoints("player");
+ if ( cp2 ) then
+ local string = format(LEVEL_UP_SKILL_POINTS, cp2);
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+ end
+ end
+ return true;
+ elseif ( event == "GUILD_MOTD" ) then
+ local arg1 = ...;
+ if ( arg1 and (strlen(arg1) > 0) ) then
+ local info = ChatTypeInfo["GUILD"];
+ local string = format(GUILD_MOTD_TEMPLATE, arg1);
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+ end
+ return true;
+ elseif ( event == "ZONE_UNDER_ATTACK" ) then
+ local arg1 = ...;
+ local info = ChatTypeInfo["SYSTEM"];
+ self:AddMessage(format(ZONE_UNDER_ATTACK, arg1), info.r, info.g, info.b, info.id);
+ return true;
+ elseif ( event == "UPDATE_INSTANCE_INFO" ) then
+ if ( RaidFrame.hasRaidInfo ) then
+ local info = ChatTypeInfo["SYSTEM"];
+ if ( RaidFrame.slashCommand and GetNumSavedInstances() == 0 and self == DEFAULT_CHAT_FRAME) then
+ self:AddMessage(NO_RAID_INSTANCES_SAVED, info.r, info.g, info.b, info.id);
+ RaidFrame.slashCommand = nil;
+ end
+ end
+ return true;
+ elseif ( event == "NEW_TITLE_EARNED" ) then
+ local arg1 = ...;
+ local info = ChatTypeInfo["SYSTEM"];
+ self:AddMessage(format(NEW_TITLE_EARNED, arg1), info.r, info.g, info.b, info.id);
+ return true;
+ elseif ( event == "OLD_TITLE_LOST" ) then
+ local arg1 = ...;
+ local info = ChatTypeInfo["SYSTEM"];
+ self:AddMessage(format(OLD_TITLE_LOST, arg1), info.r, info.g, info.b, info.id);
+ return true;
+ end
+end
+
+function GetColoredName(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12)
+ local chatType = strsub(event, 10);
+ if ( strsub(chatType, 1, 7) == "WHISPER" ) then
+ chatType = "WHISPER";
+ end
+ if ( strsub(chatType, 1, 7) == "CHANNEL" ) then
+ chatType = "CHANNEL"..arg8;
+ end
+ local info = ChatTypeInfo[chatType];
+
+ if ( info and info.colorNameByClass and arg12 ~= "" ) then
+ local localizedClass, englishClass, localizedRace, englishRace, sex = GetPlayerInfoByGUID(arg12)
+
+ if ( englishClass ) then
+ local classColorTable = RAID_CLASS_COLORS[englishClass];
+ if ( not classColorTable ) then
+ return arg2;
+ end
+ return string.format("\124cff%.2x%.2x%.2x", classColorTable.r*255, classColorTable.g*255, classColorTable.b*255)..arg2.."\124r"
+ end
+ end
+
+ return arg2;
+end
+
+function ChatFrame_MessageEventHandler(self, event, ...)
+ if ( strsub(event, 1, 8) == "CHAT_MSG" ) then
+ local arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 = ...;
+ local type = strsub(event, 10);
+ local info = ChatTypeInfo[type];
+
+ local filter = false;
+ if ( chatFilters[event] ) then
+ local newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12;
+ for _, filterFunc in next, chatFilters[event] do
+ filter, newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12 = filterFunc(self, event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);
+ if ( filter ) then
+ return true;
+ elseif ( newarg1 ) then
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12 = newarg1, newarg2, newarg3, newarg4, newarg5, newarg6, newarg7, newarg8, newarg9, newarg10, newarg11, newarg12;
+ end
+ end
+ end
+
+ local coloredName = GetColoredName(event, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);
+
+ local channelLength = strlen(arg4);
+ local infoType = type;
+ if ( (strsub(type, 1, 7) == "CHANNEL") and (type ~= "CHANNEL_LIST") and ((arg1 ~= "INVITE") or (type ~= "CHANNEL_NOTICE_USER")) ) then
+ if ( arg1 == "WRONG_PASSWORD" ) then
+ local staticPopup = _G[StaticPopup_Visible("CHAT_CHANNEL_PASSWORD") or ""];
+ if ( staticPopup and strupper(staticPopup.data) == strupper(arg9) ) then
+ -- Don't display invalid password messages if we're going to prompt for a password (bug 102312)
+ return;
+ end
+ end
+
+ local found = 0;
+ for index, value in pairs(self.channelList) do
+ if ( channelLength > strlen(value) ) then
+ -- arg9 is the channel name without the number in front...
+ if ( ((arg7 > 0) and (self.zoneChannelList[index] == arg7)) or (strupper(value) == strupper(arg9)) ) then
+ found = 1;
+ infoType = "CHANNEL"..arg8;
+ info = ChatTypeInfo[infoType];
+ if ( (type == "CHANNEL_NOTICE") and (arg1 == "YOU_LEFT") ) then
+ self.channelList[index] = nil;
+ self.zoneChannelList[index] = nil;
+ end
+ break;
+ end
+ end
+ end
+ if ( (found == 0) or not info ) then
+ return true;
+ end
+ end
+
+ local chatGroup = Chat_GetChatCategory(type);
+ local chatTarget;
+ if ( chatGroup == "CHANNEL" or chatGroup == "BN_CONVERSATION" ) then
+ chatTarget = tostring(arg8);
+ elseif ( chatGroup == "WHISPER" or chatGroup == "BN_WHISPER" ) then
+ chatTarget = strupper(arg2);
+ end
+
+ if ( FCFManager_ShouldSuppressMessage(self, chatGroup, chatTarget) ) then
+ return true;
+ end
+
+ if ( chatGroup == "WHISPER" or chatGroup == "BN_WHISPER" ) then
+ if ( self.privateMessageList and not self.privateMessageList[strlower(arg2)] ) then
+ return true;
+ elseif ( self.excludePrivateMessageList and self.excludePrivateMessageList[strlower(arg2)] ) then
+ return true;
+ end
+ elseif ( chatGroup == "BN_CONVERSATION" ) then
+ if ( self.bnConversationList and not self.bnConversationList[arg8] ) then
+ return true;
+ elseif ( self.excludeBNConversationList and self.excludeBNConversationList[arg8] ) then
+ return true;
+ end
+ end
+
+ if ( type == "SYSTEM" or type == "SKILL" or type == "LOOT" or type == "MONEY" or
+ type == "OPENING" or type == "TRADESKILLS" or type == "PET_INFO" or type == "TARGETICONS") then
+ self:AddMessage(arg1, info.r, info.g, info.b, info.id);
+ elseif ( strsub(type,1,7) == "COMBAT_" ) then
+ self:AddMessage(arg1, info.r, info.g, info.b, info.id);
+ elseif ( strsub(type,1,6) == "SPELL_" ) then
+ self:AddMessage(arg1, info.r, info.g, info.b, info.id);
+ elseif ( strsub(type,1,10) == "BG_SYSTEM_" ) then
+ self:AddMessage(arg1, info.r, info.g, info.b, info.id);
+ elseif ( strsub(type,1,11) == "ACHIEVEMENT" ) then
+ self:AddMessage(format(arg1, "|Hplayer:"..arg2.."|h".."["..coloredName.."]".."|h"), info.r, info.g, info.b, info.id);
+ elseif ( strsub(type,1,18) == "GUILD_ACHIEVEMENT" ) then
+ self:AddMessage(format(arg1, "|Hplayer:"..arg2.."|h".."["..coloredName.."]".."|h"), info.r, info.g, info.b, info.id);
+ elseif ( type == "IGNORED" ) then
+ self:AddMessage(format(CHAT_IGNORED, arg2), info.r, info.g, info.b, info.id);
+ elseif ( type == "FILTERED" ) then
+ self:AddMessage(format(CHAT_FILTERED, arg2), info.r, info.g, info.b, info.id);
+ elseif ( type == "RESTRICTED" ) then
+ self:AddMessage(CHAT_RESTRICTED, info.r, info.g, info.b, info.id);
+ elseif ( type == "CHANNEL_LIST") then
+ if(channelLength > 0) then
+ self:AddMessage(format(_G["CHAT_"..type.."_GET"]..arg1, tonumber(arg8), arg4), info.r, info.g, info.b, info.id);
+ else
+ self:AddMessage(arg1, info.r, info.g, info.b, info.id);
+ end
+ elseif (type == "CHANNEL_NOTICE_USER") then
+ local globalstring = _G["CHAT_"..arg1.."_NOTICE_BN"];
+ if ( not globalstring ) then
+ globalstring = _G["CHAT_"..arg1.."_NOTICE"];
+ end
+ if(strlen(arg5) > 0) then
+ -- TWO users in this notice (E.G. x kicked y)
+ self:AddMessage(format(globalstring, arg8, arg4, arg2, arg5), info.r, info.g, info.b, info.id);
+ elseif ( arg1 == "INVITE" ) then
+ self:AddMessage(format(globalstring, arg4, arg2), info.r, info.g, info.b, info.id);
+ else
+ self:AddMessage(format(globalstring, arg8, arg4, arg2), info.r, info.g, info.b, info.id);
+ end
+ elseif (type == "CHANNEL_NOTICE") then
+ local globalstring = _G["CHAT_"..arg1.."_NOTICE_BN"];
+ if ( not globalstring ) then
+ globalstring = _G["CHAT_"..arg1.."_NOTICE"];
+ end
+ if ( arg10 > 0 ) then
+ arg4 = arg4.." "..arg10;
+ end
+
+ local accessID = ChatHistory_GetAccessID(Chat_GetChatCategory(type), arg8);
+ local typeID = ChatHistory_GetAccessID(infoType, arg8);
+ self:AddMessage(format(globalstring, arg8, arg4), info.r, info.g, info.b, info.id, false, accessID, typeID);
+ elseif ( type == "BN_CONVERSATION_NOTICE" ) then
+ local channelLink = format(CHAT_BN_CONVERSATION_GET_LINK, arg8, MAX_WOW_CHAT_CHANNELS + arg8);
+ local playerLink = format("|HBNplayer:%s:%s:%s:%s:%s|h[%s]|h", arg2, arg13, arg11, Chat_GetChatCategory(type), arg8, arg2);
+ local message = format(_G["CHAT_CONVERSATION_"..arg1.."_NOTICE"], channelLink, playerLink)
+
+ local accessID = ChatHistory_GetAccessID(Chat_GetChatCategory(type), arg8);
+ local typeID = ChatHistory_GetAccessID(infoType, arg8);
+ self:AddMessage(message, info.r, info.g, info.b, info.id, false, accessID, typeID);
+ elseif ( type == "BN_CONVERSATION_LIST" ) then
+ local channelLink = format(CHAT_BN_CONVERSATION_GET_LINK, arg8, MAX_WOW_CHAT_CHANNELS + arg8);
+ local message = format(CHAT_BN_CONVERSATION_LIST, channelLink, arg1);
+ self:AddMessage(message, info.r, info.g, info.b, info.id, false, accessID, typeID);
+ elseif ( type == "BN_INLINE_TOAST_ALERT" ) then
+ local globalstring = _G["BN_INLINE_TOAST_"..arg1];
+ local message;
+ if ( arg1 == "FRIEND_REQUEST" ) then
+ message = globalstring;
+ elseif ( arg1 == "FRIEND_PENDING" ) then
+ message = format(BN_INLINE_TOAST_FRIEND_PENDING, BNGetNumFriendInvites());
+ elseif ( arg1 == "FRIEND_REMOVED" ) then
+ message = format(globalstring, arg2);
+ else
+ local playerLink = format("|HBNplayer:%s:%s:%s:%s:%s|h[%s]|h", arg2, arg13, arg11, Chat_GetChatCategory(type), 0, arg2);
+ message = format(globalstring, playerLink);
+ end
+ self:AddMessage(message, info.r, info.g, info.b, info.id);
+ elseif ( type == "BN_INLINE_TOAST_BROADCAST" ) then
+ if ( arg1 ~= "" ) then
+ local playerLink = format("|HBNplayer:%s:%s:%s:%s:%s|h[%s]|h", arg2, arg13, arg11, Chat_GetChatCategory(type), 0, arg2);
+ self:AddMessage(format(BN_INLINE_TOAST_BROADCAST, playerLink, arg1), info.r, info.g, info.b, info.id);
+ end
+ elseif ( type == "BN_INLINE_TOAST_BROADCAST_INFORM" ) then
+ if ( arg1 ~= "" ) then
+ self:AddMessage(BN_INLINE_TOAST_BROADCAST_INFORM, info.r, info.g, info.b, info.id);
+ end
+ elseif ( type == "BN_INLINE_TOAST_CONVERSATION" ) then
+ self:AddMessage(format(BN_INLINE_TOAST_CONVERSATION, arg1), info.r, info.g, info.b, info.id);
+ else
+ local body;
+
+ local _, fontHeight = FCF_GetChatWindowInfo(self:GetID());
+
+ if ( fontHeight == 0 ) then
+ --fontHeight will be 0 if it's still at the default (14)
+ fontHeight = 14;
+ end
+
+ -- Add AFK/DND flags
+ local pflag;
+ if(strlen(arg6) > 0) then
+ if ( arg6 == "GM" ) then
+ --If it was a whisper, dispatch it to the GMChat addon.
+ if ( type == "WHISPER" ) then
+ return;
+ end
+ --Add Blizzard Icon, this was sent by a GM
+ pflag = "|TInterface\\ChatFrame\\UI-ChatIcon-Blizz.blp:0:2:0:-3|t ";
+ elseif ( arg6 == "DEV" ) then
+ --Add Blizzard Icon, this was sent by a Dev
+ pflag = "|TInterface\\ChatFrame\\UI-ChatIcon-Blizz.blp:0:2:0:-3|t ";
+ else
+ pflag = _G["CHAT_FLAG_"..arg6];
+ end
+ else
+ pflag = "";
+ end
+ if ( type == "WHISPER_INFORM" and GMChatFrame_IsGM and GMChatFrame_IsGM(arg2) ) then
+ return;
+ end
+
+ local showLink = 1;
+ if ( strsub(type, 1, 7) == "MONSTER" or strsub(type, 1, 9) == "RAID_BOSS") then
+ showLink = nil;
+ else
+ arg1 = gsub(arg1, "%%", "%%%%");
+ end
+
+ if ((type == "PARTY_LEADER") and (HasLFGRestrictions())) then
+ type = "PARTY_GUIDE";
+ end
+
+ -- Search for icon links and replace them with texture links.
+ local term;
+ for tag in string.gmatch(arg1, "%b{}") do
+ term = strlower(string.gsub(tag, "[{}]", ""));
+ if ( ICON_TAG_LIST[term] and ICON_LIST[ICON_TAG_LIST[term]] ) then
+ arg1 = string.gsub(arg1, tag, ICON_LIST[ICON_TAG_LIST[term]] .. "0|t");
+ end
+ end
+
+ local playerLink;
+
+ if ( type ~= "BN_WHISPER" and type ~= "BN_WHISPER_INFORM" and type ~= "BN_CONVERSATION" ) then
+ playerLink = "|Hplayer:"..arg2..":"..arg11..":"..chatGroup..(chatTarget and ":"..chatTarget or "").."|h";
+ else
+ playerLink = "|HBNplayer:"..arg2..":"..arg13..":"..arg11..":"..chatGroup..(chatTarget and ":"..chatTarget or "").."|h";
+ end
+
+ if ( (strlen(arg3) > 0) and (arg3 ~= "Universal") and (arg3 ~= self.defaultLanguage) ) then
+ local languageHeader = "["..arg3.."] ";
+ if ( showLink and (strlen(arg2) > 0) ) then
+ body = format(_G["CHAT_"..type.."_GET"]..languageHeader..arg1, pflag..playerLink.."["..coloredName.."]".."|h");
+ else
+ body = format(_G["CHAT_"..type.."_GET"]..languageHeader..arg1, pflag..arg2);
+ end
+ else
+ if ( not showLink or strlen(arg2) == 0 ) then
+ body = format(_G["CHAT_"..type.."_GET"]..arg1, pflag..arg2, arg2);
+ else
+ if ( type == "EMOTE" ) then
+ body = format(_G["CHAT_"..type.."_GET"]..arg1, pflag..playerLink..coloredName.."|h");
+ elseif ( type == "TEXT_EMOTE") then
+ body = string.gsub(arg1, arg2, pflag..playerLink..coloredName.."|h", 1);
+ else
+ body = format(_G["CHAT_"..type.."_GET"]..arg1, pflag..playerLink.."["..coloredName.."]".."|h");
+ end
+ end
+ end
+
+ -- Add Channel
+ arg4 = gsub(arg4, "%s%-%s.*", "");
+ if( chatGroup == "BN_CONVERSATION" ) then
+ body = format(CHAT_BN_CONVERSATION_GET_LINK, arg8, MAX_WOW_CHAT_CHANNELS + arg8)..body;
+ elseif(channelLength > 0) then
+ body = "|Hchannel:channel:"..arg8.."|h["..arg4.."]|h "..body;
+ end
+
+ --Add Timestamps
+ if ( CHAT_TIMESTAMP_FORMAT ) then
+ body = BetterDate(CHAT_TIMESTAMP_FORMAT, time())..body;
+ end
+
+ local accessID = ChatHistory_GetAccessID(chatGroup, chatTarget);
+ local typeID = ChatHistory_GetAccessID(infoType, chatTarget);
+ self:AddMessage(body, info.r, info.g, info.b, info.id, false, accessID, typeID);
+ end
+
+ if ( type == "WHISPER" or type == "BN_WHISPER" ) then
+ --BN_WHISPER FIXME
+ ChatEdit_SetLastTellTarget(arg2);
+ if ( self.tellTimer and (GetTime() > self.tellTimer) ) then
+ PlaySound("TellMessage");
+ end
+ self.tellTimer = GetTime() + CHAT_TELL_ALERT_TIME;
+ --FCF_FlashTab(self);
+ end
+
+ if ( not self:IsShown() ) then
+ if ( (self == DEFAULT_CHAT_FRAME and info.flashTabOnGeneral) or (self ~= DEFAULT_CHAT_FRAME and info.flashTab) ) then
+ if ( not CHAT_OPTIONS.HIDE_FRAME_ALERTS or type == "WHISPER" or type == "BN_WHISPER" ) then --BN_WHISPER FIXME
+ FCF_StartAlertFlash(self);
+ end
+ end
+ end
+
+ return true;
+ end
+end
+
+function ChatFrame_AddMessageEventFilter (event, filter)
+ assert(event and filter);
+
+ if ( chatFilters[event] ) then
+ -- Only allow a filter to be added once
+ for index, filterFunc in next, chatFilters[event] do
+ if ( filterFunc == filter ) then
+ return;
+ end
+ end
+ else
+ chatFilters[event] = {};
+ end
+
+ tinsert(chatFilters[event], filter);
+end
+
+function ChatFrame_RemoveMessageEventFilter (event, filter)
+ assert(event and filter);
+
+ if ( chatFilters[event] ) then
+ for index, filterFunc in next, chatFilters[event] do
+ if ( filterFunc == filter ) then
+ tremove(chatFilters[event], index);
+ end
+ end
+
+ if ( #chatFilters[event] == 0 ) then
+ chatFilters[event] = nil;
+ end
+ end
+end
+
+function ChatFrame_GetMessageEventFilters (event)
+ assert(event);
+
+ return chatFilters[event];
+end
+
+function ChatFrame_OnUpdate(self, elapsedSec)
+ local flash = _G[self:GetName().."ButtonFrameBottomButtonFlash"];
+
+ if ( not flash ) then
+ return;
+ end
+
+ if ( self:AtBottom() ) then
+ if ( flash:IsShown() ) then
+ flash:Hide();
+ end
+ return;
+ end
+
+ local flashTimer = self.flashTimer + elapsedSec;
+ if ( flashTimer < CHAT_BUTTON_FLASH_TIME ) then
+ self.flashTimer = flashTimer;
+ return;
+ end
+
+ while ( flashTimer >= CHAT_BUTTON_FLASH_TIME ) do
+ flashTimer = flashTimer - CHAT_BUTTON_FLASH_TIME;
+ end
+ self.flashTimer = flashTimer;
+
+ if ( flash:IsShown() ) then
+ flash:Hide();
+ else
+ flash:Show();
+ end
+end
+
+function ChatFrame_OnHyperlinkShow(self, link, text, button)
+ SetItemRef(link, text, button, self);
+end
+
+function ChatFrame_OnMouseWheel(value)
+ if ( value > 0 ) then
+ SELECTED_DOCK_FRAME:ScrollUp();
+ elseif ( value < 0 ) then
+ SELECTED_DOCK_FRAME:ScrollDown();
+ end
+end
+
+function ChatFrame_OpenChat(text, chatFrame)
+ local editBox = ChatEdit_ChooseBoxForSend(chatFrame);
+
+ ChatEdit_ActivateChat(editBox);
+ editBox.setText = 1;
+ editBox.text = text;
+
+ if ( editBox:GetAttribute("chatType") == editBox:GetAttribute("stickyType") ) then
+ if ( (editBox:GetAttribute("stickyType") == "PARTY") and (GetNumPartyMembers() == 0) or
+ (editBox:GetAttribute("stickyType") == "RAID") and (GetNumRaidMembers() == 0) or
+ (editBox:GetAttribute("stickyType") == "BATTLEGROUND") and (GetNumRaidMembers() == 0) ) then
+ editBox:SetAttribute("chatType", "SAY");
+ end
+ end
+
+ ChatEdit_UpdateHeader(editBox);
+ return editBox;
+end
+
+function ChatFrame_ScrollToBottom()
+ SELECTED_DOCK_FRAME:ScrollToBottom();
+end
+
+function ChatFrame_ScrollUp()
+ SELECTED_DOCK_FRAME:ScrollUp();
+end
+
+function ChatFrame_ScrollDown()
+ SELECTED_DOCK_FRAME:ScrollDown();
+end
+
+--used for chatframe and combat log
+function MessageFrameScrollButton_OnLoad(self)
+ self.clickDelay = MESSAGE_SCROLLBUTTON_INITIAL_DELAY;
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp", "RightButtonUp", "RightButtonDown");
+end
+
+--Controls scrolling for chatframe and combat log
+function MessageFrameScrollButton_OnUpdate(self, elapsed)
+ if (self:GetButtonState() == "PUSHED") then
+ self.clickDelay = self.clickDelay - elapsed;
+ if ( self.clickDelay < 0 ) then
+ local name = self:GetName();
+ if ( name == self:GetParent():GetName().."DownButton" ) then
+ self:GetParent():GetParent():ScrollDown();
+ elseif ( name == self:GetParent():GetName().."UpButton" ) then
+ self:GetParent():GetParent():ScrollUp();
+ end
+ self.clickDelay = MESSAGE_SCROLLBUTTON_SCROLL_DELAY;
+ end
+ end
+end
+
+function ChatFrame_OpenMenu()
+ ChatMenu:Show();
+end
+
+function ChatFrameMenu_UpdateAnchorPoint()
+ --Update the menu anchor point
+ if ( FCF_GetButtonSide(DEFAULT_CHAT_FRAME) == "right" ) then
+ ChatMenu:ClearAllPoints();
+ ChatMenu:SetPoint("BOTTOMRIGHT", ChatFrameMenuButton, "TOPLEFT");
+ else
+ ChatMenu:ClearAllPoints();
+ ChatMenu:SetPoint("BOTTOMLEFT", ChatFrameMenuButton, "TOPRIGHT");
+ end
+end
+
+function ChatFrame_SendTell(name, chatFrame)
+ local editBox = ChatEdit_ChooseBoxForSend(chatFrame);
+
+ --DEBUG FIXME - for now, we're not going to remove spaces from names. We need to make sure X-server still works.
+ -- Remove spaces from the server name for slash command parsing
+ --name = gsub(name, " ", "");
+
+ if ( editBox ~= ChatEdit_GetActiveWindow() ) then
+ ChatFrame_OpenChat(SLASH_WHISPER1.." "..name.." ", chatFrame);
+ else
+ editBox:SetText(SLASH_WHISPER1.." "..name.." ");
+ end
+ ChatEdit_ParseText(editBox, 0);
+--[[
+ chatFrame.editBox:SetAttribute("chatType", "WHISPER");
+ chatFrame.editBox:SetAttribute("tellTarget", name);
+ ChatEdit_UpdateHeader(chatFrame.editBox);
+ if ( editBox ~= ChatEdit_GetActiveWindow() ) then
+ ChatFrame_OpenChat("", chatFrame);
+ end
+]]
+end
+
+function ChatFrame_ReplyTell(chatFrame)
+ local editBox = ChatEdit_ChooseBoxForSend(chatFrame);
+
+ local lastTell = ChatEdit_GetLastTellTarget();
+ if ( lastTell ~= "" ) then
+ --BN_WHISPER FIXME
+ editBox:SetAttribute("chatType", "WHISPER");
+ editBox:SetAttribute("tellTarget", lastTell);
+ ChatEdit_UpdateHeader(editBox);
+ if ( editBox ~= ChatEdit_GetActiveWindow() ) then
+ ChatFrame_OpenChat("", chatFrame);
+ end
+ else
+ -- Error message
+ end
+end
+
+function ChatFrame_ReplyTell2(chatFrame)
+ local editBox = ChatEdit_ChooseBoxForSend(chatFrame);
+
+ local lastTold = ChatEdit_GetLastToldTarget();
+ if ( lastTold ~= "" ) then
+ --BN_WHISPER FIXME
+ editBox:SetAttribute("chatType", "WHISPER");
+ editBox:SetAttribute("tellTarget", lastTold);
+ ChatEdit_UpdateHeader(editBox);
+ if ( editBox ~= ChatEdit_GetActiveWindow() ) then
+ ChatFrame_OpenChat("", chatFrame);
+ end
+ else
+ -- Error message
+ end
+end
+
+function ChatFrame_DisplayStartupText(frame)
+ if ( not frame ) then
+ return;
+ end
+
+ local info = ChatTypeInfo["SYSTEM"];
+ local i = 1;
+ local text = _G["STARTUP_TEXT_LINE"..i];
+ while text do
+ frame:AddMessage(text, info.r, info.g, info.b, info.id);
+ i = i + 1;
+ text = _G["STARTUP_TEXT_LINE"..i];
+ end
+
+end
+
+function ChatFrame_DisplayHelpText(frame)
+ if ( not frame ) then
+ return;
+ end
+
+ local info = ChatTypeInfo["SYSTEM"];
+ local i = 1;
+ local text = _G["HELP_TEXT_LINE"..i];
+ while text do
+ frame:AddMessage(text, info.r, info.g, info.b, info.id);
+ i = i + 1;
+ text = _G["HELP_TEXT_LINE"..i];
+ end
+
+end
+
+function ChatFrame_DisplayMacroHelpText(frame)
+ if ( not frame ) then
+ return;
+ end
+
+ local info = ChatTypeInfo["SYSTEM"];
+ local i = 1;
+ local text = _G["MACRO_HELP_TEXT_LINE"..i];
+ while text do
+ frame:AddMessage(text, info.r, info.g, info.b, info.id);
+ i = i + 1;
+ text = _G["MACRO_HELP_TEXT_LINE"..i];
+ end
+
+end
+
+function ChatFrame_DisplayChatHelp(frame)
+ if ( not frame ) then
+ return;
+ end
+
+ local info = ChatTypeInfo["SYSTEM"];
+ local i = 1;
+ local text = _G["CHAT_HELP_TEXT_LINE"..i];
+ while text do
+ frame:AddMessage(text, info.r, info.g, info.b, info.id);
+ i = i + 1;
+ -- hack fix for removing a line without causing localization problems
+ if ( i == 15 ) then
+ i = i + 1;
+ end
+ text = _G["CHAT_HELP_TEXT_LINE"..i];
+ end
+end
+
+function ChatFrame_DisplayGuildHelp(frame)
+ if ( not frame ) then
+ return;
+ end
+
+ local info = ChatTypeInfo["SYSTEM"];
+ local i = 1;
+ local text = _G["GUILD_HELP_TEXT_LINE"..i];
+ while text do
+ frame:AddMessage(text, info.r, info.g, info.b, info.id);
+ i = i + 1;
+ text = _G["GUILD_HELP_TEXT_LINE"..i];
+ end
+end
+
+function ChatFrame_DisplayGameTime(frame)
+ if ( not frame ) then
+ return;
+ end
+
+ local info = ChatTypeInfo["SYSTEM"];
+ frame:AddMessage(GameTime_GetGameTime(true), info.r, info.g, info.b, info.id);
+end
+
+function ChatFrame_TimeBreakDown(time)
+ local days = floor(time / (60 * 60 * 24));
+ local hours = floor((time - (days * (60 * 60 * 24))) / (60 * 60));
+ local minutes = floor((time - (days * (60 * 60 * 24)) - (hours * (60 * 60))) / 60);
+ local seconds = mod(time, 60);
+ return days, hours, minutes, seconds;
+end
+
+function ChatFrame_DisplayTimePlayed(self, totalTime, levelTime)
+ local info = ChatTypeInfo["SYSTEM"];
+ local d;
+ local h;
+ local m;
+ local s;
+ d, h, m, s = ChatFrame_TimeBreakDown(totalTime);
+ local string = format(TIME_PLAYED_TOTAL, format(TIME_DAYHOURMINUTESECOND, d, h, m, s));
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+
+ d, h, m, s = ChatFrame_TimeBreakDown(levelTime);
+ local string = format(TIME_PLAYED_LEVEL, format(TIME_DAYHOURMINUTESECOND, d, h, m, s));
+ self:AddMessage(string, info.r, info.g, info.b, info.id);
+end
+
+function ChatFrame_ChatPageUp()
+ SELECTED_CHAT_FRAME:PageUp();
+end
+
+function ChatFrame_ChatPageDown()
+ SELECTED_CHAT_FRAME:PageDown();
+end
+
+function ChatFrame_DisplayUsageError(messageTag)
+ local info = ChatTypeInfo["SYSTEM"];
+ DEFAULT_CHAT_FRAME:AddMessage(messageTag, info.r, info.g, info.b, info.id);
+end
+
+-- ChatEdit functions
+
+local ChatEdit_LastTell = {};
+for i = 1, NUM_REMEMBERED_TELLS, 1 do
+ ChatEdit_LastTell[i] = "";
+end
+local ChatEdit_LastTold = "";
+
+function ChatEdit_OnLoad(self)
+ self:SetFrameLevel(self.chatFrame:GetFrameLevel()+1);
+ self:SetAttribute("chatType", "SAY");
+ self:SetAttribute("stickyType", "SAY");
+ self.chatLanguage = GetDefaultLanguage();
+ self:RegisterEvent("UPDATE_CHAT_COLOR");
+
+ self.addSpaceToAutoComplete = true;
+
+ if ( CHAT_OPTIONS.ONE_EDIT_AT_A_TIME == "many" ) then
+ self:Show();
+ end
+end
+
+function ChatEdit_OnEvent(self, event, ...)
+ if ( event == "UPDATE_CHAT_COLOR" ) then
+ local chatType = ...;
+ if ( chatType == self:GetAttribute("chatType") ) then
+ ChatEdit_UpdateHeader(self);
+ end
+ end
+end
+
+function ChatEdit_OnUpdate(self, elapsedSec)
+ if ( self.setText == 1) then
+ self:SetText(self.text);
+ self.setText = 0;
+ ChatEdit_ParseText(self, 0, true);
+ end
+end
+
+function ChatEdit_OnShow(self)
+ ChatEdit_ResetChatType(self);
+end
+
+function ChatEdit_ResetChatType(self)
+ if ( self:GetAttribute("chatType") == "PARTY" and UnitName("party1") == "" ) then
+ self:SetAttribute("chatType", "SAY");
+ end
+ if ( self:GetAttribute("chatType") == "RAID" and (GetNumRaidMembers() == 0) ) then
+ self:SetAttribute("chatType", "SAY");
+ end
+ if ( (self:GetAttribute("chatType") == "GUILD" or self:GetAttribute("chatType") == "OFFICER") and not IsInGuild() ) then
+ self:SetAttribute("chatType", "SAY");
+ end
+ if ( self:GetAttribute("chatType") == "BATTLEGROUND" and (GetNumRaidMembers() == 0) ) then
+ self:SetAttribute("chatType", "SAY");
+ end
+ self.tabCompleteIndex = 1;
+ self.tabCompleteText = nil;
+ ChatEdit_UpdateHeader(self);
+ ChatEdit_OnInputLanguageChanged(self);
+ --[[if ( CHAT_OPTIONS.ONE_EDIT_AT_A_TIME == "old") then
+ self:SetFocus();
+ end]]
+end
+
+function ChatEdit_OnHide(self)
+ if ( ACTIVE_CHAT_EDIT_BOX == self ) then
+ ChatEdit_DeactivateChat(self);
+ end
+
+ if ( LAST_ACTIVE_CHAT_EDIT_BOX == self and self:IsShown() ) then --Our parent was hidden. Let's find a new default frame.
+ --We'll go with the active dock frame since people think of that as the primary chat.
+ ChatEdit_SetLastActiveWindow(FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK).editBox);
+ end
+end
+
+function ChatEdit_OnEditFocusGained(self)
+ ChatEdit_ActivateChat(self);
+end
+
+function ChatEdit_OnEditFocusLost(self)
+ AutoCompleteEditBox_OnEditFocusLost(self);
+ ChatEdit_DeactivateChat(self);
+end
+
+function ChatEdit_ActivateChat(editBox)
+ if ( ACTIVE_CHAT_EDIT_BOX and ACTIVE_CHAT_EDIT_BOX ~= editBox ) then
+ ChatEdit_DeactivateChat(ACTIVE_CHAT_EDIT_BOX);
+ end
+ ACTIVE_CHAT_EDIT_BOX = editBox;
+
+ ChatEdit_SetLastActiveWindow(editBox);
+
+ --Stop any sort of fading
+ UIFrameFadeRemoveFrame(editBox);
+
+ editBox:Show();
+ editBox:SetFocus();
+ editBox:SetFrameStrata("DIALOG");
+ editBox:Raise();
+
+ editBox.header:Show();
+ editBox.focusLeft:Show();
+ editBox.focusRight:Show();
+ editBox.focusMid:Show();
+ editBox:SetAlpha(1.0);
+
+ ChatEdit_UpdateHeader(editBox);
+
+ if ( CHAT_SHOW_IME ) then
+ _G[editBox:GetName().."Language"]:Show();
+ end
+end
+
+local function ChatEdit_SetDeactivated(editBox)
+ editBox:SetFrameStrata("LOW");
+ if ( GetCVar("chatStyle") == "classic") then
+ editBox:Hide();
+ else
+ editBox:SetText("");
+ editBox.header:Hide();
+ editBox:SetAlpha(0.35);
+ editBox:ClearFocus();
+
+ editBox.focusLeft:Hide();
+ editBox.focusRight:Hide();
+ editBox.focusMid:Hide();
+ ChatEdit_ResetChatTypeToSticky(editBox);
+ ChatEdit_ResetChatType(editBox);
+ end
+ _G[editBox:GetName().."Language"]:Hide();
+end
+
+function ChatEdit_DeactivateChat(editBox)
+ if ( ACTIVE_CHAT_EDIT_BOX == editBox ) then
+ ACTIVE_CHAT_EDIT_BOX = nil;
+ end
+
+ ChatEdit_SetDeactivated(editBox);
+end
+
+function ChatEdit_ChooseBoxForSend(preferredChatFrame)
+ if ( GetCVar("chatStyle") == "classic" ) then
+ return DEFAULT_CHAT_FRAME.editBox;
+ elseif ( preferredChatFrame and preferredChatFrame:IsShown() ) then
+ return preferredChatFrame.editBox;
+ elseif ( ChatEdit_GetLastActiveWindow() and ChatEdit_GetLastActiveWindow():GetParent():IsShown() ) then
+ return ChatEdit_GetLastActiveWindow();
+ else
+ return FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK).editBox;
+ end
+end
+
+function ChatEdit_SetLastActiveWindow(editBox)
+ local previousValue = LAST_ACTIVE_CHAT_EDIT_BOX;
+ if ( LAST_ACTIVE_CHAT_EDIT_BOX and LAST_ACTIVE_CHAT_EDIT_BOX ~= editBox ) then
+ if ( GetCVar("chatStyle") == "im" ) then
+ LAST_ACTIVE_CHAT_EDIT_BOX:Hide();
+ end
+ end
+
+ LAST_ACTIVE_CHAT_EDIT_BOX = editBox;
+ if ( GetCVar("chatStyle") == "im" and ACTIVE_CHAT_EDIT_BOX ~= editBox ) then
+ editBox:Show();
+ ChatEdit_SetDeactivated(editBox);
+ end
+
+ if ( previousValue ) then
+ FCFClickAnywhereButton_UpdateState(previousValue.chatFrame.clickAnywhereButton);
+ end
+ FCFClickAnywhereButton_UpdateState(editBox.chatFrame.clickAnywhereButton);
+end
+
+function ChatEdit_GetActiveWindow()
+ return ACTIVE_CHAT_EDIT_BOX;
+end
+
+function ChatEdit_GetLastActiveWindow()
+ return LAST_ACTIVE_CHAT_EDIT_BOX;
+end
+
+function ChatEdit_FocusActiveWindow()
+ local active = ChatEdit_GetActiveWindow()
+ if ( active ) then
+ ChatEdit_ActivateChat(active);
+ end
+end
+
+function ChatEdit_InsertLink(text)
+ if ( not text ) then
+ return false;
+ end
+
+ local activeWindow = ChatEdit_GetActiveWindow();
+ if ( activeWindow ) then
+ -- add a space for proper parsing
+ activeWindow:Insert(" "..text);
+ return true;
+ end
+ if ( BrowseName and BrowseName:IsVisible() ) then
+ local item;
+ if ( strfind(text, "item:", 1, true) ) then
+ item = GetItemInfo(text);
+ end
+ if ( item ) then
+ BrowseName:SetText(item);
+ return true;
+ end
+ end
+ if ( MacroFrameText and MacroFrameText:IsVisible() ) then
+ local item;
+ if ( strfind(text, "item:", 1, true) ) then
+ item = GetItemInfo(text);
+ end
+ local cursorPosition = MacroFrameText:GetCursorPosition();
+ if (cursorPosition == 0 or strsub(MacroFrameText:GetText(), cursorPosition, cursorPosition) == "\n" ) then
+ if ( item ) then
+ if ( GetItemSpell(text) ) then
+ MacroFrameText:Insert(SLASH_USE1.." "..item.."\n");
+ else
+ MacroFrameText:Insert(SLASH_EQUIP1.." "..item.."\n");
+ end
+ else
+ MacroFrameText:Insert(SLASH_CAST1.." "..text.."\n");
+ end
+ else
+ MacroFrameText:Insert(item or text);
+ end
+ return true;
+ end
+ return false;
+end
+
+function ChatEdit_GetLastTellTarget()
+ for index, value in ipairs(ChatEdit_LastTell) do
+ if ( value ~= "" ) then
+ return value;
+ end
+ end
+ return "";
+end
+
+function ChatEdit_SetLastTellTarget(target)
+ local found = #ChatEdit_LastTell;
+ for index, value in ipairs(ChatEdit_LastTell) do
+ if ( strupper(target) == strupper(value) ) then
+ found = index;
+ break;
+ end
+ end
+
+ for i = found, 2, -1 do
+ ChatEdit_LastTell[i] = ChatEdit_LastTell[i-1];
+ end
+ ChatEdit_LastTell[1] = target;
+end
+
+function ChatEdit_GetNextTellTarget(target)
+ if ( not target or target == "" ) then
+ return ChatEdit_LastTell[1];
+ end
+
+ for i = 1, #ChatEdit_LastTell - 1, 1 do
+ if ( ChatEdit_LastTell[i] == "" ) then
+ break;
+ elseif ( strupper(target) == strupper(ChatEdit_LastTell[i]) ) then
+ if ( ChatEdit_LastTell[i+1] ~= "" ) then
+ return ChatEdit_LastTell[i+1];
+ else
+ break;
+ end
+ end
+ end
+
+ return ChatEdit_LastTell[1];
+end
+
+function ChatEdit_GetLastToldTarget()
+ return ChatEdit_LastTold;
+end
+
+function ChatEdit_SetLastToldTarget(name)
+ ChatEdit_LastTold = name or "";
+end
+
+function ChatEdit_UpdateHeader(editBox)
+ local type = editBox:GetAttribute("chatType");
+ if ( not type ) then
+ return;
+ end
+
+ local info = ChatTypeInfo[type];
+ local header = _G[editBox:GetName().."Header"];
+ if ( not header ) then
+ return;
+ end
+
+ --BN_WHISPER FIXME
+ if ( type == "WHISPER" ) then
+ --If we have a BN presence ID for this name, it's a BN whisper.
+ if ( BNet_GetPresenceID(editBox:GetAttribute("tellTarget")) ) then
+ editBox:SetAttribute("chatType", "BN_WHISPER");
+ ChatEdit_UpdateHeader(editBox);
+ return;
+ end
+
+ header:SetFormattedText(CHAT_WHISPER_SEND, editBox:GetAttribute("tellTarget"));
+ elseif ( type == "BN_WHISPER" ) then
+ header:SetFormattedText(CHAT_BN_WHISPER_SEND, editBox:GetAttribute("tellTarget"));
+ elseif ( type == "EMOTE" ) then
+ header:SetFormattedText(CHAT_EMOTE_SEND, UnitName("player"));
+ elseif ( type == "CHANNEL" ) then
+ local channel, channelName, instanceID = GetChannelName(editBox:GetAttribute("channelTarget"));
+ if ( channelName ) then
+ if ( instanceID > 0 ) then
+ channelName = channelName.." "..instanceID;
+ end
+ info = ChatTypeInfo["CHANNEL"..channel];
+ editBox:SetAttribute("channelTarget", channel);
+ header:SetFormattedText(CHAT_CHANNEL_SEND, channel, channelName);
+ end
+ elseif ( type == "BN_CONVERSATION" ) then
+ local conversationID = editBox:GetAttribute("channelTarget");
+ header:SetFormattedText(CHAT_BN_CONVERSATION_SEND, conversationID + MAX_WOW_CHAT_CHANNELS);
+ else
+ header:SetText(_G["CHAT_"..type.."_SEND"]);
+ end
+
+ header:SetTextColor(info.r, info.g, info.b);
+
+ editBox:SetTextInsets(15 + header:GetWidth(), 13, 0, 0);
+ editBox:SetTextColor(info.r, info.g, info.b);
+
+ editBox.focusLeft:SetVertexColor(info.r, info.g, info.b);
+ editBox.focusRight:SetVertexColor(info.r, info.g, info.b);
+ editBox.focusMid:SetVertexColor(info.r, info.g, info.b);
+end
+
+function ChatEdit_AddHistory(editBox)
+ local text = "";
+ local type = editBox:GetAttribute("chatType");
+ local header = _G["SLASH_"..type.."1"];
+ if ( header ) then
+ text = header;
+ end
+
+ if ( type == "WHISPER" ) then
+ text = text.." "..editBox:GetAttribute("tellTarget");
+ elseif ( type == "CHANNEL" ) then
+ text = "/"..editBox:GetAttribute("channelTarget");
+ end
+
+ local editBoxText = editBox:GetText();
+ if ( strlen(editBoxText) > 0 ) then
+ text = text.." "..editBox:GetText();
+ end
+
+ if ( strlen(text) > 0 ) then
+ editBox:AddHistoryLine(text);
+ end
+end
+
+function ChatEdit_SendText(editBox, addHistory)
+ ChatEdit_ParseText(editBox, 1);
+
+ local type = editBox:GetAttribute("chatType");
+ local text = editBox:GetText();
+ if ( strfind(text, "%s*[^%s]+") ) then
+ --BN_WHISPER FIXME
+ if ( type == "WHISPER") then
+ local target = editBox:GetAttribute("tellTarget");
+ ChatEdit_SetLastToldTarget(target);
+ SendChatMessage(text, type, editBox.language, target);
+ elseif ( type == "BN_WHISPER" ) then
+ local target = editBox:GetAttribute("tellTarget");
+ local presenceID = BNet_GetPresenceID(target);
+ if ( presenceID ) then
+ ChatEdit_SetLastToldTarget(target);
+ BNSendWhisper(presenceID, text);
+ else
+ local info = ChatTypeInfo["SYSTEM"]
+ editBox.chatFrame:AddMessage(format(BN_UNABLE_TO_RESOLVE_NAME, target), info.r, info.g, info.b);
+ end
+ elseif ( type == "BN_CONVERSATION" ) then
+ local target = tonumber(editBox:GetAttribute("channelTarget"));
+ BNSendConversationMessage(target, text);
+ elseif ( type == "CHANNEL") then
+ SendChatMessage(text, type, editBox.language, editBox:GetAttribute("channelTarget"));
+ else
+ SendChatMessage(text, type, editBox.language);
+ end
+ if ( addHistory ) then
+ ChatEdit_AddHistory(editBox);
+ end
+ end
+end
+
+function ChatEdit_OnEnterPressed(self)
+ if(AutoCompleteEditBox_OnEnterPressed(self)) then
+ return;
+ end
+ ChatEdit_SendText(self, 1);
+
+ local type = self:GetAttribute("chatType");
+ local chatFrame = self:GetParent();
+ if ( chatFrame.isTemporary ) then --Temporary window sticky types never change.
+ self:SetAttribute("stickyType", chatFrame.chatType);
+ --BN_WHISPER FIXME
+ if ( chatFrame.chatType == "WHISPER" or chatFrame.chatType == "BN_WHISPER" ) then
+ self:SetAttribute("tellTarget", chatFrame.chatTarget);
+ end
+ elseif ( ChatTypeInfo[type].sticky == 1 ) then
+ self:SetAttribute("stickyType", type);
+ end
+
+ ChatEdit_OnEscapePressed(self);
+end
+
+function ChatEdit_OnEscapePressed(editBox)
+ if ( not AutoCompleteEditBox_OnEscapePressed(editBox) ) then
+ ChatEdit_ResetChatTypeToSticky(editBox);
+ if ( GetCVar("chatStyle") ~= "im" or editBox == MacroEditBox ) then
+ editBox:SetText("");
+ editBox:Hide();
+ else
+ ChatEdit_DeactivateChat(editBox);
+ end
+ end
+end
+
+function ChatEdit_ResetChatTypeToSticky(editBox)
+ editBox:SetAttribute("chatType", editBox:GetAttribute("stickyType"));
+end
+
+function ChatEdit_OnSpacePressed(self)
+ ChatEdit_ParseText(self, 0);
+end
+
+function ChatEdit_CustomTabPressed(self)
+end
+
+function ChatEdit_SecureTabPressed(self)
+ local chatType = self:GetAttribute("chatType");
+ if ( chatType == "WHISPER" or chatType == "BN_WHISPER" ) then
+ local newTarget = ChatEdit_GetNextTellTarget(self:GetAttribute("tellTarget"));
+ if ( newTarget and newTarget ~= "" ) then
+ self:SetAttribute("chatType", "WHISPER"); --UpdateHeader will change it to BN_WHISPER if needed.
+ self:SetAttribute("tellTarget", newTarget);
+ ChatEdit_UpdateHeader(self);
+ end
+ return;
+ end
+
+ local text = self.tabCompleteText;
+ if ( not text ) then
+ text = self:GetText();
+ self.tabCompleteText = text;
+ end
+
+ if ( strsub(text, 1, 1) ~= "/" ) then
+ return;
+ end
+
+ -- Increment the current tabcomplete count
+ local tabCompleteIndex = self.tabCompleteIndex;
+ self.tabCompleteIndex = tabCompleteIndex + 1;
+
+ -- If the string is in the format "/cmd blah", command will be "/cmd"
+ local command = strmatch(text, "^(/[^%s]+)") or "";
+
+ for index, value in pairs(ChatTypeInfo) do
+ local i = 1;
+ local cmdString = _G["SLASH_"..index..i];
+ while ( cmdString ) do
+ if ( strfind(cmdString, command, 1, 1) ) then
+ tabCompleteIndex = tabCompleteIndex - 1;
+ if ( tabCompleteIndex == 0 ) then
+ self.ignoreTextChange = 1;
+ self:SetText(cmdString);
+ return;
+ end
+ end
+ i = i + 1;
+ cmdString = _G["SLASH_"..index..i];
+ end
+ end
+
+ for index, value in pairs(SecureCmdList) do
+ local i = 1;
+ local cmdString = _G["SLASH_"..index..i];
+ while ( cmdString ) do
+ if ( strfind(cmdString, command, 1, 1) ) then
+ tabCompleteIndex = tabCompleteIndex - 1;
+ if ( tabCompleteIndex == 0 ) then
+ self.ignoreTextChange = 1;
+ self:SetText(cmdString);
+ return;
+ end
+ end
+ i = i + 1;
+ cmdString = _G["SLASH_"..index..i];
+ end
+ end
+ for index, value in pairs(SlashCmdList) do
+ local i = 1;
+ local cmdString = _G["SLASH_"..index..i];
+ while ( cmdString ) do
+ if ( strfind(cmdString, command, 1, 1) ) then
+ tabCompleteIndex = tabCompleteIndex - 1;
+ if ( tabCompleteIndex == 0 ) then
+ self.ignoreTextChange = 1;
+ self:SetText(cmdString);
+ return;
+ end
+ end
+ i = i + 1;
+ cmdString = _G["SLASH_"..index..i];
+ end
+ end
+
+ local i = 1;
+ local j = 1;
+ local cmdString = _G["EMOTE"..i.."_CMD"..j];
+ while ( cmdString ) do
+ if ( strfind(cmdString, command, 1, 1) ) then
+ tabCompleteIndex = tabCompleteIndex - 1;
+ if ( tabCompleteIndex == 0 ) then
+ self.ignoreTextChange = 1;
+ self:SetText(cmdString);
+ return;
+ end
+ end
+ j = j + 1;
+ cmdString = _G["EMOTE"..i.."_CMD"..j];
+ if ( not cmdString ) then
+ i = i + 1;
+ j = 1;
+ cmdString = _G["EMOTE"..i.."_CMD"..j];
+ end
+ end
+
+ -- No tab completion
+ self:SetText(self.tabCompleteText);
+end
+
+function ChatEdit_OnTabPressed(self)
+ if ( not AutoCompleteEditBox_OnTabPressed(self) ) then
+ if ( securecall("ChatEdit_CustomTabPressed") ) then
+ return;
+ end
+ ChatEdit_SecureTabPressed(self);
+ end
+end
+
+function ChatEdit_OnTextChanged(self, userInput)
+ ChatEdit_ParseText(self, 0);
+ if ( not self.ignoreTextChange ) then
+ self.tabCompleteIndex = 1;
+ self.tabCompleteText = nil;
+ end
+ self.ignoreTextChange = nil;
+ local regex = "^((/[^%s]+)%s+)(.+)"
+ local full, command, target = strmatch(self:GetText(), regex);
+ if ( not target or (strsub(target, 1, 1) == "|") ) then
+ AutoComplete_HideIfAttachedTo(self);
+ return;
+ end
+
+ if ( userInput ) then
+ self.autoCompleteRegex = regex;
+ self.autoCompleteFormatRegex = "%2$s%1$s"
+ self.autoCompleteXOffset = 35;
+ AutoComplete_Update(self, target, self:GetUTF8CursorPosition() - strlenutf8(command) - 1);
+ end
+end
+
+function ChatEdit_OnTextSet(self)
+ ChatEdit_ParseText(self, 0);
+end
+
+function ChatEdit_LanguageShow()
+ CHAT_SHOW_IME = true;
+end
+
+function ChatEdit_OnInputLanguageChanged(self)
+ local button = _G[self:GetName().."Language"];
+ local variable = _G["INPUT_"..self:GetInputLanguage()];
+ button:SetText(variable);
+end
+
+local function processChatType(editBox, msg, index, send)
+ editBox.autoCompleteParams = AUTOCOMPLETE_LIST[index];
+-- this is a special function for "ChatEdit_HandleChatType"
+ if ( ChatTypeInfo[index] ) then
+ if ( index == "WHISPER" ) then
+ local targetFound = ChatEdit_ExtractTellTarget(editBox, msg);
+ if ( send == 1 and not targetFound) then
+ ChatEdit_OnEscapePressed(editBox);
+ end
+ elseif ( index == "REPLY" ) then
+ local lastTell = ChatEdit_GetLastTellTarget();
+ if ( lastTell ~= "" ) then
+ --BN_WHISPER FIXME
+ editBox:SetAttribute("chatType", "WHISPER");
+ editBox:SetAttribute("tellTarget", lastTell);
+ editBox:SetText(msg);
+ ChatEdit_UpdateHeader(editBox);
+ else
+ if ( send == 1 ) then
+ ChatEdit_OnEscapePressed(editBox);
+ end
+ end
+ elseif (index == "CHANNEL") then
+ ChatEdit_ExtractChannel(editBox, msg);
+ elseif ( index == "BN_CONVERSATION" ) then
+ ChatEdit_ExtractBNConversation(editBox, msg);
+ else
+ editBox:SetAttribute("chatType", index);
+ editBox:SetText(msg);
+ ChatEdit_UpdateHeader(editBox);
+ end
+ return true;
+ end
+ return false;
+end
+
+function ChatEdit_HandleChatType(editBox, msg, command, send)
+ local channel = strmatch(command, "/([0-9]+)");
+
+ if( channel ) then
+ local chanNum = tonumber(channel);
+ if ( chanNum > 0 and chanNum <= MAX_WOW_CHAT_CHANNELS ) then
+ local channelNum, channelName = GetChannelName(channel);
+ if ( channelNum > 0 ) then
+ editBox:SetAttribute("channelTarget", channelNum);
+ editBox:SetAttribute("chatType", "CHANNEL");
+ editBox:SetText(msg);
+ ChatEdit_UpdateHeader(editBox);
+ return true;
+ end
+ elseif ( chanNum > MAX_WOW_CHAT_CHANNELS ) then --This is a B.Net chat.
+ local conversationNum = chanNum - MAX_WOW_CHAT_CHANNELS;
+ if ( BNGetConversationInfo(conversationNum) ) then
+ editBox:SetAttribute("channelTarget", conversationNum);
+ editBox:SetAttribute("chatType", "BN_CONVERSATION");
+ editBox:SetText(msg);
+ ChatEdit_UpdateHeader(editBox);
+ return true;
+ end
+ end
+ else
+ -- first check the hash table
+ if ( hash_ChatTypeInfoList[command] ) then
+ return processChatType(editBox, msg, hash_ChatTypeInfoList[command], send);
+ end
+ for index, value in pairs(SecureCmdList) do
+ local i = 1;
+ local cmdString = _G["SLASH_"..index..i];
+ while ( cmdString ) do
+ cmdString = strupper(cmdString);
+ if ( cmdString == command ) then
+ hash_ChatTypeInfoList[command] = index;
+ return processChatType(editBox, msg, index, send);
+ end
+ i = i + 1;
+ cmdString = _G["SLASH_"..index..i];
+ end
+ end
+ for index, value in pairs(SlashCmdList) do
+ local i = 1;
+ local cmdString = _G["SLASH_"..index..i];
+ while ( cmdString ) do
+ cmdString = strupper(cmdString);
+ if ( cmdString == command ) then
+ hash_ChatTypeInfoList[command] = index;
+ return processChatType(editBox, msg, index, send);
+ end
+ i = i + 1;
+ cmdString = _G["SLASH_"..index..i];
+ end
+ end
+ for index, value in pairs(ChatTypeInfo) do
+ local i = 1;
+ local cmdString = _G["SLASH_"..index..i];
+ while ( cmdString ) do
+ cmdString = strupper(cmdString);
+ if ( cmdString == command ) then
+ hash_ChatTypeInfoList[command] = index; -- add to hash table
+ return processChatType(editBox, msg, index, send);
+ end
+ i = i + 1;
+ cmdString = _G["SLASH_"..index..i];
+ end
+ end
+ end
+ --This isn't one we found in our list, so we're not going to autocomplete.
+ editBox.autoCompleteParams = nil;
+ return false;
+end
+
+function ChatEdit_ParseText(editBox, send, parseIfNoSpaces)
+
+ local text = editBox:GetText();
+ if ( strlen(text) <= 0 ) then
+ return;
+ end
+
+ if ( strsub(text, 1, 1) ~= "/" ) then
+ return;
+ end
+
+ --Do not bother parsing if there is no space in the message and we aren't sending.
+ if ( send ~= 1 and not parseIfNoSpaces and not strfind(text, "%s") ) then
+ return;
+ end
+
+ -- If the string is in the format "/cmd blah", command will be "/cmd"
+ local command = strmatch(text, "^(/[^%s]+)") or "";
+ local msg = "";
+
+
+ if ( command ~= text ) then
+ msg = strsub(text, strlen(command) + 2);
+ end
+
+ command = strupper(command);
+
+ -- Check and see if we've got secure commands to run before we look for chat types or slash commands.
+ -- This hash table is prepopulated, unlike the other ones, since nobody can add secure commands. (See line 1205 or thereabouts)
+ -- We don't want this code to run unless send is 1, but we need ChatEdit_HandleChatType to run when send is 1 as well, which is why we
+ -- didn't just move ChatEdit_HandleChatType inside the send == 0 conditional, which could have also solved the problem with insecure
+ -- code having the ability to affect secure commands.
+
+ if ( send == 1 and hash_SecureCmdList[command] ) then
+ hash_SecureCmdList[command](strtrim(msg));
+ editBox:AddHistoryLine(text);
+ ChatEdit_OnEscapePressed(editBox);
+ return;
+ end
+
+ -- Handle chat types. No need for a securecall here, since we should be done with anything secure.
+ if ( ChatEdit_HandleChatType(editBox, msg, command, send) ) then
+ return;
+ end
+
+ if ( send == 0 ) then
+ return;
+ end
+
+ -- Check the hash tables for slash commands and emotes to see if we've run this before.
+ if ( hash_SlashCmdList[command] ) then
+ -- if the code in here changes - change the corresponding code below
+ hash_SlashCmdList[command](strtrim(msg), editBox);
+ editBox:AddHistoryLine(text);
+ ChatEdit_OnEscapePressed(editBox);
+ return;
+ elseif ( hash_EmoteTokenList[command] ) then
+ -- if the code in here changes - change the corresponding code below
+ DoEmote(hash_EmoteTokenList[command], msg);
+ editBox:AddHistoryLine(text);
+ ChatEdit_OnEscapePressed(editBox);
+ return;
+ end
+
+ -- If we didn't have the command in the hash tables, look for it the slow way...
+ for index, value in pairs(SlashCmdList) do
+ local i = 1;
+ local cmdString = _G["SLASH_"..index..i];
+ while ( cmdString ) do
+ cmdString = strupper(cmdString);
+ if ( cmdString == command ) then
+ -- if the code in here changes - change the corresponding code above
+ hash_SlashCmdList[command] = value; -- add to hash
+ value(strtrim(msg), editBox);
+ editBox:AddHistoryLine(text);
+ ChatEdit_OnEscapePressed(editBox);
+ return;
+ end
+ i = i + 1;
+ cmdString = _G["SLASH_"..index..i];
+ end
+ end
+
+ local i = 1;
+ local j = 1;
+ local cmdString = _G["EMOTE"..i.."_CMD"..j];
+ while ( i <= MAXEMOTEINDEX ) do
+ if ( cmdString and strupper(cmdString) == command ) then
+ local token = _G["EMOTE"..i.."_TOKEN"];
+ -- if the code in here changes - change the corresponding code above
+ if ( token ) then
+ hash_EmoteTokenList[command] = token; -- add to hash
+ DoEmote(token, msg);
+ end
+ editBox:AddHistoryLine(text);
+ ChatEdit_OnEscapePressed(editBox);
+ return;
+ end
+ j = j + 1;
+ cmdString = _G["EMOTE"..i.."_CMD"..j];
+ if ( not cmdString ) then
+ i = i + 1;
+ j = 1;
+ cmdString = _G["EMOTE"..i.."_CMD"..j];
+ end
+ end
+
+ -- Unrecognized chat command, show simple help text
+ if ( editBox.chatFrame ) then
+ local info = ChatTypeInfo["SYSTEM"];
+ editBox.chatFrame:AddMessage(HELP_TEXT_SIMPLE, info.r, info.g, info.b, info.id);
+ end
+
+ -- Reset the chat type and clear the edit box's contents
+ ChatEdit_OnEscapePressed(editBox);
+ return;
+end
+
+local tellTargetExtractionAutoComplete = AUTOCOMPLETE_LIST.ALL;
+function ChatEdit_ExtractTellTarget(editBox, msg)
+ -- Grab the string after the slash command
+ local target = strmatch(msg, "%s*(.*)");
+
+ --If we haven't even finished one word, we aren't done.
+ if ( not target or not strfind(target, "%s") or (strsub(target, 1, 1) == "|") ) then
+ return false;
+ end
+
+ if ( GetAutoCompleteResults(target, tellTargetExtractionAutoComplete.include, tellTargetExtractionAutoComplete.exclude, 1, nil, true) ) then
+ --Even if there's a space, we still want to let the person keep typing -- they may be trying to type whatever is in AutoComplete.
+ return false;
+ end
+
+ --Keep pulling off everything after the last space until we either have something on the AutoComplete list or only a single word is left.
+ while ( strfind(target, "%s") ) do
+ --Pull off everything after the last space.
+ target = strmatch(target, "(.+)%s+[^%s]*");
+ if ( GetAutoCompleteResults(target, tellTargetExtractionAutoComplete.include, tellTargetExtractionAutoComplete.exclude, 1, nil, true) ) then
+ break;
+ end
+ end
+
+ msg = strsub(msg, strlen(target) + 2);
+
+ editBox:SetAttribute("tellTarget", target);
+ --BN_WHISPER FIXME
+ editBox:SetAttribute("chatType", "WHISPER");
+ editBox:SetText(msg);
+ ChatEdit_UpdateHeader(editBox);
+ return true;
+end
+
+function ChatEdit_ExtractChannel(editBox, msg)
+ local target = strmatch(msg, "%s*([^%s]+)");
+ if ( not target ) then
+ return;
+ end
+
+ local channelNum, channelName = GetChannelName(target);
+ if ( channelNum <= 0 ) then
+ return;
+ end
+
+ msg = strsub(msg, strlen(target) + 2);
+
+ editBox:SetAttribute("channelTarget", channelNum);
+ editBox:SetAttribute("chatType", "CHANNEL");
+ editBox:SetText(msg);
+ ChatEdit_UpdateHeader(editBox);
+end
+
+function ChatEdit_ExtractBNConversation(editBox, msg)
+ local target = tonumber(strmatch(msg, "%s*(%d+)"));
+ if ( not target ) then
+ return;
+ end
+
+ local conversationType = BNGetConversationInfo(target);
+ if ( not conversationType ) then
+ return;
+ end
+
+ msg = strsub(msg, strlen(tostring(target)) + 2);
+
+ editBox:SetAttribute("channelTarget", target);
+ editBox:SetAttribute("chatType", "BN_CONVERSATION");
+ editBox:SetText(msg);
+ ChatEdit_UpdateHeader(editBox);
+end
+
+-- Chat menu functions
+function ChatMenu_SetChatType(chatFrame, type)
+ local editBox = ChatFrame_OpenChat("");
+ editBox:SetAttribute("chatType", type);
+ ChatEdit_UpdateHeader(editBox);
+end
+
+function ChatMenu_Say(self)
+ ChatMenu_SetChatType(self:GetParent().chatFrame, "SAY");
+end
+
+function ChatMenu_Party(self)
+ ChatMenu_SetChatType(self:GetParent().chatFrame, "PARTY");
+end
+
+function ChatMenu_Raid(self)
+ ChatMenu_SetChatType(self:GetParent().chatFrame, "RAID");
+end
+
+function ChatMenu_Battleground(self)
+ ChatMenu_SetChatType(self:GetParent().chatFrame, "BATTLEGROUND");
+end
+
+function ChatMenu_Guild(self)
+ ChatMenu_SetChatType(self:GetParent().chatFrame, "GUILD");
+end
+
+function ChatMenu_Yell(self)
+ ChatMenu_SetChatType(self:GetParent().chatFrame, "YELL");
+end
+
+function ChatMenu_Whisper(self)
+ local editBox = ChatFrame_OpenChat(SLASH_WHISPER1.." ", chatFrame);
+ editBox:SetText(SLASH_WHISPER1.." "..editBox:GetText());
+end
+
+function ChatMenu_Emote(self)
+ ChatMenu_SetChatType(self:GetParent().chatFrame, "EMOTE");
+end
+
+function ChatMenu_Reply(self)
+ ChatFrame_ReplyTell();
+end
+
+function ChatMenu_VoiceMacro(self)
+ ChatMenu_SetChatType(self:GetParent().chatFrame, "YELL");
+end
+
+function ChatMenu_OnLoad(self)
+ self.chatFrame = DEFAULT_CHAT_FRAME;
+
+ UIMenu_Initialize(self);
+ UIMenu_AddButton(self, SAY_MESSAGE, SLASH_SAY1, ChatMenu_Say);
+ UIMenu_AddButton(self, PARTY_MESSAGE, SLASH_PARTY1, ChatMenu_Party);
+ UIMenu_AddButton(self, RAID_MESSAGE, SLASH_RAID1, ChatMenu_Raid);
+ UIMenu_AddButton(self, BATTLEGROUND_MESSAGE, SLASH_BATTLEGROUND1, ChatMenu_Battleground);
+ UIMenu_AddButton(self, GUILD_MESSAGE, SLASH_GUILD1, ChatMenu_Guild);
+ UIMenu_AddButton(self, YELL_MESSAGE, SLASH_YELL1, ChatMenu_Yell);
+ UIMenu_AddButton(self, WHISPER_MESSAGE, SLASH_WHISPER1, ChatMenu_Whisper);
+ UIMenu_AddButton(self, EMOTE_MESSAGE, SLASH_EMOTE1, ChatMenu_Emote, "EmoteMenu");
+ UIMenu_AddButton(self, REPLY_MESSAGE, SLASH_REPLY1, ChatMenu_Reply);
+ UIMenu_AddButton(self, LANGUAGE, nil, nil, "LanguageMenu");
+ UIMenu_AddButton(self, VOICEMACRO_LABEL, nil, nil, "VoiceMacroMenu");
+ UIMenu_AddButton(self, MACRO, SLASH_MACRO1, ShowMacroFrame);
+ UIMenu_AutoSize(self);
+end
+
+function ChatMenu_OnShow(self)
+ UIMenu_OnShow(self);
+ EmoteMenu:Hide();
+ LanguageMenu:Hide();
+ VoiceMacroMenu:Hide();
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+end
+
+function EmoteMenu_Click(self)
+ DoEmote(EmoteList[self:GetID()]);
+ ChatMenu:Hide();
+end
+
+function TextEmoteSort(token1, token2)
+ local i = 1;
+ local string1, string2;
+ local token = _G["EMOTE"..i.."_TOKEN"];
+ while ( token ) do
+ if ( token == token1 ) then
+ string1 = _G["EMOTE"..i.."_CMD1"];
+ if ( string2 ) then
+ break;
+ end
+ end
+ if ( token == token2 ) then
+ string2 = _G["EMOTE"..i.."_CMD1"];
+ if ( string1 ) then
+ break;
+ end
+ end
+ i = i + 1;
+ token = _G["EMOTE"..i.."_TOKEN"];
+ end
+ return string1 < string2;
+end
+
+function OnMenuLoad(self,list,func)
+ sort(list, TextEmoteSort);
+ UIMenu_Initialize(self);
+ self.parentMenu = "ChatMenu";
+ for index, value in pairs(list) do
+ local i = 1;
+ local token = _G["EMOTE"..i.."_TOKEN"];
+ while ( token ) do
+ if ( token == value ) then
+ break;
+ end
+ i = i + 1;
+ token = _G["EMOTE"..i.."_TOKEN"];
+ end
+ local label = _G["EMOTE"..i.."_CMD1"];
+ if ( not label ) then
+ label = value;
+ end
+ UIMenu_AddButton(self, label, nil, func);
+ end
+ UIMenu_AutoSize(self);
+end
+
+function EmoteMenu_OnLoad(self)
+ OnMenuLoad(self, EmoteList, EmoteMenu_Click);
+end
+
+function LanguageMenu_OnLoad(self)
+ UIMenu_Initialize(self);
+ self.parentMenu = "ChatMenu";
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("LANGUAGE_LIST_CHANGED");
+end
+
+function VoiceMacroMenu_Click(self)
+ DoEmote(TextEmoteSpeechList[self:GetID()]);
+ ChatMenu:Hide();
+end
+
+function VoiceMacroMenu_OnLoad(self)
+ OnMenuLoad(self, TextEmoteSpeechList, VoiceMacroMenu_Click);
+end
+
+function LanguageMenu_OnEvent(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self:Hide();
+ UIMenu_Initialize(self);
+ LanguageMenu_LoadLanguages(self);
+ self:GetParent().chatFrame.editBox.language = GetDefaultLanguage();
+ return;
+ end
+ if ( event == "LANGUAGE_LIST_CHANGED" ) then
+ self:Hide();
+ UIMenu_Initialize(self);
+ LanguageMenu_LoadLanguages(self);
+ return;
+ end
+end
+
+function LanguageMenu_LoadLanguages(self)
+ local numLanguages = GetNumLanguages();
+ local i;
+ local editBoxLanguage = self:GetParent().chatFrame.editBox.language;
+ local languageKnown = false;
+ for i = 1, numLanguages, 1 do
+ local language = GetLanguageByIndex(i);
+ UIMenu_AddButton(self, language, nil, LanguageMenu_Click);
+ if ( language == editBoxLanguage ) then
+ languageKnown = true;
+ end
+ end
+
+ if ( languageKnown ~= true ) then
+ self:GetParent().chatFrame.editBox.language = GetLanguageByIndex(1);
+ end
+
+ UIMenu_AutoSize(self);
+end
+
+function LanguageMenu_Click(self)
+ self:GetParent():GetParent().chatFrame.editBox.language = GetLanguageByIndex(self:GetID());
+ ChatMenu:Hide();
+end
+
+function ChatFrame_ActivateCombatMessages(chatFrame)
+ ChatFrame_AddMessageGroup(chatFrame, "OPENING");
+ ChatFrame_AddMessageGroup(chatFrame, "TRADESKILLS");
+ ChatFrame_AddMessageGroup(chatFrame, "PET_INFO");
+ ChatFrame_AddMessageGroup(chatFrame, "COMBAT_MISC_INFO");
+ ChatFrame_AddMessageGroup(chatFrame, "COMBAT_XP_GAIN");
+ ChatFrame_AddMessageGroup(chatFrame, "COMBAT_HONOR_GAIN");
+ ChatFrame_AddMessageGroup(chatFrame, "COMBAT_FACTION_CHANGE");
+end
+
+function ChatChannelDropDown_Show(chatFrame, chatType, chatTarget, chatName)
+ HideDropDownMenu(1);
+ ChatChannelDropDown.initialize = ChatChannelDropDown_Initialize;
+ ChatChannelDropDown.displayMode = "MENU";
+ ChatChannelDropDown.chatType = chatType;
+ ChatChannelDropDown.chatTarget = chatTarget;
+ ChatChannelDropDown.chatName = chatName;
+ ChatChannelDropDown.chatFrame = chatFrame;
+ ToggleDropDownMenu(1, nil, ChatChannelDropDown, "cursor");
+end
+
+function ChatChannelDropDown_Initialize()
+ local frame = ChatChannelDropDown;
+
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = frame.chatName;
+ info.notCheckable = true;
+ info.isTitle = true;
+ UIDropDownMenu_AddButton(info, 1);
+
+ info = UIDropDownMenu_CreateInfo();
+
+ if ( frame.chatType ~= "BN_CONVERSATION" or (FCFManager_GetNumDedicatedFrames(frame.chatType, frame.chatTarget) == 0)) then
+ if ( frame.chatType == "BN_CONVERSATION" ) then
+ info.text = MOVE_TO_CONVERSATION_WINDOW;
+ else
+ info.text = MOVE_TO_NEW_WINDOW;
+ end
+ info.notCheckable = 1;
+ info.func = ChatChannelDropDown_PopOutChat;
+ info.arg1 = frame.chatType;
+ info.arg2 = frame.chatTarget;
+
+ if ( frame.chatType ~= "BN_CONVERSATION" and FCF_GetNumActiveChatFrames() == NUM_CHAT_WINDOWS ) then
+ info.disabled = 1;
+ end
+
+ UIDropDownMenu_AddButton(info);
+ end
+
+ if ( frame.chatType == "BN_CONVERSATION" ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = INVITE_FRIEND_TO_CONVERSATION;
+ info.notCheckable = 1;
+ info.func = ChatChannelDropDown_InviteToConversation;
+ info.arg1 = frame.chatType;
+ info.arg2 = frame.chatTarget;
+ UIDropDownMenu_AddButton(info);
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = LEAVE_CONVERSATION;
+ info.notCheckable = 1;
+ info.func = ChatChannelDropDown_LeaveConversation;
+ info.arg1 = frame.chatType;
+ info.arg2 = frame.chatTarget;
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function ChatChannelDropDown_InviteToConversation(self, chatType, chatTarget)
+ if ( chatType == "BN_CONVERSATION" ) then
+ BNConversationInvite_SelectPlayers(chatTarget);
+ end
+end
+
+function ChatChannelDropDown_LeaveConversation(self, chatType, chatTarget)
+ BNLeaveConversation(chatTarget);
+end
+
+function ChatChannelDropDown_PopOutChat(self, chatType, chatTarget)
+ local sourceChatFrame = ChatChannelDropDown.chatFrame;
+
+ if ( chatType == "BN_CONVERSATION" ) then
+ FCF_OpenTemporaryWindow(chatType, chatTarget, sourceChatFrame, true);
+ else
+ local windowName;
+ if ( chatType == "CHANNEL" ) then
+ windowName = Chat_GetChannelShortcutName(chatTarget);
+ else
+ windowName = _G[chatType];
+ end
+ local frame = FCF_OpenNewWindow(windowName);
+ FCF_CopyChatSettings(frame, sourceChatFrame);
+
+ ChatFrame_RemoveAllMessageGroups(frame);
+ ChatFrame_RemoveAllChannels(frame);
+ ChatFrame_ReceiveAllPrivateMessages(frame);
+ ChatFrame_ReceiveAllBNConversations(frame);
+
+ ChatFrame_AddMessageGroup(frame, chatType);
+
+ if ( CHAT_CATEGORY_LIST[chatType] ) then
+ for _, chat in pairs(CHAT_CATEGORY_LIST[chatType]) do
+ ChatFrame_AddMessageGroup(frame, chat);
+ end
+ end
+
+ frame.editBox:SetAttribute("chatType", chatType);
+ frame.editBox:SetAttribute("stickyType", chatType);
+
+ if ( chatType == "CHANNEL" ) then
+ frame.editBox:SetAttribute("channelTarget", chatTarget);
+ ChatFrame_AddChannel(frame, Chat_GetChannelShortcutName(chatTarget));
+ end
+
+ --Remove the things popped out from the source chat frame.
+ if ( chatType == "CHANNEL" ) then
+ ChatFrame_RemoveChannel(sourceChatFrame, Chat_GetChannelShortcutName(chatTarget));
+ else
+ ChatFrame_RemoveMessageGroup(sourceChatFrame, chatType);
+ if ( CHAT_CATEGORY_LIST[chatType] ) then
+ for _, chat in pairs(CHAT_CATEGORY_LIST[chatType]) do
+ ChatFrame_RemoveMessageGroup(sourceChatFrame, chat);
+ end
+ end
+ end
+
+ --Copy over messages
+ local accessID = ChatHistory_GetAccessID(chatType, chatTarget);
+ for i = 1, sourceChatFrame:GetNumMessages(accessID) do
+ local text, accessID, lineID, extraData = sourceChatFrame:GetMessageInfo(i, accessID);
+ local cType, cTarget = ChatHistory_GetChatType(extraData);
+
+ local info = ChatTypeInfo[cType];
+ frame:AddMessage(text, info.r, info.g, info.b, lineID, false, accessID, extraData);
+ end
+ --Remove the messages from the old frame.
+ sourceChatFrame:RemoveMessagesByAccessID(accessID);
+ end
+end
+
+function Chat_GetChannelShortcutName(index)
+ local _, name = GetChannelName(index);
+ name = strtrim(name:match("([^%-]+)"));
+ return name;
+end
+
+function ChatChannelDropDown_PopInChat(self, chatType, chatTarget)
+ --PopOutChat_PopInChat(chatType, chatTarget);
+end
+
+function Chat_GetColoredChatName(chatType, chatTarget)
+ if ( chatType == "CHANNEL" ) then
+ local info = ChatTypeInfo["CHANNEL"..chatTarget];
+ local colorString = format("|cff%02x%02x%02x", info.r * 255, info.g * 255, info.b * 255);
+ local chanNum, channelName = GetChannelName(chatTarget);
+ return format("%s|Hchannel:channel:%d|h[%d. %s]|h", colorString, chanNum, chanNum, gsub(channelName, "%s%-%s.*", "")); --The gsub removes zone-specific markings (e.g. "General - Ironforge" to "General")
+ elseif ( chatType == "WHISPER" ) then
+ local info = ChatTypeInfo["WHISPER"];
+ local colorString = format("|cff%02x%02x%02x", info.r * 255, info.g * 255, info.b * 255);
+ return format("%s[%s] |Hplayer:%3$s|h[%3$s]|h|r", colorString, _G[chatType], chatTarget);
+ else
+ local info = ChatTypeInfo[chatType];
+ local colorString = format("|cff%02x%02x%02x", info.r * 255, info.g * 255, info.b * 255);
+ return format("%s|Hchannel:%s|h[%s]|h|r", colorString, chatType, _G[chatType]);
+ end
+end
\ No newline at end of file
diff --git a/reference/FrameXML/ChatFrame.xml b/reference/FrameXML/ChatFrame.xml
new file mode 100644
index 0000000..f31c60f
--- /dev/null
+++ b/reference/FrameXML/ChatFrame.xml
@@ -0,0 +1,174 @@
+
+
+
+
+
+ ChatFrame_OnLoad(self);
+
+
+ ChatFrame_OnEvent(self, event, ...);
+
+
+ ChatFrame_OnUpdate(self, elapsed);
+
+
+ ChatFrame_OnHyperlinkShow(self, link, text, button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():ToggleInputLanguage();
+
+
+
+
+
+
+
+
+ ChatEdit_OnLoad(self);
+
+
+ ChatEdit_OnEvent(self, event, ...);
+
+
+ ChatEdit_OnShow(self);
+
+
+ ChatEdit_OnHide(self);
+
+
+ ChatEdit_OnEditFocusGained(self);
+
+
+ ChatEdit_OnEditFocusLost(self);
+
+
+ ChatEdit_OnUpdate(self, elapsed);
+
+
+ ChatEdit_OnEnterPressed(self);
+
+
+ ChatEdit_OnEscapePressed(self);
+
+
+ ChatEdit_OnSpacePressed(self);
+
+
+ ChatEdit_OnTabPressed(self);
+
+
+ ChatEdit_OnTextChanged(self, userInput);
+
+
+ ChatEdit_OnTextSet(self);
+
+
+ ChatEdit_OnInputLanguageChanged(self, language);
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/CinematicFrame.lua b/reference/FrameXML/CinematicFrame.lua
new file mode 100644
index 0000000..3a56966
--- /dev/null
+++ b/reference/FrameXML/CinematicFrame.lua
@@ -0,0 +1,32 @@
+
+function CinematicFrame_OnLoad(self)
+ self:RegisterEvent("CINEMATIC_START");
+ self:RegisterEvent("CINEMATIC_STOP");
+
+ local width = GetScreenWidth();
+ local height = GetScreenHeight();
+
+ if ( width / height > 4 / 3) then
+ local desiredHeight = width / 2;
+ if ( desiredHeight > height ) then
+ desiredHeight = height;
+ end
+
+ local blackBarHeight = ( height - desiredHeight ) / 2;
+
+ UpperBlackBar:SetHeight( blackBarHeight );
+ UpperBlackBar:SetWidth( width );
+ LowerBlackBar:SetHeight( blackBarHeight );
+ LowerBlackBar:SetWidth( width );
+ end
+
+
+end
+
+function CinematicFrame_OnEvent(self, event, ...)
+ if ( event == "CINEMATIC_START" ) then
+ ShowUIPanel(self, 1);
+ elseif ( event == "CINEMATIC_STOP" ) then
+ HideUIPanel(self);
+ end
+end
diff --git a/reference/FrameXML/CinematicFrame.xml b/reference/FrameXML/CinematicFrame.xml
new file mode 100644
index 0000000..30ef72c
--- /dev/null
+++ b/reference/FrameXML/CinematicFrame.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GetBindingFromClick(key) == "TOGGLEGAMEMENU" ) then
+ StopCinematic();
+ elseif ( GetBindingFromClick(key) == "SCREENSHOT" ) then
+ RunBinding("SCREENSHOT");
+ end
+
+
+
+
diff --git a/reference/FrameXML/ClassTrainerFrameTemplates.xml b/reference/FrameXML/ClassTrainerFrameTemplates.xml
new file mode 100644
index 0000000..9afce1e
--- /dev/null
+++ b/reference/FrameXML/ClassTrainerFrameTemplates.xml
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 1);
+
+
+
+ _G[self:GetName().."SubText"]:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+
+
+ _G[self:GetName().."SubText"]:SetTextColor(self.r, self.g, self.b);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ScrollFrame_OnLoad(self);
+ self.scrollBarHideable = 1;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/CoinPickupFrame.lua b/reference/FrameXML/CoinPickupFrame.lua
new file mode 100644
index 0000000..1e8a68c
--- /dev/null
+++ b/reference/FrameXML/CoinPickupFrame.lua
@@ -0,0 +1,248 @@
+COINFRAME_BINDING_CACHE = {}
+
+function OpenCoinPickupFrame(multiplier, maxMoney, parent)
+ if ( CoinPickupFrame.owner ) then
+ CoinPickupFrame.owner.hasPickup = 0;
+ end
+
+ if ( GetCursorMoney() > 0 ) then
+ if ( CoinPickupFrame.owner ) then
+ MoneyTypeInfo[parent.moneyType].DropFunc(CoinPickupFrame);
+ PlaySound("igBackPackCoinSelect");
+ end
+ CoinPickupFrame:Hide();
+ return;
+ end
+
+ CoinPickupFrame.multiplier = multiplier;
+ CoinPickupFrame.maxMoney = floor(maxMoney / multiplier);
+ if ( CoinPickupFrame.maxMoney == 0 ) then
+ CoinPickupFrame:Hide();
+ return;
+ end
+
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ if ( not CoinPickupFrame.colorBlind ) then
+ CoinPickupCopperIcon:Hide();
+ CoinPickupSilverIcon:Hide();
+ CoinPickupGoldIcon:Hide();
+ CoinPickupText:SetPoint("RIGHT", -38, 18);
+ CoinPickupFrame.colorBlind = true;
+ end
+
+ if ( multiplier == 1 ) then
+ CoinPickupFrame.symbol = COPPER_AMOUNT_SYMBOL;
+ elseif ( multiplier == COPPER_PER_SILVER ) then
+ CoinPickupFrame.symbol = SILVER_AMOUNT_SYMBOL;
+ elseif ( multiplier == COPPER_PER_GOLD ) then
+ CoinPickupFrame.symbol = GOLD_AMOUNT_SYMBOL;
+ end
+ else
+ CoinPickupFrame.symbol = "";
+ if ( CoinPickupFrame.colorBlind ) then
+ CoinPickupText:SetPoint("RIGHT", -38, 18);
+ CoinPickupFrame.colorBlind = nil;
+ end
+
+
+ if ( multiplier == 1 ) then
+ CoinPickupCopperIcon:Show();
+ else
+ CoinPickupCopperIcon:Hide();
+ end
+
+ if ( multiplier == COPPER_PER_SILVER ) then
+ CoinPickupSilverIcon:Show();
+ else
+ CoinPickupSilverIcon:Hide();
+ end
+
+ if ( multiplier == (COPPER_PER_GOLD) ) then
+ CoinPickupGoldIcon:Show();
+ else
+ CoinPickupGoldIcon:Hide();
+ end
+ end
+
+ CoinPickupFrame.owner = parent;
+ CoinPickupFrame.money = 1;
+ CoinPickupFrame.typing = 0;
+ CoinPickupText:SetText(CoinPickupFrame.money .. CoinPickupFrame.symbol);
+ CoinPickupLeftButton:Disable();
+ CoinPickupRightButton:Enable();
+
+ CoinPickupFrame:SetPoint("BOTTOMRIGHT", parent, "TOPRIGHT", 0, 0);
+ CoinPickupFrame:Show();
+ PlaySound("igBackPackCoinSelect");
+end
+
+function UpdateCoinPickupFrame(maxMoney)
+ if ( not CoinPickupFrame.multiplier ) then
+ return;
+ end
+ CoinPickupFrame.maxMoney = floor(maxMoney / CoinPickupFrame.multiplier);
+ if ( CoinPickupFrame.maxMoney == 0 ) then
+ if ( CoinPickupFrame.owner ) then
+ CoinPickupFrame.owner.hasPickup = 0;
+ end
+ CoinPickupFrame:Hide();
+ return;
+ end
+
+ if ( not CoinPickupFrame.money or not CoinPickupFrame.maxMoney ) then
+ -- Failsafe
+ return;
+ end
+
+ if ( CoinPickupFrame.money > CoinPickupFrame.maxMoney ) then
+ CoinPickupFrame.money = CoinPickupFrame.maxMoney;
+ CoinPickupText:SetText(CoinPickupFrame.money .. CoinPickupFrame.symbol);
+ end
+
+ if ( CoinPickupFrame.money == CoinPickupFrame.maxMoney ) then
+ CoinPickupRightButton:Disable();
+ else
+ CoinPickupRightButton:Enable();
+ end
+
+ if ( CoinPickupFrame.money == 1 ) then
+ CoinPickupLeftButton:Disable();
+ else
+ CoinPickupLeftButton:Enable();
+ end
+end
+
+function CoinPickupFrame_OnChar(self, text)
+ if ( text < "0" or text > "9" ) then
+ return;
+ end
+
+ if ( self.typing == 0 ) then
+ self.typing = 1;
+ self.money = 0;
+ end
+
+ local money = (self.money * 10) + text;
+ if ( money == self.money ) then
+ if( self.money == 0 ) then
+ self.money = 1;
+ end
+ return;
+ end
+
+ if ( money <= self.maxMoney ) then
+ self.money = money;
+ CoinPickupText:SetText(money .. CoinPickupFrame.symbol);
+ if ( money == self.maxMoney ) then
+ CoinPickupRightButton:Disable();
+ else
+ CoinPickupRightButton:Enable();
+ end
+ if ( money == 1 ) then
+ CoinPickupLeftButton:Disable();
+ else
+ CoinPickupLeftButton:Enable();
+ end
+ elseif ( money == 0 ) then
+ self.money = 1;
+ end
+end
+
+function CoinPickupFrame_OnKeyDown(self, key)
+ if ( key == "BACKSPACE" or key == "DELETE" ) then
+ if ( self.typing == 0 or self.money == 1 ) then
+ return;
+ end
+
+ self.money = floor(self.money / 10);
+ if ( self.money <= 1 ) then
+ self.money = 1;
+ self.typing = 0;
+ CoinPickupLeftButton:Disable();
+ else
+ CoinPickupLeftButton:Enable();
+ end
+ CoinPickupText:SetText(self.money .. self.symbol);
+ if ( self.money == self.maxMoney ) then
+ CoinPickupRightButton:Disable();
+ else
+ CoinPickupRightButton:Enable();
+ end
+ elseif ( key == "ENTER" ) then
+ CoinPickupFrameOkay_Click();
+ elseif ( GetBindingFromClick(key) == "TOGGLEGAMEMENU" ) then
+ CoinPickupFrameCancel_Click();
+ elseif ( key == "LEFT" or key == "DOWN" ) then
+ CoinPickupFrameLeft_Click();
+ elseif ( key == "RIGHT" or key == "UP" ) then
+ CoinPickupFrameRight_Click();
+ elseif ( not ( tonumber(key) ) and GetBindingAction(key) ) then
+ --Running bindings not used by the CoinPickup frame allows players to retain control of their characters.
+ RunBinding(GetBindingAction(key));
+ end
+
+ COINFRAME_BINDING_CACHE[key] = true;
+end
+
+function CoinPickupFrame_OnKeyUp(self, key)
+ if ( not ( tonumber(key) ) and GetBindingAction(key) ) then
+ --If we don't run the up bindings as well, interesting things happen (like you never stop moving)
+ RunBinding(GetBindingAction(key), "up");
+ end
+
+ COINFRAME_BINDING_CACHE[key] = nil;
+end
+
+function CoinPickupFrameLeft_Click()
+ if ( CoinPickupFrame.money == 1 ) then
+ return;
+ end
+
+ CoinPickupFrame.money = CoinPickupFrame.money - 1;
+ CoinPickupText:SetText(CoinPickupFrame.money .. CoinPickupFrame.symbol);
+ if ( CoinPickupFrame.money == 1 ) then
+ CoinPickupLeftButton:Disable();
+ end
+ CoinPickupRightButton:Enable();
+end
+
+function CoinPickupFrameRight_Click()
+ if ( CoinPickupFrame.money == CoinPickupFrame.maxMoney ) then
+ return;
+ end
+
+ CoinPickupFrame.money = CoinPickupFrame.money + 1;
+ CoinPickupText:SetText(CoinPickupFrame.money .. CoinPickupFrame.symbol);
+ if ( CoinPickupFrame.money == CoinPickupFrame.maxMoney ) then
+ CoinPickupRightButton:Disable();
+ end
+ CoinPickupLeftButton:Enable();
+end
+
+function CoinPickupFrameOkay_Click()
+ if ( (CoinPickupFrame.money > 0) and CoinPickupFrame.owner ) then
+ MoneyTypeInfo[CoinPickupFrame.owner.moneyType].PickupFunc(CoinPickupFrame, CoinPickupFrame.money * CoinPickupFrame.multiplier);
+ end
+ CoinPickupFrame:Hide();
+ PlaySound("igBackPackCoinOK");
+end
+
+function CoinPickupFrameCancel_Click()
+ CoinPickupFrame:Hide();
+ PlaySound("igBackPackCoinCancel");
+end
+
+function CoinPickupFrame_OnHide()
+ if ( CoinPickupFrame.owner ) then
+ CoinPickupFrame.owner.hasPickup = 0;
+ end
+
+ for key in next, COINFRAME_BINDING_CACHE do
+ if ( GetBindingAction(key) ) then
+ RunBinding(GetBindingAction(key), "up");
+ end
+ COINFRAME_BINDING_CACHE[key] = nil;
+ end
+
+ PlaySound("MONEYFRAMECLOSE");
+end
diff --git a/reference/FrameXML/CoinPickupFrame.xml b/reference/FrameXML/CoinPickupFrame.xml
new file mode 100644
index 0000000..7dafff6
--- /dev/null
+++ b/reference/FrameXML/CoinPickupFrame.xml
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("MONEYFRAMEOPEN");
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/ColorPickerFrame.xml b/reference/FrameXML/ColorPickerFrame.xml
new file mode 100644
index 0000000..1dfa5a2
--- /dev/null
+++ b/reference/FrameXML/ColorPickerFrame.xml
@@ -0,0 +1,340 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(self:GetParent());
+ if ( ColorPickerFrame.cancelFunc ) then
+ ColorPickerFrame.cancelFunc(ColorPickerFrame.previousValues);
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(self:GetParent());
+ ColorPickerFrame.func();
+ if ( ColorPickerFrame.opacityFunc ) then
+ ColorPickerFrame.opacityFunc();
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( ColorPickerFrame.opacityFunc ) then
+ ColorPickerFrame.opacityFunc();
+ end
+
+
+
+
+
+
+
+
+
+
+
+ if ( self.hasOpacity ) then
+ OpacitySliderFrame:Show();
+ OpacitySliderFrame:SetValue(self.opacity);
+ self:SetWidth(365);
+ else
+ OpacitySliderFrame:Hide();
+ self:SetWidth(305);
+ end
+
+
+ ColorSwatch:SetTexture(r, g, b);
+ if ( self.func ) then
+ self.func();
+ end
+
+
+ if ( GetBindingFromClick(key) == "TOGGLEGAMEMENU" ) then
+ HideUIPanel(self);
+ if ( ColorPickerFrame.cancelFunc ) then
+ ColorPickerFrame.cancelFunc(ColorPickerFrame.previousValues);
+ end
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( OpacityFrame.opacityFunc ) then
+ OpacityFrame.opacityFunc();
+ end
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel()-1);
+ self:RegisterForClicks("LeftButtonDown", "RightButtonDown");
+
+
+ OpacityFrame:Hide();
+ if ( OpacityFrame.saveOpacityFunc ) then
+ OpacityFrame.saveOpacityFunc();
+ end
+
+
+
+
+
+
+ OpacityFrameCloseButton:Show();
+
+
+ OpacityFrameCloseButton:Hide();
+
+
+
+
diff --git a/reference/FrameXML/CombatFeedback.lua b/reference/FrameXML/CombatFeedback.lua
new file mode 100644
index 0000000..826379c
--- /dev/null
+++ b/reference/FrameXML/CombatFeedback.lua
@@ -0,0 +1,229 @@
+
+COMBATFEEDBACK_FADEINTIME = 0.2;
+COMBATFEEDBACK_HOLDTIME = 0.7;
+COMBATFEEDBACK_FADEOUTTIME = 0.3;
+
+SCHOOL_MASK_NONE = 0x00;
+SCHOOL_MASK_PHYSICAL = 0x01;
+SCHOOL_MASK_HOLY = 0x02;
+SCHOOL_MASK_FIRE = 0x04;
+SCHOOL_MASK_NATURE = 0x08;
+SCHOOL_MASK_FROST = 0x10;
+SCHOOL_MASK_SHADOW = 0x20;
+SCHOOL_MASK_ARCANE = 0x40;
+
+CombatFeedbackText = { };
+CombatFeedbackText["INTERRUPT"] = INTERRUPT;
+CombatFeedbackText["MISS"] = MISS;
+CombatFeedbackText["RESIST"] = RESIST;
+CombatFeedbackText["DODGE"] = DODGE;
+CombatFeedbackText["PARRY"] = PARRY;
+CombatFeedbackText["BLOCK"] = BLOCK;
+CombatFeedbackText["EVADE"] = EVADE;
+CombatFeedbackText["IMMUNE"] = IMMUNE;
+CombatFeedbackText["DEFLECT"] = DEFLECT;
+CombatFeedbackText["ABSORB"] = ABSORB;
+CombatFeedbackText["REFLECT"] = REFLECT;
+
+LOWHEALTH_MIN_ALPHA = 0.4;
+LOWHEALTH_MAX_ALPHA = 0.9;
+
+
+function CombatFeedback_Initialize(self, feedbackText, fontHeight)
+ self.feedbackText = feedbackText;
+ self.feedbackFontHeight = fontHeight;
+end
+
+function CombatFeedback_OnCombatEvent(self, event, flags, amount, type)
+ local feedbackText = self.feedbackText;
+ local fontHeight = self.feedbackFontHeight;
+ local text = "";
+ local r = 1.0;
+ local g = 1.0;
+ local b = 1.0;
+
+ if( event == "IMMUNE" ) then
+ fontHeight = fontHeight * 0.5;
+ text = CombatFeedbackText[event];
+ elseif ( event == "WOUND" ) then
+ if ( amount ~= 0 ) then
+ if ( flags == "CRITICAL" or flags == "CRUSHING" ) then
+ fontHeight = fontHeight * 1.5;
+ elseif ( flags == "GLANCING" ) then
+ fontHeight = fontHeight * 0.75;
+ end
+ if ( type ~= SCHOOL_MASK_PHYSICAL ) then
+ r = 1.0;
+ g = 1.0;
+ b = 0.0;
+ end
+ text = amount;
+ elseif ( flags == "ABSORB" ) then
+ fontHeight = fontHeight * 0.75;
+ text = CombatFeedbackText["ABSORB"];
+ elseif ( flags == "BLOCK" ) then
+ fontHeight = fontHeight * 0.75;
+ text = CombatFeedbackText["BLOCK"];
+ elseif ( flags == "RESIST" ) then
+ fontHeight = fontHeight * 0.75;
+ text = CombatFeedbackText["RESIST"];
+ else
+ text = CombatFeedbackText["MISS"];
+ end
+ elseif ( event == "BLOCK" ) then
+ fontHeight = fontHeight * 0.75;
+ text = CombatFeedbackText[event];
+ elseif ( event == "HEAL" ) then
+ text = amount;
+ r = 0.0;
+ g = 1.0;
+ b = 0.0;
+ if ( flags == "CRITICAL" ) then
+ fontHeight = fontHeight * 1.5;
+ end
+ elseif ( event == "ENERGIZE" ) then
+ text = amount;
+ r = 0.41;
+ g = 0.8;
+ b = 0.94;
+ if ( flags == "CRITICAL" ) then
+ fontHeight = fontHeight * 1.5;
+ end
+ else
+ text = CombatFeedbackText[event];
+ end
+
+ self.feedbackStartTime = GetTime();
+
+ feedbackText:SetTextHeight(fontHeight);
+ feedbackText:SetText(text);
+ feedbackText:SetTextColor(r, g, b);
+ feedbackText:SetAlpha(0.0);
+ feedbackText:Show();
+end
+
+function CombatFeedback_OnUpdate(self, elapsed)
+ local feedbackText = self.feedbackText;
+ if ( feedbackText:IsVisible() ) then
+ local elapsedTime = GetTime() - self.feedbackStartTime;
+ local fadeInTime = COMBATFEEDBACK_FADEINTIME;
+ if ( elapsedTime < fadeInTime ) then
+ local alpha = (elapsedTime / fadeInTime);
+ feedbackText:SetAlpha(alpha);
+ return;
+ end
+ local holdTime = COMBATFEEDBACK_HOLDTIME;
+ if ( elapsedTime < (fadeInTime + holdTime) ) then
+ feedbackText:SetAlpha(1.0);
+ return;
+ end
+ local fadeOutTime = COMBATFEEDBACK_FADEOUTTIME;
+ if ( elapsedTime < (fadeInTime + holdTime + fadeOutTime) ) then
+ local alpha = 1.0 - ((elapsedTime - holdTime - fadeInTime) / fadeOutTime);
+ feedbackText:SetAlpha(alpha);
+ return;
+ end
+ feedbackText:Hide();
+ end
+end
+
+function CombatFeedback_StartFullscreenStatus()
+ LowHealthFrame_StartFlashing(0.7, 0.7);
+end
+
+function CombatFeedback_StopFullscreenStatus()
+ LowHealthFrame_StopFlashing();
+end
+
+function LowHealthFrame_StartFlashing(fadeInTime, fadeOutTime, flashDuration, flashInHoldTime, flashOutHoldTime)
+ -- Time it takes to fade in a flashing frame
+ LowHealthFrame.fadeInTime = fadeInTime;
+ -- Time it takes to fade out a flashing frame
+ LowHealthFrame.fadeOutTime = fadeOutTime;
+ -- How long to keep the frame flashing
+ LowHealthFrame.flashDuration = flashDuration;
+ -- How long to hold the faded in state
+ LowHealthFrame.flashInHoldTime = flashInHoldTime;
+ -- How long to hold the faded out state
+ LowHealthFrame.flashOutHoldTime = flashOutHoldTime;
+
+ LowHealthFrame.flashMode = "IN";
+ LowHealthFrame.flashTimer = 0; -- timer for the current flash mode
+ LowHealthFrame.flashDurationTimer = 0; -- timer for the entire flash
+
+ LowHealthFrame:SetAlpha(LOWHEALTH_MIN_ALPHA);
+ LowHealthFrame:Show();
+
+ LowHealthFrame:SetScript("OnUpdate", LowHealthFrame_OnUpdate);
+end
+
+function LowHealthFrame_OnUpdate(self, elapsed)
+ self.flashDurationTimer = self.flashDurationTimer + elapsed;
+ -- If flashDuration is exceeded
+ if ( self.flashDuration and (self.flashDurationTimer > self.flashDuration) ) then
+ LowHealthFrame_StopFlashing();
+ else
+ if ( self.flashMode == "IN" ) then
+ local alpha = LOWHEALTH_MIN_ALPHA + (LOWHEALTH_MAX_ALPHA - LOWHEALTH_MIN_ALPHA) * (self.flashTimer / self.fadeOutTime);
+ self:SetAlpha(alpha);
+
+ if ( self.flashTimer >= self.fadeInTime ) then
+ if ( self.flashInHoldTime and self.flashInHoldTime > 0 ) then
+ self.flashMode = "IN_HOLD";
+ else
+ self.flashMode = "OUT";
+ end
+ self.flashTimer = 0;
+ else
+ self.flashTimer = self.flashTimer + elapsed;
+ end
+ elseif ( self.flashMode == "IN_HOLD" ) then
+ self:SetAlpha(LOWHEALTH_MAX_ALPHA);
+
+ if ( self.flashTimer >= self.flashInHoldTime ) then
+ self.flashMode = "OUT";
+ self.flashTimer = 0;
+ else
+ self.flashTimer = self.flashTimer + elapsed;
+ end
+ elseif ( self.flashMode == "OUT" ) then
+ local alpha = LOWHEALTH_MAX_ALPHA + (LOWHEALTH_MIN_ALPHA - LOWHEALTH_MAX_ALPHA) * (self.flashTimer / self.fadeOutTime);
+ self:SetAlpha(alpha);
+
+ if ( self.flashTimer >= self.fadeOutTime ) then
+ if ( self.flashOutHoldTime and self.flashOutHoldTime > 0 ) then
+ self.flashMode = "OUT_HOLD";
+ else
+ self.flashMode = "IN";
+ end
+ self.flashTimer = 0;
+ else
+ self.flashTimer = self.flashTimer + elapsed;
+ end
+ self:SetAlpha(alpha);
+ elseif ( self.flashMode == "OUT_HOLD" ) then
+ self:SetAlpha(LOWHEALTH_MIN_ALPHA);
+
+ self.flashTimer = self.flashTimer + elapsed;
+ if ( self.flashTimer >= self.flashOutHoldTime ) then
+ self.flashMode = "IN";
+ self.flashTimer = 0;
+ else
+ self.flashTimer = self.flashTimer + elapsed;
+ end
+ end
+ end
+
+ if ( not GetUIPanel("fullscreen") ) then
+ -- this feature is only supposed to be seen when the screen is covered
+ -- also, alpha is set to 0 so OnUpdate can be called
+ self:SetAlpha(0.0);
+ end
+end
+
+function LowHealthFrame_StopFlashing()
+ if ( LowHealthFrame:IsShown() ) then
+ LowHealthFrame:SetScript("OnUpdate", nil);
+ LowHealthFrame:Hide();
+ end
+end
diff --git a/reference/FrameXML/CombatFeedback.xml b/reference/FrameXML/CombatFeedback.xml
new file mode 100644
index 0000000..7a5eccb
--- /dev/null
+++ b/reference/FrameXML/CombatFeedback.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/ComboFrame.lua b/reference/FrameXML/ComboFrame.lua
new file mode 100644
index 0000000..4be646e
--- /dev/null
+++ b/reference/FrameXML/ComboFrame.lua
@@ -0,0 +1,73 @@
+COMBOFRAME_FADE_IN = 0.3;
+COMBOFRAME_FADE_OUT = 0.5;
+COMBOFRAME_HIGHLIGHT_FADE_IN = 0.4;
+COMBOFRAME_SHINE_FADE_IN = 0.3;
+COMBOFRAME_SHINE_FADE_OUT = 0.4;
+COMBO_FRAME_LAST_NUM_POINTS = 0;
+
+function ComboFrame_OnEvent(self, event, ...)
+ if ( event == "PLAYER_TARGET_CHANGED" ) then
+ ComboFrame_Update();
+ elseif ( event == "UNIT_COMBO_POINTS" ) then
+ local unit = ...;
+ if ( unit == PlayerFrame.unit ) then
+ ComboFrame_Update();
+ end
+ end
+end
+
+function ComboFrame_Update()
+ local comboPoints = GetComboPoints(PlayerFrame.unit, "target");
+ local comboPoint, comboPointHighlight, comboPointShine;
+ if ( comboPoints > 0 ) then
+ if ( not ComboFrame:IsShown() ) then
+ ComboFrame:Show();
+ UIFrameFadeIn(ComboFrame, COMBOFRAME_FADE_IN);
+ end
+
+
+ for i=1, MAX_COMBO_POINTS do
+ local fadeInfo = {};
+ comboPoint = _G["ComboPoint" .. i];
+ comboPoint:Show();
+ comboPointHighlight = _G["ComboPoint"..i.."Highlight"];
+ comboPointShine = _G["ComboPoint"..i.."Shine"];
+ if ( i <= comboPoints ) then
+ if ( i > COMBO_FRAME_LAST_NUM_POINTS ) then
+ -- Fade in the highlight and set a function that triggers when it is done fading
+ fadeInfo.mode = "IN";
+ fadeInfo.timeToFade = COMBOFRAME_HIGHLIGHT_FADE_IN;
+ fadeInfo.finishedFunc = ComboPointShineFadeIn;
+ fadeInfo.finishedArg1 = comboPointShine;
+ UIFrameFade(comboPointHighlight, fadeInfo);
+ end
+ else
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ comboPoint:Hide();
+ end
+ comboPointHighlight:SetAlpha(0);
+ comboPointShine:SetAlpha(0);
+ end
+ end
+ else
+ ComboPoint1Highlight:SetAlpha(0);
+ ComboPoint1Shine:SetAlpha(0);
+ ComboFrame:Hide();
+ end
+ COMBO_FRAME_LAST_NUM_POINTS = comboPoints;
+end
+
+function ComboPointShineFadeIn(frame)
+ -- Fade in the shine and then fade it out with the ComboPointShineFadeOut function
+ local fadeInfo = {};
+ fadeInfo.mode = "IN";
+ fadeInfo.timeToFade = COMBOFRAME_SHINE_FADE_IN;
+ fadeInfo.finishedFunc = ComboPointShineFadeOut;
+ fadeInfo.finishedArg1 = frame;
+ UIFrameFade(frame, fadeInfo);
+end
+
+--hack since a frame can't have a reference to itself in it
+function ComboPointShineFadeOut(frame)
+ UIFrameFadeOut(frame, COMBOFRAME_SHINE_FADE_OUT);
+end
diff --git a/reference/FrameXML/ComboFrame.xml b/reference/FrameXML/ComboFrame.xml
new file mode 100644
index 0000000..dfc9524
--- /dev/null
+++ b/reference/FrameXML/ComboFrame.xml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("PLAYER_TARGET_CHANGED");
+ self:RegisterEvent("UNIT_COMBO_POINTS");
+ -- init alpha
+ ComboPoint1Highlight:SetAlpha(0);
+ ComboPoint1Shine:SetAlpha(0);
+
+
+
+
+
diff --git a/reference/FrameXML/Constants.lua b/reference/FrameXML/Constants.lua
new file mode 100644
index 0000000..58b1d69
--- /dev/null
+++ b/reference/FrameXML/Constants.lua
@@ -0,0 +1,479 @@
+--
+-- New constants should be added to this file and other constants
+-- deprecated and moved to this file.
+--
+
+
+--
+-- Colors
+--
+NORMAL_FONT_COLOR_CODE = "|cffffd200";
+HIGHLIGHT_FONT_COLOR_CODE = "|cffffffff";
+RED_FONT_COLOR_CODE = "|cffff2020";
+GREEN_FONT_COLOR_CODE = "|cff20ff20";
+GRAY_FONT_COLOR_CODE = "|cff808080";
+YELLOW_FONT_COLOR_CODE = "|cffffff00";
+LIGHTYELLOW_FONT_COLOR_CODE = "|cffffff9a";
+ORANGE_FONT_COLOR_CODE = "|cffff7f3f";
+FONT_COLOR_CODE_CLOSE = "|r";
+
+NORMAL_FONT_COLOR = {r=1.0, g=0.82, b=0.0};
+HIGHLIGHT_FONT_COLOR = {r=1.0, g=1.0, b=1.0};
+RED_FONT_COLOR = {r=1.0, g=0.1, b=0.1};
+GREEN_FONT_COLOR = {r=0.1, g=1.0, b=0.1};
+GRAY_FONT_COLOR = {r=0.5, g=0.5, b=0.5};
+YELLOW_FONT_COLOR = {r=1.0, g=1.0, b=0.0};
+LIGHTYELLOW_FONT_COLOR = {r=1.0, g=1.0, b=0.6};
+ORANGE_FONT_COLOR = {r=1.0, g=0.5, b=0.25};
+PASSIVE_SPELL_FONT_COLOR = {r=0.77, g=0.64, b=0.0};
+
+CHAT_FONT_HEIGHTS = {
+ [1] = 12,
+ [2] = 14,
+ [3] = 16,
+ [4] = 18
+};
+
+MATERIAL_TEXT_COLOR_TABLE = {
+ ["Default"] = {0.18, 0.12, 0.06},
+ ["Stone"] = {1.0, 1.0, 1.0},
+ ["Parchment"] = {0.18, 0.12, 0.06},
+ ["Marble"] = {0, 0, 0},
+ ["Silver"] = {0.12, 0.12, 0.12},
+ ["Bronze"] = {0.18, 0.12, 0.06}
+};
+MATERIAL_TITLETEXT_COLOR_TABLE = {
+ ["Default"] = {0, 0, 0},
+ ["Stone"] = {0.93, 0.82, 0},
+ ["Parchment"] = {0, 0, 0},
+ ["Marble"] = {0.93, 0.82, 0},
+ ["Silver"] = {0.93, 0.82, 0},
+ ["Bronze"] = {0.93, 0.82, 0}
+};
+
+RAID_CLASS_COLORS = {
+ ["HUNTER"] = { r = 0.67, g = 0.83, b = 0.45 },
+ ["WARLOCK"] = { r = 0.58, g = 0.51, b = 0.79 },
+ ["PRIEST"] = { r = 1.0, g = 1.0, b = 1.0 },
+ ["PALADIN"] = { r = 0.96, g = 0.55, b = 0.73 },
+ ["MAGE"] = { r = 0.41, g = 0.8, b = 0.94 },
+ ["ROGUE"] = { r = 1.0, g = 0.96, b = 0.41 },
+ ["DRUID"] = { r = 1.0, g = 0.49, b = 0.04 },
+ ["SHAMAN"] = { r = 0.0, g = 0.44, b = 0.87 },
+ ["WARRIOR"] = { r = 0.78, g = 0.61, b = 0.43 },
+ ["DEATHKNIGHT"] = { r = 0.77, g = 0.12 , b = 0.23 },
+};
+
+
+--
+-- Class
+--
+CLASS_SORT_ORDER = {
+ "WARRIOR",
+ "DEATHKNIGHT",
+ "PALADIN",
+ "PRIEST",
+ "SHAMAN",
+ "DRUID",
+ "ROGUE",
+ "MAGE",
+ "WARLOCK",
+ "HUNTER",
+};
+MAX_CLASSES = #CLASS_SORT_ORDER;
+
+LOCALIZED_CLASS_NAMES_MALE = {};
+LOCALIZED_CLASS_NAMES_FEMALE = {};
+FillLocalizedClassList(LOCALIZED_CLASS_NAMES_MALE, false);
+FillLocalizedClassList(LOCALIZED_CLASS_NAMES_FEMALE, true);
+
+
+CLASS_ICON_TCOORDS = {
+ ["WARRIOR"] = {0, 0.25, 0, 0.25},
+ ["MAGE"] = {0.25, 0.49609375, 0, 0.25},
+ ["ROGUE"] = {0.49609375, 0.7421875, 0, 0.25},
+ ["DRUID"] = {0.7421875, 0.98828125, 0, 0.25},
+ ["HUNTER"] = {0, 0.25, 0.25, 0.5},
+ ["SHAMAN"] = {0.25, 0.49609375, 0.25, 0.5},
+ ["PRIEST"] = {0.49609375, 0.7421875, 0.25, 0.5},
+ ["WARLOCK"] = {0.7421875, 0.98828125, 0.25, 0.5},
+ ["PALADIN"] = {0, 0.25, 0.5, 0.75},
+ ["DEATHKNIGHT"] = {0.25, .5, 0.5, .75},
+};
+
+--
+-- Spell
+--
+
+-- Power Types
+SPELL_POWER_MANA = 0;
+SPELL_POWER_RAGE = 1;
+SPELL_POWER_FOCUS = 2;
+SPELL_POWER_ENERGY = 3;
+SPELL_POWER_HAPPINESS = 4;
+SPELL_POWER_RUNES = 5;
+SPELL_POWER_RUNIC_POWER = 6;
+
+SCHOOL_MASK_NONE = 0x00;
+SCHOOL_MASK_PHYSICAL = 0x01;
+SCHOOL_MASK_HOLY = 0x02;
+SCHOOL_MASK_FIRE = 0x04;
+SCHOOL_MASK_NATURE = 0x08;
+SCHOOL_MASK_FROST = 0x10;
+SCHOOL_MASK_SHADOW = 0x20;
+SCHOOL_MASK_ARCANE = 0x40;
+
+--
+-- Talent
+--
+SHOW_TALENT_LEVEL = 10;
+SHOW_PVP_LEVEL = 10;
+SHOW_LFD_LEVEL = 15;
+
+TALENT_SORT_ORDER = {
+ "spec1",
+ "spec2",
+ "petspec1",
+};
+
+TALENT_ACTIVATION_SPELLS = {
+ 63645,
+ 63644,
+};
+
+--
+-- Glyph
+--
+SHOW_INSCRIPTION_LEVEL = 15;
+
+--
+-- Achievement
+--
+
+-- Criteria Types
+CRITERIA_TYPE_ACHIEVEMENT = 8;
+
+-- Achievement Flags
+ACHIEVEMENT_FLAGS_STATISTIC = 0x00000001;
+ACHIEVEMENT_FLAGS_HIDDEN = 0x00000002;
+ACHIEVEMENT_FLAGS_HAS_PROGRESS_BAR = 0x00000080;
+NUM_ACHIEVEMENT_FLAGS = 3;
+
+-- Criteria Flags
+ACHIEVEMENT_CRITERIA_PROGRESS_BAR = 0x00000001;
+ACHIEVEMENT_CRITERIA_HIDDEN = 0x00000002;
+NUM_ACHIEVEMENT_CRITERIA_FLAGS = 2;
+
+--
+-- Inventory
+--
+
+-- General item constants
+ITEM_UNIQUE_EQUIPPED = -1;
+MAX_NUM_SOCKETS = 3;
+
+-- Item quality
+ITEM_QUALITY_POOR = 0;
+ITEM_QUALITY_COMMON = 1;
+ITEM_QUALITY_UNCOMMON = 2;
+ITEM_QUALITY_RARE = 3;
+ITEM_QUALITY_EPIC = 4;
+
+-- Item location bitflags
+ITEM_INVENTORY_LOCATION_PLAYER = 0x00100000;
+ITEM_INVENTORY_LOCATION_BAGS = 0x00200000;
+ITEM_INVENTORY_LOCATION_BANK = 0x00400000;
+ITEM_INVENTORY_BAG_BIT_OFFSET = 8; -- Number of bits that the bag index in GetInventoryItemsForSlot gets shifted to the left.
+
+-- Inventory slots
+INVSLOT_AMMO = 0;
+INVSLOT_HEAD = 1; INVSLOT_FIRST_EQUIPPED = INVSLOT_HEAD;
+INVSLOT_NECK = 2;
+INVSLOT_SHOULDER = 3;
+INVSLOT_BODY = 4;
+INVSLOT_CHEST = 5;
+INVSLOT_WAIST = 6;
+INVSLOT_LEGS = 7;
+INVSLOT_FEET = 8;
+INVSLOT_WRIST = 9;
+INVSLOT_HAND = 10;
+INVSLOT_FINGER1 = 11;
+INVSLOT_FINGER2 = 12;
+INVSLOT_TRINKET1 = 13;
+INVSLOT_TRINKET2 = 14;
+INVSLOT_BACK = 15;
+INVSLOT_MAINHAND = 16;
+INVSLOT_OFFHAND = 17;
+INVSLOT_RANGED = 18;
+INVSLOT_TABARD = 19;
+INVSLOT_LAST_EQUIPPED = INVSLOT_TABARD;
+
+INVSLOTS_EQUIPABLE_IN_COMBAT = {
+[INVSLOT_MAINHAND] = true,
+[INVSLOT_OFFHAND] = true,
+[INVSLOT_RANGED] = true,
+}
+
+-- Container constants
+ITEM_INVENTORY_BANK_BAG_OFFSET = 4; -- Number of bags before the first bank bag
+CONTAINER_BAG_OFFSET = 19; -- Used for PutItemInBag
+
+BACKPACK_CONTAINER = 0;
+BANK_CONTAINER = -1;
+BANK_CONTAINER_INVENTORY_OFFSET = 39; -- Used for PickupInventoryItem
+KEYRING_CONTAINER = -2;
+
+NUM_BAG_SLOTS = 4;
+NUM_BANKGENERIC_SLOTS = 28;
+NUM_BANKBAGSLOTS = 7;
+
+--
+-- Equipment Set
+--
+MAX_EQUIPMENT_SETS_PER_PLAYER = 10;
+EQUIPMENT_SET_EMPTY_SLOT = 0;
+EQUIPMENT_SET_IGNORED_SLOT = 1;
+EQUIPMENT_SET_ITEM_MISSING = -1;
+
+--
+-- Combat Log
+--
+
+-- Affiliation
+COMBATLOG_OBJECT_AFFILIATION_MINE = 0x00000001;
+COMBATLOG_OBJECT_AFFILIATION_PARTY = 0x00000002;
+COMBATLOG_OBJECT_AFFILIATION_RAID = 0x00000004;
+COMBATLOG_OBJECT_AFFILIATION_OUTSIDER = 0x00000008;
+COMBATLOG_OBJECT_AFFILIATION_MASK = 0x0000000F;
+-- Reaction
+COMBATLOG_OBJECT_REACTION_FRIENDLY = 0x00000010;
+COMBATLOG_OBJECT_REACTION_NEUTRAL = 0x00000020;
+COMBATLOG_OBJECT_REACTION_HOSTILE = 0x00000040;
+COMBATLOG_OBJECT_REACTION_MASK = 0x000000F0;
+-- Ownership
+COMBATLOG_OBJECT_CONTROL_PLAYER = 0x00000100;
+COMBATLOG_OBJECT_CONTROL_NPC = 0x00000200;
+COMBATLOG_OBJECT_CONTROL_MASK = 0x00000300;
+-- Unit type
+COMBATLOG_OBJECT_TYPE_PLAYER = 0x00000400;
+COMBATLOG_OBJECT_TYPE_NPC = 0x00000800;
+COMBATLOG_OBJECT_TYPE_PET = 0x00001000;
+COMBATLOG_OBJECT_TYPE_GUARDIAN = 0x00002000;
+COMBATLOG_OBJECT_TYPE_OBJECT = 0x00004000;
+COMBATLOG_OBJECT_TYPE_MASK = 0x0000FC00;
+
+-- Special cases (non-exclusive)
+COMBATLOG_OBJECT_TARGET = 0x00010000;
+COMBATLOG_OBJECT_FOCUS = 0x00020000;
+COMBATLOG_OBJECT_MAINTANK = 0x00040000;
+COMBATLOG_OBJECT_MAINASSIST = 0x00080000;
+COMBATLOG_OBJECT_RAIDTARGET1 = 0x00100000;
+COMBATLOG_OBJECT_RAIDTARGET2 = 0x00200000;
+COMBATLOG_OBJECT_RAIDTARGET3 = 0x00400000;
+COMBATLOG_OBJECT_RAIDTARGET4 = 0x00800000;
+COMBATLOG_OBJECT_RAIDTARGET5 = 0x01000000;
+COMBATLOG_OBJECT_RAIDTARGET6 = 0x02000000;
+COMBATLOG_OBJECT_RAIDTARGET7 = 0x04000000;
+COMBATLOG_OBJECT_RAIDTARGET8 = 0x08000000;
+COMBATLOG_OBJECT_NONE = 0x80000000;
+COMBATLOG_OBJECT_SPECIAL_MASK = 0xFFFF0000;
+COMBATLOG_OBJECT_RAIDTARGET_MASK = bit.bor(
+ COMBATLOG_OBJECT_RAIDTARGET1,
+ COMBATLOG_OBJECT_RAIDTARGET2,
+ COMBATLOG_OBJECT_RAIDTARGET3,
+ COMBATLOG_OBJECT_RAIDTARGET4,
+ COMBATLOG_OBJECT_RAIDTARGET5,
+ COMBATLOG_OBJECT_RAIDTARGET6,
+ COMBATLOG_OBJECT_RAIDTARGET7,
+ COMBATLOG_OBJECT_RAIDTARGET8
+ );
+
+-- Object type constants
+COMBATLOG_FILTER_ME = bit.bor(
+ COMBATLOG_OBJECT_AFFILIATION_MINE,
+ COMBATLOG_OBJECT_REACTION_FRIENDLY,
+ COMBATLOG_OBJECT_CONTROL_PLAYER,
+ COMBATLOG_OBJECT_TYPE_PLAYER
+ );
+
+COMBATLOG_FILTER_MINE = bit.bor(
+ COMBATLOG_OBJECT_AFFILIATION_MINE,
+ COMBATLOG_OBJECT_REACTION_FRIENDLY,
+ COMBATLOG_OBJECT_CONTROL_PLAYER,
+ COMBATLOG_OBJECT_TYPE_PLAYER,
+ COMBATLOG_OBJECT_TYPE_OBJECT
+ );
+
+COMBATLOG_FILTER_MY_PET = bit.bor(
+ COMBATLOG_OBJECT_AFFILIATION_MINE,
+ COMBATLOG_OBJECT_REACTION_FRIENDLY,
+ COMBATLOG_OBJECT_CONTROL_PLAYER,
+ COMBATLOG_OBJECT_TYPE_GUARDIAN,
+ COMBATLOG_OBJECT_TYPE_PET
+ );
+COMBATLOG_FILTER_FRIENDLY_UNITS = bit.bor(
+ COMBATLOG_OBJECT_AFFILIATION_PARTY,
+ COMBATLOG_OBJECT_AFFILIATION_RAID,
+ COMBATLOG_OBJECT_AFFILIATION_OUTSIDER,
+ COMBATLOG_OBJECT_REACTION_FRIENDLY,
+ COMBATLOG_OBJECT_CONTROL_PLAYER,
+ COMBATLOG_OBJECT_CONTROL_NPC,
+ COMBATLOG_OBJECT_TYPE_PLAYER,
+ COMBATLOG_OBJECT_TYPE_NPC,
+ COMBATLOG_OBJECT_TYPE_PET,
+ COMBATLOG_OBJECT_TYPE_GUARDIAN,
+ COMBATLOG_OBJECT_TYPE_OBJECT
+ );
+
+COMBATLOG_FILTER_HOSTILE_PLAYERS = bit.bor(
+ COMBATLOG_OBJECT_AFFILIATION_PARTY,
+ COMBATLOG_OBJECT_AFFILIATION_RAID,
+ COMBATLOG_OBJECT_AFFILIATION_OUTSIDER,
+ COMBATLOG_OBJECT_REACTION_HOSTILE,
+ COMBATLOG_OBJECT_CONTROL_PLAYER,
+ COMBATLOG_OBJECT_TYPE_PLAYER,
+ COMBATLOG_OBJECT_TYPE_NPC,
+ COMBATLOG_OBJECT_TYPE_PET,
+ COMBATLOG_OBJECT_TYPE_GUARDIAN,
+ COMBATLOG_OBJECT_TYPE_OBJECT
+ );
+
+COMBATLOG_FILTER_HOSTILE_UNITS = bit.bor(
+ COMBATLOG_OBJECT_AFFILIATION_PARTY,
+ COMBATLOG_OBJECT_AFFILIATION_RAID,
+ COMBATLOG_OBJECT_AFFILIATION_OUTSIDER,
+ COMBATLOG_OBJECT_REACTION_HOSTILE,
+ COMBATLOG_OBJECT_CONTROL_NPC,
+ COMBATLOG_OBJECT_TYPE_PLAYER,
+ COMBATLOG_OBJECT_TYPE_NPC,
+ COMBATLOG_OBJECT_TYPE_PET,
+ COMBATLOG_OBJECT_TYPE_GUARDIAN,
+ COMBATLOG_OBJECT_TYPE_OBJECT
+ );
+
+COMBATLOG_FILTER_NEUTRAL_UNITS = bit.bor(
+ COMBATLOG_OBJECT_AFFILIATION_PARTY,
+ COMBATLOG_OBJECT_AFFILIATION_RAID,
+ COMBATLOG_OBJECT_AFFILIATION_OUTSIDER,
+ COMBATLOG_OBJECT_REACTION_NEUTRAL,
+ COMBATLOG_OBJECT_CONTROL_PLAYER,
+ COMBATLOG_OBJECT_CONTROL_NPC,
+ COMBATLOG_OBJECT_TYPE_PLAYER,
+ COMBATLOG_OBJECT_TYPE_NPC,
+ COMBATLOG_OBJECT_TYPE_PET,
+ COMBATLOG_OBJECT_TYPE_GUARDIAN,
+ COMBATLOG_OBJECT_TYPE_OBJECT
+ );
+COMBATLOG_FILTER_UNKNOWN_UNITS = COMBATLOG_OBJECT_NONE;
+COMBATLOG_FILTER_EVERYTHING = 0xFFFFFFFF;
+
+--
+-- Calendar
+--
+CALENDAR_FIRST_WEEKDAY = 1; -- 1=SUN 2=MON 3=TUE 4=WED 5=THU 6=FRI 7=SAT
+
+-- Event Types
+CALENDAR_EVENTTYPE_RAID = 1;
+CALENDAR_EVENTTYPE_DUNGEON = 2;
+CALENDAR_EVENTTYPE_PVP = 3;
+CALENDAR_EVENTTYPE_MEETING = 4;
+CALENDAR_EVENTTYPE_OTHER = 5;
+CALENDAR_MAX_EVENTTYPE = CALENDAR_EVENTTYPE_OTHER;
+
+-- Invite Statuses
+CALENDAR_INVITESTATUS_INVITED = 1;
+CALENDAR_INVITESTATUS_ACCEPTED = 2;
+CALENDAR_INVITESTATUS_DECLINED = 3;
+CALENDAR_INVITESTATUS_CONFIRMED = 4;
+CALENDAR_INVITESTATUS_OUT = 5;
+CALENDAR_INVITESTATUS_STANDBY = 6;
+CALENDAR_INVITESTATUS_SIGNEDUP = 7;
+CALENDAR_INVITESTATUS_NOT_SIGNEDUP = 8;
+CALENDAR_INVITESTATUS_TENTATIVE = 9;
+CALENDAR_MAX_INVITESTATUS = CALENDAR_INVITESTATUS_TENTATIVE;
+
+-- Invite Types
+CALENDAR_INVITETYPE_NORMAL = 1;
+CALENDAR_INVITETYPE_SIGNUP = 2;
+CALENDAR_MAX_INVITETYPE = CALENDAR_INVITETYPE_SIGNUP;
+
+--
+-- Difficulty
+--
+QuestDifficultyColors = {
+ ["impossible"] = { r = 1.00, g = 0.10, b = 0.10 };
+ ["verydifficult"] = { r = 1.00, g = 0.50, b = 0.25 };
+ ["difficult"] = { r = 1.00, g = 1.00, b = 0.00 };
+ ["standard"] = { r = 0.25, g = 0.75, b = 0.25 };
+ ["trivial"] = { r = 0.50, g = 0.50, b = 0.50 };
+ ["header"] = { r = 0.70, g = 0.70, b = 0.70 };
+};
+
+--
+-- WorldMap
+--
+NUM_WORLDMAP_DETAIL_TILES = 12;
+NUM_WORLDMAP_PATCH_TILES = 6;
+NUM_WORLDMAP_DETAIL_TILE_ROWS = 3;
+NUM_WORLDMAP_DETAIL_TILE_COLS = 4;
+
+--
+-- Totems
+--
+
+MAX_TOTEMS = 4;
+
+FIRE_TOTEM_SLOT = 1;
+EARTH_TOTEM_SLOT = 2;
+WATER_TOTEM_SLOT = 3;
+AIR_TOTEM_SLOT = 4;
+
+TOTEM_PRIORITIES = {
+ EARTH_TOTEM_SLOT,
+ FIRE_TOTEM_SLOT,
+ WATER_TOTEM_SLOT,
+ AIR_TOTEM_SLOT,
+};
+
+TOTEM_MULTI_CAST_SUMMON_SPELLS = {
+ 66842,
+ 66843,
+ 66844,
+};
+
+TOTEM_MULTI_CAST_RECALL_SPELLS = {
+ 36936,
+};
+
+--
+-- GM Ticket
+--
+
+GMTICKET_QUEUE_STATUS_ENABLED = 1;
+GMTICKET_QUEUE_STATUS_DISABLED = -1;
+
+GMTICKET_ASSIGNEDTOGM_STATUS_NOT_ASSIGNED = 0; -- ticket is not currently assigned to a gm
+GMTICKET_ASSIGNEDTOGM_STATUS_ASSIGNED = 1; -- ticket is assigned to a normal gm
+GMTICKET_ASSIGNEDTOGM_STATUS_ESCALATED = 2; -- ticket is in the escalation queue
+
+GMTICKET_OPENEDBYGM_STATUS_NOT_OPENED = 0; -- ticket has never been opened by a gm
+GMTICKET_OPENEDBYGM_STATUS_OPENED = 1; -- ticket has been opened by a gm
+
+
+-- indicies for adding lights ModelFFX:Add*Light
+LIGHT_LIVE = 0;
+LIGHT_GHOST = 1;
+
+-- general constant translation table
+STATIC_CONSTANTS = {}
+RegisterStaticConstants(STATIC_CONSTANTS);
+
+-- textures for quest item overlays
+TEXTURE_ITEM_QUEST_BANG = "Interface\\ContainerFrame\\UI-Icon-QuestBang";
+TEXTURE_ITEM_QUEST_BORDER = "Interface\\ContainerFrame\\UI-Icon-QuestBorder";
+
+-- Friends
+SHOW_SEARCH_BAR_NUM_FRIENDS = 12;
+
+-- faction
+PLAYER_FACTION_GROUP = { [0] = "Horde", [1] = "Alliance" };
\ No newline at end of file
diff --git a/reference/FrameXML/ContainerFrame.lua b/reference/FrameXML/ContainerFrame.lua
new file mode 100644
index 0000000..3734cd7
--- /dev/null
+++ b/reference/FrameXML/ContainerFrame.lua
@@ -0,0 +1,914 @@
+NUM_CONTAINER_FRAMES = 13;
+NUM_BAG_FRAMES = 4;
+MAX_CONTAINER_ITEMS = 36;
+NUM_CONTAINER_COLUMNS = 4;
+ROWS_IN_BG_TEXTURE = 6;
+MAX_BG_TEXTURES = 2;
+BG_TEXTURE_HEIGHT = 512;
+CONTAINER_WIDTH = 192;
+CONTAINER_SPACING = 0;
+VISIBLE_CONTAINER_SPACING = 3;
+CONTAINER_OFFSET_Y = 70;
+CONTAINER_OFFSET_X = 0;
+CONTAINER_SCALE = 0.75;
+BACKPACK_HEIGHT = 240;
+
+function ContainerFrame_OnLoad(self)
+ self:RegisterEvent("BAG_OPEN");
+ self:RegisterEvent("BAG_CLOSED");
+ self:RegisterEvent("QUEST_ACCEPTED");
+ self:RegisterEvent("UNIT_QUEST_LOG_CHANGED");
+ ContainerFrame1.bagsShown = 0;
+ ContainerFrame1.bags = {};
+end
+
+function ContainerFrame_OnEvent(self, event, ...)
+ local arg1, arg2 = ...;
+ if ( event == "BAG_OPEN" ) then
+ if ( self:GetID() == arg1 ) then
+ self:Show();
+ end
+ elseif ( event == "BAG_CLOSED" ) then
+ if ( self:GetID() == arg1 ) then
+ self:Hide();
+ end
+ elseif ( event == "BAG_UPDATE" ) then
+ if ( self:GetID() == arg1 ) then
+ ContainerFrame_Update(self);
+ end
+ elseif ( event == "ITEM_LOCK_CHANGED" ) then
+ local bag, slot = arg1, arg2;
+ if ( bag and slot and (bag == self:GetID()) ) then
+ ContainerFrame_UpdateLockedItem(self, slot);
+ end
+ elseif ( event == "BAG_UPDATE_COOLDOWN" ) then
+ ContainerFrame_UpdateCooldowns(self);
+ elseif ( event == "QUEST_ACCEPTED" or (event == "UNIT_QUEST_LOG_CHANGED" and arg1 == "player") ) then
+ for i = 1, ContainerFrame1.bagsShown do
+ local bag = _G[ContainerFrame1.bags[i]];
+ ContainerFrame_Update(bag);
+ end
+ elseif ( event == "DISPLAY_SIZE_CHANGED" ) then
+ updateContainerFrameAnchors();
+ end
+end
+
+function ToggleBag(id)
+ if ( IsOptionFrameOpen() ) then
+ return;
+ end
+
+ local size = GetContainerNumSlots(id);
+ if ( size > 0 or id == KEYRING_CONTAINER ) then
+ local containerShowing;
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local frame = _G["ContainerFrame"..i];
+ if ( frame:IsShown() and frame:GetID() == id ) then
+ containerShowing = i;
+ frame:Hide();
+ end
+ end
+ if ( not containerShowing ) then
+ ContainerFrame_GenerateFrame(ContainerFrame_GetOpenFrame(), size, id);
+ end
+ end
+end
+
+function ToggleBackpack()
+ if ( IsOptionFrameOpen() ) then
+ return;
+ end
+
+ if ( IsBagOpen(0) ) then
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local frame = _G["ContainerFrame"..i];
+ if ( frame:IsShown() ) then
+ frame:Hide();
+ end
+ -- Hide the token bar if closing the backpack
+ if ( BackpackTokenFrame ) then
+ BackpackTokenFrame:Hide();
+ end
+ end
+ else
+ ToggleBag(0);
+ -- If there are tokens watched then show the bar
+ if ( ManageBackpackTokenFrame ) then
+ BackpackTokenFrame_Update();
+ ManageBackpackTokenFrame();
+ end
+ end
+end
+
+function ContainerFrame_OnHide(self)
+ self:UnregisterEvent("BAG_UPDATE");
+ self:UnregisterEvent("ITEM_LOCK_CHANGED");
+ self:UnregisterEvent("BAG_UPDATE_COOLDOWN");
+ self:UnregisterEvent("DISPLAY_SIZE_CHANGED");
+
+ if ( self:GetID() == 0 ) then
+ MainMenuBarBackpackButton:SetChecked(0);
+ else
+ local bagButton = _G["CharacterBag"..(self:GetID() - 1).."Slot"];
+ if ( bagButton ) then
+ bagButton:SetChecked(0);
+ else
+ -- If its a bank bag then update its highlight
+
+ UpdateBagButtonHighlight(self:GetID());
+ end
+ end
+ ContainerFrame1.bagsShown = ContainerFrame1.bagsShown - 1;
+ -- Remove the closed bag from the list and collapse the rest of the entries
+ local index = 1;
+ while ContainerFrame1.bags[index] do
+ if ( ContainerFrame1.bags[index] == self:GetName() ) then
+ local tempIndex = index;
+ while ContainerFrame1.bags[tempIndex] do
+ if ( ContainerFrame1.bags[tempIndex + 1] ) then
+ ContainerFrame1.bags[tempIndex] = ContainerFrame1.bags[tempIndex + 1];
+ else
+ ContainerFrame1.bags[tempIndex] = nil;
+ end
+ tempIndex = tempIndex + 1;
+ end
+ end
+ index = index + 1;
+ end
+ updateContainerFrameAnchors();
+
+ if ( self:GetID() == KEYRING_CONTAINER ) then
+ UpdateMicroButtons();
+ PlaySound("KeyRingClose");
+ else
+ PlaySound("igBackPackClose");
+ end
+end
+
+function ContainerFrame_OnShow(self)
+ self:RegisterEvent("BAG_UPDATE");
+ self:RegisterEvent("ITEM_LOCK_CHANGED");
+ self:RegisterEvent("BAG_UPDATE_COOLDOWN");
+ self:RegisterEvent("DISPLAY_SIZE_CHANGED");
+
+ if ( self:GetID() == 0 ) then
+ MainMenuBarBackpackButton:SetChecked(1);
+ elseif ( self:GetID() <= NUM_BAG_SLOTS ) then
+ local button = _G["CharacterBag"..(self:GetID() - 1).."Slot"];
+ if ( button ) then
+ button:SetChecked(1);
+ end
+ else
+ UpdateBagButtonHighlight(self:GetID());
+ end
+ ContainerFrame1.bagsShown = ContainerFrame1.bagsShown + 1;
+ if ( self:GetID() == KEYRING_CONTAINER ) then
+ UpdateMicroButtons();
+ PlaySound("KeyRingOpen");
+ else
+ PlaySound("igBackPackOpen");
+ end
+ ContainerFrame_Update(self);
+
+ -- If there are tokens watched then decide if we should show the bar
+ if ( ManageBackpackTokenFrame ) then
+ ManageBackpackTokenFrame();
+ end
+end
+
+function OpenBag(id)
+ if ( not CanOpenPanels() ) then
+ if ( UnitIsDead("player") ) then
+ NotWhileDeadError();
+ end
+ return;
+ end
+
+ local size = GetContainerNumSlots(id);
+ if ( size > 0 ) then
+ local containerShowing;
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local frame = _G["ContainerFrame"..i];
+ if ( frame:IsShown() and frame:GetID() == id ) then
+ containerShowing = i;
+ end
+ end
+ if ( not containerShowing ) then
+ ContainerFrame_GenerateFrame(ContainerFrame_GetOpenFrame(), size, id);
+ end
+ end
+end
+
+function CloseBag(id)
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local containerFrame = _G["ContainerFrame"..i];
+ if ( containerFrame:IsShown() and (containerFrame:GetID() == id) ) then
+ containerFrame:Hide();
+ return;
+ end
+ end
+end
+
+function IsBagOpen(id)
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local containerFrame = _G["ContainerFrame"..i];
+ if ( containerFrame:IsShown() and (containerFrame:GetID() == id) ) then
+ return i;
+ end
+ end
+ return nil;
+end
+
+function OpenBackpack()
+ if ( not CanOpenPanels() ) then
+ if ( UnitIsDead("player") ) then
+ NotWhileDeadError();
+ end
+ return;
+ end
+
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local containerFrame = _G["ContainerFrame"..i];
+ if ( containerFrame:IsShown() and (containerFrame:GetID() == 0) ) then
+ ContainerFrame1.backpackWasOpen = 1;
+ return;
+ else
+ ContainerFrame1.backpackWasOpen = nil;
+ end
+ end
+
+ if ( not ContainerFrame1.backpackWasOpen ) then
+ ToggleBackpack();
+ end
+
+ return ContainerFrame1.backpackWasOpen;
+end
+
+function CloseBackpack()
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local containerFrame = _G["ContainerFrame"..i];
+ if ( containerFrame:IsShown() and (containerFrame:GetID() == 0) and (ContainerFrame1.backpackWasOpen == nil) ) then
+ containerFrame:Hide();
+ return;
+ end
+ end
+end
+
+function ContainerFrame_GetOpenFrame()
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local frame = _G["ContainerFrame"..i];
+ if ( not frame:IsShown() ) then
+ return frame;
+ end
+ -- If all frames open return the last frame
+ if ( i == NUM_CONTAINER_FRAMES ) then
+ frame:Hide();
+ return frame;
+ end
+ end
+end
+
+function ContainerFrame_Update(frame)
+ local id = frame:GetID();
+ local name = frame:GetName();
+ local itemButton;
+ local texture, itemCount, locked, quality, readable;
+ local isQuestItem, questId, isActive, questTexture;
+ local tooltipOwner = GameTooltip:GetOwner();
+ for i=1, frame.size, 1 do
+ itemButton = _G[name.."Item"..i];
+
+ texture, itemCount, locked, quality, readable = GetContainerItemInfo(id, itemButton:GetID());
+ isQuestItem, questId, isActive = GetContainerItemQuestInfo(id, itemButton:GetID());
+
+ SetItemButtonTexture(itemButton, texture);
+ SetItemButtonCount(itemButton, itemCount);
+ SetItemButtonDesaturated(itemButton, locked, 0.5, 0.5, 0.5);
+
+ questTexture = _G[name.."Item"..i.."IconQuestTexture"];
+ if ( questId and not isActive ) then
+ questTexture:SetTexture(TEXTURE_ITEM_QUEST_BANG);
+ questTexture:Show();
+ elseif ( questId or isQuestItem ) then
+ questTexture:SetTexture(TEXTURE_ITEM_QUEST_BORDER);
+ questTexture:Show();
+ else
+ questTexture:Hide();
+ end
+
+ if ( texture ) then
+ ContainerFrame_UpdateCooldown(id, itemButton);
+ itemButton.hasItem = 1;
+ else
+ _G[name.."Item"..i.."Cooldown"]:Hide();
+ itemButton.hasItem = nil;
+ end
+ itemButton.readable = readable;
+
+ if ( itemButton == tooltipOwner ) then
+ itemButton.UpdateTooltip(itemButton);
+ end
+ end
+end
+
+function ContainerFrame_UpdateLocked(frame)
+ local id = frame:GetID();
+ local name = frame:GetName();
+ local itemButton;
+ local texture, itemCount, locked, quality, readable;
+ for i=1, frame.size, 1 do
+ itemButton = _G[name.."Item"..i];
+
+ texture, itemCount, locked, quality, readable = GetContainerItemInfo(id, itemButton:GetID());
+
+ SetItemButtonDesaturated(itemButton, locked, 0.5, 0.5, 0.5);
+ end
+end
+
+function ContainerFrame_UpdateLockedItem(frame, slot)
+ local index = frame.size + 1 - slot;
+ local itemButton = _G[frame:GetName().."Item"..index];
+ local texture, itemCount, locked, quality, readable = GetContainerItemInfo(frame:GetID(), itemButton:GetID());
+
+ SetItemButtonDesaturated(itemButton, locked, 0.5, 0.5, 0.5);
+end
+
+function ContainerFrame_UpdateCooldowns(frame)
+ local id = frame:GetID();
+ local name = frame:GetName();
+ for i=1, frame.size, 1 do
+ local itemButton = _G[name.."Item"..i];
+ if ( GetContainerItemInfo(id, itemButton:GetID()) ) then
+ ContainerFrame_UpdateCooldown(id, itemButton);
+ else
+ _G[name.."Item"..i.."Cooldown"]:Hide();
+ end
+ end
+end
+
+function ContainerFrame_UpdateCooldown(container, button)
+ local cooldown = _G[button:GetName().."Cooldown"];
+ local start, duration, enable = GetContainerItemCooldown(container, button:GetID());
+ CooldownFrame_SetTimer(cooldown, start, duration, enable);
+ if ( duration > 0 and enable == 0 ) then
+ SetItemButtonTextureVertexColor(button, 0.4, 0.4, 0.4);
+ else
+ SetItemButtonTextureVertexColor(button, 1, 1, 1);
+ end
+end
+
+function ContainerFrame_GenerateFrame(frame, size, id)
+ frame.size = size;
+ local name = frame:GetName();
+ local bgTextureTop = _G[name.."BackgroundTop"];
+ local bgTextureMiddle = _G[name.."BackgroundMiddle1"];
+ local bgTextureMiddle2 = _G[name.."BackgroundMiddle2"];
+ local bgTextureBottom = _G[name.."BackgroundBottom"];
+ local bgTexture1Slot = _G[name.."Background1Slot"];
+ local columns = NUM_CONTAINER_COLUMNS;
+ local rows = ceil(size / columns);
+ -- if id = 0 then its the backpack
+ if ( id == 0 ) then
+ bgTexture1Slot:Hide();
+ _G[name.."MoneyFrame"]:Show();
+ -- Set Backpack texture
+ bgTextureTop:SetTexture("Interface\\ContainerFrame\\UI-BackpackBackground");
+ bgTextureTop:SetHeight(256);
+ bgTextureTop:SetTexCoord(0, 1, 0, 1);
+ bgTextureTop:Show();
+
+ -- Hide unused textures
+ for i=1, MAX_BG_TEXTURES do
+ _G[name.."BackgroundMiddle"..i]:Hide();
+ end
+ bgTextureBottom:Hide();
+ frame:SetHeight(BACKPACK_HEIGHT);
+ else
+ if (size == 1) then
+ -- Halloween gag gift
+ bgTexture1Slot:Show();
+ bgTextureTop:Hide();
+ bgTextureMiddle:Hide();
+ bgTextureMiddle2:Hide();
+ bgTextureBottom:Hide();
+ _G[name.."MoneyFrame"]:Hide();
+ else
+ bgTexture1Slot:Hide();
+ bgTextureTop:Show();
+
+ -- Not the backpack
+ -- Set whether or not its a bank bag
+ local bagTextureSuffix = "";
+ if ( id > NUM_BAG_FRAMES ) then
+ bagTextureSuffix = "-Bank";
+ elseif ( id == KEYRING_CONTAINER ) then
+ bagTextureSuffix = "-Keyring";
+ end
+
+ -- Set textures
+ bgTextureTop:SetTexture("Interface\\ContainerFrame\\UI-Bag-Components"..bagTextureSuffix);
+ for i=1, MAX_BG_TEXTURES do
+ _G[name.."BackgroundMiddle"..i]:SetTexture("Interface\\ContainerFrame\\UI-Bag-Components"..bagTextureSuffix);
+ _G[name.."BackgroundMiddle"..i]:Hide();
+ end
+ bgTextureBottom:SetTexture("Interface\\ContainerFrame\\UI-Bag-Components"..bagTextureSuffix);
+ -- Hide the moneyframe since its not the backpack
+ _G[name.."MoneyFrame"]:Hide();
+
+ local bgTextureCount, height;
+ local rowHeight = 41;
+ -- Subtract one, since the top texture contains one row already
+ local remainingRows = rows-1;
+
+ -- See if the bag needs the texture with two slots at the top
+ local isPlusTwoBag;
+ if ( mod(size,columns) == 2 ) then
+ isPlusTwoBag = 1;
+ end
+
+ -- Bag background display stuff
+ if ( isPlusTwoBag ) then
+ bgTextureTop:SetTexCoord(0, 1, 0.189453125, 0.330078125);
+ bgTextureTop:SetHeight(72);
+ else
+ if ( rows == 1 ) then
+ -- If only one row chop off the bottom of the texture
+ bgTextureTop:SetTexCoord(0, 1, 0.00390625, 0.16796875);
+ bgTextureTop:SetHeight(86);
+ else
+ bgTextureTop:SetTexCoord(0, 1, 0.00390625, 0.18359375);
+ bgTextureTop:SetHeight(94);
+ end
+ end
+ -- Calculate the number of background textures we're going to need
+ bgTextureCount = ceil(remainingRows/ROWS_IN_BG_TEXTURE);
+
+ local middleBgHeight = 0;
+ -- If one row only special case
+ if ( rows == 1 ) then
+ bgTextureBottom:SetPoint("TOP", bgTextureMiddle:GetName(), "TOP", 0, 0);
+ bgTextureBottom:Show();
+ -- Hide middle bg textures
+ for i=1, MAX_BG_TEXTURES do
+ _G[name.."BackgroundMiddle"..i]:Hide();
+ end
+ else
+ -- Try to cycle all the middle bg textures
+ local firstRowPixelOffset = 9;
+ local firstRowTexCoordOffset = 0.353515625;
+ for i=1, bgTextureCount do
+ bgTextureMiddle = _G[name.."BackgroundMiddle"..i];
+ if ( remainingRows > ROWS_IN_BG_TEXTURE ) then
+ -- If more rows left to draw than can fit in a texture then draw the max possible
+ height = ( ROWS_IN_BG_TEXTURE*rowHeight ) + firstRowTexCoordOffset;
+ bgTextureMiddle:SetHeight(height);
+ bgTextureMiddle:SetTexCoord(0, 1, firstRowTexCoordOffset, ( height/BG_TEXTURE_HEIGHT + firstRowTexCoordOffset) );
+ bgTextureMiddle:Show();
+ remainingRows = remainingRows - ROWS_IN_BG_TEXTURE;
+ middleBgHeight = middleBgHeight + height;
+ else
+ -- If not its a huge bag
+ bgTextureMiddle:Show();
+ height = remainingRows*rowHeight-firstRowPixelOffset;
+ bgTextureMiddle:SetHeight(height);
+ bgTextureMiddle:SetTexCoord(0, 1, firstRowTexCoordOffset, ( height/BG_TEXTURE_HEIGHT + firstRowTexCoordOffset) );
+ middleBgHeight = middleBgHeight + height;
+ end
+ end
+ -- Position bottom texture
+ bgTextureBottom:SetPoint("TOP", bgTextureMiddle:GetName(), "BOTTOM", 0, 0);
+ bgTextureBottom:Show();
+ end
+
+ -- Set the frame height
+ frame:SetHeight(bgTextureTop:GetHeight()+bgTextureBottom:GetHeight()+middleBgHeight);
+ end
+ end
+
+ if (size == 1) then
+ -- Halloween gag gift
+ frame:SetHeight(70);
+ frame:SetWidth(99);
+ _G[frame:GetName().."Name"]:SetText("");
+ SetBagPortraitTexture(_G[frame:GetName().."Portrait"], id);
+ local itemButton = _G[name.."Item1"];
+ itemButton:SetID(1);
+ itemButton:SetPoint("BOTTOMRIGHT", name, "BOTTOMRIGHT", -10, 5);
+ itemButton:Show();
+ else
+ frame:SetWidth(CONTAINER_WIDTH);
+
+ --Special case code for keyrings
+ if ( id == KEYRING_CONTAINER ) then
+ _G[frame:GetName().."Name"]:SetText(KEYRING);
+ SetPortraitToTexture(frame:GetName().."Portrait", "Interface\\ContainerFrame\\KeyRing-Bag-Icon");
+ else
+ _G[frame:GetName().."Name"]:SetText(GetBagName(id));
+ SetBagPortraitTexture(_G[frame:GetName().."Portrait"], id);
+ end
+
+ local index, itemButton;
+ for i=1, size, 1 do
+ index = size - i + 1;
+ itemButton = _G[name.."Item"..i];
+ itemButton:SetID(index);
+ -- Set first button
+ if ( i == 1 ) then
+ -- Anchor the first item differently if its the backpack frame
+ if ( id == 0 ) then
+ itemButton:SetPoint("BOTTOMRIGHT", name, "TOPRIGHT", -12, -208);
+ else
+ itemButton:SetPoint("BOTTOMRIGHT", name, "BOTTOMRIGHT", -12, 9);
+ end
+
+ else
+ if ( mod((i-1), columns) == 0 ) then
+ itemButton:SetPoint("BOTTOMRIGHT", name.."Item"..(i - columns), "TOPRIGHT", 0, 4);
+ else
+ itemButton:SetPoint("BOTTOMRIGHT", name.."Item"..(i - 1), "BOTTOMLEFT", -5, 0);
+ end
+ end
+ itemButton:Show();
+ end
+ end
+ for i=size + 1, MAX_CONTAINER_ITEMS, 1 do
+ _G[name.."Item"..i]:Hide();
+ end
+
+ frame:SetID(id);
+ _G[frame:GetName().."PortraitButton"]:SetID(id);
+
+ -- Add the bag to the baglist
+ ContainerFrame1.bags[ContainerFrame1.bagsShown + 1] = frame:GetName();
+ updateContainerFrameAnchors();
+ frame:Show();
+end
+
+function updateContainerFrameAnchors()
+ local frame, xOffset, yOffset, screenHeight, freeScreenHeight, leftMostPoint, column;
+ local screenWidth = GetScreenWidth();
+ local containerScale = 1;
+ local leftLimit = 0;
+ if ( BankFrame:IsShown() ) then
+ leftLimit = BankFrame:GetRight() - 25;
+ end
+
+ while ( containerScale > CONTAINER_SCALE ) do
+ screenHeight = GetScreenHeight() / containerScale;
+ -- Adjust the start anchor for bags depending on the multibars
+ xOffset = CONTAINER_OFFSET_X / containerScale;
+ yOffset = CONTAINER_OFFSET_Y / containerScale;
+ -- freeScreenHeight determines when to start a new column of bags
+ freeScreenHeight = screenHeight - yOffset;
+ leftMostPoint = screenWidth - xOffset;
+ column = 1;
+ local frameHeight;
+ for index, frameName in ipairs(ContainerFrame1.bags) do
+ frameHeight = _G[frameName]:GetHeight();
+ if ( freeScreenHeight < frameHeight ) then
+ -- Start a new column
+ column = column + 1;
+ leftMostPoint = screenWidth - ( column * CONTAINER_WIDTH * containerScale ) - xOffset;
+ freeScreenHeight = screenHeight - yOffset;
+ end
+ freeScreenHeight = freeScreenHeight - frameHeight - VISIBLE_CONTAINER_SPACING;
+ end
+ if ( leftMostPoint < leftLimit ) then
+ containerScale = containerScale - 0.01;
+ else
+ break;
+ end
+ end
+
+ if ( containerScale < CONTAINER_SCALE ) then
+ containerScale = CONTAINER_SCALE;
+ end
+
+ screenHeight = GetScreenHeight() / containerScale;
+ -- Adjust the start anchor for bags depending on the multibars
+ xOffset = CONTAINER_OFFSET_X / containerScale;
+ yOffset = CONTAINER_OFFSET_Y / containerScale;
+ -- freeScreenHeight determines when to start a new column of bags
+ freeScreenHeight = screenHeight - yOffset;
+ column = 0;
+ for index, frameName in ipairs(ContainerFrame1.bags) do
+ frame = _G[frameName];
+ frame:SetScale(containerScale);
+ if ( index == 1 ) then
+ -- First bag
+ frame:SetPoint("BOTTOMRIGHT", frame:GetParent(), "BOTTOMRIGHT", -xOffset, yOffset );
+ elseif ( freeScreenHeight < frame:GetHeight() ) then
+ -- Start a new column
+ column = column + 1;
+ freeScreenHeight = screenHeight - yOffset;
+ frame:SetPoint("BOTTOMRIGHT", frame:GetParent(), "BOTTOMRIGHT", -(column * CONTAINER_WIDTH) - xOffset, yOffset );
+ else
+ -- Anchor to the previous bag
+ frame:SetPoint("BOTTOMRIGHT", ContainerFrame1.bags[index - 1], "TOPRIGHT", 0, CONTAINER_SPACING);
+ end
+ freeScreenHeight = freeScreenHeight - frame:GetHeight() - VISIBLE_CONTAINER_SPACING;
+ end
+end
+
+function ContainerFrameItemButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:RegisterForDrag("LeftButton");
+
+ self.SplitStack = function(button, split)
+ SplitContainerItem(button:GetParent():GetID(), button:GetID(), split);
+ end
+ self.UpdateTooltip = ContainerFrameItemButton_OnEnter;
+end
+
+function ContainerFrameItemButton_OnDrag (self)
+ ContainerFrameItemButton_OnClick(self, "LeftButton");
+end
+
+function ContainerFrame_GetExtendedPriceString(itemButton, isEquipped, quantity)
+ quantity = (quantity or 1);
+ local slot = itemButton:GetID();
+ local bag = itemButton:GetParent():GetID();
+
+ local money, honorPoints, arenaPoints, itemCount, refundSec = GetContainerItemPurchaseInfo(bag, slot, isEquipped);
+ if ( not refundSec or ((honorPoints == 0) and (arenaPoints == 0) and (itemCount == 0) and (money == 0)) ) then
+ return false;
+ end
+
+ local count = itemButton.count or 1;
+ honorPoints, arenaPoints, itemCount = (honorPoints or 0) * quantity, (arenaPoints or 0) * quantity, (itemCount or 0) * quantity;
+ local itemsString;
+
+ if ( honorPoints and honorPoints ~= 0 ) then
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ local pointsTexture = "Interface\\PVPFrame\\PVP-Currency-"..factionGroup;
+ itemsString = " |T" .. pointsTexture .. ":0:0:0:-1|t" .. honorPoints .. " " .. HONOR_POINTS;
+ end
+ end
+ if ( arenaPoints and arenaPoints ~= 0 ) then
+ if ( itemsString ) then
+ -- adding an extra space here because it looks nicer
+ itemsString = itemsString .. " |TInterface\\PVPFrame\\PVP-ArenaPoints-Icon:0:0:0:-1|t" .. arenaPoints .. " " .. ARENA_POINTS;
+ else
+ itemsString = " |TInterface\\PVPFrame\\PVP-ArenaPoints-Icon:0:0:0:-1|t" .. arenaPoints .. " " .. ARENA_POINTS;
+ end
+ end
+
+ local maxQuality = 0;
+ for i=1, itemCount, 1 do
+ local itemTexture, itemQuantity, itemLink = GetContainerItemPurchaseItem(bag, slot, i, isEquipped);
+ if ( itemLink ) then
+ local _, _, itemQuality = GetItemInfo(itemLink);
+ maxQuality = math.max(itemQuality, maxQuality);
+ if ( itemsString ) then
+ itemsString = itemsString .. ", " .. format(ITEM_QUANTITY_TEMPLATE, (itemQuantity or 0) * quantity, itemLink);
+ else
+ itemsString = format(ITEM_QUANTITY_TEMPLATE, (itemQuantity or 0) * quantity, itemLink);
+ end
+ end
+ end
+ if(itemsString == nil) then
+ itemsString = "";
+ end
+ MerchantFrame.price = money;
+ MerchantFrame.refundBag = bag;
+ MerchantFrame.refundSlot = slot;
+ MerchantFrame.honorPoints = honorPoints;
+ MerchantFrame.arenaPoints = arenaPoints;
+
+ local refundItemTexture, refundItemLink;
+ if ( isEquipped ) then
+ refundItemTexture = GetInventoryItemTexture("player", slot);
+ refundItemLink = GetInventoryItemLink("player", slot);
+ else
+ refundItemTexture, _, _, _, _, _, refundItemLink = GetContainerItemInfo(bag, slot);
+ end
+ local itemName, _, itemQuality = GetItemInfo(refundItemLink);
+ local r, g, b = GetItemQualityColor(itemQuality);
+ StaticPopupDialogs["CONFIRM_REFUND_TOKEN_ITEM"].hasMoneyFrame = (money ~= 0) and 1 or nil;
+ StaticPopup_Show("CONFIRM_REFUND_TOKEN_ITEM", itemsString, "", {["texture"] = refundItemTexture, ["name"] = itemName, ["color"] = {r, g, b, 1}, ["link"] = refundItemLink, ["index"] = index, ["count"] = count * quantity});
+ return true;
+end
+
+function ContainerFrameItemButton_OnClick(self, button)
+ MerchantFrame_ResetRefundItem();
+
+ if ( button == "LeftButton" ) then
+ local type, money = GetCursorInfo();
+ if ( SpellCanTargetItem() ) then
+ -- Target the spell with the selected item
+ UseContainerItem(self:GetParent():GetID(), self:GetID());
+ elseif ( type == "guildbankmoney" ) then
+ WithdrawGuildBankMoney(money);
+ ClearCursor();
+ elseif ( type == "money" ) then
+ DropCursorMoney();
+ ClearCursor();
+ elseif ( type == "merchant" ) then
+ if ( MerchantFrame.extendedCost ) then
+ MerchantFrame_ConfirmExtendedItemCost(MerchantFrame.extendedCost);
+ elseif ( MerchantFrame.price and MerchantFrame.price >= MERCHANT_HIGH_PRICE_COST ) then
+ MerchantFrame_ConfirmHighCostItem(self);
+ else
+ PickupContainerItem(self:GetParent():GetID(), self:GetID());
+ end
+ else
+ PickupContainerItem(self:GetParent():GetID(), self:GetID());
+ if ( CursorHasItem() ) then
+ MerchantFrame_SetRefundItem(self);
+ end
+ end
+ StackSplitFrame:Hide();
+ else
+ if ( MerchantFrame:IsShown() ) then
+ if ( MerchantFrame.selectedTab == 2 ) then
+ -- Don't sell the item if the buyback tab is selected
+ return;
+ end
+ if ( ContainerFrame_GetExtendedPriceString(self)) then
+ -- a confirmation dialog has been shown
+ return;
+ end
+ end
+ UseContainerItem(self:GetParent():GetID(), self:GetID());
+ StackSplitFrame:Hide();
+ end
+end
+
+function ContainerFrameItemButton_OnModifiedClick(self, button)
+ if ( HandleModifiedItemClick(GetContainerItemLink(self:GetParent():GetID(), self:GetID())) ) then
+ return;
+ end
+ if ( IsModifiedClick("SOCKETITEM") ) then
+ SocketContainerItem(self:GetParent():GetID(), self:GetID());
+ end
+ if ( IsModifiedClick("SPLITSTACK") ) then
+ local texture, itemCount, locked = GetContainerItemInfo(self:GetParent():GetID(), self:GetID());
+ if ( not locked ) then
+ self.SplitStack = function(button, split)
+ SplitContainerItem(button:GetParent():GetID(), button:GetID(), split);
+ end
+ OpenStackSplitFrame(itemCount, self, "BOTTOMRIGHT", "TOPRIGHT");
+ end
+ return;
+ end
+end
+
+function ContainerFrameItemButton_OnEnter(self)
+ local x;
+ x = self:GetRight();
+ if ( x >= ( GetScreenWidth() / 2 ) ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+
+ -- Keyring specific code
+ if ( self:GetParent():GetID() == KEYRING_CONTAINER ) then
+ GameTooltip:SetInventoryItem("player", KeyRingButtonIDToInvSlotID(self:GetID()));
+ CursorUpdate(self);
+ return;
+ end
+
+ local showSell = nil;
+ local hasCooldown, repairCost = GameTooltip:SetBagItem(self:GetParent():GetID(), self:GetID());
+ if ( InRepairMode() and (repairCost and repairCost > 0) ) then
+ GameTooltip:AddLine(REPAIR_COST, "", 1, 1, 1);
+ SetTooltipMoney(GameTooltip, repairCost);
+ GameTooltip:Show();
+ elseif ( MerchantFrame:IsShown() and MerchantFrame.selectedTab == 1 ) then
+ showSell = 1;
+ end
+
+ if ( IsModifiedClick("DRESSUP") and self.hasItem ) then
+ ShowInspectCursor();
+ elseif ( showSell ) then
+ ShowContainerSellCursor(self:GetParent():GetID(),self:GetID());
+ elseif ( self.readable ) then
+ ShowInspectCursor();
+ else
+ ResetCursor();
+ end
+end
+
+function OpenAllBags(forceOpen)
+ if ( not UIParent:IsShown() ) then
+ return;
+ end
+
+ local bagsOpen = 0;
+ local totalBags = 1;
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local containerFrame = _G["ContainerFrame"..i];
+ local bagButton = _G["CharacterBag"..(i -1).."Slot"];
+ if ( (i <= NUM_BAG_FRAMES) and GetContainerNumSlots(bagButton:GetID() - CharacterBag0Slot:GetID() + 1) > 0) then
+ totalBags = totalBags + 1;
+ end
+ if ( containerFrame:IsShown() ) then
+ containerFrame:Hide();
+ if ( containerFrame:GetID() ~= KEYRING_CONTAINER ) then
+ bagsOpen = bagsOpen + 1;
+ end
+ end
+ end
+ if ( bagsOpen >= totalBags and not forceOpen ) then
+ return;
+ else
+ ToggleBackpack();
+ ToggleBag(1);
+ ToggleBag(2);
+ ToggleBag(3);
+ ToggleBag(4);
+ if ( BankFrame:IsShown() ) then
+ ToggleBag(5);
+ ToggleBag(6);
+ ToggleBag(7);
+ ToggleBag(8);
+ ToggleBag(9);
+ ToggleBag(10);
+ ToggleBag(11);
+ end
+ end
+
+end
+
+function CloseAllBags()
+ CloseBackpack();
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ CloseBag(i);
+ end
+end
+
+--KeyRing functions
+
+function PutKeyInKeyRing()
+ local texture;
+ local emptyKeyRingSlot;
+ for i=1, GetKeyRingSize() do
+ texture = GetContainerItemInfo(KEYRING_CONTAINER, i);
+ if ( not texture ) then
+ emptyKeyRingSlot = i;
+ break;
+ end
+ end
+ if ( emptyKeyRingSlot ) then
+ PickupContainerItem(KEYRING_CONTAINER, emptyKeyRingSlot);
+ else
+ UIErrorsFrame:AddMessage(NO_EMPTY_KEYRING_SLOTS, 1.0, 0.1, 0.1, 1.0);
+ end
+end
+
+function ToggleKeyRing()
+ if ( IsOptionFrameOpen() ) then
+ return;
+ end
+
+ local shownContainerID = IsBagOpen(KEYRING_CONTAINER);
+ if ( shownContainerID ) then
+ _G["ContainerFrame"..shownContainerID]:Hide();
+ else
+ ContainerFrame_GenerateFrame(ContainerFrame_GetOpenFrame(), GetKeyRingSize(), KEYRING_CONTAINER);
+
+ -- Stop keyring button pulse
+ SetButtonPulse(KeyRingButton, 0, 1);
+ end
+end
+
+function GetKeyRingSize()
+ local numKeyringSlots = GetContainerNumSlots(KEYRING_CONTAINER);
+ local maxSlotNumberFilled = 0;
+ local numItems = 0;
+ for i=1, numKeyringSlots do
+ local texture = GetContainerItemInfo(KEYRING_CONTAINER, i);
+ -- Update max slot
+ if ( texture and i > maxSlotNumberFilled) then
+ maxSlotNumberFilled = i;
+ end
+ -- Count how many items you have
+ if ( texture ) then
+ numItems = numItems + 1;
+ end
+ end
+
+ -- Round to the nearest 4 rows that will hold the keys
+ local modulo = maxSlotNumberFilled % 4;
+ local size;
+ if ( (modulo == 0) and (numItems < maxSlotNumberFilled) ) then
+ size = maxSlotNumberFilled;
+ else
+ -- Only expand if the number of keys in the keyring exceed or equal the max slot filled
+ size = maxSlotNumberFilled + (4 - modulo);
+ end
+ size = min(size, numKeyringSlots);
+
+ return size;
+end
+
+function GetBackpackFrame()
+ local index = IsBagOpen(0);
+ if ( index ) then
+ return _G["ContainerFrame"..index];
+ else
+ return nil;
+ end
+end
diff --git a/reference/FrameXML/ContainerFrame.xml b/reference/FrameXML/ContainerFrame.xml
new file mode 100644
index 0000000..1b33c6f
--- /dev/null
+++ b/reference/FrameXML/ContainerFrame.xml
@@ -0,0 +1,282 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local modifiedClick = IsModifiedClick();
+ -- If we can loot the item and autoloot toggle is active, then do a normal click
+ if ( button ~= "LeftButton" and modifiedClick and IsModifiedClick("AUTOLOOTTOGGLE") ) then
+ local _, _, _, _, _, lootable = GetContainerItemInfo(self:GetParent():GetID(), self:GetID());
+ if ( lootable ) then
+ modifiedClick = false;
+ end
+ end
+ if ( modifiedClick ) then
+ ContainerFrameItemButton_OnModifiedClick(self, button);
+ else
+ ContainerFrameItemButton_OnClick(self, button);
+ end
+
+
+ ContainerFrameItemButton_OnLoad(self);
+
+
+ ContainerFrameItemButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ if ( self.hasStackSplit and (self.hasStackSplit == 1) ) then
+ StackSplitFrame:Hide();
+ end
+
+
+ ContainerFrameItemButton_OnDrag(self, button);
+
+
+ ContainerFrameItemButton_OnDrag(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if ( self:GetID() == 0 ) then
+ GameTooltip:SetText(BACKPACK_TOOLTIP, 1.0, 1.0, 1.0);
+ if (GetBindingKey("TOGGLEBACKPACK")) then
+ GameTooltip:AppendText(" "..NORMAL_FONT_COLOR_CODE.."("..GetBindingKey("TOGGLEBACKPACK")..")"..FONT_COLOR_CODE_CLOSE)
+ end
+ elseif ( self:GetID() == KEYRING_CONTAINER ) then
+ GameTooltip:SetText(KEYRING, 1.0, 1.0, 1.0);
+ if (GetBindingKey("TOGGLEKEYRING")) then
+ GameTooltip:AppendText(" "..NORMAL_FONT_COLOR_CODE.."("..GetBindingKey("TOGGLEKEYRING")..")"..FONT_COLOR_CODE_CLOSE)
+ end
+ elseif ( GameTooltip:SetInventoryItem("player", ContainerIDToInventoryID(self:GetID())) ) then
+ local binding = GetBindingKey("TOGGLEBAG"..(4 - self:GetID() + 1));
+ if ( binding ) then
+ GameTooltip:AppendText(" "..NORMAL_FONT_COLOR_CODE.."("..binding..")"..FONT_COLOR_CODE_CLOSE);
+ end
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ToggleBag(self:GetParent():GetID());
+
+
+
+
+
+
+ ContainerFrame_OnEvent(self, event, ...);
+
+
+ ContainerFrame_OnLoad(self);
+
+
+ ContainerFrame_OnHide(self);
+
+
+ ContainerFrame_OnShow(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/Cooldown.lua b/reference/FrameXML/Cooldown.lua
new file mode 100644
index 0000000..72787f5
--- /dev/null
+++ b/reference/FrameXML/Cooldown.lua
@@ -0,0 +1,9 @@
+
+function CooldownFrame_SetTimer(self, start, duration, enable)
+ if ( start > 0 and duration > 0 and enable > 0) then
+ self:SetCooldown(start, duration);
+ self:Show();
+ else
+ self:Hide();
+ end
+end
diff --git a/reference/FrameXML/Cooldown.xml b/reference/FrameXML/Cooldown.xml
new file mode 100644
index 0000000..7eaf5f5
--- /dev/null
+++ b/reference/FrameXML/Cooldown.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/reference/FrameXML/DressUpFrame.lua b/reference/FrameXML/DressUpFrame.lua
new file mode 100644
index 0000000..1f5bdc8
--- /dev/null
+++ b/reference/FrameXML/DressUpFrame.lua
@@ -0,0 +1,35 @@
+
+function DressUpItemLink(link)
+ if ( not link or not IsDressableItem(link) ) then
+ return;
+ end
+ if ( not DressUpFrame:IsShown() ) then
+ ShowUIPanel(DressUpFrame);
+ DressUpModel:SetUnit("player");
+ end
+ DressUpModel:TryOn(link);
+end
+
+function DressUpTexturePath()
+ -- HACK
+ local race, fileName = UnitRace("player");
+ if ( strupper(fileName) == "GNOME" ) then
+ fileName = "Dwarf";
+ elseif ( strupper(fileName) == "TROLL" ) then
+ fileName = "Orc";
+ end
+ if ( not fileName ) then
+ fileName = "Orc";
+ end
+ -- END HACK
+
+ return "Interface\\DressUpFrame\\DressUpBackground-"..fileName;
+end
+
+function SetDressUpBackground()
+ local texture = DressUpTexturePath();
+ DressUpBackgroundTopLeft:SetTexture(texture..1);
+ DressUpBackgroundTopRight:SetTexture(texture..2);
+ DressUpBackgroundBotLeft:SetTexture(texture..3);
+ DressUpBackgroundBotRight:SetTexture(texture..4);
+end
diff --git a/reference/FrameXML/DressUpFrame.xml b/reference/FrameXML/DressUpFrame.xml
new file mode 100644
index 0000000..8ff3e75
--- /dev/null
+++ b/reference/FrameXML/DressUpFrame.xml
@@ -0,0 +1,257 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ DressUpModel:Dress();
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateLeft(self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateRight(self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+ SetPortraitTexture(DressUpFramePortrait, "player");
+ PlaySound("igCharacterInfoOpen");
+
+
+ PlaySound("igCharacterInfoClose");
+
+
+
+
diff --git a/reference/FrameXML/DurabilityFrame.lua b/reference/FrameXML/DurabilityFrame.lua
new file mode 100644
index 0000000..09f710f
--- /dev/null
+++ b/reference/FrameXML/DurabilityFrame.lua
@@ -0,0 +1,64 @@
+INVENTORY_ALERT_STATUS_SLOTS = {};
+INVENTORY_ALERT_STATUS_SLOTS[1] = {slot = "Head"};
+INVENTORY_ALERT_STATUS_SLOTS[2] = {slot ="Shoulders"};
+INVENTORY_ALERT_STATUS_SLOTS[3] = {slot ="Chest"};
+INVENTORY_ALERT_STATUS_SLOTS[4] = {slot ="Waist"};
+INVENTORY_ALERT_STATUS_SLOTS[5] = {slot ="Legs"};
+INVENTORY_ALERT_STATUS_SLOTS[6] = {slot ="Feet"};
+INVENTORY_ALERT_STATUS_SLOTS[7] = {slot ="Wrists"};
+INVENTORY_ALERT_STATUS_SLOTS[8] = {slot ="Hands"};
+INVENTORY_ALERT_STATUS_SLOTS[9] = {slot ="Weapon", showSeparate = 1};
+INVENTORY_ALERT_STATUS_SLOTS[10] = {slot ="Shield", showSeparate = 1};
+INVENTORY_ALERT_STATUS_SLOTS[11] = {slot ="Ranged", showSeparate = 1};
+
+INVENTORY_ALERT_COLORS = {};
+INVENTORY_ALERT_COLORS[1] = {r = 1, g = 0.82, b = 0.18};
+INVENTORY_ALERT_COLORS[2] = {r = 0.93, g = 0.07, b = 0.07};
+
+function DurabilityFrame_SetAlerts()
+ local numAlerts = 0;
+ local texture, color, showDurability;
+ for index, value in pairs(INVENTORY_ALERT_STATUS_SLOTS) do
+ texture = _G["Durability"..value.slot];
+ if ( value.slot == "Shield" ) then
+ if ( OffhandHasWeapon() ) then
+ DurabilityShield:Hide();
+ texture = DurabilityOffWeapon;
+ else
+ DurabilityOffWeapon:Hide();
+ texture = DurabilityShield;
+ end
+ end
+
+ color = INVENTORY_ALERT_COLORS[GetInventoryAlertStatus(index)];
+ if ( color ) then
+ texture:SetVertexColor(color.r, color.g, color.b, 1.0);
+ if ( value.showSeparate ) then
+ texture:Show();
+ else
+ showDurability = 1;
+ end
+ numAlerts = numAlerts + 1;
+ else
+ texture:SetVertexColor(1.0, 1.0, 1.0, 0.5);
+ if ( value.showSeparate ) then
+ texture:Hide();
+ end
+ end
+ end
+ for index, value in pairs(INVENTORY_ALERT_STATUS_SLOTS) do
+ if ( not value.showSeparate ) then
+ if ( showDurability ) then
+ _G["Durability"..value.slot]:Show();
+ else
+ _G["Durability"..value.slot]:Hide();
+ end
+ end
+ end
+
+ if ( numAlerts > 0 and (not VehicleSeatIndicator:IsShown()) and ((not ArenaEnemyFrames) or (not ArenaEnemyFrames:IsShown())) ) then
+ DurabilityFrame:Show();
+ else
+ DurabilityFrame:Hide();
+ end
+end
diff --git a/reference/FrameXML/DurabilityFrame.xml b/reference/FrameXML/DurabilityFrame.xml
new file mode 100644
index 0000000..2dab297
--- /dev/null
+++ b/reference/FrameXML/DurabilityFrame.xml
@@ -0,0 +1,185 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() - 1);
+ self:RegisterEvent("UPDATE_INVENTORY_ALERTS");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+
+ DurabilityFrame_SetAlerts();
+ UIParent_ManageFramePositions();
+
+
+
+
+
+
diff --git a/reference/FrameXML/EasyMenu.lua b/reference/FrameXML/EasyMenu.lua
new file mode 100644
index 0000000..0b78e92
--- /dev/null
+++ b/reference/FrameXML/EasyMenu.lua
@@ -0,0 +1,34 @@
+
+-- Simplified Menu Display System
+-- This is a basic system for displaying a menu from a structure table.
+--
+-- See UIDropDownMenu.lua for the menuList details.
+--
+-- Args:
+-- menuList - menu table
+-- menuFrame - the UI frame to populate
+-- anchor - where to anchor the frame (e.g. CURSOR)
+-- x - x offset
+-- y - y offset
+-- displayMode - border type
+-- autoHideDelay - how long until the menu disappears
+--
+--
+function EasyMenu(menuList, menuFrame, anchor, x, y, displayMode, autoHideDelay )
+ if ( displayMode == "MENU" ) then
+ menuFrame.displayMode = displayMode;
+ end
+ UIDropDownMenu_Initialize(menuFrame, EasyMenu_Initialize, displayMode, nil, menuList);
+ ToggleDropDownMenu(1, nil, menuFrame, anchor, x, y, menuList);
+end
+
+function EasyMenu_Initialize( frame, level, menuList )
+ for index = 1, #menuList do
+ local value = menuList[index]
+ if (value.text) then
+ value.index = index;
+ UIDropDownMenu_AddButton( value, level );
+ end
+ end
+end
+
diff --git a/reference/FrameXML/EquipmentManager.lua b/reference/FrameXML/EquipmentManager.lua
new file mode 100644
index 0000000..0cce0ba
--- /dev/null
+++ b/reference/FrameXML/EquipmentManager.lua
@@ -0,0 +1,333 @@
+EQUIPMENTMANAGER_INVENTORYSLOTS = {};
+EQUIPMENTMANAGER_BAGSLOTS = {};
+
+local _isAtBank = false;
+local SLOT_LOCKED = -1;
+local SLOT_EMPTY = -2;
+
+local EQUIP_ITEM = 1;
+local UNEQUIP_ITEM = 2;
+local SWAP_ITEM = 3;
+
+for i = KEYRING_CONTAINER, NUM_BAG_SLOTS do
+ EQUIPMENTMANAGER_BAGSLOTS[i] = {};
+end
+
+EquipmentManager = CreateFrame("FRAME");
+
+local workTable = {};
+function EquipmentManager_UpdateFreeBagSpace ()
+ local bagSlots = EQUIPMENTMANAGER_BAGSLOTS;
+
+ for i = BANK_CONTAINER, NUM_BAG_SLOTS + GetNumBankSlots() do
+ wipe(workTable);
+ local _, bagType = GetContainerNumFreeSlots(i);
+ if ( GetContainerFreeSlots(i, workTable) ) then
+ for index, slot in next, workTable do
+ if ( bagSlots[i] and not bagSlots[i][slot] and bagType == 0 ) then -- Don't overwrite locked slots, don't reset empty slots to empty, only use normal bags
+ bagSlots[i][slot] = SLOT_EMPTY;
+ end
+ end
+ end
+ end
+end
+
+local function _EquipmentManager_BagsFullError()
+ UIErrorsFrame:AddMessage(EQUIPMENT_MANAGER_BAGS_FULL, 1.0, 0.1, 0.1, 1.0);
+end
+
+function EquipmentManager_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" or event == "PLAYERBANKBAGSLOTS_CHANGED" ) then
+ for i = #EQUIPMENTMANAGER_BAGSLOTS + 1, NUM_BAG_SLOTS + GetNumBankSlots() do
+ EQUIPMENTMANAGER_BAGSLOTS[i] = {};
+ end
+ elseif ( event == "WEAR_EQUIPMENT_SET" ) then
+ local setName = ...;
+ EquipmentManager_EquipSet(setName);
+ elseif ( event == "ITEM_UNLOCKED" ) then
+ local arg1, arg2 = ...; -- inventory slot or bag and slot
+
+ if ( not arg2 ) then
+ EQUIPMENTMANAGER_INVENTORYSLOTS[arg1] = nil;
+ else
+ EQUIPMENTMANAGER_BAGSLOTS[arg1][arg2] = nil;
+ end
+
+ elseif ( event == "BANKFRAME_OPENED" ) then
+ _isAtBank = true;
+ elseif ( event == "BANKFRAME_CLOSED" ) then
+ _isAtBank = false;
+ end
+end
+
+EquipmentManager:SetScript("OnEvent", EquipmentManager_OnEvent);
+EquipmentManager:RegisterEvent("PLAYER_ENTERING_WORLD");
+EquipmentManager:RegisterEvent("PLAYERBANKBAGSLOTS_CHANGED");
+EquipmentManager:RegisterEvent("WEAR_EQUIPMENT_SET");
+EquipmentManager:RegisterEvent("ITEM_UNLOCKED");
+EquipmentManager:RegisterEvent("BANKFRAME_OPENED");
+EquipmentManager:RegisterEvent("BANKFRAME_CLOSED");
+
+function EquipmentManager_EquipItemByLocation (location, invSlot)
+ local player, bank, bags, slot, bag = EquipmentManager_UnpackLocation(location);
+
+ ClearCursor();
+
+ if ( not bags and slot == invSlot ) then --We're trying to reequip an equipped item in the same spot, ignore it.
+ return nil;
+ end
+
+ local currentItemID = GetInventoryItemID("player", invSlot);
+
+ local action = {};
+ action.type = (currentItemID and SWAP_ITEM) or EQUIP_ITEM;
+ action.invSlot = invSlot;
+ action.player = player;
+ action.bank = bank;
+ action.bags = bags;
+ action.slot = slot;
+ action.bag = bag;
+
+ return action;
+end
+
+function EquipmentManager_EquipContainerItem (action)
+ ClearCursor();
+
+ PickupContainerItem(action.bag, action.slot);
+
+ if ( not CursorHasItem() ) then
+ return false;
+ end
+
+ if ( not CursorCanGoInSlot(action.invSlot) ) then
+ return false;
+ elseif ( IsInventoryItemLocked(action.invSlot) ) then
+ return false;
+ end
+
+ PickupInventoryItem(action.invSlot);
+
+ EQUIPMENTMANAGER_BAGSLOTS[action.bag][action.slot] = action.invSlot;
+ EQUIPMENTMANAGER_INVENTORYSLOTS[action.invSlot] = SLOT_LOCKED;
+
+ return true;
+end
+
+function EquipmentManager_EquipInventoryItem (action)
+ ClearCursor();
+ PickupInventoryItem(action.slot);
+ if ( not CursorCanGoInSlot(action.invSlot) ) then
+ return false;
+ elseif ( IsInventoryItemLocked(action.invSlot) ) then
+ return false;
+ end
+ PickupInventoryItem(action.invSlot);
+ EQUIPMENTMANAGER_INVENTORYSLOTS[action.slot] = SLOT_LOCKED;
+ EQUIPMENTMANAGER_INVENTORYSLOTS[action.invSlot] = SLOT_LOCKED;
+
+ return true;
+end
+
+function EquipmentManager_UnpackLocation (location) -- Use me, I'm here to be used.
+ if ( location < 0 ) then -- Thanks Seerah!
+ return false, false, false, 0;
+ end
+
+ local player = (bit.band(location, ITEM_INVENTORY_LOCATION_PLAYER) ~= 0);
+ local bank = (bit.band(location, ITEM_INVENTORY_LOCATION_BANK) ~= 0);
+ local bags = (bit.band(location, ITEM_INVENTORY_LOCATION_BAGS) ~= 0);
+
+ if ( player ) then
+ location = location - ITEM_INVENTORY_LOCATION_PLAYER;
+ elseif ( bank ) then
+ location = location - ITEM_INVENTORY_LOCATION_BANK;
+ end
+
+ if ( bags ) then
+ location = location - ITEM_INVENTORY_LOCATION_BAGS;
+ local bag = bit.rshift(location, ITEM_INVENTORY_BAG_BIT_OFFSET);
+ local slot = location - bit.lshift(bag, ITEM_INVENTORY_BAG_BIT_OFFSET);
+
+ if ( bank ) then
+ bag = bag + ITEM_INVENTORY_BANK_BAG_OFFSET;
+ end
+ return player, bank, bags, slot, bag
+ else
+ return player, bank, bags, location
+ end
+end
+
+function EquipmentManager_UnequipItemInSlot (invSlot)
+ local itemID = GetInventoryItemID("player", invSlot);
+ if ( not itemID ) then
+ return nil; -- Slot was empty already;
+ end
+
+ local action = {};
+ action.type = UNEQUIP_ITEM;
+ action.invSlot = invSlot;
+
+ return action;
+end
+
+function EquipmentManager_PutItemInInventory (action)
+ if ( not CursorHasItem() ) then
+ return;
+ end
+
+ EquipmentManager_UpdateFreeBagSpace();
+
+ local bagSlots = EQUIPMENTMANAGER_BAGSLOTS;
+
+ local firstSlot;
+ for slot, flag in next, bagSlots[0] do
+ if ( flag == SLOT_EMPTY ) then
+ firstSlot = min(firstSlot or slot, slot);
+ end
+ end
+
+ if ( firstSlot ) then
+ if ( action ) then
+ action.bag = 0;
+ action.slot = firstSlot;
+ end
+
+ bagSlots[0][firstSlot] = SLOT_LOCKED;
+ PutItemInBackpack();
+ return true;
+ end
+
+ for bag = 1, NUM_BAG_SLOTS do
+ if ( bagSlots[bag] ) then
+ for slot, flag in next, bagSlots[bag] do
+ if ( flag == SLOT_EMPTY ) then
+ firstSlot = min(firstSlot or slot, slot);
+ end
+ end
+ if ( firstSlot ) then
+ bagSlots[bag][firstSlot] = SLOT_LOCKED;
+ PutItemInBag(bag + CONTAINER_BAG_OFFSET);
+
+ if ( action ) then
+ action.bag = bag;
+ action.slot = firstSlot;
+ end
+ return true;
+ end
+ end
+ end
+
+ if ( _isAtBank ) then
+ for slot, flag in next, bagSlots[BANK_CONTAINER] do
+ if ( flag == SLOT_EMPTY ) then
+ firstSlot = min(firstSlot or slot, slot);
+ end
+ end
+ if ( firstSlot ) then
+ bagSlots[BANK_CONTAINER][firstSlot] = SLOT_LOCKED;
+ PickupInventoryItem(firstSlot + BANK_CONTAINER_INVENTORY_OFFSET);
+
+ if ( action ) then
+ action.bag = BANK_CONTAINER;
+ action.slot = firstSlot;
+ end
+ return true;
+ else
+ for bag = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + GetNumBankSlots() do
+ if ( bagSlots[bag] ) then
+ for slot, flag in next, bagSlots[bag] do
+ if ( flag == SLOT_EMPTY ) then
+ firstSlot = min(firstSlot or slot, slot);
+ end
+ end
+ if ( firstSlot ) then
+ bagSlots[bag][firstSlot] = SLOT_LOCKED;
+ PickupContainerItem(bag, firstSlot);
+
+ if ( action ) then
+ action.bag = bag;
+ action.slot = firstSlot;
+ end
+ return true;
+ end
+ end
+ end
+ end
+ end
+
+ ClearCursor();
+ _EquipmentManager_BagsFullError();
+end
+
+function EquipmentManager_GetItemInfoByLocation (location)
+ local player, bank, bags, slot, bag = EquipmentManager_UnpackLocation(location);
+ if ( not player and not bank and not bags ) then -- Invalid location
+ return;
+ end
+
+ local id, name, textureName, count, durability, maxDurability, invType, locked, start, duration, enable, setTooltip, gem1, gem2, gem3, _;
+ if ( not bags ) then -- and (player or bank)
+ id = GetInventoryItemID("player", slot);
+ name, _, _, _, _, _, _, _, invType, textureName = GetItemInfo(id);
+ if ( textureName ) then
+ count = GetInventoryItemCount("player", slot);
+ durability, maxDurability = GetInventoryItemDurability(slot);
+ start, duration, enable = GetInventoryItemCooldown("player", slot);
+ end
+
+ setTooltip = function () GameTooltip:SetInventoryItem("player", slot) end;
+ gem1, gem2, gem3 = GetInventoryItemGems(slot);
+ else -- bags
+ id = GetContainerItemID(bag, slot);
+ name, _, _, _, _, _, _, _, invType = GetItemInfo(id);
+ textureName, count, locked = GetContainerItemInfo(bag, slot);
+ start, duration, enable = GetContainerItemCooldown(bag, slot);
+
+ durability, maxDurability = GetContainerItemDurability(bag, slot);
+
+ setTooltip = function () GameTooltip:SetBagItem(bag, slot); end;
+ gem1, gem2, gem3 = GetContainerItemGems(bag, slot);
+ end
+
+ return id, name, textureName, count, durability, maxDurability, invType, locked, start, duration, enable, setTooltip, gem1, gem2, gem3;
+end
+
+function EquipmentManager_EquipSet (name)
+ if ( EquipmentSetContainsLockedItems(name) or UnitCastingInfo("player") ) then
+ UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
+ return;
+ end
+
+ UseEquipmentSet(name);
+end
+
+function EquipmentManager_RunAction (action)
+ if ( UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[action.invSlot] ) then
+ return true;
+ end
+ action.run = true;
+ if ( action.type == EQUIP_ITEM or action.type == SWAP_ITEM ) then
+ if ( not action.bags ) then
+ return EquipmentManager_EquipInventoryItem(action);
+ else
+ local hasItem = action.invSlot and GetInventoryItemID("player", action.invSlot);
+ local pending = EquipmentManager_EquipContainerItem(action);
+
+ if ( pending and not hasItem ) then
+ EQUIPMENTMANAGER_BAGSLOTS[action.bag][action.slot] = SLOT_EMPTY;
+ end
+
+ return pending;
+ end
+ elseif ( action.type == UNEQUIP_ITEM ) then
+ ClearCursor();
+
+ if ( IsInventoryItemLocked(action.invSlot) ) then
+ return;
+ else
+ PickupInventoryItem(action.invSlot);
+ return EquipmentManager_PutItemInInventory(action);
+ end
+ end
+end
diff --git a/reference/FrameXML/FadingFrame.lua b/reference/FrameXML/FadingFrame.lua
new file mode 100644
index 0000000..bedff59
--- /dev/null
+++ b/reference/FrameXML/FadingFrame.lua
@@ -0,0 +1,44 @@
+
+function FadingFrame_SetFadeInTime(fadingFrame, time)
+ fadingFrame.fadeInTime = time;
+end
+function FadingFrame_SetHoldTime(fadingFrame, time)
+ fadingFrame.holdTime = time;
+end
+function FadingFrame_SetFadeOutTime(fadingFrame, time)
+ fadingFrame.fadeOutTime = time;
+end
+function FadingFrame_OnLoad(fadingFrame)
+ assert(fadingFrame);
+ fadingFrame.fadeInTime = 0;
+ fadingFrame.holdTime = 0;
+ fadingFrame.fadeOutTime = 0;
+ fadingFrame:Hide();
+end
+function FadingFrame_Show(fadingFrame)
+ assert(fadingFrame);
+ fadingFrame.startTime = GetTime();
+ fadingFrame:Show();
+end
+function FadingFrame_OnUpdate(fadingFrame)
+ assert(fadingFrame);
+ local elapsed = GetTime() - fadingFrame.startTime;
+ local fadeInTime = fadingFrame.fadeInTime;
+ if ( elapsed < fadeInTime ) then
+ local alpha = (elapsed / fadeInTime);
+ fadingFrame:SetAlpha(alpha);
+ return;
+ end
+ local holdTime = fadingFrame.holdTime;
+ if ( elapsed < (fadeInTime + holdTime) ) then
+ fadingFrame:SetAlpha(1.0);
+ return;
+ end
+ local fadeOutTime = fadingFrame.fadeOutTime;
+ if ( elapsed < (fadeInTime + holdTime + fadeOutTime) ) then
+ local alpha = 1.0 - ((elapsed - holdTime - fadeInTime) / fadeOutTime);
+ fadingFrame:SetAlpha(alpha);
+ return;
+ end
+ fadingFrame:Hide();
+end
diff --git a/reference/FrameXML/FadingFrame.xml b/reference/FrameXML/FadingFrame.xml
new file mode 100644
index 0000000..a909cfc
--- /dev/null
+++ b/reference/FrameXML/FadingFrame.xml
@@ -0,0 +1,5 @@
+
+
+
+
diff --git a/reference/FrameXML/FloatingChatFrame.lua b/reference/FrameXML/FloatingChatFrame.lua
new file mode 100644
index 0000000..f1d52bc
--- /dev/null
+++ b/reference/FrameXML/FloatingChatFrame.lua
@@ -0,0 +1,2518 @@
+-- CHAT PROTOTYPE STUFF
+SELECTED_DOCK_FRAME = nil;
+DOCKED_CHAT_FRAMES = {};
+DOCK_COPY = {};
+
+MOVING_CHATFRAME = nil;
+
+CHAT_TAB_SHOW_DELAY = 0.2;
+CHAT_TAB_HIDE_DELAY = 1;
+CHAT_FRAME_FADE_TIME = 0.15;
+CHAT_FRAME_FADE_OUT_TIME = 2.0;
+CHAT_FRAME_BUTTON_FRAME_MIN_ALPHA = 0.2;
+
+CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA = 1.0;
+CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA = 0.4;
+CHAT_FRAME_TAB_ALERTING_MOUSEOVER_ALPHA = 1.0;
+CHAT_FRAME_TAB_ALERTING_NOMOUSE_ALPHA = 1.0;
+CHAT_FRAME_TAB_NORMAL_MOUSEOVER_ALPHA = 0.6;
+CHAT_FRAME_TAB_NORMAL_NOMOUSE_ALPHA = 0.2;
+
+DEFAULT_CHATFRAME_ALPHA = 0.25;
+DEFAULT_CHATFRAME_COLOR = {r = 0, g = 0, b = 0};
+
+CHAT_FRAME_NORMAL_MIN_HEIGHT = 120;
+CHAT_FRAME_BIGGER_MIN_HEIGHT = 147;
+CHAT_FRAME_MIN_WIDTH = 296;
+
+CURRENT_CHAT_FRAME_ID = nil;
+
+CHAT_FRAME_TEXTURES = {
+ "Background",
+ "TopLeftTexture",
+ "BottomLeftTexture",
+ "TopRightTexture",
+ "BottomRightTexture",
+ "LeftTexture",
+ "RightTexture",
+ "BottomTexture",
+ "TopTexture",
+ --"ResizeButton",
+
+ "ButtonFrameBackground",
+ "ButtonFrameTopLeftTexture",
+ "ButtonFrameBottomLeftTexture",
+ "ButtonFrameTopRightTexture",
+ "ButtonFrameBottomRightTexture",
+ "ButtonFrameLeftTexture",
+ "ButtonFrameRightTexture",
+ "ButtonFrameBottomTexture",
+ "ButtonFrameTopTexture",
+}
+
+CHAT_FRAMES = {};
+
+function FloatingChatFrame_OnLoad(self)
+ --IMPORTANT NOTE: This function isn't run by ChatFrame1.
+ tinsert(CHAT_FRAMES, self:GetName());
+
+ FCF_SetTabPosition(self, 0);
+ FloatingChatFrame_Update(self:GetID());
+
+ FCFTab_UpdateColors(_G[self:GetName().."Tab"], true);
+ self:SetClampRectInsets(-35, 35, 26, -50);
+
+ local chatTab = _G[self:GetName().."Tab"];
+ chatTab.mouseOverAlpha = CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA;
+ chatTab.noMouseAlpha = CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA;
+end
+
+function FloatingChatFrame_OnEvent(self, event, ...)
+ if ( (event == "UPDATE_CHAT_WINDOWS") or (event == "UPDATE_FLOATING_CHAT_WINDOWS") ) then
+ FloatingChatFrame_Update(self:GetID(), 1);
+ self.isInitialized = 1;
+ elseif ( event == "UPDATE_CHAT_COLOR" ) then
+ local chatType, r, g, b = ...;
+ if ( self.isTemporary and self.chatType == chatType ) then
+ local tab = _G[self:GetName().."Tab"];
+ tab.selectedColorTable.r, tab.selectedColorTable.g, tab.selectedColorTable.b = r, g, b;
+ FCFTab_UpdateColors(tab, not self.isDocked or self == FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK));
+ end
+ end
+end
+
+function FloatingChatFrame_OnMouseScroll(self, delta)
+ if ( delta > 0 ) then
+ self:ScrollUp();
+ else
+ self:ScrollDown();
+ end
+end
+
+function FCF_GetChatWindowInfo(id)
+ if ( id > NUM_CHAT_WINDOWS ) then
+ local frame = _G["ChatFrame"..id];
+ local tab = _G["ChatFrame"..id.."Tab"];
+ local background = _G["ChatFrame"..id.."Background"];
+
+ if ( frame and tab and background ) then
+ local r, g, b, a = background:GetVertexColor();
+
+ return tab:GetText(), select(2, frame:GetFont()), r, g, b, a, frame:IsShown(), frame.isLocked, frame.isDocked, frame.isUninteractable;
+ --This is a temporary chat window. Pass this to whatever handles those options.
+ end
+ else
+ return GetChatWindowInfo(id);
+ end
+end
+
+function FCF_CopyChatSettings(copyTo, copyFrom)
+ local name, fontSize, r, g, b, a, shown, locked, docked, uninteractable = FCF_GetChatWindowInfo(copyFrom:GetID());
+ FCF_SetWindowColor(copyTo, r, g, b, 1);
+ FCF_SetWindowAlpha(copyTo, a, 1);
+ --If we're copying to a docked window, we don't want to copy locked.
+ if ( not copyTo.isDocked ) then
+ FCF_SetLocked(copyTo, locked);
+ end
+ FCF_SetUninteractable(copyTo, uninteractable);
+ FCF_SetChatWindowFontSize(nil, copyTo, fontSize);
+end
+
+function FloatingChatFrame_Update(id, onUpdateEvent)
+ local chatFrame = _G["ChatFrame"..id];
+ local chatTab = _G["ChatFrame"..id.."Tab"];
+
+ local name, fontSize, r, g, b, a, shown, locked, docked, uninteractable = FCF_GetChatWindowInfo(id);
+
+ -- Set Tab Name
+ FCF_SetWindowName(chatFrame, name, 1)
+
+ if ( onUpdateEvent ) then
+ -- Set Frame Color and Alpha
+ FCF_SetWindowColor(chatFrame, r, g, b, 1);
+ FCF_SetWindowAlpha(chatFrame, a, 1);
+ FCF_SetLocked(chatFrame, locked);
+ FCF_SetUninteractable(chatFrame, uninteractable);
+ end
+
+ if ( shown ) then
+ if ( not chatFrame.minimized ) then
+ chatFrame:Show();
+ end
+ FCF_SetTabPosition(chatFrame, 0);
+ else
+ if ( not chatFrame.isDocked ) then
+ chatFrame:Hide();
+ chatTab:Hide();
+ end
+ end
+
+ if ( docked ) then
+ FCF_DockFrame(chatFrame, docked, (id == 1));
+ else
+ if ( shown ) then
+ FCF_UnDockFrame(chatFrame);
+ if ( not chatFrame.minimized ) then
+ chatTab:Show();
+ end
+ else
+ FCF_Close(chatFrame);
+ end
+ end
+
+ if ( not chatFrame.isTemporary and (chatFrame == DEFAULT_CHAT_FRAME or not chatFrame.isDocked)) then
+ FCF_RestorePositionAndDimensions(chatFrame);
+ end
+
+ FCF_UpdateButtonSide(chatFrame);
+end
+
+-- Channel Dropdown
+function FCFOptionsDropDown_OnLoad(self)
+ CURRENT_CHAT_FRAME_ID = self:GetParent():GetID();
+ UIDropDownMenu_Initialize(self, FCFOptionsDropDown_Initialize, "MENU");
+ UIDropDownMenu_SetButtonWidth(self, 50);
+ UIDropDownMenu_SetWidth(self, 50);
+end
+
+function FCFOptionsDropDown_Initialize(dropDown)
+ -- Window preferences
+ local name, fontSize, r, g, b, a, shown = FCF_GetChatWindowInfo(FCF_GetCurrentChatFrameID());
+ local info;
+
+ local chatFrame = FCF_GetCurrentChatFrame();
+ local isTemporary = chatFrame and chatFrame.isTemporary;
+
+ -- If level 2
+ if ( UIDROPDOWNMENU_MENU_LEVEL == 2 ) then
+ -- If this is the font size menu then create dropdown
+ if ( UIDROPDOWNMENU_MENU_VALUE == FONT_SIZE ) then
+ -- Add the font heights from the font height table
+ local value;
+ for i=1, #CHAT_FONT_HEIGHTS do
+ value = CHAT_FONT_HEIGHTS[i];
+ info = UIDropDownMenu_CreateInfo();
+ info.text = format(FONT_SIZE_TEMPLATE, value);
+ info.value = value;
+ info.func = FCF_SetChatWindowFontSize;
+
+ local fontFile, fontHeight, fontFlags = FCF_GetCurrentChatFrame():GetFont();
+ if ( value == floor(fontHeight+0.5) ) then
+ info.checked = 1;
+ end
+
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+ end
+ return;
+ end
+ return;
+ end
+ -- Window options
+ info = UIDropDownMenu_CreateInfo();
+ if ( FCF_GetCurrentChatFrame(dropDown) and FCF_GetCurrentChatFrame(dropDown).isLocked ) then
+ info.text = UNLOCK_WINDOW;
+ else
+ info.text = LOCK_WINDOW;
+ end
+ info.func = FCF_ToggleLock;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ --Add Uninteractable button
+ info = UIDropDownMenu_CreateInfo();
+ if ( FCF_GetCurrentChatFrame(dropDown) and FCF_GetCurrentChatFrame(dropDown).isUninteractable) then
+ info.text = MAKE_INTERACTABLE;
+ else
+ info.text = MAKE_UNINTERACTABLE;
+ end
+ info.func = FCF_ToggleUninteractable;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ if ( not isTemporary ) then
+ -- Add name button
+ info = UIDropDownMenu_CreateInfo();
+ info.text = RENAME_CHAT_WINDOW;
+ info.func = FCF_RenameChatWindow_Popup;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+
+ if ( chatFrame == DEFAULT_CHAT_FRAME ) then
+ -- Create new chat window
+ info = UIDropDownMenu_CreateInfo();
+ info.text = NEW_CHAT_WINDOW;
+ info.func = FCF_NewChatWindow;
+ info.notCheckable = 1;
+ if (FCF_GetNumActiveChatFrames() == NUM_CHAT_WINDOWS ) then
+ info.disabled = 1;
+ end
+ UIDropDownMenu_AddButton(info);
+
+ -- Reset Chat windows to default
+ info = UIDropDownMenu_CreateInfo();
+ info.text = RESET_ALL_WINDOWS;
+ info.func = FCF_ResetAllWindows;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+
+ -- Close current chat window
+ if ( chatFrame and shown and (chatFrame ~= DEFAULT_CHAT_FRAME and not IsCombatLog(chatFrame)) ) then
+ if ( not chatFrame.isTemporary ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CLOSE_CHAT_WINDOW;
+ info.func = FCF_PopInWindow;
+ info.arg1 = FCF_GetCurrentChatFrame(dropDown);
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ elseif ( chatFrame.isTemporary and (chatFrame.chatType == "WHISPER" or chatFrame.chatType == "BN_WHISPER") ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CLOSE_CHAT_WHISPER_WINDOW;
+ info.func = FCF_PopInWindow;
+ info.arg1 = FCF_GetCurrentChatFrame(dropDown);
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ elseif ( chatFrame.isTemporary and (chatFrame.chatType == "BN_CONVERSATION" ) ) then
+ if ( GetCVar("conversationMode") == "popout" ) then
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CLOSE_AND_LEAVE_CHAT_CONVERSATION_WINDOW;
+ info.func = FCF_LeaveConversation;
+ info.arg1 = FCF_GetCurrentChatFrame(dropDown);
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ else
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CLOSE_CHAT_CONVERSATION_WINDOW;
+ info.func = FCF_PopInWindow;
+ info.arg1 = FCF_GetCurrentChatFrame(dropDown);
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+ else
+ error(format("Unhandled temporary window type. chatType: %s, chatTarget %s", tostring(chatFrame.chatType), tostring(chatFrame.chatTarget)));
+ end
+ end
+
+ -- Display header
+ info = UIDropDownMenu_CreateInfo();
+ info.text = DISPLAY;
+ info.notClickable = 1;
+ info.isTitle = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ -- Font size
+ info = UIDropDownMenu_CreateInfo();
+ info.text = FONT_SIZE;
+ --info.notClickable = 1;
+ info.hasArrow = 1;
+ info.func = nil;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ -- Set Background color
+ info = UIDropDownMenu_CreateInfo();
+ info.text = BACKGROUND;
+ info.hasColorSwatch = 1;
+ info.r = r;
+ info.g = g;
+ info.b = b;
+ -- Done because the slider is reversed
+ if ( a ) then
+ a = 1- a;
+ end
+ info.opacity = a;
+ info.swatchFunc = FCF_SetChatWindowBackGroundColor;
+ info.func = UIDropDownMenuButton_OpenColorPicker;
+ --info.notCheckable = 1;
+ info.hasOpacity = 1;
+ info.opacityFunc = FCF_SetChatWindowOpacity;
+ info.cancelFunc = FCF_CancelWindowColorSettings;
+ UIDropDownMenu_AddButton(info);
+
+ if ( not isTemporary ) then
+ -- Filter header
+ info = UIDropDownMenu_CreateInfo();
+ info.text = FILTERS;
+ --info.notClickable = 1;
+ info.isTitle = 1;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ -- Configure settings
+ info = UIDropDownMenu_CreateInfo();
+ info.text = CHAT_CONFIGURATION;
+ info.func = function() ShowUIPanel(ChatConfigFrame); end;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+ end
+end
+--[[
+function FCFDropDown_LoadServerChannels(...)
+ local checked;
+ local channelList = FCF_GetCurrentChatFrame().channelList;
+ local zoneChannelList = FCF_GetCurrentChatFrame().zoneChannelList;
+ local info, channel;
+
+ -- Server Channels header
+ info = UIDropDownMenu_CreateInfo();
+ info.text = SERVER_CHANNELS;
+ info.notClickable = 1;
+ info.isTitle = 1;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+
+ info = UIDropDownMenu_CreateInfo();
+ for i=1, select("#", ...) do
+ checked = nil;
+ channel = select(i, ...);
+ if ( channelList ) then
+ for index, value in pairs(channelList) do
+ if ( value == channel ) then
+ checked = 1;
+ end
+ end
+ end
+ if ( zoneChannelList ) then
+ for index, value in pairs(zoneChannelList) do
+ if ( value == channel ) then
+ checked = 1;
+ end
+ end
+ end
+
+ info.text = channel;
+ info.value = channel;
+ info.func = FCFServerChannelsDropDown_OnClick;
+ info.checked = checked;
+ info.keepShownOnClick = 1;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+ end
+end
+
+function FCFServerChannelsDropDown_OnClick()
+ if ( UIDropDownMenuButton_GetChecked() ) then
+ ChatFrame_RemoveChannel(FCF_GetCurrentChatFrame(), UIDropDownMenuButton_GetName());
+ else
+ JoinPermanentChannel(UIDropDownMenuButton_GetName(), nil, FCF_GetCurrentChatFrameID(), 1);
+ ChatFrame_AddChannel(FCF_GetCurrentChatFrame(), UIDropDownMenuButton_GetName());
+ end
+end
+]]
+function FCFDropDown_LoadChannels(...)
+ local checked;
+ local channelList = FCF_GetCurrentChatFrame().channelList;
+ local zoneChannelList = FCF_GetCurrentChatFrame().zoneChannelList;
+ local info = UIDropDownMenu_CreateInfo();
+ local channel, tag;
+ for i=1, select("#", ...), 2 do
+ checked = nil;
+ tag = "CHANNEL"..select(i, ...);
+ channel = select(i+1, ...);
+ if ( channelList ) then
+ for index, value in pairs(channelList) do
+ if ( value == channel ) then
+ checked = 1;
+ end
+ end
+ end
+ if ( zoneChannelList ) then
+ for index, value in pairs(zoneChannelList) do
+ if ( value == channel ) then
+ checked = 1;
+ end
+ end
+ end
+ info.text = channel;
+ info.value = tag;
+ info.func = FCFChannelDropDown_OnClick;
+ info.checked = checked;
+ info.keepShownOnClick = 1;
+ -- Color the chat channel
+ local color = ChatTypeInfo[tag];
+ info.hasColorSwatch = 1;
+ info.r = color.r;
+ info.g = color.g;
+ info.b = color.b;
+ -- Set the function the color picker calls
+ info.swatchFunc = FCF_SetChatTypeColor;
+ info.cancelFunc = FCF_CancelFontColorSettings;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+ end
+end
+
+function FCFChannelDropDown_OnClick()
+ if ( UIDropDownMenuButton_GetChecked() ) then
+ ChatFrame_RemoveChannel(FCF_GetCurrentChatFrame(), UIDropDownMenuButton_GetName());
+ else
+ ChatFrame_AddChannel(FCF_GetCurrentChatFrame(), UIDropDownMenuButton_GetName());
+ end
+end
+
+-- Used to display chattypegroups
+function FCFDropDown_LoadChatTypes(menuChatTypeGroups)
+ local checked, chatTypeInfo;
+ local messageTypeList = FCF_GetCurrentChatFrame().messageTypeList;
+ local info, group;
+ for index, value in pairs(menuChatTypeGroups) do
+ checked = nil;
+ if ( messageTypeList ) then
+ for joinedIndex, joinedValue in pairs(messageTypeList) do
+ if ( value == joinedValue ) then
+ checked = 1;
+ end
+ end
+ end
+ info = UIDropDownMenu_CreateInfo();
+ info.value = value;
+ info.func = FCFMessageTypeDropDown_OnClick;
+ info.checked = checked;
+ -- Set to keep shown on button click
+ info.keepShownOnClick = 1;
+
+ -- If more than one message type in a Chat Type Group need to show an expand arrow
+ group = ChatTypeGroup[value];
+ if ( getn(group) > 1 ) then
+ info.text = _G[value];
+ info.hasArrow = 1;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+ else
+ info.text = _G[group[1]];
+ chatTypeInfo = ChatTypeInfo[FCF_StripChatMsg(group[1])];
+ -- If no chatTypeInfo then don't display
+ if ( chatTypeInfo ) then
+ -- Set the function to be called when a color is set
+ info.swatchFunc = FCF_SetChatTypeColor;
+ -- Set the swatch color info
+ info.hasColorSwatch = 1;
+ info.r = chatTypeInfo.r;
+ info.g = chatTypeInfo.g;
+ info.b = chatTypeInfo.b;
+ info.cancelFunc = FCF_CancelFontColorSettings;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+ end
+ end
+ end
+end
+
+-- Used to display chatsubtypes
+function FCF_LoadChatSubTypes(chatGroup)
+ if ( chatGroup ) then
+ chatGroup = ChatTypeGroup[chatGroup];
+ else
+ chatGroup = ChatTypeGroup[UIDROPDOWNMENU_MENU_VALUE];
+ end
+ if ( chatGroup ) then
+ local info = UIDropDownMenu_CreateInfo();
+ local chatTypeInfo
+ for index, value in pairs(chatGroup) do
+ chatTypeInfo = ChatTypeInfo[FCF_StripChatMsg(value)];
+ if ( chatTypeInfo ) then
+ info.text = _G[value];
+ info.value = FCF_StripChatMsg(value);
+ -- Disable the button and color the text white
+ info.notClickable = 1;
+ -- Set to be notcheckable
+ info.notCheckable = 1;
+ -- Set the function to be called when a color is set
+ info.swatchFunc = FCF_SetChatTypeColor;
+ -- Set the swatch color info
+ info.hasColorSwatch = 1;
+ info.r = chatTypeInfo.r;
+ info.g = chatTypeInfo.g;
+ info.b = chatTypeInfo.b;
+ -- Set function called when cancel is clicked in the colorpicker
+ info.cancelFunc = FCF_CancelFontColorSettings;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+ end
+ end
+ end
+end
+
+function FCFMessageTypeDropDown_OnClick(self)
+ if ( UIDropDownMenuButton_GetChecked() ) then
+ ChatFrame_RemoveMessageGroup(FCF_GetCurrentChatFrame(), self.value);
+ else
+ ChatFrame_AddMessageGroup(FCF_GetCurrentChatFrame(), self.value);
+ end
+end
+
+function FCF_OpenNewWindow(name)
+ local count = 1;
+ local chatFrame, chatTab;
+
+ for i=1, NUM_CHAT_WINDOWS do
+ local _, _, _, _, _, _, shown = FCF_GetChatWindowInfo(i);
+ chatFrame = _G["ChatFrame"..i];
+ chatTab = _G["ChatFrame"..i.."Tab"];
+ if ( (not shown and not chatFrame.isDocked) or (count == NUM_CHAT_WINDOWS) ) then
+ if ( not name or name == "" ) then
+ name = format(CHAT_NAME_TEMPLATE, i);
+ end
+
+ -- initialize the frame
+ FCF_SetWindowName(chatFrame, name);
+ FCF_SetWindowColor(chatFrame, DEFAULT_CHATFRAME_COLOR.r, DEFAULT_CHATFRAME_COLOR.g, DEFAULT_CHATFRAME_COLOR.b);
+ FCF_SetWindowAlpha(chatFrame, DEFAULT_CHATFRAME_ALPHA);
+ SetChatWindowLocked(i, nil);
+
+ -- clear stale messages
+ chatFrame:Clear();
+
+ -- Listen to the standard messages
+ ChatFrame_RemoveAllMessageGroups(chatFrame);
+ ChatFrame_RemoveAllChannels(chatFrame);
+ ChatFrame_ReceiveAllPrivateMessages(chatFrame);
+ ChatFrame_ReceiveAllBNConversations(chatFrame);
+
+ ChatFrame_AddMessageGroup(chatFrame, "SAY");
+ ChatFrame_AddMessageGroup(chatFrame, "YELL");
+ ChatFrame_AddMessageGroup(chatFrame, "GUILD");
+ ChatFrame_AddMessageGroup(chatFrame, "WHISPER");
+ ChatFrame_AddMessageGroup(chatFrame, "BN_WHISPER");
+ ChatFrame_AddMessageGroup(chatFrame, "PARTY");
+ ChatFrame_AddMessageGroup(chatFrame, "PARTY_LEADER");
+ ChatFrame_AddMessageGroup(chatFrame, "CHANNEL");
+
+ --Clear the edit box history.
+ chatFrame.editBox:ClearHistory();
+
+ -- Show the frame and tab
+ chatFrame:Show();
+ chatTab:Show();
+ SetChatWindowShown(i, 1);
+
+ -- Dock the frame by default
+ FCF_DockFrame(chatFrame, (#FCFDock_GetChatFrames(GENERAL_CHAT_DOCK)+1), true);
+ FCF_FadeInChatFrame(FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK));
+ return chatFrame;
+ end
+ count = count + 1;
+ end
+end
+
+function FCF_SetTemporaryWindowType(chatFrame, chatType, chatTarget)
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ --If the frame was already registered, unregister it.
+ if ( chatFrame.isRegistered ) then
+ FCFManager_UnregisterDedicatedFrame(chatFrame, chatFrame.chatType, chatFrame.chatTarget);
+ chatFrame.isRegistered = false;
+ end
+
+ --Set the title text
+ local name;
+ if ( chatType == "WHISPER" or chatType == "BN_WHISPER" ) then
+ name = chatTarget;
+ elseif ( chatType == "BN_CONVERSATION" ) then
+ name = format(CONVERSATION_NAME, tonumber(chatTarget) + MAX_WOW_CHAT_CHANNELS);
+ end
+ FCF_SetWindowName(chatFrame, name);
+
+
+ --Set up the window to receive the message types we want.
+ chatFrame.chatType = chatType;
+ chatFrame.chatTarget = chatTarget;
+
+ ChatFrame_RemoveAllMessageGroups(chatFrame);
+ ChatFrame_RemoveAllChannels(chatFrame);
+ ChatFrame_ReceiveAllPrivateMessages(chatFrame);
+ ChatFrame_ReceiveAllBNConversations(chatFrame);
+
+ ChatFrame_AddMessageGroup(chatFrame, chatType);
+
+ chatFrame.editBox:SetAttribute("chatType", chatType);
+ chatFrame.editBox:SetAttribute("stickyType", chatType);
+
+ if ( chatType == "WHISPER" or chatType == "BN_WHISPER" ) then
+ chatFrame.editBox:SetAttribute("tellTarget", chatTarget);
+ ChatFrame_AddPrivateMessageTarget(chatFrame, chatTarget);
+ elseif ( chatType == "BN_CONVERSATION" ) then
+ chatFrame.editBox:SetAttribute("channelTarget", chatTarget);
+ ChatFrame_AddBNConversationTarget(chatFrame, chatTarget);
+ end
+
+ -- Set up the colors
+ local info = ChatTypeInfo[chatType];
+ chatTab.selectedColorTable = { r = info.r, g = info.g, b = info.b };
+ FCFTab_UpdateColors(chatTab, not chatFrame.isDocked or chatFrame == FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK));
+
+ --If it's a conversation, create the conversation button
+ if ( chatType == "BN_CONVERSATION" or chatType == "BN_WHISPER" ) then
+ if ( chatFrame.conversationButton ) then
+ BNConversationButton_UpdateTarget(chatFrame.conversationButton);
+ chatFrame.conversationButton:Show();
+ else
+ CreateFrame("Button", chatFrame:GetName().."ConversationButton", chatFrame.buttonFrame, "BNConversationRosterButtonTemplate", chatFrame:GetID());
+ end
+ if ( chatFrame:GetHeight() < CHAT_FRAME_BIGGER_MIN_HEIGHT ) then
+ chatFrame:SetHeight(CHAT_FRAME_BIGGER_MIN_HEIGHT);
+ end
+ chatFrame:SetMinResize(CHAT_FRAME_MIN_WIDTH, CHAT_FRAME_BIGGER_MIN_HEIGHT);
+ else
+ if ( chatFrame.conversationButton ) then
+ chatFrame.conversationButton:Hide();
+ end
+ chatFrame:SetMinResize(CHAT_FRAME_MIN_WIDTH, CHAT_FRAME_NORMAL_MIN_HEIGHT);
+ end
+
+ --If it's a conversation, get it ready to convert to a whisper if needed.
+ if ( chatType == "BN_CONVERSATION" ) then
+ chatFrame:RegisterEvent("BN_CHAT_CHANNEL_CLOSED");
+ else
+ chatFrame:UnregisterEvent("BN_CHAT_CHANNEL_CLOSED");
+ end
+
+ --Set the icon
+ local conversationIcon;
+ if ( chatType == "WHISPER" or chatType == "BN_WHISPER" ) then
+ conversationIcon = "Interface\\ChatFrame\\UI-ChatWhisperIcon";
+ else
+ conversationIcon = "Interface\\ChatFrame\\UI-ChatConversationIcon";
+ end
+
+ chatTab.conversationIcon:SetTexture(conversationIcon);
+ if ( chatFrame.minFrame ) then
+ chatFrame.minFrame.conversationIcon:SetTexture(conversationIcon);
+ end
+
+ --Register this frame
+ FCFManager_RegisterDedicatedFrame(chatFrame, chatType, chatTarget);
+ chatFrame.isRegistered = true;
+
+ --The window name may have been updated, so update the dock and tabs.
+ FCF_DockUpdate();
+end
+
+local maxTempIndex = NUM_CHAT_WINDOWS + 1;
+function FCF_OpenTemporaryWindow(chatType, chatTarget, sourceChatFrame, selectWindow)
+ local chatFrame, chatTab, conversationIcon;
+ for _, chatFrameName in pairs(CHAT_FRAMES) do
+ local frame = _G[chatFrameName];
+ if ( frame.isTemporary ) then
+ if ( not frame.inUse and not frame.isDocked ) then
+ chatFrame = frame;
+ chatTab = _G[chatFrame:GetName().."Tab"];
+ break;
+ end
+ end
+ end
+
+ if ( not chatFrame ) then
+ chatTab = CreateFrame("Button", "ChatFrame"..maxTempIndex.."Tab", UIParent, "ChatTabTemplate", maxTempIndex);
+
+ conversationIcon = chatTab:CreateTexture(chatTab:GetName().."ConversationIcon", "ARTWORK", "ChatTabConversationIconTemplate");
+ conversationIcon:ClearAllPoints();
+ conversationIcon:SetPoint("RIGHT", chatTab:GetFontString(), "LEFT", 0, -2);
+ chatTab.conversationIcon = conversationIcon;
+
+ local tabText = _G[chatTab:GetName().."Text"];
+ tabText:SetPoint("LEFT", chatTab.leftTexture, "RIGHT", 10, -6);
+ tabText:SetJustifyH("LEFT");
+ chatTab.sizePadding = 10;
+
+ chatFrame = CreateFrame("ScrollingMessageFrame", "ChatFrame"..maxTempIndex, UIParent, "FloatingChatFrameTemplate", maxTempIndex);
+
+ if ( GetCVarBool("chatMouseScroll") ) then
+ chatFrame:SetScript("OnMouseWheel", FloatingChatFrame_OnMouseScroll);
+ chatFrame:EnableMouseWheel(true);
+ end
+
+ maxTempIndex = maxTempIndex + 1;
+ end
+
+ --Copy chat settings from the source frame.
+ FCF_CopyChatSettings(chatFrame, sourceChatFrame or DEFAULT_CHAT_FRAME);
+
+ -- clear stale messages
+ chatFrame:Clear();
+ chatFrame.inUse = true;
+ chatFrame.isTemporary = true;
+
+ FCF_SetTemporaryWindowType(chatFrame, chatType, chatTarget);
+
+ --Clear the edit box history.
+ chatFrame.editBox:ClearHistory();
+
+ if ( sourceChatFrame ) then
+ --Stop displaying this type of chat in the old chat frame.
+ if ( chatType == "WHISPER" or chatType == "BN_WHISPER" ) then
+ ChatFrame_ExcludePrivateMessageTarget(sourceChatFrame, chatTarget);
+ elseif ( chatType == "BN_CONVERSATION" ) then
+ ChatFrame_ExcludeBNConversationTarget(sourceChatFrame, chatTarget);
+ end
+
+ --Copy over messages
+ local accessID = ChatHistory_GetAccessID(chatType, chatTarget);
+ for i = 1, sourceChatFrame:GetNumMessages(accessID) do
+ local text, accessID, lineID, extraData = sourceChatFrame:GetMessageInfo(i, accessID);
+ local cType, cTarget = ChatHistory_GetChatType(extraData);
+
+ local info = ChatTypeInfo[cType];
+ chatFrame:AddMessage(text, info.r, info.g, info.b, lineID, false, accessID, extraData);
+ end
+ --Remove the messages from the old frame.
+ sourceChatFrame:RemoveMessagesByAccessID(accessID);
+ end
+
+ --Close the Editbox
+ ChatEdit_DeactivateChat(chatFrame.editBox);
+
+ -- Show the frame and tab
+ chatFrame:Show();
+ chatTab:Show();
+
+ -- Dock the frame by default
+ FCF_DockFrame(chatFrame, (#FCFDock_GetChatFrames(GENERAL_CHAT_DOCK)+1), selectWindow);
+ return chatFrame;
+end
+
+function FCF_GetNumActiveChatFrames()
+ local count = 0;
+ local chatFrame;
+ for i=1, NUM_CHAT_WINDOWS do
+ local _, _, _, _, _, _, shown = FCF_GetChatWindowInfo(i);
+ chatFrame = _G["ChatFrame"..i];
+ if ( chatFrame ) then
+ if ( shown or chatFrame.isDocked ) then
+ count = count + 1;
+ end
+ end
+ end
+ return count;
+end
+
+function FCF_RenameChatWindow_Popup()
+ local dialog = StaticPopup_Show("NAME_CHAT");
+ dialog.data = FCF_GetCurrentChatFrameID();
+end
+
+function FCF_NewChatWindow()
+ StaticPopup_Show("NAME_CHAT");
+end
+
+function FCF_ResetAllWindows()
+ StaticPopup_Show("RESET_CHAT");
+end
+
+--[[function FCF_ChatChannels()
+ ToggleFriendsFrame(4);
+end]]--
+
+function FCF_SetWindowName(frame, name, doNotSave)
+ if ( not name or name == "") then
+ -- Hack to initialize the chat window names, since globalstrings are not available on init
+ if ( frame:GetID() == 1 ) then
+ name = GENERAL;
+ doNotSave = nil;
+ elseif ( frame:GetID() == 2 ) then
+ name = COMBAT_LOG;
+ doNotSave = nil;
+ else
+ name = format(CHAT_NAME_TEMPLATE, frame:GetID());
+ end
+ else
+ FCFDock_SetDirty(GENERAL_CHAT_DOCK);
+ end
+ frame.name = name;
+ local tab = _G[frame:GetName().."Tab"];
+ tab:SetText(name);
+ PanelTemplates_TabResize(tab, tab.sizePadding or 0);
+ -- Save this off so we know how big the tab should always be, even if it gets shrunken on the dock.
+ tab.textWidth = _G[tab:GetName().."Text"]:GetWidth();
+ if ( not doNotSave ) then
+ SetChatWindowName(frame:GetID(), name);
+ end
+ if ( frame.minFrame ) then
+ frame.minFrame:SetText(name);
+ end
+end
+
+function FCF_SetWindowColor(frame, r, g, b, doNotSave)
+ local name = frame:GetName();
+ for index, value in pairs(CHAT_FRAME_TEXTURES) do
+ --NOTE - If this is changed, please change the equivalent code in GMChatFrame_OnLoad.
+ local object = _G[name..value];
+ local objectType = object:GetObjectType();
+ if ( objectType == "Button" ) then
+ object:GetNormalTexture():SetVertexColor(r, g, b);
+ object:GetHighlightTexture():SetVertexColor(r, g, b);
+ object:GetPushedTexture():SetVertexColor(r, g, b);
+ elseif ( objectType == "Texture" ) then
+ _G[name..value]:SetVertexColor(r,g,b);
+ else
+ --error("Unhandled frame type...");
+ end
+ end
+ if ( not doNotSave ) then
+ SetChatWindowColor(frame:GetID(), r, g, b);
+ end
+end
+
+function FCF_SetWindowAlpha(frame, alpha, doNotSave)
+ local name = frame:GetName();
+ for index, value in pairs(CHAT_FRAME_TEXTURES) do
+ _G[name..value]:SetAlpha(alpha);
+ end
+ if ( not doNotSave ) then
+ SetChatWindowAlpha(frame:GetID(), alpha);
+ end
+ -- Remember the alpha
+ frame.oldAlpha = alpha;
+end
+
+function FCF_GetCurrentChatFrameID()
+ return CURRENT_CHAT_FRAME_ID;
+end
+
+function FCF_GetCurrentChatFrame(child)
+ local currentChatFrame = nil;
+ if ( CURRENT_CHAT_FRAME_ID ) then
+ currentChatFrame = _G["ChatFrame"..CURRENT_CHAT_FRAME_ID];
+ end
+ if ( not currentChatFrame and child ) then
+ currentChatFrame = _G["ChatFrame"..child:GetParent():GetID()];
+ end
+ return currentChatFrame;
+end
+
+function FCF_SetChatTypeColor()
+ local r,g,b = ColorPickerFrame:GetColorRGB();
+ ChangeChatColor(UIDROPDOWNMENU_MENU_VALUE, r, g, b);
+end
+
+function FCF_SetChatWindowBackGroundColor()
+ local r,g,b = ColorPickerFrame:GetColorRGB();
+ FCF_SetWindowColor(FCF_GetCurrentChatFrame(), r, g, b)
+ SetChatWindowColor(FCF_GetCurrentChatFrameID(), r, g, b);
+end
+
+function FCF_SetChatWindowOpacity()
+ local alpha = 1.0 - OpacitySliderFrame:GetValue();
+ FCF_SetWindowAlpha(FCF_GetCurrentChatFrame(), alpha);
+end
+
+function FCF_SetChatWindowFontSize(self, chatFrame, fontSize)
+ if ( not chatFrame ) then
+ chatFrame = FCF_GetCurrentChatFrame();
+ end
+ if ( not fontSize ) then
+ fontSize = self.value;
+ end
+ local fontFile, unused, fontFlags = chatFrame:GetFont();
+ chatFrame:SetFont(fontFile, fontSize, fontFlags);
+ if ( GMChatFrame and chatFrame == DEFAULT_CHAT_FRAME ) then
+ GMChatFrame:SetFont(fontFile, fontSize, fontFlags);
+ end
+ SetChatWindowSize(chatFrame:GetID(), fontSize);
+end
+
+function FCF_CancelFontColorSettings(previousValues)
+ if ( previousValues.r ) then
+ ChangeChatColor(UIDROPDOWNMENU_MENU_VALUE, previousValues.r, previousValues.g, previousValues.b);
+ end
+end
+
+function FCF_CancelWindowColorSettings(previousValues)
+ if ( previousValues.r ) then
+ FCF_SetWindowColor(FCF_GetCurrentChatFrame(), previousValues.r, previousValues.g, previousValues.b)
+ SetChatWindowColor(FCF_GetCurrentChatFrameID(), previousValues.r, previousValues.g, previousValues.b);
+ end
+ if ( previousValues.opacity ) then
+ FCF_SetWindowAlpha(FCF_GetCurrentChatFrame(), 1 - previousValues.opacity);
+ end
+end
+
+function FCF_StripChatMsg(string)
+ if ( strsub(string,1,8) == "CHAT_MSG" ) then
+ return strsub(string,10);
+ else
+ return string;
+ end
+end
+
+function FCF_ToggleLock()
+ local chatFrame = FCF_GetCurrentChatFrame();
+ if ( chatFrame.isLocked ) then
+ -- If unlocking a docked frame then undock it and center it on the screen
+ if ( chatFrame.isDocked and chatFrame ~= DEFAULT_CHAT_FRAME ) then
+ FCF_UnDockFrame(chatFrame);
+ chatFrame:ClearAllPoints();
+ chatFrame:SetPoint("CENTER", "UIParent", "CENTER", 0, 0);
+ FCF_SetTabPosition(chatFrame, 0);
+ chatFrame:Show();
+ end
+ FCF_SetLocked(chatFrame, nil);
+ else
+ FCF_SetLocked(chatFrame, 1);
+ end
+end
+
+function FCF_SetLocked(chatFrame, isLocked)
+ chatFrame.isLocked = isLocked;
+ if ( chatFrame.isUninteractable or isLocked ) then
+ chatFrame.resizeButton:Hide();
+ else
+ chatFrame.resizeButton:Show();
+ --chatFrame.resizeButton:SetAlpha(_G[chatFrame:GetName().."Background"]:GetAlpha());
+ end
+ SetChatWindowLocked(chatFrame:GetID(), isLocked);
+end
+
+function FCF_ToggleUninteractable()
+ local chatFrame = FCF_GetCurrentChatFrame();
+ if ( chatFrame.isUninteractable ) then
+ FCF_SetExpandedUninteractable(chatFrame, false)
+ else
+ FCF_SetExpandedUninteractable(chatFrame, true)
+ end
+end
+
+function FCF_SetExpandedUninteractable(chatFrame, isUninteractable)
+ if ( chatFrame.isDocked ) then
+ for _, frame in pairs(GENERAL_CHAT_DOCK.DOCKED_CHAT_FRAMES) do
+ FCF_SetUninteractable(frame, isUninteractable);
+ end
+ else
+ FCF_SetUninteractable(chatFrame, isUninteractable);
+ end
+end
+
+function FCF_SetUninteractable(chatFrame, isUninteractable) --No, uninteractable is not really a word.
+ chatFrame.isUninteractable = isUninteractable;
+ SetChatWindowUninteractable(chatFrame:GetID(), isUninteractable);
+ if ( not chatFrame.overrideHyperlinksEnabled ) then
+ chatFrame:SetHyperlinksEnabled(not isUninteractable);
+ end
+ local chatFrameName = chatFrame:GetName();
+ if ( isUninteractable or chatFrame.isLocked ) then
+ _G[chatFrameName.."ResizeButton"]:Hide();
+ else
+ _G[chatFrameName.."ResizeButton"]:Show();
+ end
+end
+
+function FCF_FadeInChatFrame(chatFrame)
+ local frameName = chatFrame:GetName();
+ chatFrame.hasBeenFaded = true;
+ for index, value in pairs(CHAT_FRAME_TEXTURES) do
+ local object = _G[frameName..value];
+ if ( object:IsShown() ) then
+ UIFrameFadeIn(object, CHAT_FRAME_FADE_TIME, object:GetAlpha(), max(chatFrame.oldAlpha, DEFAULT_CHATFRAME_ALPHA));
+ end
+ end
+ if ( chatFrame == FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK) ) then
+ for _, frame in pairs(FCFDock_GetChatFrames(GENERAL_CHAT_DOCK)) do
+ if ( frame ~= chatFrame ) then
+ FCF_FadeInChatFrame(frame);
+ end
+ end
+ if ( GENERAL_CHAT_DOCK.overflowButton:IsShown() ) then
+ UIFrameFadeIn(GENERAL_CHAT_DOCK.overflowButton, CHAT_FRAME_FADE_TIME, GENERAL_CHAT_DOCK.overflowButton:GetAlpha(), CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA);
+ end
+ end
+
+ local chatTab = _G[frameName.."Tab"];
+ UIFrameFadeIn(chatTab, CHAT_FRAME_FADE_TIME, chatTab:GetAlpha(), chatTab.mouseOverAlpha);
+
+ --Fade in the button frame
+ if ( not chatFrame.isDocked ) then
+ UIFrameFadeIn(chatFrame.buttonFrame, CHAT_FRAME_FADE_TIME, chatFrame.buttonFrame:GetAlpha(), 1);
+ end
+end
+
+function FCF_FadeOutChatFrame(chatFrame)
+ local frameName = chatFrame:GetName();
+ chatFrame.hasBeenFaded = nil;
+ for index, value in pairs(CHAT_FRAME_TEXTURES) do
+ -- Fade out chat frame
+ local object = _G[frameName..value];
+ if ( object:IsShown() ) then
+ UIFrameFadeOut(object, CHAT_FRAME_FADE_OUT_TIME, max(object:GetAlpha(), chatFrame.oldAlpha), chatFrame.oldAlpha);
+ end
+ end
+ if ( chatFrame == FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK) ) then
+ for _, frame in pairs(FCFDock_GetChatFrames(GENERAL_CHAT_DOCK)) do
+ if ( frame ~= chatFrame ) then
+ FCF_FadeOutChatFrame(frame);
+ end
+ end
+ if ( GENERAL_CHAT_DOCK.overflowButton:IsShown() ) then
+ UIFrameFadeOut(GENERAL_CHAT_DOCK.overflowButton, CHAT_FRAME_FADE_OUT_TIME, GENERAL_CHAT_DOCK.overflowButton:GetAlpha(), CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA);
+ end
+ end
+
+ local chatTab = _G[frameName.."Tab"];
+ UIFrameFadeOut(chatTab, CHAT_FRAME_FADE_OUT_TIME, chatTab:GetAlpha(), chatTab.noMouseAlpha);
+
+ --Fade out the ButtonFrame
+ if ( not chatFrame.isDocked ) then
+ UIFrameFadeOut(chatFrame.buttonFrame, CHAT_FRAME_FADE_OUT_TIME, chatFrame.buttonFrame:GetAlpha(), CHAT_FRAME_BUTTON_FRAME_MIN_ALPHA);
+ end
+end
+
+local LAST_CURSOR_X, LAST_CURSOR_Y;
+function FCF_OnUpdate(elapsed)
+ local cursorX, cursorY = GetCursorPosition();
+
+ local overSomething = false;
+ for _, frameName in pairs(CHAT_FRAMES) do
+ local chatFrame = _G[frameName];
+ if ( chatFrame:IsShown() ) then
+ local topOffset = 28;
+ if ( IsCombatLog(chatFrame) ) then
+ topOffset = topOffset + CombatLogQuickButtonFrame_Custom:GetHeight();
+ end
+ --Items that will always cause the frame to fade in.
+ if ( MOVING_CHATFRAME or chatFrame.resizeButton:GetButtonState() == "PUSHED" or (chatFrame.isDocked and GENERAL_CHAT_DOCK.overflowButton.list:IsShown())) then
+ overSomething = true;
+ chatFrame.mouseOutTime = 0;
+ if ( not chatFrame.hasBeenFaded ) then
+ overSomething = true;
+ FCF_FadeInChatFrame(chatFrame);
+ end
+ --Things that will cause the frame to fade in if the mouse is stationary.
+ elseif ( chatFrame:IsMouseOver(topOffset, -2, -2, 2) or --This should be slightly larger than the hit rect insets to give us some wiggle room.
+ (chatFrame.isDocked and FriendsMicroButton:IsMouseOver()) or
+ (chatFrame.buttonFrame:IsMouseOver())) then
+ overSomething = true;
+ chatFrame.mouseOutTime = 0;
+ if ( cursorX == LAST_CURSOR_X and cursorY == LAST_CURSOR_Y and not chatFrame.hasBeenFaded ) then
+ chatFrame.mouseInTime = (chatFrame.mouseInTime or 0) + elapsed;
+ if ( chatFrame.mouseInTime > CHAT_TAB_SHOW_DELAY ) then
+ FCF_FadeInChatFrame(chatFrame);
+ end
+ else
+ chatFrame.mouseInTime = 0;
+ end
+ elseif ( chatFrame:IsShown() and chatFrame.hasBeenFaded ) then
+ chatFrame.mouseInTime = 0;
+ chatFrame.mouseOutTime = (chatFrame.mouseOutTime or 0) + elapsed;
+ if ( chatFrame.mouseOutTime > CHAT_TAB_HIDE_DELAY ) then
+ FCF_FadeOutChatFrame(chatFrame);
+ end
+ end
+ end
+ end
+
+ LAST_CURSOR_X, LAST_CURSOR_Y = cursorX, cursorY;
+end
+
+function FCF_SavePositionAndDimensions(chatFrame)
+ local centerX = chatFrame:GetLeft() + chatFrame:GetWidth() / 2;
+ local centerY = chatFrame:GetBottom() + chatFrame:GetHeight() / 2;
+
+ local horizPoint, vertPoint;
+ local screenWidth, screenHeight = GetScreenWidth(), GetScreenHeight();
+ local xOffset, yOffset;
+ if ( centerX > screenWidth / 2 ) then
+ horizPoint = "RIGHT";
+ xOffset = (chatFrame:GetRight() - screenWidth)/screenWidth;
+ else
+ horizPoint = "LEFT";
+ xOffset = chatFrame:GetLeft()/screenWidth;
+ end
+
+ if ( centerY > screenHeight / 2 ) then
+ vertPoint = "TOP";
+ yOffset = (chatFrame:GetTop() - screenHeight)/screenHeight;
+ else
+ vertPoint = "BOTTOM";
+ yOffset = chatFrame:GetBottom()/screenHeight;
+ end
+
+ SetChatWindowSavedPosition(chatFrame:GetID(), vertPoint..horizPoint, xOffset, yOffset);
+ SetChatWindowSavedDimensions(chatFrame:GetID(), chatFrame:GetWidth(), chatFrame:GetHeight());
+end
+
+function FCF_RestorePositionAndDimensions(chatFrame)
+ local width, height = GetChatWindowSavedDimensions(chatFrame:GetID());
+ if ( width and height ) then
+ chatFrame:SetSize(width, height);
+ end
+
+ local point, xOffset, yOffset = GetChatWindowSavedPosition(chatFrame:GetID());
+ if ( point ) then
+ chatFrame:ClearAllPoints();
+ chatFrame:SetPoint(point, xOffset * GetScreenWidth(), yOffset * GetScreenHeight());
+ chatFrame:SetUserPlaced(true);
+ else
+ chatFrame:SetUserPlaced(false);
+ end
+end
+
+-- Docking handling functions
+function FCF_StopDragging(chatFrame)
+ chatFrame:StopMovingOrSizing();
+
+ _G[chatFrame:GetName().."Tab"]:UnlockHighlight();
+
+ FCFDock_HideInsertHighlight(GENERAL_CHAT_DOCK);
+
+ if ( GENERAL_CHAT_DOCK:IsMouseOver(10, -10, 0, 10) ) then
+ local mouseX, mouseY = GetCursorPosition();
+ mouseX, mouseY = mouseX / UIParent:GetScale(), mouseY / UIParent:GetScale();
+ FCF_DockFrame(chatFrame, FCFDock_GetInsertIndex(GENERAL_CHAT_DOCK, chatFrame, mouseX, mouseY), true);
+ else
+ FCF_SetTabPosition(chatFrame, 0);
+ end
+
+ FCF_SavePositionAndDimensions(chatFrame);
+
+ MOVING_CHATFRAME = nil;
+end
+
+function FCFTab_OnUpdate(self, elapsed)
+ local cursorX, cursorY = GetCursorPosition();
+ cursorX, cursorY = cursorX / UIParent:GetScale(), cursorY / UIParent:GetScale();
+ local chatFrame = _G["ChatFrame"..self:GetID()];
+ if ( chatFrame ~= GENERAL_CHAT_DOCK.primary and GENERAL_CHAT_DOCK:IsMouseOver(10, -10, 0, 10) ) then
+ FCFDock_PlaceInsertHighlight(GENERAL_CHAT_DOCK, chatFrame, cursorX, cursorY);
+ else
+ FCFDock_HideInsertHighlight(GENERAL_CHAT_DOCK);
+ end
+
+ FCF_UpdateButtonSide(chatFrame);
+ if ( chatFrame == GENERAL_CHAT_DOCK.primary ) then
+ for _, frame in pairs(FCFDock_GetChatFrames(GENERAL_CHAT_DOCK)) do
+ FCF_SetButtonSide(frame, FCF_GetButtonSide(GENERAL_CHAT_DOCK.primary));
+ end
+ end
+
+ if ( not IsMouseButtonDown(self.dragButton) ) then
+ FCFTab_OnDragStop(self, self.dragButton);
+ self.dragButton = nil;
+ self:SetScript("OnUpdate", nil);
+ end
+
+ if ( BNToastFrame and BNToastFrame:IsShown() ) then
+ BNToastFrame_UpdateAnchor();
+ end
+end
+
+function FCFTab_OnDragStop(self, button)
+ FCF_StopDragging(_G["ChatFrame"..self:GetID()]);
+end
+
+DEFAULT_TAB_SELECTED_COLOR_TABLE = { r = 1, g = 0.5, b = 0.25 };
+
+function FCFTab_UpdateColors(self, selected)
+ if ( selected ) then
+ self.leftSelectedTexture:Show();
+ self.middleSelectedTexture:Show();
+ self.rightSelectedTexture:Show();
+ else
+ self.leftSelectedTexture:Hide();
+ self.middleSelectedTexture:Hide();
+ self.rightSelectedTexture:Hide();
+ end
+
+ local colorTable = self.selectedColorTable or DEFAULT_TAB_SELECTED_COLOR_TABLE;
+
+ if ( self.selectedColorTable ) then
+ self:GetFontString():SetTextColor(colorTable.r, colorTable.g, colorTable.b);
+ else
+ self:GetFontString():SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+
+ self.leftSelectedTexture:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ self.middleSelectedTexture:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ self.rightSelectedTexture:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+
+ self.leftHighlightTexture:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ self.middleHighlightTexture:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ self.rightHighlightTexture:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ self.glow:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+
+ if ( self.conversationIcon ) then
+ self.conversationIcon:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ end
+
+ local minimizedFrame = _G["ChatFrame"..self:GetID().."Minimized"];
+ if ( minimizedFrame ) then
+ minimizedFrame.selectedColorTable = self.selectedColorTable;
+ FCFMin_UpdateColors(minimizedFrame);
+ end
+end
+
+function FCFTab_UpdateAlpha(chatFrame)
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ if ( not chatFrame.isDocked or chatFrame == FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK) ) then
+ chatTab.mouseOverAlpha = CHAT_FRAME_TAB_SELECTED_MOUSEOVER_ALPHA;
+ chatTab.noMouseAlpha = CHAT_FRAME_TAB_SELECTED_NOMOUSE_ALPHA;
+ else
+ if ( chatTab.alerting ) then
+ chatTab.mouseOverAlpha = CHAT_FRAME_TAB_ALERTING_MOUSEOVER_ALPHA;
+ chatTab.noMouseAlpha = CHAT_FRAME_TAB_ALERTING_NOMOUSE_ALPHA;
+ else
+ chatTab.mouseOverAlpha = CHAT_FRAME_TAB_NORMAL_MOUSEOVER_ALPHA;
+ chatTab.noMouseAlpha = CHAT_FRAME_TAB_NORMAL_NOMOUSE_ALPHA;
+ end
+ end
+
+ -- If this is in the middle of fading, stop it, since we're about to set the alpha
+ UIFrameFadeRemoveFrame(chatTab);
+
+ if ( chatFrame.hasBeenFaded ) then
+ chatTab:SetAlpha(chatTab.mouseOverAlpha);
+ else
+ chatTab:SetAlpha(chatTab.noMouseAlpha);
+ end
+end
+
+function FCF_HideOnFadeFinished(frame)
+ frame:Hide();
+end
+
+function FCF_IsValidChatFrame(chatFrame)
+ -- Break out all the cases individually because the logic gets convoluted
+ if ( chatFrame == MOVING_CHATFRAME ) then
+ return nil;
+ end
+
+ if ( not chatFrame:IsShown() and not chatFrame.isDocked ) then
+ return nil;
+ end
+
+ return 1;
+end
+
+function FCF_UpdateButtonSide(chatFrame)
+ local leftDist = chatFrame:GetLeft();
+ local rightDist = GetScreenWidth() - chatFrame:GetRight();
+ local changed = nil;
+ if (( leftDist > 0 and leftDist <= rightDist ) or rightDist < 0 ) then
+ if ( chatFrame.buttonSide ~= "left" ) then
+ FCF_SetButtonSide(chatFrame, "left");
+ changed = 1;
+ end
+ else
+ if ( chatFrame.buttonSide ~= "right" or leftDist < 0 ) then
+ FCF_SetButtonSide(chatFrame, "right");
+ changed = 1;
+ end
+ end
+ return changed;
+end
+
+function FCF_SetButtonSide(chatFrame, buttonSide, forceUpdate)
+ if ( not forceUpdate and chatFrame.buttonSide == buttonSide ) then
+ return;
+ end
+ chatFrame.buttonFrame:ClearAllPoints();
+
+ local topY = 0;
+ if ( IsCombatLog(chatFrame) ) then
+ topY = topY + CombatLogQuickButtonFrame_Custom:GetHeight();
+ end
+
+ if ( buttonSide == "left" ) then
+ chatFrame.buttonFrame:SetPoint("TOPRIGHT", chatFrame, "TOPLEFT", -4, topY);
+ chatFrame.buttonFrame:SetPoint("BOTTOMRIGHT", chatFrame, "BOTTOMLEFT", -4, 0);
+ elseif ( buttonSide == "right" ) then
+ chatFrame.buttonFrame:SetPoint("TOPLEFT", chatFrame, "TOPRIGHT", 4, topY);
+ chatFrame.buttonFrame:SetPoint("BOTTOMLEFT", chatFrame, "BOTTOMRIGHT", 4, 0);
+ end
+ chatFrame.buttonSide = buttonSide;
+
+ if ( chatFrame == DEFAULT_CHAT_FRAME ) then
+ ChatFrameMenu_UpdateAnchorPoint();
+ end
+end
+
+function FCF_StartAlertFlash(chatFrame)
+ if ( chatFrame.minFrame ) then
+ UIFrameFlash(chatFrame.minFrame.glow, 1.0, 1.0, -1, false, 0, 0, "chat");
+
+ chatFrame.minFrame.alerting = true;
+ end
+
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ UIFrameFlash(chatTab.glow, 1.0, 1.0, -1, false, 0, 0, "chat");
+
+ chatTab.alerting = true;
+
+ FCFTab_UpdateAlpha(chatFrame);
+
+ FCFDockOverflowButton_UpdatePulseState(GENERAL_CHAT_DOCK.overflowButton);
+end
+
+function FCF_StopAlertFlash(chatFrame)
+ if ( chatFrame.minFrame ) then
+ UIFrameFlashStop(chatFrame.minFrame.glow);
+
+ chatFrame.minFrame.alerting = false;
+ end
+
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ UIFrameFlashStop(chatTab.glow);
+
+ chatTab.alerting = false;
+
+ FCFTab_UpdateAlpha(chatFrame);
+
+ FCFDockOverflowButton_UpdatePulseState(GENERAL_CHAT_DOCK.overflowButton);
+end
+
+function FCF_GetButtonSide(chatFrame)
+ return chatFrame.buttonSide;
+end
+
+function FCF_DockUpdate()
+ FCFDock_UpdateTabs(GENERAL_CHAT_DOCK, true);
+end
+--[[
+ local numDockedFrames = getn(DOCKED_CHAT_FRAMES);
+ local dockRegion, chatTab, previousDockedFrame;
+ local dockWidth = 0;
+ local previousDockRegion;
+ local name;
+ for index, value in pairs(DOCKED_CHAT_FRAMES) do
+ -- If not the initial chatframe then anchor the frame to the base chatframe
+ name = value:GetName();
+ if ( index ~= 1 ) then
+ value:ClearAllPoints();
+ value:SetPoint("TOPLEFT", DEFAULT_CHAT_FRAME, "TOPLEFT", 0, 0);
+ value:SetPoint("BOTTOMLEFT", DEFAULT_CHAT_FRAME, "BOTTOMLEFT", 0, 0);
+ value:SetPoint("BOTTOMRIGHT", DEFAULT_CHAT_FRAME, "BOTTOMRIGHT", 0, 0);
+ end
+
+ -- Select or deselect the frame
+ chatTab = _G[value:GetName().."Tab"];
+ -- chatTab.textWidth is the original width of the text name of the tab
+ -- We need to use this as an absolute measure of the text's width is altered when the chat dock gets too small
+ -- If the text is shrunken the original width is lost, unless we save it and use it in the following manner
+ -- This is a fix for Bug ID: 71180
+ PanelTemplates_TabResize(chatTab, 5, nil, nil, chatTab.textWidth);
+ if ( value == SELECTED_DOCK_FRAME ) then
+ value:Show();
+ if ( chatTab:IsShown() ) then
+ chatTab:SetAlpha(1.0);
+ end
+ else
+ value:Hide();
+ if ( chatTab:IsShown() ) then
+ chatTab:SetAlpha(0.5);
+ end
+ end
+
+ -- If there was a frame before this frame then anchor the tab
+
+ if ( previousDockedFrame ) then
+ chatTab:ClearAllPoints();
+ FCF_SetTabPosition(value, dockWidth);
+ _G[previousDockedFrame:GetName().."TabDockRegion"]:SetPoint("RIGHT", value:GetName().."Tab", "CENTER", 0, 0);
+ end
+
+ -- If this is the last frame in the dock then extend the dockRegion, otherwise shrink it to the default width
+ dockRegion = _G[chatTab:GetName().."DockRegion"];
+ dockRegion:SetPoint("LEFT", chatTab, "CENTER", 0 , 0);
+ if ( numDockedFrames == index ) then
+ dockRegion:SetPoint("RIGHT", "ChatFrame"..chatTab:GetID(), "RIGHT", 0, 0);
+ end
+ dockRegion:Hide();
+
+ -- Keep track of the width of the dock for anchoring purposes
+ dockWidth = dockWidth + chatTab:GetWidth();
+ previousDockedFrame = value;
+ end
+
+ -- Intelligently resize the chat tabs if dockwidth is greater than the window width
+ if ( dockWidth > DEFAULT_CHAT_FRAME:GetWidth() ) then
+ DOCK_COPY = {};
+ -- Copy the array
+ for index, value in pairs(DOCKED_CHAT_FRAMES) do
+ DOCK_COPY[index] = DOCKED_CHAT_FRAMES[index];
+ end
+ sort(DOCK_COPY, FCF_TabCompare);
+ local totalWidth = DEFAULT_CHAT_FRAME:GetWidth();
+ local avgWidth = totalWidth / numDockedFrames;
+ local chatTabWidth;
+ -- Resize the tabs
+ for index, value in pairs(DOCK_COPY) do
+ chatTab = _G[value:GetName().."Tab"];
+ chatTabWidth = chatTab:GetWidth();
+ if ( chatTabWidth < avgWidth ) then
+ -- If tab is smaller than the average then remove it from the list and recalc the average
+ totalWidth = totalWidth - chatTabWidth;
+ numDockedFrames = numDockedFrames - 1;
+ avgWidth = totalWidth / numDockedFrames;
+ else
+ -- Set the tab to the average width
+ PanelTemplates_TabResize(chatTab, 0, avgWidth);
+ end
+ end
+
+ -- Reanchor the tabs
+ previousDockedFrame = nil;
+ dockWidth = 0;
+ for index, value in pairs(DOCKED_CHAT_FRAMES) do
+ -- If there was a frame before this frame then anchor the tab
+ if ( previousDockedFrame ) then
+ FCF_SetTabPosition(value, dockWidth);
+ end
+ chatTab = _G[value:GetName().."Tab"];
+ dockWidth = dockWidth + chatTab:GetWidth();
+ previousDockedFrame = value;
+ end
+ end
+end]]
+
+function FCF_TabCompare(chatFrame1, chatFrame2)
+ local tab1 = _G[chatFrame1:GetName().."Tab"];
+ local tab2 = _G[chatFrame2:GetName().."Tab"];
+ return tab1:GetWidth() < tab2:GetWidth();
+end
+
+function FCF_DockFrame(frame, index, selected)
+ -- Return if already docked
+ if ( frame.isDocked ) then
+ return;
+ end
+
+ FCFDock_AddChatFrame(GENERAL_CHAT_DOCK, frame, index);
+
+ -- Save docked state
+ FCF_SaveDock();
+ if ( selected ) then
+ --FCF_SelectDockFrame(frame);
+ FCFDock_SelectWindow(GENERAL_CHAT_DOCK, frame);
+ end
+
+ -- Set scroll button side
+ if ( frame == DEFAULT_CHAT_FRAME ) then
+ FCF_UpdateButtonSide(frame);
+ else
+ FCF_SetButtonSide(frame, FCF_GetButtonSide(DEFAULT_CHAT_FRAME));
+ end
+
+ -- Lock frame
+ FCF_SetLocked(frame, 1);
+
+ --If the frame that is being docked and the frame it is docking to have different interactable settings, make them both interactable.
+ if ( frame.isUninteractable ~= DEFAULT_CHAT_FRAME.isUninteractable ) then
+ FCF_SetExpandedUninteractable(frame, false)
+ end
+
+ if ( frame == COMBATLOG ) then
+ Blizzard_CombatLog_Update_QuickButtons();
+ end
+
+ FCF_DockUpdate();
+end
+
+function FCF_UnDockFrame(frame)
+ if ( frame == DEFAULT_CHAT_FRAME or not frame.isDocked ) then
+ return;
+ end
+ -- Undock frame regardless of whether its docked or not
+ SetChatWindowDocked(frame:GetID(), nil);
+ FCFDock_RemoveChatFrame(GENERAL_CHAT_DOCK, frame);
+
+ FCF_SaveDock();
+
+ -- Set tab to full alpha
+ local chatTab = _G[frame:GetName().."Tab"];
+ chatTab:SetAlpha(1.0);
+end
+
+function FCF_SelectDockFrame(frame)
+ SELECTED_DOCK_FRAME = frame;
+ -- Stop tab flashing
+ local tabFlash;
+ if ( frame ) then
+ tabFlash = _G["ChatFrame"..frame:GetID().."TabFlash"];
+ end
+
+ if ( tabFlash ) then
+ UIFrameFlashRemoveFrame(tabFlash);
+ tabFlash:Hide();
+ end
+ FCFDock_SelectWindow(GENERAL_CHAT_DOCK, frame);
+ FCF_DockUpdate();
+end
+
+function FCF_Tab_OnClick(self, button)
+ local chatFrame = _G["ChatFrame"..self:GetID()];
+ -- If Rightclick bring up the options menu
+ if ( button == "RightButton" ) then
+ chatFrame:StopMovingOrSizing();
+ CURRENT_CHAT_FRAME_ID = self:GetID();
+ ToggleDropDownMenu(1, nil, _G[self:GetName().."DropDown"], self:GetName(), 0, 0);
+ return;
+ end
+
+ -- Close all dropdowns
+ CloseDropDownMenus();
+
+ -- If frame is docked assume that a click is to select a chat window, not drag it
+ SELECTED_CHAT_FRAME = chatFrame;
+ if ( chatFrame.isDocked and FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK) ~= chatFrame ) then
+ FCF_SelectDockFrame(chatFrame);
+ FCF_FadeInChatFrame(chatFrame);
+ return;
+ else
+ if ( GetCVar("chatStyle") ~= "classic" ) then
+ ChatEdit_SetLastActiveWindow(chatFrame.editBox);
+ end
+ FCF_FadeInChatFrame(chatFrame);
+ end
+
+end
+
+function FCF_SetTabPosition(chatFrame, x)
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ chatTab:ClearAllPoints();
+ chatTab:SetPoint("BOTTOMLEFT", chatFrame:GetName().."Background", "TOPLEFT", x+2, 0);
+end
+
+function FCF_SaveDock()
+ for index, value in pairs(FCFDock_GetChatFrames(GENERAL_CHAT_DOCK)) do
+ SetChatWindowDocked(value:GetID(), index);
+ end
+end
+
+function FCF_LeaveConversation(frame, fallback)
+ if ( fallback ) then
+ frame=fallback
+ end
+ if ( not frame ) then
+ frame = FCF_GetCurrentChatFrame();
+ end
+
+ assert(frame.chatType == "BN_CONVERSATION");
+ BNLeaveConversation(tonumber(frame.chatTarget));
+
+ FCF_Close(frame);
+end
+
+function FCF_PopInWindow(frame, fallback)
+ if ( fallback ) then
+ frame=fallback
+ end
+ if ( not frame ) then
+ frame = FCF_GetCurrentChatFrame();
+ end
+ if ( frame == DEFAULT_CHAT_FRAME ) then
+ return;
+ end
+
+ --Restore any chats this frame had to the DEFAULT_CHAT_FRAME
+ FCF_RestoreChatsToFrame(DEFAULT_CHAT_FRAME, frame);
+
+ FCF_Close(frame);
+end
+
+function FCF_Close(frame, fallback)
+ if ( fallback ) then
+ frame=fallback
+ end
+ if ( not frame ) then
+ frame = FCF_GetCurrentChatFrame();
+ end
+ if ( frame == DEFAULT_CHAT_FRAME ) then
+ return;
+ end
+ FCF_UnDockFrame(frame);
+ HideUIPanel(frame);
+ _G[frame:GetName().."Tab"]:Hide();
+ FCF_FlagMinimizedPositionReset(frame);
+ if ( frame.minFrame and frame.minFrame:IsShown() ) then
+ frame.minFrame:Hide();
+ end
+ if ( frame.isTemporary ) then
+ FCFManager_UnregisterDedicatedFrame(frame, frame.chatType, frame.chatTarget);
+ frame.isRegistered = false;
+ frame.inUse = false;
+ end
+ if ( PENDING_BN_WHISPER_TO_CONVERSATION_FRAME == frame ) then
+ PENDING_BN_WHISPER_TO_CONVERSATION_FRAME = nil;
+ end
+
+ --Reset what this window receives.
+ ChatFrame_RemoveAllMessageGroups(frame);
+ ChatFrame_RemoveAllChannels(frame);
+ ChatFrame_ReceiveAllPrivateMessages(frame);
+ ChatFrame_ReceiveAllBNConversations(frame);
+end
+
+function FCF_RestoreChatsToFrame(targetFrame, sourceFrame)
+ --Restore chat types
+ for _, messageType in pairs(sourceFrame.messageTypeList) do
+ ChatFrame_AddMessageGroup(targetFrame, messageType);
+ end
+
+ --Restore channels
+ for _, channel in pairs(sourceFrame.channelList) do
+ ChatFrame_AddChannel(targetFrame, channel);
+ end
+
+ --Restore whispers
+ if ( sourceFrame.privateMessageList ) then
+ for name, value in pairs(sourceFrame.privateMessageList) do
+ if ( value ) then
+ ChatFrame_RemoveExcludePrivateMessageTarget(targetFrame, name);
+ end
+ end
+ end
+
+ if ( sourceFrame.bnConversationList ) then
+ for name, value in pairs(sourceFrame.bnConversationList) do
+ if ( value ) then
+ ChatFrame_RemoveExcludeBNConversationTarget(targetFrame, name);
+ end
+ end
+ end
+end
+
+-- Tab flashing functions
+function FCF_FlashTab(self)
+ local tabFlash = _G[self:GetName().."TabFlash"];
+ if ( not self.isDocked or (self == SELECTED_DOCK_FRAME) or UIFrameIsFlashing(tabFlash) ) then
+ return;
+ end
+ tabFlash:Show();
+ UIFrameFlash(tabFlash, 0.25, 0.25, 60, nil, 0.5, 0.5);
+end
+
+-- Function for repositioning the chat dock depending on if there's a shapeshift bar/stance bar, etc...
+function FCF_UpdateDockPosition()
+ if ( DEFAULT_CHAT_FRAME:IsUserPlaced() ) then
+ return;
+ end
+
+ local chatOffset = 85;
+ if ( GetNumShapeshiftForms() > 0 or HasPetUI() or PetHasActionBar() ) then
+ if ( MultiBarBottomLeft:IsShown() ) then
+ chatOffset = chatOffset + 55;
+ else
+ chatOffset = chatOffset + 15;
+ end
+ elseif ( MultiBarBottomLeft:IsShown() ) then
+ chatOffset = chatOffset + 15;
+ end
+ DEFAULT_CHAT_FRAME:SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMLEFT", 32, chatOffset);
+ FCF_DockUpdate();
+end
+
+function FCF_Set_NormalChat()
+ ChatFrame2:StartMoving();
+ ChatFrame2:StopMovingOrSizing();
+ FCF_SetLocked(ChatFrame2, nil);
+ -- to fix a bug with the combat log not repositioning its tab properly when coming out of
+ -- simple chat, we need to update now
+ FCF_DockUpdate();
+end
+
+-- Functions to set and remove the chat window show delay on mouseover
+function SetChatMouseOverDelay(noDelay)
+ if ( noDelay == "1" ) then
+ CHAT_TAB_SHOW_DELAY = 0;
+ CHAT_FRAME_FADE_TIME = 0;
+ else
+ CHAT_TAB_SHOW_DELAY = 0.2;
+ CHAT_FRAME_FADE_TIME = 0.15;
+ end
+end
+
+-- Reset the chat windows to default
+function FCF_ResetChatWindows()
+ ChatFrame1:ClearAllPoints();
+ ChatFrame1:SetPoint("BOTTOMLEFT", "UIParent", "BOTTOMLEFT", 32, 95);
+ ChatFrame1:SetWidth(430);
+ ChatFrame1:SetHeight(120);
+ ChatFrame1.isInitialized = 0;
+ FCF_SetButtonSide(ChatFrame1, "left")
+ FCF_SetChatWindowFontSize(nil, ChatFrame1, 14);
+ FCF_SetWindowName(ChatFrame1, GENERAL);
+ FCF_SetWindowColor(ChatFrame1, DEFAULT_CHATFRAME_COLOR.r, DEFAULT_CHATFRAME_COLOR.g, DEFAULT_CHATFRAME_COLOR.b);
+ FCF_SetWindowAlpha(ChatFrame1, DEFAULT_CHATFRAME_ALPHA);
+ FCF_UnDockFrame(ChatFrame1);
+ ChatFrame_RemoveAllMessageGroups(ChatFrame1);
+ ChatFrame_RemoveAllChannels(ChatFrame1);
+ ChatFrame_ReceiveAllPrivateMessages(ChatFrame1);
+ ChatFrame_ReceiveAllBNConversations(ChatFrame1);
+ SELECTED_CHAT_FRAME = ChatFrame1;
+ DEFAULT_CHAT_FRAME.chatframe = DEFAULT_CHAT_FRAME;
+
+ FCF_SetChatWindowFontSize(nil, ChatFrame2, 14);
+ FCF_SetWindowName(ChatFrame2, COMBAT_LOG);
+ FCF_SetWindowColor(ChatFrame2, DEFAULT_CHATFRAME_COLOR.r, DEFAULT_CHATFRAME_COLOR.g, DEFAULT_CHATFRAME_COLOR.b);
+ FCF_SetWindowAlpha(ChatFrame2, DEFAULT_CHATFRAME_ALPHA);
+ ChatFrame_RemoveAllMessageGroups(ChatFrame2);
+ ChatFrame_RemoveAllChannels(ChatFrame2);
+ ChatFrame_ReceiveAllPrivateMessages(ChatFrame2);
+ ChatFrame_ReceiveAllBNConversations(ChatFrame2);
+ FCF_UnDockFrame(ChatFrame2);
+ ChatFrame2.isInitialized = 0;
+ for _, chatFrameName in ipairs(CHAT_FRAMES) do
+ if ( chatFrameName ~= "ChatFrame1" ) then
+ local chatFrame = _G[chatFrameName];
+ if ( chatFrame.isTemporary and chatFrame.chatType == "BN_CONVERSATION" and
+ BNGetConversationInfo(tonumber(chatFrame.chatTarget)) and GetCVar("conversationMode") == "popout" ) then
+ --We're still in this conversation, so we just want to reset the position, not remove the frame.
+ FCF_DockFrame(chatFrame, 3); --Put it after General and Combat Log
+ else
+ chatFrame.isInitialized = 0;
+ FCF_SetTabPosition(chatFrame, 0);
+ FCF_Close(chatFrame);
+ FCF_UnDockFrame(chatFrame);
+ FCF_SetWindowName(chatFrame, "");
+ ChatFrame_RemoveAllMessageGroups(chatFrame);
+ ChatFrame_RemoveAllChannels(chatFrame);
+ ChatFrame_ReceiveAllPrivateMessages(chatFrame);
+ ChatFrame_ReceiveAllBNConversations(chatFrame);
+ end
+ FCF_SetChatWindowFontSize(nil, chatFrame, 14);
+ FCF_SetWindowColor(chatFrame, DEFAULT_CHATFRAME_COLOR.r, DEFAULT_CHATFRAME_COLOR.g, DEFAULT_CHATFRAME_COLOR.b);
+ FCF_SetWindowAlpha(chatFrame, DEFAULT_CHATFRAME_ALPHA);
+ end
+ end
+ ChatFrame1.init = 0;
+ FCF_DockFrame(ChatFrame1, 1, true);
+ FCF_DockFrame(ChatFrame2, 2);
+
+ -- resets to hard coded defaults
+ ResetChatWindows();
+ UIParent_ManageFramePositions();
+ FCFDock_SelectWindow(GENERAL_CHAT_DOCK, ChatFrame1);
+end
+
+function IsCombatLog(frame)
+ if ( frame == ChatFrame2 and IsAddOnLoaded("Blizzard_CombatLog") ) then
+ return true;
+ else
+ return false;
+ end
+end
+
+function FCFClickAnywhereButton_OnLoad(self)
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() - 1);
+ self:RegisterEvent("VARIABLES_LOADED");
+ self:RegisterEvent("CVAR_UPDATE");
+ self:RegisterForClicks("LeftButtonDown", "RightButtonDown");
+ FCFClickAnywhereButton_UpdateState(self);
+end
+
+function FCFClickAnywhereButton_OnEvent(self, event, ...)
+ local arg1 = ...;
+ if ( event == "VARIABLES_LOADED" or
+ (event == "CVAR_UPDATE" and (arg1 == "chatStyle" or arg1 == "CHAT_WHOLE_WINDOW_CLICKABLE")) ) then
+ FCFClickAnywhereButton_UpdateState(self);
+ end
+end
+
+function FCFClickAnywhereButton_UpdateState(self)
+ if ( GetCVar("chatStyle") == "im" and GetCVarBool("wholeChatWindowClickable") and
+ LAST_ACTIVE_CHAT_EDIT_BOX ~= self:GetParent().editBox ) then
+ self:Show();
+ else
+ self:Hide();
+ end
+end
+
+function FCF_MinimizeFrame(chatFrame, side)
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+
+ local createdFrame = false;
+ if ( not chatFrame.minFrame ) then
+ chatFrame.minFrame = FCF_CreateMinimizedFrame(chatFrame);
+ end
+
+ if ( chatFrame.minFrame.resetPosition ) then
+ chatFrame.minFrame:ClearAllPoints();
+ chatFrame.minFrame:SetPoint("TOP"..side, chatFrame, "TOP"..side, 0, 0);
+ chatFrame.minFrame.resetPosition = false;
+ end
+
+ chatFrame.minimized = true;
+
+ chatFrame.minFrame:Show();
+ chatFrame:Hide();
+ chatTab:Hide();
+end
+
+function FCF_MaximizeFrame(chatFrame)
+ local minFrame = chatFrame.minFrame;
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+
+ chatFrame.minimized = false;
+
+ minFrame:UnlockHighlight();
+ minFrame:Hide();
+ chatFrame:Show();
+ chatTab:Show();
+
+ FCF_FadeInChatFrame(chatFrame);
+end
+
+function FCF_CreateMinimizedFrame(chatFrame)
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+
+ local minFrame = CreateFrame("Button", chatFrame:GetName().."Minimized", UIParent, "FloatingChatFrameMinimizedTemplate");
+ minFrame.maxFrame = chatFrame;
+
+ minFrame:SetText(chatFrame.name);
+
+ --Copy the colors from the minimized frame.
+ minFrame.selectedColorTable = chatTab.selectedColorTable;
+ FCFMin_UpdateColors(minFrame);
+
+ if ( not chatFrame.isTemporary ) then
+ minFrame.conversationIcon:Hide();
+ else
+ local conversationIcon;
+ if ( chatFrame.chatType == "WHISPER" or chatFrame.chatType == "BN_WHISPER" ) then
+ conversationIcon = "Interface\\ChatFrame\\UI-ChatWhisperIcon";
+ else
+ conversationIcon = "Interface\\ChatFrame\\UI-ChatConversationIcon";
+ end
+
+ minFrame.conversationIcon:SetTexture(conversationIcon);
+ end
+
+ if (chatFrame.isTemporary) then
+ minFrame.Text:SetJustifyH("LEFT");
+ minFrame.Text:SetPoint("LEFT", minFrame, "LEFT", 30, 0);
+ end
+
+ --Make sure the position is reset.
+ minFrame.resetPosition = true;
+
+ return minFrame;
+end
+
+function FCFMin_UpdateColors(minFrame)
+ --Color it.
+ local colorTable = minFrame.selectedColorTable or DEFAULT_TAB_SELECTED_COLOR_TABLE;
+
+ if ( minFrame.selectedColorTable ) then
+ minFrame:GetFontString():SetTextColor(colorTable.r, colorTable.g, colorTable.b);
+ else
+ minFrame:GetFontString():SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+
+ minFrame.leftHighlightTexture:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ minFrame.middleHighlightTexture:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ minFrame.rightHighlightTexture:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ minFrame.glow:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+
+ minFrame.conversationIcon:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+end
+
+--This function just makes the position be reset the next time the minimize frame is shown.
+function FCF_FlagMinimizedPositionReset(chatFrame)
+ if ( chatFrame.minFrame ) then
+ chatFrame.minFrame.resetPosition = true;
+ end
+end
+
+------Docking related functions for the new docking system
+--[[
+Since we've been discussing allowing multiple docks, this code is designed to be mostly-OO. Please try not to use global variables.
+(Theoretically, all of these functions may be put in a metatable to allow, e.g., "Dock:SelectWindow(chatWindow)".
+To keep with this, please ensure that "dock" is the first argument of every function.)
+]]
+
+function FCFDock_OnLoad(dock)
+ dock.DOCKED_CHAT_FRAMES = {};
+ dock.isDirty = true; --You dirty, dirty frame
+end
+
+function FCFDock_OnEvent(dock, event, ...)
+ if ( event == "UPDATE_CHAT_WINDOWS" ) then
+ --FCFDock_ForceTabSort(dock);
+ --FCFDock_ForceReanchoring(dock);
+ end
+end
+
+function FCFDock_GetChatFrames(dock)
+ return dock.DOCKED_CHAT_FRAMES;
+end
+
+function FCFDock_SetPrimary(dock, chatFrame)
+ dock.primary = chatFrame;
+ dock:SetPoint("BOTTOMLEFT", chatFrame, "TOPLEFT", 0, 6);
+ dock:SetPoint("BOTTOMRIGHT", chatFrame, "TOPRIGHT", 0, 6);
+
+ chatFrame:SetScript("OnSizeChanged", function(self) FCFDock_OnPrimarySizeChanged(dock) end);
+
+ if ( not FCFDock_GetSelectedWindow(dock) ) then
+ FCFDock_SelectWindow(dock, chatFrame);
+ end
+
+ FCFDock_ForceReanchoring(dock);
+
+ FCFDock_AddChatFrame(dock, chatFrame, 1);
+end
+
+function FCFDock_OnPrimarySizeChanged(dock)
+ dock.isDirty = true;
+
+ --We have to save off the current leftmost-tab before we resize the tabs.
+ dock.leftTab = FCFDockScrollFrame_GetLeftmostTab(dock.scrollFrame);
+
+ --We have to do it on the next frame to deal with issues caused by resizing the WoW client (frame positions may not be valid)
+ dock:SetScript("OnUpdate", FCFDock_OnUpdate);
+end
+
+function FCFDock_OnUpdate(self)
+ --These may fail if we're resizing the WoW client
+ if ( FCFDock_UpdateTabs(self) and FCFDockScrollFrame_JumpToTab(self.scrollFrame, self.leftTab) ) then
+ self.leftTab = nil;
+ self:SetScript("OnUpdate", nil);
+ end
+end
+
+function FCFDock_ForceReanchoring(dock)
+ for index, chatFrame in pairs(dock.DOCKED_CHAT_FRAMES) do
+ if ( dock.primary ~= chatFrame ) then
+ chatFrame:ClearAllPoints();
+ chatFrame:SetAllPoints(dock.primary);
+ end
+ end
+end
+
+function FCFDock_AddChatFrame(dock, chatFrame, position)
+ if ( not dock.primary ) then
+ error("Need a primary window before another can be added.");
+ end
+
+ if ( FCFDock_HasDockedChatFrame(dock, chatFrame) ) then
+ return; --We're already docked...
+ end
+
+ dock.isDirty = true;
+ chatFrame.isDocked = 1;
+
+ if ( position and position <= #dock.DOCKED_CHAT_FRAMES + 1 ) then
+ assert(position ~=1 or chatFrame == dock.primary);
+ tinsert(dock.DOCKED_CHAT_FRAMES, position, chatFrame);
+ else
+ tinsert(dock.DOCKED_CHAT_FRAMES, chatFrame);
+ end
+
+ FCFDock_HideInsertHighlight(dock);
+
+ if ( dock.primary ~= chatFrame ) then
+ chatFrame:ClearAllPoints();
+ chatFrame:SetAllPoints(dock.primary);
+ chatFrame:SetMovable(false);
+ chatFrame:SetResizable(false);
+ end
+
+ if ( chatFrame.conversationButton ) then
+ BNConversationButton_UpdateAttachmentPoint(chatFrame.conversationButton);
+ end
+
+ chatFrame.buttonFrame.minimizeButton:Hide();
+ chatFrame.buttonFrame:SetAlpha(1.0);
+
+ dock.overflowButton.list:Hide();
+ FCFDock_UpdateTabs(dock);
+end
+
+function FCFDock_RemoveChatFrame(dock, chatFrame)
+ assert(chatFrame ~= dock.primary or #dock.DOCKED_CHAT_FRAMES == 1);
+ dock.isDirty = true;
+ tDeleteItem(dock.DOCKED_CHAT_FRAMES, chatFrame);
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ chatFrame.isDocked = nil;
+ chatTab:SetParent(UIParent);
+ chatTab:SetFrameStrata("LOW");
+ chatFrame:SetMovable(true);
+ chatFrame:SetResizable(true);
+ FCFTab_UpdateColors(chatTab, true);
+ PanelTemplates_TabResize(chatTab, chatTab.sizePadding or 0, nil, nil, chatTab.textWidth);
+ if ( FCFDock_GetSelectedWindow(dock) == chatFrame ) then
+ FCFDock_SelectWindow(dock, dock.DOCKED_CHAT_FRAMES[1]);
+ end
+
+ if ( chatFrame.conversationButton ) then
+ BNConversationButton_UpdateAttachmentPoint(chatFrame.conversationButton);
+ end
+
+ chatFrame.buttonFrame.minimizeButton:Show();
+ dock.overflowButton.list:Hide();
+ chatFrame:Show();
+ FCFDock_UpdateTabs(dock);
+end
+
+function FCFDock_HasDockedChatFrame(dock, chatFrame)
+ return tContains(dock.DOCKED_CHAT_FRAMES, chatFrame);
+end
+
+function FCFDock_SelectWindow(dock, chatFrame)
+ assert(chatFrame)
+ dock.isDirty = true;
+ dock.selected = chatFrame;
+ dock.overflowButton.list:Hide();
+ FCFDock_UpdateTabs(dock);
+
+ if ( ChatFrameMenuButton ) then
+ if ( chatFrame.conversationButton and chatFrame.conversationButton:IsShown() ) then
+ ChatFrameMenuButton:Hide();
+ else
+ ChatFrameMenuButton:Show();
+ end
+ end
+end
+
+function FCFDock_GetSelectedWindow(dock)
+ return dock.selected;
+end
+
+function FCFDock_UpdateTabs(dock, forceUpdate)
+ if ( not dock.isDirty and not forceUpdate ) then --No changes have been made since the last update.
+ return;
+ end
+
+ local scrollChild = dock.scrollFrame:GetScrollChild();
+ local lastDockedStaticTab = nil;
+ local lastDockedDynamicTab = nil;
+
+ local numDynFrames = 0; --Number of dynamicly sized frames.
+ local selectedDynIndex = nil;
+
+ for index, chatFrame in ipairs(dock.DOCKED_CHAT_FRAMES) do
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ if ( chatFrame == FCFDock_GetSelectedWindow(dock) ) then
+ chatFrame:Show();
+ else
+ chatFrame:Hide();
+ end
+ FCFTab_UpdateAlpha(chatFrame);
+ chatTab:ClearAllPoints();
+ chatTab:Show();
+ FCFTab_UpdateColors(chatTab, chatFrame == FCFDock_GetSelectedWindow(dock));
+
+ if ( chatFrame.isStaticDocked ) then
+ chatTab:SetParent(dock);
+ PanelTemplates_TabResize(chatTab, chatTab.sizePadding or 0);
+ if ( lastDockedStaticTab ) then
+ chatTab:SetPoint("LEFT", lastDockedStaticTab, "RIGHT", 0, 0);
+ else
+ chatTab:SetPoint("LEFT", dock, "LEFT", 0, 0);
+ end
+ lastDockedStaticTab = chatTab;
+ else
+ chatTab:SetParent(scrollChild);
+ numDynFrames = numDynFrames + 1;
+
+ if ( FCFDock_GetSelectedWindow(dock) == chatFrame ) then
+ selectedDynIndex = numDynFrames;
+ end
+
+ if ( lastDockedDynamicTab ) then
+ chatTab:SetPoint("LEFT", lastDockedDynamicTab, "RIGHT", 0, 0);
+ else
+ chatTab:SetPoint("LEFT", scrollChild, "LEFT", 0, 0);
+ end
+ lastDockedDynamicTab = chatTab;
+ end
+ end
+
+ local dynTabSize, hasOverflow = FCFDock_CalculateTabSize(dock, numDynFrames);
+
+ for index, chatFrame in ipairs(dock.DOCKED_CHAT_FRAMES) do
+ if ( not chatFrame.isStaticDocked ) then
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ PanelTemplates_TabResize(chatTab, chatTab.sizePadding or 0, dynTabSize);
+ end
+ end
+
+ dock.scrollFrame:SetPoint("LEFT", lastDockedStaticTab, "RIGHT", 0, 0);
+ if ( hasOverflow ) then
+ dock.overflowButton:Show();
+ dock.scrollFrame:SetPoint("BOTTOMRIGHT", dock.overflowButton, "BOTTOMLEFT", 0, 0);
+ else
+ dock.overflowButton:Hide();
+ dock.scrollFrame:SetPoint("BOTTOMRIGHT", dock, "BOTTOMRIGHT", 0, -5);
+ end
+
+ --Cache some of this data on the scroll frame for animating to the selected tab.
+ dock.scrollFrame.dynTabSize = dynTabSize;
+ dock.scrollFrame.numDynFrames = numDynFrames;
+ dock.scrollFrame.selectedDynIndex = selectedDynIndex;
+
+ dock.isDirty = false;
+
+ return FCFDock_ScrollToSelectedTab(dock);
+end
+
+--Returns dynTabSize, hasOverflow
+function FCFDock_CalculateTabSize(dock, numDynFrames)
+ local MIN_SIZE, MAX_SIZE = 60, 90;
+ local scrollSize = dock.scrollFrame:GetWidth() + (dock.overflowButton:IsShown() and dock.overflowButton.width or 0); --We want the total width assuming no overflow button.
+
+ --First, see if we can fit all the tabs at the maximum size
+ if ( numDynFrames * MAX_SIZE < scrollSize ) then
+ return MAX_SIZE, false;
+ end
+
+ if ( scrollSize / MIN_SIZE < numDynFrames ) then
+ --Not everything fits, so we'll need room for the overflow button.
+ scrollSize = scrollSize - dock.overflowButton.width;
+ end
+
+ --Figure out how many tabs we're going to be able to fit at the minimum size
+ local numWholeTabs = min(floor(scrollSize / MIN_SIZE), numDynFrames)
+
+ if ( numWholeTabs == 0 ) then
+ return scrollSize, true;
+ end
+
+ --How big each tab should be.
+ local tabSize = scrollSize / numWholeTabs;
+
+ return tabSize, (numDynFrames > numWholeTabs);
+end
+
+function FCFDock_ScrollToSelectedTab(dock)
+ if ( FCFDockScrollFrame_GetScrollDistanceNeeded(dock.scrollFrame, dock.scrollFrame.selectedDynIndex) ~= 0) then
+ dock.scrollFrame:SetScript("OnUpdate", FCFDockScrollFrame_OnUpdate);
+ return true;
+ else
+ return FCFDockScrollFrame_JumpToTab(dock.scrollFrame, FCFDockScrollFrame_GetLeftmostTab(dock.scrollFrame)); --Make sure we're exactly aligned with the tab.
+ end
+end
+
+---These functions deal with the scroll frame handling dynamic tabs.
+function FCFDockScrollFrame_OnUpdate(self, elapsed)
+ local MOVEMENT_SPEED = 10;
+
+ local totalDistanceNeeded = FCFDockScrollFrame_GetScrollDistanceNeeded(self, self.selectedDynIndex);
+ if ( abs(totalDistanceNeeded) < 1.0 ) then --Delta chosen through experimentation
+ self:SetScript("OnUpdate", nil);
+ FCFDockScrollFrame_JumpToTab(self, FCFDockScrollFrame_GetLeftmostTab(self)); --Make sure we're exactly aligned with the tab.
+ return;
+ end
+
+ local currentPosition = self:GetHorizontalScroll();
+
+ local distanceNoCap = totalDistanceNeeded * MOVEMENT_SPEED * elapsed;
+ local distanceToMove = (totalDistanceNeeded > 0) and min(totalDistanceNeeded, distanceNoCap) or max(totalDistanceNeeded, distanceNoCap);
+
+ self:SetHorizontalScroll(max(currentPosition + distanceToMove, 0));
+end
+
+function FCFDock_GetInsertIndex(dock, chatFrame, mouseX, mouseY)
+ if ( chatFrame.isStaticDocked ) then
+ local maxPosition = 0;
+ for index, value in ipairs(dock.DOCKED_CHAT_FRAMES) do
+ if ( value.isStaticDocked ) then
+ local tab = _G[value:GetName().."Tab"];
+ if ( mouseX < (tab:GetLeft() + tab:GetRight()) / 2 and --Find the first tab we're on the left of. (Being on top of the tab, but left of the center counts)
+ tab:GetID() ~= dock.primary:GetID()) then --We never count as being to the left of the primary tab.
+ return index;
+ end
+ maxPosition = index;
+ end
+ end
+ --We aren't to the left of anything, so we're going into the far-right position.
+ return maxPosition + 1;
+ else
+ --Find the dynamic insertion spot
+ local maxPosition = 9^9;
+ local leftTab = FCFDockScrollFrame_GetLeftmostTab(dock.scrollFrame);
+ local numDynTabsDisplayed = dock.scrollFrame:GetWidth() / dock.scrollFrame.dynTabSize;
+
+ local currTabNum = 0;
+ for index, value in ipairs(dock.DOCKED_CHAT_FRAMES) do
+ if ( not value.isStaticDocked ) then
+ currTabNum = currTabNum + 1;
+ if ( currTabNum >= leftTab and currTabNum < leftTab + numDynTabsDisplayed ) then
+ local tab = _G[value:GetName().."Tab"];
+ if ( mouseX < (tab:GetLeft() + tab:GetRight())/2 ) then
+ return index;
+ end
+ maxPosition = index;
+ end
+ end
+ end
+ return min(#dock.DOCKED_CHAT_FRAMES + 1, maxPosition + 1);
+ end
+end
+
+function FCFDock_PlaceInsertHighlight(dock, chatFrame, mouseX, mouseY)
+ local insert = FCFDock_GetInsertIndex(dock, chatFrame, mouseX, mouseY);
+
+ local attachFrame = dock.primary;
+
+ local leftDynTab = FCFDockScrollFrame_GetLeftmostTab(dock.scrollFrame);
+ local numDynTabsDisplayed = dock.scrollFrame:GetWidth() / dock.scrollFrame.dynTabSize;
+
+ local dynamicIndex = 0;
+ for index, value in ipairs(dock.DOCKED_CHAT_FRAMES) do
+ if ( index < insert ) then
+ if ( value.isStaticDocked ) then
+ attachFrame = value;
+ else
+ dynamicIndex = dynamicIndex + 1;
+ if ( dynamicIndex >= leftDynTab and dynamicIndex < leftDynTab + numDynTabsDisplayed ) then
+ attachFrame = value;
+ end
+ end
+ end
+ end
+
+ dock.insertHighlight:ClearAllPoints();
+ dock.insertHighlight:SetPoint("BOTTOMLEFT", _G[attachFrame:GetName().."Tab"], "BOTTOMRIGHT", -15, -4);
+ dock.insertHighlight:Show();
+end
+
+function FCFDock_HideInsertHighlight(dock)
+ dock.insertHighlight:Hide();
+end
+
+function FCFDock_SetDirty(dock)
+ dock.isDirty = true;
+end
+
+function FCFDockScrollFrame_GetScrollDistanceNeeded(scrollFrame, dynFrameIndex)
+
+ local firstIndex = (scrollFrame:GetHorizontalScroll() / scrollFrame.dynTabSize) + 1;
+
+ local numDisplayedFrames = scrollFrame:GetWidth() / scrollFrame.dynTabSize;
+ local lastIndex = firstIndex + numDisplayedFrames - 1;
+
+ if ( dynFrameIndex and dynFrameIndex < firstIndex ) then --Need to scroll left to get to the selected button
+ return (dynFrameIndex - firstIndex) * scrollFrame.dynTabSize;
+ elseif ( dynFrameIndex and dynFrameIndex > lastIndex ) then --Need to scroll right to get to the selected button
+ return (dynFrameIndex - lastIndex) * scrollFrame.dynTabSize;
+ elseif ( firstIndex > 1 and scrollFrame.numDynFrames < lastIndex ) then --Need to scroll left to fill in empty space at the end.
+ return (scrollFrame.numDynFrames - lastIndex) * scrollFrame.dynTabSize;
+ else
+ return 0;
+ end
+end
+
+function FCFDockScrollFrame_GetLeftmostTab(scrollFrame)
+ return floor((scrollFrame:GetHorizontalScroll() / scrollFrame.dynTabSize) + 0.5) + 1;
+end
+
+function FCFDockScrollFrame_JumpToTab(scrollFrame, leftTab)
+ --If we have a selected frame, make sure it's still in view.
+ local numTabsDisplayed = scrollFrame:GetWidth() / scrollFrame.dynTabSize;
+
+ if ( scrollFrame.selectedDynIndex ) then
+ if ( scrollFrame.selectedDynIndex >= leftTab + numTabsDisplayed ) then
+ leftTab = scrollFrame.selectedDynIndex - numTabsDisplayed + 1;
+ elseif ( scrollFrame.selectedDynIndex < leftTab ) then
+ leftTab = scrollFrame.selectedDynIndex;
+ end
+ end
+
+ --Make sure, if we can show more frames, we do.
+ leftTab = min(leftTab, scrollFrame.numDynFrames - numTabsDisplayed + 1);
+
+ --And make sure we never go to the left of 1 (for example, if we have extra space)
+ leftTab = max(leftTab, 1);
+
+ scrollFrame:SetHorizontalScroll(scrollFrame.dynTabSize * (leftTab - 1));
+
+ return FCFDockOverflowButton_UpdatePulseState(scrollFrame:GetParent().overflowButton);
+end
+
+--Dock list related functions
+function FCFDockOverflow_CloseLists()
+ local list = GENERAL_CHAT_DOCK.overflowButton.list;
+ if ( list:IsShown() ) then
+ list:Hide();
+ return true;
+ else
+ return false;
+ end
+end
+
+function FCFDockOverflowButton_UpdatePulseState(self)
+ local dock = self:GetParent();
+ local shouldPulse = false;
+ for _, chatFrame in pairs(FCFDock_GetChatFrames(dock)) do
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ if ( not chatFrame.isStaticDocked and chatTab.alerting) then
+ --Make sure the rects are valid. (Not always the case when resizing the WoW client
+ if ( not chatTab:GetRight() or not dock.scrollFrame:GetRight() ) then
+ return false;
+ end
+ --Check if it's off the screen.
+ local DELTA = 3; --Chosen through experimentation
+ if ( chatTab:GetRight() < (dock.scrollFrame:GetLeft() + DELTA) or chatTab:GetLeft() > (dock.scrollFrame:GetRight() - DELTA) ) then
+ shouldPulse = true;
+ break;
+ end
+ end
+ end
+
+ if ( shouldPulse ) then
+ UIFrameFlash(self:GetHighlightTexture(), 1.0, 1.0, -1, true, 0, 0, "chat");
+ self:LockHighlight();
+ self.alerting = true;
+ else
+ UIFrameFlashStop(self:GetHighlightTexture());
+ self:UnlockHighlight();
+ self:GetHighlightTexture():Show();
+ self.alerting = false;
+ end
+
+ if ( self.list:IsShown() ) then
+ FCFDockOverflowList_Update(self.list, dock);
+ end
+ return true;
+end
+
+function FCFDockOverflowButton_OnClick(self, button)
+ PlaySound("UChatScrollButton");
+ if ( self.list:IsShown() ) then
+ self.list:Hide();
+ else
+ FCFDockOverflowList_Update(self.list, self:GetParent());
+ self.list:Show();
+ end
+end
+
+function FCFDockOverflowButton_OnEvent(self, event, ...)
+ if ( event == "UPDATE_CHAT_COLOR" and self.list:IsShown() ) then
+ FCFDockOverflowList_Update(self.list, self:GetParent());
+ end
+end
+
+function FCFDockOverflowList_Update(list, dock)
+ local dockedFrames = FCFDock_GetChatFrames(dock);
+
+ list:SetHeight(#dockedFrames *15 + 35);
+
+ list.numTabs:SetFormattedText(CHAT_WINDOWS_COUNT, #dockedFrames);
+
+ for i = 1, #dockedFrames do
+ local button = list.buttons[i];
+ if ( not button ) then
+ list.buttons[i] = CreateFrame("Button", list:GetName().."Button"..i, list, "DockManagerOverflowListButtonTemplate");
+ button = list.buttons[i];
+
+ if ( not list.buttons[i-1] ) then
+ button:SetPoint("TOPLEFT", list, "TOPLEFT", 5, -19);
+ else
+ button:SetPoint("TOPLEFT", list.buttons[i-1], "BOTTOMLEFT", 0, -3);
+ end
+ button:SetWidth(list:GetWidth() - 10); -- buttons are 5 pixels in on both sides
+ end
+
+ FCFDockOverflowListButton_SetValue(button, dockedFrames[i]);
+ end
+
+ for i = #dockedFrames + 1, #list.buttons do
+ list.buttons[i]:Hide();
+ end
+end
+
+function FCFDockOverflowListButton_SetValue(button, chatFrame)
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ button.chatFrame = chatFrame;
+ button:SetText(chatFrame.name);
+
+ local colorTable = chatTab.selectedColorTable or DEFAULT_TAB_SELECTED_COLOR_TABLE;
+
+ if ( chatTab.selectedColorTable ) then
+ button:GetFontString():SetTextColor(colorTable.r, colorTable.g, colorTable.b);
+ else
+ button:GetFontString():SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+
+ button.glow:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+
+ if ( chatTab.conversationIcon ) then
+ button.conversationIcon:SetVertexColor(colorTable.r, colorTable.g, colorTable.b);
+ button.conversationIcon:Show();
+ else
+ button.conversationIcon:Hide();
+ end
+
+ if ( chatTab.alerting ) then
+ button.alerting = true;
+ UIFrameFlash(button.glow, 1.0, 1.0, -1, false, 0, 0, "chat");
+ else
+ button.alerting = false;
+ UIFrameFlashStop(button.glow);
+ end
+
+ button:Show();
+end
+
+function FCFDockOverflowListButton_OnClick(self, button)
+ FCFDock_SelectWindow(self:GetParent():GetParent():GetParent(), self.chatFrame);
+end
+
+---------------------------------------------------
+-----------Temp Window Manager-------------
+----------------------------------------------------
+local dedicatedWindows = {};
+
+local function FCFManager_GetToken(chatType, chatTarget)
+ return strlower(chatType)..(chatTarget and ";;"..strlower(chatTarget) or "");
+end
+
+function FCFManager_RegisterDedicatedFrame(chatFrame, chatType, chatTarget)
+ local token = FCFManager_GetToken(chatType, chatTarget);
+ if ( not dedicatedWindows[token] ) then
+ dedicatedWindows[token] = {};
+ end
+
+ if ( not tContains(dedicatedWindows[token], chatFrame) ) then
+ tinsert(dedicatedWindows[token], chatFrame);
+ end
+end
+
+function FCFManager_UnregisterDedicatedFrame(chatFrame, chatType, chatTarget)
+ local token = FCFManager_GetToken(chatType, chatTarget);
+ local windowList = dedicatedWindows[token];
+ if ( windowList ) then
+ tDeleteItem(windowList, chatFrame);
+ end
+end
+
+function FCFManager_GetNumDedicatedFrames(chatType, chatTarget)
+ local token = FCFManager_GetToken(chatType, chatTarget);
+ local windowList = dedicatedWindows[token];
+ return (windowList and #windowList or 0);
+end
+
+function FCFManager_ShouldSuppressMessage(chatFrame, chatType, chatTarget)
+ --Using GetToken probably isn't the best way to do this due to the string concatenation, but it's the easiest to get in quickly.
+ if ( chatFrame.chatType and FCFManager_GetToken(chatType, chatTarget) == FCFManager_GetToken(chatFrame.chatType, chatFrame.chatTarget) ) then
+ --This frame is a dedicated frame of this type, so we should always display.
+ return false;
+ end
+
+ if ( chatType == "BN_CONVERSATION" and GetCVar("conversationMode") == "popout" ) then
+ return true;
+ end
+
+ return false;
+end
+
+function FloatingChatFrameManager_OnLoad(self)
+ --Register for BN_CONVERSATION related messages to be able to spawn off new windows as needed
+ for _, event in pairs(ChatTypeGroup["BN_CONVERSATION"]) do
+ self:RegisterEvent(event);
+ end
+end
+
+function FloatingChatFrameManager_OnEvent(self, event, ...)
+ local arg1 = ...;
+ if ( strsub(event, 1, 9) == "CHAT_MSG_" ) then
+ local chatType = strsub(event, 10);
+ local chatGroup = Chat_GetChatCategory(chatType);
+
+ if ( chatGroup == "BN_CONVERSATION" ) then
+ if ( GetCVar("conversationMode") == "popout" ) then
+ if( not (event == "CHAT_MSG_BN_CONVERSATION_NOTICE" and arg1 == "YOU_LEFT_CONVERSATION") ) then
+ local chatTarget = tostring(select(8, ...));
+ if ( FCFManager_GetNumDedicatedFrames(chatGroup, chatTarget) == 0 ) then
+ local chatFrame = FCF_OpenTemporaryWindow(chatGroup, chatTarget);
+ chatFrame:GetScript("OnEvent")(chatFrame, event, ...); --Re-fire the event for the frame.
+ end
+ end
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/reference/FrameXML/FloatingChatFrame.xml b/reference/FrameXML/FloatingChatFrame.xml
new file mode 100644
index 0000000..fc3b1da
--- /dev/null
+++ b/reference/FrameXML/FloatingChatFrame.xml
@@ -0,0 +1,1025 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.highlight:Show();
+
+
+ self.highlight:Hide();
+
+
+ FCFDockOverflowListButton_OnClick(self, button)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropColor(0.05, 0.05, 0.11);
+ self.buttons = {};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.width = self:GetWidth();
+ self:RegisterEvent("UPDATE_CHAT_COLOR");
+
+
+ FCFDockOverflowButton_OnEvent(self, event, ...);
+
+
+ GameTooltip_AddNewbieTip(self, CHAT_OVERFLOW_LABEL, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_CHAT_OVERFLOW, 1);
+
+
+ GameTooltip:Hide();
+
+
+ FCFDockOverflowButton_OnClick(self, button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FCFDock_OnEvent(self, event, ...);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:RegisterForDrag("LeftButton");
+
+
+ FCF_Tab_OnClick(self, button);
+ PlaySound("UChatScrollButton");
+
+
+ if ( button ~= "RightButton" ) then
+ local chatFrame = _G["ChatFrame"..self:GetID()];
+ if ( not chatFrame.isDocked ) then
+ FCF_MinimizeFrame(chatFrame, chatFrame.buttonSide);
+ end
+ end
+
+
+ local chatFrame = _G["ChatFrame"..self:GetID()];
+
+ if ( chatFrame.isTemporary and chatFrame.chatType == "BN_CONVERSATION" ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ BNConversation_DisplayConversationTooltip(tonumber(chatFrame.chatTarget));
+ else
+ GameTooltip_AddNewbieTip(self, CHAT_OPTIONS_LABEL, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_CHATOPTIONS, 1);
+ end
+
+
+ GameTooltip:Hide();
+
+
+ local chatFrame = _G["ChatFrame"..self:GetID()];
+ if ( chatFrame == DEFAULT_CHAT_FRAME ) then
+ if (chatFrame.isLocked) then
+ return;
+ end
+ chatFrame:StartMoving();
+ MOVING_CHATFRAME = chatFrame;
+ elseif ( chatFrame.isDocked ) then
+ FCF_UnDockFrame(chatFrame);
+ FCF_SetLocked(chatFrame, nil);
+ local chatTab = _G[chatFrame:GetName().."Tab"];
+ local x,y = chatTab:GetCenter();
+ x = x - (chatTab:GetWidth()/2);
+ y = y - (chatTab:GetHeight()/2);
+ chatTab:ClearAllPoints();
+ chatFrame:ClearAllPoints();
+ chatFrame:SetPoint("TOPLEFT", "UIParent", "BOTTOMLEFT", x, y);
+ FCF_SetTabPosition(chatFrame, 0);
+ chatFrame:StartMoving();
+ MOVING_CHATFRAME = chatFrame;
+ Blizzard_CombatLog_Update_QuickButtons();
+ SELECTED_CHAT_FRAME = chatFrame;
+ else
+ if ( chatFrame.isLocked ) then
+ return;
+ end
+ chatFrame:StartMoving();
+ SELECTED_CHAT_FRAME = chatFrame;
+ MOVING_CHATFRAME = chatFrame;
+ end
+
+ self:LockHighlight();
+
+ --OnUpdate simulates OnDragStop
+ --This is a hack fix we need to do because when SetParent is called, the OnDragStop never fires for the matching OnDragStart.
+ self.dragButton = button;
+ self:SetScript("OnUpdate", FCFTab_OnUpdate);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FCFClickAnywhereButton_OnLoad(self);
+
+
+ FCFClickAnywhereButton_OnEvent(self, event, ...);
+
+
+ ChatEdit_SetLastActiveWindow(self:GetParent().editBox);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local chatFrame = self:GetParent();
+ self:SetButtonState("PUSHED", true);
+ SetCursor("UI-Cursor-Size"); --Hide the cursor
+
+ self:GetHighlightTexture():Hide();
+
+ chatFrame:StartSizing("BOTTOMRIGHT");
+
+
+ self:SetButtonState("NORMAL", false);
+ SetCursor(nil); --Show the cursor again
+
+ self:GetHighlightTexture():Show();
+
+ self:GetParent():StopMovingOrSizing();
+ FCF_SavePositionAndDimensions(self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igChatBottom");
+ self:GetParent():GetParent():ScrollToBottom();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MessageFrameScrollButton_OnLoad(self);
+
+
+ MessageFrameScrollButton_OnUpdate(self, elapsed);
+
+
+ if ( self:GetButtonState() == "PUSHED" ) then
+ self.clickDelay = MESSAGE_SCROLLBUTTON_INITIAL_DELAY;
+ else
+ self:GetParent():GetParent():ScrollDown();
+ end
+ PlaySound("igChatScrollDown");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MessageFrameScrollButton_OnLoad(self);
+
+
+ MessageFrameScrollButton_OnUpdate(self, elapsed);
+
+
+ if ( self:GetButtonState() == "PUSHED" ) then
+ self.clickDelay = MESSAGE_SCROLLBUTTON_INITIAL_DELAY;
+ else
+ self:GetParent():GetParent():ScrollUp();
+ end
+ PlaySound("igChatScrollUp");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local chatFrame = self:GetParent():GetParent();
+ FCF_MinimizeFrame(chatFrame, strupper(chatFrame.buttonSide));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.chatFrame = self:GetParent();
+ ChatEdit_OnLoad(self);
+
+
+
+
+
+
+ ChatFrame_OnLoad(self);
+ FloatingChatFrame_OnLoad(self);
+
+
+ ChatFrame_OnUpdate(self, elapsed);
+
+
+ local name = self:GetName();
+ _G[name.."ButtonFrameBottomButton"]:Show();
+ _G[name.."ButtonFrameDownButton"]:Show();
+ _G[name.."ButtonFrameUpButton"]:Show();
+ SetChatWindowShown(self:GetID(), 1);
+ FCF_StopAlertFlash(self);
+
+
+ --If UIParent is hidden (Alt-Z), OnHide is called, but self:IsShown() is still true (self:IsVisible() would be false)
+ if ( not self:IsShown() ) then
+ local name = self:GetName();
+ _G[name.."ButtonFrameBottomButton"]:Hide();
+ _G[name.."ButtonFrameDownButton"]:Hide();
+ _G[name.."ButtonFrameUpButton"]:Hide();
+ if ( not self.minimized ) then
+ SetChatWindowShown(self:GetID(), nil);
+ end
+ end
+
+
+ ChatFrame_OnEvent(self, event, ...);
+ FloatingChatFrame_OnEvent(self, event, ...);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FCF_MaximizeFrame(self:GetParent().maxFrame);
+
+
+
+
+
+
+ self:RegisterForDrag("LeftButton");
+ self:SetClampRectInsets(0, 0, 0, -50);
+ self.Text:ClearAllPoints();
+ self.Text:SetPoint("LEFT", self, "LEFT", 15, 0);
+ self.Text:SetPoint("RIGHT", self, "RIGHT", -25, 0);
+
+
+ self:StartMoving();
+
+
+ self:StopMovingOrSizing();
+ self:SetUserPlaced(false); --So that we don't save the position
+
+
+ FCF_MaximizeFrame(self.maxFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FCFDock_OnLoad(self);
+ GENERAL_CHAT_DOCK = self;
+ -- resize for locales
+ local list = self.overflowButton.list;
+ list.numTabs:SetFormattedText(CHAT_WINDOWS_COUNT, 10);
+ list:SetWidth(list.numTabs:GetWidth() + 48); -- 24 pixel margins
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ tinsert(CHAT_FRAMES, self:GetName());
+ ChatFrame_OnLoad(self);
+ DEFAULT_CHAT_FRAME = ChatFrame1;
+ SELECTED_CHAT_FRAME = ChatFrame1;
+ SELECTED_DOCK_FRAME = ChatFrame1;
+
+ self.isStaticDocked = true;
+ FCFDock_SetPrimary(GENERAL_CHAT_DOCK, self);
+ ChatEdit_SetLastActiveWindow(self.editBox);
+
+ self:SetClampRectInsets(-35, 35, 38, -50);
+ self:RegisterEvent("UPDATE_CHAT_WINDOWS");
+ self:RegisterEvent("UPDATE_FLOATING_CHAT_WINDOWS");
+
+
+ ChatFrame_OnEvent(self, event, ...);
+ FloatingChatFrame_OnEvent(self, event, ...);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igChatEmoteButton");
+ ChatFrame_OpenMenu();
+
+
+ GameTooltip_AddNewbieTip(self, CHAT_LABEL, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_CHATMENU, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetPoint("BOTTOM", DEFAULT_CHAT_FRAME.buttonFrame, "TOP", 0, 4);
+ local _, numBNetOnline = BNGetNumFriends();
+ local _, numWoWOnline = GetNumFriends();
+ FriendsMicroButtonCount:SetText(numBNetOnline + numWoWOnline);
+ FriendsMicroButtonCount:SetShadowOffset(1, 1);
+
+
+ ToggleFriendsFrame(1);
+
+
+ GameTooltip_AddNewbieTip(self, MicroButtonTooltipText(SOCIAL_BUTTON, "TOGGLESOCIAL"), 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_SOCIAL);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ChatFrame_OnLoad(self);
+ FloatingChatFrame_OnLoad(self);
+ self.isStaticDocked = true;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/FocusFrame.lua b/reference/FrameXML/FocusFrame.lua
new file mode 100644
index 0000000..e525551
--- /dev/null
+++ b/reference/FrameXML/FocusFrame.lua
@@ -0,0 +1,491 @@
+MAX_FOCUS_DEBUFFS = 8;
+
+function FocusFrame_OnLoad (self)
+ self.statusCounter = 0;
+ self.statusSign = -1;
+ self.unitHPPercent = 1;
+
+ FocusFrame.debuffTotal = 0;
+
+ self:RegisterForDrag("LeftButton");
+ FocusFrame_Update(self);
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("PLAYER_FOCUS_CHANGED");
+ self:RegisterEvent("UNIT_HEALTH");
+ self:RegisterEvent("UNIT_LEVEL");
+ self:RegisterEvent("UNIT_FACTION");
+ self:RegisterEvent("UNIT_CLASSIFICATION_CHANGED");
+ self:RegisterEvent("UNIT_AURA");
+ self:RegisterEvent("PLAYER_FLAGS_CHANGED");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("RAID_TARGET_UPDATE");
+ self:RegisterEvent("VARIABLES_LOADED");
+
+ local frameLevel = FocusFrameTextureFrame:GetFrameLevel();
+ FocusFrameHealthBar:SetFrameLevel(frameLevel-1);
+ FocusFrameManaBar:SetFrameLevel(frameLevel-1);
+ FocusFrameSpellBar:SetFrameLevel(frameLevel-1);
+
+ local showmenu = function()
+ ToggleDropDownMenu(1, nil, FocusFrameDropDown, "FocusFrame", 120, 10);
+ end
+ SecureUnitButton_OnLoad(self, "focus", showmenu);
+end
+
+function FocusFrame_Update (self)
+ -- This check is here so the frame will hide when the target goes away
+ -- even if some of the functions below are hooked by addons.
+ if ( not UnitExists("focus") ) then
+ self:Hide();
+ else
+ self:Show();
+
+ -- Moved here to avoid taint from functions below
+ TargetofFocus_Update();
+
+ UnitFrame_Update(self);
+ FocusFrame_CheckFaction(self);
+ FocusFrame_UpdateAuras(self);
+ FocusPortrait:SetAlpha(1.0);
+ end
+end
+
+function FocusFrame_OnEvent (self, event, ...)
+ UnitFrame_OnEvent(self, event, ...);
+
+ local arg1 = ...;
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ FocusFrame_Update(self);
+ elseif ( event == "PLAYER_FOCUS_CHANGED" ) then
+ -- Moved here to avoid taint from functions below
+ FocusFrame_Update(self);
+ FocusFrame_UpdateRaidTargetIcon(self);
+ CloseDropDownMenus();
+
+ if ( UnitExists("focus") ) then
+ if ( UnitIsEnemy("focus", "player") ) then
+ PlaySound("igCreatureAggroSelect");
+ elseif ( UnitIsFriend("player", "focus") ) then
+ PlaySound("igCharacterNPCSelect");
+ else
+ PlaySound("igCreatureNeutralSelect");
+ end
+ end
+ elseif ( event == "UNIT_FACTION" ) then
+ if ( arg1 == "focus" or arg1 == "player" ) then
+ FocusFrame_CheckFaction(self);
+ end
+ elseif ( event == "UNIT_AURA" ) then
+ if ( arg1 == "focus" ) then
+ FocusFrame_UpdateAuras(self);
+ end
+ elseif ( event == "PARTY_MEMBERS_CHANGED" ) then
+ TargetofFocus_Update();
+ FocusFrame_CheckFaction(self);
+ elseif ( event == "RAID_TARGET_UPDATE" ) then
+ FocusFrame_UpdateRaidTargetIcon(self);
+ elseif ( event == "VARIABLES_LOADED" ) then
+ FocusFrame_SetFullSize(GetCVarBool("fullSizeFocusFrame"));
+ end
+end
+
+function FocusFrame_OnHide (self)
+ PlaySound("INTERFACESOUND_LOSTTARGETUNIT");
+ CloseDropDownMenus();
+end
+
+function FocusFrame_CheckFaction (self)
+ if ( not UnitPlayerControlled("focus") and UnitIsTapped("focus") and not UnitIsTappedByPlayer("focus") and not UnitIsTappedByAllThreatList("focus") ) then
+ FocusFrameNameBackground:SetVertexColor(0.5, 0.5, 0.5);
+ FocusPortrait:SetVertexColor(0.5, 0.5, 0.5);
+ else
+ FocusFrameNameBackground:SetVertexColor(UnitSelectionColor("focus"));
+ FocusPortrait:SetVertexColor(1.0, 1.0, 1.0);
+ end
+end
+
+function FocusFrame_OnUpdate (self, elapsed)
+ if ( TargetofFocusFrame:IsShown() ~= UnitExists("focus-target") ) then
+ TargetofFocus_Update();
+ end
+end
+
+function FocusFrame_UpdateAuras (self)
+ RefreshDebuffs(self, "focus", MAX_FOCUS_DEBUFFS);
+end
+
+function FocusFrame_HealthUpdate (self, elapsed, unit)
+ if ( UnitIsPlayer(unit) ) then
+ if ( (self.unitHPPercent > 0) and (self.unitHPPercent <= 0.2) ) then
+ local alpha = 255;
+ local counter = self.statusCounter + elapsed;
+ local sign = self.statusSign;
+
+ if ( counter > 0.5 ) then
+ sign = -sign;
+ self.statusSign = sign;
+ end
+ counter = mod(counter, 0.5);
+ self.statusCounter = counter;
+
+ if ( sign == 1 ) then
+ alpha = (127 + (counter * 256)) / 255;
+ else
+ alpha = (255 - (counter * 256)) / 255;
+ end
+ FocusPortrait:SetAlpha(alpha);
+ end
+ end
+end
+
+function FocusHealthCheck (self)
+ if ( UnitIsPlayer("focus") ) then
+ local unitHPMin, unitHPMax, unitCurrHP;
+ unitHPMin, unitHPMax = self:GetMinMaxValues();
+ unitCurrHP = self:GetValue();
+ self:GetParent().unitHPPercent = unitCurrHP / unitHPMax;
+ if ( UnitIsDead("focus") ) then
+ FocusPortrait:SetVertexColor(0.35, 0.35, 0.35, 1.0);
+ elseif ( UnitIsGhost("focus") ) then
+ FocusPortrait:SetVertexColor(0.2, 0.2, 0.75, 1.0);
+ elseif ( (self:GetParent().unitHPPercent > 0) and (self:GetParent().unitHPPercent <= 0.2) ) then
+ FocusPortrait:SetVertexColor(1.0, 0.0, 0.0);
+ else
+ FocusPortrait:SetVertexColor(1.0, 1.0, 1.0, 1.0);
+ end
+ end
+end
+
+function FocusFrameDropDown_OnLoad (self)
+ UIDropDownMenu_Initialize(self, FocusFrameDropDown_Initialize, "MENU");
+end
+
+function FocusFrameDropDown_Initialize (self)
+ UnitPopup_ShowMenu(self, "FOCUS", "focus", SET_FOCUS);
+end
+
+function FocusFrame_UpdateRaidTargetIcon (self)
+ local index = GetRaidTargetIndex("focus");
+ if ( index ) then
+ SetRaidTargetIconTexture(FocusRaidTargetIcon, index);
+ FocusRaidTargetIcon:Show();
+ else
+ FocusRaidTargetIcon:Hide();
+ end
+end
+
+function TargetofFocus_OnLoad (self)
+ local frameLevel = FocusFrame:GetFrameLevel();
+ TargetofFocusFrame:SetFrameLevel(frameLevel-1);
+
+ UnitFrame_Initialize(self, "focus-target", TargetofFocusName, TargetofFocusPortrait,
+ TargetofFocusHealthBar, TargetofFocusHealthBarText,
+ TargetofFocusManaBar, TargetofFocusFrameManaBarText,
+ TargetofFocusThreatIndicator, "player");
+ SetTextStatusBarTextZeroText(TargetofFocusHealthBar, DEAD);
+ self:RegisterEvent("UNIT_AURA");
+
+ SecureUnitButton_OnLoad(self, "focus-target");
+end
+
+function TargetofFocus_Update (self, elapsed)
+ if ( not self ) then
+ self = TargetofFocusFrame;
+ end
+
+ local show;
+ if ( SHOW_TARGET_OF_TARGET == "1" and UnitExists("focus") and UnitExists("focus-target") and --[[( not UnitIsUnit(PlayerFrame.unit, "focus") ) and ]]( UnitHealth("focus") > 0 ) ) then
+ if ( ( SHOW_TARGET_OF_TARGET_STATE == "5" ) or
+ ( SHOW_TARGET_OF_TARGET_STATE == "4" and ( (GetNumRaidMembers() > 0) or (GetNumPartyMembers() > 0) ) ) or
+ ( SHOW_TARGET_OF_TARGET_STATE == "3" and ( (GetNumRaidMembers() == 0) and (GetNumPartyMembers() == 0) ) ) or
+ ( SHOW_TARGET_OF_TARGET_STATE == "2" and ( (GetNumPartyMembers() > 0) and (GetNumRaidMembers() == 0) ) ) or
+ ( SHOW_TARGET_OF_TARGET_STATE == "1" and ( GetNumRaidMembers() > 0 ) ) ) then
+ show = true;
+ end
+ end
+
+ if ( show ) then
+ if ( not TargetofFocusFrame:IsShown() ) then
+ TargetofFocusFrame:Show();
+ Focus_Spellbar_AdjustPosition();
+ end
+ UnitFrame_Update(self);
+ TargetofFocus_CheckDead();
+ TargetofFocusHealthCheck();
+ RefreshDebuffs(TargetofFocusFrame, "focus-target");
+ else
+ if ( TargetofFocusFrame:IsShown() ) then
+ TargetofFocusFrame:Hide();
+ Focus_Spellbar_AdjustPosition();
+ end
+ end
+end
+
+function TargetofFocus_CheckDead ()
+ if ( (UnitHealth("focus-target") <= 0) and UnitIsConnected("focus-target") ) then
+ TargetofFocusBackground:SetAlpha(0.9);
+ TargetofFocusDeadText:Show();
+ else
+ TargetofFocusBackground:SetAlpha(1);
+ TargetofFocusDeadText:Hide();
+ end
+end
+
+function TargetofFocusHealthCheck ()
+ if ( UnitIsPlayer("focus-target") ) then
+ local unitHPMin, unitHPMax, unitCurrHP;
+ unitHPMin, unitHPMax = TargetofFocusHealthBar:GetMinMaxValues();
+ unitCurrHP = TargetofFocusHealthBar:GetValue();
+ TargetofFocusFrame.unitHPPercent = unitCurrHP / unitHPMax;
+ if ( UnitIsDead("focus-target") ) then
+ TargetofFocusPortrait:SetVertexColor(0.35, 0.35, 0.35, 1.0);
+ elseif ( UnitIsGhost("focus-target") ) then
+ TargetofFocusPortrait:SetVertexColor(0.2, 0.2, 0.75, 1.0);
+ elseif ( (TargetofFocusFrame.unitHPPercent > 0) and (TargetofFocusFrame.unitHPPercent <= 0.2) ) then
+ TargetofFocusPortrait:SetVertexColor(1.0, 0.0, 0.0);
+ else
+ TargetofFocusPortrait:SetVertexColor(1.0, 1.0, 1.0, 1.0);
+ end
+ end
+end
+
+
+function SetFocusSpellbarAspect()
+ local frameText = _G[FocusFrameSpellBar:GetName().."Text"];
+ if ( frameText ) then
+ frameText:SetFontObject(SystemFont_Shadow_Small);
+ frameText:ClearAllPoints();
+ frameText:SetPoint("TOP", FocusFrameSpellBar, "TOP", 0, 4);
+ end
+
+ local frameBorder = _G[FocusFrameSpellBar:GetName().."Border"];
+ if ( frameBorder ) then
+ frameBorder:SetTexture("Interface\\CastingBar\\UI-CastingBar-Border-Small");
+ frameBorder:SetWidth(177);
+ frameBorder:SetHeight(49);
+ frameBorder:ClearAllPoints();
+ frameBorder:SetPoint("TOP", FocusFrameSpellBar, "TOP", 0, 20);
+ end
+
+ local frameBorderShield = _G[FocusFrameSpellBar:GetName().."BorderShield"];
+ if ( frameBorderShield ) then
+ --frameBorderShield:SetTexture("Interface\\CastingBar\\UI-CastingBar-Small-FocusShield");
+ frameBorderShield:SetWidth(177);
+ frameBorderShield:SetHeight(49);
+ frameBorderShield:ClearAllPoints();
+ frameBorderShield:SetPoint("TOP", FocusFrameSpellBar, "TOP", -6, 20);
+ end
+
+ local frameFlash = _G[FocusFrameSpellBar:GetName().."Flash"];
+ if ( frameFlash ) then
+ frameFlash:SetTexture("Interface\\CastingBar\\UI-CastingBar-Flash-Small");
+ frameFlash:SetWidth(177);
+ frameFlash:SetHeight(49);
+ frameFlash:ClearAllPoints();
+ frameFlash:SetPoint("TOP", FocusFrameSpellBar, "TOP", -2, 20);
+ end
+end
+
+function Focus_Spellbar_OnLoad (self)
+ self:RegisterEvent("PLAYER_FOCUS_CHANGED");
+ self:RegisterEvent("CVAR_UPDATE");
+ self:RegisterEvent("VARIABLES_LOADED");
+
+ CastingBarFrame_OnLoad(self, "focus", false, false);
+
+ local barIcon = _G[self:GetName().."Icon"];
+ barIcon:Show();
+ barIcon:ClearAllPoints();
+ barIcon:SetPoint("RIGHT", self:GetName(), "LEFT", -5, 0);
+
+ SetFocusSpellbarAspect();
+ self.showShield = true;
+
+ _G[self:GetName().."Text"]:SetWidth(130);
+ -- check to see if the castbar should be shown
+ if ( GetCVar("showTargetCastbar") == "0") then
+ self.showCastbar = false;
+ end
+end
+
+function Focus_Spellbar_OnEvent (self, event, ...)
+ local arg1 = ...
+
+ -- Check for target specific events
+ if ( (event == "VARIABLES_LOADED") or ((event == "CVAR_UPDATE") and (arg1 == "SHOW_TARGET_CASTBAR")) ) then
+ if ( GetCVar("showTargetCastbar") == "0") then
+ self.showCastbar = false;
+ else
+ self.showCastbar = true;
+ end
+
+ if ( not self.showCastbar ) then
+ self:Hide();
+ elseif ( self.casting or self.channeling ) then
+ self:Show();
+ end
+ return;
+ elseif ( event == "PLAYER_FOCUS_CHANGED" ) then
+ -- check if the new target is casting a spell
+ local nameChannel = UnitChannelInfo(self.unit);
+ local nameSpell = UnitCastingInfo(self.unit);
+ if ( nameChannel ) then
+ event = "UNIT_SPELLCAST_CHANNEL_START";
+ arg1 = "focus";
+ elseif ( nameSpell ) then
+ event = "UNIT_SPELLCAST_START";
+ arg1 = "focus";
+ else
+ self.casting = nil;
+ self.channeling = nil;
+ self:SetMinMaxValues(0, 0);
+ self:SetValue(0);
+ self:Hide();
+ return;
+ end
+ -- The position depends on the classification of the target
+ Focus_Spellbar_AdjustPosition();
+ end
+ CastingBarFrame_OnEvent(self, event, arg1, select(2, ...));
+end
+
+function Focus_Spellbar_AdjustPosition ()
+ local yPos = 3;
+ if ( FocusFrame.debuffTotal > 4 ) then
+ yPos = 25;
+ elseif ( TargetofFocusFrame:IsShown() ) then
+ yPos = 30;
+ elseif ( FocusFrame.debuffTotal > 0 ) then
+ yPos = 15
+ end
+ FocusFrameSpellBar:SetPoint("BOTTOM", "FocusFrame", "BOTTOM", 20, -yPos);
+end
+
+FOCUS_FRAME_LOCKED = true;
+function FocusFrame_IsLocked()
+ return FOCUS_FRAME_LOCKED;
+end
+function FocusFrame_SetLock(locked)
+ FOCUS_FRAME_LOCKED = locked;
+end
+
+function FocusFrame_OnDragStart(self, button)
+ FOCUS_FRAME_MOVING = false;
+ if ( not FOCUS_FRAME_LOCKED ) then
+ local cursorX, cursorY = GetCursorPosition();
+ self:SetFrameStrata("DIALOG");
+ self:StartMoving();
+ FOCUS_FRAME_MOVING = true;
+ end
+end
+
+function FocusFrame_OnDragStop(self)
+ if ( not FOCUS_FRAME_LOCKED and FOCUS_FRAME_MOVING ) then
+ self:StopMovingOrSizing();
+ self:SetFrameStrata("BACKGROUND");
+ ValidateFramePosition(self, 25);
+ FOCUS_FRAME_MOVING = false;
+ end
+end
+
+
+--------Support for a full-size Focus Frame---------
+local dimsAndAnchors = {setDims = true, numAnchorsToCopy = 1}; --This way we don't have to have duplicate tables...
+local justAnchors = { setDims = false, numAnchorsToCopy = 1};
+local framesToDuplicate = {
+ ["Frame"] = {
+ setDims = true,
+ numAnchorsToCopy = 0,
+ },
+ ["FrameFlash"] = dimsAndAnchors,
+ ["FrameBackground"] = dimsAndAnchors,
+ ["FrameNameBackground"] = dimsAndAnchors,
+ ["Portrait"] = dimsAndAnchors,
+ ["Name"] = dimsAndAnchors,
+ ["FrameHealthBarText"] = justAnchors,
+ ["FrameManaBarText"] = justAnchors,
+ ["RaidTargetIcon"] = dimsAndAnchors,
+ ["FrameHealthBar"] = dimsAndAnchors,
+ ["FrameManaBar"] = dimsAndAnchors,
+ ["FrameNumericalThreat"] = dimsAndAnchors,
+}
+-- temp fixes to focus frame
+TargetPortrait = TargetFramePortrait;
+TargetFrameManaBarText = TargetFrameTextureFrameManaBarText;
+TargetFrameHealthBarText = TargetFrameTextureFrameHealthBarText;
+TargetRaidTargetIcon = TargetFrameTextureFrameRaidTargetIcon;
+TargetName = TargetFrameTextureFrameName;
+
+function FocusFrame_SetFullSize(fullSize)
+ if ( fullSize and not FocusFrame.fullSize) then --It copies the TargetFrame. That way we don't have to explicitly maintain a bunch of alternate coordinates.
+ FocusFrame.fullSize = true;
+ for name, value in pairs(framesToDuplicate) do
+ local frame = _G["Focus"..name];
+ local equivFrame = _G["Target"..name];
+ if ( value.setDims ) then
+ --Save off the old dimensions so that we can set them back later (the or stops it from overwriting if there are already values)
+ frame.oldHeight = frame.oldHeight or frame:GetHeight();
+ frame.oldWidth = frame.oldWidth or frame:GetWidth();
+
+ frame:SetHeight(equivFrame:GetHeight());
+ frame:SetWidth(equivFrame:GetWidth());
+ end
+ if ( value.numAnchorsToCopy > 0 ) then
+ frame.oldAnchors = frame.oldAnchors or {};
+ for i=1, frame:GetNumPoints() do
+ frame.oldAnchors[i] = frame.oldAnchors[i] or {frame:GetPoint(i)};
+ end
+ frame:ClearAllPoints();
+ for i=1, value.numAnchorsToCopy do
+ local point, relativeTo, relativePoint, xOffset, yOffset = equivFrame:GetPoint(i);
+ relativeTo = string.gsub(relativeTo:GetName(), "Target", "Focus", 1);
+ frame:SetPoint(point, relativeTo, relativePoint, xOffset, yOffset);
+ end
+ end
+ end
+
+ for i=1, MAX_FOCUS_DEBUFFS do
+ _G["FocusFrameDebuff"..i]:SetHeight(21);
+ _G["FocusFrameDebuff"..i]:SetWidth(21);
+ end
+
+ TargetofFocusFrame:SetPoint("BOTTOMRIGHT", -35, -10);
+
+ FocusFrameFlash:SetTexture("Interface\\TargetingFrame\\UI-FocusFrame-Large-Flash");
+ FocusFrameFlash:SetTexCoord(0.0, 0.945, 0.0, 0.73125);
+
+ FocusFrameTextureFrameSmall:Hide();
+ FocusFrameTextureFrameFullSize:Show();
+ elseif ( not fullSize and FocusFrame.fullSize ) then
+ FocusFrame.fullSize = false;
+ for name, value in pairs(framesToDuplicate) do
+ local frame = _G["Focus"..name];
+ if ( frame.oldHeight ) then
+ frame:SetHeight(frame.oldHeight);
+ end
+ if ( frame.oldWidth ) then
+ frame:SetWidth(frame.oldWidth);
+ end
+
+ if ( frame.oldAnchors ) then
+ frame:ClearAllPoints();
+ for i=1, #frame.oldAnchors do
+ frame:SetPoint(unpack(frame.oldAnchors[i]));
+ end
+ end
+ end
+
+ for i=1, MAX_FOCUS_DEBUFFS do
+ _G["FocusFrameDebuff"..i]:SetHeight(15);
+ _G["FocusFrameDebuff"..i]:SetWidth(15);
+ end
+
+ TargetofFocusFrame:SetPoint("BOTTOMRIGHT", 14, -9);
+
+ FocusFrameFlash:SetTexture("Interface\\TargetingFrame\\UI-TargetingFrame-Flash");
+ FocusFrameFlash:SetTexCoord(0.55078125, 0, 0.400390625, 0.52734375);
+
+ FocusFrameTextureFrameSmall:Show();
+ FocusFrameTextureFrameFullSize:Hide();
+ end
+end
diff --git a/reference/FrameXML/FocusFrame.xml b/reference/FrameXML/FocusFrame.xml
new file mode 100644
index 0000000..c89e415
--- /dev/null
+++ b/reference/FrameXML/FocusFrame.xml
@@ -0,0 +1,527 @@
+
+
+
+
+
+
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetUnitDebuff("focus", self:GetID());
+ end
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetUnitDebuff("focus", self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ self.textLockable = 1;
+ self.cvar = "targetStatusText";
+ self.cvarLabel = "STATUS_TEXT_TARGET";
+ self.zeroText = "";
+
+
+ UnitFrameHealthBar_OnValueChanged(self, value);
+ FocusHealthCheck(self, value);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ self.textLockable = 1;
+ self.cvar = "targetStatusText";
+ self.cvarLabel = "STATUS_TEXT_TARGET";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.text = _G[self:GetName().."Value"];
+ self.bg = _G[self:GetName().."BG"];
+
+
+
+
+
+
+ UnitFrame_Initialize(self, "focus", FocusName, FocusPortrait,
+ FocusFrameHealthBar, FocusFrameHealthBarText,
+ FocusFrameManaBar, FocusFrameManaBarText,
+ FocusFrameFlash,
+ "player",
+ FocusFrameNumericalThreat);
+ self.noTextPrefix = true;
+ FocusFrame_OnLoad(self);
+
+
+
+ FocusFrame_OnUpdate(self, elapsed);
+ FocusFrame_HealthUpdate(self, elapsed, "focus");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/FontStyles.xml b/reference/FrameXML/FontStyles.xml
new file mode 100644
index 0000000..08e9b97
--- /dev/null
+++ b/reference/FrameXML/FontStyles.xml
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/Fonts.xml b/reference/FrameXML/Fonts.xml
new file mode 100644
index 0000000..baf9d60
--- /dev/null
+++ b/reference/FrameXML/Fonts.xml
@@ -0,0 +1,329 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/FrameXML.toc b/reference/FrameXML/FrameXML.toc
new file mode 100644
index 0000000..056d239
--- /dev/null
+++ b/reference/FrameXML/FrameXML.toc
@@ -0,0 +1,147 @@
+# Do not delete the following line!
+## Interface: 30300
+##DebugHook.lua
+GlobalStrings.lua
+Constants.lua
+Fonts.xml
+FontStyles.xml
+Localization.xml
+## add new modules below here
+
+BasicControls.xml
+WorldFrame.xml
+UIParent.xml
+AnimTimerFrame.xml
+MoneyFrame.lua
+MoneyFrame.xml
+MoneyInputFrame.lua
+MoneyInputFrame.xml
+GameTooltip.xml
+UIMenu.xml
+UIDropDownMenu.xml
+UIPanelTemplates.lua
+UIPanelTemplates.xml
+SecureTemplates.xml
+SecureHandlerTemplates.xml
+ItemButtonTemplate.xml
+SparkleFrame.xml
+HybridScrollFrame.lua
+HybridScrollFrame.xml
+GameMenuFrame.xml
+CharacterFrameTemplates.xml
+TextStatusBar.lua
+TextStatusBar.xml
+UIErrorsFrame.xml
+AutoComplete.xml
+StaticPopup.xml
+Sound.lua
+OptionsFrameTemplates.xml
+OptionsPanelTemplates.xml
+VideoOptionsFrame.xml
+VideoOptionsPanels.xml
+AudioOptionsFrame.xml
+AudioOptionsPanels.xml
+InterfaceOptionsFrame.xml
+InterfaceOptionsPanels.xml
+AlertFrames.xml
+MirrorTimer.xml
+CoinPickupFrame.xml
+StackSplitFrame.xml
+FadingFrame.xml
+ZoneText.xml
+BattlefieldFrame.xml
+MainMenuBar.xml
+MainMenuBarMicroButtons.xml
+TutorialFrame.xml
+Minimap.xml
+GameTime.xml
+Cooldown.xml
+ActionButtonTemplate.xml
+ActionBarFrame.xml
+MultiActionBars.xml
+##ActionWindow.xml
+BuffFrame.xml
+CombatFeedback.xml
+CastingBarFrame.xml
+UnitPopup.xml
+UnitFrame.xml
+BNet.xml
+HistoryKeeper.lua
+BNConversations.xml
+ChatFrame.xml
+FloatingChatFrame.xml
+VoiceChat.xml
+ReadyCheck.xml
+PlayerFrame.xml
+PartyFrame.xml
+TargetFrame.xml
+TotemFrame.xml
+PetFrame.xml
+StatsFrame.xml
+SpellBookFrame.xml
+CharacterFrame.xml
+EquipmentManager.lua
+PaperDollFrame.xml
+PetPaperDollFrame.xml
+SkillFrame.xml
+ReputationFrame.xml
+HonorFrame.xml
+QuestFrame.xml
+QuestPOI.xml
+WatchFrame.xml
+QuestLogFrame.xml
+QuestInfo.xml
+MerchantFrame.xml
+TradeFrame.xml
+ContainerFrame.xml
+LootFrame.xml
+ItemTextFrame.xml
+TaxiFrame.xml
+BankFrame.xml
+FriendsFrame.xml
+RaidFrame.xml
+ChannelFrame.xml
+PetActionBarFrame.xml
+MultiCastActionBarFrame.xml
+BonusActionBarFrame.xml
+MainMenuBarBagButtons.xml
+WorldMapFrame.xml
+CinematicFrame.xml
+ItemRef.xml
+ComboFrame.xml
+TabardFrame.xml
+GuildRegistrarFrame.xml
+PetitionFrame.xml
+HelpFrame.xml
+KnowledgeBaseFrame.xml
+ColorPickerFrame.xml
+GossipFrame.xml
+MailFrame.xml
+PetStable.xml
+DurabilityFrame.xml
+WorldStateFrame.xml
+DressUpFrame.xml
+RaidWarning.xml
+ClassTrainerFrameTemplates.xml
+PVPFrame.xml
+PVPBattlegroundFrame.xml
+ArenaFrame.xml
+ArenaRegistrarFrame.xml
+LFGFrame.xml
+LFDFrame.xml
+LFRFrame.xml
+MovieRecordingProgress.xml
+MacOptionsFrame.xml
+RatingMenuFrame.xml
+TalentFrameBase.lua
+TalentFrameTemplates.xml
+RuneFrame.xml
+EasyMenu.lua
+ChatConfigFrame.xml
+MovieFrame.xml
+VehicleMenuBar.xml
+AlternatePowerBar.xml
+AnimationSystem.lua
+
+## add new modules above here
+LocalizationPost.xml
diff --git a/reference/FrameXML/FriendsFrame.lua b/reference/FrameXML/FriendsFrame.lua
new file mode 100644
index 0000000..8d70d9d
--- /dev/null
+++ b/reference/FrameXML/FriendsFrame.lua
@@ -0,0 +1,2831 @@
+FRIENDS_TO_DISPLAY = 10;
+FRIENDS_FRAME_FRIEND_HEIGHT = 34;
+IGNORES_TO_DISPLAY = 19;
+FRIENDS_FRAME_IGNORE_HEIGHT = 16;
+PENDING_INVITES_TO_DISPLAY = 4;
+PENDING_BUTTON_MIN_HEIGHT = 92;
+FRIENDS_FRIENDS_TO_DISPLAY = 11;
+FRIENDS_FRAME_FRIENDS_FRIENDS_HEIGHT = 16;
+MAX_INVITE_MESSAGE_LINES = 10;
+MAX_INVITE_MESSAGE_HEIGHT = 0; -- automatically set in FriendsFramePendingScrollFrame:OnLoad
+WHOS_TO_DISPLAY = 17;
+FRIENDS_FRAME_WHO_HEIGHT = 16;
+GUILDMEMBERS_TO_DISPLAY = 13;
+FRIENDS_FRAME_GUILD_HEIGHT = 14;
+MAX_WHOS_FROM_SERVER = 50;
+MAX_GUILDCONTROL_OPTIONS = 12;
+CURRENT_GUILD_MOTD = "";
+GUILD_DETAIL_NORM_HEIGHT = 195
+GUILD_DETAIL_OFFICER_HEIGHT = 255
+MAX_GUILDBANK_TABS = 6;
+MAX_GOLD_WITHDRAW = 1000;
+GUILDEVENT_TRANSACTION_HEIGHT = 13;
+MAX_EVENTS_SHOWN = 25;
+MAX_GOLD_WITHDRAW_DIGITS = 9;
+PENDING_GUILDBANK_PERMISSIONS = {};
+FRIENDS_BUTTON_HEADER_HEIGHT = 16;
+FRIENDS_BUTTON_NORMAL_HEIGHT = 34;
+FRIENDS_BUTTON_LARGE_HEIGHT = 48;
+FRIENDS_BUTTON_TYPE_HEADER = 1;
+FRIENDS_BUTTON_TYPE_BNET = 2;
+FRIENDS_BUTTON_TYPE_WOW = 3;
+FRIENDS_TEXTURE_ONLINE = "Interface\\FriendsFrame\\StatusIcon-Online";
+FRIENDS_TEXTURE_AFK = "Interface\\FriendsFrame\\StatusIcon-Away";
+FRIENDS_TEXTURE_DND = "Interface\\FriendsFrame\\StatusIcon-DnD";
+FRIENDS_TEXTURE_OFFLINE = "Interface\\FriendsFrame\\StatusIcon-Offline";
+FRIENDS_TEXTURE_BROADCAST = "Interface\\FriendsFrame\\BroadcastIcon";
+FRIENDS_BNET_NAME_COLOR = {r=0.510, g=0.773, b=1.0};
+FRIENDS_BNET_BACKGROUND_COLOR = {r=0, g=0.694, b=0.941, a=0.05};
+FRIENDS_WOW_NAME_COLOR = {r=0.996, g=0.882, b=0.361};
+FRIENDS_WOW_BACKGROUND_COLOR = {r=1.0, g=0.824, b=0.0, a=0.05};
+FRIENDS_GRAY_COLOR = {r=0.486, g=0.518, b=0.541};
+FRIENDS_OFFLINE_BACKGROUND_COLOR = {r=0.588, g=0.588, b=0.588, a=0.05};
+FRIENDS_PRESENCE_COLOR_CODE = "|cff7c848a";
+FRIENDS_BNET_NAME_COLOR_CODE = "|cff82c5ff";
+FRIENDS_BROADCAST_TIME_COLOR_CODE = "|cff4381a8"
+FRIENDS_WOW_NAME_COLOR_CODE = "|cfffde05c";
+FRIENDS_OTHER_NAME_COLOR_CODE = "|cff7b8489";
+SQUELCH_TYPE_IGNORE = 1;
+SQUELCH_TYPE_BLOCK_INVITE = 2;
+SQUELCH_TYPE_MUTE = 3;
+SQUELCH_TYPE_BLOCK_TOON = 4;
+FRIENDS_FRIENDS_POTENTIAL = 1;
+FRIENDS_FRIENDS_MUTUAL = 2;
+FRIENDS_FRIENDS_ALL = 3;
+BNET_CLIENT_WOW = "WoW";
+BNET_CLIENT_SC2 = "S2";
+FRIENDS_TOOLTIP_MAX_TOONS = 5;
+FRIENDS_TOOLTIP_MAX_WIDTH = 200;
+FRIENDS_TOOLTIP_MARGIN_WIDTH = 12;
+
+local FriendButtons = { };
+local BNetBroadcasts = { };
+local totalScrollHeight = 0;
+local numOnlineBroadcasts = 0;
+local numOfflineBroadcasts = 0;
+local PendingInvitesNew = { };
+local playerRealmName;
+local playerFactionGroup;
+
+WHOFRAME_DROPDOWN_LIST = {
+ {name = ZONE, sortType = "zone"},
+ {name = GUILD, sortType = "guild"},
+ {name = RACE, sortType = "race"}
+};
+
+FRIENDSFRAME_SUBFRAMES = { "FriendsListFrame", "IgnoreListFrame", "PendingListFrame", "WhoFrame", "GuildFrame", "ChannelFrame", "RaidFrame" };
+function FriendsFrame_ShowSubFrame(frameName)
+ for index, value in pairs(FRIENDSFRAME_SUBFRAMES) do
+ if ( value == frameName ) then
+ _G[value]:Show()
+ else
+ _G[value]:Hide();
+ end
+ end
+end
+
+function FriendsFrame_SummonButton_OnEvent (self, event, ...)
+ if ( event == "SPELL_UPDATE_COOLDOWN" and self:GetParent().id ) then
+ FriendsFrame_SummonButton_Update(self);
+ end
+end
+
+function FriendsFrame_SummonButton_OnShow (self)
+ FriendsFrame_SummonButton_Update(self);
+end
+
+function FriendsFrame_SummonButton_Update (self)
+ local id = self:GetParent().id;
+ if ( not id or (self:GetParent().buttonType ~= FRIENDS_BUTTON_TYPE_WOW) or not IsReferAFriendLinked(GetFriendInfo(id)) ) then
+ self:Hide();
+ return;
+ end
+
+ self:Show();
+
+ local start, duration = GetSummonFriendCooldown();
+
+ if ( duration > 0 ) then
+ self.duration = duration;
+ self.start = start;
+ else
+ self.duration = nil;
+ self.start = nil;
+ end
+
+ local enable = CanSummonFriend(GetFriendInfo(id));
+
+ local icon = _G[self:GetName().."Icon"];
+ local normalTexture = _G[self:GetName().."NormalTexture"];
+ if ( enable ) then
+ icon:SetVertexColor(1.0, 1.0, 1.0);
+ normalTexture:SetVertexColor(1.0, 1.0, 1.0);
+ else
+ icon:SetVertexColor(0.4, 0.4, 0.4);
+ normalTexture:SetVertexColor(1.0, 1.0, 1.0);
+ end
+ CooldownFrame_SetTimer(_G[self:GetName().."Cooldown"], start, duration, ((enable and 0) or 1));
+end
+
+function FriendsFrame_ClickSummonButton (self)
+ local name = GetFriendInfo(self:GetParent().id);
+ if ( CanSummonFriend(name) ) then
+ SummonFriend(name);
+ end
+end
+
+function FriendsFrame_ShowDropdown(name, connected, lineID, chatType, chatFrame, friendsList)
+ HideDropDownMenu(1);
+ if ( connected or friendsList ) then
+ if ( connected ) then
+ FriendsDropDown.initialize = FriendsFrameDropDown_Initialize;
+ else
+ FriendsDropDown.initialize = FriendsFrameOfflineDropDown_Initialize;
+ end
+
+ FriendsDropDown.displayMode = "MENU";
+ FriendsDropDown.name = name;
+ FriendsDropDown.friendsList = friendsList;
+ FriendsDropDown.lineID = lineID;
+ FriendsDropDown.chatType = chatType;
+ FriendsDropDown.chatTarget = name;
+ FriendsDropDown.chatFrame = chatFrame;
+ FriendsDropDown.presenceID = nil;
+ ToggleDropDownMenu(1, nil, FriendsDropDown, "cursor");
+ end
+end
+
+function FriendsFrame_ShowBNDropdown(name, connected, lineID, chatType, chatFrame, friendsList, presenceID)
+ if ( connected or friendsList ) then
+ if ( connected ) then
+ FriendsDropDown.initialize = FriendsFrameBNDropDown_Initialize;
+ else
+ FriendsDropDown.initialize = FriendsFrameBNOfflineDropDown_Initialize;
+ end
+ FriendsDropDown.displayMode = "MENU";
+ FriendsDropDown.name = name;
+ FriendsDropDown.friendsList = friendsList;
+ FriendsDropDown.lineID = lineID;
+ FriendsDropDown.chatType = chatType;
+ FriendsDropDown.chatTarget = name;
+ FriendsDropDown.chatFrame = chatFrame;
+ FriendsDropDown.presenceID = presenceID;
+ ToggleDropDownMenu(1, nil, FriendsDropDown, "cursor");
+ end
+end
+
+function FriendsFrameDropDown_Initialize()
+ UnitPopup_ShowMenu(UIDROPDOWNMENU_OPEN_MENU, "FRIEND", nil, FriendsDropDown.name);
+end
+
+function FriendsFrameOfflineDropDown_Initialize()
+ UnitPopup_ShowMenu(UIDROPDOWNMENU_OPEN_MENU, "FRIEND_OFFLINE", nil, FriendsDropDown.name);
+end
+
+function FriendsFrameBNDropDown_Initialize()
+ UnitPopup_ShowMenu(UIDROPDOWNMENU_OPEN_MENU, "BN_FRIEND", nil, FriendsDropDown.name);
+end
+
+function FriendsFrameBNOfflineDropDown_Initialize()
+ UnitPopup_ShowMenu(UIDROPDOWNMENU_OPEN_MENU, "BN_FRIEND_OFFLINE", nil, FriendsDropDown.name);
+end
+
+function FriendsFrame_OnLoad(self)
+ PanelTemplates_SetNumTabs(self, 5);
+ self.selectedTab = 1;
+ PanelTemplates_UpdateTabs(self);
+ self:RegisterEvent("FRIENDLIST_SHOW");
+ self:RegisterEvent("FRIENDLIST_UPDATE");
+ self:RegisterEvent("IGNORELIST_UPDATE");
+ self:RegisterEvent("MUTELIST_UPDATE");
+ self:RegisterEvent("WHO_LIST_UPDATE");
+ self:RegisterEvent("GUILD_ROSTER_UPDATE");
+ self:RegisterEvent("PLAYER_GUILD_UPDATE");
+ self:RegisterEvent("GUILD_MOTD");
+ self:RegisterEvent("VOICE_CHAT_ENABLED_UPDATE");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("PLAYER_FLAGS_CHANGED");
+ self:RegisterEvent("BN_FRIEND_LIST_SIZE_CHANGED");
+ self:RegisterEvent("BN_FRIEND_INFO_CHANGED");
+ self:RegisterEvent("BN_FRIEND_INVITE_LIST_INITIALIZED");
+ self:RegisterEvent("BN_FRIEND_INVITE_ADDED");
+ self:RegisterEvent("BN_FRIEND_INVITE_REMOVED");
+ self:RegisterEvent("BN_CUSTOM_MESSAGE_CHANGED");
+ self:RegisterEvent("BN_CUSTOM_MESSAGE_LOADED");
+ self:RegisterEvent("BN_SELF_ONLINE");
+ self:RegisterEvent("BN_BLOCK_LIST_UPDATED");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("BN_CONNECTED");
+ self:RegisterEvent("BN_DISCONNECTED");
+ self.playersInBotRank = 0;
+ self.playerStatusFrame = 1;
+ self.selectedFriend = 1;
+ self.selectedIgnore = 1;
+ self.guildStatus = 0;
+ GuildFrame.notesToggle = 1;
+ GuildFrame.selectedGuildMember = 0;
+ SetGuildRosterSelection(0);
+ CURRENT_GUILD_MOTD = GetGuildRosterMOTD();
+ GuildFrameNotesText:SetText(CURRENT_GUILD_MOTD);
+ GuildMemberDetailRankText:SetPoint("RIGHT", GuildFramePromoteButton, "LEFT");
+ -- friends list
+ DynamicScrollFrame_CreateButtons(FriendsFrameFriendsScrollFrame, "FriendsFrameButtonTemplate", FRIENDS_BUTTON_HEADER_HEIGHT, FriendsFrame_SetButton, FriendsFrame_GetTopButton);
+ FriendsFrameOfflineHeader:SetParent(FriendsFrameFriendsScrollFrameScrollChild);
+ FriendsFrameBroadcastInputClearButton.icon:SetVertexColor(FRIENDS_BNET_NAME_COLOR.r, FRIENDS_BNET_NAME_COLOR.g, FRIENDS_BNET_NAME_COLOR.b);
+ if ( not BNFeaturesEnabled() ) then
+ FriendsTabHeaderTab3:Hide();
+ FriendsFrameBroadcastInput:Hide();
+ FriendsFrameBattlenetStatus:Hide();
+ FriendsFrameStatusDropDown:Show();
+ end
+end
+
+function FriendsFrame_OnShow()
+ VoiceChat_Toggle();
+ FriendsList_Update();
+ FriendsFrame_Update();
+ UpdateMicroButtons();
+ PlaySound("igCharacterInfoTab");
+ GuildFrame.selectedGuildMember = 0;
+ SetGuildRosterSelection(0);
+ InGuildCheck();
+end
+
+function FriendsFrame_Update()
+ if ( FriendsFrame.selectedTab == 1 ) then
+ FriendsTabHeader:Show();
+ if ( FriendsTabHeader.selectedTab == 1 ) then
+ ShowFriends();
+ FriendsFrameTopLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-TopLeft-bnet");
+ FriendsFrameTopRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-TopRight-bnet");
+ FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrameMute-BotLeft-bnet");
+ FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrameMute-BotRight-bnet");
+ FriendsFrameTitleText:SetText(FRIENDS_LIST);
+ FriendsFrame_ShowSubFrame("FriendsListFrame");
+ elseif ( FriendsTabHeader.selectedTab == 3 ) then
+ FriendsFrameTopLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-TopLeft-bnet");
+ FriendsFrameTopRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-TopRight-bnet");
+ FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-Pending-BotRight");
+ FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-Pending-BotLeft");
+ FriendsFrameTitleText:SetText(PENDING_INVITE_LIST);
+ FriendsFrame_ShowSubFrame("PendingListFrame");
+ else
+ FriendsFrameTopLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-TopLeft-bnet");
+ FriendsFrameTopRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-TopRight-bnet");
+ if ( IsVoiceChatEnabled() ) then
+ FriendsFrameMutePlayerButton:Show();
+ FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrameThree-BotLeft-bnet");
+ FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrameThree-BotRight-bnet");
+ FriendsFrameIgnorePlayerButton:SetWidth(110);
+ FriendsFrameUnsquelchButton:SetWidth(111);
+ else
+ FriendsFrameMutePlayerButton:Hide();
+ FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrameMute-BotLeft-bnet");
+ FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrameMute-BotRight-bnet");
+ FriendsFrameIgnorePlayerButton:SetWidth(131);
+ FriendsFrameUnsquelchButton:SetWidth(134);
+ end
+ FriendsFrameTitleText:SetText(IGNORE_LIST);
+ FriendsFrame_ShowSubFrame("IgnoreListFrame");
+ IgnoreList_Update();
+ end
+ else
+ FriendsTabHeader:Hide();
+ if ( FriendsFrame.selectedTab == 2 ) then
+ FriendsFrameTopLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopLeft");
+ FriendsFrameTopRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopRight");
+ FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\WhoFrame-BotLeft");
+ FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\WhoFrame-BotRight");
+ FriendsFrameTitleText:SetText(WHO_LIST);
+ FriendsFrame_ShowSubFrame("WhoFrame");
+ WhoList_Update();
+ elseif ( FriendsFrame.selectedTab == 3 ) then
+ FriendsFrameTopLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopLeft");
+ FriendsFrameTopRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopRight");
+ FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\GuildFrame-BotLeft");
+ FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\GuildFrame-BotRight");
+ local guildName, title, rank = GetGuildInfo("player");
+ if ( guildName ) then
+ FriendsFrameTitleText:SetFormattedText(GUILD_TITLE_TEMPLATE, title, guildName);
+ else
+ FriendsFrameTitleText:SetText("");
+ end
+ GuildStatus_Update();
+ FriendsFrame_ShowSubFrame("GuildFrame");
+ elseif ( FriendsFrame.selectedTab == 4 ) then
+ FriendsFrameTopLeft:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft");
+ FriendsFrameTopRight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight");
+ FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\UI-ChannelFrame-BotLeft");
+ FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\UI-ChannelFrame-BotRight");
+ FriendsFrameTitleText:SetText(CHAT_CHANNELS);
+ FriendsFrame_ShowSubFrame("ChannelFrame");
+ elseif ( FriendsFrame.selectedTab == 5 ) then
+ FriendsFrameTopLeft:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft");
+ FriendsFrameTopRight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight");
+ FriendsFrameBottomLeft:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomLeft");
+ FriendsFrameBottomRight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomRight");
+ FriendsFrameTitleText:SetText(RAID);
+ FriendsFrame_ShowSubFrame("RaidFrame");
+ end
+ end
+end
+
+function FriendsFrame_OnHide()
+ UpdateMicroButtons();
+ PlaySound("igMainMenuClose");
+ SetGuildRosterSelection(0);
+ GuildFrame.selectedGuildMember = 0;
+ GuildFramePopup_HideAll();
+ RaidInfoFrame:Hide();
+ for index, value in pairs(FRIENDSFRAME_SUBFRAMES) do
+ _G[value]:Hide();
+ end
+end
+
+function FriendsList_Update()
+ local numBNetTotal, numBNetOnline = BNGetNumFriends();
+ local numBNetOffline = numBNetTotal - numBNetOnline;
+ local numWoWTotal, numWoWOnline = GetNumFriends();
+ local numWoWOffline = numWoWTotal - numWoWOnline;
+
+ FriendsMicroButtonCount:SetText(numBNetOnline + numWoWOnline);
+ if ( not FriendsListFrame:IsShown() ) then
+ return;
+ end
+
+ local buttonCount = numBNetTotal + numWoWTotal;
+ local haveHeader;
+
+ totalScrollHeight = 0;
+ if ( numBNetOnline > 0 or numWoWOnline > 0 ) then
+ totalScrollHeight = totalScrollHeight + (numBNetOnline + numWoWOnline) * FRIENDS_BUTTON_NORMAL_HEIGHT + numOnlineBroadcasts * (FRIENDS_BUTTON_LARGE_HEIGHT - FRIENDS_BUTTON_NORMAL_HEIGHT);
+ end
+ if ( numBNetOffline > 0 or numWoWOffline > 0 ) then
+ totalScrollHeight = totalScrollHeight + (numBNetOffline + numWoWOffline) * FRIENDS_BUTTON_NORMAL_HEIGHT + numOfflineBroadcasts * (FRIENDS_BUTTON_LARGE_HEIGHT - FRIENDS_BUTTON_NORMAL_HEIGHT);
+ -- use a header if there are online and offline friends
+ if ( numBNetOnline > 0 or numWoWOnline > 0 ) then
+ haveHeader = true;
+ buttonCount = buttonCount + 1;
+ totalScrollHeight = totalScrollHeight + FRIENDS_BUTTON_HEADER_HEIGHT;
+ end
+ end
+ if ( buttonCount > #FriendButtons ) then
+ for i = #FriendButtons + 1, buttonCount do
+ FriendButtons[i] = { };
+ end
+ end
+
+ local index = 0;
+ -- online Battlenet friends
+ for i = 1, numBNetOnline do
+ index = index + 1;
+ FriendButtons[index].buttonType = FRIENDS_BUTTON_TYPE_BNET;
+ FriendButtons[index].id = i;
+ end
+ -- online WoW friends
+ for i = 1, numWoWOnline do
+ index = index + 1;
+ FriendButtons[index].buttonType = FRIENDS_BUTTON_TYPE_WOW;
+ FriendButtons[index].id = i;
+ end
+ -- offline header
+ if ( haveHeader ) then
+ index = index + 1;
+ FriendButtons[index].buttonType = FRIENDS_BUTTON_TYPE_HEADER;
+ end
+ -- offline Battlenet friends
+ for i = 1, numBNetOffline do
+ index = index + 1;
+ FriendButtons[index].buttonType = FRIENDS_BUTTON_TYPE_BNET;
+ FriendButtons[index].id = i + numBNetOnline;
+ end
+ -- offline WoW friends
+ for i = 1, numWoWOffline do
+ index = index + 1;
+ FriendButtons[index].buttonType = FRIENDS_BUTTON_TYPE_WOW;
+ FriendButtons[index].id = i + numWoWOnline;
+ end
+
+ -- selection
+ local selectedFriend = 0;
+ -- check that we have at least 1 friend
+ if ( index > 0 ) then
+ -- get friend
+ if ( FriendsFrame.selectedFriendType == FRIENDS_BUTTON_TYPE_WOW ) then
+ selectedFriend = GetSelectedFriend();
+ elseif ( FriendsFrame.selectedFriendType == FRIENDS_BUTTON_TYPE_BNET ) then
+ selectedFriend = BNGetSelectedFriend();
+ end
+ -- set to first in list if no friend
+ if ( selectedFriend == 0 ) then
+ FriendsFrame_SelectFriend(FriendButtons[1].buttonType, 1);
+ selectedFriend = 1;
+ end
+ -- check if friend is online
+ local isOnline;
+ if ( FriendsFrame.selectedFriendType == FRIENDS_BUTTON_TYPE_WOW ) then
+ local name, level, class, area;
+ name, level, class, area, isOnline = GetFriendInfo(selectedFriend);
+ elseif ( FriendsFrame.selectedFriendType == FRIENDS_BUTTON_TYPE_BNET ) then
+ local presenceID, givenName, surname, toonName, toonID, client;
+ presenceID, givenName, surname, toonName, toonID, client, isOnline = BNGetFriendInfo(selectedFriend);
+ if ( not givenName or not surname ) then
+ isOnline = false;
+ end
+ end
+ if ( isOnline ) then
+ FriendsFrameSendMessageButton:Enable();
+ else
+ FriendsFrameSendMessageButton:Disable();
+ end
+ else
+ FriendsFrameSendMessageButton:Disable();
+ end
+ FriendsFrame.selectedFriend = selectedFriend;
+
+ DynamicScrollFrame_Update(FriendsFrameFriendsScrollFrame);
+end
+
+function IgnoreList_Update()
+ local button;
+ local numIgnores = GetNumIgnores();
+ local numBlocks = BNGetNumBlocked();
+ local numToonBlocks = BNGetNumBlockedToons();
+ local numMutes = 0;
+ if ( IsVoiceChatEnabled() ) then
+ numMutes = GetNumMutes();
+ end
+ -- Headers stuff
+ local ignoredHeader, blockedHeader, mutedHeader, blockedToonHeader;
+ if ( numIgnores > 0 ) then
+ ignoredHeader = 1;
+ else
+ ignoredHeader = 0;
+ end
+ if ( numBlocks > 0 ) then
+ blockedHeader = 1;
+ else
+ blockedHeader = 0;
+ end
+ if ( numToonBlocks > 0 ) then
+ blockedToonHeader = 1;
+ else
+ blockedToonHeader = 0;
+ end
+ if ( numMutes > 0 ) then
+ mutedHeader = 1;
+ else
+ mutedHeader = 0;
+ end
+
+ local lastIgnoredIndex = numIgnores + ignoredHeader;
+ local lastBlockedIndex = lastIgnoredIndex + numBlocks + blockedHeader;
+ local lastBlockedToonIndex = lastBlockedIndex + numToonBlocks + blockedToonHeader;
+ local lastMutedIndex = lastBlockedToonIndex + numMutes + mutedHeader;
+ local numEntries = lastMutedIndex;
+
+ FriendsFrameIgnoredHeader:Hide();
+ FriendsFrameBlockedInviteHeader:Hide();
+ FriendsFrameBlockedToonHeader:Hide();
+ FriendsFrameMutedHeader:Hide();
+
+ -- selection stuff
+ local selectedSquelchType = FriendsFrame.selectedSquelchType;
+ local selectedSquelchIndex = 0 ;
+ if ( selectedSquelchType == SQUELCH_TYPE_IGNORE ) then
+ selectedSquelchIndex = GetSelectedIgnore();
+ elseif ( selectedSquelchType == SQUELCH_TYPE_BLOCK_INVITE ) then
+ selectedSquelchIndex = BNGetSelectedBlock();
+ elseif ( selectedSquelchType == SQUELCH_TYPE_BLOCK_TOON ) then
+ selectedSquelchIndex = BNGetSelectedToonBlock();
+ elseif ( selectedSquelchType == SQUELCH_TYPE_MUTE ) then
+ selectedSquelchIndex = GetSelectedMute();
+ end
+ if ( selectedSquelchIndex == 0 ) then
+ if ( numIgnores > 0 ) then
+ FriendsFrame_SelectSquelched(SQUELCH_TYPE_IGNORE, 1);
+ selectedSquelchType = SQUELCH_TYPE_IGNORE;
+ selectedSquelchIndex = 1;
+ elseif ( numBlocks > 0 ) then
+ FriendsFrame_SelectSquelched(SQUELCH_TYPE_BLOCK_INVITE, 1);
+ selectedSquelchType = SQUELCH_TYPE_BLOCK_INVITE;
+ selectedSquelchIndex = 1;
+ elseif ( numToonBlocks > 0 ) then
+ FriendsFrame_SelectSquelched(SQUELCH_TYPE_BLOCK_TOON, 1);
+ selectedSquelchType = SQUELCH_TYPE_BLOCK_TOON;
+ selectedSquelchIndex = 1;
+ elseif ( numMutes > 0 ) then
+ FriendsFrame_SelectSquelched(SQUELCH_TYPE_MUTE, 1);
+ selectedSquelchType = SQUELCH_TYPE_MUTE;
+ selectedSquelchIndex = 1;
+ end
+ end
+ if ( selectedSquelchIndex > 0 ) then
+ FriendsFrameUnsquelchButton:Enable();
+ else
+ FriendsFrameUnsquelchButton:Disable();
+ end
+
+ local scrollOffset = FauxScrollFrame_GetOffset(FriendsFrameIgnoreScrollFrame);
+ local squelchedIndex;
+ for i = 1, IGNORES_TO_DISPLAY, 1 do
+ squelchedIndex = i + scrollOffset;
+ button = _G["FriendsFrameIgnoreButton"..i];
+ button.type = nil;
+ if ( squelchedIndex == ignoredHeader ) then
+ -- ignored header
+ IgnoreList_SetHeader(FriendsFrameIgnoredHeader, button);
+ elseif ( squelchedIndex <= lastIgnoredIndex ) then
+ -- ignored
+ button.index = squelchedIndex - ignoredHeader;
+ button.name:SetText(GetIgnoreName(button.index));
+ button.type = SQUELCH_TYPE_IGNORE;
+ elseif ( blockedHeader == 1 and squelchedIndex == lastIgnoredIndex + 1 ) then
+ -- blocked header
+ IgnoreList_SetHeader(FriendsFrameBlockedInviteHeader, button);
+ elseif ( squelchedIndex <= lastBlockedIndex ) then
+ -- blocked
+ button.index = squelchedIndex - lastIgnoredIndex - blockedHeader;
+ local blockID, blockName = BNGetBlockedInfo(button.index);
+ button.name:SetText(blockName);
+ button.type = SQUELCH_TYPE_BLOCK_INVITE;
+ elseif ( blockedToonHeader == 1 and squelchedIndex == lastBlockedIndex + 1 ) then
+ -- blocked TOON header
+ IgnoreList_SetHeader(FriendsFrameBlockedToonHeader, button);
+ elseif ( squelchedIndex <= lastBlockedToonIndex ) then
+ -- blocked TOON
+ button.index = squelchedIndex - lastBlockedIndex - blockedToonHeader;
+ local blockID, blockName = BNGetBlockedToonInfo(button.index);
+ button.name:SetText(blockName);
+ button.type = SQUELCH_TYPE_BLOCK_TOON;
+ elseif ( mutedHeader == 1 and squelchedIndex == lastBlockedToonIndex + 1 ) then
+ -- muted header
+ IgnoreList_SetHeader(FriendsFrameMutedHeader, button);
+ elseif ( squelchedIndex <= lastMutedIndex ) then
+ -- muted
+ button.index = squelchedIndex - lastBlockedToonIndex - mutedHeader;
+ button.name:SetText(GetMuteName(button.index));
+ button.type = SQUELCH_TYPE_MUTE;
+ end
+ if ( selectedSquelchType == button.type and selectedSquelchIndex == button.index ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+ if ( squelchedIndex > numEntries ) then
+ button:Hide();
+ else
+ button:Show();
+ end
+ end
+ -- ScrollFrame stuff
+ FauxScrollFrame_Update(FriendsFrameIgnoreScrollFrame, numEntries, IGNORES_TO_DISPLAY, FRIENDS_FRAME_IGNORE_HEIGHT );
+end
+
+function IgnoreList_SetHeader(header, parent)
+ parent.name:SetText("");
+ header:SetParent(parent);
+ header:SetPoint("TOPLEFT", parent, 0, 0);
+ header:Show();
+end
+
+function PendingListFrame_OnShow(self)
+ PendingList_Update();
+end
+
+function PendingList_Update(newInvite)
+ local numPending = BNGetNumFriendInvites();
+
+ PendingList_UpdateTab();
+ if ( numPending > 0 ) then
+ if ( not GetCVarBool("pendingInviteInfoShown") ) then
+ PendingListInfoFrame:SetFrameLevel(FriendsFramePendingButton1:GetFrameLevel() + 1);
+ PendingListInfoFrame:Show();
+ end
+
+ local scrollFrame = FriendsFramePendingScrollFrame;
+ local buttonHeight, message, _;
+ local heightLeft = scrollFrame.scrollHeight;
+ local scrollBar = scrollFrame.scrollBar;
+
+ FriendsFramePendingButton1.message:SetHeight(0);
+ for i = numPending, 1, -1 do
+ buttonHeight = PENDING_BUTTON_MIN_HEIGHT;
+ _, _, _, message = BNGetFriendInviteInfo(i);
+ if ( message and message ~= "" ) then
+ FriendsFramePendingButton1.message:SetText(message);
+ local textHeight = min(FriendsFramePendingButton1.message:GetHeight(), MAX_INVITE_MESSAGE_HEIGHT);
+ buttonHeight = buttonHeight + textHeight;
+ end
+ heightLeft = heightLeft - buttonHeight;
+ if ( heightLeft <= 0 ) then
+ -- one less notch on the scrollbar if it's a perfect fit
+ if ( heightLeft == 0 ) then
+ i = i - 1;
+ end
+ local value = scrollBar:GetValue();
+ scrollFrame.extraHeight = -heightLeft;
+ scrollFrame.max = i;
+ scrollBar:Show();
+ scrollBar:SetMinMaxValues(0, i);
+ if ( newInvite ) then
+ -- adjust the scroll if the user is looking at the frame, otherwise jump it to the top
+ if ( PendingListFrame:IsShown() ) then
+ scrollBar:SetValue(value + 1);
+ else
+ scrollBar:SetValue(0)
+ end
+ elseif ( value <= i ) then
+ scrollBar:SetValue(value);
+ PendingList_Scroll(value);
+ end
+ return;
+ end
+ end
+ -- not enough buttons to have a scrollbar
+ scrollFrame.extraHeight = 0;
+ scrollFrame.max = numPending;
+ scrollBar:Hide();
+ scrollBar:SetValue(0);
+ end
+ PendingList_Scroll(0);
+end
+
+function PendingList_Scroll(offset)
+ local button, buttonHeight;
+ local name, surname, message;
+ local heightUsed = 0;
+ local scrollFrame = FriendsFramePendingScrollFrame;
+ local scrollHeight = scrollFrame.scrollHeight;
+ local max = scrollFrame.max;
+ local numPending = BNGetNumFriendInvites();
+ offset = offset or scrollFrame.scrollBar:GetValue();
+ -- if scrolled to the bottom and there would be a button partially showing, start with it and "scroll" it up
+ if ( offset == max and scrollFrame.extraHeight > 0 ) then
+ offset = offset - 1;
+ _G["FriendsFramePendingButton1"]:SetPoint("TOPLEFT", 0, scrollFrame.extraHeight);
+ heightUsed = heightUsed - scrollFrame.extraHeight;
+ else
+ _G["FriendsFramePendingButton1"]:SetPoint("TOPLEFT", 0, 0);
+ end
+ for i = 1, PENDING_INVITES_TO_DISPLAY do
+ button = _G["FriendsFramePendingButton"..i];
+ offset = offset + 1;
+ if ( offset > numPending or heightUsed > scrollHeight ) then
+ button:Hide();
+ else
+ inviteID, givenName, surname, message, timeSent, days = BNGetFriendInviteInfo(offset);
+ button.index = offset;
+ button.inviteID = inviteID;
+ buttonHeight = PENDING_BUTTON_MIN_HEIGHT;
+ if ( givenName and surname ) then
+ button.name:SetFormattedText(BATTLENET_NAME_FORMAT, givenName, surname);
+ else
+ button.name:SetText(UNKNOWN);
+ end
+ if ( message ) then
+ button.message:SetHeight(0);
+ button.message:SetText(message);
+ local textHeight = button.message:GetHeight();
+ if ( textHeight > MAX_INVITE_MESSAGE_HEIGHT ) then
+ textHeight = MAX_INVITE_MESSAGE_HEIGHT;
+ button.message:SetHeight(textHeight);
+ end
+ buttonHeight = buttonHeight + textHeight;
+ else
+ button.message:SetText("");
+ button.message:SetHeight(0);
+ end
+ if ( timeSent and timeSent ~= 0 ) then
+ button.sent:SetFormattedText(BNET_INVITE_SENT_TIME, FriendsFrame_GetLastOnline(timeSent));
+ else
+ button.sent:SetText("");
+ end
+ button:SetHeight(buttonHeight);
+ heightUsed = heightUsed + buttonHeight;
+ if ( PendingInvitesNew["all"] or PendingInvitesNew[inviteID] ) then
+ button.highlight:Show();
+ else
+ button.highlight:Hide();
+ end
+ button:Show();
+ end
+ end
+end
+
+function FriendsFramePendingScrollFrame_AdjustScroll(delta)
+ local scrollBar = FriendsFramePendingScrollFrame.scrollBar;
+ if ( scrollBar:IsShown() ) then
+ scrollBar:SetValue(scrollBar:GetValue() + delta);
+ end
+end
+
+function PendingListFrame_OnHide()
+ table.wipe(PendingInvitesNew);
+ PendingList_UpdateTab();
+end
+
+function PendingListFrame_BlockCommunication(self)
+ local inviteID, name, surname, message = BNGetFriendInviteInfo(self:GetParent().index);
+ local dialog = StaticPopup_Show("CONFIRM_BLOCK_INVITES", string.format(BATTLENET_NAME_FORMAT, name, surname));
+ if ( dialog ) then
+ dialog.data = inviteID;
+ end
+end
+
+function PendingListFrame_ReportSpam(self)
+ local inviteID, name, surname, message = BNGetFriendInviteInfo(self:GetParent().index);
+ local dialog = StaticPopup_Show("CONFIRM_REPORT_SPAM_INVITE", string.format(BATTLENET_NAME_FORMAT, name, surname));
+ if ( dialog ) then
+ dialog.data = inviteID;
+ end
+end
+
+function PendingListFrame_ReportPlayer(self)
+ ToggleDropDownMenu(1, self:GetParent().index, PendingListFrameDropDown, "cursor", 3, -3)
+end
+
+function PendingListFrameDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, PendingListFrameDropDown_Initialize, "MENU");
+end
+
+function PendingListFrameDropDown_Initialize(self)
+ UnitPopup_ShowMenu(self, "BN_REPORT", nil, BNET_REPORT);
+end
+
+function PendingList_UpdateTab()
+ local numPending = BNGetNumFriendInvites();
+ if ( numPending > 0 ) then
+ FriendsTabHeaderTab3:SetText(PENDING_INVITE.." ("..numPending..")");
+ if ( next(PendingInvitesNew) and FriendsTabHeader.selectedTab ~= 3 and not FriendsTabHeaderTab3:IsMouseOver() ) then
+ FriendsTabHeaderInviteAlert:Show();
+ else
+ FriendsTabHeaderInviteAlert:Hide();
+ end
+ else
+ FriendsTabHeaderTab3:SetText(PENDING_INVITE);
+ FriendsTabHeaderInviteAlert:Hide();
+ end
+ PanelTemplates_TabResize(FriendsTabHeaderTab3, 0);
+end
+
+function WhoList_Update()
+ local numWhos, totalCount = GetNumWhoResults();
+ local name, guild, level, race, class, zone;
+ local button, buttonText, classTextColor, classFileName;
+ local columnTable;
+ local whoOffset = FauxScrollFrame_GetOffset(WhoListScrollFrame);
+ local whoIndex;
+ local showScrollBar = nil;
+ if ( numWhos > WHOS_TO_DISPLAY ) then
+ showScrollBar = 1;
+ end
+ local displayedText = "";
+ if ( totalCount > MAX_WHOS_FROM_SERVER ) then
+ displayedText = format(WHO_FRAME_SHOWN_TEMPLATE, MAX_WHOS_FROM_SERVER);
+ end
+ WhoFrameTotals:SetText(format(WHO_FRAME_TOTAL_TEMPLATE, totalCount).." "..displayedText);
+ for i=1, WHOS_TO_DISPLAY, 1 do
+ whoIndex = whoOffset + i;
+ button = _G["WhoFrameButton"..i];
+ button.whoIndex = whoIndex;
+ name, guild, level, race, class, zone, classFileName = GetWhoInfo(whoIndex);
+ columnTable = { zone, guild, race };
+
+ if ( classFileName ) then
+ classTextColor = RAID_CLASS_COLORS[classFileName];
+ else
+ classTextColor = HIGHLIGHT_FONT_COLOR;
+ end
+ buttonText = _G["WhoFrameButton"..i.."Name"];
+ buttonText:SetText(name);
+ buttonText = _G["WhoFrameButton"..i.."Level"];
+ buttonText:SetText(level);
+ buttonText = _G["WhoFrameButton"..i.."Class"];
+ buttonText:SetText(class);
+ buttonText:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b);
+ local variableText = _G["WhoFrameButton"..i.."Variable"];
+ variableText:SetText(columnTable[UIDropDownMenu_GetSelectedID(WhoFrameDropDown)]);
+
+ -- If need scrollbar resize columns
+ if ( showScrollBar ) then
+ variableText:SetWidth(95);
+ else
+ variableText:SetWidth(110);
+ end
+
+ -- Highlight the correct who
+ if ( WhoFrame.selectedWho == whoIndex ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+
+ if ( whoIndex > numWhos ) then
+ button:Hide();
+ else
+ button:Show();
+ end
+ end
+
+ if ( not WhoFrame.selectedWho ) then
+ WhoFrameGroupInviteButton:Disable();
+ WhoFrameAddFriendButton:Disable();
+ else
+ WhoFrameGroupInviteButton:Enable();
+ WhoFrameAddFriendButton:Enable();
+ WhoFrame.selectedName = GetWhoInfo(WhoFrame.selectedWho);
+ end
+
+ -- If need scrollbar resize columns
+ if ( showScrollBar ) then
+ WhoFrameColumn_SetWidth(WhoFrameColumnHeader2, 105);
+ UIDropDownMenu_SetWidth(WhoFrameDropDown, 80);
+ else
+ WhoFrameColumn_SetWidth(WhoFrameColumnHeader2, 120);
+ UIDropDownMenu_SetWidth(WhoFrameDropDown, 95);
+ end
+
+ -- ScrollFrame update
+ FauxScrollFrame_Update(WhoListScrollFrame, numWhos, WHOS_TO_DISPLAY, FRIENDS_FRAME_WHO_HEIGHT );
+
+ PanelTemplates_SetTab(FriendsFrame, 2);
+ ShowUIPanel(FriendsFrame);
+end
+
+function GuildStatus_Update()
+ -- Set the tab
+ PanelTemplates_SetTab(FriendsFrame, 3);
+ -- Show the frame
+ ShowUIPanel(FriendsFrame);
+ -- Number of players in the lowest rank
+ FriendsFrame.playersInBotRank = 0;
+
+ local numGuildMembers = GetNumGuildMembers();
+ local name, rank, rankIndex, level, class, zone, note, officernote, online, status, classFileName;
+ local guildName, guildRankName, guildRankIndex = GetGuildInfo("player");
+ local maxRankIndex = GuildControlGetNumRanks() - 1;
+ local button, buttonText, classTextColor;
+ local onlinecount = 0;
+ local guildIndex;
+
+ -- Get selected guild member info
+ name, rank, rankIndex, level, class, zone, note, officernote, online = GetGuildRosterInfo(GetGuildRosterSelection());
+ GuildFrame.selectedName = name;
+ -- If there's a selected guildmember
+ if ( GetGuildRosterSelection() > 0 ) then
+ -- Update the guild member details frame
+ GuildMemberDetailName:SetText(GuildFrame.selectedName);
+ GuildMemberDetailLevel:SetFormattedText(FRIENDS_LEVEL_TEMPLATE, level, class);
+ GuildMemberDetailZoneText:SetText(zone);
+ GuildMemberDetailRankText:SetText(rank);
+ if ( online ) then
+ GuildMemberDetailOnlineText:SetText(GUILD_ONLINE_LABEL);
+ else
+ GuildMemberDetailOnlineText:SetText(GuildFrame_GetLastOnline(GetGuildRosterSelection()));
+ end
+ -- Update public note
+ if ( CanEditPublicNote() ) then
+ PersonalNoteText:SetTextColor(1.0, 1.0, 1.0);
+ if ( (not note) or (note == "") ) then
+ note = GUILD_NOTE_EDITLABEL;
+ end
+ else
+ PersonalNoteText:SetTextColor(0.65, 0.65, 0.65);
+ end
+ GuildMemberNoteBackground:EnableMouse(CanEditPublicNote());
+ PersonalNoteText:SetText(note);
+ -- Update officer note
+ if ( CanViewOfficerNote() ) then
+ if ( CanEditOfficerNote() ) then
+ if ( (not officernote) or (officernote == "") ) then
+ officernote = GUILD_OFFICERNOTE_EDITLABEL;
+ end
+ OfficerNoteText:SetTextColor(1.0, 1.0, 1.0);
+ else
+ OfficerNoteText:SetTextColor(0.65, 0.65, 0.65);
+ end
+ GuildMemberOfficerNoteBackground:EnableMouse(CanEditOfficerNote());
+ OfficerNoteText:SetText(officernote);
+
+ -- Resize detail frame
+ GuildMemberDetailOfficerNoteLabel:Show();
+ GuildMemberOfficerNoteBackground:Show();
+ GuildMemberDetailFrame:SetHeight(GUILD_DETAIL_OFFICER_HEIGHT);
+ else
+ GuildMemberDetailOfficerNoteLabel:Hide();
+ GuildMemberOfficerNoteBackground:Hide();
+ GuildMemberDetailFrame:SetHeight(GUILD_DETAIL_NORM_HEIGHT);
+ end
+
+ -- Manage guild member related buttons
+ if ( CanGuildPromote() and ( rankIndex > 1 ) and ( rankIndex > (guildRankIndex + 1) ) ) then
+ GuildFramePromoteButton:Enable();
+ else
+ GuildFramePromoteButton:Disable();
+ end
+ if ( CanGuildDemote() and ( rankIndex >= 1 ) and ( rankIndex > guildRankIndex ) and ( rankIndex ~= maxRankIndex ) ) then
+ GuildFrameDemoteButton:Enable();
+ else
+ GuildFrameDemoteButton:Disable();
+ end
+ -- Hide promote/demote buttons if both disabled
+ if ( GuildFrameDemoteButton:IsEnabled() == 0 and GuildFramePromoteButton:IsEnabled() == 0 ) then
+ GuildFramePromoteButton:Hide();
+ GuildFrameDemoteButton:Hide();
+ else
+ GuildFramePromoteButton:Show();
+ GuildFrameDemoteButton:Show();
+ end
+ if ( CanGuildRemove() and ( rankIndex >= 1 ) and ( rankIndex > guildRankIndex ) ) then
+ GuildMemberRemoveButton:Enable();
+ else
+ GuildMemberRemoveButton:Disable();
+ end
+ if ( (UnitName("player") == name) or (not online) ) then
+ GuildMemberGroupInviteButton:Disable();
+ else
+ GuildMemberGroupInviteButton:Enable();
+ end
+
+ GuildFrame.selectedName = GetGuildRosterInfo(GetGuildRosterSelection());
+ else
+ GuildMemberDetailFrame:Hide();
+ end
+
+ -- Message of the day stuff
+ local guildMOTD = GetGuildRosterMOTD();
+ if ( CanEditMOTD() ) then
+ if ( (not guildMOTD) or (guildMOTD == "") ) then
+ guildMOTD = GUILD_MOTD_EDITLABEL;
+ end
+ GuildFrameNotesText:SetTextColor(1.0, 1.0, 1.0);
+ GuildMOTDEditButton:Enable();
+ else
+ GuildFrameNotesText:SetTextColor(0.65, 0.65, 0.65);
+ GuildMOTDEditButton:Disable();
+ end
+ GuildFrameNotesText:SetText(CURRENT_GUILD_MOTD);
+
+ -- Scrollbar stuff
+ local showScrollBar = nil;
+ if ( numGuildMembers > GUILDMEMBERS_TO_DISPLAY ) then
+ showScrollBar = 1;
+ end
+
+ -- Get number of online members
+ for i=1, numGuildMembers, 1 do
+ name, rank, rankIndex, level, class, zone, note, officernote, online = GetGuildRosterInfo(i);
+ if ( online ) then
+ onlinecount = onlinecount + 1;
+ end
+ if ( rankIndex == maxRankIndex ) then
+ FriendsFrame.playersInBotRank = FriendsFrame.playersInBotRank + 1;
+ end
+ end
+ GuildFrameTotals:SetFormattedText(GUILD_TOTAL, numGuildMembers);
+ GuildFrameOnlineTotals:SetFormattedText(GUILD_TOTALONLINE, onlinecount);
+
+ -- Update global guild frame buttons
+ if ( IsGuildLeader() ) then
+ GuildFrameControlButton:Enable();
+ else
+ GuildFrameControlButton:Disable();
+ end
+ if ( CanGuildInvite() ) then
+ GuildFrameAddMemberButton:Enable();
+ else
+ GuildFrameAddMemberButton:Disable();
+ end
+
+
+ if ( FriendsFrame.playerStatusFrame ) then
+ -- Player specific info
+ local guildOffset = FauxScrollFrame_GetOffset(GuildListScrollFrame);
+
+ for i=1, GUILDMEMBERS_TO_DISPLAY, 1 do
+ guildIndex = guildOffset + i;
+ button = _G["GuildFrameButton"..i];
+ button.guildIndex = guildIndex;
+ name, rank, rankIndex, level, class, zone, note, officernote, online, status, classFileName = GetGuildRosterInfo(guildIndex);
+
+ if ( not online ) then
+ buttonText = _G["GuildFrameButton"..i.."Name"];
+ buttonText:SetText(name);
+ buttonText:SetTextColor(0.5, 0.5, 0.5);
+ buttonText = _G["GuildFrameButton"..i.."Zone"];
+ buttonText:SetText(zone);
+ buttonText:SetTextColor(0.5, 0.5, 0.5);
+ buttonText = _G["GuildFrameButton"..i.."Level"];
+ buttonText:SetText(level);
+ buttonText:SetTextColor(0.5, 0.5, 0.5);
+ buttonText = _G["GuildFrameButton"..i.."Class"];
+ buttonText:SetText(class);
+ buttonText:SetTextColor(0.5, 0.5, 0.5);
+ else
+ if ( classFileName ) then
+ classTextColor = RAID_CLASS_COLORS[classFileName];
+ else
+ classTextColor = NORMAL_FONT_COLOR;
+ end
+
+ buttonText = _G["GuildFrameButton"..i.."Name"];
+ buttonText:SetText(name);
+ buttonText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ buttonText = _G["GuildFrameButton"..i.."Zone"];
+ buttonText:SetText(zone);
+ buttonText:SetTextColor(1.0, 1.0, 1.0);
+ buttonText = _G["GuildFrameButton"..i.."Level"];
+ buttonText:SetText(level);
+ buttonText:SetTextColor(1.0, 1.0, 1.0);
+ buttonText = _G["GuildFrameButton"..i.."Class"];
+ buttonText:SetText(class);
+ buttonText:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b);
+ end
+
+ -- If need scrollbar resize columns
+ if ( showScrollBar ) then
+ _G["GuildFrameButton"..i.."Zone"]:SetWidth(95);
+ else
+ _G["GuildFrameButton"..i.."Zone"]:SetWidth(110);
+ end
+
+ -- Highlight the correct who
+ if ( GetGuildRosterSelection() == guildIndex ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+
+ if ( guildIndex > numGuildMembers ) then
+ button:Hide();
+ else
+ button:Show();
+ end
+ end
+
+ GuildFrameGuildListToggleButton:SetText(PLAYER_STATUS);
+ -- If need scrollbar resize column headers
+ if ( showScrollBar ) then
+ WhoFrameColumn_SetWidth(GuildFrameColumnHeader2, 105);
+ GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 284, -67);
+ else
+ WhoFrameColumn_SetWidth(GuildFrameColumnHeader2, 120);
+ GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 307, -67);
+ end
+ -- ScrollFrame update
+ FauxScrollFrame_Update(GuildListScrollFrame, numGuildMembers, GUILDMEMBERS_TO_DISPLAY, FRIENDS_FRAME_GUILD_HEIGHT );
+
+ GuildPlayerStatusFrame:Show();
+ GuildStatusFrame:Hide();
+ else
+ -- Guild specific info
+ local year, month, day, hour;
+ local yearlabel, monthlabel, daylabel, hourlabel;
+ local guildOffset = FauxScrollFrame_GetOffset(GuildListScrollFrame);
+ local classFileName;
+
+ for i=1, GUILDMEMBERS_TO_DISPLAY, 1 do
+ guildIndex = guildOffset + i;
+ button = _G["GuildFrameGuildStatusButton"..i];
+ button.guildIndex = guildIndex;
+ name, rank, rankIndex, level, class, zone, note, officernote, online, status, classFileName = GetGuildRosterInfo(guildIndex);
+
+ _G["GuildFrameGuildStatusButton"..i.."Name"]:SetText(name);
+ _G["GuildFrameGuildStatusButton"..i.."Rank"]:SetText(rank);
+ _G["GuildFrameGuildStatusButton"..i.."Note"]:SetText(note);
+
+ if ( online ) then
+ if ( status == "" ) then
+ _G["GuildFrameGuildStatusButton"..i.."Online"]:SetText(GUILD_ONLINE_LABEL);
+ else
+ _G["GuildFrameGuildStatusButton"..i.."Online"]:SetText(status);
+ end
+
+ if ( classFileName ) then
+ classTextColor = RAID_CLASS_COLORS[classFileName];
+ else
+ classTextColor = NORMAL_FONT_COLOR;
+ end
+ _G["GuildFrameGuildStatusButton"..i.."Name"]:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ _G["GuildFrameGuildStatusButton"..i.."Rank"]:SetTextColor(1.0, 1.0, 1.0);
+ _G["GuildFrameGuildStatusButton"..i.."Note"]:SetTextColor(1.0, 1.0, 1.0);
+ _G["GuildFrameGuildStatusButton"..i.."Online"]:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b);
+ else
+ _G["GuildFrameGuildStatusButton"..i.."Online"]:SetText(GuildFrame_GetLastOnline(guildIndex));
+ _G["GuildFrameGuildStatusButton"..i.."Name"]:SetTextColor(0.5, 0.5, 0.5);
+ _G["GuildFrameGuildStatusButton"..i.."Rank"]:SetTextColor(0.5, 0.5, 0.5);
+ _G["GuildFrameGuildStatusButton"..i.."Note"]:SetTextColor(0.5, 0.5, 0.5);
+ _G["GuildFrameGuildStatusButton"..i.."Online"]:SetTextColor(0.5, 0.5, 0.5);
+ end
+
+ -- If need scrollbar resize columns
+ if ( showScrollBar ) then
+ _G["GuildFrameGuildStatusButton"..i.."Note"]:SetWidth(70);
+ else
+ _G["GuildFrameGuildStatusButton"..i.."Note"]:SetWidth(85);
+ end
+
+ -- Highlight the correct who
+ if ( GetGuildRosterSelection() == guildIndex ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+
+ if ( guildIndex > numGuildMembers ) then
+ button:Hide();
+ else
+ button:Show();
+ end
+ end
+
+ GuildFrameGuildListToggleButton:SetText(GUILD_STATUS);
+ -- If need scrollbar resize columns
+ if ( showScrollBar ) then
+ WhoFrameColumn_SetWidth(GuildFrameGuildStatusColumnHeader3, 75);
+ GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 284, -67);
+ else
+ WhoFrameColumn_SetWidth(GuildFrameGuildStatusColumnHeader3, 90);
+ GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 307, -67);
+ end
+
+ -- ScrollFrame update
+ FauxScrollFrame_Update(GuildListScrollFrame, numGuildMembers, GUILDMEMBERS_TO_DISPLAY, FRIENDS_FRAME_GUILD_HEIGHT );
+
+ GuildPlayerStatusFrame:Hide();
+ GuildStatusFrame:Show();
+ end
+end
+
+function WhoFrameColumn_SetWidth(frame, width)
+ frame:SetWidth(width);
+ _G[frame:GetName().."Middle"]:SetWidth(width - 9);
+end
+
+function WhoFrameDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+ for i=1, getn(WHOFRAME_DROPDOWN_LIST), 1 do
+ info.text = WHOFRAME_DROPDOWN_LIST[i].name;
+ info.func = WhoFrameDropDownButton_OnClick;
+ info.checked = nil;
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function WhoFrameDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, WhoFrameDropDown_Initialize);
+ UIDropDownMenu_SetWidth(self, 80);
+ UIDropDownMenu_SetButtonWidth(self, 24);
+ UIDropDownMenu_JustifyText(WhoFrameDropDown, "LEFT")
+end
+
+function WhoFrameDropDownButton_OnClick(self)
+ UIDropDownMenu_SetSelectedID(WhoFrameDropDown, self:GetID());
+ WhoList_Update();
+end
+
+function FriendsFrame_OnEvent(self, event, ...)
+ if ( event == "FRIENDLIST_SHOW" ) then
+ FriendsList_Update();
+ FriendsFrame_Update();
+ elseif ( event == "FRIENDLIST_UPDATE" or event == "PARTY_MEMBERS_CHANGED" ) then
+ FriendsList_Update();
+ elseif ( event == "BN_FRIEND_LIST_SIZE_CHANGED" or event == "BN_FRIEND_INFO_CHANGED" ) then
+ BNetBroadcasts, numOnlineBroadcasts, numOfflineBroadcasts = BNGetCustomMessageTable(BNetBroadcasts);
+ if(not BNetBroadcasts) then
+ BNetBroadcasts = { };
+ end
+ FriendsList_Update();
+ elseif ( event == "BN_CUSTOM_MESSAGE_CHANGED" ) then
+ local arg1 = ...;
+ if ( arg1 ) then --There is no presenceID given if this is ourself.
+ BNetBroadcasts, numOnlineBroadcasts, numOfflineBroadcasts = BNGetCustomMessageTable(BNetBroadcasts);
+ if(not BNetBroadcasts) then
+ BNetBroadcasts = { };
+ end
+ FriendsList_Update();
+ else
+ FriendsFrameBroadcastInput_UpdateDisplay();
+ end
+ elseif ( event == "BN_CUSTOM_MESSAGE_LOADED" ) then
+ FriendsFrameBroadcastInput_UpdateDisplay();
+ elseif ( event == "BN_FRIEND_INVITE_ADDED" ) then
+ local arg1 = ...;
+ if ( arg1 ) then
+ PendingInvitesNew[arg1] = true;
+ PendingList_Update(true);
+ end
+ elseif ( event == "BN_FRIEND_INVITE_LIST_INITIALIZED" ) then
+ PendingInvitesNew["all"] = true;
+ PendingList_Update();
+ elseif ( event == "BN_FRIEND_INVITE_REMOVED" ) then
+ PendingList_Update();
+ elseif ( event == "IGNORELIST_UPDATE" or event == "MUTELIST_UPDATE" or event == "BN_BLOCK_LIST_UPDATED" ) then
+ IgnoreList_Update();
+ elseif ( event == "WHO_LIST_UPDATE" ) then
+ WhoList_Update();
+ FriendsFrame_Update();
+ elseif ( event == "GUILD_ROSTER_UPDATE" ) then
+ GuildInfoFrame.cachedText = nil;
+ if ( GuildFrame:IsShown() ) then
+ local arg1 = ...;
+ if ( arg1 ) then
+ GuildRoster();
+ end
+ GuildStatus_Update();
+ FriendsFrame_Update();
+ GuildControlPopupFrame_Initialize();
+ end
+ elseif ( event == "PLAYER_GUILD_UPDATE" ) then
+ if ( FriendsFrame:IsVisible() ) then
+ InGuildCheck();
+ end
+ if ( not IsInGuild() ) then
+ GuildControlPopupFrame.initialized = false;
+ end
+ elseif ( event == "GUILD_MOTD") then
+ CURRENT_GUILD_MOTD = ...;
+ GuildFrameNotesText:SetText(CURRENT_GUILD_MOTD);
+ elseif ( event == "VOICE_CHAT_ENABLED_UPDATE" ) then
+ VoiceChat_Toggle();
+ elseif ( event == "PLAYER_FLAGS_CHANGED" ) then
+ SynchronizeBNetStatus();
+ FriendsFrameStatusDropDown_Update();
+ elseif ( event == "PLAYER_ENTERING_WORLD" or event == "BN_CONNECTED" or event == "BN_DISCONNECTED" or event == "BN_SELF_ONLINE" ) then
+ FriendsFrame_CheckBattlenetStatus();
+ end
+end
+
+function FriendsFrameFriendButton_OnClick(self, button)
+ if ( button == "LeftButton" ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ FriendsFrame_SelectFriend(self.buttonType, self.id);
+ FriendsList_Update();
+ elseif ( button == "RightButton" ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ if ( self.buttonType == FRIENDS_BUTTON_TYPE_BNET ) then
+ -- bnet friend
+ local presenceID, givenName, surname, toonName, toonID, client, isOnline = BNGetFriendInfo(self.id);
+ FriendsFrame_ShowBNDropdown(format(BATTLENET_NAME_FORMAT, givenName, surname), isOnline, nil, nil, nil, 1, presenceID);
+ else
+ -- wow friend
+ local name, level, class, area, connected = GetFriendInfo(self.id);
+ FriendsFrame_ShowDropdown(name, connected, nil, nil, nil, 1);
+ end
+ end
+end
+
+function FriendsFrame_SelectFriend(friendType, id)
+ if ( friendType == FRIENDS_BUTTON_TYPE_WOW ) then
+ SetSelectedFriend(id);
+ elseif ( friendType == FRIENDS_BUTTON_TYPE_BNET ) then
+ BNSetSelectedFriend(id);
+ end
+ FriendsFrame.selectedFriendType = friendType;
+end
+
+function FriendsFrame_SelectSquelched(ignoreType, index)
+ if ( ignoreType == SQUELCH_TYPE_IGNORE ) then
+ SetSelectedIgnore(index);
+ elseif ( ignoreType == SQUELCH_TYPE_BLOCK_INVITE ) then
+ BNSetSelectedBlock(index);
+ elseif ( ignoreType == SQUELCH_TYPE_BLOCK_TOON ) then
+ BNSetSelectedToonBlock(index);
+ elseif ( ignoreType == SQUELCH_TYPE_MUTE ) then
+ SetSelectedMute(index);
+ end
+ FriendsFrame.selectedSquelchType = ignoreType;
+end
+
+function FriendsFrameAddFriendButton_OnClick(self)
+ if ( UnitIsPlayer("target") and UnitCanCooperate("player", "target") and not GetFriendInfo(UnitName("target")) ) then
+ local name, server = UnitName("target");
+ if ( server and (not UnitIsSameServer("player", "target")) ) then
+ name = name.."-"..server;
+ end
+ AddFriend(name);
+ PlaySound("UChatScrollButton");
+ else
+ if ( BNFeaturesEnabled() ) then
+ AddFriendEntryFrame_Collapse(true);
+ AddFriendFrame.editFocus = AddFriendNameEditBox;
+ StaticPopupSpecial_Show(AddFriendFrame);
+ if ( GetCVarBool("addFriendInfoShown") ) then
+ AddFriendFrame_ShowEntry();
+ else
+ AddFriendFrame_ShowInfo();
+ end
+ else
+ StaticPopup_Show("ADD_FRIEND");
+ end
+ end
+end
+
+function FriendsFrameSendMessageButton_OnClick(self)
+ local name;
+ if ( FriendsFrame.selectedFriendType == FRIENDS_BUTTON_TYPE_WOW ) then
+ name = GetFriendInfo(FriendsFrame.selectedFriend);
+ elseif ( FriendsFrame.selectedFriendType == FRIENDS_BUTTON_TYPE_BNET ) then
+ local presenceID, givenName, surname = BNGetFriendInfo(FriendsFrame.selectedFriend);
+ name = string.format(BATTLENET_NAME_FORMAT, givenName, surname);
+ end
+ if ( name ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ ChatFrame_SendTell(name);
+ end
+end
+
+function FriendsFrameMuteButton_OnClick(self)
+ SetSelectedMute(self:GetID());
+ MutedList_Update();
+end
+
+function FriendsFrameUnsquelchButton_OnClick(self)
+ local selectedSquelchType = FriendsFrame.selectedSquelchType;
+ if ( selectedSquelchType == SQUELCH_TYPE_IGNORE ) then
+ local name = GetIgnoreName(GetSelectedIgnore());
+ DelIgnore(name);
+ elseif ( selectedSquelchType == SQUELCH_TYPE_BLOCK_INVITE ) then
+ local blockID = BNGetBlockedInfo(BNGetSelectedBlock());
+ BNSetBlocked(blockID, false);
+ elseif ( selectedSquelchType == SQUELCH_TYPE_BLOCK_TOON ) then
+ local blockID = BNGetBlockedToonInfo(BNGetSelectedToonBlock());
+ BNSetToonBlocked(blockID, false);
+ elseif ( selectedSquelchType == SQUELCH_TYPE_MUTE ) then
+ local name = GetMuteName(GetSelectedMute());
+ DelMute(name);
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+function FriendsFrameWhoButton_OnClick(self, button)
+ if ( button == "LeftButton" ) then
+ WhoFrame.selectedWho = _G["WhoFrameButton"..self:GetID()].whoIndex;
+ WhoFrame.selectedName = _G["WhoFrameButton"..self:GetID().."Name"]:GetText();
+ WhoList_Update();
+ else
+ local name = _G["WhoFrameButton"..self:GetID().."Name"]:GetText();
+ FriendsFrame_ShowDropdown(name, 1);
+ end
+end
+
+function FriendsFrameGuildStatusButton_OnClick(self, button)
+ if ( button == "LeftButton" ) then
+ GuildFrame.previousSelectedGuildMember = GuildFrame.selectedGuildMember;
+ GuildFrame.selectedGuildMember = self.guildIndex;
+ GuildFrame.selectedName = _G[self:GetName().."Name"]:GetText();
+ SetGuildRosterSelection(GuildFrame.selectedGuildMember);
+ -- Toggle guild details frame
+ if ( GuildMemberDetailFrame:IsShown() and (GuildFrame.previousSelectedGuildMember and (GuildFrame.previousSelectedGuildMember == GuildFrame.selectedGuildMember)) ) then
+ GuildMemberDetailFrame:Hide();
+ GuildFrame.selectedGuildMember = 0;
+ SetGuildRosterSelection(0);
+ else
+ GuildFramePopup_Show(GuildMemberDetailFrame);
+ end
+ GuildStatus_Update();
+ else
+ local guildIndex = self.guildIndex;
+ local name, rank, rankIndex, level, class, zone, note, officernote, online = GetGuildRosterInfo(guildIndex);
+ FriendsFrame_ShowDropdown(name, online);
+ end
+end
+
+function FriendsFrame_UnIgnore(button, name)
+ DelIgnore(name);
+end
+
+function FriendsFrame_UnMute(button, name)
+ DelMute(name);
+end
+
+function FriendsFrame_UnBlock(button, blockID)
+ BNSetBlocked(blockID, false);
+end
+
+function FriendsFrame_RemoveFriend()
+ if ( FriendsFrame.selectedFriend ) then
+ RemoveFriend(FriendsFrame.selectedFriend);
+ PlaySound("UChatScrollButton");
+ end
+end
+
+function FriendsFrame_SendMessage()
+ local name = GetFriendInfo(FriendsFrame.selectedFriend);
+ ChatFrame_SendTell(name);
+ PlaySound("UChatScrollButton");
+end
+
+function FriendsFrame_GroupInvite()
+ local name = GetFriendInfo(FriendsFrame.selectedFriend);
+ InviteUnit(name);
+ PlaySound("UChatScrollButton");
+end
+
+function ToggleFriendsFrame(tab)
+ if ( not tab ) then
+ if ( FriendsFrame:IsShown() ) then
+ HideUIPanel(FriendsFrame);
+ else
+ ShowUIPanel(FriendsFrame);
+ end
+ else
+ -- If not in a guild don't do anything when they try to toggle the guild tab
+ if ( tab == 3 and not IsInGuild() ) then
+ return;
+ end
+ if ( tab == PanelTemplates_GetSelectedTab(FriendsFrame) and FriendsFrame:IsShown() ) then
+ HideUIPanel(FriendsFrame);
+ return;
+ end
+ PanelTemplates_SetTab(FriendsFrame, tab);
+ if ( FriendsFrame:IsShown() ) then
+ FriendsFrame_OnShow();
+ else
+ ShowUIPanel(FriendsFrame);
+ end
+ end
+end
+
+function WhoFrameEditBox_OnEnterPressed(self)
+ SendWho(self:GetText());
+ self:ClearFocus();
+end
+
+function ToggleFriendsPanel()
+ local friendsTabShown =
+ FriendsFrame:IsShown() and
+ PanelTemplates_GetSelectedTab(FriendsFrame) == 1 and
+ FriendsTabHeader.selectedTab == 1;
+
+ if ( friendsTabShown ) then
+ HideUIPanel(FriendsFrame);
+ else
+ PanelTemplates_SetTab(FriendsFrame, 1);
+ PanelTemplates_SetTab(FriendsTabHeader, 1);
+ ShowUIPanel(FriendsFrame);
+ end
+end
+
+function ShowWhoPanel()
+ PanelTemplates_SetTab(FriendsFrame, 2);
+ if ( FriendsFrame:IsShown() ) then
+ FriendsFrame_OnShow();
+ else
+ ShowUIPanel(FriendsFrame);
+ end
+end
+
+function ToggleIgnorePanel()
+ local ignoreTabShown =
+ FriendsFrame:IsShown() and
+ PanelTemplates_GetSelectedTab(FriendsFrame) == 1 and
+ FriendsTabHeader.selectedTab == 2;
+
+ if ( ignoreTabShown ) then
+ HideUIPanel(FriendsFrame);
+ else
+ PanelTemplates_SetTab(FriendsFrame, 1);
+ PanelTemplates_SetTab(FriendsTabHeader, 2);
+ FriendsFrame_Update();
+ ShowUIPanel(FriendsFrame);
+ end
+end
+
+function WhoFrame_GetDefaultWhoCommand()
+ local level = UnitLevel("player");
+ local minLevel = level-3;
+ if ( minLevel <= 0 ) then
+ minLevel = 1;
+ end
+ local command = WHO_TAG_ZONE.."\""..GetRealZoneText().."\" "..minLevel.."-"..(level+3);
+ return command;
+end
+
+function GuildControlPopupFrame_OnLoad()
+ local buttonText;
+ for i=1, 17 do
+ buttonText = _G["GuildControlPopupFrameCheckbox"..i.."Text"];
+ if ( buttonText ) then
+ buttonText:SetText(_G["GUILDCONTROL_OPTION"..i]);
+ end
+ end
+ GuildControlTabPermissionsViewTabText:SetText(GUILDCONTROL_VIEW_TAB);
+ GuildControlTabPermissionsDepositItemsText:SetText(GUILDCONTROL_DEPOSIT_ITEMS);
+ GuildControlTabPermissionsUpdateTextText:SetText(GUILDCONTROL_UPDATE_TEXT);
+ ClearPendingGuildBankPermissions();
+end
+
+--Need to call this function on an event since the guildroster is not available during OnLoad()
+function GuildControlPopupFrame_Initialize()
+ if ( GuildControlPopupFrame.initialized ) then
+ return;
+ end
+ UIDropDownMenu_Initialize(GuildControlPopupFrameDropDown, GuildControlPopupFrameDropDown_Initialize);
+ GuildControlSetRank(1);
+ UIDropDownMenu_SetSelectedID(GuildControlPopupFrameDropDown, 1);
+ UIDropDownMenu_SetText(GuildControlPopupFrameDropDown, GuildControlGetRankName(1));
+ -- Select tab 1
+ GuildBankTabPermissionsTab_OnClick(1);
+
+ GuildControlPopupFrame:SetScript("OnEvent", GuildControlPopupFrame_OnEvent);
+ GuildControlPopupFrame.initialized = 1;
+ GuildControlPopupFrame.rank = GuildControlGetRankName(1);
+end
+
+function GuildControlPopupFrame_OnShow()
+ FriendsFrame:SetAttribute("UIPanelLayout-defined", nil);
+ FriendsFrame.guildControlShow = 1;
+ GuildControlPopupAcceptButton:Disable();
+ -- Update popup
+ GuildControlPopupframe_Update();
+
+ UIPanelWindows["FriendsFrame"].width = FriendsFrame:GetWidth() + GuildControlPopupFrame:GetWidth();
+ UpdateUIPanelPositions(FriendsFrame);
+ --GuildControlPopupFrame:RegisterEvent("GUILD_ROSTER_UPDATE"); --It was decided that having a risk of conflict when two people are editing the guild permissions at once is better than resetting whenever someone joins the guild or changes ranks.
+end
+
+function GuildControlPopupFrame_OnEvent (self, event, ...)
+ if ( not IsGuildLeader(UnitName("player")) ) then
+ GuildControlPopupFrame:Hide();
+ return;
+ end
+
+ local rank
+ for i = 1, GuildControlGetNumRanks() do
+ rank = GuildControlGetRankName(i);
+ if ( GuildControlPopupFrame.rank and rank == GuildControlPopupFrame.rank ) then
+ UIDropDownMenu_SetSelectedID(GuildControlPopupFrameDropDown, i);
+ UIDropDownMenu_SetText(GuildControlPopupFrameDropDown, rank);
+ end
+ end
+
+ GuildControlPopupframe_Update()
+end
+
+function GuildControlPopupFrame_OnHide()
+ FriendsFrame:SetAttribute("UIPanelLayout-defined", nil);
+ FriendsFrame.guildControlShow = 0;
+
+ UIPanelWindows["FriendsFrame"].width = FriendsFrame:GetWidth();
+ UpdateUIPanelPositions();
+
+ GuildControlPopupFrame.goldChanged = nil;
+ GuildControlPopupFrame:UnregisterEvent("GUILD_ROSTER_UPDATE");
+end
+
+function GuildControlPopupframe_Update(loadPendingTabPermissions, skipCheckboxUpdate)
+ -- Skip non-tab specific updates to fix Bug ID: 110210
+ if ( not skipCheckboxUpdate ) then
+ -- Update permission flags
+ GuildControlCheckboxUpdate(GuildControlGetRankFlags());
+ end
+
+ local rankID = UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown);
+ GuildControlPopupFrameEditBox:SetText(GuildControlGetRankName(rankID));
+ if ( GuildControlPopupFrame.previousSelectedRank and GuildControlPopupFrame.previousSelectedRank ~= rankID ) then
+ ClearPendingGuildBankPermissions();
+ end
+ GuildControlPopupFrame.previousSelectedRank = rankID;
+
+ --If rank to modify is guild master then gray everything out
+ if ( IsGuildLeader() and rankID == 1 ) then
+ GuildBankTabLabel:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ GuildControlTabPermissionsDepositItems:SetChecked(1);
+ GuildControlTabPermissionsViewTab:SetChecked(1);
+ GuildControlTabPermissionsUpdateText:SetChecked(1);
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlTabPermissionsDepositItems);
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlTabPermissionsViewTab);
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlTabPermissionsUpdateText);
+ GuildControlTabPermissionsWithdrawItemsText:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ GuildControlWithdrawItemsEditBox:SetNumeric(nil);
+ GuildControlWithdrawItemsEditBox:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ GuildControlWithdrawItemsEditBox:SetText(UNLIMITED);
+ GuildControlWithdrawItemsEditBox:ClearFocus();
+ GuildControlWithdrawItemsEditBoxMask:Show();
+ GuildControlWithdrawGoldText:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ GuildControlWithdrawGoldAmountText:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ GuildControlWithdrawGoldEditBox:SetNumeric(nil);
+ GuildControlWithdrawGoldEditBox:SetMaxLetters(0);
+ GuildControlWithdrawGoldEditBox:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ GuildControlWithdrawGoldEditBox:SetText(UNLIMITED);
+ GuildControlWithdrawGoldEditBox:ClearFocus();
+ GuildControlWithdrawGoldEditBoxMask:Show();
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlPopupFrameCheckbox15);
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlPopupFrameCheckbox16);
+ else
+ if ( GetNumGuildBankTabs() == 0 ) then
+ -- No tabs, no permissions! Disable the tab related doohickies
+ GuildBankTabLabel:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlTabPermissionsViewTab);
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlTabPermissionsDepositItems);
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlTabPermissionsUpdateText);
+ GuildControlTabPermissionsWithdrawItemsText:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ GuildControlWithdrawItemsEditBox:SetText(UNLIMITED);
+ GuildControlWithdrawItemsEditBox:ClearFocus();
+ GuildControlWithdrawItemsEditBoxMask:Show();
+ else
+ GuildBankTabLabel:SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ BlizzardOptionsPanel_CheckButton_Enable(GuildControlTabPermissionsViewTab);
+ GuildControlTabPermissionsWithdrawItemsText:SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GuildControlWithdrawItemsEditBox:SetNumeric(1);
+ GuildControlWithdrawItemsEditBox:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GuildControlWithdrawItemsEditBoxMask:Hide();
+ end
+
+ GuildControlWithdrawGoldText:SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GuildControlWithdrawGoldAmountText:SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GuildControlWithdrawGoldEditBox:SetNumeric(1);
+ GuildControlWithdrawGoldEditBox:SetMaxLetters(MAX_GOLD_WITHDRAW_DIGITS);
+ GuildControlWithdrawGoldEditBox:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GuildControlWithdrawGoldEditBoxMask:Hide();
+ BlizzardOptionsPanel_CheckButton_Enable(GuildControlPopupFrameCheckbox15);
+ BlizzardOptionsPanel_CheckButton_Enable(GuildControlPopupFrameCheckbox16);
+
+ -- Update tab specific info
+ local viewTab, canDeposit, canUpdateText, numWithdrawals = GetGuildBankTabPermissions(GuildControlPopupFrameTabPermissions.selectedTab);
+ if ( rankID == 1 ) then
+ --If is guildmaster then force checkboxes to be selected
+ viewTab = 1;
+ canDeposit = 1;
+ canUpdateText = 1;
+ elseif ( loadPendingTabPermissions ) then
+ local permissions = PENDING_GUILDBANK_PERMISSIONS[GuildControlPopupFrameTabPermissions.selectedTab];
+ local value;
+ value = permissions[GuildControlTabPermissionsViewTab:GetID()];
+ if ( value ) then
+ viewTab = value;
+ end
+ value = permissions[GuildControlTabPermissionsDepositItems:GetID()];
+ if ( value ) then
+ canDeposit = value;
+ end
+ value = permissions[GuildControlTabPermissionsUpdateText:GetID()];
+ if ( value ) then
+ canUpdateText = value;
+ end
+ value = permissions["withdraw"];
+ if ( value ) then
+ numWithdrawals = value;
+ end
+ end
+ GuildControlTabPermissionsViewTab:SetChecked(viewTab);
+ GuildControlTabPermissionsDepositItems:SetChecked(canDeposit);
+ GuildControlTabPermissionsUpdateText:SetChecked(canUpdateText);
+ GuildControlWithdrawItemsEditBox:SetText(numWithdrawals);
+ local goldWithdrawLimit = GetGuildBankWithdrawLimit();
+ -- Only write to the editbox if the value hasn't been changed by the player
+ if ( not GuildControlPopupFrame.goldChanged ) then
+ if ( goldWithdrawLimit >= 0 ) then
+ GuildControlWithdrawGoldEditBox:SetText(goldWithdrawLimit);
+ else
+ -- This is for the guild leader who defaults to -1
+ GuildControlWithdrawGoldEditBox:SetText(MAX_GOLD_WITHDRAW);
+ end
+ end
+ GuildControlPopup_UpdateDepositCheckBox();
+ end
+
+ --Only show available tabs
+ local tab;
+ local numTabs = GetNumGuildBankTabs();
+ local name, permissionsTabBackground, permissionsText;
+ for i=1, MAX_GUILDBANK_TABS do
+ name = GetGuildBankTabInfo(i);
+ tab = _G["GuildBankTabPermissionsTab"..i];
+
+ if ( i <= numTabs ) then
+ tab:Show();
+ tab.tooltip = name;
+ permissionsTabBackground = _G["GuildBankTabPermissionsTab"..i.."Background"];
+ permissionsText = _G["GuildBankTabPermissionsTab"..i.."Text"];
+ if ( GuildControlPopupFrameTabPermissions.selectedTab == i ) then
+ tab:LockHighlight();
+ permissionsTabBackground:SetTexCoord(0, 1.0, 0, 1.0);
+ permissionsTabBackground:SetHeight(32);
+ permissionsText:SetPoint("CENTER", permissionsTabBackground, "CENTER", 0, -3);
+ else
+ tab:UnlockHighlight();
+ permissionsTabBackground:SetTexCoord(0, 1.0, 0, 0.875);
+ permissionsTabBackground:SetHeight(28);
+ permissionsText:SetPoint("CENTER", permissionsTabBackground, "CENTER", 0, -5);
+ end
+ if ( IsGuildLeader() and rankID == 1 ) then
+ tab:Disable();
+ else
+ tab:Enable();
+ end
+ else
+ tab:Hide();
+ end
+ end
+end
+
+function WithdrawGoldEditBox_Update()
+ if ( not GuildControlPopupFrameCheckbox15:GetChecked() and not GuildControlPopupFrameCheckbox16:GetChecked() ) then
+ GuildControlWithdrawGoldAmountText:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ GuildControlWithdrawGoldEditBox:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ GuildControlWithdrawGoldEditBox:ClearFocus();
+ GuildControlWithdrawGoldEditBoxMask:Show();
+ else
+ GuildControlWithdrawGoldAmountText:SetVertexColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GuildControlWithdrawGoldEditBox:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GuildControlWithdrawGoldEditBoxMask:Hide();
+ end
+end
+
+function GuildControlPopupAcceptButton_OnClick()
+ local amount = GuildControlWithdrawGoldEditBox:GetText();
+ if(amount and amount ~= "" and amount ~= UNLIMITED and tonumber(amount) and tonumber(amount) > 0) then
+ SetGuildBankWithdrawLimit(amount);
+ else
+ SetGuildBankWithdrawLimit(0);
+ end
+ SavePendingGuildBankTabPermissions()
+ GuildControlSaveRank(GuildControlPopupFrameEditBox:GetText());
+ GuildStatus_Update();
+ GuildControlPopupAcceptButton:Disable();
+ UIDropDownMenu_SetText(GuildControlPopupFrameDropDown, GuildControlPopupFrameEditBox:GetText());
+ GuildControlPopupFrame:Hide();
+ ClearPendingGuildBankPermissions();
+end
+
+function GuildControlPopupFrameDropDown_OnLoad(self)
+ UIDropDownMenu_SetWidth(self, 160);
+ UIDropDownMenu_SetButtonWidth(self, 54);
+ UIDropDownMenu_JustifyText(GuildControlPopupFrameDropDown, "LEFT");
+end
+
+function GuildControlPopupFrameDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+ for i=1, GuildControlGetNumRanks() do
+ info.text = GuildControlGetRankName(i);
+ info.func = GuildControlPopupFrameDropDownButton_OnClick;
+ info.checked = nil;
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function GuildControlPopupFrameDropDownButton_OnClick(self)
+ local rank = self:GetID();
+ UIDropDownMenu_SetSelectedID(GuildControlPopupFrameDropDown, rank);
+ GuildControlSetRank(rank);
+ GuildControlPopupFrame.rank = GuildControlGetRankName(rank);
+ GuildControlPopupFrame.goldChanged = nil;
+ GuildControlPopupframe_Update();
+ GuildControlPopupFrameAddRankButton_OnUpdate(GuildControlPopupFrameAddRankButton);
+ GuildControlPopupFrameRemoveRankButton_OnUpdate(GuildControlPopupFrameRemoveRankButton);
+ GuildControlPopupAcceptButton:Disable();
+end
+
+function GuildControlCheckboxUpdate(...)
+ local checkbox;
+ for i=1, select("#", ...), 1 do
+ checkbox = _G["GuildControlPopupFrameCheckbox"..i]
+ if ( checkbox ) then
+ checkbox:SetChecked(select(i, ...));
+ else
+ --We need to skip checkbox 14 since it's a deprecated flag
+ --message("GuildControlPopupFrameCheckbox"..i.." does not exist!");
+ end
+ end
+end
+
+function GuildControlPopupFrameAddRankButton_OnUpdate(self)
+ if ( GuildControlGetNumRanks() >= 10 ) then
+ self:Disable();
+ else
+ self:Enable();
+ end
+end
+
+function GuildControlPopupFrameRemoveRankButton_OnClick()
+ GuildControlDelRank(GuildControlGetRankName(UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown)));
+ GuildControlPopupFrame.rank = GuildControlGetRankName(1);
+ GuildControlSetRank(1);
+ GuildStatus_Update();
+ UIDropDownMenu_SetSelectedID(GuildControlPopupFrameDropDown, 1);
+ GuildControlPopupFrameEditBox:SetText(GuildControlGetRankName(1));
+ GuildControlCheckboxUpdate(GuildControlGetRankFlags());
+ CloseDropDownMenus();
+ -- Set this to call guildroster in the next frame
+ --GuildRoster();
+ --GuildControlPopupFrame.update = 1;
+end
+
+function GuildControlPopupFrameRemoveRankButton_OnUpdate(self)
+ local numRanks = GuildControlGetNumRanks()
+ if ( (UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown) == numRanks) and (numRanks > 5) ) then
+ self:Show();
+ if ( FriendsFrame.playersInBotRank > 0 ) then
+ self:Disable();
+ else
+ self:Enable();
+ end
+ else
+ self:Hide();
+ end
+end
+
+function GuildControlPopup_UpdateDepositCheckBox()
+ if(GuildControlTabPermissionsViewTab:GetChecked()) then
+ BlizzardOptionsPanel_CheckButton_Enable(GuildControlTabPermissionsDepositItems);
+ BlizzardOptionsPanel_CheckButton_Enable(GuildControlTabPermissionsUpdateText);
+ else
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlTabPermissionsDepositItems);
+ BlizzardOptionsPanel_CheckButton_Disable(GuildControlTabPermissionsUpdateText);
+ end
+end
+
+function InGuildCheck()
+ if ( not IsInGuild() ) then
+ PanelTemplates_DisableTab( FriendsFrame, 3 );
+ if ( FriendsFrame.selectedTab == 3 ) then
+ FriendsFrame.selectedTab = 1;
+ FriendsFrame_Update();
+ end
+ else
+ PanelTemplates_EnableTab( FriendsFrame, 3 );
+ FriendsFrame_Update();
+ end
+end
+
+function GuildFrameGuildListToggleButton_OnClick()
+ if ( FriendsFrame.playerStatusFrame ) then
+ FriendsFrame.playerStatusFrame = nil;
+ else
+ FriendsFrame.playerStatusFrame = 1;
+ end
+ GuildStatus_Update();
+end
+
+function GuildFrameControlButton_OnUpdate()
+ if ( FriendsFrame.guildControlShow == 1 ) then
+ GuildFrameControlButton:LockHighlight();
+ else
+ GuildFrameControlButton:UnlockHighlight();
+ end
+ -- Janky way to make sure a change made to the guildroster will reflect in the guildroster call
+ if ( GuildControlPopupFrame.update == 1 ) then
+ GuildControlPopupFrame.update = 2;
+ elseif ( GuildControlPopupFrame.update == 2 ) then
+ GuildRoster();
+ GuildControlPopupFrame.update = nil;
+ end
+end
+
+function GuildFrame_GetLastOnline(guildIndex)
+ return RecentTimeDate( GetGuildRosterLastOnline(guildIndex) );
+end
+
+function FriendsFrame_GetLastOnline(lastOnline)
+ local year, month, day, hour, minute;
+ local timeDifference = time() - lastOnline;
+ local ONE_MINUTE = 60;
+ local ONE_HOUR = 60 * ONE_MINUTE;
+ local ONE_DAY = 24 * ONE_HOUR;
+ local ONE_MONTH = 30 * ONE_DAY;
+ local ONE_YEAR = 12 * ONE_MONTH;
+ -- local ONE_MILLENIUM = 1000 * ONE_YEAR; for the future
+
+ if ( timeDifference < ONE_MINUTE ) then
+ return LASTONLINE_SECS;
+ elseif ( timeDifference >= ONE_MINUTE and timeDifference < ONE_HOUR ) then
+ return format(LASTONLINE_MINUTES, floor(timeDifference / ONE_MINUTE));
+ elseif ( timeDifference >= ONE_HOUR and timeDifference < ONE_DAY ) then
+ return format(LASTONLINE_HOURS, floor(timeDifference / ONE_HOUR));
+ elseif ( timeDifference >= ONE_DAY and timeDifference < ONE_MONTH ) then
+ return format(LASTONLINE_DAYS, floor(timeDifference / ONE_DAY));
+ elseif ( timeDifference >= ONE_MONTH and timeDifference < ONE_YEAR ) then
+ return format(LASTONLINE_MONTHS, floor(timeDifference / ONE_MONTH));
+ else
+ return format(LASTONLINE_YEARS, floor(timeDifference / ONE_YEAR));
+ end
+end
+
+function ToggleGuildInfoFrame()
+ if ( GuildInfoFrame:IsShown() ) then
+ GuildInfoFrame:Hide();
+ else
+ GuildFramePopup_Show(GuildInfoFrame);
+ end
+end
+
+function GuildBankTabPermissionsTab_OnClick(tab)
+ GuildControlPopupFrameTabPermissions.selectedTab = tab;
+ GuildControlPopupframe_Update(true, true);
+end
+
+-- Functions to allow canceling
+function ClearPendingGuildBankPermissions()
+ for i=1, MAX_GUILDBANK_TABS do
+ PENDING_GUILDBANK_PERMISSIONS[i] = {};
+ end
+end
+
+function SetPendingGuildBankTabPermissions(tab, id, checked)
+ if ( not checked ) then
+ checked = 0;
+ end
+ PENDING_GUILDBANK_PERMISSIONS[tab][id] = checked;
+end
+
+function SetPendingGuildBankTabWithdraw(tab, amount)
+ PENDING_GUILDBANK_PERMISSIONS[tab]["withdraw"] = amount;
+end
+
+function SavePendingGuildBankTabPermissions()
+ for index, value in pairs(PENDING_GUILDBANK_PERMISSIONS) do
+ for i=1, 3 do
+ if ( value[i] ) then
+ SetGuildBankTabPermissions(index, i, value[i]);
+ end
+ end
+ if ( value["withdraw"] ) then
+ SetGuildBankTabWithdraw(index, value["withdraw"]);
+ end
+ end
+end
+
+-- Guild event log functions
+function ToggleGuildEventLog()
+ if ( GuildEventLogFrame:IsShown() ) then
+ GuildEventLogFrame:Hide();
+ else
+ GuildFramePopup_Show(GuildEventLogFrame);
+-- QueryGuildEventLog();
+ end
+end
+
+function GuildEventLog_Update()
+ local numEvents = GetNumGuildEvents();
+ local type, player1, player2, rank, year, month, day, hour;
+ local msg;
+ local buffer = "";
+ local max = GuildEventMessage:GetFieldSize()
+ local length = 0;
+ for i=numEvents, 1, -1 do
+ type, player1, player2, rank, year, month, day, hour = GetGuildEventInfo(i);
+ if ( not player1 ) then
+ player1 = UNKNOWN;
+ end
+ if ( not player2 ) then
+ player2 = UNKNOWN;
+ end
+ if ( type == "invite" ) then
+ msg = format(GUILDEVENT_TYPE_INVITE, player1, player2);
+ elseif ( type == "join" ) then
+ msg = format(GUILDEVENT_TYPE_JOIN, player1);
+ elseif ( type == "promote" ) then
+ msg = format(GUILDEVENT_TYPE_PROMOTE, player1, player2, rank);
+ elseif ( type == "demote" ) then
+ msg = format(GUILDEVENT_TYPE_DEMOTE, player1, player2, rank);
+ elseif ( type == "remove" ) then
+ msg = format(GUILDEVENT_TYPE_REMOVE, player1, player2);
+ elseif ( type == "quit" ) then
+ msg = format(GUILDEVENT_TYPE_QUIT, player1);
+ end
+ if ( msg ) then
+ msg = msg.."|cff009999 "..format(GUILD_BANK_LOG_TIME, RecentTimeDate(year, month, day, hour)).."|r|n";
+ length = length + msg:len();
+ if(length>max) then
+ i=0
+ else
+ buffer = buffer..msg
+ end
+ end
+ end
+ GuildEventMessage:SetText(buffer);
+end
+
+GUILDFRAME_POPUPS = {
+ "GuildEventLogFrame",
+ "GuildInfoFrame",
+ "GuildMemberDetailFrame",
+ "GuildControlPopupFrame",
+};
+
+function GuildFramePopup_Show(frame)
+ local name = frame:GetName();
+ for index, value in ipairs(GUILDFRAME_POPUPS) do
+ if ( name ~= value ) then
+ _G[value]:Hide();
+ end
+ end
+ frame:Show();
+end
+
+function GuildFramePopup_HideAll()
+ for index, value in ipairs(GUILDFRAME_POPUPS) do
+ _G[value]:Hide();
+ end
+end
+
+-- Battle.net stuff starts here
+
+function FriendsFrame_CheckBattlenetStatus()
+ if ( BNFeaturesEnabled() ) then
+ if ( BNConnected() ) then
+ BNetBroadcasts, numOnlineBroadcasts, numOfflineBroadcasts = BNGetCustomMessageTable(BNetBroadcasts);
+ if(not BNetBroadcasts) then
+ BNetBroadcasts = { };
+ end
+ playerRealmName = GetRealmName();
+ playerFactionGroup = UnitFactionGroup("player");
+ FriendsFrameBattlenetStatus:Hide();
+ FriendsFrameStatusDropDown:Show();
+ FriendsFrameBroadcastInput:Show();
+ FriendsFrameBroadcastInput_UpdateDisplay();
+ else
+ numOnlineBroadcasts = 0;
+ numOfflineBroadcasts = 0;
+ FriendsFrameBattlenetStatus:Show();
+ FriendsFrameStatusDropDown:Hide();
+ FriendsFrameBroadcastInput:Hide();
+ FriendsFrameOfflineHeader:Hide();
+ end
+ if ( FriendsFrame:IsShown() ) then
+ IgnoreList_Update();
+ PendingList_Update();
+ end
+ -- has its own check if it is being shown, after it updates the count on the FriendsMicroButton
+ FriendsList_Update();
+ end
+end
+
+function FriendsFrame_GetTopButton(offset)
+ local heightLeft = offset;
+ local priorHeight = 0;
+ local buttonHeight;
+ local numBNetTotal, numBNetOnline = BNGetNumFriends();
+ local numBNetOffline = numBNetTotal - numBNetOnline;
+ local numWoWTotal, numWoWOnline = GetNumFriends();
+ local numWoWOffline = numWoWTotal - numWoWOnline;
+ local buttonIndex = 0;
+
+ -- online
+ if ( numBNetOnline + numWoWOnline > 0 ) then
+ local totalBNOnlineHeight = numBNetOnline * FRIENDS_BUTTON_NORMAL_HEIGHT + numOnlineBroadcasts * (FRIENDS_BUTTON_LARGE_HEIGHT - FRIENDS_BUTTON_NORMAL_HEIGHT);
+ if ( heightLeft < totalBNOnlineHeight ) then
+ for i = 1, numBNetOnline do
+ if ( BNetBroadcasts[i] ) then
+ buttonHeight = FRIENDS_BUTTON_LARGE_HEIGHT;
+ else
+ buttonHeight = FRIENDS_BUTTON_NORMAL_HEIGHT;
+ end
+ if ( (heightLeft - buttonHeight) < 1 ) then
+ return i + buttonIndex, offset - heightLeft, totalScrollHeight;
+ else
+ heightLeft = heightLeft - buttonHeight;
+ end
+ end
+ end
+ heightLeft = heightLeft - totalBNOnlineHeight;
+ buttonIndex = buttonIndex + numBNetOnline;
+ if ( heightLeft < numWoWOnline * FRIENDS_BUTTON_NORMAL_HEIGHT ) then
+ local index = math.floor(heightLeft / FRIENDS_BUTTON_NORMAL_HEIGHT) + 1;
+ return buttonIndex + index, offset - heightLeft + (index - 1) * FRIENDS_BUTTON_NORMAL_HEIGHT, totalScrollHeight;
+ end
+ heightLeft = heightLeft - numWoWOnline * FRIENDS_BUTTON_NORMAL_HEIGHT;
+ buttonIndex = buttonIndex + numWoWOnline;
+ end
+ -- offline
+ if ( numBNetOffline + numWoWOffline > 0 ) then
+ -- check header first
+ if ( numBNetOnline + numWoWOnline > 0 ) then
+ buttonIndex = buttonIndex + 1;
+ if ( heightLeft < FRIENDS_BUTTON_HEADER_HEIGHT ) then
+ return buttonIndex, offset - heightLeft, totalScrollHeight;
+ else
+ heightLeft = heightLeft - FRIENDS_BUTTON_HEADER_HEIGHT;
+ end
+ end
+ local totalBNOfflineHeight = numBNetOffline * FRIENDS_BUTTON_NORMAL_HEIGHT + numOfflineBroadcasts * (FRIENDS_BUTTON_LARGE_HEIGHT - FRIENDS_BUTTON_NORMAL_HEIGHT);
+ if ( heightLeft < totalBNOfflineHeight ) then
+ for i = 1, numBNetOffline do
+ if ( BNetBroadcasts[numBNetOnline + i] ) then
+ buttonHeight = FRIENDS_BUTTON_LARGE_HEIGHT;
+ else
+ buttonHeight = FRIENDS_BUTTON_NORMAL_HEIGHT;
+ end
+ if ( (heightLeft - buttonHeight) < 1 ) then
+ return i + buttonIndex, offset - heightLeft, totalScrollHeight;
+ else
+ heightLeft = heightLeft - buttonHeight;
+ end
+ end
+ end
+ heightLeft = heightLeft - totalBNOfflineHeight;
+ buttonIndex = buttonIndex + numBNetOffline;
+ if ( heightLeft < numWoWOffline * FRIENDS_BUTTON_NORMAL_HEIGHT ) then
+ local index = math.floor(heightLeft / FRIENDS_BUTTON_NORMAL_HEIGHT) + 1;
+ return buttonIndex + index, offset - heightLeft + (index - 1) * FRIENDS_BUTTON_NORMAL_HEIGHT, totalScrollHeight;
+ end
+ end
+end
+
+function FriendsFrame_SetButton(button, index, firstButton)
+ local height;
+ local nameText, nameColor, infoText, broadcastText;
+
+ if ( firstButton ) then
+ FriendsFrameOfflineHeader:Hide();
+ DynamicScrollFrame_UnlockAllHighlights(FriendsFrameFriendsScrollFrame);
+ end
+ button.buttonType = FriendButtons[index].buttonType;
+ button.id = FriendButtons[index].id;
+ if ( FriendButtons[index].buttonType == FRIENDS_BUTTON_TYPE_WOW ) then
+ local name, level, class, area, connected, status, note = GetFriendInfo(FriendButtons[index].id);
+ if ( connected ) then
+ button.background:SetTexture(FRIENDS_WOW_BACKGROUND_COLOR.r, FRIENDS_WOW_BACKGROUND_COLOR.g, FRIENDS_WOW_BACKGROUND_COLOR.b, FRIENDS_WOW_BACKGROUND_COLOR.a);
+ if ( status == "" ) then
+ button.status:SetTexture(FRIENDS_TEXTURE_ONLINE);
+ elseif ( status == CHAT_FLAG_AFK ) then
+ button.status:SetTexture(FRIENDS_TEXTURE_AFK);
+ elseif ( status == CHAT_FLAG_DND ) then
+ button.status:SetTexture(FRIENDS_TEXTURE_DND);
+ end
+ nameText = name..", "..format(FRIENDS_LEVEL_TEMPLATE, level, class);
+ nameColor = FRIENDS_WOW_NAME_COLOR;
+ else
+ button.background:SetTexture(FRIENDS_OFFLINE_BACKGROUND_COLOR.r, FRIENDS_OFFLINE_BACKGROUND_COLOR.g, FRIENDS_OFFLINE_BACKGROUND_COLOR.b, FRIENDS_OFFLINE_BACKGROUND_COLOR.a);
+ button.status:SetTexture(FRIENDS_TEXTURE_OFFLINE);
+ nameText = name;
+ nameColor = FRIENDS_GRAY_COLOR;
+ end
+ infoText = area;
+ button.gameIcon:Hide();
+ FriendsFrame_SummonButton_Update(button.summonButton);
+ elseif ( FriendButtons[index].buttonType == FRIENDS_BUTTON_TYPE_BNET ) then
+ local presenceID, givenName, surname, toonName, toonID, client, isOnline, lastOnline, isAFK, isDND, messageText, noteText = BNGetFriendInfo(FriendButtons[index].id);
+ broadcastText = messageText;
+ if ( isOnline ) then
+ local _, _, _, _, _, _, _, _, zoneName, _, gameText = BNGetToonInfo(toonID);
+ button.background:SetTexture(FRIENDS_BNET_BACKGROUND_COLOR.r, FRIENDS_BNET_BACKGROUND_COLOR.g, FRIENDS_BNET_BACKGROUND_COLOR.b, FRIENDS_BNET_BACKGROUND_COLOR.a);
+ if ( isAFK ) then
+ button.status:SetTexture(FRIENDS_TEXTURE_AFK);
+ elseif ( isDND ) then
+ button.status:SetTexture(FRIENDS_TEXTURE_DND);
+ else
+ button.status:SetTexture(FRIENDS_TEXTURE_ONLINE);
+ end
+ if ( client == BNET_CLIENT_WOW ) then
+ if ( not zoneName or zoneName == "" ) then
+ infoText = UNKNOWN;
+ else
+ infoText = zoneName;
+ end
+ button.gameIcon:SetTexture("Interface\\FriendsFrame\\Battlenet-WoWicon");
+ elseif ( client == BNET_CLIENT_SC2 ) then
+ button.gameIcon:SetTexture("Interface\\FriendsFrame\\Battlenet-Sc2icon");
+ infoText = gameText;
+ end
+ nameColor = FRIENDS_BNET_NAME_COLOR;
+ button.gameIcon:Show();
+ else
+ button.background:SetTexture(FRIENDS_OFFLINE_BACKGROUND_COLOR.r, FRIENDS_OFFLINE_BACKGROUND_COLOR.g, FRIENDS_OFFLINE_BACKGROUND_COLOR.b, FRIENDS_OFFLINE_BACKGROUND_COLOR.a);
+ button.status:SetTexture(FRIENDS_TEXTURE_OFFLINE);
+ nameColor = FRIENDS_GRAY_COLOR;
+ button.gameIcon:Hide();
+ if ( lastOnline == 0 ) then
+ infoText = FRIENDS_LIST_OFFLINE;
+ else
+ infoText = string.format(BNET_LAST_ONLINE_TIME, FriendsFrame_GetLastOnline(lastOnline));
+ end
+ end
+ if ( givenName and surname ) then
+ if ( toonName ) then
+ if ( client == BNET_CLIENT_WOW and CanCooperateWithToon(toonID) ) then
+ nameText = string.format(BATTLENET_NAME_FORMAT, givenName, surname).." "..FRIENDS_WOW_NAME_COLOR_CODE.."("..toonName..")";
+ else
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ toonName = toonName..CANNOT_COOPERATE_LABEL;
+ end
+ nameText = string.format(BATTLENET_NAME_FORMAT, givenName, surname).." "..FRIENDS_OTHER_NAME_COLOR_CODE.."("..toonName..")";
+ end
+ else
+ nameText = string.format(BATTLENET_NAME_FORMAT, givenName, surname);
+ end
+ else
+ nameText = UNKNOWN;
+ end
+ FriendsFrame_SummonButton_Update(button.summonButton);
+ else -- header
+ button:Hide();
+ FriendsFrameOfflineHeader:Show();
+ FriendsFrameOfflineHeader:SetAllPoints(button);
+ return FRIENDS_BUTTON_HEADER_HEIGHT;
+ end
+
+ if ( FriendsFrame.selectedFriendType == FriendButtons[index].buttonType and FriendsFrame.selectedFriend == FriendButtons[index].id ) then
+ button:LockHighlight();
+ end
+
+ button.name:SetText(nameText);
+ button.name:SetTextColor(nameColor.r, nameColor.g, nameColor.b);
+ button.info:SetText(infoText);
+ -- don't display a broadcast if the BNetBroadcasts data is out of sync
+ if ( broadcastText and broadcastText ~= "" and BNetBroadcasts[FriendButtons[index].id] ) then
+ height = FRIENDS_BUTTON_LARGE_HEIGHT;
+ button.broadcastMessage:SetText(broadcastText);
+ button.broadcastMessage:Show();
+ button.broadcastIcon:Show();
+ else
+ height = FRIENDS_BUTTON_NORMAL_HEIGHT;
+ button.broadcastMessage:Hide();
+ button.broadcastIcon:Hide();
+ end
+ -- update the tooltip if hovering over a button
+ if ( FriendsTooltip.button == button ) then
+ FriendsFrameTooltip_Show(button);
+ end
+ button:Show();
+ return height;
+end
+
+function FriendsFrameStatusDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, FriendsFrameStatusDropDown_Initialize);
+ UIDropDownMenu_SetWidth(FriendsFrameStatusDropDown, 28);
+ FriendsFrameStatusDropDownText:Hide();
+ FriendsFrameStatusDropDownButton:SetScript("OnEnter", FriendsFrameStatusDropDown_ShowTooltip);
+ FriendsFrameStatusDropDownButton:SetScript("OnLeave", function() GameTooltip:Hide(); end);
+end
+
+function FriendsFrameStatusDropDown_ShowTooltip()
+ local statusText;
+ local status = FriendsFrameStatusDropDown.status;
+ if ( status == 2 ) then
+ statusText = FRIENDS_LIST_AWAY;
+ elseif ( status == 3 ) then
+ statusText = FRIENDS_LIST_BUSY;
+ else
+ statusText = FRIENDS_LIST_AVAILABLE;
+ end
+ GameTooltip:SetOwner(FriendsFrameStatusDropDown, "ANCHOR_RIGHT", -18, 0);
+ GameTooltip:SetText(format(FRIENDS_LIST_STATUS_TOOLTIP, statusText));
+ GameTooltip:Show();
+end
+
+function FriendsFrameStatusDropDown_OnShow(self)
+ UIDropDownMenu_Initialize(self, FriendsFrameStatusDropDown_Initialize);
+ FriendsFrameStatusDropDown_Update(self);
+end
+
+function FriendsFrameStatusDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+ local optionText = "\124T%s.tga:16:16:0:0\124t %s";
+ info.padding = 8;
+ info.checked = nil;
+ info.notCheckable = 1;
+ info.func = FriendsFrame_SetOnlineStatus;
+
+ info.text = string.format(optionText, FRIENDS_TEXTURE_ONLINE, FRIENDS_LIST_AVAILABLE);
+ UIDropDownMenu_AddButton(info);
+
+ info.text = string.format(optionText, FRIENDS_TEXTURE_AFK, FRIENDS_LIST_AWAY);
+ UIDropDownMenu_AddButton(info);
+
+ info.text = string.format(optionText, FRIENDS_TEXTURE_DND, FRIENDS_LIST_BUSY);
+ UIDropDownMenu_AddButton(info);
+end
+
+function FriendsFrameStatusDropDown_Update(self)
+ local status;
+ self = self or FriendsFrameStatusDropDown;
+ if ( UnitIsAFK("player") ) then
+ FriendsFrameStatusDropDownStatus:SetTexture(FRIENDS_TEXTURE_AFK);
+ status = 2;
+ elseif ( UnitIsDND("player") ) then
+ FriendsFrameStatusDropDownStatus:SetTexture(FRIENDS_TEXTURE_DND);
+ status = 3;
+ else
+ FriendsFrameStatusDropDownStatus:SetTexture(FRIENDS_TEXTURE_ONLINE);
+ status = 1;
+ end
+ FriendsFrameStatusDropDown.status = status;
+end
+
+function FriendsFrame_SetOnlineStatus(button, status)
+ status = status or button:GetID();
+ if ( status == FriendsFrameStatusDropDown.status ) then
+ return;
+ end
+ if ( status == 1 ) then
+ if ( UnitIsAFK("player") ) then
+ SendChatMessage("", "AFK");
+ elseif ( UnitIsDND("player") ) then
+ SendChatMessage("", "DND");
+ end
+ elseif ( status == 2 ) then
+ SendChatMessage("", "AFK");
+ else
+ SendChatMessage("", "DND");
+ end
+end
+
+function FriendsFrameBroadcastInput_OnEnterPressed(self)
+ local broadcastText = self:GetText()
+ BNSetCustomMessage(broadcastText);
+ FriendsFrameBroadcastInput_UpdateDisplay(self, broadcastText);
+end
+
+function FriendsFrameBroadcastInput_OnEscapePressed(self)
+ FriendsFrameBroadcastInput_UpdateDisplay(self);
+end
+
+function FriendsFrameBroadcastInput_OnClearPressed(self)
+ BNSetCustomMessage("");
+ FriendsFrameBroadcastInput_UpdateDisplay(nil, "");
+end
+
+function FriendsFrameBroadcastInput_UpdateDisplay(self, broadcastText)
+ local _;
+ self = self or FriendsFrameBroadcastInput;
+ if ( not broadcastText ) then
+ _, _, broadcastText = BNGetInfo();
+ broadcastText = broadcastText or "";
+ end
+ self:ClearFocus();
+ self:SetText(broadcastText);
+ if ( broadcastText ~= "" ) then
+ self.icon:SetAlpha(1);
+ self:SetCursorPosition(0);
+ self.clear:Show();
+ self:SetTextInsets(0, 18, 0, 0);
+ else
+ self.icon:SetAlpha(0.35);
+ self.clear:Hide();
+ self:SetTextInsets(0, 10, 0, 0);
+ end
+end
+
+function FriendsFrameTooltip_Show(self)
+ if ( self.buttonType == FRIENDS_BUTTON_TYPE_HEADER ) then
+ return;
+ end
+ local anchor, text;
+ local FRIENDS_TOOLTIP_WOW_INFO_TEMPLATE = NORMAL_FONT_COLOR_CODE..FRIENDS_LIST_ZONE.."|r%1$s|n"..NORMAL_FONT_COLOR_CODE..FRIENDS_LIST_REALM.."|r%2$s";
+ local numToons = 0;
+ local tooltip = FriendsTooltip;
+ tooltip.height = 0;
+ tooltip.maxWidth = 0;
+
+ if ( self.buttonType == FRIENDS_BUTTON_TYPE_BNET ) then
+ local nameText;
+ local presenceID, givenName, surname, toonName, toonID, client, isOnline, lastOnline, isAFK, isDND, broadcastText, noteText, isFriend, broadcastTime = BNGetFriendInfo(self.id);
+ -- account name
+ if ( givenName and surname ) then
+ nameText = format(BATTLENET_NAME_FORMAT, givenName, surname);
+ else
+ nameText = UNKNOWN;
+ end
+ anchor = FriendsFrameTooltip_SetLine(FriendsTooltipHeader, nil, nameText);
+ -- toon 1
+ if ( toonID ) then
+ local hasFocus, toonName, client, realmName, faction, race, class, guild, zoneName, level, gameText = BNGetToonInfo(toonID);
+ level = level or "";
+ race = race or "";
+ class = class or "";
+ if ( client == BNET_CLIENT_WOW ) then
+ if ( CanCooperateWithToon(toonID) ) then
+ text = string.format(FRIENDS_TOOLTIP_WOW_TOON_TEMPLATE, toonName, level, race, class);
+ else
+ text = string.format(FRIENDS_TOOLTIP_WOW_TOON_TEMPLATE, toonName..CANNOT_COOPERATE_LABEL, level, race, class);
+ end
+ FriendsFrameTooltip_SetLine(FriendsTooltipToon1Name, nil, text);
+ anchor = FriendsFrameTooltip_SetLine(FriendsTooltipToon1Info, nil, string.format(FRIENDS_TOOLTIP_WOW_INFO_TEMPLATE, zoneName, realmName), -4);
+ elseif ( client == BNET_CLIENT_SC2 ) then
+ FriendsFrameTooltip_SetLine(FriendsTooltipToon1Name, nil, toonName);
+ anchor = FriendsFrameTooltip_SetLine(FriendsTooltipToon1Info, nil, gameText, -4);
+ end
+ else
+ FriendsTooltipToon1Info:Hide();
+ FriendsTooltipToon1Name:Hide();
+ end
+ -- note
+ if ( noteText and noteText ~= "" ) then
+ FriendsTooltipNoteIcon:Show();
+ anchor = FriendsFrameTooltip_SetLine(FriendsTooltipNoteText, anchor, noteText, -8);
+ else
+ FriendsTooltipNoteIcon:Hide();
+ FriendsTooltipNoteText:Hide();
+ end
+ -- broadcast
+ if ( broadcastText and broadcastText ~= "" ) then
+ FriendsTooltipBroadcastIcon:Show();
+ broadcastText = broadcastText.."|n"..FRIENDS_BROADCAST_TIME_COLOR_CODE..string.format(BNET_BROADCAST_SENT_TIME, FriendsFrame_GetLastOnline(broadcastTime));
+ anchor = FriendsFrameTooltip_SetLine(FriendsTooltipBroadcastText, anchor, broadcastText, -8);
+ else
+ FriendsTooltipBroadcastIcon:Hide();
+ FriendsTooltipBroadcastText:Hide();
+ end
+ if ( isOnline ) then
+ FriendsTooltipHeader:SetTextColor(FRIENDS_BNET_NAME_COLOR.r, FRIENDS_BNET_NAME_COLOR.g, FRIENDS_BNET_NAME_COLOR.b);
+ FriendsTooltipLastOnline:Hide();
+ numToons = BNGetNumFriendToons(self.id);
+ else
+ FriendsTooltipHeader:SetTextColor(FRIENDS_GRAY_COLOR.r, FRIENDS_GRAY_COLOR.g, FRIENDS_GRAY_COLOR.b);
+ if ( lastOnline == 0 ) then
+ text = FRIENDS_LIST_OFFLINE;
+ else
+ text = string.format(BNET_LAST_ONLINE_TIME, FriendsFrame_GetLastOnline(lastOnline));
+ end
+ anchor = FriendsFrameTooltip_SetLine(FriendsTooltipLastOnline, anchor, text, -4);
+ end
+ elseif ( self.buttonType == FRIENDS_BUTTON_TYPE_WOW ) then
+ local name, level, class, area, connected, status, noteText = GetFriendInfo(self.id);
+ anchor = FriendsFrameTooltip_SetLine(FriendsTooltipHeader, nil, name);
+ if ( connected ) then
+ FriendsTooltipHeader:SetTextColor(FRIENDS_WOW_NAME_COLOR.r, FRIENDS_WOW_NAME_COLOR.g, FRIENDS_WOW_NAME_COLOR.b);
+ FriendsFrameTooltip_SetLine(FriendsTooltipToon1Name, nil, string.format(FRIENDS_LEVEL_TEMPLATE, level, class));
+ anchor = FriendsFrameTooltip_SetLine(FriendsTooltipToon1Info, nil, area);
+ else
+ FriendsTooltipHeader:SetTextColor(FRIENDS_GRAY_COLOR.r, FRIENDS_GRAY_COLOR.g, FRIENDS_GRAY_COLOR.b);
+ FriendsTooltipToon1Name:Hide();
+ FriendsTooltipToon1Info:Hide();
+ end
+ if ( noteText ) then
+ FriendsTooltipNoteIcon:Show();
+ anchor = FriendsFrameTooltip_SetLine(FriendsTooltipNoteText, anchor, noteText, -8);
+ else
+ FriendsTooltipNoteIcon:Hide();
+ FriendsTooltipNoteText:Hide();
+ end
+ FriendsTooltipBroadcastIcon:Hide();
+ FriendsTooltipBroadcastText:Hide();
+ FriendsTooltipLastOnline:Hide();
+ end
+
+ -- other toons
+ local toonIndex = 1;
+ local toonNameString;
+ local toonInfoString;
+ if ( numToons > 1 ) then
+ FriendsFrameTooltip_SetLine(FriendsTooltipOtherToons, anchor, nil, -8);
+ for i = 1, numToons do
+ local hasFocus, toonName, client, realmName, faction, race, class, guild, zoneName, level, gameText = BNGetFriendToonInfo(self.id, i);
+ -- the focused toon is already at the top of the tooltip
+ if ( not hasFocus ) then
+ toonIndex = toonIndex + 1;
+ if ( toonIndex > FRIENDS_TOOLTIP_MAX_TOONS ) then
+ break;
+ end
+ toonNameString = _G["FriendsTooltipToon"..toonIndex.."Name"];
+ toonInfoString = _G["FriendsTooltipToon"..toonIndex.."Info"];
+ if ( client == BNET_CLIENT_WOW ) then
+ if ( realmName == playerRealmName and PLAYER_FACTION_GROUP[faction] == playerFactionGroup ) then
+ text = string.format(FRIENDS_TOOLTIP_WOW_TOON_TEMPLATE, toonName, level, race, class);
+ else
+ text = string.format(FRIENDS_TOOLTIP_WOW_TOON_TEMPLATE, toonName..CANNOT_COOPERATE_LABEL, level, race, class);
+ end
+ gameText = zoneName;
+ elseif ( client == BNET_CLIENT_SC2 ) then
+ text = toonName;
+ end
+ FriendsFrameTooltip_SetLine(toonNameString, nil, text);
+ FriendsFrameTooltip_SetLine(toonInfoString, nil, gameText);
+ end
+ end
+ else
+ FriendsTooltipOtherToons:Hide();
+ end
+ for i = toonIndex + 1, FRIENDS_TOOLTIP_MAX_TOONS do
+ toonNameString = _G["FriendsTooltipToon"..i.."Name"];
+ toonInfoString = _G["FriendsTooltipToon"..i.."Info"];
+ toonNameString:Hide();
+ toonInfoString:Hide();
+ end
+ if ( numToons > FRIENDS_TOOLTIP_MAX_TOONS ) then
+ FriendsFrameTooltip_SetLine(FriendsTooltipToonMany, nil, string.format(FRIENDS_TOOLTIP_TOO_MANY_CHARACTERS, numToons - FRIENDS_TOOLTIP_MAX_TOONS), 0);
+ else
+ FriendsTooltipToonMany:Hide();
+ end
+
+ tooltip.button = self;
+ tooltip:SetPoint("TOPLEFT", self, "TOPRIGHT", 36, 0);
+ tooltip:SetHeight(tooltip.height + FRIENDS_TOOLTIP_MARGIN_WIDTH);
+ tooltip:SetWidth(min(FRIENDS_TOOLTIP_MAX_WIDTH, tooltip.maxWidth + FRIENDS_TOOLTIP_MARGIN_WIDTH));
+ tooltip:Show();
+end
+
+function FriendsFrameTooltip_SetLine(line, anchor, text, yOffset)
+ local tooltip = FriendsTooltip;
+ local top = 0;
+ local left = FRIENDS_TOOLTIP_MAX_WIDTH - FRIENDS_TOOLTIP_MARGIN_WIDTH - line:GetWidth();
+
+ if ( text ) then
+ line:SetText(text);
+ end
+ if ( anchor ) then
+ top = yOffset or 0;
+ line:SetPoint("TOP", anchor, "BOTTOM", 0, top);
+ else
+ local point, _, _, _, y = line:GetPoint(1);
+ if ( point == "TOP" or point == "TOPLEFT" ) then
+ top = y;
+ end
+ end
+ line:Show();
+ tooltip.height = tooltip.height + line:GetHeight() - top;
+ tooltip.maxWidth = max(tooltip.maxWidth, line:GetStringWidth() + left);
+ return line;
+end
+
+function AddFriendFrame_OnShow()
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ local textureFile = "Interface\\FriendsFrame\\PlusManz-"..factionGroup;
+ AddFriendInfoFrameFactionIcon:SetTexture(textureFile);
+ AddFriendInfoFrameFactionIcon:Show();
+ AddFriendEntryFrameRightIcon:SetTexture(textureFile);
+ AddFriendEntryFrameRightIcon:Show();
+ end
+end
+
+function AddFriendFrame_ShowInfo()
+ AddFriendFrame:SetWidth(AddFriendInfoFrame:GetWidth());
+ AddFriendFrame:SetHeight(AddFriendInfoFrame:GetHeight());
+ AddFriendInfoFrame:Show();
+ AddFriendEntryFrame:Hide();
+ PlaySound("igMainMenuOpen");
+end
+
+function AddFriendFrame_ShowEntry()
+ AddFriendFrame:SetWidth(AddFriendEntryFrame:GetWidth());
+ AddFriendFrame:SetHeight(AddFriendEntryFrame:GetHeight());
+ AddFriendInfoFrame:Hide();
+ AddFriendEntryFrame:Show();
+ if ( BNFeaturesEnabledAndConnected() ) then
+ AddFriendFrame.BNconnected = true;
+ AddFriendEntryFrameLeftTitle:SetAlpha(1);
+ AddFriendEntryFrameLeftDescription:SetText(BATTLENET_FRIEND_LABEL);
+ AddFriendEntryFrameLeftDescription:SetTextColor(1, 1, 1);
+ AddFriendEntryFrameLeftIcon:SetVertexColor(1, 1, 1);
+ AddFriendEntryFrameLeftFriend:SetVertexColor(1, 1, 1);
+ else
+ AddFriendFrame.BNconnected = nil;
+ AddFriendEntryFrameLeftTitle:SetAlpha(0.35);
+ AddFriendEntryFrameLeftDescription:SetText(BATTLENET_UNAVAILABLE);
+ AddFriendEntryFrameLeftDescription:SetTextColor(1, 0, 0);
+ AddFriendEntryFrameLeftIcon:SetVertexColor(.4, .4, .4);
+ AddFriendEntryFrameLeftFriend:SetVertexColor(.4, .4, .4);
+ end
+ if ( AddFriendFrame.editFocus ) then
+ AddFriendFrame.editFocus:SetFocus();
+ end
+ PlaySound("igMainMenuOpen");
+end
+
+function AddFriendNameEditBox_OnTextChanged(self, userInput)
+ if ( not AutoCompleteEditBox_OnTextChanged(self, userInput) ) then
+ local text = self:GetText();
+ if ( text ~= "" ) then
+ AddFriendNameEditBoxFill:Hide();
+ if ( AddFriendFrame.BNconnected ) then
+ if ( string.find(text, "@") ) then
+ AddFriendEntryFrame_Expand();
+ else
+ AddFriendEntryFrame_Collapse();
+ end
+ end
+ else
+ AddFriendEntryFrame_Collapse();
+ AddFriendNameEditBoxFill:Show();
+ end
+ end
+end
+
+function AddFriendEntryFrame_Expand()
+ AddFriendEntryFrame:SetHeight(296);
+ AddFriendFrame:SetHeight(296);
+ AddFriendNoteFrame:Show();
+ AddFriendEntryFrameAcceptButton:SetText(SEND_REQUEST);
+ AddFriendEntryFrameRightTitle:SetAlpha(0.35);
+ AddFriendEntryFrameRightDescription:SetAlpha(0.35);
+ AddFriendEntryFrameRightIcon:SetVertexColor(.4, .4, .4);
+ AddFriendEntryFrameRightFriend:SetVertexColor(.4, .4, .4);
+ AddFriendEntryFrameLeftIcon:SetAlpha(1);
+ AddFriendEntryFrameOrLabel:SetVertexColor(.3, .3, .3);
+end
+
+function AddFriendEntryFrame_Collapse(clearText)
+ AddFriendEntryFrame:SetHeight(218);
+ AddFriendFrame:SetHeight(218);
+ AddFriendNoteFrame:Hide();
+ AddFriendEntryFrameAcceptButton:SetText(ADD_FRIEND);
+ AddFriendEntryFrameRightTitle:SetAlpha(1);
+ AddFriendEntryFrameRightDescription:SetAlpha(1);
+ AddFriendEntryFrameRightIcon:SetVertexColor(1, 1, 1);
+ AddFriendEntryFrameRightFriend:SetVertexColor(1, 1, 1);
+ AddFriendEntryFrameLeftIcon:SetAlpha(0.5);
+ if ( AddFriendFrame.BNconnected ) then
+ AddFriendEntryFrameOrLabel:SetVertexColor(1, 1, 1);
+ else
+ AddFriendEntryFrameOrLabel:SetVertexColor(0.3, 0.3, 0.3);
+ end
+ if ( clearText ) then
+ AddFriendNameEditBox:SetText("");
+ AddFriendNoteEditBox:SetText("");
+ end
+end
+
+function AddFriendFrame_Accept()
+ local name = AddFriendNameEditBox:GetText();
+ if ( AddFriendFrame.BNconnected and string.find(name, "@") ) then
+ BNSendFriendInvite(name, AddFriendNoteEditBox:GetText());
+ else
+ AddFriend(name);
+ end
+ StaticPopupSpecial_Hide(AddFriendFrame);
+end
+
+function FriendsFriendsFrameDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+ local value = FriendsFriendsFrame.view;
+
+ info.value = FRIENDS_FRIENDS_ALL;
+ info.text = FRIENDS_FRIENDS_CHOICE_EVERYONE;
+ info.func = FriendsFriendsFrameDropDown_OnClick;
+ info.arg1 = FRIENDS_FRIENDS_ALL;
+ if ( value == info.value ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(FriendsFriendsFrameDropDown, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+
+ info.value = FRIENDS_FRIENDS_POTENTIAL;
+ info.text = FRIENDS_FRIENDS_CHOICE_POTENTIAL;
+ info.func = FriendsFriendsFrameDropDown_OnClick;
+ info.arg1 = FRIENDS_FRIENDS_POTENTIAL;
+ if ( value == info.value ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(FriendsFriendsFrameDropDown, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+
+ info.value = FRIENDS_FRIENDS_MUTUAL;
+ info.text = FRIENDS_FRIENDS_CHOICE_MUTUAL;
+ info.func = FriendsFriendsFrameDropDown_OnClick;
+ info.arg1 = FRIENDS_FRIENDS_MUTUAL;
+ if ( value == info.value ) then
+ info.checked = 1;
+ UIDropDownMenu_SetText(FriendsFriendsFrameDropDown, info.text);
+ else
+ info.checked = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+end
+
+function FriendsFriendsFrameDropDown_OnClick(self, value)
+ FriendsFriendsFrame.view = value;
+ UIDropDownMenu_SetSelectedValue(FriendsFriendsFrameDropDown, value);
+ FriendsFriendsScrollFrameScrollBar:SetValue(0);
+ FriendsFriendsList_Update();
+end
+
+function FriendsFriendsList_Update()
+ if ( FriendsFriendsWaitFrame:IsShown() ) then
+ return;
+ end
+
+ local friendsButton, friendsIndex;
+ local showMutual, showPotential;
+ local view = FriendsFriendsFrame.view;
+ local selection = FriendsFriendsFrame.selection;
+ local requested = FriendsFriendsFrame.requested;
+ local presenceID = FriendsFriendsFrame.presenceID;
+ local numFriendsFriends = 0;
+ local numMutual, numPotential = BNGetNumFOF(presenceID);
+ local offset = FauxScrollFrame_GetOffset(FriendsFriendsScrollFrame);
+ local haveSelection;
+ if ( view == FRIENDS_FRIENDS_POTENTIAL or view == FRIENDS_FRIENDS_ALL ) then
+ showPotential = true;
+ numFriendsFriends = numFriendsFriends + numPotential;
+ end
+ if ( view == FRIENDS_FRIENDS_MUTUAL or view == FRIENDS_FRIENDS_ALL ) then
+ showMutual = true;
+ numFriendsFriends = numFriendsFriends + numMutual;
+ end
+ for i = 1, FRIENDS_FRIENDS_TO_DISPLAY, 1 do
+ friendsIndex = i + offset;
+ friendsButton = _G["FriendsFriendsButton"..i];
+ if ( friendsIndex > numFriendsFriends ) then
+ friendsButton:Hide();
+ else
+ local friendID, givenName, surname, isMutual = BNGetFOFInfo(presenceID, showMutual, showPotential, friendsIndex);
+ local name = string.format(BATTLENET_NAME_FORMAT, givenName, surname);
+ if ( isMutual ) then
+ friendsButton:Disable();
+ if ( view ~= FRIENDS_FRIENDS_MUTUAL ) then
+ friendsButton.name:SetText(name.." "..HIGHLIGHT_FONT_COLOR_CODE..FRIENDS_FRIENDS_MUTUAL_TEXT);
+ else
+ friendsButton.name:SetText(name);
+ end
+ friendsButton.name:SetTextColor(GRAY_FONT_COLOR .r, GRAY_FONT_COLOR .g, GRAY_FONT_COLOR .b);
+ elseif ( requested[friendID] ) then
+ friendsButton.name:SetText(name.." "..HIGHLIGHT_FONT_COLOR_CODE..FRIENDS_FRIENDS_REQUESTED_TEXT);
+ friendsButton:Disable();
+ friendsButton.name:SetTextColor(GRAY_FONT_COLOR .r, GRAY_FONT_COLOR .g, GRAY_FONT_COLOR .b);
+ else
+ friendsButton.name:SetText(name);
+ friendsButton:Enable();
+ friendsButton.name:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ if ( selection == friendID ) then
+ haveSelection = true;
+ friendsButton:LockHighlight();
+ else
+ friendsButton:UnlockHighlight();
+ end
+ end
+ friendsButton.friendID = friendID;
+ friendsButton:Show();
+ end
+ end
+ if ( haveSelection ) then
+ FriendsFriendsSendRequestButton:Enable();
+ else
+ FriendsFriendsSendRequestButton:Disable();
+ end
+ FauxScrollFrame_Update(FriendsFriendsScrollFrame, numFriendsFriends, FRIENDS_FRIENDS_TO_DISPLAY, FRIENDS_FRAME_FRIENDS_FRIENDS_HEIGHT);
+end
+
+function FriendsFriendsButton_OnClick(self)
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ FriendsFriendsFrame.selection = self.friendID;
+ FriendsFriendsList_Update();
+end
+
+function FriendsFrameIgnoreButton_OnClick(self)
+ FriendsFrame_SelectSquelched(self.type, self.index);
+ IgnoreList_Update();
+end
+
+function FriendsFriendsFrame_SendRequest()
+ PlaySound("igCharacterInfoTab");
+ FriendsFriendsFrame.requested[FriendsFriendsFrame.selection] = true;
+ BNSendFriendInviteByID(FriendsFriendsFrame.selection, FriendsFriendsNoteEditBox:GetText());
+ FriendsFriendsFrame_Reset();
+ FriendsFriendsList_Update();
+end
+
+function FriendsFriendsFrame_Close()
+ StaticPopupSpecial_Hide(FriendsFriendsFrame);
+end
+
+function FriendsFriendsFrame_OnEvent(self, event)
+ if ( event == "BN_REQUEST_FOF_SUCCEEDED" ) then
+ if ( self:IsShown() ) then
+ FriendsFriendsFrame.view = FRIENDS_FRIENDS_ALL;
+ UIDropDownMenu_EnableDropDown(FriendsFriendsFrameDropDown);
+ UIDropDownMenu_Initialize(FriendsFriendsFrameDropDown, FriendsFriendsFrameDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(FriendsFriendsFrameDropDown, FRIENDS_FRIENDS_ALL);
+ local waitFrame = FriendsFriendsWaitFrame;
+ -- need to stop the flashing because it's flashing with showWhenDone set to true
+ if ( UIFrameIsFlashing(waitFrame) ) then
+ UIFrameFlashStop(waitFrame);
+ end
+ waitFrame:Hide();
+ FriendsFriendsList_Update();
+ end
+ elseif ( event == "BN_REQUEST_FOF_FAILED" ) then
+ -- FIX ME - need an error here
+ elseif ( event == "BN_DISCONNECTED" ) then
+ FriendsFriendsFrame_Close();
+ end
+end
+
+function FriendsFriendsFrame_Reset()
+ FriendsFriendsSendRequestButton:Disable();
+ FriendsFriendsNoteEditBox:SetText("");
+ FriendsFriendsNoteEditBox:ClearFocus();
+ FriendsFriendsFrame.selection = nil;
+end
+
+function FriendsFriendsFrame_Show(presenceID)
+ local presenceID, givenName, surname = BNGetFriendInfoByID(presenceID);
+ FriendsFriendsFrameTitle:SetFormattedText(FRIENDS_FRIENDS_HEADER, FRIENDS_BNET_NAME_COLOR_CODE..string.format(BATTLENET_NAME_FORMAT, givenName, surname));
+ FriendsFriendsFrame.presenceID = presenceID;
+ UIDropDownMenu_DisableDropDown(FriendsFriendsFrameDropDown);
+ FriendsFriendsFrame_Reset();
+ FriendsFriendsWaitFrame:Show();
+ for i = 1, FRIENDS_FRIENDS_TO_DISPLAY, 1 do
+ _G["FriendsFriendsButton"..i]:Hide();
+ end
+ FauxScrollFrame_Update(FriendsFriendsScrollFrame, 0, FRIENDS_FRIENDS_TO_DISPLAY, FRIENDS_FRAME_FRIENDS_FRIENDS_HEIGHT);
+ StaticPopupSpecial_Show(FriendsFriendsFrame);
+ BNRequestFOFInfo(presenceID);
+end
+
+function CanCooperateWithToon(toonID)
+ local hasFocus, toonName, client, realmName, faction = BNGetToonInfo(toonID);
+ if ( realmName == playerRealmName and PLAYER_FACTION_GROUP[faction] == playerFactionGroup ) then
+ return true;
+ else
+ return false;
+ end
+end
\ No newline at end of file
diff --git a/reference/FrameXML/FriendsFrame.xml b/reference/FrameXML/FriendsFrame.xml
new file mode 100644
index 0000000..1b566b9
--- /dev/null
+++ b/reference/FrameXML/FriendsFrame.xml
@@ -0,0 +1,5954 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Icon"]:SetTexture("Interface\\Icons\\Spell_Shadow_Teleport");
+ self:RegisterEvent("SPELL_UPDATE_COOLDOWN");
+ local normalTexture = _G[self:GetName().."NormalTexture"];
+ normalTexture:SetWidth(40);
+ normalTexture:SetHeight(40);
+
+
+ FriendsFrame_SummonButton_OnEvent(self, event, ...);
+
+
+ FriendsFrame_SummonButton_OnShow(self);
+
+
+ FriendsFrame_ClickSummonButton(self, button, down);
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:AddLine(RAF_SUMMON_LINKED, 1, 1, 1, 1);
+ if ( self.duration ) then
+ GameTooltip:AddLine(COOLDOWN_REMAINING .. " " .. SecondsToTime(self.duration - (GetTime() - self.start)), 1, 1, 1, 1);
+ end
+ if ( SHOW_NEWBIE_TIPS == "1" ) then
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_RAF_SUMMON_LINKED, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1)
+ end
+ GameTooltip:Show();
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+ self.highlight:SetVertexColor(0.243, 0.570, 1);
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+
+ FriendsTooltip.button = nil;
+ FriendsTooltip:Hide();
+
+
+ FriendsFrameFriendButton_OnClick(self, button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FriendsFrameIgnoreButton_OnClick(self);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -- smooth alpha from 0.2 to 0.6
+ local pulseInterval = mod(GetTime() * 1.5, math.pi);
+ self:SetAlpha(math.sin(pulseInterval) / 2.5 + 0.2)
+
+
+
+
+
+
+
+
+
+
+
+
+ BNAcceptFriendInvite(self:GetParent().inviteID);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+ BNDeclineFriendInvite(self:GetParent().inviteID);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.texture:SetAlpha(1.0);
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:AddLine(BNET_REPORT_PLAYER, 1, 1, 1);
+ GameTooltip:AddLine(BNET_REPORT_PLAYER_TOOLTIP, nil, nil, nil, 1);
+ GameTooltip:Show();
+
+
+ self.texture:SetAlpha(0.5);
+ GameTooltip:Hide();
+
+
+ self.texture:SetPoint("TOPLEFT", 1, 0);
+
+
+ self.texture:SetPoint("TOPLEFT", 0, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.texture:SetAlpha(1.0);
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:AddLine(BLOCK_INVITES, 1, 1, 1);
+ GameTooltip:AddLine(BLOCK_INVITES_TOOLTIP, nil, nil, nil, 1);
+ GameTooltip:Show();
+
+
+ self.texture:SetAlpha(0.5);
+ GameTooltip:Hide();
+
+
+ self.texture:SetPoint("TOPLEFT", 0, 0);
+
+
+ self.texture:SetPoint("TOPLEFT", -1, 1);
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0, 0.694, 0.941, 0.26);
+ self:SetBackdropColor(0, 0.090, 0.122, 0.6 );
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ FriendsFrameWhoButton_OnClick(self, button);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self.sortType ) then
+ SortWho(self.sortType);
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ FriendsFrameGuildStatusButton_OnClick(self, button, down);
+
+
+ GameTooltip_AddNewbieTip(self, GUILD_MEMBER_OPTIONS, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GUILD_MEMBER_OPTIONS, 1);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ FriendsFrameGuildStatusButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self.sortType ) then
+ SortGuildRoster(self.sortType);
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+ GuildControlSetRankFlag(self:GetID(), self:GetChecked());
+ GuildControlPopupAcceptButton:Enable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GuildBankTabPermissionsTab_OnClick(self:GetID());
+
+
+ if(self.tooltip) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip);
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PanelTemplates_Tab_OnClick(self, FriendsFrame);
+ FriendsFrame_OnShow();
+ GuildControlPopupFrame:Hide();
+ GuildMemberDetailFrame:Hide();
+ GuildInfoFrame:Hide();
+ GuildFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Texture"]:SetPoint("TOPLEFT", 1, -1);
+
+
+ _G[self:GetName().."Texture"]:SetPoint("TOPLEFT", 0, 0);
+
+
+ StaticPopup_Show("BATTLENET_UNAVAILABLE");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.icon:SetAlpha(0.35);
+
+
+
+
+
+
+ self.icon:SetAlpha(1);
+ self.clear:Hide();
+ self:SetTextInsets(0, 10, 0, 0);
+
+
+ FriendsFrameBroadcastInputTooltipButton:Show();
+
+
+ if ( self:GetText() ~= "" ) then
+ FriendsFrameBroadcastInputFill:Hide();
+ else
+ FriendsFrameBroadcastInputFill:Show();
+ end
+
+
+
+
+
+
+
+
+
+
+ local editBox = FriendsFrameBroadcastInput;
+ editBox:SetFocus();
+ editBox:SetCursorPosition(strlen(editBox:GetText()));
+ editBox:HighlightText(0, -1); -- highlight all
+ self:Hide();
+
+
+ GameTooltip:SetOwner(FriendsFrameBroadcastInput, "ANCHOR_RIGHT");
+ GameTooltip:SetText(BN_BROADCAST_TOOLTIP, nil, nil, nil, nil, 1);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.icon:SetAlpha(1.0);
+ self:SetPoint("RIGHT", -2, 0);
+ self.icon:SetAlpha(0.60);
+ self:SetPoint("RIGHT", -1, -1);
+ self:SetPoint("RIGHT", -2, 0);
+
+
+
+
+
+
+ frameLevel = self:GetFrameLevel();
+ FriendsFrameBroadcastInputTooltipButton:SetFrameLevel(frameLevel + 1);
+ FriendsFrameBroadcastInputClearButton:SetFrameLevel(frameLevel + 2);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PanelTemplates_TabResize(self, 0);
+ _G[self:GetName().."HighlightTexture"]:SetWidth(self:GetTextWidth() + 31);
+
+
+ PanelTemplates_Tab_OnClick(self, FriendsTabHeader);
+ FriendsFrame_Update();
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PanelTemplates_Tab_OnClick(self, FriendsTabHeader);
+ FriendsFrame_Update();
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PanelTemplates_Tab_OnClick(self, FriendsTabHeader);
+ FriendsFrame_Update();
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+ FriendsTabHeaderInviteAlert:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetAlpha(abs(mod(GetTime(), 2) - 1));
+
+
+
+
+
+
+ PanelTemplates_SetNumTabs(self, 3);
+ PanelTemplates_SetTab(self, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, ADD_FRIEND, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_ADDFRIEND, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, SEND_MESSAGE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_SENDMESSAGE, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel( self:GetFrameLevel() + 3 );
+
+
+ if ( UnitCanCooperate("player", "target") ) then
+ AddIgnore(UnitName("target"));
+ PlaySound("UChatScrollButton");
+ else
+ StaticPopup_Show("ADD_IGNORE");
+ end
+
+
+ GameTooltip_AddNewbieTip(self, IGNORE_PLAYER, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_IGNOREPLAYER, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel( self:GetFrameLevel() + 3 );
+
+
+
+ GameTooltip_AddNewbieTip(self, REMOVE_PLAYER, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_REMOVEPLAYER, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel( self:GetFrameLevel() + 3 );
+
+
+ if ( UnitCanCooperate("player", "target") ) then
+ AddMute(UnitName("target"));
+ PlaySound("UChatScrollButton");
+ else
+ StaticPopup_Show("ADD_MUTE");
+ end
+
+
+ GameTooltip_AddNewbieTip(self, MUTE_PLAYER, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_MUTEPLAYER, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, FRIENDS_FRAME_IGNORE_HEIGHT, IgnoreList_Update);
+
+
+
+
+
+
+ FriendsFrameIgnoredHeaderTitle:SetText(IGNORED);
+ FriendsFrameBlockedInviteHeaderTitle:SetText(BLOCKED_INVITES);
+ FriendsFrameBlockedToonHeaderTitle:SetText(BLOCKED_COMMUNICATION);
+ FriendsFrameMutedHeaderTitle:SetText(MUTED);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SetCVar("pendingInviteInfoShown", 1);
+ PendingListInfoFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local button = _G[self:GetName().."ScrollUpButton"];
+ button:SetScript("OnClick", function() FriendsFramePendingScrollFrame_AdjustScroll(-2); PlaySound("UChatScrollButton"); end);
+ local button = _G[self:GetName().."ScrollDownButton"];
+ button:SetScript("OnClick", function() FriendsFramePendingScrollFrame_AdjustScroll(2); PlaySound("UChatScrollButton"); end);
+
+
+ local value = self:GetValue();
+ local min, max = self:GetMinMaxValues();
+ if ( value == 0 ) then
+ _G[self:GetName().."ScrollUpButton"]:Disable();
+ else
+ _G[self:GetName().."ScrollUpButton"]:Enable();
+ end
+ if ( value == max ) then
+ _G[self:GetName().."ScrollDownButton"]:Disable();
+ else
+ _G[self:GetName().."ScrollDownButton"]:Enable();
+ end
+ PendingList_Scroll(value);
+
+
+
+
+
+
+ self.scrollBar:SetValueStep(1);
+ self.scrollHeight = self:GetHeight();
+ FriendsFramePendingButton1.message:SetText(PENDING_INVITE);
+ MAX_INVITE_MESSAGE_HEIGHT = MAX_INVITE_MESSAGE_LINES * FriendsFramePendingButton1.message:GetHeight();
+
+
+ FriendsFramePendingScrollFrame_AdjustScroll(delta * -2);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 83);
+ self.sortType = "name";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UIDropDownMenu_Initialize(self, WhoFrameDropDown_Initialize);
+ UIDropDownMenu_SetSelectedID(self, 1);
+
+
+ WhoFrameDropDownHighlightTexture:Show();
+
+
+ WhoFrameDropDownHighlightTexture:Hide();
+
+
+ if ( WHOFRAME_DROPDOWN_LIST[UIDropDownMenu_GetSelectedID(self)].sortType ) then
+ SortWho(WHOFRAME_DROPDOWN_LIST[UIDropDownMenu_GetSelectedID(self)].sortType);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 105);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 32);
+ self.sortType = "level";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 92);
+ self.sortType = "class";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ InviteUnit(WhoFrame.selectedName);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AddFriend(WhoFrame.selectedName);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameEditBox_OnEnterPressed(WhoFrameEditBox);
+ WhoFrame.selectedWho = nil;
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, FRIENDS_FRAME_WHO_HEIGHT, WhoList_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SetWhoToUI(0);
+
+
+ SetWhoToUI(1);
+
+
+ SetWhoToUI(0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("VARIABLES_LOADED");
+
+
+ self:SetChecked(GetGuildRosterShowOffline());
+
+
+ SetGuildRosterSelection(0);
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+ SetGuildRosterShowOffline(self:GetChecked());
+ GuildStatus_Update();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 83);
+ self.sortType = "name";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 105);
+ self.sortType = "zone";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 32);
+ self.sortType = "level";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 92);
+ self.sortType = "class";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 83);
+ self.sortType = "name";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 75);
+ self.sortType = "rank";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 75);
+ self.sortType = "note";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 75);
+ self.sortType = "online";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, FRIENDS_FRAME_GUILD_HEIGHT, GuildStatus_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GuildFrameGuildListToggleButton_OnClick();
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GuildControlPopupFrame:IsShown() ) then
+ GuildControlPopupFrame:Hide();
+ else
+ GuildFramePopup_Show(GuildControlPopupFrame);
+ end
+
+
+ GameTooltip_AddNewbieTip(self, GUILDCONTROL, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GUILDCONTROL, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("ADD_GUILDMEMBER");
+
+
+ GameTooltip_AddNewbieTip(self, ADDMEMBER, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_ADDMEMBER, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, GUILD_INFORMATION, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GUILD_INFORMATION, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("SET_GUILDMOTD");
+
+
+
+
+
+
+
+ GuildControlPopupFrame:Hide();
+ GuildMemberDetailFrame:Hide();
+ GuildEventLogFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("ADD_GUILDRANK");
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(GUILDADDRANK_BUTTON_TOOLTIP);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(GUILDREMOVERANK_BUTTON_TOOLTIP);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetText() ~= UNLIMITED ) then
+ GuildControlPopupAcceptButton:Enable();
+ GuildControlPopupFrame.goldChanged = 1;
+ end
+
+
+ GuildControlPopupAcceptButton:Enable();
+
+
+ self:ClearFocus();
+ GuildControlPopupAcceptButton:Enable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+ GuildControlSetRankFlag(self:GetID(), self:GetChecked());
+ GuildControlPopupAcceptButton:Enable();
+ WithdrawGoldEditBox_Update();
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(GUILDCONTROL_OPTION16_TOOLTIP, nil, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+ GuildControlSetRankFlag(self:GetID(), self:GetChecked());
+ GuildControlPopupAcceptButton:Enable();
+ WithdrawGoldEditBox_Update();
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(GUILDCONTROL_OPTION15_TOOLTIP, nil, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GuildControlPopupAcceptButton:Enable();
+
+
+ self:ClearFocus();
+ GuildControlPopupAcceptButton:Enable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SetPendingGuildBankTabPermissions(GuildControlPopupFrameTabPermissions.selectedTab, self:GetID(), self:GetChecked());
+ GuildControlPopupAcceptButton:Enable();
+ GuildControlPopup_UpdateDepositCheckBox();
+
+
+
+
+
+
+
+
+
+
+
+ SetPendingGuildBankTabPermissions(GuildControlPopupFrameTabPermissions.selectedTab, self:GetID(), self:GetChecked());
+ GuildControlPopupAcceptButton:Enable();
+
+
+
+
+
+
+
+
+
+
+
+ SetPendingGuildBankTabPermissions(GuildControlPopupFrameTabPermissions.selectedTab, self:GetID(), self:GetChecked());
+ GuildControlPopupAcceptButton:Enable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GuildControlPopupAcceptButton:Enable();
+
+
+ local amount = self:GetText();
+ if(amount and amount ~= "" and amount ~= UNLIMITED) then
+ SetPendingGuildBankTabWithdraw(GuildControlPopupFrameTabPermissions.selectedTab, amount);
+ end
+
+
+ self:ClearFocus();
+ GuildControlPopupAcceptButton:Enable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.15, 0.15, 0.15);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( CanEditGuildInfo() ) then
+ GuildInfoEditBox:SetFocus();
+ else
+ GuildInfoEditBox:ClearFocus();
+ end
+
+
+ if ( CanEditGuildInfo() ) then
+ GuildInfoEditBox:SetFocus();
+ else
+ GuildInfoEditBox:ClearFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent());
+
+
+
+ ScrollingEdit_OnUpdate(self, 0, self:GetParent());
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+
+ -- If the player made a change GetGuildInfoText returns the old value until the next GUILD_ROSTER_UPDATE, so a cached value is used in the interim
+ local guildInfoText = GuildInfoFrame.cachedText or GetGuildInfoText();
+ if ( not guildInfoText ) then
+ guildInfoText = "";
+ end
+ if ( CanEditGuildInfo() ) then
+ if ( guildInfoText ~= "" ) then
+ GuildInfoEditBox:SetText(guildInfoText);
+ else
+ GuildInfoEditBox:SetText(GUILD_INFO_EDITLABEL);
+ end
+ GuildInfoEditBox:SetTextColor(1, 1, 1);
+ GuildInfoEditBox:EnableMouse(1);
+ GuildInfoSaveButton:Enable();
+ else
+ GuildInfoEditBox:SetText(guildInfoText);
+ GuildInfoEditBox:SetTextColor(0.65, 0.65, 0.65);
+ GuildInfoEditBox:EnableMouse();
+ GuildInfoSaveButton:Disable();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SetGuildInfoText(GuildInfoEditBox:GetText());
+ GuildInfoFrame.cachedText = GuildInfoEditBox:GetText();
+ GuildRoster();
+ GuildInfoFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("REMOVE_GUILDMEMBER");
+
+
+ GameTooltip_AddNewbieTip(self, REMOVE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GUILDREMOVE, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ InviteUnit(GuildFrame.selectedName);
+
+
+ GameTooltip_AddNewbieTip(self, GROUP_INVITE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GROUPINVITE, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GuildPromote(GuildFrame.selectedName);
+ PlaySound("UChatScrollButton");
+ GuildFramePromoteButton:Disable();
+
+
+ GameTooltip_AddNewbieTip(self, PROMOTE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_PROMOTE, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GuildDemote(GuildFrame.selectedName);
+ PlaySound("UChatScrollButton");
+ GuildFrameDemoteButton:Disable();
+
+
+ GameTooltip_AddNewbieTip(self, DEMOTE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_DEMOTE, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b, 0.25);
+
+
+ StaticPopup_Show("SET_GUILDPLAYERNOTE");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b, 0.5);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b, 0.25);
+
+
+ StaticPopup_Show("SET_GUILDOFFICERNOTE");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("GUILD_EVENT_LOG_UPDATE");
+
+
+ GuildEventLog_Update();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, MicroButtonTooltipText(FRIENDS, "TOGGLEFRIENDSTAB"), 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_FRIENDSTAB, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, MicroButtonTooltipText(WHO, "TOGGLEWHOTAB"), 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_WHOTAB, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ InGuildCheck();
+ FriendsFrame_Update();
+
+
+ PanelTemplates_Tab_OnClick(self, FriendsFrame);
+ FriendsFrame_OnShow();
+
+
+ GameTooltip_AddNewbieTip(self, MicroButtonTooltipText(GUILD, "TOGGLEGUILDTAB"), 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GUILDTAB, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, MicroButtonTooltipText(CHAT_CHANNELS, "TOGGLECHANNELTAB"), 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_CHANNELTAB, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, MicroButtonTooltipText(RAID, "TOGGLERAIDTAB"), 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_RAIDTAB, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FriendsFrame_OnEvent(self, event, ...);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SetCVar("addFriendInfoShown", 1);
+ AddFriendFrame_ShowEntry();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Texture"]:SetPoint("TOPLEFT", 1, -1);
+
+
+ _G[self:GetName().."Texture"]:SetPoint("TOPLEFT", 0, 0);
+
+
+ if ( AddFriendNameEditBox:HasFocus() ) then
+ AddFriendFrame.editFocus = AddFriendNameEditBox;
+ elseif ( AddFriendNoteEditBox:HasFocus() ) then
+ AddFriendFrame.editFocus = AddFriendNoteEditBox;
+ else
+ AddFriendFrame.editFocus = nil;
+ end
+ AddFriendFrame_ShowInfo();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.autoCompleteParams = AUTOCOMPLETE_LIST.ADDFRIEND;
+
+
+ if ( not AutoCompleteEditBox_OnEnterPressed(self) ) then
+ AddFriendFrame_Accept();
+ end
+
+
+ if ( AddFriendNoteEditBox:IsShown() and not AutoCompleteEditBox_OnTabPressed(self) ) then
+ AddFriendNoteEditBox:SetFocus();
+ end
+
+
+ self:ClearFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AddFriendNoteEditBox:SetFocus();
+
+
+
+
+
+
+ local scrollBar = _G[self:GetName().."ScrollBar"];
+ scrollBar:SetFrameLevel(_G[self:GetName().."FocusButton"]:GetFrameLevel() + 2);
+ scrollBar:ClearAllPoints();
+ scrollBar:SetPoint("TOPLEFT", self, "TOPRIGHT", -18, -10);
+ scrollBar:SetPoint("BOTTOMLEFT", self, "BOTTOMRIGHT", -18, 8);
+ -- reposition the up and down buttons
+ _G[self:GetName().."ScrollBarScrollDownButton"]:SetPoint("TOP", scrollBar, "BOTTOM", 0, 4);
+ _G[self:GetName().."ScrollBarScrollUpButton"]:SetPoint("BOTTOM", scrollBar, "TOP", 0, -4);
+ -- make the scroll bar hideable and force it to start off hidden so positioning calculations can be done
+ -- as soon as it needs to be shown
+ self.scrollBarHideable = 1;
+ scrollBar:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ AddFriendNameEditBox:SetFocus();
+
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent());
+ if ( self:GetText() ~= "" ) then
+ AddFriendNoteEditBoxFill:Hide();
+ else
+ AddFriendNoteEditBoxFill:Show();
+ end
+
+
+
+ ScrollingEdit_OnUpdate(self, elapsed, self:GetParent());
+
+
+ self:ClearFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopupSpecial_Hide(AddFriendFrame);
+
+
+
+
+
+
+
+
+ self.exclusive = true;
+ self.hideOnEscape = true;
+
+
+
+ AddFriendFrame.editFocus = nil;
+ PlaySound("igMainMenuClose");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(0, 0, 0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, FRIENDS_FRAME_IGNORE_HEIGHT, FriendsFriendsList_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( UIFrameIsFlashing(self) ) then
+ UIFrameFlashStop(self);
+ end
+ UIFrameFlash(self, 1, 0.5, 60, true, 1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FriendsFriendsNoteEditBox:SetFocus();
+
+
+
+
+
+
+ local scrollBar = _G[self:GetName().."ScrollBar"];
+ scrollBar:SetFrameLevel(_G[self:GetName().."FocusButton"]:GetFrameLevel() + 2);
+ scrollBar:ClearAllPoints();
+ scrollBar:SetPoint("TOPLEFT", self, "TOPRIGHT", -18, -10);
+ scrollBar:SetPoint("BOTTOMLEFT", self, "BOTTOMRIGHT", -18, 8);
+ -- reposition the up and down buttons
+ _G[self:GetName().."ScrollBarScrollDownButton"]:SetPoint("TOP", scrollBar, "BOTTOM", 0, 4);
+ _G[self:GetName().."ScrollBarScrollUpButton"]:SetPoint("BOTTOM", scrollBar, "TOP", 0, -4);
+ -- make the scroll bar hideable and force it to start off hidden so positioning calculations can be done
+ -- as soon as it needs to be shown
+ self.scrollBarHideable = 1;
+ scrollBar:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent());
+ if ( self:GetText() ~= "" ) then
+ FriendsFriendsNoteEditBoxFill:Hide();
+ else
+ FriendsFriendsNoteEditBoxFill:Show();
+ end
+
+
+
+ ScrollingEdit_OnUpdate(self, elapsed, self:GetParent());
+
+
+ self:ClearFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("BN_REQUEST_FOF_SUCCEEDED");
+ self:RegisterEvent("BN_DISCONNECTED");
+ self:RegisterEvent("BN_REQUEST_FOF_FAILED");
+ self.requested = { };
+ self.hideOnEscape = true;
+ self.exclusive = true;
+ UIDropDownMenu_SetWidth(FriendsFriendsFrameDropDown, 120);
+
+
+ PlaySound("igMainMenuOpen");
+
+
+ PlaySound("igMainMenuClose");
+
+
+
+
+
diff --git a/reference/FrameXML/GameMenuFrame.xml b/reference/FrameXML/GameMenuFrame.xml
new file mode 100644
index 0000000..b25ca5b
--- /dev/null
+++ b/reference/FrameXML/GameMenuFrame.xml
@@ -0,0 +1,247 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ ShowUIPanel(VideoOptionsFrame);
+ VideoOptionsFrame.lastFrame = GameMenuFrame;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ ShowUIPanel(AudioOptionsFrame);
+ AudioOptionsFrame.lastFrame = GameMenuFrame;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ ShowUIPanel(InterfaceOptionsFrame);
+ InterfaceOptionsFrame.lastFrame = GameMenuFrame;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ HideUIPanel(GameMenuFrame);
+ ShowUIPanel(MacOptionsFrame);
+
+
+ if(not IsMacClient()) then
+ GameMenuButtonMacOptions:Hide();
+ GameMenuButtonUIOptions:SetPoint("TOP", GameMenuButtonSoundOptions, "BOTTOM", 0, -1);
+ else
+ GameMenuFrame:SetHeight(266);
+ GameMenuButtonMacOptions:Show();
+ GameMenuButtonUIOptions:SetPoint("TOP", GameMenuButtonMacOptions, "BOTTOM", 0, -1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ KeyBindingFrame_LoadUI();
+ KeyBindingFrame.mode = 1;
+ ShowUIPanel(KeyBindingFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ HideUIPanel(GameMenuFrame);
+ ShowMacroFrame();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ HideUIPanel(GameMenuFrame);
+ ShowUIPanel(RatingMenuFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if (GameMenuButtonRatings:IsShown()) then
+ self:SetPoint("TOP", GameMenuButtonRatings, "BOTTOM", 0, -1);
+ end;
+ if ( not StaticPopup_Visible("CAMP") and not StaticPopup_Visible("QUIT") ) then
+ self:Enable();
+ else
+ self:Disable();
+ end
+
+
+ PlaySound("igMainMenuLogout");
+ Logout();
+ HideUIPanel(GameMenuFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( not StaticPopup_Visible("CAMP") and not StaticPopup_Visible("QUIT") ) then
+ self:Enable();
+ else
+ self:Disable();
+ end
+
+
+ PlaySound("igMainMenuQuit");
+ Quit();
+ HideUIPanel(GameMenuFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuContinue");
+ HideUIPanel(GameMenuFrame);
+
+
+
+
+
+
+ UpdateMicroButtons();
+ Disable_BagButtons();
+ VoiceChat_Toggle();
+
+
+ UpdateMicroButtons();
+ Enable_BagButtons();
+
+
+
+
diff --git a/reference/FrameXML/GameTime.lua b/reference/FrameXML/GameTime.lua
new file mode 100644
index 0000000..7b22eef
--- /dev/null
+++ b/reference/FrameXML/GameTime.lua
@@ -0,0 +1,250 @@
+
+GAMETIME_AM = true;
+GAMETIME_PM = false;
+
+local GAMETIME_DAWN = ( 5 * 60) + 30; -- 5:30 AM
+local GAMETIME_DUSK = (21 * 60) + 0; -- 9:00 PM
+
+
+local date = date;
+local format = format;
+local GetCVarBool = GetCVarBool;
+local CalendarGetDate = CalendarGetDate;
+local max = max;
+local tonumber = tonumber;
+
+local PI = PI;
+local TWOPI = PI * 2.0;
+local cos = math.cos;
+local INVITE_PULSE_SEC = 1.0 / (2.0*1.0); -- mul by 2 so the pulse constant counts for half a flash
+
+-- general GameTime functions
+function GameTime_GetFormattedTime(hour, minute, wantAMPM)
+ if ( GetCVarBool("timeMgrUseMilitaryTime") ) then
+ return format(TIMEMANAGER_TICKER_24HOUR, hour, minute);
+ else
+ if ( wantAMPM ) then
+ local timeFormat = TIME_TWELVEHOURAM;
+ if ( hour == 0 ) then
+ hour = 12;
+ elseif ( hour == 12 ) then
+ timeFormat = TIME_TWELVEHOURPM;
+ elseif ( hour > 12 ) then
+ timeFormat = TIME_TWELVEHOURPM;
+ hour = hour - 12;
+ end
+ return format(timeFormat, hour, minute);
+ else
+ if ( hour == 0 ) then
+ hour = 12;
+ elseif ( hour > 12 ) then
+ hour = hour - 12;
+ end
+ return format(TIMEMANAGER_TICKER_12HOUR, hour, minute);
+ end
+ end
+end
+
+function GameTime_ComputeMinutes(hour, minute, militaryTime, am)
+ local minutes;
+ if ( militaryTime ) then
+ minutes = minute + hour*60;
+ else
+ local h = hour;
+ if ( am ) then
+ if ( h == 12 ) then
+ h = 0;
+ end
+ else
+ if ( h ~= 12 ) then
+ h = h + 12;
+ end
+ end
+ minutes = minute + h*60;
+ end
+ return minutes;
+end
+
+-- GameTime_ComputeStandardTime assumes the given time is military (24 hour)
+function GameTime_ComputeStandardTime(hour)
+ if ( hour > 12 ) then
+ return hour - 12, GAMETIME_PM;
+ elseif ( hour == 0 ) then
+ return 12, GAMETIME_AM;
+ else
+ return hour, GAMETIME_AM;
+ end
+end
+
+-- GameTime_ComputeMilitaryTime assumes the given time is standard (12 hour)
+function GameTime_ComputeMilitaryTime(hour, am)
+ if ( am and hour == 12 ) then
+ return 0;
+ elseif ( not am and hour < 12 ) then
+ return hour + 12;
+ else
+ return hour;
+ end
+end
+
+function GameTime_GetLocalTime(wantAMPM)
+ local hour, minute = tonumber(date("%H")), tonumber(date("%M"));
+ return GameTime_GetFormattedTime(hour, minute, wantAMPM), hour, minute;
+end
+
+function GameTime_GetGameTime(wantAMPM)
+ local hour, minute = GetGameTime();
+ return GameTime_GetFormattedTime(hour, minute, wantAMPM), hour, minute;
+end
+
+function GameTime_GetTime(showAMPM)
+ if ( GetCVarBool("timeMgrUseLocalTime") ) then
+ return GameTime_GetLocalTime(showAMPM);
+ else
+ return GameTime_GetGameTime(showAMPM);
+ end
+end
+
+function GameTime_UpdateTooltip()
+ -- title
+ GameTooltip:AddLine(TIMEMANAGER_TOOLTIP_TITLE, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ -- realm time
+ GameTooltip:AddDoubleLine(
+ TIMEMANAGER_TOOLTIP_REALMTIME,
+ GameTime_GetGameTime(true),
+ NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b,
+ HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ -- local time
+ GameTooltip:AddDoubleLine(
+ TIMEMANAGER_TOOLTIP_LOCALTIME,
+ GameTime_GetLocalTime(true),
+ NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b,
+ HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+end
+
+
+-- GameTimeFrame functions
+
+function GameTimeFrame_OnLoad(self)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("CALENDAR_UPDATE_PENDING_INVITES");
+ self:RegisterEvent("CALENDAR_EVENT_ALARM");
+ self:RegisterForClicks("AnyUp");
+
+ -- adjust button texture layers to not interfere with overlaid textures
+ local tex;
+ tex = self:GetNormalTexture();
+ tex:SetDrawLayer("BACKGROUND");
+ tex = self:GetPushedTexture();
+ tex:SetDrawLayer("BACKGROUND");
+
+ self:GetFontString():SetDrawLayer("BACKGROUND");
+
+ self.timeOfDay = 0;
+ self:SetFrameLevel(self:GetFrameLevel() + 2);
+ self.pendingCalendarInvites = 0;
+ self.hour = 0;
+ self.flashTimer = 0.0;
+ GameTimeFrame_OnUpdate(self);
+end
+
+function GameTimeFrame_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT");
+end
+
+function GameTimeFrame_OnEvent(self, event, ...)
+ if ( event == "CALENDAR_UPDATE_PENDING_INVITES" or event == "PLAYER_ENTERING_WORLD" ) then
+ local pendingCalendarInvites = CalendarGetNumPendingInvites();
+ if ( pendingCalendarInvites > self.pendingCalendarInvites ) then
+ if ( not CalendarFrame or (CalendarFrame and not CalendarFrame:IsShown()) ) then
+ GameTimeCalendarInvitesTexture:Show();
+ GameTimeCalendarInvitesGlow:Show();
+ GameTimeFrame.flashInvite = true;
+ self.pendingCalendarInvites = pendingCalendarInvites;
+ end
+ elseif ( pendingCalendarInvites == 0 ) then
+ GameTimeCalendarInvitesTexture:Hide();
+ GameTimeCalendarInvitesGlow:Hide();
+ GameTimeFrame.flashInvite = false;
+ self.pendingCalendarInvites = 0;
+ end
+ GameTimeFrame_SetDate();
+ elseif ( event == "CALENDAR_EVENT_ALARM" ) then
+ local title, hour, minute = ...;
+ local info = ChatTypeInfo["SYSTEM"];
+ DEFAULT_CHAT_FRAME:AddMessage(format(CALENDAR_EVENT_ALARM_MESSAGE, title), info.r, info.g, info.b, info.id);
+ --UIFrameFlash(GameTimeCalendarEventAlarmTexture, 1.0, 1.0, 6);
+ end
+end
+
+function GameTimeFrame_OnUpdate(self, elapsed)
+ local hour, minute = GetGameTime();
+ local time = (hour * 60) + minute;
+ if ( time ~= self.timeOfDay ) then
+ self.timeOfDay = time;
+ local minx = 0;
+ local maxx = 50/128;
+ local miny = 0;
+ local maxy = 50/64;
+ if(time < GAMETIME_DAWN or time >= GAMETIME_DUSK) then
+ minx = minx + 0.5;
+ maxx = maxx + 0.5;
+ end
+ if ( hour ~= self.hour ) then
+ self.hour = hour;
+ GameTimeFrame_SetDate();
+ end
+ GameTimeTexture:SetTexCoord(minx, maxx, miny, maxy);
+ end
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:ClearLines();
+ if ( GameTimeCalendarInvitesTexture:IsShown() ) then
+ GameTooltip:AddLine(GAMETIME_TOOLTIP_CALENDAR_INVITES);
+ if ( CalendarFrame and not CalendarFrame:IsShown() ) then
+ GameTooltip:AddLine(" ");
+ GameTooltip:AddLine(GAMETIME_TOOLTIP_TOGGLE_CALENDAR);
+ end
+ else
+ if ( not TimeManagerClockButton or not TimeManagerClockButton:IsVisible() or TimeManager_IsAlarmFiring() ) then
+ GameTooltip:AddLine(GameTime_GetGameTime(true), HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(" ");
+ end
+ GameTooltip:AddLine(GAMETIME_TOOLTIP_TOGGLE_CALENDAR);
+ end
+ GameTooltip:Show();
+ end
+ -- Flashing stuff
+ if ( elapsed and GameTimeFrame.flashInvite ) then
+ local flashIndex = TWOPI * self.flashTimer * INVITE_PULSE_SEC;
+ local flashValue = max(0.0, 0.5 + 0.5*cos(flashIndex));
+ if ( flashIndex >= TWOPI ) then
+ self.flashTimer = 0.0;
+ else
+ self.flashTimer = self.flashTimer + elapsed;
+ end
+
+ GameTimeCalendarInvitesTexture:SetAlpha(flashValue);
+ GameTimeCalendarInvitesGlow:SetAlpha(flashValue);
+ end
+end
+
+function GameTimeFrame_OnClick(self)
+ if ( GameTimeCalendarInvitesTexture:IsShown() ) then
+ Calendar_LoadUI();
+ if ( Calendar_Show ) then
+ Calendar_Show();
+ end
+ GameTimeCalendarInvitesTexture:Hide();
+ GameTimeCalendarInvitesGlow:Hide();
+ self.pendingCalendarInvites = 0;
+ GameTimeFrame.flashInvite = false;
+ else
+ ToggleCalendar();
+ end
+end
+
+function GameTimeFrame_SetDate()
+ local _, _, day = CalendarGetDate();
+ GameTimeFrame:SetText(day);
+end
+
diff --git a/reference/FrameXML/GameTime.xml b/reference/FrameXML/GameTime.xml
new file mode 100644
index 0000000..ba25279
--- /dev/null
+++ b/reference/FrameXML/GameTime.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/GameTooltip.lua b/reference/FrameXML/GameTooltip.lua
new file mode 100644
index 0000000..f0c261d
--- /dev/null
+++ b/reference/FrameXML/GameTooltip.lua
@@ -0,0 +1,369 @@
+-- The default tooltip border color
+--TOOLTIP_DEFAULT_COLOR = { r = 0.5, g = 0.5, b = 0.5 };
+TOOLTIP_DEFAULT_COLOR = { r = 1, g = 1, b = 1 };
+TOOLTIP_DEFAULT_BACKGROUND_COLOR = { r = 0.09, g = 0.09, b = 0.19 };
+DEFAULT_TOOLTIP_POSITION = -13;
+
+function GameTooltip_UnitColor(unit)
+ local r, g, b;
+ if ( UnitPlayerControlled(unit) ) then
+ if ( UnitCanAttack(unit, "player") ) then
+ -- Hostile players are red
+ if ( not UnitCanAttack("player", unit) ) then
+ --[[
+ r = 1.0;
+ g = 0.5;
+ b = 0.5;
+ ]]
+ --[[
+ r = 0.0;
+ g = 0.0;
+ b = 1.0;
+ ]]
+ r = 1.0;
+ g = 1.0;
+ b = 1.0;
+ else
+ r = FACTION_BAR_COLORS[2].r;
+ g = FACTION_BAR_COLORS[2].g;
+ b = FACTION_BAR_COLORS[2].b;
+ end
+ elseif ( UnitCanAttack("player", unit) ) then
+ -- Players we can attack but which are not hostile are yellow
+ r = FACTION_BAR_COLORS[4].r;
+ g = FACTION_BAR_COLORS[4].g;
+ b = FACTION_BAR_COLORS[4].b;
+ elseif ( UnitIsPVP(unit) ) then
+ -- Players we can assist but are PvP flagged are green
+ r = FACTION_BAR_COLORS[6].r;
+ g = FACTION_BAR_COLORS[6].g;
+ b = FACTION_BAR_COLORS[6].b;
+ else
+ -- All other players are blue (the usual state on the "blue" server)
+ --[[
+ r = 0.0;
+ g = 0.0;
+ b = 1.0;
+ ]]
+ r = 1.0;
+ g = 1.0;
+ b = 1.0;
+ end
+ else
+ local reaction = UnitReaction(unit, "player");
+ if ( reaction ) then
+ r = FACTION_BAR_COLORS[reaction].r;
+ g = FACTION_BAR_COLORS[reaction].g;
+ b = FACTION_BAR_COLORS[reaction].b;
+ else
+ --[[
+ r = 0.0;
+ g = 0.0;
+ b = 1.0;
+ ]]
+ r = 1.0;
+ g = 1.0;
+ b = 1.0;
+ end
+ end
+ return r, g, b;
+end
+
+function GameTooltip_SetDefaultAnchor(tooltip, parent)
+ tooltip:SetOwner(parent, "ANCHOR_NONE");
+ tooltip:SetPoint("BOTTOMRIGHT", "UIParent", "BOTTOMRIGHT", -CONTAINER_OFFSET_X - 13, CONTAINER_OFFSET_Y);
+ tooltip.default = 1;
+end
+
+function GameTooltip_OnLoad(self)
+ self.updateTooltip = TOOLTIP_UPDATE_TIME;
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+ self.statusBar2 = _G[self:GetName().."StatusBar2"];
+ self.statusBar2Text = _G[self:GetName().."StatusBar2Text"];
+end
+
+function GameTooltip_OnTooltipAddMoney(self, cost, maxcost)
+ if( not maxcost ) then --We just have 1 price to display
+ SetTooltipMoney(self, cost, nil, string.format("%s:", SELL_PRICE));
+ else
+ self:AddLine(string.format("%s:", SELL_PRICE), 1.0, 1.0, 1.0);
+ local indent = string.rep(" ",4)
+ SetTooltipMoney(self, cost, nil, string.format("%s%s:", indent, MINIMUM));
+ SetTooltipMoney(self, maxcost, nil, string.format("%s%s:", indent, MAXIMUM));
+ end
+end
+
+function SetTooltipMoney(frame, money, type, prefixText, suffixText)
+ frame:AddLine(" ", 1.0, 1.0, 1.0);
+ local numLines = frame:NumLines();
+ if ( not frame.numMoneyFrames ) then
+ frame.numMoneyFrames = 0;
+ end
+ if ( not frame.shownMoneyFrames ) then
+ frame.shownMoneyFrames = 0;
+ end
+ local name = frame:GetName().."MoneyFrame"..frame.shownMoneyFrames+1;
+ local moneyFrame = _G[name];
+ if ( not moneyFrame ) then
+ frame.numMoneyFrames = frame.numMoneyFrames+1;
+ moneyFrame = CreateFrame("Frame", name, frame, "TooltipMoneyFrameTemplate");
+ name = moneyFrame:GetName();
+ MoneyFrame_SetType(moneyFrame, "STATIC");
+ end
+ _G[name.."PrefixText"]:SetText(prefixText);
+ _G[name.."SuffixText"]:SetText(suffixText);
+ if ( type ) then
+ MoneyFrame_SetType(moneyFrame, type);
+ end
+ --We still have this variable offset because many AddOns use this function. The money by itself will be unaligned if we do not use this.
+ local xOffset;
+ if ( prefixText ) then
+ xOffset = 4;
+ else
+ xOffset = 0;
+ end
+ moneyFrame:SetPoint("LEFT", frame:GetName().."TextLeft"..numLines, "LEFT", xOffset, 0);
+ moneyFrame:Show();
+ if ( not frame.shownMoneyFrames ) then
+ frame.shownMoneyFrames = 1;
+ else
+ frame.shownMoneyFrames = frame.shownMoneyFrames+1;
+ end
+ MoneyFrame_Update(moneyFrame:GetName(), money);
+ local moneyFrameWidth = moneyFrame:GetWidth();
+ if ( frame:GetMinimumWidth() < moneyFrameWidth ) then
+ frame:SetMinimumWidth(moneyFrameWidth);
+ end
+ frame.hasMoney = 1;
+end
+
+function GameTooltip_ClearMoney(self)
+ if ( not self.shownMoneyFrames ) then
+ return;
+ end
+
+ local moneyFrame;
+ for i=1, self.shownMoneyFrames do
+ moneyFrame = _G[self:GetName().."MoneyFrame"..i];
+ if(moneyFrame) then
+ moneyFrame:Hide();
+ MoneyFrame_SetType(moneyFrame, "STATIC");
+ end
+ end
+ self.shownMoneyFrames = nil;
+end
+
+function GameTooltip_ClearStatusBars(self)
+ if ( not self.shownStatusBars ) then
+ return;
+ end
+ local statusBar;
+ for i=1, self.shownStatusBars do
+ statusBar = _G[self:GetName().."StatusBar"..i];
+ if ( statusBar ) then
+ statusBar:Hide();
+ end
+ end
+ self.shownStatusBars = 0;
+end
+
+function GameTooltip_OnHide(self)
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+ self.default = nil;
+ GameTooltip_ClearMoney(self);
+ GameTooltip_ClearStatusBars(self);
+ if ( self.shoppingTooltips ) then
+ for _, frame in pairs(self.shoppingTooltips) do
+ frame:Hide();
+ end
+ end
+ self.comparing = false;
+end
+
+function GameTooltip_OnUpdate(self, elapsed)
+ -- Only update every TOOLTIP_UPDATE_TIME seconds
+ self.updateTooltip = self.updateTooltip - elapsed;
+ if ( self.updateTooltip > 0 ) then
+ return;
+ end
+ self.updateTooltip = TOOLTIP_UPDATE_TIME;
+
+ local owner = self:GetOwner();
+ if ( owner and owner.UpdateTooltip ) then
+ owner:UpdateTooltip();
+ end
+end
+
+function GameTooltip_AddNewbieTip(frame, normalText, r, g, b, newbieText, noNormalText)
+ if ( SHOW_NEWBIE_TIPS == "1" ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, frame);
+ if ( normalText ) then
+ GameTooltip:SetText(normalText, r, g, b);
+ GameTooltip:AddLine(newbieText, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ else
+ GameTooltip:SetText(newbieText, r, g, b, 1, 1);
+ end
+ GameTooltip:Show();
+ else
+ if ( not noNormalText ) then
+ GameTooltip:SetOwner(frame, "ANCHOR_RIGHT");
+ GameTooltip:SetText(normalText, r, g, b);
+ end
+ end
+end
+
+function GameTooltip_ShowCompareItem(self, shift)
+ if ( not self ) then
+ self = GameTooltip;
+ end
+ local item, link = self:GetItem();
+ if ( not link ) then
+ return;
+ end
+
+ local shoppingTooltip1, shoppingTooltip2, shoppingTooltip3 = unpack(self.shoppingTooltips);
+
+ local item1 = nil;
+ local item2 = nil;
+ local item3 = nil;
+ local side = "left";
+ if ( shoppingTooltip1:SetHyperlinkCompareItem(link, 1, shift, self) ) then
+ item1 = true;
+ end
+ if ( shoppingTooltip2:SetHyperlinkCompareItem(link, 2, shift, self) ) then
+ item2 = true;
+ end
+ if ( shoppingTooltip3:SetHyperlinkCompareItem(link, 3, shift, self) ) then
+ item3 = true;
+ end
+
+ -- find correct side
+ local rightDist = 0;
+ local leftPos = self:GetLeft();
+ local rightPos = self:GetRight();
+ if ( not rightPos ) then
+ rightPos = 0;
+ end
+ if ( not leftPos ) then
+ leftPos = 0;
+ end
+
+ rightDist = GetScreenWidth() - rightPos;
+
+ if (leftPos and (rightDist < leftPos)) then
+ side = "left";
+ else
+ side = "right";
+ end
+
+ -- see if we should slide the tooltip
+ if ( self:GetAnchorType() and self:GetAnchorType() ~= "ANCHOR_PRESERVE" ) then
+ local totalWidth = 0;
+ if ( item1 ) then
+ totalWidth = totalWidth + shoppingTooltip1:GetWidth();
+ end
+ if ( item2 ) then
+ totalWidth = totalWidth + shoppingTooltip2:GetWidth();
+ end
+ if ( item3 ) then
+ totalWidth = totalWidth + shoppingTooltip3:GetWidth();
+ end
+
+ if ( (side == "left") and (totalWidth > leftPos) ) then
+ self:SetAnchorType(self:GetAnchorType(), (totalWidth - leftPos), 0);
+ elseif ( (side == "right") and (rightPos + totalWidth) > GetScreenWidth() ) then
+ self:SetAnchorType(self:GetAnchorType(), -((rightPos + totalWidth) - GetScreenWidth()), 0);
+ end
+ end
+
+ -- anchor the compare tooltips
+ if ( item3 ) then
+ shoppingTooltip3:SetOwner(self, "ANCHOR_NONE");
+ shoppingTooltip3:ClearAllPoints();
+ if ( side and side == "left" ) then
+ shoppingTooltip3:SetPoint("TOPRIGHT", self, "TOPLEFT", 0, -10);
+ else
+ shoppingTooltip3:SetPoint("TOPLEFT", self, "TOPRIGHT", 0, -10);
+ end
+ shoppingTooltip3:SetHyperlinkCompareItem(link, 3, shift, self);
+ shoppingTooltip3:Show();
+ end
+
+ if ( item1 ) then
+ if( item3 ) then
+ shoppingTooltip1:SetOwner(shoppingTooltip3, "ANCHOR_NONE");
+ else
+ shoppingTooltip1:SetOwner(self, "ANCHOR_NONE");
+ end
+ shoppingTooltip1:ClearAllPoints();
+ if ( side and side == "left" ) then
+ if( item3 ) then
+ shoppingTooltip1:SetPoint("TOPRIGHT", shoppingTooltip3, "TOPLEFT", 0, 0);
+ else
+ shoppingTooltip1:SetPoint("TOPRIGHT", self, "TOPLEFT", 0, -10);
+ end
+ else
+ if( item3 ) then
+ shoppingTooltip1:SetPoint("TOPLEFT", shoppingTooltip3, "TOPRIGHT", 0, 0);
+ else
+ shoppingTooltip1:SetPoint("TOPLEFT", self, "TOPRIGHT", 0, -10);
+ end
+ end
+ shoppingTooltip1:SetHyperlinkCompareItem(link, 1, shift, self);
+ shoppingTooltip1:Show();
+
+ if ( item2 ) then
+ shoppingTooltip2:SetOwner(shoppingTooltip1, "ANCHOR_NONE");
+ shoppingTooltip2:ClearAllPoints();
+ if ( side and side == "left" ) then
+ shoppingTooltip2:SetPoint("TOPRIGHT", shoppingTooltip1, "TOPLEFT", 0, 0);
+ else
+ shoppingTooltip2:SetPoint("TOPLEFT", shoppingTooltip1, "TOPRIGHT", 0, 0);
+ end
+ shoppingTooltip2:SetHyperlinkCompareItem(link, 2, shift, self);
+ shoppingTooltip2:Show();
+ end
+ end
+end
+
+function GameTooltip_ShowStatusBar(self, min, max, value, text)
+ self:AddLine(" ", 1.0, 1.0, 1.0);
+ local numLines = self:NumLines();
+ if ( not self.numStatusBars ) then
+ self.numStatusBars = 0;
+ end
+ if ( not self.shownStatusBars ) then
+ self.shownStatusBars = 0;
+ end
+ local index = self.shownStatusBars+1;
+ local name = self:GetName().."StatusBar"..index;
+ local statusBar = _G[name];
+ if ( not statusBar ) then
+ self.numStatusBars = self.numStatusBars+1;
+ statusBar = CreateFrame("StatusBar", name, self, "TooltipStatusBarTemplate");
+ end
+ if ( not text ) then
+ text = "";
+ end
+ _G[name.."Text"]:SetText(text);
+ statusBar:SetMinMaxValues(min, max);
+ statusBar:SetValue(value);
+ statusBar:Show();
+ statusBar:SetPoint("LEFT", self:GetName().."TextLeft"..numLines, "LEFT", 0, -2);
+ statusBar:SetPoint("RIGHT", self, "RIGHT", -9, 0);
+ statusBar:Show();
+ self.shownStatusBars = index;
+ self:SetMinimumWidth(140);
+end
+
+function GameTooltip_Hide()
+ -- Used for XML OnLeave handlers
+ GameTooltip:Hide();
+end
+
+function GameTooltip_HideResetCursor()
+ GameTooltip:Hide();
+ ResetCursor();
+end
diff --git a/reference/FrameXML/GameTooltip.xml b/reference/FrameXML/GameTooltip.xml
new file mode 100644
index 0000000..14b3f5f
--- /dev/null
+++ b/reference/FrameXML/GameTooltip.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_OnLoad(self);
+ self.shoppingTooltips = { ShoppingTooltip1, ShoppingTooltip2, ShoppingTooltip3 };
+
+
+ if ( self:IsUnit("mouseover") ) then
+ _G[self:GetName().."TextLeft1"]:SetTextColor(GameTooltip_UnitColor("mouseover"));
+ end
+
+
+ if ( IsModifiedClick("COMPAREITEMS") or
+ (GetCVarBool("alwaysCompareItems") and not self:IsEquippedItem()) ) then
+ GameTooltip_ShowCompareItem(self, 1);
+ end
+
+
+ GameTooltip_OnHide(self);
+ ShoppingTooltip1:Hide();
+ ShoppingTooltip2:Hide();
+ ShoppingTooltip3:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+
+ self:SetWidth(SmallTextTooltipText:GetWidth() + 20);
+
+
+
+
diff --git a/reference/FrameXML/GameTooltipTemplate.xml b/reference/FrameXML/GameTooltipTemplate.xml
new file mode 100644
index 0000000..098d926
--- /dev/null
+++ b/reference/FrameXML/GameTooltipTemplate.xml
@@ -0,0 +1,432 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HealthBar_OnValueChanged(self, value);
+
+
+
+
+
+
+
+ GameTooltip_OnLoad(self);
+
+
+ GameTooltip_OnHide(self);
+
+
+ GameTooltip_SetDefaultAnchor(self, UIParent);
+
+
+ GameTooltip_OnTooltipAddMoney(self, cost, maxcost);
+
+
+ GameTooltip_ClearMoney(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetStatusBarColor(0, 1.0, 0);
+
+
+
+
+
diff --git a/reference/FrameXML/GlobalStrings.lua b/reference/FrameXML/GlobalStrings.lua
new file mode 100644
index 0000000..9ccd050
--- /dev/null
+++ b/reference/FrameXML/GlobalStrings.lua
@@ -0,0 +1,9001 @@
+-- AUTOMATICALLY GENERATED -- DO NOT EDIT!
+
+ABANDON_PET = "Are you sure you want to permanently abandon your pet?";
+ABANDON_QUEST = "Abandon Quest";
+ABANDON_QUEST_ABBREV = "Abandon";
+ABANDON_QUEST_CONFIRM = "Abandon \"%s\"?";
+ABANDON_QUEST_CONFIRM_WITH_ITEMS = "Abandon \"%s\", destroying %s?";
+ABILITIES = "Abilities";
+ABSORB = "Absorb";
+ABSORB_TRAILER = " (%d absorbed)";
+ACCEPT = "Accept";
+ACCEPT_ALT = "Accept";
+ACCEPT_COMMENT = "Set Comment";
+ACHIEVEMENT = "Achievement Announce";
+ACHIEVEMENTFRAME_FILTER_ALL = "All";
+ACHIEVEMENTFRAME_FILTER_COMPLETED = "Earned";
+ACHIEVEMENTFRAME_FILTER_INCOMPLETE = "Incomplete";
+ACHIEVEMENTS = "Achievements";
+ACHIEVEMENTS_COMPLETED = "Achievements Earned";
+ACHIEVEMENTS_COMPLETED_CATEGORY = "%s Achievements Earned";
+ACHIEVEMENT_BROADCAST = "%s has earned the achievement %s!";
+ACHIEVEMENT_BROADCAST_SELF = "You have earned the achievement %s!";
+ACHIEVEMENT_BUTTON = "Achievements";
+ACHIEVEMENT_CATEGORY_PROGRESS = "Progress Overview";
+ACHIEVEMENT_META_COMPLETED_DATE = "Completed %s";
+ACHIEVEMENT_SUMMARY_CATEGORY = "Summary";
+ACHIEVEMENT_TITLE = "Achievement Points";
+ACHIEVEMENT_TOOLTIP_COMPLETE = "Achievement earned by %1$s on %2$d/%3$02d/20%4$02d";
+ACHIEVEMENT_TOOLTIP_IN_PROGRESS = "Achievement in progress by %s";
+ACHIEVEMENT_UNLOCKED = "Achievement Earned";
+ACHIEVEMENT_UNLOCKED_CHAT_MSG = "Achievement Earned: %s";
+ACHIEVEMENT_WATCH_TOO_MANY = "You may only track %d achievements at a time.";
+ACTIONBARS_LABEL = "ActionBars";
+ACTIONBARS_SUBTEXT = "ActionBars are banks of hotkeys that allow you to quickly access abilities and inventory items. Here you can activate additional ActionBars and control their behaviors.";
+ACTIONBAR_LABEL = "Action Bars";
+ACTION_DAMAGE_SHIELD = "damages";
+ACTION_DAMAGE_SHIELD_FULL_TEXT = "%1$s %2$s reflects %9$s %7$s damage to %4$s.%6$s";
+ACTION_DAMAGE_SHIELD_FULL_TEXT_NO_SOURCE = "%2$s reflects %9$s %7$s damage to %4$s.%6$s";
+ACTION_DAMAGE_SHIELD_MISSED = "missed";
+ACTION_DAMAGE_SHIELD_MISSED_BLOCK = "(Blocked)";
+ACTION_DAMAGE_SHIELD_MISSED_BLOCK_FULL_TEXT = "%1$s %2$s was blocked by %4$s.%6$s";
+ACTION_DAMAGE_SHIELD_MISSED_BLOCK_FULL_TEXT_NO_SOURCE = "%2$s was blocked by %4$s.%6$s";
+ACTION_DAMAGE_SHIELD_MISSED_BLOCK_POSSESSIVE = "1";
+ACTION_DAMAGE_SHIELD_MISSED_DEFLECT = "(Deflected)";
+ACTION_DAMAGE_SHIELD_MISSED_DEFLECT_FULL_TEXT = "%1$s %2$s was deflected by %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_DEFLECT_FULL_TEXT_NO_SOURCE = "%2$s was deflected by %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_DEFLECT_POSSESSIVE = "1";
+ACTION_DAMAGE_SHIELD_MISSED_DODGE = "(Dodged)";
+ACTION_DAMAGE_SHIELD_MISSED_DODGE_FULL_TEXT = "%1$s %2$s was dodged by %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_DODGE_FULL_TEXT_NO_SOURCE = "%2$s was dodged by %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_DODGE_POSSESSIVE = "1";
+ACTION_DAMAGE_SHIELD_MISSED_EVADED = "(Evaded)";
+ACTION_DAMAGE_SHIELD_MISSED_EVADED_FULL_TEXT = "%1$s %2$s was evaded by %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_EVADED_FULL_TEXT_NO_SOURCE = "%2$s was evaded by %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_EVADED_POSSESSIVE = "1";
+ACTION_DAMAGE_SHIELD_MISSED_FULL_TEXT = "%1$s %2$s missed %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_FULL_TEXT_NO_SOURCE = "%2$s missed %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_IMMUNE = "(Immune)";
+ACTION_DAMAGE_SHIELD_MISSED_IMMUNE_FULL_TEXT = "%1$s %2$s failed. %4$s was immune.";
+ACTION_DAMAGE_SHIELD_MISSED_IMMUNE_FULL_TEXT_NO_SOURCE = "%2$s failed. %4$s was immune.";
+ACTION_DAMAGE_SHIELD_MISSED_IMMUNE_POSSESSIVE = "1";
+ACTION_DAMAGE_SHIELD_MISSED_MISS = "(Missed)";
+ACTION_DAMAGE_SHIELD_MISSED_MISS_FULL_TEXT = "%1$s %2$s misses %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_MISS_FULL_TEXT_NO_SOURCE = "%2$s misses %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_MISS_POSSESSIVE = "1";
+ACTION_DAMAGE_SHIELD_MISSED_PARRY = "(Parried)";
+ACTION_DAMAGE_SHIELD_MISSED_PARRY_FULL_TEXT = "%1$s %2$s was parried by %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_PARRY_FULL_TEXT_NO_SOURCE = "%2$s was parried by %4$s.";
+ACTION_DAMAGE_SHIELD_MISSED_PARRY_POSSESSIVE = "1";
+ACTION_DAMAGE_SHIELD_MISSED_POSSESSIVE = "1";
+ACTION_DAMAGE_SHIELD_MISSED_RESIST = "(Resisted)";
+ACTION_DAMAGE_SHIELD_MISSED_RESIST_FULL_TEXT = "%1$s %2$s was fully resisted by %4$s.%6$s";
+ACTION_DAMAGE_SHIELD_MISSED_RESIST_FULL_TEXT_NO_SOURCE = "%2$s was fully resisted by %4$s.%6$s";
+ACTION_DAMAGE_SHIELD_MISSED_RESIST_POSSESSIVE = "1";
+ACTION_DAMAGE_SHIELD_POSSESSIVE = "1";
+ACTION_DAMAGE_SPLIT = "shared damage";
+ACTION_DAMAGE_SPLIT_ABSORBED_FULL_TEXT = "%1$s's %2$s damage was absorbed by %4$s %6$s.";
+ACTION_DAMAGE_SPLIT_FULL_TEXT = "%1$s %2$s causes %9$s damage to %4$s.";
+ACTION_DAMAGE_SPLIT_POSSESSIVE = "0";
+ACTION_DAMAGE_SPLIT_RESULT_FULL_TEXT = "%1$s's %2$s causes %9$s damage to %4$s %6$s.";
+ACTION_ENCHANT_APPLIED = "enchanted";
+ACTION_ENCHANT_APPLIED_FULL_TEXT = "%1$s cast %2$s on %4$s %5$s.";
+ACTION_ENCHANT_APPLIED_POSSESSIVE = "0";
+ACTION_ENCHANT_REMOVED = "enchant faded";
+ACTION_ENCHANT_REMOVED_FULL_TEXT = "%2$s fades from %4$s %5$s.";
+ACTION_ENCHANT_REMOVED_POSSESSIVE = "0";
+ACTION_ENVIRONMENTAL_DAMAGE = "damaged";
+ACTION_ENVIRONMENTAL_DAMAGE_DROWNING = "Drowning";
+ACTION_ENVIRONMENTAL_DAMAGE_DROWNING_FULL_TEXT = "%4$s is drowning and loses %9$s health.";
+ACTION_ENVIRONMENTAL_DAMAGE_DROWNING_POSSESSIVE = "0";
+ACTION_ENVIRONMENTAL_DAMAGE_FALLING = "Falling";
+ACTION_ENVIRONMENTAL_DAMAGE_FALLING_FULL_TEXT = "%4$s falls and loses %9$s health.";
+ACTION_ENVIRONMENTAL_DAMAGE_FALLING_POSSESSIVE = "0";
+ACTION_ENVIRONMENTAL_DAMAGE_FATIGUE = "Fatigue";
+ACTION_ENVIRONMENTAL_DAMAGE_FATIGUE_FULL_TEXT = "%4$s is exhausted and loses %9$s health.";
+ACTION_ENVIRONMENTAL_DAMAGE_FATIGUE_POSSESSIVE = "0";
+ACTION_ENVIRONMENTAL_DAMAGE_FIRE = "Fire";
+ACTION_ENVIRONMENTAL_DAMAGE_FIRE_FULL_TEXT = "%4$s suffers %9$s fire damage.";
+ACTION_ENVIRONMENTAL_DAMAGE_FIRE_POSSESSIVE = "0";
+ACTION_ENVIRONMENTAL_DAMAGE_FULL_TEXT = "%4$s loses %9$s health from environmental damage.";
+ACTION_ENVIRONMENTAL_DAMAGE_LAVA = "Lava";
+ACTION_ENVIRONMENTAL_DAMAGE_LAVA_FULL_TEXT = "%4$s loses %9$s health from swimming in lava. %6$s";
+ACTION_ENVIRONMENTAL_DAMAGE_LAVA_POSSESSIVE = "0";
+ACTION_ENVIRONMENTAL_DAMAGE_POSSESSIVE = "0";
+ACTION_ENVIRONMENTAL_DAMAGE_SLIME = "Slime";
+ACTION_ENVIRONMENTAL_DAMAGE_SLIME_FULL_TEXT = "%4$s loses %9$s health for swimming in slime. %6$s";
+ACTION_ENVIRONMENTAL_DAMAGE_SLIME_POSSESSIVE = "0";
+ACTION_PARTY_KILL = "killed";
+ACTION_PARTY_KILL_FULL_TEXT = "%1$s has slain %4$s!";
+ACTION_PARTY_KILL_POSSESSIVE = "0";
+ACTION_RANGED = "Shot";
+ACTION_RANGE_DAMAGE = "hit";
+ACTION_RANGE_DAMAGE_FULL_TEXT = "%1$s ranged shot hit %4$s for %5$s.%6$s";
+ACTION_RANGE_DAMAGE_FULL_TEXT_NO_SOURCE = "A ranged shot hit %4$s for %5$s.%6$s";
+ACTION_RANGE_DAMAGE_POSSESSIVE = "1";
+ACTION_RANGE_MISSED = "missed";
+ACTION_RANGE_MISSED_ABSORB = "(Absorbed)";
+ACTION_RANGE_MISSED_ABSORB_FULL_TEXT = "%1$s shot was absorbed by %4$s.%6$s";
+ACTION_RANGE_MISSED_ABSORB_POSSESSIVE = "1";
+ACTION_RANGE_MISSED_BLOCK = "(Blocked)";
+ACTION_RANGE_MISSED_BLOCK_FULL_TEXT = "%1$s shot was blocked by %4$s.%6$s";
+ACTION_RANGE_MISSED_BLOCK_POSSESSIVE = "1";
+ACTION_RANGE_MISSED_DEFLECT = "(Deflected)";
+ACTION_RANGE_MISSED_DEFLECT_FULL_TEXT = "%1$s shot was deflected by %4$s.";
+ACTION_RANGE_MISSED_DEFLECT_POSSESSIVE = "1";
+ACTION_RANGE_MISSED_DODGE = "(Dodged)";
+ACTION_RANGE_MISSED_DODGE_FULL_TEXT = "%1$s shot was dodged by %4$s.";
+ACTION_RANGE_MISSED_DODGE_POSSESSIVE = "1";
+ACTION_RANGE_MISSED_EVADE = "(Evaded)";
+ACTION_RANGE_MISSED_EVADE_FULL_TEXT = "%1$s shot was evaded by %4$s.";
+ACTION_RANGE_MISSED_EVADE_POSSESSIVE = "1";
+ACTION_RANGE_MISSED_FULL_TEXT = "%1$s shot misses %4$s.";
+ACTION_RANGE_MISSED_IMMUNE = "(Immune)";
+ACTION_RANGE_MISSED_IMMUNE_FULL_TEXT = "%1$s shot failed. %4$s was immune.";
+ACTION_RANGE_MISSED_IMMUNE_POSSESSIVE = "1";
+ACTION_RANGE_MISSED_MISS = "(Missed)";
+ACTION_RANGE_MISSED_MISS_FULL_TEXT = "%1$s shot misses %4$s.";
+ACTION_RANGE_MISSED_MISS_POSSESSIVE = "1";
+ACTION_RANGE_MISSED_PARRY = "(Parried)";
+ACTION_RANGE_MISSED_PARRY_FULL_TEXT = "%1$s shot was parried by %4$s.";
+ACTION_RANGE_MISSED_PARRY_POSSESSIVE = "1";
+ACTION_RANGE_MISSED_POSSESSIVE = "1";
+ACTION_RANGE_MISSED_RESIST = "(Resisted)";
+ACTION_RANGE_MISSED_RESIST_FULL_TEXT = "%1$s shot was fully resisted by %4$s.%6$s";
+ACTION_RANGE_MISSED_RESIST_POSSESSIVE = "1";
+ACTION_SPELL_AURA_APPLIED = "applied";
+ACTION_SPELL_AURA_APPLIED_BUFF = "applied";
+ACTION_SPELL_AURA_APPLIED_BUFF_FULL_TEXT = "%4$s gains %1$s %2$s.";
+ACTION_SPELL_AURA_APPLIED_BUFF_FULL_TEXT_NO_SOURCE = "%4$s gains %2$s.";
+ACTION_SPELL_AURA_APPLIED_BUFF_MASTER = "2";
+ACTION_SPELL_AURA_APPLIED_BUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_APPLIED_DEBUFF = "afflicted";
+ACTION_SPELL_AURA_APPLIED_DEBUFF_FULL_TEXT = "%4$s is afflicted by %1$s %2$s.";
+ACTION_SPELL_AURA_APPLIED_DEBUFF_FULL_TEXT_NO_SOURCE = "%4$s is afflicted by %2$s.";
+ACTION_SPELL_AURA_APPLIED_DEBUFF_MASTER = "1";
+ACTION_SPELL_AURA_APPLIED_DEBUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_APPLIED_DOSE = "stacked";
+ACTION_SPELL_AURA_APPLIED_DOSE_BUFF = "stacked";
+ACTION_SPELL_AURA_APPLIED_DOSE_BUFF_FULL_TEXT = "%4$s gains %1$s %2$s (%9$s).";
+ACTION_SPELL_AURA_APPLIED_DOSE_BUFF_FULL_TEXT_NO_SOURCE = "%4$s gains %2$s (%9$s).";
+ACTION_SPELL_AURA_APPLIED_DOSE_BUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_APPLIED_DOSE_DEBUFF = "afflicted";
+ACTION_SPELL_AURA_APPLIED_DOSE_DEBUFF_FULL_TEXT = "%4$s is afflicted by %1$s %2$s (%9$s).";
+ACTION_SPELL_AURA_APPLIED_DOSE_DEBUFF_FULL_TEXT_NO_SOURCE = "%4$s is afflicted by %2$s (%9$s).";
+ACTION_SPELL_AURA_APPLIED_DOSE_DEBUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_APPLIED_MASTER = "2";
+ACTION_SPELL_AURA_APPLIED_POSSESSIVE = "1";
+ACTION_SPELL_AURA_BROKEN = "broke";
+ACTION_SPELL_AURA_BROKEN_BUFF = "broke";
+ACTION_SPELL_AURA_BROKEN_BUFF_FULL_TEXT = "%1$s broke %4$s %2$s.";
+ACTION_SPELL_AURA_BROKEN_BUFF_FULL_TEXT_NO_SOURCE = "%1$s %2$s was broken by someone.";
+ACTION_SPELL_AURA_BROKEN_BUFF_POSSESSIVE = "0";
+ACTION_SPELL_AURA_BROKEN_DEBUFF = "broke";
+ACTION_SPELL_AURA_BROKEN_DEBUFF_FULL_TEXT = "%1$s broke %4$s %2$s.";
+ACTION_SPELL_AURA_BROKEN_DEBUFF_FULL_TEXT_NO_SOURCE = "%1$s %2$s was broken by someone.";
+ACTION_SPELL_AURA_BROKEN_DEBUFF_POSSESSIVE = "0";
+ACTION_SPELL_AURA_BROKEN_SPELL_BUFF = "broke";
+ACTION_SPELL_AURA_BROKEN_SPELL_BUFF_FULL_TEXT = "%1$s broke %4$s %2$s with %5$s.";
+ACTION_SPELL_AURA_BROKEN_SPELL_BUFF_FULL_TEXT_NO_SOURCE = "%5$s broke %4$s %2$s.";
+ACTION_SPELL_AURA_BROKEN_SPELL_BUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_BROKEN_SPELL_DEBUFF = "broke";
+ACTION_SPELL_AURA_BROKEN_SPELL_DEBUFF_FULL_TEXT = "%1$s broke %4$s %2$s with %5$s.";
+ACTION_SPELL_AURA_BROKEN_SPELL_DEBUFF_FULL_TEXT_NO_SOURCE = "%5$s broke %4$s %2$s.";
+ACTION_SPELL_AURA_BROKEN_SPELL_DEBUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_REFRESH = "refreshed";
+ACTION_SPELL_AURA_REFRESH_BUFF = "refreshed";
+ACTION_SPELL_AURA_REFRESH_BUFF_FULL_TEXT = "%1$s %2$s is refreshed on %4$s.";
+ACTION_SPELL_AURA_REFRESH_BUFF_FULL_TEXT_NO_SOURCE = "%2$s is refreshed on %4$s.";
+ACTION_SPELL_AURA_REFRESH_BUFF_MASTER = "2";
+ACTION_SPELL_AURA_REFRESH_BUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_REFRESH_DEBUFF = "refreshed";
+ACTION_SPELL_AURA_REFRESH_DEBUFF_FULL_TEXT = "%1$s %2$s is refreshed on %4$s.";
+ACTION_SPELL_AURA_REFRESH_DEBUFF_FULL_TEXT_NO_SOURCE = "%2$s is refreshed on %4$s.";
+ACTION_SPELL_AURA_REFRESH_DEBUFF_MASTER = "1";
+ACTION_SPELL_AURA_REFRESH_DEBUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_REFRESH_MASTER = "2";
+ACTION_SPELL_AURA_REMOVED = "removed";
+ACTION_SPELL_AURA_REMOVED_BUFF = "faded";
+ACTION_SPELL_AURA_REMOVED_BUFF_FULL_TEXT = "%1$s %2$s fades from %4$s.";
+ACTION_SPELL_AURA_REMOVED_BUFF_FULL_TEXT_NO_SOURCE = "%2$s fades from %4$s.";
+ACTION_SPELL_AURA_REMOVED_BUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_REMOVED_DEBUFF = "dissipated";
+ACTION_SPELL_AURA_REMOVED_DEBUFF_FULL_TEXT = "%1$s %2$s dissipates from %4$s.";
+ACTION_SPELL_AURA_REMOVED_DEBUFF_FULL_TEXT_NO_SOURCE = "%2$s dissipates from %4$s.";
+ACTION_SPELL_AURA_REMOVED_DEBUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_REMOVED_DOSE = "reduced";
+ACTION_SPELL_AURA_REMOVED_DOSE_BUFF = "reduced";
+ACTION_SPELL_AURA_REMOVED_DOSE_BUFF_FULL_TEXT = "%1$s %2$s (%9$s) diminishes.";
+ACTION_SPELL_AURA_REMOVED_DOSE_BUFF_FULL_TEXT_NO_SOURCE = "%2$s (%9$s) diminishes.";
+ACTION_SPELL_AURA_REMOVED_DOSE_BUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_REMOVED_DOSE_DEBUFF = "diminished";
+ACTION_SPELL_AURA_REMOVED_DOSE_DEBUFF_FULL_TEXT = "%1$s %2$s (%9$s) subsides.";
+ACTION_SPELL_AURA_REMOVED_DOSE_DEBUFF_FULL_TEXT_NO_SOURCE = "%2$s (%9$s) subsides.";
+ACTION_SPELL_AURA_REMOVED_DOSE_DEBUFF_POSSESSIVE = "1";
+ACTION_SPELL_AURA_REMOVED_FULL_TEXT = "%1$s %2$s was removed from %4$s.";
+ACTION_SPELL_AURA_REMOVED_FULL_TEXT_NO_SOURCE = "%1$s %2$s was removed from %4$s.";
+ACTION_SPELL_AURA_REMOVED_POSSESSIVE = "1";
+ACTION_SPELL_BUILDING_DAMAGE = "strikes";
+ACTION_SPELL_BUILDING_DAMAGE_FULL_TEXT = "%1$s %2$s strikes %4$s for %5$s.%6$s";
+ACTION_SPELL_BUILDING_DAMAGE_FULL_TEXT_NO_SOURCE = "%2$s strike %4$s for %5$s.%6$s";
+ACTION_SPELL_BUILDING_DAMAGE_MASTER = "1";
+ACTION_SPELL_BUILDING_DAMAGE_POSSESSIVE = "1";
+ACTION_SPELL_BUILDING_HEAL = "repaired";
+ACTION_SPELL_BUILDING_HEAL_FULL_TEXT = "%1$s %2$s repairs %4$s for %9$s.%6$s";
+ACTION_SPELL_BUILDING_HEAL_FULL_TEXT_NO_SOURCE = "%2$s repairs %4$s for %9$s.%6$s";
+ACTION_SPELL_BUILDING_HEAL_POSSESSIVE = "1";
+ACTION_SPELL_CAST_FAILED = "failed";
+ACTION_SPELL_CAST_FAILED_FULL_TEXT = "%1$s %2$s failed.%6$s";
+ACTION_SPELL_CAST_FAILED_MASTER = "1";
+ACTION_SPELL_CAST_FAILED_POSSESSIVE = "1";
+ACTION_SPELL_CAST_START = "began to cast";
+ACTION_SPELL_CAST_START_FULL_TEXT = "Something begins casting %2$s at %4$s.";
+ACTION_SPELL_CAST_START_FULL_TEXT_NO_DEST = "%1$s begins casting %2$s.";
+ACTION_SPELL_CAST_START_FULL_TEXT_NO_SOURCE = "%1$s begins casting %2$s at %4$s.";
+ACTION_SPELL_CAST_START_MASTER = "2";
+ACTION_SPELL_CAST_START_POSSESSIVE = "0";
+ACTION_SPELL_CAST_SUCCESS = "cast";
+ACTION_SPELL_CAST_SUCCESS_FULL_TEXT = "%1$s casts %2$s at %4$s.";
+ACTION_SPELL_CAST_SUCCESS_FULL_TEXT_NO_DEST = "%1$s casts %2$s.";
+ACTION_SPELL_CAST_SUCCESS_FULL_TEXT_NO_SOURCE = "Something cast %2$s at %4$s.";
+ACTION_SPELL_CAST_SUCCESS_MASTER = "2";
+ACTION_SPELL_CAST_SUCCESS_POSSESSIVE = "0";
+ACTION_SPELL_CREATE = "created";
+ACTION_SPELL_CREATE_FULL_TEXT = "%1$s %2$s creates a %4$s.%6$s";
+ACTION_SPELL_CREATE_FULL_TEXT_NO_SOURCE = "%2$s creates a %4$s.%6$s";
+ACTION_SPELL_CREATE_POSSESSIVE = "1";
+ACTION_SPELL_DAMAGE = "hit";
+ACTION_SPELL_DAMAGE_FULL_TEXT = "%1$s %2$s hits %4$s for %5$s.%6$s";
+ACTION_SPELL_DAMAGE_FULL_TEXT_NO_SOURCE = "%2$s hits %4$s for %5$s.%6$s";
+ACTION_SPELL_DAMAGE_MASTER = "1";
+ACTION_SPELL_DAMAGE_POSSESSIVE = "1";
+ACTION_SPELL_DISPEL = "dispelled";
+ACTION_SPELL_DISPEL_BUFF = "dispelled";
+ACTION_SPELL_DISPEL_BUFF_FULL_TEXT = "%4$s %5$s is dispelled by %1$s %2$s.";
+ACTION_SPELL_DISPEL_BUFF_FULL_TEXT_NO_SOURCE = "%4$s %5$s is dispelled by %2$s.";
+ACTION_SPELL_DISPEL_BUFF_POSSESSIVE = "1";
+ACTION_SPELL_DISPEL_DEBUFF = "cleansed";
+ACTION_SPELL_DISPEL_DEBUFF_FULL_TEXT = "%4$s %5$s is cleansed by %1$s %2$s.";
+ACTION_SPELL_DISPEL_DEBUFF_FULL_TEXT_NO_SOURCE = "%4$s %5$s cleansed by %2$s.";
+ACTION_SPELL_DISPEL_DEBUFF_POSSESSIVE = "1";
+ACTION_SPELL_DISPEL_FAILED = "dispel failed";
+ACTION_SPELL_DISPEL_FAILED_FULL_TEXT = "%1$s %2$s fails to dispel %4$s %5$s.";
+ACTION_SPELL_DISPEL_FAILED_FULL_TEXT_NO_SOURCE = "%2$s fails to dispel %4$s %5$s.";
+ACTION_SPELL_DISPEL_FAILED_POSSESSIVE = "1";
+ACTION_SPELL_DISPEL_POSSESSIVE = "1";
+ACTION_SPELL_DRAIN = "drained";
+ACTION_SPELL_DRAIN_FULL_TEXT = "%1$s %2$s drains %9$s %8$s from %4$s.";
+ACTION_SPELL_DRAIN_FULL_TEXT_NO_SOURCE = " %2$s drains %9$s %8$s from %4$s.";
+ACTION_SPELL_DRAIN_POSSESSIVE = "1";
+ACTION_SPELL_DURABILITY_DAMAGE = "durability loss";
+ACTION_SPELL_DURABILITY_DAMAGE_ALL = "full durability loss";
+ACTION_SPELL_DURABILITY_DAMAGE_ALL_FULL_TEXT = "%1$s %2$s damages %4$s: all items damaged.";
+ACTION_SPELL_DURABILITY_DAMAGE_ALL_POSSESSIVE = "1";
+ACTION_SPELL_DURABILITY_DAMAGE_FULL_TEXT = "%1$s %2$s damages %4$s: $item damaged.";
+ACTION_SPELL_DURABILITY_DAMAGE_POSSESSIVE = "1";
+ACTION_SPELL_ENERGIZE = "energized";
+ACTION_SPELL_ENERGIZE_FULL_TEXT = "%4$s gains %9$s %8$s from %1$s %2$s.";
+ACTION_SPELL_ENERGIZE_FULL_TEXT_NO_SOURCE = "%4$s gains %9$s %8$s from %2$s.";
+ACTION_SPELL_ENERGIZE_POSSESSIVE = "1";
+ACTION_SPELL_ENERGIZE_RESULT = "%9$s %8$s Gained";
+ACTION_SPELL_EXTRA_ATTACKS = "granted extra attacks";
+ACTION_SPELL_EXTRA_ATTACKS_FULL_TEXT = "%1$s gains %9$s extra attacks through %2$s.";
+ACTION_SPELL_EXTRA_ATTACKS_FULL_TEXT_NO_SOURCE = "%9$s extra attacks granted by %2$s.";
+ACTION_SPELL_EXTRA_ATTACKS_POSSESSIVE = "1";
+ACTION_SPELL_HEAL = "healed";
+ACTION_SPELL_HEAL_FULL_TEXT = "%1$s %2$s heals %4$s for %9$s.%6$s";
+ACTION_SPELL_HEAL_FULL_TEXT_NO_SOURCE = "%2$s heals %4$s for %9$s.%6$s";
+ACTION_SPELL_HEAL_POSSESSIVE = "1";
+ACTION_SPELL_INSTAKILL = "killed";
+ACTION_SPELL_INSTAKILL_FULL_TEXT = "%1$s %2$s instantly kills %4$s.";
+ACTION_SPELL_INSTAKILL_FULL_TEXT_NO_SOURCE = "%2$s instantly kills %4$s.";
+ACTION_SPELL_INSTAKILL_POSSESSIVE = "1";
+ACTION_SPELL_INTERRUPT = "interrupted";
+ACTION_SPELL_INTERRUPT_FULL_TEXT = "%1$s %2$s interrupts %4$s %5$s.";
+ACTION_SPELL_INTERRUPT_FULL_TEXT_NO_SOURCE = "%2$s interrupts %4$s %5$s.";
+ACTION_SPELL_INTERRUPT_POSSESSIVE = "1";
+ACTION_SPELL_LEECH = "drained";
+ACTION_SPELL_LEECH_FULL_TEXT = "%1$s %2$s drains %9$s %8$s from %4$s. %1$s gains %10$s %8$s.";
+ACTION_SPELL_LEECH_FULL_TEXT_NO_SOURCE = "%2$s drains %9$s %8$s from %4$s.";
+ACTION_SPELL_LEECH_POSSESSIVE = "1";
+ACTION_SPELL_LEECH_RESULT = "%10$s %8$s Gained";
+ACTION_SPELL_MISSED = "missed";
+ACTION_SPELL_MISSED_ABSORB = "Absorbed";
+ACTION_SPELL_MISSED_ABSORB_FULL_TEXT = "%1$s %2$s was absorbed by %4$s.%6$s";
+ACTION_SPELL_MISSED_ABSORB_FULL_TEXT_NO_SOURCE = "%2$s was absorbed by %4$s.%6$s";
+ACTION_SPELL_MISSED_ABSORB_POSSESSIVE = "1";
+ACTION_SPELL_MISSED_BLOCK = "Blocked";
+ACTION_SPELL_MISSED_BLOCK_FULL_TEXT = "%1$s %2$s was blocked by %4$s.%6$s";
+ACTION_SPELL_MISSED_BLOCK_FULL_TEXT_NO_SOURCE = "%2$s was blocked by %4$s.%6$s";
+ACTION_SPELL_MISSED_BLOCK_POSSESSIVE = "1";
+ACTION_SPELL_MISSED_DEFLECT = "Deflected";
+ACTION_SPELL_MISSED_DEFLECT_FULL_TEXT = "%1$s %2$s was deflected by %4$s.";
+ACTION_SPELL_MISSED_DEFLECT_FULL_TEXT_NO_SOURCE = "%2$s was deflected by %4$s.";
+ACTION_SPELL_MISSED_DEFLECT_POSSESSIVE = "1";
+ACTION_SPELL_MISSED_DODGE = "Dodged";
+ACTION_SPELL_MISSED_DODGE_FULL_TEXT = "%1$s %2$s was dodged by %4$s.";
+ACTION_SPELL_MISSED_DODGE_FULL_TEXT_NO_SOURCE = "%2$s was dodged by %4$s.";
+ACTION_SPELL_MISSED_DODGE_POSSESSIVE = "1";
+ACTION_SPELL_MISSED_EVADE = "Evaded";
+ACTION_SPELL_MISSED_EVADE_FULL_TEXT = "%1$s %2$s was evaded by %4$s.";
+ACTION_SPELL_MISSED_EVADE_FULL_TEXT_NO_SOURCE = "%2$s was evaded by %4$s.";
+ACTION_SPELL_MISSED_EVADE_POSSESSIVE = "1";
+ACTION_SPELL_MISSED_FULL_TEXT = "%1$s %2$s missed %4$s.";
+ACTION_SPELL_MISSED_FULL_TEXT_NO_SOURCE = "%2$s missed %4$s.";
+ACTION_SPELL_MISSED_IMMUNE = "Immune";
+ACTION_SPELL_MISSED_IMMUNE_FULL_TEXT = "%1$s %2$s failed. %4$s was immune.";
+ACTION_SPELL_MISSED_IMMUNE_FULL_TEXT_NO_SOURCE = "%2$s failed. %4$s was immune.";
+ACTION_SPELL_MISSED_MISS = "Missed";
+ACTION_SPELL_MISSED_MISS_FULL_TEXT = "%1$s %2$s misses %4$s.";
+ACTION_SPELL_MISSED_MISS_FULL_TEXT_NO_SOURCE = "%2$s misses %4$s.";
+ACTION_SPELL_MISSED_MISS_POSSESSIVE = "1";
+ACTION_SPELL_MISSED_PARRY = "Parried";
+ACTION_SPELL_MISSED_PARRY_FULL_TEXT = "%1$s %2$s was parried by %4$s.";
+ACTION_SPELL_MISSED_PARRY_FULL_TEXT_NO_SOURCE = "%2$s was parried by %4$s.";
+ACTION_SPELL_MISSED_PARRY_POSSESSIVE = "1";
+ACTION_SPELL_MISSED_POSSESSIVE = "1";
+ACTION_SPELL_MISSED_REFLECT = "reflected";
+ACTION_SPELL_MISSED_REFLECT_FULL_TEXT = "%1$s %2$s was reflected by %4$s.";
+ACTION_SPELL_MISSED_REFLECT_FULL_TEXT_NO_SOURCE = "%2$s was reflected by %4$s.";
+ACTION_SPELL_MISSED_RESIST = "resisted";
+ACTION_SPELL_MISSED_RESIST_FULL_TEXT = "%1$s %2$s was fully resisted by %4$s.%6$s";
+ACTION_SPELL_MISSED_RESIST_FULL_TEXT_NO_SOURCE = "%2$s was fully resisted by %4$s.%6$s";
+ACTION_SPELL_MISSED_RESIST_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_DAMAGE = "damaged";
+ACTION_SPELL_PERIODIC_DAMAGE_FULL_TEXT = "%4$s suffers %5$s damage from %1$s %2$s.%6$s";
+ACTION_SPELL_PERIODIC_DAMAGE_FULL_TEXT_NO_SOURCE = "%4$s suffers %5$s damage from %2$s.%6$s";
+ACTION_SPELL_PERIODIC_DAMAGE_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_DRAIN = "drained";
+ACTION_SPELL_PERIODIC_DRAIN_FULL_TEXT = "%1$s %2$s drains %9$s %8$s from %4$s.";
+ACTION_SPELL_PERIODIC_DRAIN_FULL_TEXT_NO_SOURCE = "%2$s drains %9$s %8$s from %4$s.";
+ACTION_SPELL_PERIODIC_DRAIN_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_ENERGIZE = "energized";
+ACTION_SPELL_PERIODIC_ENERGIZE_FULL_TEXT = "%4$s gains %9$s %8$s from %1$s %2$s.";
+ACTION_SPELL_PERIODIC_ENERGIZE_FULL_TEXT_NO_SOURCE = "%4$s gains %9$s %8$s from %2$s.";
+ACTION_SPELL_PERIODIC_ENERGIZE_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_ENERGIZE_RESULT = "$extraAmount %8$s Gained";
+ACTION_SPELL_PERIODIC_HEAL = "healed";
+ACTION_SPELL_PERIODIC_HEAL_FULL_TEXT = "%4$s gains %9$s Health from %1$s %2$s.%6$s";
+ACTION_SPELL_PERIODIC_HEAL_FULL_TEXT_NO_SOURCE = "%4$s gains %9$s health from %2$s.%6$s";
+ACTION_SPELL_PERIODIC_HEAL_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_LEECH = "drained";
+ACTION_SPELL_PERIODIC_LEECH_FULL_TEXT = "%1$s %2$s drains %9$s %8$s from %4$s. %1$s gains %10$s %8$s.";
+ACTION_SPELL_PERIODIC_LEECH_FULL_TEXT_NO_SOURCE = "%2$s drains %9$s %8$s from %4$s. %1$s gains %10$s %8$s.";
+ACTION_SPELL_PERIODIC_LEECH_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_LEECH_RESULT = "(%10$s %8$s Gained)";
+ACTION_SPELL_PERIODIC_MISSED = "missed";
+ACTION_SPELL_PERIODIC_MISSED_ABSORB = "(%1$s Absorbed)";
+ACTION_SPELL_PERIODIC_MISSED_ABSORB_FULL_TEXT = "%1$s %2$s was absorbed by %4$s.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_ABSORB_FULL_TEXT_NO_SOURCE = "%2$s was absorbed by %4$s.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_ABSORB_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_MISSED_BLOCK = "(Tick Blocked)";
+ACTION_SPELL_PERIODIC_MISSED_BLOCK_FULL_TEXT = "%1$s %2$s was blocked by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_BLOCK_FULL_TEXT_NO_SOURCE = "%2$s was blocked by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_BLOCK_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_MISSED_DEFLECTED = "(Tick Deflected)";
+ACTION_SPELL_PERIODIC_MISSED_DEFLECTED_FULL_TEXT = "%1$s %2$s was deflected by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_DEFLECTED_FULL_TEXT_NO_SOURCE = "%2$s was deflected by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_DEFLECTED_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_MISSED_DODGE = "(Tick Dodged)";
+ACTION_SPELL_PERIODIC_MISSED_DODGE_FULL_TEXT = "%1$s %2$s was dodged by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_DODGE_FULL_TEXT_NO_SOURCE = "%2$s was dodged by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_DODGE_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_MISSED_EVADED = "(Tick Evaded)";
+ACTION_SPELL_PERIODIC_MISSED_EVADED_FULL_TEXT = "%1$s %2$s was evaded by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_EVADED_FULL_TEXT_NO_SOURCE = "%2$s was evaded by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_EVADED_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_MISSED_FULL_TEXT = "%1$s %2$s does not affect %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_FULL_TEXT_NO_SOURCE = "%2$s does not affect %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_IMMUNE = "(Immune)";
+ACTION_SPELL_PERIODIC_MISSED_IMMUNE_FULL_TEXT = "%4$s was immune to %1$s %2$s.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_IMMUNE_FULL_TEXT_NO_SOURCE = "%4$s was immune to %2$s.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_IMMUNE_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_MISSED_MISS = "(Tick Missed)";
+ACTION_SPELL_PERIODIC_MISSED_MISS_FULL_TEXT = "%1$s %2$s missed %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_MISS_FULL_TEXT_NO_SOURCE = "%2$s missed %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_MISS_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_MISSED_PARRY = "(Tick Parried)";
+ACTION_SPELL_PERIODIC_MISSED_PARRY_FULL_TEXT = "%1$s %2$s was parried by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_PARRY_FULL_TEXT_NO_SOURCE = "%2$s was parried by %4$s for a moment.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_PARRY_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_MISSED_POSSESSIVE = "1";
+ACTION_SPELL_PERIODIC_MISSED_RESIST = "(Tick Resisted)";
+ACTION_SPELL_PERIODIC_MISSED_RESIST_FULL_TEXT = "%1$s %2$s does not affect %4$s. %4$s resisted.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_RESIST_FULL_TEXT_NO_SOURCE = "%2$s does not affect %4$s. %4$s resisted.%6$s";
+ACTION_SPELL_PERIODIC_MISSED_RESIST_POSSESSIVE = "1";
+ACTION_SPELL_RESURRECT = "resurrected";
+ACTION_SPELL_RESURRECT_FULL_TEXT = "%1$s %2$s resurrects %4$s.%6$s";
+ACTION_SPELL_RESURRECT_FULL_TEXT_NO_SOURCE = "%2$s resurrects %4$s.%6$s";
+ACTION_SPELL_RESURRECT_POSSESSIVE = "1";
+ACTION_SPELL_STOLEN = "stole";
+ACTION_SPELL_STOLEN_BUFF = "stole";
+ACTION_SPELL_STOLEN_BUFF_FULL_TEXT = "%1$s %2$s steals %4$s %5$s.";
+ACTION_SPELL_STOLEN_BUFF_FULL_TEXT_NO_SOURCE = "%2$s steals %4$s %5$s.";
+ACTION_SPELL_STOLEN_BUFF_POSSESSIVE = "1";
+ACTION_SPELL_STOLEN_BUFF__POSSESSIVE = "1";
+ACTION_SPELL_STOLEN_DEBUFF = "stole";
+ACTION_SPELL_STOLEN_DEBUFF_FULL_TEXT = "%1$s %2$s transfers %4$s $extraSpell to %1$s.";
+ACTION_SPELL_STOLEN_DEBUFF_FULL_TEXT_NO_SOURCE = "%2$s transfers %4$s $extraSpell.";
+ACTION_SPELL_STOLEN_DEBUFF_POSSESSIVE = "1";
+ACTION_SPELL_STOLEN_FULL_TEXT = "%1$s %2$s steals %4$s %5$s.";
+ACTION_SPELL_STOLEN_FULL_TEXT_NO_SOURCE = "%2$s steals %4$s %5$s.";
+ACTION_SPELL_STOLEN_POSSESSIVE = "1";
+ACTION_SPELL_SUMMON = "summoned";
+ACTION_SPELL_SUMMON_FULL_TEXT = "%1$s %2$s summons %4$s.%6$s";
+ACTION_SPELL_SUMMON_FULL_TEXT_NO_SOURCE = "%2$s summons %4$s.%6$s";
+ACTION_SPELL_SUMMON_POSSESSIVE = "1";
+ACTION_SWING = "Melee";
+ACTION_SWING_DAMAGE = "hit";
+ACTION_SWING_DAMAGE_FULL_TEXT = "%1$s melee swing hits %4$s for %5$s.%6$s";
+ACTION_SWING_DAMAGE_FULL_TEXT_NO_SOURCE = "A melee swing hit %4$s for %5$s.%6$s";
+ACTION_SWING_DAMAGE_POSSESSIVE = "1";
+ACTION_SWING_MISSED = "missed";
+ACTION_SWING_MISSED_ABSORB = "(Absorbed)";
+ACTION_SWING_MISSED_ABSORB_FULL_TEXT = "%1$s attack was absorbed by %4$s.%6$s";
+ACTION_SWING_MISSED_ABSORB_POSSESSIVE = "1";
+ACTION_SWING_MISSED_BLOCK = "(Blocked)";
+ACTION_SWING_MISSED_BLOCK_FULL_TEXT = "%1$s attack was blocked by %4$s.%6$s";
+ACTION_SWING_MISSED_BLOCK_POSSESSIVE = "1";
+ACTION_SWING_MISSED_DEFLECT = "(Deflected)";
+ACTION_SWING_MISSED_DEFLECT_FULL_TEXT = "%1$s attack was deflected by %4$s.";
+ACTION_SWING_MISSED_DEFLECT_POSSESSIVE = "1";
+ACTION_SWING_MISSED_DODGE = "(Dodged)";
+ACTION_SWING_MISSED_DODGE_FULL_TEXT = "%1$s attack was dodged by %4$s.";
+ACTION_SWING_MISSED_DODGE_POSSESSIVE = "1";
+ACTION_SWING_MISSED_EVADE = "(Evaded)";
+ACTION_SWING_MISSED_EVADE_FULL_TEXT = "%1$s attack was evaded by %4$s.";
+ACTION_SWING_MISSED_EVADE_POSSESSIVE = "1";
+ACTION_SWING_MISSED_FULL_TEXT = "%1$s attack misses %4$s.";
+ACTION_SWING_MISSED_IMMUNE = "(Immune)";
+ACTION_SWING_MISSED_IMMUNE_FULL_TEXT = "%1$s attack failed. %4$s was immune.";
+ACTION_SWING_MISSED_IMMUNE_POSSESSIVE = "1";
+ACTION_SWING_MISSED_MISS = "(Missed)";
+ACTION_SWING_MISSED_MISS_FULL_TEXT = "%1$s attack misses %4$s.";
+ACTION_SWING_MISSED_MISS_POSSESSIVE = "1";
+ACTION_SWING_MISSED_PARRY = "(Parried)";
+ACTION_SWING_MISSED_PARRY_FULL_TEXT = "%1$s attack was parried by %4$s.";
+ACTION_SWING_MISSED_PARRY_POSSESSIVE = "1";
+ACTION_SWING_MISSED_POSSESSIVE = "1";
+ACTION_SWING_MISSED_RESIST = "(Resisted)";
+ACTION_SWING_MISSED_RESIST_FULL_TEXT = "%1$s attack was fully resisted by %4$s.%6$s";
+ACTION_SWING_MISSED_RESIST_POSSESSIVE = "1";
+ACTION_UNIT_DESTROYED = "destroyed";
+ACTION_UNIT_DESTROYED_FULL_TEXT = "%4$s was destroyed.";
+ACTION_UNIT_DESTROYED_POSSESSIVE = "0";
+ACTION_UNIT_DIED = "died";
+ACTION_UNIT_DIED_FULL_TEXT = "%4$s died.";
+ACTION_UNIT_DIED_POSSESSIVE = "0";
+ACTION_UNIT_DISSIPATES = "dissipates";
+ACTION_UNIT_DISSIPATES_FULL_TEXT = "%4$s dissipates.";
+ACTION_UNIT_DISSIPATES_POSSESSIVE = "0";
+ACTIVATE = "Activate";
+ADD = "Add";
+ADDITIONAL_COMMENTS = "Is there anything else you would like to tell us about? What could we have done to make this a better experience for you?";
+ADDITIONAL_FILTERS = "Additional Filters";
+ADDMEMBER = "Add Member";
+ADDMEMBER_TEAM = "Add Member";
+ADDONS = "AddOns";
+ADDON_ACTION_FORBIDDEN = "%s has been blocked from an action only available to the Blizzard UI.\nYou can disable this addon and reload the UI.";
+ADDON_BANNED = "Banned";
+ADDON_CORRUPT = "Corrupt";
+ADDON_DEMAND_LOADED = "Only loadable on demand";
+ADDON_DEP_BANNED = "Dependency banned";
+ADDON_DEP_CORRUPT = "Dependency corrupt";
+ADDON_DEP_DEMAND_LOADED = "Dependency only loadable on demand";
+ADDON_DEP_DISABLED = "Dependency disabled";
+ADDON_DEP_INCOMPATIBLE = "Dependency incompatible";
+ADDON_DEP_INSECURE = "Dependency insecure";
+ADDON_DEP_INTERFACE_VERSION = "Dependency out of date";
+ADDON_DEP_MISSING = "Dependency missing";
+ADDON_DISABLED = "Disabled";
+ADDON_INCOMPATIBLE = "Incompatible";
+ADDON_INSECURE = "Insecure";
+ADDON_INTERFACE_VERSION = "Out of date";
+ADDON_LOAD_FAILED = "Couldn't load %s: %s";
+ADDON_MEM_KB_ABBR = "(%.0f KB) %s";
+ADDON_MEM_MB_ABBR = "(%.2f MB) %s";
+ADDON_MISSING = "Missing";
+ADDON_UNKNOWN_ERROR = "Unknown load problem";
+ADD_ANOTHER = "Add Another";
+ADD_CHANNEL = "Enter channel name";
+ADD_CHAT_CHANNEL = "Add a channel";
+ADD_FILTER = "Add Filter";
+ADD_FRIEND = "Add Friend";
+ADD_FRIEND_LABEL = "Enter name of friend to add:";
+ADD_GUILDMEMBER_LABEL = "Add Guild Member:";
+ADD_GUILDRANK_LABEL = "Add Guild Rank:";
+ADD_IGNORE_LABEL = "Enter name of player to ignore\nor\nShift-Click a name from the chat window:";
+ADD_MUTE_LABEL = "Enter name of player to mute\nor\nShift-Click a name from the chat window:";
+ADD_RAIDMEMBER_LABEL = "Add Raid Member:";
+ADD_RAID_MEMBER = "Add Member";
+ADD_TEAMMEMBER_LABEL = "Add Team Member:";
+ADVANCED_OBJECTIVES_TEXT = "Advanced Objectives Tracking";
+ADVANCED_OPTIONS = "Advanced Options";
+ADVANCED_OPTIONS_TOOLTIP = "Configure advanced interface options";
+ADVANCED_WATCHFRAME_OPTION_ENABLE_INTERRUPT = "Disabling Advanced Objectives Tracking will cause your settings to be lost. Are you sure you want to disable Advanced Objectives Tracking?";
+ADVANCED_WORLD_MAP_TEXT = "Movable World Map";
+AFK = "Away";
+AGGRO_WARNING_DISPLAY = "Display Aggro Warning";
+AGGRO_WARNING_IN_INSTANCE = "In Instance";
+AGGRO_WARNING_IN_PARTY = "In Party";
+AGI = "Agi";
+AGILITY_COLON = "Agility:";
+AGILITY_TOOLTIP = "Increases all characters’ chance to Critical Hit. The|namount of the bonus is higher per point on Rogues than|nother classes. Agility affects dodge. Rogues get more|nDodge per point of Agility than other classes. Agility|nadds directly to Armor.";
+AIM_DOWN = "Aim Down";
+AIM_UP = "Aim Up";
+ALL = "All";
+ALLIED = "Allied";
+ALL_BOSSES_ALIVE = "All Bosses are |cff20ff20alive|r.";
+ALL_INVENTORY_SLOTS = "All Slots";
+ALL_SETTINGS = "All Settings";
+ALL_SUBCLASSES = "All Subclasses";
+ALREADY_BOUND = "|cffff0000Conflicts with %s!|r";
+ALREADY_LEARNED = "Already learned";
+ALT_KEY = "ALT key";
+ALWAYS = "Always";
+ALWAYS_SHOW_MULTIBARS_TEXT = "Always Show ActionBars";
+AMBIENCE_VOLUME = "Ambience";
+AMMOSLOT = "Ammo";
+AMMO_DAMAGE_TEMPLATE = "Adds %g damage per second";
+AMMO_SCHOOL_DAMAGE_TEMPLATE = "Adds %g %s damage per second";
+AMOUNT_PAID_COLON = "Amount Paid:";
+AMOUNT_RECEIVED_COLON = "Amount Received:";
+AMOUNT_TO_SEND = "Amount to send:";
+ANIMATION = "Animation";
+ANISOTROPIC = "Texture Filtering";
+APPEARANCE_LABEL = "Appearance";
+APPEARANCE_SUBTEXT = "These options control the ranges and levels of detail used to draw effects and objects in the game.";
+APPLY = "Apply";
+AREA_SPIRIT_HEAL = "Resurrection in %d %s";
+ARENA = "Arena";
+ARENA_BANNER_VENDOR_GREETING = "Greetings! Choose the symbol and colors of your arena team.";
+ARENA_BATTLES = "Arena Battles";
+ARENA_CASUAL = "Skirmish";
+ARENA_CHARTER_PURCHASE = "Purchase a Team Charter";
+ARENA_CHARTER_TEMPLATE = "%s Team Petition";
+ARENA_CHARTER_TURN_IN = "Turn in your Team Charter";
+ARENA_COMPLETE_MESSAGE = "The battle has ended. This arena will close in %s";
+ARENA_MASTER_NO_SEASON_TEXT = "So, you want to fight for the glory of victory in the games? Well, you're going to have to wait. The Steamwheedle Cartel is taking a break after the great excitement of last season! Come back next week for your shot at glory! Feel free to practice in the meantime, but the true fun will have to wait.";
+ARENA_MASTER_TEXT = "Let the games begin! The door is open to all who wish to find glory in the arena, and the Steamwheedle Cartel is prepared to accept your entry into the games. If victory is your destiny, then register a team with an Arena Organizer, or join one that has already been registered!";
+ARENA_OFF_SEASON_TEXT = "Arena Season %d has come to an end!|n|nDuring the week after the close of the arena season all titles and rewards will be awarded.|n|nBe sure to check with arena organizers for information about the start of Season %d!";
+ARENA_PETITION_LEADER_INSTRUCTIONS = "Select a player you wish to invite and click . To create this team, turn it in to the arena team registrar when you have gotten the required number of signatures.";
+ARENA_PETITION_MEMBER_INSTRUCTIONS = "Click the button to become a founding member of this arena team.";
+ARENA_POINTS = "Arena Points";
+ARENA_PRACTICE_BATTLE = "Practice Battle:";
+ARENA_RATED = "Battle";
+ARENA_RATED_BATTLE = "Rated Battle:";
+ARENA_RATED_MATCH = "Rated Match";
+ARENA_REGISTRAR_PURCHASE_TEXT = "To create an arena team you must purchase this charter, get the same number of unique player signatures as the size of your team, and return the charter to me. Please enter the desired name for your arena team.";
+ARENA_SPECTATOR = "You are in Spectator Mode. To abandon this battle, right click the Arena icon on the minimap and select 'Leave Arena'.";
+ARENA_TEAM = "Arena Team";
+ARENA_TEAM_2V2 = "2v2 Arena Team";
+ARENA_TEAM_3V3 = "3v3 Arena Team";
+ARENA_TEAM_5V5 = "5v5 Arena Team";
+ARENA_TEAM_CAPTAIN = "Arena Team Captain";
+ARENA_TEAM_INVITATION = "%s invites you to join the arena team: %s";
+ARENA_TEAM_LEAD_IN = "Visit an Arena Master to form a new Arena Team.";
+ARENA_TEAM_RATING = "Team Rating";
+ARENA_THIS_SEASON = "This Season";
+ARENA_THIS_SEASON_TOGGLE = "View this Season's Stats";
+ARENA_THIS_WEEK = "This Week";
+ARENA_THIS_WEEK_TOGGLE = "View this Week's Stats";
+ARMOR = "Armor";
+ARMOR_TEMPLATE = "%d Armor";
+ARMOR_TOOLTIP = "Decreases the amount of damage taken from physical attacks. The amount of reduction is influenced by the level of the attacker.\nDamage reduction against a level %d attacker: %.1f%%";
+ASSEMBLING_GROUP = "Assembling Group...";
+ASSIGNED_COLON = "Currently Assigned:";
+ASSIST_ATTACK = "Attack on Assist";
+ATTACHMENT_TEXT = "Drag an item here to include it with your mail";
+ATTACK = "Attack";
+ATTACK_COLON = "Attack:";
+ATTACK_POWER = "Power";
+ATTACK_POWER_TOOLTIP = "Attack Power";
+ATTACK_SPEED = "Attack Speed";
+ATTACK_SPEED_SECONDS = "Attack Speed (seconds)";
+ATTACK_SPEED_TOOLTIP1 = "Seconds per attack";
+ATTACK_TOOLTIP = "Attack Rating";
+ATTACK_TOOLTIP_SUBTEXT = "Your attack rating affects your chance to hit a target, and is based on the weapon skill of the weapon you are currently wielding.";
+AT_WAR = "At War";
+AUCTIONS = "Auctions";
+AUCTION_BUYOUT_ERROR = "(Must be >= the start price)";
+AUCTION_CREATING = "Creating %d/%d";
+AUCTION_CREATOR = "Seller";
+AUCTION_DURATION = "Duration";
+AUCTION_DURATION_ERROR = "(Auction will be set to 5 mins)";
+AUCTION_DURATION_ONE = "12 Hours";
+AUCTION_DURATION_THREE = "48 Hours";
+AUCTION_DURATION_TWO = "24 Hours";
+AUCTION_EXPIRED_MAIL_SUBJECT = "Auction expired: %s";
+AUCTION_HOUSE_CUT_COLON = "Auction House Cut:";
+AUCTION_INVOICE_FUNDS_DELAY = "Estimated delivery time %s";
+AUCTION_INVOICE_FUNDS_NOT_YET_SENT = "Amount not yet sent";
+AUCTION_INVOICE_MAIL_SUBJECT = "Sale Pending: %s";
+AUCTION_INVOICE_PENDING_FUNDS_COLON = "Amount Pending:";
+AUCTION_ITEM = "Auction Item";
+AUCTION_ITEM_INCOMING_AMOUNT = "Incoming Amount";
+AUCTION_ITEM_SOLD = "%s - Sold";
+AUCTION_ITEM_TEXT = "Drag an item here to auction it";
+AUCTION_ITEM_TIME_UNTIL_DELIVERY = "%s Until Delivery";
+AUCTION_NUM_STACKS = "Number of Stacks";
+AUCTION_OUTBID_MAIL_SUBJECT = "Outbid on %s";
+AUCTION_PRICE = "Price";
+AUCTION_PRICE_PER_ITEM = "per item";
+AUCTION_PRICE_PER_STACK = "per stack";
+AUCTION_REMOVED_MAIL_SUBJECT = "Auction cancelled: %s";
+AUCTION_SOLD_MAIL_SUBJECT = "Auction successful: %s";
+AUCTION_STACK_SIZE = "Stack Size";
+AUCTION_TIME_LEFT1 = "Short";
+AUCTION_TIME_LEFT1_DETAIL = "Less than 30 mins";
+AUCTION_TIME_LEFT2 = "Medium";
+AUCTION_TIME_LEFT2_DETAIL = "Between 30 mins and 2 hrs";
+AUCTION_TIME_LEFT3 = "Long";
+AUCTION_TIME_LEFT3_DETAIL = "Between 2 hrs and 12 hrs";
+AUCTION_TIME_LEFT4 = "Very Long";
+AUCTION_TIME_LEFT4_DETAIL = "Greater than 12 hrs";
+AUCTION_TITLE = "%s's Auctions";
+AUCTION_TOOLTIP_BID_PREFIX = "Price per unit:";
+AUCTION_TOOLTIP_BUYOUT_PREFIX = "Buyout price per unit:";
+AUCTION_WON_MAIL_SUBJECT = "Auction won: %s";
+AURAS = "Auras";
+AURAS_COMBATLOG_TOOLTIP = "Shows message about beneficial and harmful state effects.";
+AURA_END = "<%s> fades";
+AUTOFOLLOWSTART = "Following %s.";
+AUTOFOLLOWSTOP = "You stop following %s.";
+AUTOFOLLOWSTOPCOMBAT = "You stop moving to attack %s";
+AUTO_ADD_DISABLED_GROUPED_TOOLTIP = "You cannot automatically add more members to your group if your group is already full, or you are not the leader.";
+AUTO_ADD_DISABLED_QUEUED_TOOLTIP = "You cannot automatically add more members to your group if you are already looking for a group to join.";
+AUTO_ADD_MEMBERS = "Auto Add Members";
+AUTO_ADD_TOOLTIP = "Automatically add members to your group. Only works for dungeons.";
+AUTO_DISMOUNT_FLYING_TEXT = "Auto Dismount in Flight";
+AUTO_FOLLOW_SPEED = "Auto Follow Speed";
+AUTO_JOIN = "Auto Join";
+AUTO_JOIN_DISABLED_TOOLTIP = "You cannot automatically join a group if you are currently automatically looking for more people to add to your group.";
+AUTO_JOIN_GUILD_CHANNEL = "Auto Join Guild Recruitment Channel";
+AUTO_JOIN_TOOLTIP = "Automatically places you in a group that matches your criteria. Only works for dungeons.";
+AUTO_JOIN_VOICE = "Auto Join Voice Chat";
+AUTO_LOOT_DEFAULT_TEXT = "Auto Loot";
+AUTO_LOOT_KEY_TEXT = "Auto Loot Key";
+AUTO_QUEST_PROGRESS_TEXT = "Automatic Quest Progress Updates";
+AUTO_QUEST_WATCH_TEXT = "Automatic Quest Tracking";
+AUTO_RANGED_COMBAT_TEXT = "Auto Attack/Auto Shot";
+AUTO_SELF_CAST_KEY_TEXT = "Self Cast Key";
+AUTO_SELF_CAST_TEXT = "Auto Self Cast";
+AVAILABLE = "Available";
+AVAILABLE_QUESTS = "Available Quests";
+AVAILABLE_SERVICES = "Available Services";
+AVERAGE_WAIT_TIME = "Average Wait Time:";
+A_RANDOM_DUNGEON = "a Random Dungeon";
+BACK = "Back";
+BACKGROUND = "Background";
+BACKPACK_TOOLTIP = "Backpack";
+BACKSLOT = "Back";
+BAGSLOT = "Bag";
+BAGSLOTTEXT = "Bag Slots";
+BAGS_ONLY = "Only bags can go here!";
+BANKSLOTPURCHASE = "Purchase";
+BANKSLOTPURCHASE_LABEL = "Do you wish to purchase space for an additional bag?";
+BANK_BAG = "Bag Slot";
+BANK_BAG_PURCHASE = "Purchasable Bag Slot";
+BARBERSHOP = "Barber Shop";
+BASIC_OPTIONS_TOOLTIP = "Configure basic interface options";
+BATTLEFIELDMINIMAP_OPACITY_LABEL = "Change Opacity";
+BATTLEFIELDMINIMAP_OPTIONS_LABEL = "Zone Map Options";
+BATTLEFIELDS = "Battlegrounds";
+BATTLEFIELD_ALERT = "You are eligible to enter %s You have %s";
+BATTLEFIELD_CONFIRM_STATUS = "Ready to Enter";
+BATTLEFIELD_FULL = "%s (Full)";
+BATTLEFIELD_GROUP_JOIN = "Join as Group";
+BATTLEFIELD_IN_BATTLEFIELD = "You are in %s\n|cffffffff\n|r";
+BATTLEFIELD_IN_QUEUE = "You are in the queue for %s\nAverage wait time: %s (Last 10 players)\nTime in queue: %s";
+BATTLEFIELD_IN_QUEUE_SIMPLE = "You are in the queue for %s";
+BATTLEFIELD_JOIN = "Join Battle";
+BATTLEFIELD_LEVEL = "Level Range:";
+BATTLEFIELD_MINIMAP = "Zone Map";
+BATTLEFIELD_MINIMAP_SHOW_ALWAYS = "Always Show";
+BATTLEFIELD_MINIMAP_SHOW_BATTLEGROUNDS = "Show in Battlegrounds";
+BATTLEFIELD_MINIMAP_SHOW_NEVER = "Never Show";
+BATTLEFIELD_NAME = "Battlefield Instance:";
+BATTLEFIELD_QUEUE_CONFIRM = "You are eligible to enter %s\nYou will be removed from the queue in %s";
+BATTLEFIELD_QUEUE_CONFIRM_SIMPLE = "You are eligible to enter %s";
+BATTLEFIELD_QUEUE_PENDING_REMOVAL = "You are eligible to enter %s\nYou are about to be removed from the queue.";
+BATTLEFIELD_QUEUE_STATUS = "In Queue";
+BATTLEGROUND = "Battleground";
+BATTLEGROUNDS = "Battlegrounds";
+BATTLEGROUND_COMPLETE_MESSAGE = "The battle has ended. This battleground will close in %s";
+BATTLEGROUND_HOLIDAY = "Call to Arms";
+BATTLEGROUND_HOLIDAY_EXPLANATION = "Your urgent assistance is needed to combat our foes! Completing this Battleground will earn you extra rewards.";
+BATTLEGROUND_INSTANCE = "Instance";
+BATTLEGROUND_INSTANCE_TOOLTIP = "Join the queue to enter this battleground when space becomes available. This will result in a longer wait than selecting first available.";
+BATTLEGROUND_LEADER = "Battleground Leader";
+BATTLEGROUND_MESSAGE = "Battleground";
+BATTLEGROUND_REQUIRED_LEVEL_TOOLTIP = "Requires level %s to enter.";
+BATTLEGROUND_SILENCE = "Silence in Battleground";
+BATTLEGROUND_UNSILENCE = "Unsilence in Battleground";
+BATTLENET_FRIEND = "Real ID";
+BATTLENET_FRIEND_INFO = "This is a person you know and trust in real life. You will be able to chat with them no matter which Blizzard game you are playing. They must accept your friend invite, at which point your real name will be displayed to all of their friends.";
+BATTLENET_FRIEND_LABEL = "Enter email address";
+BATTLENET_NAME_FORMAT = "%1$s %2$s";
+BATTLENET_OPTIONS_LABEL = "Battle.net|TInterface\\OptionsFrame\\UI-OptionsFrame-NewFeatureIcon:0:0:0:-1|t";
+BATTLENET_OPTIONS_SUBTEXT = "These options allow you to change the types of Battle.net messages you receive.";
+BATTLENET_UNAVAILABLE = "Battle.net is unavailable";
+BATTLENET_UNAVAILABLE_ALERT = "The Battle.net service is currently unavailable.|n|nYour Real ID friends will not show up. You will also not be able to send or receive new Real ID friend requests. A game restart may be required to re-enable functionality.";
+BENCHMARK_TAXI_AVERAGE_FPS = "Average FPS %.3f";
+BENCHMARK_TAXI_MAX_FPS = "Maximum FPS %.3f";
+BENCHMARK_TAXI_MIN_FPS = "Minimum FPS %.3f";
+BENCHMARK_TAXI_MODE_OFF = "Taxi Time Test OFF";
+BENCHMARK_TAXI_MODE_ON = "Taxi Time Test ON";
+BENCHMARK_TAXI_RESULTS = "Taxi time test results:";
+BENCHMARK_TAXI_TOTAL_TIME = "Total time %.3f seconds";
+BENEFICIAL = "Beneficial";
+BENEFICIAL_AURA_COMBATLOG_TOOLTIP = "Show when you gain or lose a beneficial aura.";
+BF_NOT_IN = "You are not currently in a battleground";
+BG_SYSTEM_ALLIANCE = "Battleground Alliance";
+BG_SYSTEM_HORDE = "Battleground Horde";
+BG_SYSTEM_NEUTRAL = "Battleground Neutral";
+BID = "Bid";
+BIDS = "Bids";
+BID_AUCTION_CONFIRMATION = "Bid on auction for:";
+BID_STATUS = "Bid Status";
+BILLING_NAG_DIALOG = "Your play time expires in %d %s";
+BILLING_NAG_WARNING = "Your play time expires in %d |4minute:minutes;";
+BINDING_HEADER_ACTIONBAR = "Action Bar Functions";
+BINDING_HEADER_BLANK = " ";
+BINDING_HEADER_CAMERA = "Camera Functions";
+BINDING_HEADER_CHAT = "Chat Functions";
+BINDING_HEADER_INTERFACE = "Interface Panel Functions";
+BINDING_HEADER_ITUNES_REMOTE = "iTunes Remote";
+BINDING_HEADER_MISC = "Miscellaneous Functions";
+BINDING_HEADER_MOVEMENT = "Movement Keys";
+BINDING_HEADER_MOVIE_RECORDING_SECTION = "Movie Recording";
+BINDING_HEADER_MULTIACTIONBAR = "MultiActionBar Bindings";
+BINDING_HEADER_MULTICASTFUNCTIONS = "Shaman Totem Bar Functions";
+BINDING_HEADER_RAID_TARGET = "Raid Targeting";
+BINDING_HEADER_TARGETING = "Targeting Functions";
+BINDING_HEADER_VEHICLE = "Vehicle Controls";
+BINDING_HEADER_VOICE_CHAT = "Voice Chat";
+BINDING_NAME_ACTIONBUTTON1 = "Action Button 1";
+BINDING_NAME_ACTIONBUTTON10 = "Action Button 10";
+BINDING_NAME_ACTIONBUTTON11 = "Action Button 11";
+BINDING_NAME_ACTIONBUTTON12 = "Action Button 12";
+BINDING_NAME_ACTIONBUTTON2 = "Action Button 2";
+BINDING_NAME_ACTIONBUTTON3 = "Action Button 3";
+BINDING_NAME_ACTIONBUTTON4 = "Action Button 4";
+BINDING_NAME_ACTIONBUTTON5 = "Action Button 5";
+BINDING_NAME_ACTIONBUTTON6 = "Action Button 6";
+BINDING_NAME_ACTIONBUTTON7 = "Action Button 7";
+BINDING_NAME_ACTIONBUTTON8 = "Action Button 8";
+BINDING_NAME_ACTIONBUTTON9 = "Action Button 9";
+BINDING_NAME_ACTIONPAGE1 = "Action Page 1";
+BINDING_NAME_ACTIONPAGE2 = "Action Page 2";
+BINDING_NAME_ACTIONPAGE3 = "Action Page 3";
+BINDING_NAME_ACTIONPAGE4 = "Action Page 4";
+BINDING_NAME_ACTIONPAGE5 = "Action Page 5";
+BINDING_NAME_ACTIONPAGE6 = "Action Page 6";
+BINDING_NAME_ACTIONWINDOW1 = "Movable Action 1";
+BINDING_NAME_ACTIONWINDOW2 = "Movable Action 2";
+BINDING_NAME_ACTIONWINDOW3 = "Movable Action 3";
+BINDING_NAME_ACTIONWINDOW4 = "Movable Action 4";
+BINDING_NAME_ACTIONWINDOWDECREMENT = "Slide Movable Actions Left";
+BINDING_NAME_ACTIONWINDOWINCREMENT = "Slide Movable Actions Right";
+BINDING_NAME_ACTIONWINDOWMOVE = "Slide Movable Actions";
+BINDING_NAME_ALLNAMEPLATES = "Show All Name Plates";
+BINDING_NAME_ASSISTTARGET = "Assist Target";
+BINDING_NAME_ATTACKTARGET = "Attack Target";
+BINDING_NAME_BONUSACTIONBUTTON1 = "Secondary Action Button 1";
+BINDING_NAME_BONUSACTIONBUTTON10 = "Secondary Action Button 10";
+BINDING_NAME_BONUSACTIONBUTTON2 = "Secondary Action Button 2";
+BINDING_NAME_BONUSACTIONBUTTON3 = "Secondary Action Button 3";
+BINDING_NAME_BONUSACTIONBUTTON4 = "Secondary Action Button 4";
+BINDING_NAME_BONUSACTIONBUTTON5 = "Secondary Action Button 5";
+BINDING_NAME_BONUSACTIONBUTTON6 = "Secondary Action Button 6";
+BINDING_NAME_BONUSACTIONBUTTON7 = "Secondary Action Button 7";
+BINDING_NAME_BONUSACTIONBUTTON8 = "Secondary Action Button 8";
+BINDING_NAME_BONUSACTIONBUTTON9 = "Secondary Action Button 9";
+BINDING_NAME_CAMERAZOOMIN = "Zoom In";
+BINDING_NAME_CAMERAZOOMOUT = "Zoom Out";
+BINDING_NAME_CHATBOTTOM = "Chat Bottom";
+BINDING_NAME_CHATPAGEDOWN = "Chat Page Down";
+BINDING_NAME_CHATPAGEUP = "Chat Page Up";
+BINDING_NAME_COMBATLOGBOTTOM = "Combat Log Bottom";
+BINDING_NAME_COMBATLOGPAGEDOWN = "Combat Log Page Down";
+BINDING_NAME_COMBATLOGPAGEUP = "Combat Log Page Up";
+BINDING_NAME_DISMOUNT = "Dismount";
+BINDING_NAME_FLIPCAMERAYAW = "Flip Camera";
+BINDING_NAME_FOCUSTARGET = "Focus Target";
+BINDING_NAME_FOLLOWTARGET = "Follow Target";
+BINDING_NAME_FRIENDNAMEPLATES = "Show Friendly Name Plates";
+BINDING_NAME_INTERACTMOUSEOVER = "Interact With Mouseover";
+BINDING_NAME_INTERACTTARGET = "Interact With Target";
+BINDING_NAME_INVERTBINDINGMODE1 = "Action Binding Mode Modifier";
+BINDING_NAME_INVERTBINDINGMODE2 = "Target Binding Mode Modifier";
+BINDING_NAME_INVERTBINDINGMODE3 = "Custom Binding Mode Modifier";
+BINDING_NAME_ITUNES_BACKTRACK = "iTunes Back Track";
+BINDING_NAME_ITUNES_NEXTTRACK = "iTunes Next Track";
+BINDING_NAME_ITUNES_PLAYPAUSE = "iTunes Play/Pause";
+BINDING_NAME_ITUNES_VOLUMEDOWN = "iTunes Volume Down";
+BINDING_NAME_ITUNES_VOLUMEUP = "iTunes Volume Up";
+BINDING_NAME_JUMP = "Jump";
+BINDING_NAME_MASTERVOLUMEDOWN = "Master Volume Down";
+BINDING_NAME_MASTERVOLUMEUP = "Master Volume Up";
+BINDING_NAME_MINIMAPZOOMIN = "Minimap Zoom In";
+BINDING_NAME_MINIMAPZOOMOUT = "Minimap Zoom Out";
+BINDING_NAME_MOVEANDSTEER = "Move and Steer";
+BINDING_NAME_MOVEBACKWARD = "Move Backward";
+BINDING_NAME_MOVEFORWARD = "Move Forward";
+BINDING_NAME_MOVEVIEWIN = "Move View In";
+BINDING_NAME_MOVEVIEWOUT = "Move View Out";
+BINDING_NAME_MOVIE_RECORDING_CANCEL = "Cancel Recording/Compression";
+BINDING_NAME_MOVIE_RECORDING_COMPRESS = "Compress Movies";
+BINDING_NAME_MOVIE_RECORDING_GUI = "Show/Hide User Interface";
+BINDING_NAME_MOVIE_RECORDING_STARTSTOP = "Start/Stop Recording";
+BINDING_NAME_MULTIACTIONBAR1BUTTON1 = "BottomLeft Action Button 1";
+BINDING_NAME_MULTIACTIONBAR1BUTTON10 = "BottomLeft Action Button 10";
+BINDING_NAME_MULTIACTIONBAR1BUTTON11 = "BottomLeft Action Button 11";
+BINDING_NAME_MULTIACTIONBAR1BUTTON12 = "BottomLeft Action Button 12";
+BINDING_NAME_MULTIACTIONBAR1BUTTON2 = "BottomLeft Action Button 2";
+BINDING_NAME_MULTIACTIONBAR1BUTTON3 = "BottomLeft Action Button 3";
+BINDING_NAME_MULTIACTIONBAR1BUTTON4 = "BottomLeft Action Button 4";
+BINDING_NAME_MULTIACTIONBAR1BUTTON5 = "BottomLeft Action Button 5";
+BINDING_NAME_MULTIACTIONBAR1BUTTON6 = "BottomLeft Action Button 6";
+BINDING_NAME_MULTIACTIONBAR1BUTTON7 = "BottomLeft Action Button 7";
+BINDING_NAME_MULTIACTIONBAR1BUTTON8 = "BottomLeft Action Button 8";
+BINDING_NAME_MULTIACTIONBAR1BUTTON9 = "BottomLeft Action Button 9";
+BINDING_NAME_MULTIACTIONBAR2BUTTON1 = "BottomRight Action Button 1";
+BINDING_NAME_MULTIACTIONBAR2BUTTON10 = "BottomRight Action Button 10";
+BINDING_NAME_MULTIACTIONBAR2BUTTON11 = "BottomRight Action Button 11";
+BINDING_NAME_MULTIACTIONBAR2BUTTON12 = "BottomRight Action Button 12";
+BINDING_NAME_MULTIACTIONBAR2BUTTON2 = "BottomRight Action Button 2";
+BINDING_NAME_MULTIACTIONBAR2BUTTON3 = "BottomRight Action Button 3";
+BINDING_NAME_MULTIACTIONBAR2BUTTON4 = "BottomRight Action Button 4";
+BINDING_NAME_MULTIACTIONBAR2BUTTON5 = "BottomRight Action Button 5";
+BINDING_NAME_MULTIACTIONBAR2BUTTON6 = "BottomRight Action Button 6";
+BINDING_NAME_MULTIACTIONBAR2BUTTON7 = "BottomRight Action Button 7";
+BINDING_NAME_MULTIACTIONBAR2BUTTON8 = "BottomRight Action Button 8";
+BINDING_NAME_MULTIACTIONBAR2BUTTON9 = "BottomRight Action Button 9";
+BINDING_NAME_MULTIACTIONBAR3BUTTON1 = "Right Action Button 1";
+BINDING_NAME_MULTIACTIONBAR3BUTTON10 = "Right Action Button 10";
+BINDING_NAME_MULTIACTIONBAR3BUTTON11 = "Right Action Button 11";
+BINDING_NAME_MULTIACTIONBAR3BUTTON12 = "Right Action Button 12";
+BINDING_NAME_MULTIACTIONBAR3BUTTON2 = "Right Action Button 2";
+BINDING_NAME_MULTIACTIONBAR3BUTTON3 = "Right Action Button 3";
+BINDING_NAME_MULTIACTIONBAR3BUTTON4 = "Right Action Button 4";
+BINDING_NAME_MULTIACTIONBAR3BUTTON5 = "Right Action Button 5";
+BINDING_NAME_MULTIACTIONBAR3BUTTON6 = "Right Action Button 6";
+BINDING_NAME_MULTIACTIONBAR3BUTTON7 = "Right Action Button 7";
+BINDING_NAME_MULTIACTIONBAR3BUTTON8 = "Right Action Button 8";
+BINDING_NAME_MULTIACTIONBAR3BUTTON9 = "Right Action Button 9";
+BINDING_NAME_MULTIACTIONBAR4BUTTON1 = "Right ActionBar 2 Button 1";
+BINDING_NAME_MULTIACTIONBAR4BUTTON10 = "Right ActionBar 2 Button 10";
+BINDING_NAME_MULTIACTIONBAR4BUTTON11 = "Right ActionBar 2 Button 11";
+BINDING_NAME_MULTIACTIONBAR4BUTTON12 = "Right ActionBar 2 Button 12";
+BINDING_NAME_MULTIACTIONBAR4BUTTON2 = "Right ActionBar 2 Button 2";
+BINDING_NAME_MULTIACTIONBAR4BUTTON3 = "Right ActionBar 2 Button 3";
+BINDING_NAME_MULTIACTIONBAR4BUTTON4 = "Right ActionBar 2 Button 4";
+BINDING_NAME_MULTIACTIONBAR4BUTTON5 = "Right ActionBar 2 Button 5";
+BINDING_NAME_MULTIACTIONBAR4BUTTON6 = "Right ActionBar 2 Button 6";
+BINDING_NAME_MULTIACTIONBAR4BUTTON7 = "Right ActionBar 2 Button 7";
+BINDING_NAME_MULTIACTIONBAR4BUTTON8 = "Right ActionBar 2 Button 8";
+BINDING_NAME_MULTIACTIONBAR4BUTTON9 = "Right ActionBar 2 Button 9";
+BINDING_NAME_MULTICASTACTIONBUTTON1 = "Earth Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON10 = "Fire Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON11 = "Water Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON12 = "Air Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON2 = "Fire Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON3 = "Water Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON4 = "Air Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON5 = "Earth Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON6 = "Fire Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON7 = "Water Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON8 = "Air Totem";
+BINDING_NAME_MULTICASTACTIONBUTTON9 = "Earth Totem";
+BINDING_NAME_MULTICASTRECALLBUTTON1 = "Totemic Recall";
+BINDING_NAME_MULTICASTSUMMONBUTTON1 = "Call of the Elements";
+BINDING_NAME_MULTICASTSUMMONBUTTON2 = "Call of the Ancestors";
+BINDING_NAME_MULTICASTSUMMONBUTTON3 = "Call of the Spirits";
+BINDING_NAME_NAMEPLATES = "Show Enemy Name Plates";
+BINDING_NAME_NEXTACTIONPAGE = "Next Action Bar";
+BINDING_NAME_NEXTVIEW = "Next View";
+BINDING_NAME_OPENALLBAGS = "Open All Bags";
+BINDING_NAME_OPENCHAT = "Open Chat";
+BINDING_NAME_OPENCHATSLASH = "Open Chat Slash";
+BINDING_NAME_PETATTACK = "Pet Attack";
+BINDING_NAME_PITCHDECREMENT = "Pitch Decrement";
+BINDING_NAME_PITCHDOWN = "Pitch Down";
+BINDING_NAME_PITCHINCREMENT = "Pitch Increment";
+BINDING_NAME_PITCHUP = "Pitch Up";
+BINDING_NAME_PREVIOUSACTIONPAGE = "Previous Action Bar";
+BINDING_NAME_PREVVIEW = "Previous View";
+BINDING_NAME_PUSHTOTALK = "Push to Talk";
+BINDING_NAME_RAIDTARGET1 = "Assign Star to Target";
+BINDING_NAME_RAIDTARGET2 = "Assign Circle to Target";
+BINDING_NAME_RAIDTARGET3 = "Assign Diamond to Target";
+BINDING_NAME_RAIDTARGET4 = "Assign Triangle to Target";
+BINDING_NAME_RAIDTARGET5 = "Assign Moon to Target";
+BINDING_NAME_RAIDTARGET6 = "Assign Square to Target";
+BINDING_NAME_RAIDTARGET7 = "Assign Cross to Target";
+BINDING_NAME_RAIDTARGET8 = "Assign Skull to Target";
+BINDING_NAME_RAIDTARGETNONE = "Clear Raid Target Icon";
+BINDING_NAME_REPLY = "Chat Reply";
+BINDING_NAME_REPLY2 = "Re-Whisper";
+BINDING_NAME_RESETVIEW1 = "Reset View 1";
+BINDING_NAME_RESETVIEW2 = "Reset View 2";
+BINDING_NAME_RESETVIEW3 = "Reset View 3";
+BINDING_NAME_RESETVIEW4 = "Reset View 4";
+BINDING_NAME_RESETVIEW5 = "Reset View 5";
+BINDING_NAME_SAVEVIEW1 = "Save View 1";
+BINDING_NAME_SAVEVIEW2 = "Save View 2";
+BINDING_NAME_SAVEVIEW3 = "Save View 3";
+BINDING_NAME_SAVEVIEW4 = "Save View 4";
+BINDING_NAME_SAVEVIEW5 = "Save View 5";
+BINDING_NAME_SCREENSHOT = "Screen Shot";
+BINDING_NAME_SETVIEW1 = "Set View 1";
+BINDING_NAME_SETVIEW2 = "Set View 2";
+BINDING_NAME_SETVIEW3 = "Set View 3";
+BINDING_NAME_SETVIEW4 = "Set View 4";
+BINDING_NAME_SETVIEW5 = "Set View 5";
+BINDING_NAME_SHAPESHIFTBUTTON1 = "Special Action Button 1";
+BINDING_NAME_SHAPESHIFTBUTTON10 = "Special Action Button 10";
+BINDING_NAME_SHAPESHIFTBUTTON2 = "Special Action Button 2";
+BINDING_NAME_SHAPESHIFTBUTTON3 = "Special Action Button 3";
+BINDING_NAME_SHAPESHIFTBUTTON4 = "Special Action Button 4";
+BINDING_NAME_SHAPESHIFTBUTTON5 = "Special Action Button 5";
+BINDING_NAME_SHAPESHIFTBUTTON6 = "Special Action Button 6";
+BINDING_NAME_SHAPESHIFTBUTTON7 = "Special Action Button 7";
+BINDING_NAME_SHAPESHIFTBUTTON8 = "Special Action Button 8";
+BINDING_NAME_SHAPESHIFTBUTTON9 = "Special Action Button 9";
+BINDING_NAME_SITORSTAND = "Sit/Move Down";
+BINDING_NAME_STARTATTACK = "Start Attack";
+BINDING_NAME_STOPATTACK = "Stop Attacking";
+BINDING_NAME_STOPCASTING = "Stop Casting";
+BINDING_NAME_STRAFELEFT = "Strafe Left";
+BINDING_NAME_STRAFERIGHT = "Strafe Right";
+BINDING_NAME_SWINGCAMERA = "Swing Camera";
+BINDING_NAME_SWINGCAMERAANDPLAYER = "Swing Camera And Player";
+BINDING_NAME_TARGETENEMYDIRECTIONAL = "Target Enemy In Direction";
+BINDING_NAME_TARGETFOCUS = "Target Focus";
+BINDING_NAME_TARGETFRIENDDIRECTIONAL = "Target Friend In Direction";
+BINDING_NAME_TARGETLASTHOSTILE = "Target Last Hostile";
+BINDING_NAME_TARGETLASTTARGET = "Target Last Target";
+BINDING_NAME_TARGETMOUSEOVER = "Target Mouseover";
+BINDING_NAME_TARGETNEARESTENEMY = "Target Nearest Enemy";
+BINDING_NAME_TARGETNEARESTENEMYPLAYER = "Target Nearest Enemy Player";
+BINDING_NAME_TARGETNEARESTFRIEND = "Target Nearest Friend";
+BINDING_NAME_TARGETNEARESTFRIENDPLAYER = "Target Nearest Friendly Player";
+BINDING_NAME_TARGETPARTYMEMBER1 = "Target Party Member 1";
+BINDING_NAME_TARGETPARTYMEMBER2 = "Target Party Member 2";
+BINDING_NAME_TARGETPARTYMEMBER3 = "Target Party Member 3";
+BINDING_NAME_TARGETPARTYMEMBER4 = "Target Party Member 4";
+BINDING_NAME_TARGETPARTYPET1 = "Target Party Pet 1";
+BINDING_NAME_TARGETPARTYPET2 = "Target Party Pet 2";
+BINDING_NAME_TARGETPARTYPET3 = "Target Party Pet 3";
+BINDING_NAME_TARGETPARTYPET4 = "Target Party Pet 4";
+BINDING_NAME_TARGETPET = "Target Pet";
+BINDING_NAME_TARGETPREVIOUSENEMY = "Target Previous Enemy";
+BINDING_NAME_TARGETPREVIOUSENEMYPLAYER = "Target Previous Enemy Player";
+BINDING_NAME_TARGETPREVIOUSFRIEND = "Target Previous Friend";
+BINDING_NAME_TARGETPREVIOUSFRIENDPLAYER = "Target Previous Friendly Player";
+BINDING_NAME_TARGETSELF = "Target Self";
+BINDING_NAME_TARGETTALKER = "Target Current Talker";
+BINDING_NAME_TOGGLEABILITYBOOK = "Toggle Abilities";
+BINDING_NAME_TOGGLEACHIEVEMENT = "Toggle Achievement Frame";
+BINDING_NAME_TOGGLEACTIONBARLOCK = "Toggle ActionBar Lock";
+BINDING_NAME_TOGGLEAUTORUN = "Toggle Autorun";
+BINDING_NAME_TOGGLEAUTOSELFCAST = "Toggle Auto Self Cast";
+BINDING_NAME_TOGGLEBACKPACK = "Toggle Backpack";
+BINDING_NAME_TOGGLEBAG1 = "Toggle Bag 1";
+BINDING_NAME_TOGGLEBAG2 = "Toggle Bag 2";
+BINDING_NAME_TOGGLEBAG3 = "Toggle Bag 3";
+BINDING_NAME_TOGGLEBAG4 = "Toggle Bag 4";
+BINDING_NAME_TOGGLEBAG5 = "Toggle Bag 5";
+BINDING_NAME_TOGGLEBATTLEFIELDMINIMAP = "Toggle Zone Map";
+BINDING_NAME_TOGGLEBINDINGMODE1 = "Action Binding Mode Toggle";
+BINDING_NAME_TOGGLEBINDINGMODE2 = "Target Binding Mode Toggle";
+BINDING_NAME_TOGGLEBINDINGMODE3 = "Custom Binding Mode Toggle";
+BINDING_NAME_TOGGLECHANNELPULLOUT = "Toggle Channel Pullout";
+BINDING_NAME_TOGGLECHANNELTAB = "Toggle Channel Pane";
+BINDING_NAME_TOGGLECHARACTER0 = "Toggle Character Pane";
+BINDING_NAME_TOGGLECHARACTER1 = "Toggle Skill Pane";
+BINDING_NAME_TOGGLECHARACTER2 = "Toggle Reputation Pane";
+BINDING_NAME_TOGGLECHARACTER3 = "Toggle Pet Pane";
+BINDING_NAME_TOGGLECHARACTER4 = "Toggle PVP Pane";
+BINDING_NAME_TOGGLECHATTAB = "Toggle Chat Pane";
+BINDING_NAME_TOGGLECOMBATLOG = "Toggle Combat Log";
+BINDING_NAME_TOGGLECURRENCY = "Toggle Currency Frame";
+BINDING_NAME_TOGGLEFPS = "Toggle Framerate Display";
+BINDING_NAME_TOGGLEFRIENDSTAB = "Toggle Friends Pane";
+BINDING_NAME_TOGGLEGAMEMENU = "Toggle Game Menu";
+BINDING_NAME_TOGGLEGUILDTAB = "Toggle Guild Pane";
+BINDING_NAME_TOGGLEIGNORETAB = "Toggle Ignore Pane";
+BINDING_NAME_TOGGLEINSCRIPTION = "Toggle Glyphs";
+BINDING_NAME_TOGGLEKEYRING = "Toggle Keyring";
+BINDING_NAME_TOGGLELFGPARENT = "Toggle Dungeon Finder Frame";
+BINDING_NAME_TOGGLELFRPARENT = "Toggle Raid Browser";
+BINDING_NAME_TOGGLEMINIMAP = "Toggle Minimap";
+BINDING_NAME_TOGGLEMINIMAPROTATION = "Toggle Minimap Rotation";
+BINDING_NAME_TOGGLEMOUSE = "Joystick Mouse Mode";
+BINDING_NAME_TOGGLEMUSIC = "Toggle Music";
+BINDING_NAME_TOGGLEPETBOOK = "Toggle Pet Book";
+BINDING_NAME_TOGGLEPVP = "Toggle PvP Frame";
+BINDING_NAME_TOGGLEQUESTLOG = "Toggle Quest Log";
+BINDING_NAME_TOGGLERAIDTAB = "Toggle Raid Pane";
+BINDING_NAME_TOGGLERUN = "Toggle Run/Walk";
+BINDING_NAME_TOGGLESELFMUTE = "Toggle Self Mute";
+BINDING_NAME_TOGGLESHEATH = "Sheath/Unsheath Weapon";
+BINDING_NAME_TOGGLESOCIAL = "Toggle Social Pane";
+BINDING_NAME_TOGGLESOUND = "Toggle Sound";
+BINDING_NAME_TOGGLESPELLBOOK = "Toggle Spellbook";
+BINDING_NAME_TOGGLESTATISTICS = "Toggle Statistics Frame";
+BINDING_NAME_TOGGLETALENTS = "Toggle Talent Pane";
+BINDING_NAME_TOGGLEUI = "Toggle User Interface";
+BINDING_NAME_TOGGLEWHOTAB = "Toggle Who Pane";
+BINDING_NAME_TOGGLEWORLDMAP = "Toggle World Map Pane";
+BINDING_NAME_TOGGLEWORLDMAPSIZE = "Toggle World Map Size";
+BINDING_NAME_TOGGLEWORLDSTATESCORES = "Toggle Score Screen";
+BINDING_NAME_TURNLEFT = "Turn Left";
+BINDING_NAME_TURNRIGHT = "Turn Right";
+BINDING_NAME_VEHICLEAIMDECREMENT = "Aim Decrement";
+BINDING_NAME_VEHICLEAIMDOWN = "Aim Down";
+BINDING_NAME_VEHICLEAIMINCREMENT = "Aim Increment";
+BINDING_NAME_VEHICLEAIMUP = "Aim Up";
+BINDING_NAME_VEHICLECAMERAZOOMIN = "Camera Zoom In";
+BINDING_NAME_VEHICLECAMERAZOOMOUT = "Camera Zoom Out";
+BINDING_NAME_VEHICLEEXIT = "Exit Vehicle";
+BINDING_NAME_VEHICLENEXTSEAT = "Next Seat";
+BINDING_NAME_VEHICLEPREVSEAT = "Previous Seat";
+BIND_ENCHANT = "Enchanting this item will bind it to you.";
+BIND_KEY_TO_COMMAND = "Press Key to Bind to Command -> %s";
+BIND_TRADE_TIME_REMAINING = "You may trade this item with players that were also eligible to loot this item for the next %s.";
+BIND_ZONE_DISPLAY = "You are bound in %s.";
+BLIZZARD_COMBAT_LOG_MENU_BOTH = "Show everything involving %s?";
+BLIZZARD_COMBAT_LOG_MENU_EVERYTHING = "Show everything";
+BLIZZARD_COMBAT_LOG_MENU_INCOMING = "What happened to %s?";
+BLIZZARD_COMBAT_LOG_MENU_OUTGOING = "What did %s do?";
+BLIZZARD_COMBAT_LOG_MENU_OUTGOING_ME = "What did %s do to you?";
+BLIZZARD_COMBAT_LOG_MENU_RESET = "Reset";
+BLIZZARD_COMBAT_LOG_MENU_REVERT = "Revert to Last Filter";
+BLIZZARD_COMBAT_LOG_MENU_SAVE = "Save as a new filter";
+BLIZZARD_COMBAT_LOG_MENU_SPELL_HIDE = "Hide messages like this one.";
+BLIZZARD_COMBAT_LOG_MENU_SPELL_LINK = "Link %s to chat.";
+BLIZZARD_COMBAT_LOG_MENU_SPELL_TYPE_HEADER = "Message Types";
+BLOCK = "Block";
+BLOCKED_COMMUNICATION = "Blocked Communication";
+BLOCKED_INVITES = "Blocked Invite";
+BLOCK_CHANCE = "Block Chance";
+BLOCK_COMMUNICATION = "Block Communication";
+BLOCK_INVITES = "Block Invites";
+BLOCK_INVITES_CONFIRMATION = "Are you sure you want to block any further invitations from %s?";
+BLOCK_INVITES_TOOLTIP = "Remove this invite and block further invitations from this player.";
+BLOCK_TRADES = "Block Trades";
+BLOCK_TRAILER = " (%d blocked)";
+BLUE_GEM = "Blue";
+BNET_BROADCAST_SENT_TIME = "(%s ago)";
+BNET_INVITE_SENT_TIME = "Sent %s ago";
+BNET_LAST_ONLINE_TIME = "last online %s ago";
+BNET_REPORT = "Report";
+BNET_REPORT_ABUSE = "Abuse";
+BNET_REPORT_ABUSE_BUTTON = "Report Abuse";
+BNET_REPORT_ABUSE_LABEL = "Report Abuse from:";
+BNET_REPORT_ABUSE_PROMPT = "Please leave a comment to help resolve the type of abuse.";
+BNET_REPORT_CONFIRM_ABUSE = "Are you sure you want to report %s for abuse?";
+BNET_REPORT_CONFIRM_NAME = "Are you sure you want to report %s for an inappropriate name?";
+BNET_REPORT_CONFIRM_SPAM = "Are you sure you want to report %s for spamming?";
+BNET_REPORT_NAME = "Inappropriate Name";
+BNET_REPORT_PLAYER = "Report Player";
+BNET_REPORT_PLAYER_TOOLTIP = "Report this player for spamming, abuse, or an inappropriate name.";
+BNET_REPORT_SENT = "Report sent.";
+BNET_REPORT_SPAM = "Spam";
+BN_BROADCAST_TOOLTIP = "Send a Broadcast message to your Real ID friends.";
+BN_CONVERSATION = "Real ID Conversation";
+BN_INLINE_TOAST_ALERT = "Battle.net Alerts";
+BN_INLINE_TOAST_BROADCAST = "\124TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:2:29:2:29\124t%s: %s";
+BN_INLINE_TOAST_BROADCAST_INFORM = "\124TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:2:29:2:29\124tYour broadcast has been sent.";
+BN_INLINE_TOAST_CONVERSATION = "\124TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:66:95:2:29\124tYou are now in a conversation with %s.";
+BN_INLINE_TOAST_FRIEND_ADDED = "\124TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:98:127:2:29\124t%s is now a Real ID friend.";
+BN_INLINE_TOAST_FRIEND_OFFLINE = "\124TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:2:29:34:61\124t%s has gone offline.";
+BN_INLINE_TOAST_FRIEND_ONLINE = "\124TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:2:29:34:61\124t%s has come online.";
+BN_INLINE_TOAST_FRIEND_PENDING = "\124TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:98:127:2:29\124tYou have %s friend |4request:requests;.";
+BN_INLINE_TOAST_FRIEND_REMOVED = "\124TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:2:29:34:61\124t%s is no longer a Real ID friend.";
+BN_INLINE_TOAST_FRIEND_REQUEST = "\124TInterface\\FriendsFrame\\UI-Toast-ToastIcons.tga:16:16:0:0:128:64:98:127:2:29\124tYou have received a new friend request.";
+BN_TOAST_CONVERSATION = "You have joined";
+BN_TOAST_NEW_INVITE = "You have received a new friend request.";
+BN_TOAST_OFFLINE = "has gone |cffff0000offline|r.";
+BN_TOAST_ONLINE = "has come |cff00ff00online|r.";
+BN_TOAST_PENDING_INVITES = "You have |cff82c5ff%d|r friend |4request:requests;.";
+BN_UNABLE_TO_RESOLVE_NAME = "Unable to whisper '%s'. Battle.net may be unavailable.";
+BN_WHISPER = "Real ID Whisper";
+BONUS_ARENA_POINTS = "Bonus arena points:";
+BONUS_DAMAGE = "Bonus Damage";
+BONUS_DAMAGE_ABBR = "B. Dmg";
+BONUS_HEALING = "Bonus Healing";
+BONUS_HEALING_ABBR = "B. Heal";
+BONUS_HEALING_TOOLTIP = "Increases your healing by up to %d";
+BONUS_HONOR = "Bonus honor:";
+BONUS_TALENTS = "Bonus talents:";
+BOSS = "Boss";
+BOSSES = "Bosses:";
+BOSSES_KILLED = "%d/%d Bosses Killed";
+BOSS_ALIVE = "Alive";
+BOSS_DEAD = "Killed";
+BREATH_LABEL = "Breath";
+BROWSE = "Browse";
+BROWSE_AUCTIONS = "Browse Auctions";
+BROWSE_NO_RESULTS = "No items found";
+BROWSE_SEARCH_TEXT = "Choose search criteria and press \"Search\"";
+BROWSING = "Browsing:";
+BUFFERING = "Buffering";
+BUFFER_DOUBLE = "Double";
+BUFFOPTIONS_LABEL = "Buffs and Debuffs";
+BUFFOPTIONS_SUBTEXT = "These options allow you to control how buffs and debuffs are displayed.";
+BUG_BUTTON = "Bugs & Suggestions";
+BUG_CATEGORY1 = "Character Classes";
+BUG_CATEGORY2 = "Outdoor Zones";
+BUG_CATEGORY3 = "Dungeons";
+BUG_CATEGORY4 = "Cities";
+BUG_CATEGORY5 = "User Interface";
+BUG_CATEGORY6 = "Monsters - Balance/Abilities";
+BUG_CATEGORY7 = "Monsters - Placement";
+BUG_CATEGORY8 = "Quests & Story";
+BUG_CATEGORY9 = "Art";
+BUG_CATEGORY10 = "Sound";
+BUG_CATEGORY11 = "Items";
+BUG_CATEGORY12 = "Tradeskills";
+BUG_CATEGORY13 = "Miscellaneous";
+BUG_CATEGORY14 = "Player vs. Player";
+BUG_CATEGORY15 = "Language Translation";
+BUG_CATEGORY_CHOOSE = "--> Please Choose a Category";
+BUG_CATEGORY_ERROR = "You must choose a category to submit your bug/suggestion.";
+BUG_SUBMITTED = "Bug submitted";
+BUG_SUBMIT_FAILED = "Bug submission failed";
+BUILDING_DAMAGE = "Siege";
+BUILDING_DAMAGE_COMBATLOG_TOOLTIP = "Show messages when a spell or ability deals damage to a destructible building.";
+BUILDING_HEAL = "Repairs";
+BUILDING_HEAL_COMBATLOG_TOOLTIP = "Show messages when a spell or ability repairs a building.";
+BUTTON_LAG_AUCTIONHOUSE = "Auction House";
+BUTTON_LAG_AUCTIONHOUSE_NEWBIE = "There is a long delay when posting, buying, searching or paging through auctions.";
+BUTTON_LAG_AUCTIONHOUSE_TOOLTIP = "Auction House Lag";
+BUTTON_LAG_CHAT = "Chat";
+BUTTON_LAG_CHAT_NEWBIE = "It takes a long time for your friends to see messages you send them or for you to see messages they send you.";
+BUTTON_LAG_CHAT_TOOLTIP = "Chat Message Lag";
+BUTTON_LAG_LOOT = "Loot";
+BUTTON_LAG_LOOT_NEWBIE = "It takes a long time for loot that you click on or that someone assigns to you to show up in your inventory. It may also take a long time to trade items with another player.";
+BUTTON_LAG_LOOT_TOOLTIP = "Loot Lag";
+BUTTON_LAG_MAIL = "Mail";
+BUTTON_LAG_MAIL_NEWBIE = "It takes a long time to open mail or retrieve items from mail.";
+BUTTON_LAG_MAIL_TOOLTIP = "In Game Mail Lag";
+BUTTON_LAG_MOVEMENT = "Movement";
+BUTTON_LAG_MOVEMENT_NEWBIE = "Creatures and players may pop or teleport from place to place. They may also run in place. You may notice that you try to attack creatures that aren't really where you think they are.";
+BUTTON_LAG_MOVEMENT_TOOLTIP = "Movement Lag";
+BUTTON_LAG_SPELL = "Spells and Abilities";
+BUTTON_LAG_SPELL_NEWBIE = "It takes a long time after you try and use a spell or ability before the spell or ability actually occurs. Abilities may behave as if they are on cooldown even though they are not.";
+BUTTON_LAG_SPELL_TOOLTIP = "Spell and Ability Lag";
+BUYBACK = "Buyback";
+BUYBACK_THIS_ITEM = "Buy Back This Item";
+BUYOUT = "Buyout";
+BUYOUT_AUCTION_CONFIRMATION = "Buyout auction for:";
+BUYOUT_COST = "Buyout";
+BUYOUT_PRICE = "Buyout Price";
+BUY_GUILDBANK_TAB = "Buy New Guild Bank Tab";
+BY_SOURCE = "By Source";
+BY_SOURCE_COMBATLOG_TOOLTIP = "Line color based on caster.";
+BY_TARGET = "By Target";
+BY_TARGET_COMBATLOG_TOOLTIP = "Line color based on target.";
+CALENDAR_ACCEPT_INVITATION = "Accept Invitation";
+CALENDAR_ANNOUNCEMENT_CREATEDBY_PLAYER = "Created by %s";
+CALENDAR_ANNOUNCEMENT_CREATEDBY_YOURSELF = "This is your announcement";
+CALENDAR_AUTO_APPROVE = "Auto Approve Members";
+CALENDAR_COPY_EVENT = "Copy";
+CALENDAR_CREATE = "Create";
+CALENDAR_CREATE_ANNOUNCEMENT = "Create Announcement";
+CALENDAR_CREATE_ARENATEAM_EVENT = "Create Arena Team Event";
+CALENDAR_CREATE_EVENT = "Create Event";
+CALENDAR_CREATE_GUILD_ANNOUNCEMENT = "Create Guild Announcement";
+CALENDAR_CREATE_GUILD_EVENT = "Create Guild Event";
+CALENDAR_DECLINE_INVITATION = "Decline Invitation";
+CALENDAR_DELETE_ANNOUNCEMENT_CONFIRM = "Are you sure you want to delete this announcement?";
+CALENDAR_DELETE_EVENT = "Delete";
+CALENDAR_DELETE_EVENT_CONFIRM = "Are you sure you want to delete this event?";
+CALENDAR_DELETE_GUILD_EVENT_CONFIRM = "Are you sure you want to delete this guild event?";
+CALENDAR_EDIT_ANNOUNCEMENT = "Edit Announcement";
+CALENDAR_EDIT_EVENT = "Edit Event";
+CALENDAR_EDIT_GUILD_EVENT = "Edit Guild Event";
+CALENDAR_ERROR = "%s";
+CALENDAR_ERROR_ALREADY_INVITED_TO_EVENT_S = "%s has already been invited.";
+CALENDAR_ERROR_ARENA_EVENTS_EXCEEDED = "Your arena team has reached the limit of created events.";
+CALENDAR_ERROR_CREATEDATE_AFTER_MAX = "You cannot create events after %2$s %4$d.";
+CALENDAR_ERROR_CREATEDATE_BEFORE_TODAY = "You cannot create events before today.";
+CALENDAR_ERROR_DELETE_CREATOR_FAILED = "You cannot remove the creator of the event.";
+CALENDAR_ERROR_EVENTS_EXCEEDED = "You have reached your limit of %d |4created event:created events.";
+CALENDAR_ERROR_EVENT_INVALID = "Event not found.";
+CALENDAR_ERROR_EVENT_LOCKED = "This event is locked.";
+CALENDAR_ERROR_EVENT_PASSED = "This event has already occured.";
+CALENDAR_ERROR_EVENT_THROTTLED = "The speed that events can be created is limited, please wait to create another event.";
+CALENDAR_ERROR_EVENT_TIME_PASSED = "The time for this event has already passed.";
+CALENDAR_ERROR_EVENT_WRONG_SERVER = "You cannot create events on this server.";
+CALENDAR_ERROR_GUILD_EVENTS_EXCEEDED = "Your guild has reached the limit of %d |4created event:created events.";
+CALENDAR_ERROR_IGNORED = "%s is ignoring you.";
+CALENDAR_ERROR_INTERNAL = "Internal Calendar Error.";
+CALENDAR_ERROR_INVALID_DATE = "Enter a valid date.";
+CALENDAR_ERROR_INVALID_SIGNUP = "You cannot sign up to this event.";
+CALENDAR_ERROR_INVALID_TIME = "Enter a valid time.";
+CALENDAR_ERROR_INVITES_DISABLED = "You cannot invite players to this event.";
+CALENDAR_ERROR_INVITES_EXCEEDED = "You cannot invite more than %d |4player:players; to this event.";
+CALENDAR_ERROR_INVITE_THROTTLED = "The number of invites that can be sent is limited, please wait to send another invite.";
+CALENDAR_ERROR_INVITE_WRONG_SERVER = "You cannot invite players from another server.";
+CALENDAR_ERROR_NEEDS_TITLE = "Enter a title.";
+CALENDAR_ERROR_NOT_ALLIED = "You cannot invite players from the opposing alliance.";
+CALENDAR_ERROR_NOT_INVITED = "You are not invited to this event.";
+CALENDAR_ERROR_NO_GUILD_INVITES = "Invites to guild members are not allowed.";
+CALENDAR_ERROR_NO_INVITE = "Invite not found.";
+CALENDAR_ERROR_NO_MODERATOR = "Invites to sign up events are not allowed to be moderators.";
+CALENDAR_ERROR_OTHER_INVITES_EXCEEDED = "%s already has the maximum number of events. They need to remove one to be invited to another.";
+CALENDAR_ERROR_PERMISSIONS = "You don't have permission to do that.";
+CALENDAR_ERROR_RESTRICTED_LEVEL = "You need to have at least a level 20 character on your account.";
+CALENDAR_ERROR_SELF_INVITES_EXCEEDED = "Maximum number of invites reached. Remove an old event to add an additional one.";
+CALENDAR_EVENTNAME_FORMAT_END = "%s Ends";
+CALENDAR_EVENTNAME_FORMAT_RAID_LOCKOUT = "%s Unlocks";
+CALENDAR_EVENTNAME_FORMAT_RAID_RESET = "%s Resets";
+CALENDAR_EVENTNAME_FORMAT_START = "%s Begins";
+CALENDAR_EVENT_ALARM_MESSAGE = "%s begins in 15 minutes.";
+CALENDAR_EVENT_CREATORNAME = "Created by %s";
+CALENDAR_EVENT_DESCRIPTION = "Description";
+CALENDAR_EVENT_INVITEDBY_PLAYER = "Invited by %s";
+CALENDAR_EVENT_INVITEDBY_YOURSELF = "This is your event";
+CALENDAR_EVENT_NAME = "Name";
+CALENDAR_EVENT_PICKER_TITLE = "Select an Event";
+CALENDAR_EVENT_REMOVED_MAIL_BODY = "%s cancelled %s. (%s)";
+CALENDAR_EVENT_REMOVED_MAIL_SUBJECT = "%s cancelled.";
+CALENDAR_FILTERS = "Filters";
+CALENDAR_FILTER_BATTLEGROUND = "Battleground Call to Arms";
+CALENDAR_FILTER_DARKMOON = "Darkmoon Faire";
+CALENDAR_FILTER_RAID_LOCKOUTS = "Active Raid Lockouts";
+CALENDAR_FILTER_RAID_RESETS = "Raid Resets";
+CALENDAR_FILTER_WEEKLY_HOLIDAYS = "Weekly Holidays";
+CALENDAR_GUILDEVENT_INVITEDBY_YOURSELF = "This is your guild event";
+CALENDAR_INVITELIST_CLEARMODERATOR = "Remove Moderator Status";
+CALENDAR_INVITELIST_CREATORNAME = "%s (Creator)";
+CALENDAR_INVITELIST_INVITETORAID = "Invite to Party or Raid";
+CALENDAR_INVITELIST_MODERATORNAME = "%s (Moderator)";
+CALENDAR_INVITELIST_SETINVITESTATUS = "Set Invite Status";
+CALENDAR_INVITELIST_SETMODERATOR = "Grant Moderator Status";
+CALENDAR_INVITE_ALL = "Invite All";
+CALENDAR_INVITE_CONFIRMED = "Invite Confirmed/Accepted";
+CALENDAR_INVITE_LABEL = "Who do you want to invite?";
+CALENDAR_INVITE_MEMBERS = "Invite Members";
+CALENDAR_INVITE_PLAYER = "Invite Player";
+CALENDAR_INVITE_REMOVED_MAIL_BODY = "%s has removed you from %s. (%s)";
+CALENDAR_INVITE_REMOVED_MAIL_SUBJECT = "You have been removed from %s.";
+CALENDAR_LOCK_EVENT = "Lock Event";
+CALENDAR_MASSINVITE_ARENA_HELP = "Invite arena team members:";
+CALENDAR_MASSINVITE_GUILD_HELP = "Invite guild members who meet the following conditions:";
+CALENDAR_MASSINVITE_GUILD_MINRANK = "Minimum Rank";
+CALENDAR_MASS_INVITE = "Mass Invite";
+CALENDAR_NOT_SIGNEDUP_FOR_GUILDEVENT = "Not signed up";
+CALENDAR_PASTE_EVENT = "Paste";
+CALENDAR_PLAYER_NAME = "Player Name";
+CALENDAR_RAID_LOCKOUT_DESCRIPTION = "Your %1$s instance unlocks at %2$s.";
+CALENDAR_RAID_RESET_DESCRIPTION = "%1$s resets at %2$s.";
+CALENDAR_REMOVE_INVITATION = "Remove Invitation";
+CALENDAR_REMOVE_SIGNUP = "Remove from Guild Event";
+CALENDAR_REPEAT_BIWEEKLY = "Biweekly";
+CALENDAR_REPEAT_MONTHLY = "Monthly";
+CALENDAR_REPEAT_NEVER = "Never";
+CALENDAR_REPEAT_WEEKLY = "Weekly";
+CALENDAR_SET_DESCRIPTION_LABEL = "Set the calendar event description:";
+CALENDAR_SIGNEDUP_FOR_GUILDEVENT_WITH_STATUS = "Signed up (%s)";
+CALENDAR_SIGNUP = "Sign Up ";
+CALENDAR_SIGNUP_FOR_GUILDEVENT = "Sign Up for Guild Event";
+CALENDAR_STATUS_ACCEPTED = "Accepted";
+CALENDAR_STATUS_CONFIRMED = "Confirmed";
+CALENDAR_STATUS_DECLINED = "Declined";
+CALENDAR_STATUS_INVITED = "Invited";
+CALENDAR_STATUS_NOT_SIGNEDUP = "Not Signed Up";
+CALENDAR_STATUS_OUT = "Out";
+CALENDAR_STATUS_SIGNEDUP = "Signed Up";
+CALENDAR_STATUS_STANDBY = "Standby";
+CALENDAR_STATUS_TENTATIVE = "Tentative";
+CALENDAR_TENTATIVE_INVITATION = "Tentative Invitation";
+CALENDAR_TEXTURE_PICKER_TITLE_DUNGEON = "Select a Dungeon";
+CALENDAR_TEXTURE_PICKER_TITLE_RAID = "Select a Raid";
+CALENDAR_TOOLTIP_AUTOAPPROVE = "If checked, invitees whom respond to this event will have their status approved automatically; otherwise, you will have to approve them manually.";
+CALENDAR_TOOLTIP_AVAILABLEBUTTON = "Sets your status to Accepted for this event.";
+CALENDAR_TOOLTIP_DECLINEBUTTON = "Sets your status to Declined for this event.";
+CALENDAR_TOOLTIP_INVITEMEMBERS_BUTTON_PARTY = "Invite Accepted and Confirmed players to your Party.";
+CALENDAR_TOOLTIP_INVITEMEMBERS_BUTTON_RAID = "Invite Accepted and Confirmed players to your Raid.";
+CALENDAR_TOOLTIP_INVITE_RESPONDED = "Responded on:";
+CALENDAR_TOOLTIP_INVITE_TOTALS = "Confirmed/Accepted/Signed Up Invites";
+CALENDAR_TOOLTIP_LOCKEVENT = "If checked, invitees will be unable to respond to this event.";
+CALENDAR_TOOLTIP_MASSINVITE = "A Mass Invite will populate your invite list based on a filter.|n|nNOTE: A Mass Invite clears your current invite list.";
+CALENDAR_TOOLTIP_REMOVEBUTTON = "Remove this event from your Calendar.";
+CALENDAR_TOOLTIP_REMOVESIGNUPBUTTON = "Remove yourself from this event.";
+CALENDAR_TOOLTIP_SIGNUPBUTTON = "Add yourself to this event.";
+CALENDAR_TOOLTIP_TENTATIVEBUTTON = "Sets your status to Tentative for this event.";
+CALENDAR_TYPE_DUNGEON = "Dungeon";
+CALENDAR_TYPE_MEETING = "Meeting";
+CALENDAR_TYPE_OTHER = "Other";
+CALENDAR_TYPE_PVP = "PvP";
+CALENDAR_TYPE_RAID = "Raid";
+CALENDAR_UPDATE = "Update";
+CALENDAR_VIEW_ANNOUNCEMENT = "View Announcement";
+CALENDAR_VIEW_EVENT = "View Event";
+CALENDAR_VIEW_EVENTTITLE_LOCKED = "|cff7f7f7f%s|r |cffffd200(Locked)|r";
+CALENDAR_VIEW_EVENTTYPE = "%1$s - %2$s";
+CALENDAR_VIEW_EVENT_REMOVE = "Remove";
+CALENDAR_VIEW_EVENT_SETSTATUS = "Set your status:";
+CALENDAR_VIEW_EVENT_TENTATIVE = "Tentative";
+CALENDAR_VIEW_GUILD_EVENT = "View Guild Event";
+CALIBRATION_TEXT = "Each of the 21 gray bars below should be distinct from one another. Adjust the gamma slider until you can distinguish between each shade of gray. If using the slider alone is not enough to achieve this, adjust your monitor's brightness and contrast settings until satisfied.";
+CAMERA_ALWAYS = "Always adjust camera";
+CAMERA_FOLLOWING_STYLE = "Camera Following Style";
+CAMERA_LABEL = "Camera";
+CAMERA_LOCKED = "Locked";
+CAMERA_MODE = "Detach Camera";
+CAMERA_NEVER = "Never adjust camera";
+CAMERA_SMART = "Only horizontal when moving";
+CAMERA_SMARTER = "Only when moving";
+CAMERA_SUBTEXT = "These options allow you to modify the camera's behavior inside the game.";
+CAMP_NOW = "Logout now";
+CAMP_TIMER = "%d %s until logout";
+CANCEL = "Cancel";
+CANCEL_AUCTION = "Cancel Auction";
+CANCEL_AUCTION_CONFIRMATION = "You will lose your initial deposit by canceling this auction.";
+CANCEL_AUCTION_CONFIRMATION_MONEY = "Canceling this auction will cost you your deposit and:";
+CANNOT_COOPERATE_LABEL = "*";
+CANT_AFFORD_ITEM = "You can't afford that.";
+CANT_USE_ITEM = "You can't use that item.";
+CAN_BIND_PTT = "Press Push-to-Talk button";
+CAPSLOCK_KEY_TEXT = "Capslock";
+CASH_ON_DELIVERY = "C.O.D.";
+CAST_WHILE_MOVING = "%s Failed: Cannot cast while moving.";
+CATEGORIES = "Categories";
+CATEGORY = "Category";
+CHANCE_TO_BLOCK = "%.2f%% chance to block";
+CHANCE_TO_CRIT = "%.2f%% chance to crit";
+CHANCE_TO_DODGE = "%.2f%% chance to dodge";
+CHANCE_TO_PARRY = "%.2f%% chance to parry";
+CHANGE_INSTANCE = "Change Instance";
+CHANGE_MACRO_NAME_ICON = "Change Name/Icon";
+CHANGE_OPACITY = "Change Opacity";
+CHANNEL = "Channel";
+CHANNELING = "Channeling";
+CHANNELPULLOUT_OPACITY_LABEL = "Change Opacity";
+CHANNELPULLOUT_OPTIONS_LABEL = "Channel Pullout Options";
+CHANNELS = "Channels";
+CHANNEL_CATEGORY_CUSTOM = "Custom";
+CHANNEL_CATEGORY_GROUP = "Group";
+CHANNEL_CATEGORY_WORLD = "World";
+CHANNEL_CHANNEL_NAME = "Channel Name";
+CHANNEL_INVITE = "Who would you like to invite to %s?";
+CHANNEL_JOIN_CHANNEL = "Join a Channel";
+CHANNEL_NEW_CHANNEL = "New Channel";
+CHANNEL_PASSWORD = "Enter a password for %s.";
+CHANNEL_ROSTER = "Channel Roster";
+CHARACTER = "Character";
+CHARACTER_BUTTON = "Character Info";
+CHARACTER_FRIEND = "World of Warcraft";
+CHARACTER_FRIEND_INFO = "This is a character you have enjoyed playing with on your realm, You can party and chat with this character.";
+CHARACTER_FRIEND_LABEL = "Enter character's name";
+CHARACTER_INFO = "Character Info";
+CHARACTER_KEY_BINDINGS = "Key Bindings for %s";
+CHARACTER_POINTS2_COLON = "Skill Points:";
+CHARACTER_POINTS_CHANGED = "Character Points Changed";
+CHARACTER_SHADOWS = "Character Shadows";
+CHARACTER_SPECIFIC_KEYBINDINGS = "Character Specific Key Bindings";
+CHARACTER_SPECIFIC_KEYBINDING_TOOLTIP = "Click this to toggle between general key bindings and key bindings specific to this character.";
+CHARACTER_SPECIFIC_MACROS = "%s Specific Macros";
+CHAT = "Chat";
+CHATCONFIG_HEADER = "%s Config";
+CHATLOGDISABLED = "Chat logging disabled.";
+CHATLOGENABLED = "Chat being logged to Logs\\WoWChatLog.txt";
+CHAT_AFK_GET = "%s is Away:\32";
+CHAT_ANNOUNCE = "Announce";
+CHAT_ANNOUNCEMENTS_OFF_NOTICE = "|Hchannel:%d|h[%s]|h Channel announcements disabled by %s.";
+CHAT_ANNOUNCEMENTS_OFF_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Channel announcements disabled by %s.";
+CHAT_ANNOUNCEMENTS_ON_NOTICE = "|Hchannel:%d|h[%s]|h Channel announcements enabled by %s.";
+CHAT_ANNOUNCEMENTS_ON_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Channel announcements enabled by %s.";
+CHAT_AUTO_JOIN = "Auto Join";
+CHAT_BAN = "Ban";
+CHAT_BANNED_NOTICE = "[%s] You are banned from that channel.";
+CHAT_BATTLEGROUND_GET = "|Hchannel:BATTLEGROUND|h[Battleground]|h %s:\32";
+CHAT_BATTLEGROUND_LEADER_GET = "|Hchannel:BATTLEGROUND|h[Battleground Leader]|h %s:\32";
+CHAT_BATTLEGROUND_SEND = "Battleground:\32";
+CHAT_BN_CONVERSATION_GET = "%s:\32";
+CHAT_BN_CONVERSATION_GET_LINK = "|Hchannel:BN_CONVERSATION:%d|h[%s. Conversation]|h";
+CHAT_BN_CONVERSATION_LIST = "%s %s";
+CHAT_BN_CONVERSATION_SEND = "[%d. Conversation]:";
+CHAT_BN_WHISPER_GET = "%s whispers:\32";
+CHAT_BN_WHISPER_INFORM_GET = "To %s:\32";
+CHAT_BN_WHISPER_SEND = "Tell %s:\32";
+CHAT_BUBBLES_TEXT = "Chat Bubbles";
+CHAT_CHANNELS = "Chat Channels";
+CHAT_CHANNEL_GET = "%s:\32";
+CHAT_CHANNEL_JOIN_GET = "%s joined channel.";
+CHAT_CHANNEL_LEAVE_GET = "%s left channel.";
+CHAT_CHANNEL_LIST_GET = "|Hchannel:CHANNEL:%d|h[%s]|h\32";
+CHAT_CHANNEL_OWNER_NOTICE = "|Hchannel:%d|h[%s]|h Channel owner is %s.";
+CHAT_CHANNEL_OWNER_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Channel owner is %s.";
+CHAT_CHANNEL_SEND = "[%d. %s]:\32";
+CHAT_COMBAT_MISC_INFO_GET = "";
+CHAT_CONFIGURATION = "Settings";
+CHAT_CONVERSATION_CONVERSATION_CONVERTED_TO_WHISPER_NOTICE = "%s has been converted to a whisper with %s.";
+CHAT_CONVERSATION_MEMBER_JOINED_NOTICE = "%s: %s has joined the conversation.";
+CHAT_CONVERSATION_MEMBER_LEFT_NOTICE = "%s: %s left the conversation.";
+CHAT_CONVERSATION_YOU_JOINED_CONVERSATION_NOTICE = "You joined %s.";
+CHAT_CONVERSATION_YOU_LEFT_CONVERSATION_NOTICE = "You left %s.";
+CHAT_DEFAULT = "Default";
+CHAT_DEFAULTS = "Chat Defaults";
+CHAT_DEMOTE = "Demote";
+CHAT_DND_GET = "%s does not wish to be disturbed:\32";
+CHAT_EMOTE_GET = "%s\32";
+CHAT_EMOTE_SEND = "%s\32";
+CHAT_EMOTE_UNKNOWN = "makes some strange gestures.";
+CHAT_FILTERED = "Unable to send chat to %s because your message contained reserved words.";
+CHAT_FLAG_AFK = "";
+CHAT_FLAG_DND = "";
+CHAT_FLAG_GM = "";
+CHAT_GUILD_DEMOTE_SEND = "Demote";
+CHAT_GUILD_GET = "|Hchannel:GUILD|h[Guild]|h %s:\32";
+CHAT_GUILD_INVITE_SEND = "Invite to guild: ";
+CHAT_GUILD_LEADER_SEND = "Set guild leader: ";
+CHAT_GUILD_MOTD_SEND = "Guild MOTD: ";
+CHAT_GUILD_PROMOTE_SEND = "Promote ";
+CHAT_GUILD_SEND = "Guild:\32";
+CHAT_GUILD_UNINVITE_SEND = "Remove from guild: ";
+CHAT_HELP_TEXT_LINE1 = "Chat commands:";
+CHAT_HELP_TEXT_LINE2 = "/#, /c, /csay - Send text to channel # (E.G. /1 Hi!)";
+CHAT_HELP_TEXT_LINE3 = "/chat, /chathelp - This help";
+CHAT_HELP_TEXT_LINE4 = "/join, /channel, /chan - Join a channel";
+CHAT_HELP_TEXT_LINE5 = "/leave, /chatleave, /chatexit [channel] - Leave a channel (or all channels)";
+CHAT_HELP_TEXT_LINE6 = "/chatlist, /chatwho, /chatinfo [channel] - List channels, or channel members";
+CHAT_HELP_TEXT_LINE7 = "/password, /pass - Change password";
+CHAT_HELP_TEXT_LINE8 = "/owner [player] - Display or change channel owner";
+CHAT_HELP_TEXT_LINE9 = "/mod, /moderator, /unmod, /unmoderator - change a player's moderator status";
+CHAT_HELP_TEXT_LINE10 = "/mute, /squelch, /unvoice, /unmute, /unsquelch, /voice - change a player's permission";
+CHAT_HELP_TEXT_LINE11 = "/cinvite, /chatinvite - invite a player to a channel";
+CHAT_HELP_TEXT_LINE12 = "/ckick - kick a player off a channel";
+CHAT_HELP_TEXT_LINE13 = "/ban, /unban - ban/unban a player from a channel";
+CHAT_HELP_TEXT_LINE14 = "/announce, /ann - toggle join/leave announcements on a channel";
+CHAT_HELP_TEXT_LINE15 = "/moderate - toggle moderation on a channel";
+CHAT_HELP_TEXT_LINE16 = "/away, /busy - Set your Away or Busy flags";
+CHAT_IGNORED = "%s is ignoring you.";
+CHAT_INVALID_NAME_NOTICE = "Invalid channel name";
+CHAT_INVITE_NOTICE = "%2$s has invited you to join the channel '%1$s'.";
+CHAT_INVITE_NOTICE_POPUP = "%2$s has invited you to join the channel '%1$s'.";
+CHAT_INVITE_SEND = "Invite ";
+CHAT_INVITE_WRONG_FACTION_NOTICE = "Target is in the wrong alliance for %s.";
+CHAT_JOIN = "Join";
+CHAT_JOIN_HELP = "Type /join [password] to create a channel or join an existing one.";
+CHAT_KICK = "Kick";
+CHAT_LABEL = "Chat";
+CHAT_LEAVE = "Leave";
+CHAT_LOCKED_TEXT = "Lock Chat Settings";
+CHAT_MODERATE = "Moderate";
+CHAT_MODERATION_OFF_NOTICE = "|Hchannel:%d|h[%s]|h Channel moderation disabled by %s.";
+CHAT_MODERATION_OFF_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Channel moderation disabled by %s.";
+CHAT_MODERATION_ON_NOTICE = "|Hchannel:%d|h[%s]|h Channel moderation enabled by %s.";
+CHAT_MODERATION_ON_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Channel moderation enabled by %s.";
+CHAT_MONSTER_EMOTE_GET = "";
+CHAT_MONSTER_PARTY_GET = "|Hchannel:PARTY|h[Party]|h %s:\32";
+CHAT_MONSTER_SAY_GET = "%s says:\32";
+CHAT_MONSTER_WHISPER_GET = "%s whispers:\32";
+CHAT_MONSTER_YELL_GET = "%s yells:\32";
+CHAT_MOUSE_WHEEL_SCROLL = "Enable Mouse Wheel Scrolling";
+CHAT_MSG_ACHIEVEMENT = "Achievement Announce";
+CHAT_MSG_AFK = "Away";
+CHAT_MSG_BATTLEGROUND = "Battleground";
+CHAT_MSG_BATTLEGROUND_LEADER = "Battleground Leader";
+CHAT_MSG_BG_SYSTEM_ALLIANCE = "Alliance zone message";
+CHAT_MSG_BG_SYSTEM_HORDE = "Horde zone message";
+CHAT_MSG_BG_SYSTEM_NEUTRAL = "Neutral zone message";
+CHAT_MSG_BN_CONVERSATION = "Real ID Conversation";
+CHAT_MSG_BN_WHISPER = "Real ID Whisper";
+CHAT_MSG_CHANNEL_LIST = "Channel List";
+CHAT_MSG_COMBAT_HONOR_GAIN = "Honor Gain";
+CHAT_MSG_EMOTE = "Emote";
+CHAT_MSG_FILTERED = "Chat Filtered Message";
+CHAT_MSG_GUILD = "Guild";
+CHAT_MSG_GUILD_ACHIEVEMENT = "Guild Announce";
+CHAT_MSG_LOOT = "Item Loot";
+CHAT_MSG_MONEY = "Money Loot";
+CHAT_MSG_MONSTER_EMOTE = "Creature Emote";
+CHAT_MSG_MONSTER_PARTY = "Creature Party";
+CHAT_MSG_MONSTER_SAY = "Creature Say";
+CHAT_MSG_MONSTER_WHISPER = "Creature Whisper";
+CHAT_MSG_MONSTER_YELL = "Creature Yell";
+CHAT_MSG_OFFICER = "Officer";
+CHAT_MSG_PARTY = "Party";
+CHAT_MSG_PARTY_LEADER = "Party Leader";
+CHAT_MSG_RAID = "Raid";
+CHAT_MSG_RAID_BOSS_EMOTE = "Raid Boss Emote";
+CHAT_MSG_RAID_LEADER = "Raid Leader";
+CHAT_MSG_RAID_WARNING = "Raid Warning";
+CHAT_MSG_RESTRICTED = "Restricted";
+CHAT_MSG_SAY = "Say";
+CHAT_MSG_SKILL = "Skill";
+CHAT_MSG_SYSTEM = "System";
+CHAT_MSG_TEXT_EMOTE = "Text Emote";
+CHAT_MSG_WHISPER = "Incoming Whisper";
+CHAT_MSG_WHISPER_INFORM = "Whisper";
+CHAT_MSG_YELL = "Yell";
+CHAT_MUTED_NOTICE = "|Hchannel:%d|h[%s]|h You do not have permission to speak.";
+CHAT_MUTED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h You do not have permission to speak.";
+CHAT_NAME_TEMPLATE = "Chat %d";
+CHAT_NOT_IN_AREA_NOTICE = "[%s] You are not in the correct area for this channel.";
+CHAT_NOT_MEMBER_NOTICE = "Not on channel %s.";
+CHAT_NOT_MODERATED_NOTICE = "%s is not moderated";
+CHAT_NOT_MODERATOR_NOTICE = "Not a moderator of |Hchannel:%d|h[%s]|h.";
+CHAT_NOT_MODERATOR_NOTICE_BN = "Not a moderator of |Hchannel:CHANNEL:%d|h[%s]|h.";
+CHAT_NOT_OWNER_NOTICE = "|Hchannel:%d|h[%s]|h You are not the channel owner.";
+CHAT_NOT_OWNER_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h You are not the channel owner.";
+CHAT_OFFICER_GET = "|Hchannel:OFFICER|h[Officer]|h %s:\32";
+CHAT_OFFICER_SEND = "Officer:\32";
+CHAT_OPTIONS_LABEL = "Chat Options";
+CHAT_OVERFLOW_LABEL = "List All Tabs";
+CHAT_OWNER = "Make Owner";
+CHAT_OWNER_CHANGED_NOTICE = "|Hchannel:%d|h[%s]|h Owner changed to %s.";
+CHAT_OWNER_CHANGED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Owner changed to %s.";
+CHAT_PARTY_GET = "|Hchannel:PARTY|h[Party]|h %s:\32";
+CHAT_PARTY_GUIDE_GET = "|Hchannel:PARTY|h[Dungeon Guide]|h %s:\32";
+CHAT_PARTY_LEADER_GET = "|Hchannel:PARTY|h[Party Leader]|h %s:\32";
+CHAT_PARTY_SEND = "Party:\32";
+CHAT_PASSWORD = "Set Password";
+CHAT_PASSWORD_CHANGED_NOTICE = "|Hchannel:%d|h[%s]|h Password changed by %s.";
+CHAT_PASSWORD_CHANGED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Password changed by %s.";
+CHAT_PASSWORD_NOTICE_POPUP = "Please enter a password for '%1$s'.";
+CHAT_PLAYER_ALREADY_MEMBER_NOTICE = "|Hchannel:%d|h[%s]|h Player %s is already on the channel.";
+CHAT_PLAYER_ALREADY_MEMBER_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Player %s is already on the channel.";
+CHAT_PLAYER_BANNED_NOTICE = "|Hchannel:%d|h[%s]|h Player %s banned by %s.";
+CHAT_PLAYER_BANNED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Player %s banned by %s.";
+CHAT_PLAYER_INVITED_NOTICE = "|Hchannel:%d|h[%s]|h You invited %s to join the channel";
+CHAT_PLAYER_INVITED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h You invited %s to join the channel.";
+CHAT_PLAYER_INVITE_BANNED_NOTICE = "|Hchannel:%d|h[%s]|h %s has been banned.";
+CHAT_PLAYER_INVITE_BANNED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h %s has been banned.";
+CHAT_PLAYER_KICKED_NOTICE = "|Hchannel:%d|h[%s]|h Player %s kicked by %s.";
+CHAT_PLAYER_KICKED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Player %s kicked by %s.";
+CHAT_PLAYER_NOT_BANNED_NOTICE = "|Hchannel:%d|h[%s]|h Player %s is not banned.";
+CHAT_PLAYER_NOT_BANNED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Player %s is not banned.";
+CHAT_PLAYER_NOT_FOUND_NOTICE = "|Hchannel:%d|h[%s]|h Player %s was not found.";
+CHAT_PLAYER_NOT_FOUND_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Player %s was not found.";
+CHAT_PLAYER_UNBANNED_NOTICE = "|Hchannel:%d|h[%s]|h Player %s unbanned by %s.";
+CHAT_PLAYER_UNBANNED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Player %s unbanned by %s.";
+CHAT_PROMOTE = "Promote";
+CHAT_PROMOTE_SEND = "Promote ";
+CHAT_RAID_BOSS_EMOTE_GET = "";
+CHAT_RAID_BOSS_WHISPER_GET = "";
+CHAT_RAID_GET = "|Hchannel:RAID|h[Raid]|h %s:\32";
+CHAT_RAID_LEADER_GET = "|Hchannel:RAID|h[Raid Leader]|h %s:\32";
+CHAT_RAID_SEND = "Raid:\32";
+CHAT_RAID_WARNING_GET = "[Raid Warning] %s:\32";
+CHAT_RAID_WARNING_SEND = "Raid Warning:\32";
+CHAT_RESTRICTED = "A trial account may only send whispers to characters that have you on their friends list.";
+CHAT_SAY_GET = "%s says:\32";
+CHAT_SAY_SEND = "Say:\32";
+CHAT_SAY_UNKNOWN = "says something unintelligible.";
+CHAT_SET_MODERATOR_NOTICE = "|Hchannel:%d|h[%s]|h Moderation privileges given to %s.";
+CHAT_SET_MODERATOR_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Moderation privileges given to %s.";
+CHAT_SET_SPEAK_NOTICE = "|Hchannel:%d|h[%s]|h Voice permission given to %s.";
+CHAT_SET_SPEAK_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Voice permission given to %s.";
+CHAT_SET_VOICE_NOTICE = "|Hchannel:%d|h[%s]|h Chat permission given to %s.";
+CHAT_SET_VOICE_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Chat permission given to %s.";
+CHAT_SILENCE = "Silence in Channel";
+CHAT_STYLE = "Chat Style|TInterface\\OptionsFrame\\UI-OptionsFrame-NewFeatureIcon:0:0:0:-1|t";
+CHAT_SUSPENDED_NOTICE = "Left Channel: |Hchannel:%d|h[%s]|h ";
+CHAT_SUSPENDED_NOTICE_BN = "Left Channel: |Hchannel:CHANNEL:%d|h[%s]|h";
+CHAT_THROTTLED_NOTICE = "|Hchannel:%d|h[%s]|h The number of messages that can be sent to this channel is limited, please wait to send another message.";
+CHAT_THROTTLED_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h The number of messages that can be sent to this channel is limited, please wait to send another message.";
+CHAT_UNINVITE_SEND = "Uninvite ";
+CHAT_UNSET_MODERATOR_NOTICE = "|Hchannel:%d|h[%s]|h Moderation privileges removed from %s.";
+CHAT_UNSET_MODERATOR_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Moderation privileges removed from %s.";
+CHAT_UNSET_SPEAK_NOTICE = "|Hchannel:%d|h[%s]|h %s lost voice permission.";
+CHAT_UNSET_SPEAK_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h %s lost voice permission.";
+CHAT_UNSET_VOICE_NOTICE = "|Hchannel:%d|h[%s]|h %s lost chat permission.";
+CHAT_UNSET_VOICE_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h %s lost chat permission.";
+CHAT_UNSILENCE = "Unsilence in Channel";
+CHAT_VOICE = "Voice Chat";
+CHAT_VOICE_OFF = "Disable Voice";
+CHAT_VOICE_OFF_NOTICE = "|Hchannel:%d|h[%s]|h Channel voice disabled by %s.";
+CHAT_VOICE_OFF_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Channel voice disabled by %s.";
+CHAT_VOICE_ON = "Enable Voice";
+CHAT_VOICE_ON_NOTICE = "|Hchannel:%d|h[%s]|h Channel voice enabled by %s.";
+CHAT_VOICE_ON_NOTICE_BN = "|Hchannel:CHANNEL:%d|h[%s]|h Channel voice enabled by %s.";
+CHAT_WHISPER_GET = "%s whispers:\32";
+CHAT_WHISPER_INFORM_GET = "To %s:\32";
+CHAT_WHISPER_SEND = "Tell %s:\32";
+CHAT_WHOLE_WINDOW_CLICKABLE = "Click to Focus";
+CHAT_WINDOWS_COUNT = "%d Chat Windows";
+CHAT_WRONG_FACTION_NOTICE = "Wrong alliance for %s.";
+CHAT_WRONG_PASSWORD_NOTICE = "Wrong password for %s.";
+CHAT_YELL_GET = "%s yells:\32";
+CHAT_YELL_SEND = "Yell:\32";
+CHAT_YELL_UNKNOWN = "yells at his team members.";
+CHAT_YELL_UNKNOWN_FEMALE = "yells at her team members.";
+CHAT_YOU_CHANGED_NOTICE = "Changed Channel: |Hchannel:%d|h[%s]|h";
+CHAT_YOU_CHANGED_NOTICE_BN = "Changed Channel: |Hchannel:CHANNEL:%d|h[%s]|h";
+CHAT_YOU_JOINED_NOTICE = "Joined Channel: |Hchannel:%d|h[%s]|h";
+CHAT_YOU_JOINED_NOTICE_BN = "Joined Channel: |Hchannel:CHANNEL:%d|h[%s]|h";
+CHAT_YOU_LEFT_NOTICE = "Left Channel: |Hchannel:%d|h[%s]|h";
+CHAT_YOU_LEFT_NOTICE_BN = "Left Channel: |Hchannel:CHANNEL:%d|h[%s]|h";
+CHESTSLOT = "Chest";
+CHOOSE_BOX = "Choose a box:";
+CHOOSE_RAID = "Choose Raid";
+CHOOSE_STATIONERY = "Choose Stationery";
+CHOOSE_YOUR_DUNGEON = "Type:";
+CHOSEN_FOR_GMSURVEY = "You have been chosen to fill out a GM survey.";
+CINEMATIC_SUBTITLES = "Cinematic Subtitles";
+CLASS = "Class";
+CLASSIC_STYLE = "Classic Style";
+CLASS_COLORS = "Class Colors";
+CLASS_SKILLS = "%s Skills:";
+CLEARED_AFK = "You are no longer Away.";
+CLEARED_DND = "You are no longer marked Busy.";
+CLEAR_AFK = "Auto Clear Away";
+CLEAR_ALL = "Clear All";
+CLEAR_FOCUS = "Clear Focus";
+CLICK_CAMERA_STYLE = "Click-to-Move Camera Style";
+CLICK_FOR_ADDITIONAL_QUEST_LOCATIONS = "Click here to see additional locations.";
+CLICK_FOR_DETAILS = "Click for details";
+CLICK_HERE_FOR_MORE_INFO = "Click here for more information.";
+CLICK_TO_ENTER_COMMENT = "Click here to enter a comment";
+CLICK_TO_INVITE_TO_CONVERSATION = "Click here to invite another friend to this Conversation.";
+CLICK_TO_LEARN = "Click to learn skill";
+CLICK_TO_MOVE = "Click-to-Move";
+CLICK_TO_REMOVE_ADDITIONAL_QUEST_LOCATIONS = "Click here to hide additional locations.";
+CLICK_TO_START_CONVERSATION = "Click here to start a Conversation with this player and one other friend.";
+CLIENT_LOGOUT_ALERT = "Some of your settings will not take effect until you log out and log back into the game.";
+CLIENT_RESTART_ALERT = "Some of your settings will not take effect until you restart the game.";
+CLOSE = "Close";
+CLOSES_IN = "Time Left";
+CLOSE_AND_LEAVE_CHAT_CONVERSATION_WINDOW = "Leave Conversation";
+CLOSE_CHAT = "Close Chat";
+CLOSE_CHAT_CONVERSATION_WINDOW = "Close Conversation Window";
+CLOSE_CHAT_WHISPER_WINDOW = "Close Whisper Window";
+CLOSE_CHAT_WINDOW = "Close Window";
+CLOSE_LOG = "Close Log";
+COD = "C.O.D.";
+COD_AMOUNT = "Cash on Delivery Amount:";
+COD_CONFIRMATION = "Accepting this item will cost:";
+COD_INSUFFICIENT_MONEY = "You do not have enough money to pay the C.O.D. charges.";
+COD_PAYMENT = "COD Payment: %s";
+COINPICKUP_CANCEL = "Cancel";
+COLOR = "Color";
+COLORBLIND_NAMEWRAPPER_ENEMY = "%s - Enemy";
+COLORBLIND_NAMEWRAPPER_FRIENDLY = "%s - Friendly";
+COLORBLIND_NAMEWRAPPER_NEUTRAL = "%s - Neutral";
+COLORIZE = "Colorize:";
+COLORS = "Colors";
+COLOR_BY_SCHOOL = "Color-by-School";
+COLOR_PICKER = "Color Picker";
+COMBAT = "Combat";
+COMBATLOGDISABLED = "Combat logging disabled.";
+COMBATLOGENABLED = "Combat being logged to Logs\\WoWCombatLog.txt";
+COMBATLOG_ARENAPOINTSAWARD = "You have been awarded %d arena points.";
+COMBATLOG_DEFAULTS = "Combat Log Defaults";
+COMBATLOG_DISHONORGAIN = "%s dies, dishonorable kill.";
+COMBATLOG_FILTER_STRING_CUSTOM_UNIT = "Custom Unit";
+COMBATLOG_FILTER_STRING_FRIENDLY_UNITS = "Friends";
+COMBATLOG_FILTER_STRING_HOSTILE_PLAYERS = "Enemy Players";
+COMBATLOG_FILTER_STRING_HOSTILE_UNITS = "Enemy Units";
+COMBATLOG_FILTER_STRING_ME = "Me";
+COMBATLOG_FILTER_STRING_MY_PET = "Pet";
+COMBATLOG_FILTER_STRING_NEUTRAL_UNITS = "Neutral";
+COMBATLOG_FILTER_STRING_UNKNOWN_UNITS = "Unknown";
+COMBATLOG_HIGHLIGHT_ABILITY = "Ability";
+COMBATLOG_HIGHLIGHT_DAMAGE = "Damage";
+COMBATLOG_HIGHLIGHT_KILL = "Kill";
+COMBATLOG_HIGHLIGHT_SCHOOL = "School";
+COMBATLOG_HONORAWARD = "You have been awarded %d honor points.";
+COMBATLOG_HONORGAIN = "%s dies, honorable kill Rank: %s (%d Honor Points)";
+COMBATLOG_HONORGAIN_NO_RANK = "%s dies, honorable kill (%d Honor Points)";
+COMBATLOG_UNKNOWN_UNIT = "Something";
+COMBATLOG_XPGAIN_EXHAUSTION1 = "%s dies, you gain %d experience. (%s exp %s bonus)";
+COMBATLOG_XPGAIN_EXHAUSTION1_GROUP = "%s dies, you gain %d experience. (%s exp %s bonus, +%d group bonus)";
+COMBATLOG_XPGAIN_EXHAUSTION1_RAID = "%s dies, you gain %d experience. (%s exp %s bonus, -%d raid penalty)";
+COMBATLOG_XPGAIN_EXHAUSTION2 = "%s dies, you gain %d experience. (%s exp %s bonus)";
+COMBATLOG_XPGAIN_EXHAUSTION2_GROUP = "%s dies, you gain %d experience. (%s exp %s bonus, +%d group bonus)";
+COMBATLOG_XPGAIN_EXHAUSTION2_RAID = "%s dies, you gain %d experience. (%s exp %s bonus, -%d raid penalty)";
+COMBATLOG_XPGAIN_EXHAUSTION4 = "%s dies, you gain %d experience. (%s exp %s penalty)";
+COMBATLOG_XPGAIN_EXHAUSTION4_GROUP = "%s dies, you gain %d experience. (%s exp %s penalty, +%d group bonus)";
+COMBATLOG_XPGAIN_EXHAUSTION4_RAID = "%s dies, you gain %d experience. (%s exp %s penalty, -%d raid penalty)";
+COMBATLOG_XPGAIN_EXHAUSTION5 = "%s dies, you gain %d experience. (%s exp %s penalty)";
+COMBATLOG_XPGAIN_EXHAUSTION5_GROUP = "%s dies, you gain %d experience. (%s exp %s penalty, +%d group bonus)";
+COMBATLOG_XPGAIN_EXHAUSTION5_RAID = "%s dies, you gain %d experience. (%s exp %s penalty, -%d raid penalty)";
+COMBATLOG_XPGAIN_FIRSTPERSON = "%s dies, you gain %d experience.";
+COMBATLOG_XPGAIN_FIRSTPERSON_GROUP = "%s dies, you gain %d experience. (+%d group bonus)";
+COMBATLOG_XPGAIN_FIRSTPERSON_RAID = "%s dies, you gain %d experience. (-%d raid penalty)";
+COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED = "You gain %d experience.";
+COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_GROUP = "You gain %d experience. (+%d group bonus)";
+COMBATLOG_XPGAIN_FIRSTPERSON_UNNAMED_RAID = "You gain %d experience. (-%d raid penalty)";
+COMBATLOG_XPGAIN_QUEST = "You gain %d experience. (%s exp %s bonus)";
+COMBATLOG_XPLOSS_FIRSTPERSON_UNNAMED = "You lose %d experience.";
+COMBATTEXT_LABEL = "Combat Text";
+COMBATTEXT_SUBTEXT = "These options allow you to configure the floating combat text which can be displayed in the center of the screen, making it easier to follow battles.";
+COMBAT_ENEMY = "Combat Enemy";
+COMBAT_ERROR = "Combat Error";
+COMBAT_FACTION_CHANGE = "Reputation";
+COMBAT_HONOR_GAIN = "Honor";
+COMBAT_LABEL = "Combat";
+COMBAT_LOG = "Combat Log";
+COMBAT_LOG_MENU_BOTH = "Show everything involving %s?";
+COMBAT_LOG_MENU_EVERYTHING = "Show Everything";
+COMBAT_LOG_MENU_INCOMING = "What happened to %s?";
+COMBAT_LOG_MENU_OUTGOING = "What did %s do?";
+COMBAT_LOG_MENU_OUTGOING_ME = "What did %s do to you?";
+COMBAT_LOG_MENU_REVERT = "Revert to Last Filter";
+COMBAT_LOG_MENU_SAVE = "Save as a new filter";
+COMBAT_LOG_MENU_SPELL_HIDE = "Hide messages like this one.";
+COMBAT_LOG_MENU_SPELL_LINK = "Link %s to chat.";
+COMBAT_LOG_MENU_SPELL_TYPE_HEADER = "Message Types";
+COMBAT_LOG_UNIT_YOU_ENABLED = "1";
+COMBAT_MESSAGES = "Combat Messages";
+COMBAT_MISC = "Combat Misc";
+COMBAT_MISC_INFO = "Misc Info";
+COMBAT_PARTY = "Combat Party";
+COMBAT_RATING_NAME1 = "Weapon Skill";
+COMBAT_RATING_NAME10 = "Crit Rating";
+COMBAT_RATING_NAME11 = "Crit Rating";
+COMBAT_RATING_NAME15 = "Resilience";
+COMBAT_RATING_NAME2 = "Defense Rating";
+COMBAT_RATING_NAME24 = "Expertise";
+COMBAT_RATING_NAME3 = "Dodge Rating";
+COMBAT_RATING_NAME4 = "Parry Rating";
+COMBAT_RATING_NAME5 = "Block Rating";
+COMBAT_RATING_NAME6 = "Hit Rating";
+COMBAT_RATING_NAME7 = "Hit Rating";
+COMBAT_RATING_NAME8 = "Hit Rating";
+COMBAT_RATING_NAME9 = "Crit Rating";
+COMBAT_SELF = "Combat Self";
+COMBAT_SUBTEXT = "These options affect your character's behaviors in combat, and allow you to change the way combat is displayed in the UI.";
+COMBAT_TEXT_ABSORB = "Absorb";
+COMBAT_TEXT_ARENA_POINTS_GAINED = "Arena Points %s";
+COMBAT_TEXT_BLOCK = "Block";
+COMBAT_TEXT_COMBO_POINTS = "<%d Combo |4Point:Points;>";
+COMBAT_TEXT_DEFLECT = "Deflect";
+COMBAT_TEXT_DODGE = "Dodge";
+COMBAT_TEXT_EVADE = "Evade";
+COMBAT_TEXT_FLOAT_MODE_LABEL = "Combat Text Float Mode";
+COMBAT_TEXT_HONOR_GAINED = "Honor %s";
+COMBAT_TEXT_IMMUNE = "Immune";
+COMBAT_TEXT_LABEL = "Floating Combat Text";
+COMBAT_TEXT_MISS = "Miss";
+COMBAT_TEXT_NONE = "None";
+COMBAT_TEXT_PARRY = "Parry";
+COMBAT_TEXT_REFLECT = "Reflect";
+COMBAT_TEXT_RESIST = "Resist";
+COMBAT_TEXT_RUNE_BLOOD = "Blood Rune";
+COMBAT_TEXT_RUNE_DEATH = "Death Rune";
+COMBAT_TEXT_RUNE_FROST = "Frost Rune";
+COMBAT_TEXT_RUNE_UNHOLY = "Unholy Rune";
+COMBAT_TEXT_SCROLL_ARC = "Arc";
+COMBAT_TEXT_SCROLL_DOWN = "Scroll Down";
+COMBAT_TEXT_SCROLL_DOWN_TEXT = "Scroll Text Down";
+COMBAT_TEXT_SCROLL_UP = "Scroll Up";
+COMBAT_TEXT_SHOW_AURAS_TEXT = "Auras";
+COMBAT_TEXT_SHOW_AURA_FADE_TEXT = "Fading Auras";
+COMBAT_TEXT_SHOW_COMBAT_STATE_TEXT = "Combat State";
+COMBAT_TEXT_SHOW_COMBO_POINTS_TEXT = "Combo Points";
+COMBAT_TEXT_SHOW_DODGE_PARRY_MISS_TEXT = "Dodges/Parries/Misses";
+COMBAT_TEXT_SHOW_ENERGIZE_TEXT = "Energy Gains";
+COMBAT_TEXT_SHOW_FRIENDLY_NAMES_TEXT = "Friendly Healer Names";
+COMBAT_TEXT_SHOW_HONOR_GAINED_TEXT = "Honor Gained";
+COMBAT_TEXT_SHOW_LOW_HEALTH_MANA_TEXT = "Low Mana & Health";
+COMBAT_TEXT_SHOW_PERIODIC_ENERGIZE_TEXT = "Periodic Energy Gains";
+COMBAT_TEXT_SHOW_REACTIVES_TEXT = "Reactive Spells & Abilities";
+COMBAT_TEXT_SHOW_REPUTATION_TEXT = "Reputation Changes";
+COMBAT_TEXT_SHOW_RESISTANCES_TEXT = "Damage Reduction";
+COMBAT_THREAT_DECREASE_0 = "Changed Target!";
+COMBAT_THREAT_DECREASE_1 = "Changed Target!";
+COMBAT_THREAT_DECREASE_2 = "Losing Threat";
+COMBAT_THREAT_INCREASE_1 = "High Threat";
+COMBAT_THREAT_INCREASE_3 = "Attacking You!";
+COMBAT_XP_GAIN = "Experience";
+COMBAT_ZONE = "(Combat Zone)";
+COMMAND = "Command";
+COMMENT = "Comment";
+COMMENTS_COLON = "Comments:";
+COMPANIONS = "Companions";
+COMPARE_ACHIEVEMENTS = "Compare Achievements";
+COMPLAINT_ADDED = "Complaint Registered.";
+COMPLETE = "Complete";
+COMPLETE_QUEST = "Complete Quest";
+CONFIRM_ACCEPT_PVP_QUEST = "Accepting this quest will flag you for PvP as long as the quest is in your log. Do you wish to accept?";
+CONFIRM_ACCEPT_SOCKETS = "One or more gems will be destroyed by socketing. Do you really want to socket the new gem(s)?";
+CONFIRM_BATTLEFIELD_ENTRY = "You are now eligible to enter %s, choose an action:";
+CONFIRM_BINDER = "Do you want to make %s your new home?";
+CONFIRM_BUY_BANK_SLOT = "Do you want to purchase a bank slot for:";
+CONFIRM_BUY_GUILDBANK_TAB = "Do you want to purchase a Guild Bank tab for:";
+CONFIRM_BUY_STABLE_SLOT = "Are you sure you wish to purchase a new stable slot for the following amount?";
+CONFIRM_COMBAT_FILTER_DEFAULTS = "Do you really want to reset your filters to their default values?";
+CONFIRM_COMBAT_FILTER_DELETE = "Do you really want to delete this filter?";
+CONFIRM_COMPLETE_EXPENSIVE_QUEST = "Completing this quest requires the following amount of gold. Are you sure you want to complete this quest?";
+CONFIRM_DELETE_EQUIPMENT_SET = "Are you sure you want to delete the equipment set %s?";
+CONFIRM_DELETING_CHARACTER_SPECIFIC_BINDINGS = "Really switch to general key bindings? All key bindings specific to this character will be permanantly deleted.";
+CONFIRM_GLYPH_PLACEMENT = "Are you sure you want to inscribe this glyph? The existing glyph will be lost.";
+CONFIRM_GUILD_DISBAND = "Do you really want to disband your guild?";
+CONFIRM_GUILD_LEAVE = "Really leave %s?";
+CONFIRM_GUILD_PROMOTE = "Really promote %s to Guildmaster?";
+CONFIRM_HIGH_COST_ITEM = "Are you sure you wish to purchase %s for the following amount?";
+CONFIRM_LEARN_PREVIEW_TALENTS = "Are you sure you want to learn these talents?";
+CONFIRM_LEAVE_QUEUE = "Are you sure you would like to leave the meeting stone queue?";
+CONFIRM_LOOT_DISTRIBUTION = "You wish to assign %s to %s. Is this correct?";
+CONFIRM_LOSE_BINDING_CHANGES = "You will lose any unsaved changes if you switch between general and character specific key bindings.";
+CONFIRM_OVERWRITE_EQUIPMENT_SET = "You already have an equipment set named %s. Would you like to overwrite it?";
+CONFIRM_PET_UNLEARN = "Do you want to unlearn all of your pet's skills? The cost will increase each time you do it.";
+CONFIRM_PURCHASE_TOKEN_ITEM = "Are you sure you wish to exchange %s for the following item?";
+CONFIRM_REFUND_MAX_ARENA_POINTS = "You are close to the maximum number of arena points. Selling this item will result in the loss of %d arena points. Proceed?";
+CONFIRM_REFUND_MAX_HONOR = "You are close to the maximum number of honor points. Selling this item will result in the loss of %d honor points. Proceed?";
+CONFIRM_REFUND_MAX_HONOR_AND_ARENA = "You are close to the maximum number of honor and arena points. Selling this item will result in the loss of %1$d honor points and %2$d arena points. Proceed?";
+CONFIRM_REFUND_TOKEN_ITEM = "Are you sure you wish to get a refund of %s for the following item?";
+CONFIRM_REMOVE_GLYPH = "Are you sure you want to remove %s? This glyph will be permanently destroyed.";
+CONFIRM_RESET_INSTANCES = "Do you really want to reset all of your instances?";
+CONFIRM_RESET_INTERFACE_SETTINGS = "Do you want to reset all user interface and addon settings to their defaults, or only the settings for this category or addon?";
+CONFIRM_RESET_SETTINGS = "Do you want to reset all settings to their defaults? This will immediately apply all settings.";
+CONFIRM_SUMMON = "%s wants to summon you to %s. The spell will be cancelled in %d %s.";
+CONFIRM_TALENT_WIPE = "Do you want to unlearn all of your talents? This will unsummon any controlled pet and the cost will increase each time.";
+CONFIRM_TEAM_DISBAND = "Do you really want to disband your arena team %s?";
+CONFIRM_TEAM_KICK = "Really remove %s from %s?";
+CONFIRM_TEAM_LEAVE = "Really leave %s?";
+CONFIRM_TEAM_PROMOTE = "Really promote %s to Team Captain?";
+CONFIRM_XP_LOSS = "If you find your corpse, you can resurrect for no penalty. If I resurrect you all of your items will take up to 25%% durability damage (equipped and inventory) and you will be afflicted by %s of Resurrection Sickness.";
+CONFIRM_XP_LOSS_AGAIN = "Remember, if you find your corpse there is no penalty. Are you sure you want to take up to 25%% durability damage (equipped and inventory) and incur %s of Resurrection Sickness?";
+CONFIRM_XP_LOSS_AGAIN_NO_DURABILITY = "Remember, if you find your corpse there is no penalty. Are you sure you want to incur %s of Resurrection Sickness?";
+CONFIRM_XP_LOSS_AGAIN_NO_SICKNESS = "Remember, if you find your corpse there is no penalty. Are you sure you want to have all your items take up to 25% durability damage?";
+CONFIRM_XP_LOSS_NO_DURABILITY = "If you find your corpse, you can resurrect for no penalty. Otherwise you will be afflicted by %s of Resurrection Sickness.";
+CONFIRM_XP_LOSS_NO_SICKNESS = "If you find your corpse, you can resurrect for no penalty. If I resurrect you all of your items will take up to 25%% durability damage (equipped and inventory).";
+CONFIRM_XP_LOSS_NO_SICKNESS_NO_DURABILITY = "You can find your corpse and resurrect at that location. Players that are level 10 or below can resurrect here with no penalty.";
+CONFIRM_YOUR_ROLE = "Confirm your role:";
+CONSOLIDATE_BUFFS_TEXT = "Consolidate Buffs";
+CONTAINER_SLOTS = "%d Slot %s";
+CONTESTED_TERRITORY = "(Contested Territory)";
+CONTINENT = "Continent";
+CONTINUE = "Continue";
+CONTINUED = "...";
+CONTROLS_LABEL = "Controls";
+CONTROLS_SUBTEXT = "These are general gameplay related controls that affect how your character interacts with objects and other players in the game world.";
+CONVERSATION_MODE = "New Real ID Conversations|TInterface\\OptionsFrame\\UI-OptionsFrame-NewFeatureIcon:0:0:0:-1|t";
+CONVERSATION_MODE_INLINE = "In-line";
+CONVERSATION_MODE_POPOUT = "New Tab";
+CONVERSATION_NAME = "%d. Conversation";
+CONVERT_TO_RAID = "Convert To Raid";
+COOLDOWN_ON_LEAVE_COMBAT = "(Cooldown Starts Upon Leaving Combat)";
+COOLDOWN_REMAINING = "Cooldown remaining:";
+COPPER_AMOUNT = "%d Copper";
+COPPER_AMOUNT_SYMBOL = "c";
+COPPER_AMOUNT_TEXTURE = "%d\124TInterface\\MoneyFrame\\UI-CopperIcon:%d:%d:2:0\124t";
+COPY_FILTER = "Copy Filter";
+COPY_NAME = "Copy Name";
+CORPSE = "Corpse";
+CORPSE_RED = "|cffff2020Corpse|r";
+CORPSE_TOOLTIP = "Corpse of %s";
+COSTS_LABEL = "Cost:";
+CRAFT_IS_MAKEABLE = "Have Materials";
+CRAFT_IS_MAKEABLE_TOOLTIP = "Only show recipes that you have the materials to make.";
+CREATE = "Create";
+CREATED_ITEM = "%s creates: %s.";
+CREATED_ITEM_MULTIPLE = "%s creates: %sx%d.";
+CREATE_ALL = "Create All";
+CREATE_AUCTION = "Create Auction";
+CREATE_CONVERSATION_WITH = "Create Conversation";
+CREATE_MACROS = "Create Macros";
+CREATURE = "Creature";
+CREATURE_MESSAGES = "Creature Messages";
+CRIT_ABBR = "Crit";
+CRUSHING_TRAILER = " (crushing)";
+CR_BLOCK_TOOLTIP = "Block Rating of %d adds %.2f%% Block\nYour block stops %d damage.";
+CR_CRIT_MELEE_TOOLTIP = "Crit rating %d (+%.2f%% crit chance)";
+CR_CRIT_RANGED_TOOLTIP = "Crit rating %d (+%.2f%% crit chance)";
+CR_DODGE_TOOLTIP = "Dodge Rating of %d adds %.2f%% Dodge|n|cff888888(Before diminishing returns)|r";
+CR_EXPERTISE_TOOLTIP = "Reduces chance to be dodged or parried by %s\nExpertise rating %d (+%d expertise)";
+CR_HASTE_RATING_TOOLTIP = "Haste rating %d (%.2f%% haste)";
+CR_HIT_MELEE_TOOLTIP = "Increases your melee chance to hit a target of level %d by %.2f%%\n\nArmor penetration rating %d (Enemy armor reduced by up to %.2f%%).";
+CR_HIT_RANGED_TOOLTIP = "Increases your ranged chance to hit a target of level %d by %.2f%%\n\nArmor penetration rating %d (Enemy Armor Reduced by up to %.2f%%).";
+CR_HIT_SPELL_TOOLTIP = "Increases your spell chance to hit a target of level %d by %.2f%%.\n\nSpell Penetration %d (Reduces enemy resistances by %d)";
+CR_PARRY_TOOLTIP = "Parry Rating of %d adds %.2f%% Parry|n|cff888888(Before diminishing returns)|r";
+CTRL_KEY = "CTRL key";
+CTRL_KEY_TEXT = "CTRL";
+CURRENCY = "Currency";
+CURRENCY_AMOUNT_REFUND_FORMAT = "%d %s";
+CURRENTLY_EQUIPPED = "Currently Equipped";
+CURRENT_BID = "Current Bid";
+CURRENT_PET = "Current Pet:";
+CURRENT_QUESTS = "Current Quests";
+CURRENT_SETTINGS = "These Settings";
+CUSTOM = "Custom";
+DAILY = "Daily";
+DAILY_QUESTS_REMAINING = "You can only complete %d more daily |4quest:quests; today.";
+DAILY_QUEST_TAG_TEMPLATE = "Daily %s";
+DAMAGE = "Damage";
+DAMAGER = "Damage";
+DAMAGE_BONUS_TOOLTIP = "Increases weapon damage";
+DAMAGE_DONE_TOOLTIP = "The total amount of damage done.";
+DAMAGE_NUMBER = "Damage Number";
+DAMAGE_PER_SECOND = "Damage per Second";
+DAMAGE_SCHOOL2 = "Holy";
+DAMAGE_SCHOOL3 = "Fire";
+DAMAGE_SCHOOL4 = "Nature";
+DAMAGE_SCHOOL5 = "Frost";
+DAMAGE_SCHOOL6 = "Shadow";
+DAMAGE_SCHOOL7 = "Arcane";
+DAMAGE_SCHOOL_TEXT = "Damage School";
+DAMAGE_SHIELD = "Damage Shields";
+DAMAGE_SHIELD_COMBATLOG_TOOLTIP = "Show messages when a spell or ability deals damage in reaction to a melee swing, such as Thorns.";
+DAMAGE_TEMPLATE = "%d - %d Damage";
+DAMAGE_TEMPLATE_WITH_SCHOOL = "%d - %d %s Damage";
+DAMAGE_TOOLTIP = "Weapon Damage";
+DATE_COMPLETED = "Completed: %s";
+DAYS = "|4Day:Days;";
+DAYS_ABBR = "%d |4Day:Days;";
+DAY_ONELETTER_ABBR = "%d d";
+DEAD = "Dead";
+DEATHBINDALREADYBOUND = "You are already bound here!";
+DEATHBIND_SUCCESSFUL = "Your soul is bound to this place.";
+DEATHS = "Deaths";
+DEATHS_COMBATLOG_TOOLTIP = "Show messages when something dies.";
+DEATHS_TOOLTIP = "Number of times you were killed.";
+DEATH_CORPSE_SKINNED = "Insignia Taken - You can only resurrect at the graveyard";
+DEATH_EFFECT = "Death Effect";
+DEATH_RELEASE = "Release Spirit";
+DEATH_RELEASE_NOTIMER = "You have died. Release to the nearest graveyard?";
+DEATH_RELEASE_SPECTATOR = "You have died. Release spirit to enter Spectator Mode.";
+DEATH_RELEASE_TIMER = "%d %s until release";
+DEBUFF_SYMBOL_CURSE = "Cu";
+DEBUFF_SYMBOL_DISEASE = "Di";
+DEBUFF_SYMBOL_MAGIC = "Ma";
+DEBUFF_SYMBOL_POISON = "Po";
+DEBUG_FRAMESTACK = "Frame Stack";
+DECLENSION_SET = "%s of %s";
+DECLINE = "Decline";
+DEDE = "German";
+DEFAULT = "Default";
+DEFAULTS = "Defaults";
+DEFAULT_AFK_MESSAGE = "Away";
+DEFAULT_AGILITY_TOOLTIP = "Increases attack power with ranged weapons.|nImproves chance to score a critical hit with all weapons.|nIncreases armor and chance to dodge attacks.";
+DEFAULT_COMBATLOG_FILTER_NAME = "Filter %d";
+DEFAULT_DND_MESSAGE = "Busy";
+DEFAULT_INTELLECT_TOOLTIP = "Increases the rate at which weapon skills improve.";
+DEFAULT_SPIRIT_TOOLTIP = "Increases health and mana regeneration rates.";
+DEFAULT_STAMINA_TOOLTIP = "Increases health points.";
+DEFAULT_STAT1_TOOLTIP = "Increases Attack Power by %d";
+DEFAULT_STAT2_TOOLTIP = "Increases Critical Hit chance by %.2f%%|nIncreases Armor by %d";
+DEFAULT_STAT3_TOOLTIP = "Increases Health by %d";
+DEFAULT_STAT4_TOOLTIP = "Increases Mana by %d|nIncreases Spell Critical Hit by %.2f%%";
+DEFAULT_STAT5_TOOLTIP = "Increases Health Regeneration by %d Per Second while not in combat";
+DEFAULT_STATARMOR_TOOLTIP = "Reduces Physical Damage taken by %0.2f%%";
+DEFAULT_STATDEFENSE_TOOLTIP = "Defense Rating %d (+%d Defense)|nIncreases chance to Dodge, Block and Parry by %.2f%%|nDecreases chance to be hit and critically hit by %.2f%%|n|cff888888(Before diminishing returns)|r";
+DEFAULT_STATSPELLBONUS_TOOLTIP = "Bonus damage to spell attacks.";
+DEFENSE = "Defense";
+DEFENSE_ABBR = "Def";
+DEFENSE_TOOLTIP = "Defense Rating";
+DEFLECT = "Deflect";
+DELETE = "Delete";
+DELETE_GOOD_ITEM = "Do you want to destroy %s?\n\nType \"DELETE\" into the field to confirm.";
+DELETE_ITEM = "Do you want to destroy %s?";
+DELETE_ITEM_CONFIRM_STRING = "DELETE";
+DELETE_MAIL_CONFIRMATION = "Deleting this mail will also destroy %s";
+DELETE_MONEY_CONFIRMATION = "Deleting this mail will also destroy:";
+DEMOTE = "Demote";
+DEPOSIT = "Deposit";
+DEPOSIT_COLON = "Deposit:";
+DEPTH_CONVERGENCE = "Screen Depth";
+DESERTER = "Deserter";
+DESKTOP_GAMMA = "Use desktop gamma";
+DESTROY_GEM = "Gem to be destroyed";
+DISABLE = "Disable";
+DISABLE_ADDONS = "Disable AddOns";
+DISABLE_SPAM_FILTER = "Disable Spam Filter";
+DISGUISE = "Disguise";
+DISHONORABLE_KILLS = "Dishonorable Kills";
+DISPELS = "Dispels";
+DISPEL_AURA_COMBATLOG_TOOLTIP = "Show when an aura is removed, broken, or stolen.";
+DISPLAY = "Display";
+DISPLAY_ACTIVE_CHANNEL = "Display Active Channel";
+DISPLAY_CHANNEL_PULLOUT = "Display Chat Roster Pullout";
+DISPLAY_FREE_BAG_SLOTS = "Show Free Bag Space";
+DISPLAY_LABEL = "Display";
+DISPLAY_ON_CHARACTER = "Display on Character";
+DISPLAY_ON_CHAR_TOOLTIP = "Checking this will show any selected auction items on your character.\n\nCTRL-Left Clicking any equippable item in the game will also allow you to try it on your character.";
+DISPLAY_OPTIONS = "Display Options";
+DISPLAY_SUBTEXT = "These options affect whether certain UI and character elements are hidden or displayed.";
+DK = "DK";
+DMG = "Dmg";
+DND = "Busy";
+DODGE = "Dodge";
+DODGE_CHANCE = "Dodge Chance";
+DONE = "Done";
+DONE_BY = "Done By:";
+DONE_TO = "Done To:";
+DPS_TEMPLATE = "(%.1f damage per second)";
+DRAINS = "Drains";
+DRESSUP_FRAME = "Dressing Room";
+DRESSUP_FRAME_INSTRUCTIONS = "CTRL-Left Click additional items to display them on your character";
+DRUID_INTELLECT_TOOLTIP = "Increases mana points and chance to score a critical hit with spells.\nIncreases the rate at which weapon skills improve.";
+DRUNK_MESSAGE_ITEM_OTHER1 = "%s is looking sober from the %s.";
+DRUNK_MESSAGE_ITEM_OTHER2 = "%s seems a little tipsy from the %s.";
+DRUNK_MESSAGE_ITEM_OTHER3 = "%s is getting drunk off of %s.";
+DRUNK_MESSAGE_ITEM_OTHER4 = "%s is completely smashed from the %s.";
+DRUNK_MESSAGE_ITEM_SELF1 = "You feel sober after the %s.";
+DRUNK_MESSAGE_ITEM_SELF2 = "You feel a little tipsy from the %s.";
+DRUNK_MESSAGE_ITEM_SELF3 = "You're feeling drunk off of %s.";
+DRUNK_MESSAGE_ITEM_SELF4 = "You feel completely smashed after that %s.";
+DRUNK_MESSAGE_OTHER1 = "%s seems to be sobering up.";
+DRUNK_MESSAGE_OTHER2 = "%s looks tipsy.";
+DRUNK_MESSAGE_OTHER3 = "%s looks drunk.";
+DRUNK_MESSAGE_OTHER4 = "%s looks completely smashed.";
+DRUNK_MESSAGE_SELF1 = "You feel sober again.";
+DRUNK_MESSAGE_SELF2 = "You feel tipsy. Whee!";
+DRUNK_MESSAGE_SELF3 = "You feel drunk. Woah!";
+DRUNK_MESSAGE_SELF4 = "You feel completely smashed.";
+DUEL = "Duel";
+DUEL_COUNTDOWN = "Duel starting: %d";
+DUEL_OUTOFBOUNDS_TIMER = "Exiting duel area, you will forfeit in %d %s.";
+DUEL_REQUESTED = "%s has challenged you to a duel.";
+DUEL_WINNER_KNOCKOUT = "%1$s has defeated %2$s in a duel";
+DUEL_WINNER_RETREAT = "%2$s has fled from %1$s in a duel";
+DUNGEONS_BUTTON = "Dungeon Finder";
+DUNGEON_COMPLETED = "Dungeon Complete!";
+DUNGEON_DIFFICULTY = "Dungeon Difficulty";
+DUNGEON_DIFFICULTY1 = "5 Player";
+DUNGEON_DIFFICULTY2 = "5 Player (Heroic)";
+DUNGEON_DIFFICULTY3 = "Epic (Unused)";
+DUNGEON_DIFFICULTY_5PLAYER = "5 Player";
+DUNGEON_DIFFICULTY_5PLAYER_HEROIC = "5 Player (Heroic)";
+DUNGEON_FLOOR_AHNKAHET1 = "Ahn'Kahet";
+DUNGEON_FLOOR_AZJOLNERUB1 = "The Brood Pit";
+DUNGEON_FLOOR_AZJOLNERUB2 = "Hadronox's Lair";
+DUNGEON_FLOOR_AZJOLNERUB3 = "The Gilded Gate";
+DUNGEON_FLOOR_COTSTRATHOLME0 = "The Road to Stratholme";
+DUNGEON_FLOOR_COTSTRATHOLME1 = "Stratholme City";
+DUNGEON_FLOOR_DALARAN1 = "Dalaran City";
+DUNGEON_FLOOR_DALARAN2 = "The Underbelly";
+DUNGEON_FLOOR_DRAKTHARONKEEP1 = "The Vestibules of Drak'Tharon";
+DUNGEON_FLOOR_DRAKTHARONKEEP2 = "Drak'Tharon Overlook";
+DUNGEON_FLOOR_GUNDRAK1 = "Gundrak";
+DUNGEON_FLOOR_HALLSOFLIGHTNING1 = "Unyielding Garrison";
+DUNGEON_FLOOR_HALLSOFLIGHTNING2 = "Walk of the Makers";
+DUNGEON_FLOOR_HALLSOFREFLECTION1 = "Halls of Reflection";
+DUNGEON_FLOOR_ICECROWNCITADEL1 = "The Lower Citadel";
+DUNGEON_FLOOR_ICECROWNCITADEL2 = "The Rampart of Skulls";
+DUNGEON_FLOOR_ICECROWNCITADEL3 = "Deathbringer's Rise";
+DUNGEON_FLOOR_ICECROWNCITADEL4 = "The Frost Queen's Lair";
+DUNGEON_FLOOR_ICECROWNCITADEL5 = "The Upper Reaches";
+DUNGEON_FLOOR_ICECROWNCITADEL6 = "Royal Quarters";
+DUNGEON_FLOOR_ICECROWNCITADEL7 = "The Frozen Throne";
+DUNGEON_FLOOR_ICECROWNCITADEL8 = "Frostmourne";
+DUNGEON_FLOOR_NAXXRAMAS1 = "The Construct Quarter";
+DUNGEON_FLOOR_NAXXRAMAS2 = "The Arachnid Quarter";
+DUNGEON_FLOOR_NAXXRAMAS3 = "The Military Quarter";
+DUNGEON_FLOOR_NAXXRAMAS4 = "The Plague Quarter";
+DUNGEON_FLOOR_NAXXRAMAS5 = "The Lower Necropolis";
+DUNGEON_FLOOR_NAXXRAMAS6 = "The Upper Necropolis";
+DUNGEON_FLOOR_NEXUS801 = "Band of Variance";
+DUNGEON_FLOOR_NEXUS802 = "Band of Acceleration";
+DUNGEON_FLOOR_NEXUS803 = "Band of Transmutation";
+DUNGEON_FLOOR_NEXUS804 = "Band of Alignment";
+DUNGEON_FLOOR_PITOFSARON1 = "Pit of Saron";
+DUNGEON_FLOOR_THEARGENTCOLISEUM1 = "The Argent Coliseum";
+DUNGEON_FLOOR_THEARGENTCOLISEUM2 = "The Icy Depths";
+DUNGEON_FLOOR_THEEYEOFETERNITY1 = "The Eye of Eternity";
+DUNGEON_FLOOR_THEFORGEOFSOULS1 = "The Forge of Souls";
+DUNGEON_FLOOR_THENEXUS1 = "The Nexus";
+DUNGEON_FLOOR_THEOBSIDIANSANCTUM1 = "The Obsidian Sanctum";
+DUNGEON_FLOOR_ULDUAR0 = "The Grand Approach ";
+DUNGEON_FLOOR_ULDUAR1 = "The Antechamber of Ulduar";
+DUNGEON_FLOOR_ULDUAR2 = "The Inner Sanctum of Ulduar";
+DUNGEON_FLOOR_ULDUAR3 = "The Prison of Yogg-Saron";
+DUNGEON_FLOOR_ULDUAR4 = "The Spark of Imagination";
+DUNGEON_FLOOR_ULDUAR5 = "The Mind's Eye";
+DUNGEON_FLOOR_ULDUAR771 = "Halls of Stone";
+DUNGEON_FLOOR_UTGARDEKEEP1 = "Norndir Preperation";
+DUNGEON_FLOOR_UTGARDEKEEP2 = "Dragonflayer Ascent";
+DUNGEON_FLOOR_UTGARDEKEEP3 = "Tyr's Terrace";
+DUNGEON_FLOOR_UTGARDEPINNACLE1 = "Lower Pinnacle";
+DUNGEON_FLOOR_UTGARDEPINNACLE2 = "Upper Pinnacle";
+DUNGEON_FLOOR_VAULTOFARCHAVON1 = "Vault of Archavon";
+DUNGEON_FLOOR_VIOLETHOLD1 = "The Violet Hold";
+DUNGEON_GROUP_FOUND_TOOLTIP = "A Dungeon group has been found.";
+DUNGEON_NAME_WITH_DIFFICULTY = "%1$s (%2$s)";
+DURABILITY = "Durability";
+DURABILITYDAMAGE_DEATH = "Your equipped items suffer a 10% durability loss.";
+DURABILITY_ABBR = "Dura";
+DURABILITY_TEMPLATE = "Durability %d / %d";
+DYNAMIC = "Dynamic";
+D_DAYS = "%d |4Day:Days;";
+D_HOURS = "%d |4Hour:Hours;";
+D_MINUTES = "%d |4Minute:Minutes;";
+D_SECONDS = "%d |4Second:Seconds;";
+EDIT_TICKET = "Save Changes";
+EFFECTS_LABEL = "Effects";
+EFFECTS_SUBTEXT = "These controls allow you to modify specific detail levels for many game elements and effects.";
+EJECT_PASSENGER = "Eject Passenger";
+ELITE = "Elite";
+EMBLEM_BACKGROUND = "Background";
+EMBLEM_BORDER = "Border";
+EMBLEM_BORDER_COLOR = "Border Color";
+EMBLEM_SYMBOL = "Icon";
+EMBLEM_SYMBOL_COLOR = "Icon Color";
+EMOTE = "Emote";
+EMOTE100_CMD1 = "/tired";
+EMOTE100_CMD2 = "/tired";
+EMOTE101_CMD = "/victory";
+EMOTE101_CMD1 = "/victory";
+EMOTE101_CMD2 = "/victory";
+EMOTE101_CMD3 = "/victory";
+EMOTE102_CMD1 = "/wave";
+EMOTE102_CMD2 = "/wave";
+EMOTE103_CMD1 = "/welcome";
+EMOTE103_CMD2 = "/welcome";
+EMOTE104_CMD1 = "/whine";
+EMOTE104_CMD2 = "/whine";
+EMOTE105_CMD1 = "/whistle";
+EMOTE105_CMD2 = "/whistle";
+EMOTE106_CMD1 = "/work";
+EMOTE106_CMD2 = "/work";
+EMOTE107_CMD1 = "/yawn";
+EMOTE107_CMD2 = "/yawn";
+EMOTE107_CMD3 = "/yawn";
+EMOTE108_CMD1 = "/boggle";
+EMOTE108_CMD2 = "/boggle";
+EMOTE109_CMD1 = "/calm";
+EMOTE109_CMD2 = "/calm";
+EMOTE109_CMD3 = "/calm";
+EMOTE10_CMD1 = "/bleed";
+EMOTE10_CMD2 = "/blood";
+EMOTE10_CMD3 = "/bleed";
+EMOTE10_CMD4 = "/blood";
+EMOTE110_CMD1 = "/cold";
+EMOTE110_CMD2 = "/cold";
+EMOTE111_CMD1 = "/comfort";
+EMOTE111_CMD2 = "/comfort";
+EMOTE112_CMD1 = "/cuddle";
+EMOTE112_CMD2 = "/spoon";
+EMOTE112_CMD3 = "/cuddle";
+EMOTE112_CMD4 = "/spoon";
+EMOTE113_CMD1 = "/duck";
+EMOTE113_CMD2 = "/duck";
+EMOTE114_CMD1 = "/insult";
+EMOTE114_CMD2 = "/insult";
+EMOTE114_CMD3 = "/insult";
+EMOTE115_CMD1 = "/introduce";
+EMOTE115_CMD2 = "/introduce";
+EMOTE116_CMD1 = "/jk";
+EMOTE116_CMD2 = "/jk";
+EMOTE117_CMD1 = "/lick";
+EMOTE117_CMD2 = "/lick";
+EMOTE118_CMD1 = "/listen";
+EMOTE118_CMD2 = "/listen";
+EMOTE119_CMD1 = "/lost";
+EMOTE119_CMD2 = "/lost";
+EMOTE11_CMD1 = "/blink";
+EMOTE11_CMD2 = "/blink";
+EMOTE120_CMD1 = "/mock";
+EMOTE120_CMD2 = "/mock";
+EMOTE121_CMD1 = "/ponder";
+EMOTE121_CMD2 = "/ponder";
+EMOTE122_CMD1 = "/pounce";
+EMOTE122_CMD2 = "/pounce";
+EMOTE123_CMD1 = "/praise";
+EMOTE123_CMD2 = "/lavish";
+EMOTE123_CMD3 = "/praise";
+EMOTE123_CMD4 = "/lavish";
+EMOTE124_CMD1 = "/purr";
+EMOTE124_CMD2 = "/purr";
+EMOTE125_CMD1 = "/puzzled";
+EMOTE125_CMD2 = "/puzzled";
+EMOTE126_CMD1 = "/raise";
+EMOTE126_CMD2 = "/volunteer";
+EMOTE126_CMD3 = "/raise";
+EMOTE126_CMD4 = "/volunteer";
+EMOTE127_CMD1 = "/ready";
+EMOTE127_CMD2 = "/rdy";
+EMOTE127_CMD3 = "/ready";
+EMOTE127_CMD4 = "/rdy";
+EMOTE128_CMD1 = "/shimmy";
+EMOTE128_CMD2 = "/shimmy";
+EMOTE129_CMD1 = "/shiver";
+EMOTE129_CMD2 = "/shiver";
+EMOTE12_CMD1 = "/blush";
+EMOTE12_CMD2 = "/blush";
+EMOTE130_CMD1 = "/shoo";
+EMOTE130_CMD2 = "/pest";
+EMOTE130_CMD3 = "/shoo";
+EMOTE130_CMD4 = "/pest";
+EMOTE131_CMD1 = "/slap";
+EMOTE131_CMD2 = "/slap";
+EMOTE132_CMD1 = "/smirk";
+EMOTE132_CMD2 = "/smirk";
+EMOTE133_CMD1 = "/sniff";
+EMOTE133_CMD2 = "/sniff";
+EMOTE134_CMD1 = "/snub";
+EMOTE134_CMD2 = "/snub";
+EMOTE135_CMD1 = "/soothe";
+EMOTE135_CMD2 = "/soothe";
+EMOTE136_CMD1 = "/stink";
+EMOTE136_CMD2 = "/smell";
+EMOTE136_CMD3 = "/stink";
+EMOTE136_CMD4 = "/smell";
+EMOTE137_CMD1 = "/taunt";
+EMOTE137_CMD2 = "/taunt";
+EMOTE138_CMD1 = "/tease";
+EMOTE138_CMD2 = "/tease";
+EMOTE139_CMD1 = "/thirsty";
+EMOTE139_CMD2 = "/thirsty";
+EMOTE13_CMD1 = "/bonk";
+EMOTE13_CMD2 = "/doh";
+EMOTE13_CMD3 = "/bonk";
+EMOTE13_CMD4 = "/doh";
+EMOTE140_CMD1 = "/veto";
+EMOTE140_CMD2 = "/veto";
+EMOTE141_CMD1 = "/snicker";
+EMOTE141_CMD2 = "/snicker";
+EMOTE142_CMD1 = "/tickle";
+EMOTE142_CMD2 = "/tickle";
+EMOTE143_CMD1 = "/stand";
+EMOTE143_CMD2 = "/stand";
+EMOTE144_CMD1 = "/violin";
+EMOTE144_CMD2 = "/violin";
+EMOTE145_CMD1 = "/smile";
+EMOTE145_CMD2 = "/smile";
+EMOTE146_CMD1 = "/rasp";
+EMOTE146_CMD2 = "/rasp";
+EMOTE147_CMD1 = "/growl";
+EMOTE147_CMD2 = "/growl";
+EMOTE148_CMD1 = "/bark";
+EMOTE148_CMD2 = "/bark";
+EMOTE149_CMD1 = "/pity";
+EMOTE149_CMD2 = "/pity";
+EMOTE14_CMD1 = "/bored";
+EMOTE14_CMD2 = "/bored";
+EMOTE150_CMD1 = "/scared";
+EMOTE150_CMD2 = "/scared";
+EMOTE151_CMD1 = "/flop";
+EMOTE151_CMD2 = "/flop";
+EMOTE152_CMD1 = "/love";
+EMOTE152_CMD2 = "/love";
+EMOTE153_CMD1 = "/moo";
+EMOTE153_CMD2 = "/moo";
+EMOTE154_CMD1 = "/commend";
+EMOTE154_CMD2 = "/commend";
+EMOTE155_CMD1 = "/train";
+EMOTE155_CMD2 = "/train";
+EMOTE156_CMD1 = "/helpme";
+EMOTE156_CMD2 = "/helpme";
+EMOTE157_CMD1 = "/incoming";
+EMOTE157_CMD2 = "/incoming";
+EMOTE158_CMD1 = "/openfire";
+EMOTE158_CMD2 = "/openfire";
+EMOTE159_CMD1 = "/charge";
+EMOTE159_CMD2 = "/charge";
+EMOTE15_CMD1 = "/bounce";
+EMOTE15_CMD2 = "/bounce";
+EMOTE160_CMD1 = "/flee";
+EMOTE160_CMD2 = "/flee";
+EMOTE161_CMD1 = "/attacktarget";
+EMOTE161_CMD2 = "/attacktarget";
+EMOTE162_CMD1 = "/oom";
+EMOTE162_CMD2 = "/oom";
+EMOTE163_CMD1 = "/followme";
+EMOTE163_CMD2 = "/followme";
+EMOTE164_CMD1 = "/wait";
+EMOTE164_CMD2 = "/wait";
+EMOTE165_CMD1 = "/flirt";
+EMOTE165_CMD2 = "/flirt";
+EMOTE166_CMD1 = "/healme";
+EMOTE166_CMD2 = "/healme";
+EMOTE167_CMD1 = "/silly";
+EMOTE167_CMD2 = "/silly";
+EMOTE168_CMD1 = "/wink";
+EMOTE168_CMD2 = "/wink";
+EMOTE169_CMD1 = "/pat";
+EMOTE169_CMD2 = "/pat";
+EMOTE16_CMD1 = "/brb";
+EMOTE16_CMD2 = "/brb";
+EMOTE170_CMD1 = "/golfclap";
+EMOTE170_CMD2 = "/golfclap";
+EMOTE171_CMD1 = "/mountspecial";
+EMOTE171_CMD2 = "/mountspecial";
+EMOTE17_CMD1 = "/bow";
+EMOTE17_CMD2 = "/bow";
+EMOTE18_CMD1 = "/burp";
+EMOTE18_CMD2 = "/belch";
+EMOTE18_CMD3 = "/burp";
+EMOTE18_CMD4 = "/belch";
+EMOTE19_CMD1 = "/bye";
+EMOTE19_CMD2 = "/goodbye";
+EMOTE19_CMD3 = "/farewell";
+EMOTE19_CMD4 = "/bye";
+EMOTE19_CMD5 = "/goodbye";
+EMOTE19_CMD6 = "/farewell";
+EMOTE1_CMD1 = "/agree";
+EMOTE1_CMD2 = "/agree";
+EMOTE20_CMD1 = "/cackle";
+EMOTE20_CMD2 = "/cackle";
+EMOTE21_CMD1 = "/cheer";
+EMOTE21_CMD2 = "/cheer";
+EMOTE21_CMD3 = "/woot";
+EMOTE21_CMD4 = "/woot";
+EMOTE22_CMD1 = "/chicken";
+EMOTE22_CMD2 = "/flap";
+EMOTE22_CMD3 = "/strut";
+EMOTE22_CMD4 = "/chicken";
+EMOTE22_CMD5 = "/flap";
+EMOTE22_CMD6 = "/strut";
+EMOTE23_CMD1 = "/chuckle";
+EMOTE23_CMD2 = "/chuckle";
+EMOTE24_CMD1 = "/clap";
+EMOTE24_CMD2 = "/clap";
+EMOTE25_CMD1 = "/confused";
+EMOTE25_CMD2 = "/confused";
+EMOTE26_CMD1 = "/congratulate";
+EMOTE26_CMD2 = "/congrats";
+EMOTE26_CMD3 = "/cong";
+EMOTE26_CMD4 = "/congratulate";
+EMOTE26_CMD5 = "/grats";
+EMOTE26_CMD6 = "/cong";
+EMOTE27_CMD1 = "/unused";
+EMOTE27_CMD2 = "/unused";
+EMOTE28_CMD1 = "/cough";
+EMOTE28_CMD2 = "/cough";
+EMOTE29_CMD1 = "/cower";
+EMOTE29_CMD2 = "/fear";
+EMOTE29_CMD3 = "/cower";
+EMOTE29_CMD4 = "/fear";
+EMOTE2_CMD1 = "/amaze";
+EMOTE2_CMD2 = "/amaze";
+EMOTE304_CMD1 = "/incoming";
+EMOTE304_CMD3 = "/incoming";
+EMOTE304_CMD4 = "/inc";
+EMOTE306_CMD1 = "/retreat";
+EMOTE306_CMD2 = "/retreat";
+EMOTE306_CMD3 = "/flee";
+EMOTE306_CMD4 = "/flee";
+EMOTE30_CMD1 = "/crack";
+EMOTE30_CMD2 = "/knuckles";
+EMOTE30_CMD3 = "/crack";
+EMOTE30_CMD4 = "/knuckles";
+EMOTE31_CMD1 = "/cringe";
+EMOTE31_CMD2 = "/cringe";
+EMOTE32_CMD1 = "/cry";
+EMOTE32_CMD2 = "/sob";
+EMOTE32_CMD3 = "/weep";
+EMOTE32_CMD4 = "/cry";
+EMOTE32_CMD5 = "/sob";
+EMOTE32_CMD6 = "/weep";
+EMOTE33_CMD1 = "/curious";
+EMOTE33_CMD2 = "/curious";
+EMOTE34_CMD1 = "/curtsey";
+EMOTE34_CMD2 = "/curtsey";
+EMOTE35_CMD1 = "/dance";
+EMOTE35_CMD2 = "/dance";
+EMOTE368_CMD1 = "/blame";
+EMOTE368_CMD2 = "/blame";
+EMOTE369_CMD1 = "/blank";
+EMOTE369_CMD2 = "/blank";
+EMOTE36_CMD1 = "/drink";
+EMOTE36_CMD2 = "/shindig";
+EMOTE36_CMD3 = "/drink";
+EMOTE36_CMD4 = "/shindig";
+EMOTE370_CMD1 = "/brandish";
+EMOTE370_CMD2 = "/brandish";
+EMOTE371_CMD1 = "/breath";
+EMOTE371_CMD2 = "/breath";
+EMOTE372_CMD1 = "/disagree";
+EMOTE372_CMD2 = "/disagree";
+EMOTE373_CMD1 = "/doubt";
+EMOTE373_CMD2 = "/doubt";
+EMOTE374_CMD1 = "/embarrass";
+EMOTE374_CMD2 = "/embarrass";
+EMOTE375_CMD1 = "/encourage";
+EMOTE375_CMD2 = "/encourage";
+EMOTE376_CMD1 = "/enemy";
+EMOTE376_CMD2 = "/enemy";
+EMOTE377_CMD1 = "/eyebrow";
+EMOTE377_CMD2 = "/eyebrow";
+EMOTE377_CMD3 = "/brow";
+EMOTE377_CMD4 = "/brow";
+EMOTE37_CMD1 = "/drool";
+EMOTE37_CMD2 = "/drool";
+EMOTE380_CMD1 = "/highfive";
+EMOTE380_CMD2 = "/highfive";
+EMOTE381_CMD1 = "/absent";
+EMOTE381_CMD2 = "/absent";
+EMOTE382_CMD1 = "/arm";
+EMOTE382_CMD2 = "/arm";
+EMOTE383_CMD1 = "/awe";
+EMOTE383_CMD2 = "/awe";
+EMOTE384_CMD1 = "/backpack";
+EMOTE384_CMD2 = "/backpack";
+EMOTE384_CMD3 = "/pack";
+EMOTE384_CMD4 = "/pack";
+EMOTE385_CMD1 = "/badfeeling";
+EMOTE385_CMD2 = "/badfeeling";
+EMOTE385_CMD3 = "/bad";
+EMOTE385_CMD4 = "/bad";
+EMOTE386_CMD1 = "/challenge";
+EMOTE386_CMD2 = "/challenge";
+EMOTE387_CMD1 = "/chug";
+EMOTE387_CMD2 = "/chug";
+EMOTE389_CMD1 = "/ding";
+EMOTE389_CMD2 = "/ding";
+EMOTE38_CMD1 = "/eat";
+EMOTE38_CMD2 = "/chew";
+EMOTE38_CMD3 = "/feast";
+EMOTE38_CMD4 = "/eat";
+EMOTE38_CMD5 = "/chew";
+EMOTE38_CMD6 = "/feast";
+EMOTE390_CMD1 = "/facepalm";
+EMOTE390_CMD2 = "/facepalm";
+EMOTE390_CMD3 = "/palm";
+EMOTE390_CMD4 = "/palm";
+EMOTE391_CMD1 = "/faint";
+EMOTE391_CMD2 = "/faint";
+EMOTE392_CMD1 = "/go";
+EMOTE392_CMD2 = "/go";
+EMOTE393_CMD1 = "/going";
+EMOTE393_CMD2 = "/going";
+EMOTE394_CMD1 = "/glower";
+EMOTE394_CMD2 = "/glower";
+EMOTE395_CMD1 = "/headache";
+EMOTE395_CMD2 = "/headache";
+EMOTE396_CMD1 = "/hiccup";
+EMOTE396_CMD2 = "/hiccup";
+EMOTE398_CMD1 = "/hiss";
+EMOTE398_CMD2 = "/hiss";
+EMOTE399_CMD1 = "/holdhand";
+EMOTE399_CMD2 = "/holdhand";
+EMOTE39_CMD1 = "/eye";
+EMOTE39_CMD2 = "/eye";
+EMOTE3_CMD1 = "/angry";
+EMOTE3_CMD2 = "/mad";
+EMOTE3_CMD3 = "/angry";
+EMOTE3_CMD4 = "/mad";
+EMOTE401_CMD1 = "/hurry";
+EMOTE401_CMD2 = "/hurry";
+EMOTE402_CMD1 = "/idea";
+EMOTE402_CMD2 = "/idea";
+EMOTE403_CMD1 = "/jealous";
+EMOTE403_CMD2 = "/jealous";
+EMOTE404_CMD1 = "/luck";
+EMOTE404_CMD2 = "/luck";
+EMOTE405_CMD1 = "/map";
+EMOTE405_CMD2 = "/map";
+EMOTE406_CMD1 = "/mercy";
+EMOTE406_CMD2 = "/mercy";
+EMOTE407_CMD1 = "/mutter";
+EMOTE407_CMD2 = "/mutter";
+EMOTE408_CMD1 = "/nervous";
+EMOTE408_CMD2 = "/nervous";
+EMOTE409_CMD1 = "/offer";
+EMOTE409_CMD2 = "/offer";
+EMOTE40_CMD1 = "/fart";
+EMOTE40_CMD2 = "/fart";
+EMOTE410_CMD1 = "/pet";
+EMOTE410_CMD2 = "/pet";
+EMOTE411_CMD1 = "/pinch";
+EMOTE411_CMD2 = "/pinch";
+EMOTE413_CMD1 = "/proud";
+EMOTE413_CMD2 = "/proud";
+EMOTE414_CMD1 = "/promise";
+EMOTE414_CMD2 = "/promise";
+EMOTE415_CMD1 = "/pulse";
+EMOTE415_CMD2 = "/pulse";
+EMOTE416_CMD1 = "/punch";
+EMOTE416_CMD2 = "/punch";
+EMOTE417_CMD1 = "/pout";
+EMOTE417_CMD2 = "/pout";
+EMOTE418_CMD1 = "/regret";
+EMOTE418_CMD2 = "/regret";
+EMOTE41_CMD1 = "/fidget";
+EMOTE41_CMD2 = "/impatient";
+EMOTE41_CMD3 = "/fidget";
+EMOTE41_CMD4 = "/impatient";
+EMOTE420_CMD1 = "/revenge";
+EMOTE420_CMD2 = "/revenge";
+EMOTE421_CMD1 = "/rolleyes";
+EMOTE421_CMD2 = "/rolleyes";
+EMOTE421_CMD3 = "/eyeroll";
+EMOTE421_CMD4 = "/eyeroll";
+EMOTE422_CMD1 = "/ruffle";
+EMOTE422_CMD2 = "/ruffle";
+EMOTE423_CMD1 = "/sad";
+EMOTE423_CMD2 = "/sad";
+EMOTE424_CMD1 = "/scoff";
+EMOTE424_CMD2 = "/scoff";
+EMOTE425_CMD1 = "/scold";
+EMOTE425_CMD2 = "/scold";
+EMOTE426_CMD1 = "/scowl";
+EMOTE426_CMD2 = "/scowl";
+EMOTE427_CMD1 = "/search";
+EMOTE427_CMD2 = "/search";
+EMOTE428_CMD1 = "/shakefist";
+EMOTE428_CMD2 = "/shakefist";
+EMOTE428_CMD3 = "/fist";
+EMOTE428_CMD4 = "/fist";
+EMOTE429_CMD1 = "/shifty";
+EMOTE429_CMD2 = "/shifty";
+EMOTE42_CMD1 = "/flex";
+EMOTE42_CMD2 = "/strong";
+EMOTE42_CMD3 = "/flex";
+EMOTE42_CMD4 = "/strong";
+EMOTE430_CMD1 = "/shudder";
+EMOTE430_CMD2 = "/shudder";
+EMOTE431_CMD1 = "/signal";
+EMOTE431_CMD2 = "/signal";
+EMOTE432_CMD1 = "/silence";
+EMOTE432_CMD2 = "/silence";
+EMOTE432_CMD3 = "/shush";
+EMOTE432_CMD4 = "/shush";
+EMOTE433_CMD1 = "/sing";
+EMOTE433_CMD2 = "/sing";
+EMOTE434_CMD1 = "/smack";
+EMOTE434_CMD2 = "/smack";
+EMOTE435_CMD1 = "/sneak";
+EMOTE435_CMD2 = "/sneak";
+EMOTE436_CMD1 = "/sneeze";
+EMOTE436_CMD2 = "/sneeze";
+EMOTE437_CMD1 = "/snort";
+EMOTE437_CMD2 = "/snort";
+EMOTE438_CMD1 = "/squeal";
+EMOTE438_CMD2 = "/squeal";
+EMOTE43_CMD1 = "/frown";
+EMOTE43_CMD2 = "/disappointed";
+EMOTE43_CMD3 = "/disappointment";
+EMOTE43_CMD4 = "/frown";
+EMOTE43_CMD5 = "/disappointed";
+EMOTE43_CMD6 = "/disappointment";
+EMOTE440_CMD1 = "/suspicious";
+EMOTE440_CMD2 = "/suspicious";
+EMOTE441_CMD1 = "/think";
+EMOTE441_CMD2 = "/think";
+EMOTE442_CMD1 = "/truce";
+EMOTE442_CMD2 = "/truce";
+EMOTE443_CMD1 = "/twiddle";
+EMOTE443_CMD2 = "/twiddle";
+EMOTE444_CMD1 = "/warn";
+EMOTE444_CMD2 = "/warn";
+EMOTE445_CMD1 = "/snap";
+EMOTE445_CMD2 = "/snap";
+EMOTE446_CMD1 = "/charm";
+EMOTE446_CMD2 = "/charm";
+EMOTE447_CMD1 = "/coverears";
+EMOTE447_CMD2 = "/coverears";
+EMOTE448_CMD1 = "/crossarms";
+EMOTE448_CMD2 = "/crossarms";
+EMOTE449_CMD1 = "/look";
+EMOTE449_CMD2 = "/look";
+EMOTE44_CMD1 = "/gasp";
+EMOTE44_CMD2 = "/gasp";
+EMOTE44_CMD3 = "/gasp";
+EMOTE450_CMD1 = "/object";
+EMOTE450_CMD2 = "/object";
+EMOTE450_CMD3 = "/objection";
+EMOTE450_CMD4 = "/objection";
+EMOTE450_CMD5 = "/holdit";
+EMOTE450_CMD6 = "/holdit";
+EMOTE451_CMD1 = "/sweat";
+EMOTE451_CMD2 = "/sweat";
+EMOTE452_CMD1 = "/yw";
+EMOTE452_CMD2 = "/yw";
+EMOTE45_CMD1 = "/gaze";
+EMOTE45_CMD2 = "/gaze";
+EMOTE46_CMD1 = "/giggle";
+EMOTE46_CMD2 = "/giggle";
+EMOTE47_CMD1 = "/glare";
+EMOTE47_CMD2 = "/glare";
+EMOTE48_CMD1 = "/gloat";
+EMOTE48_CMD2 = "/gloat";
+EMOTE49_CMD1 = "/greet";
+EMOTE49_CMD2 = "/greetings";
+EMOTE49_CMD3 = "/greet";
+EMOTE49_CMD4 = "/greetings";
+EMOTE4_CMD1 = "/apologize";
+EMOTE4_CMD2 = "/sorry";
+EMOTE4_CMD3 = "/apologize";
+EMOTE4_CMD4 = "/sorry";
+EMOTE50_CMD1 = "/grin";
+EMOTE50_CMD2 = "/wicked";
+EMOTE50_CMD3 = "/wickedly";
+EMOTE50_CMD4 = "/grin";
+EMOTE50_CMD5 = "/wicked";
+EMOTE50_CMD6 = "/wickedly";
+EMOTE51_CMD1 = "/groan";
+EMOTE51_CMD2 = "/groan";
+EMOTE52_CMD1 = "/grovel";
+EMOTE52_CMD2 = "/peon";
+EMOTE52_CMD3 = "/grovel";
+EMOTE52_CMD4 = "/peon";
+EMOTE53_CMD1 = "/guffaw";
+EMOTE53_CMD2 = "/guffaw";
+EMOTE54_CMD1 = "/hail";
+EMOTE54_CMD2 = "/hail";
+EMOTE55_CMD1 = "/happy";
+EMOTE55_CMD2 = "/glad";
+EMOTE55_CMD3 = "/yay";
+EMOTE55_CMD4 = "/happy";
+EMOTE55_CMD5 = "/glad";
+EMOTE55_CMD6 = "/yay";
+EMOTE56_CMD1 = "/hello";
+EMOTE56_CMD2 = "/hi";
+EMOTE56_CMD3 = "/hello";
+EMOTE56_CMD4 = "/hi";
+EMOTE57_CMD1 = "/hug";
+EMOTE57_CMD2 = "/hug";
+EMOTE58_CMD1 = "/hungry";
+EMOTE58_CMD2 = "/food";
+EMOTE58_CMD3 = "/hungry";
+EMOTE58_CMD4 = "/food";
+EMOTE58_CMD5 = "/pizza";
+EMOTE58_CMD6 = "/pizza";
+EMOTE59_CMD1 = "/kiss";
+EMOTE59_CMD2 = "/blow";
+EMOTE59_CMD3 = "/kiss";
+EMOTE59_CMD4 = "/blow";
+EMOTE5_CMD1 = "/applaud";
+EMOTE5_CMD2 = "/bravo";
+EMOTE5_CMD3 = "/applause";
+EMOTE5_CMD4 = "/applaud";
+EMOTE5_CMD5 = "/bravo";
+EMOTE5_CMD6 = "/applause";
+EMOTE60_CMD1 = "/kneel";
+EMOTE60_CMD2 = "/kneel";
+EMOTE60_CMD3 = "/kneel";
+EMOTE61_CMD1 = "/laugh";
+EMOTE61_CMD2 = "/lol";
+EMOTE61_CMD3 = "/laugh";
+EMOTE61_CMD4 = "/lol";
+EMOTE62_CMD1 = "/laydown";
+EMOTE62_CMD2 = "/liedown";
+EMOTE62_CMD3 = "/lay";
+EMOTE62_CMD4 = "/lie";
+EMOTE62_CMD5 = "/laydown";
+EMOTE62_CMD6 = "/liedown";
+EMOTE62_CMD7 = "/lay";
+EMOTE62_CMD8 = "/lie";
+EMOTE63_CMD1 = "/massage";
+EMOTE63_CMD2 = "/massage";
+EMOTE64_CMD1 = "/moan";
+EMOTE64_CMD2 = "/moan";
+EMOTE65_CMD1 = "/moon";
+EMOTE65_CMD2 = "/moon";
+EMOTE66_CMD1 = "/mourn";
+EMOTE66_CMD2 = "/mourn";
+EMOTE67_CMD1 = "/no";
+EMOTE67_CMD2 = "/no";
+EMOTE68_CMD1 = "/nod";
+EMOTE68_CMD2 = "/yes";
+EMOTE68_CMD3 = "/nod";
+EMOTE68_CMD4 = "/yes";
+EMOTE69_CMD1 = "/nosepick";
+EMOTE69_CMD2 = "/pick";
+EMOTE69_CMD3 = "/nosepick";
+EMOTE69_CMD4 = "/pick";
+EMOTE6_CMD1 = "/bashful";
+EMOTE6_CMD2 = "/bashful";
+EMOTE70_CMD1 = "/panic";
+EMOTE70_CMD2 = "/panic";
+EMOTE71_CMD1 = "/peer";
+EMOTE71_CMD2 = "/peer";
+EMOTE72_CMD1 = "/plead";
+EMOTE72_CMD2 = "/plead";
+EMOTE73_CMD1 = "/point";
+EMOTE73_CMD2 = "/point";
+EMOTE74_CMD1 = "/poke";
+EMOTE74_CMD2 = "/poke";
+EMOTE75_CMD1 = "/pray";
+EMOTE75_CMD2 = "/pray";
+EMOTE76_CMD1 = "/roar";
+EMOTE76_CMD2 = "/roar";
+EMOTE76_CMD3 = "/rawr";
+EMOTE76_CMD4 = "/rawr";
+EMOTE77_CMD1 = "/rofl";
+EMOTE77_CMD2 = "/rofl";
+EMOTE78_CMD1 = "/rude";
+EMOTE78_CMD2 = "/rude";
+EMOTE79_CMD1 = "/salute";
+EMOTE79_CMD2 = "/salute";
+EMOTE7_CMD1 = "/beckon";
+EMOTE7_CMD2 = "/beckon";
+EMOTE80_CMD1 = "/scratch";
+EMOTE80_CMD2 = "/cat";
+EMOTE80_CMD3 = "/catty";
+EMOTE80_CMD4 = "/scratch";
+EMOTE80_CMD5 = "/cat";
+EMOTE80_CMD6 = "/catty";
+EMOTE81_CMD1 = "/sexy";
+EMOTE81_CMD2 = "/sexy";
+EMOTE82_CMD1 = "/shake";
+EMOTE82_CMD2 = "/rear";
+EMOTE82_CMD3 = "/shake";
+EMOTE82_CMD4 = "/rear";
+EMOTE83_CMD1 = "/shout";
+EMOTE83_CMD2 = "/holler";
+EMOTE83_CMD3 = "/holler";
+EMOTE84_CMD1 = "/shrug";
+EMOTE84_CMD2 = "/shrug";
+EMOTE85_CMD1 = "/shy";
+EMOTE85_CMD2 = "/shy";
+EMOTE86_CMD1 = "/sigh";
+EMOTE86_CMD2 = "/sigh";
+EMOTE87_CMD1 = "/sit";
+EMOTE87_CMD2 = "/sit";
+EMOTE88_CMD1 = "/sleep";
+EMOTE88_CMD2 = "/sleep";
+EMOTE89_CMD1 = "/snarl";
+EMOTE89_CMD2 = "/snarl";
+EMOTE8_CMD1 = "/beg";
+EMOTE8_CMD2 = "/beg";
+EMOTE90_CMD1 = "/spit";
+EMOTE90_CMD2 = "/spit";
+EMOTE91_CMD1 = "/stare";
+EMOTE91_CMD2 = "/stare";
+EMOTE92_CMD1 = "/surprised";
+EMOTE92_CMD2 = "/surprised";
+EMOTE93_CMD1 = "/surrender";
+EMOTE93_CMD2 = "/surrender";
+EMOTE94_CMD1 = "/talk";
+EMOTE94_CMD2 = "/talk";
+EMOTE95_CMD1 = "/talkex";
+EMOTE95_CMD2 = "/excited";
+EMOTE95_CMD3 = "/talkex";
+EMOTE95_CMD4 = "/excited";
+EMOTE96_CMD1 = "/talkq";
+EMOTE96_CMD2 = "/question";
+EMOTE96_CMD3 = "/talkq";
+EMOTE96_CMD4 = "/question";
+EMOTE97_CMD1 = "/tap";
+EMOTE97_CMD2 = "/tap";
+EMOTE98_CMD1 = "/thank";
+EMOTE98_CMD2 = "/thanks";
+EMOTE98_CMD3 = "/ty";
+EMOTE98_CMD4 = "/thank";
+EMOTE98_CMD5 = "/thanks";
+EMOTE98_CMD6 = "/ty";
+EMOTE99_CMD1 = "/threaten";
+EMOTE99_CMD2 = "/doom";
+EMOTE99_CMD3 = "/threat";
+EMOTE99_CMD4 = "/wrath";
+EMOTE99_CMD5 = "/threaten";
+EMOTE99_CMD6 = "/doom";
+EMOTE99_CMD7 = "/threat";
+EMOTE99_CMD8 = "/wrath";
+EMOTE9_CMD1 = "/bite";
+EMOTE9_CMD2 = "/bite";
+EMOTE_MESSAGE = "Emote";
+EMOTE_STATE_KNEEL = "/kneel";
+EMPTY = "Empty";
+EMPTY_SOCKET = "Level %d Socket";
+EMPTY_SOCKET_BLUE = "Blue Socket";
+EMPTY_SOCKET_META = "Meta Socket";
+EMPTY_SOCKET_NO_COLOR = "Prismatic Socket";
+EMPTY_SOCKET_RED = "Red Socket";
+EMPTY_SOCKET_YELLOW = "Yellow Socket";
+EMPTY_STABLE_SLOT = "Empty Stable Slot";
+ENABLE = "Enable";
+ENABLE_ALL_SHADERS = "Enable All Shader Effects";
+ENABLE_AMBIENCE = "Ambient Sounds";
+ENABLE_BGSOUND = "Sound in Background";
+ENABLE_DSP_EFFECTS = "Death Knight Voices";
+ENABLE_EMOTE_SOUNDS = "Emote Sounds";
+ENABLE_ERROR_SPEECH = "Error Speech";
+ENABLE_GROUP_SPEECH = "Enable Group Speech";
+ENABLE_HARDWARE = "Use Hardware";
+ENABLE_MICROPHONE = "Enable Microphone";
+ENABLE_MUSIC = "Music";
+ENABLE_MUSIC_LOOPING = "Loop Music";
+ENABLE_PET_SOUNDS = "Enable Pet Sounds";
+ENABLE_REVERB = "Enable Reverb";
+ENABLE_SOFTWARE_HRTF = "Headphone mode";
+ENABLE_SOUND = "Enable Sound";
+ENABLE_SOUNDFX = "Sound Effects";
+ENABLE_SOUND_AT_CHARACTER = "Sound at Character";
+ENABLE_STEREO_VIDEO = "Enable Stereo Video";
+ENABLE_TUTORIAL_TEXT = "Auto Open Tutorials";
+ENABLE_VOICECHAT = "Enable Voice Chat";
+ENCHANTS = "Enchants";
+ENCHANT_AURA_COMBATLOG_TOOLTIP = "Show when a weapon enchantment is gained or removed.";
+ENCHANT_CONDITION_AND = " and\32";
+ENCHANT_CONDITION_EQUAL_COMPARE = "an equal number of %s and %s gems";
+ENCHANT_CONDITION_EQUAL_VALUE = "exactly %d %s |4gem:gems;";
+ENCHANT_CONDITION_LESS_VALUE = "less than %d %s |4gem:gems;";
+ENCHANT_CONDITION_MORE_COMPARE = "more %s gems than %s gems";
+ENCHANT_CONDITION_MORE_EQUAL_COMPARE = "at least as many %s gems as %s gems";
+ENCHANT_CONDITION_MORE_VALUE = "at least %d %s |4gem:gems;";
+ENCHANT_CONDITION_NOT_EQUAL_COMPARE = "a different number of %s and %s gems";
+ENCHANT_CONDITION_NOT_EQUAL_VALUE = "any number but %d %s |4gem:gems;";
+ENCHANT_CONDITION_REQUIRES = "Requires\32";
+ENCHANT_ITEM_MIN_SKILL = "Enchantment Requires %s (%d)";
+ENCHANT_ITEM_REQ_LEVEL = "Enchantment Requires Level %d";
+ENCHANT_ITEM_REQ_SKILL = "Enchantment Requires %s";
+ENCHANT_SLOT = "Enchant/Unlock Slot";
+ENCHSLOT_2HWEAPON = "2H Weapon";
+ENCHSLOT_WEAPON = "Weapon";
+ENCLOSED_MONEY = "Enclosed amount";
+ENCN = "Simplified Chinese (English speech)";
+ENCRYPTED = "Encrypted";
+END_BOUND_TRADEABLE = "Performing this action will make this item non-tradeable.";
+END_REFUND = "Performing this action will make this item non-refundable";
+ENEMY = "Enemy";
+ENERGY = "Energy";
+ENERGY_COST = "%d Energy";
+ENERGY_COST_PER_TIME = "%d Energy, plus %d per sec";
+ENGB = "English (EU)";
+ENSCRIBE = "Enchant";
+ENTERING_COMBAT = "Entering Combat";
+ENTER_BATTLE = "Enter Battle";
+ENTER_CODE = "Please enter code:";
+ENTER_DUNGEON = "Enter Dungeon";
+ENTER_FILTER_NAME = "Enter filter name:";
+ENTER_INVITE_NOTE = "Include a message for your friend (optional)";
+ENTER_MACRO_LABEL = "Enter Macro Commands:";
+ENTER_NAME_OR_EMAIL = "Enter email address or character's name";
+ENTIRE_LINE = "Entire Line";
+ENTIRE_LINE_COMBATLOG_TOOLTIP = "Color the entire line based on the selection below.";
+ENTW = "Traditional Chinese (English speech)";
+ENUS = "English (US)";
+ENVIRONMENTAL_DAMAGE = "Environmental Damage";
+ENVIRONMENTAL_DAMAGE_COMBATLOG_TOOLTIP = "Show messages when someone takes damage from falling, drowning or swimming in lava.";
+ENVIRONMENT_DETAIL = "Environment Detail";
+EQUIPMENT_MANAGER = "Equipment Manager";
+EQUIPMENT_MANAGER_BAGS_FULL = "Equipment swap failed. Inventory is full.";
+EQUIPMENT_MANAGER_COMBAT_SWAP = "Some items from set %s cannot be swapped because you are in combat.";
+EQUIPMENT_MANAGER_IGNORE_SLOT = "Ignore This Slot";
+EQUIPMENT_MANAGER_IS_DISABLED = "The Equipment Manager is disabled.";
+EQUIPMENT_MANAGER_ITEMS_MISSING_TOOLTIP = "%d %s |cffff0000(%d missing)";
+EQUIPMENT_MANAGER_MISSING_ITEM = "One or more items from set %s were missing and could not be equipped.";
+EQUIPMENT_MANAGER_PLACE_IN_BAGS = "Place In Bags";
+EQUIPMENT_MANAGER_UNIGNORE_SLOT = "Include This Slot";
+EQUIPMENT_SETS = "Equipment Sets: |cFFFFFFFF%s|r";
+EQUIPMENT_SETS_TOO_MANY = "You cannot create any more new equipment sets.";
+EQUIPSET_EQUIP = "Equip";
+EQUIP_CONTAINER = "Equip Container";
+EQUIP_NO_DROP = "Equipping this item will bind it to you.";
+ERRORS = "Errors";
+ERROR_CANNOT_BIND = "|cffff0000Error! Cannot bind that button!|r";
+ERROR_CAPS = "ERROR";
+ERROR_SLASH_CHANGEACTIONBAR = "Appropriate format is /changeactionbar x where x is an action bar page number in the range %d to %d.";
+ERROR_SLASH_EQUIP_TO_SLOT = "Appropriate format is /equipslot x [item name] where x is an equippable item slot in the range %d to %d.";
+ERROR_SLASH_LOOT_SETTHRESHOLD = "Appropriate format is /threshold [item quality name] or /threshold x where x is an item quality number between %d and %d.";
+ERROR_SLASH_SWAPACTIONBAR = "Appropriate format is /swapactionbar x y where x and y are action bar page numbers in the range %d to %d.";
+ERROR_SLASH_TEAM_CAPTAIN = "Appropriate format is /teamcaptain [2v2, 3v3, 5v5] [player name]";
+ERROR_SLASH_TEAM_DISBAND = "Appropriate format is /teamdisband [2v2, 3v3, 5v5]";
+ERROR_SLASH_TEAM_INVITE = "Appropriate format is /teaminvite [2v2, 3v3, 5v5] [player name]";
+ERROR_SLASH_TEAM_QUIT = "Appropriate format is /teamquit [2v2, 3v3, 5v5]";
+ERROR_SLASH_TEAM_UNINVITE = "Appropriate format is /teamremove [2v2, 3v3, 5v5] [player name]";
+ERR_2HANDED_EQUIPPED = "Cannot equip that with a two-handed weapon.";
+ERR_2HSKILLNOTFOUND = "You cannot dual-wield";
+ERR_ABILITY_COOLDOWN = "Ability is not ready yet.";
+ERR_ACHIEVEMENT_WATCH_COMPLETED = "This achievement has already been completed.";
+ERR_ALREADY_INVITED_TO_ARENA_TEAM_S = "%s has already been invited to an arena team.";
+ERR_ALREADY_INVITED_TO_GUILD_S = "%s has already been invited to a guild.";
+ERR_ALREADY_IN_ARENA_TEAM = "You are already in an arena team of that size.";
+ERR_ALREADY_IN_ARENA_TEAM_S = "%s is already in an arena team of that size.";
+ERR_ALREADY_IN_GROUP_S = "%s is already in a group.";
+ERR_ALREADY_IN_GUILD = "You are already in a guild.";
+ERR_ALREADY_IN_GUILD_S = "%s is already in a guild.";
+ERR_ALREADY_PICKPOCKETED = "Your target has already had its pockets picked";
+ERR_ALREADY_QUEUED_FOR_SOMETHING_ELSE = "You are already queued for something else.";
+ERR_ALREADY_TRADING = "You are already trading";
+ERR_AMMO_ONLY = "Only ammo can go there.";
+ERR_APPROACHING_NO_PLAY_TIME = "You have %s until you enter unhealthy time, at which point you will no longer receive experience or loot until you have logged out for 5 hours.";
+ERR_APPROACHING_NO_PLAY_TIME_2 = "You are in tired time, and your benefits have been reduced to 50% of normal. For the sake of your own health, please go offline and rest, do some exercise, and arrange your time properly.";
+ERR_APPROACHING_PARTIAL_PLAY_TIME = "You have %s until you enter tired time. Your rewards will be cut in half.";
+ERR_APPROACHING_PARTIAL_PLAY_TIME_2 = "Your accumulated online time is %s hours.";
+ERR_ARENA_EXPIRED_CAIS = "You may not queue while one or more of your team members is under the effect of restricted play.";
+ERR_ARENA_NO_TEAM_II = "You are not in a %dv%d arena team.";
+ERR_ARENA_TEAMS_LOCKED = "Arena teams are currently locked.";
+ERR_ARENA_TEAM_CHANGE_FAILED_QUEUED = "Can't modify arena team while queued or in a match.";
+ERR_ARENA_TEAM_CREATE_S = "%s created. To disband, use /teamdisband [2v2, 3v3, 5v5].";
+ERR_ARENA_TEAM_DISBANDED_S = "%s has disbanded %s.";
+ERR_ARENA_TEAM_FOUNDER_S = "Congratulations, you are a founding member of %s! To leave, use /teamquit [2v2, 3v3, 5v5].";
+ERR_ARENA_TEAM_INTERNAL = "Internal arena team error";
+ERR_ARENA_TEAM_INVITE_SS = "You have invited %s to join %s.";
+ERR_ARENA_TEAM_JOIN_SS = "%s has joined %s.";
+ERR_ARENA_TEAM_LEADER_CHANGED_SSS = "%s has made %s the new captain of %s.";
+ERR_ARENA_TEAM_LEADER_IS_SS = "%s is the captain of %s.";
+ERR_ARENA_TEAM_LEADER_LEAVE_S = "You must promote a new team captain using /teamcaptain before leaving the team.";
+ERR_ARENA_TEAM_LEAVE_SS = "%s has left %s.";
+ERR_ARENA_TEAM_LEVEL_TOO_LOW_I = "You must be level %d to form an arena team.";
+ERR_ARENA_TEAM_NAME_EXISTS_S = "There is already an arena team named \"%s\".";
+ERR_ARENA_TEAM_NAME_INVALID = "That name contains invalid characters, please enter a new name.";
+ERR_ARENA_TEAM_NOT_ALLIED = "You cannot invite players from the opposing alliance.";
+ERR_ARENA_TEAM_NOT_FOUND = "That arena team has gone offline.";
+ERR_ARENA_TEAM_PARTY_SIZE = "Incorrect party size for this arena.";
+ERR_ARENA_TEAM_PERMISSIONS = "You don't have permission to do that.";
+ERR_ARENA_TEAM_PLAYER_NOT_FOUND_S = "\"%s\" not found.";
+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM = "You are not in an arena team of that size.";
+ERR_ARENA_TEAM_PLAYER_NOT_IN_TEAM_SS = "%s is not in %s.";
+ERR_ARENA_TEAM_QUIT_S = "You are no longer a member of %s.";
+ERR_ARENA_TEAM_REMOVE_SSS = "%s has been kicked out of %s by %s.";
+ERR_ARENA_TEAM_TARGET_TOO_HIGH_S = "%s's level is too high to join your team.";
+ERR_ARENA_TEAM_TARGET_TOO_LOW_S = "%s is not high enough level to join your team.";
+ERR_ARENA_TEAM_TOO_MANY_MEMBERS_S = "%s is full.";
+ERR_ARENA_TEAM_YOU_JOIN_S = "You have joined %s. To leave, use /teamquit [2v2, 3v3, 5v5].";
+ERR_ATTACK_CHANNEL = "Can't attack while channeling.";
+ERR_ATTACK_CHARMED = "Can't attack while charmed.";
+ERR_ATTACK_CONFUSED = "Can't attack while confused.";
+ERR_ATTACK_DEAD = "Can't attack while dead.";
+ERR_ATTACK_FLEEING = "Can't attack while fleeing.";
+ERR_ATTACK_MOUNTED = "Can't attack while mounted.";
+ERR_ATTACK_PACIFIED = "Can't attack while pacified.";
+ERR_ATTACK_PREVENTED_BY_MECHANIC_S = "Can't attack while %s.";
+ERR_ATTACK_STUNNED = "Can't attack while stunned.";
+ERR_AUCTION_BAG = "You cannot sell a non-empty bag.";
+ERR_AUCTION_BID_INCREMENT = "Your bid increment is too small.";
+ERR_AUCTION_BID_OWN = "You cannot bid on your own auction.";
+ERR_AUCTION_BID_PLACED = "Bid accepted.";
+ERR_AUCTION_BOUND_ITEM = "You cannot sell a soulbound item.";
+ERR_AUCTION_CONJURED_ITEM = "You cannot auction a conjured item.";
+ERR_AUCTION_DATABASE_ERROR = "Internal auction error.";
+ERR_AUCTION_ENOUGH_ITEMS = "You do not have enough items.";
+ERR_AUCTION_EXPIRED_S = "Your auction of %s has expired.";
+ERR_AUCTION_HIGHER_BID = "There is already a higher bid on that item.";
+ERR_AUCTION_HOUSE_DISABLED = "The auction house is closed at the moment.|nPlease try again later.";
+ERR_AUCTION_LIMITED_DURATION_ITEM = "You cannot auction items with a limited duration.";
+ERR_AUCTION_LOOT_ITEM = "You cannot auction a lootable item.";
+ERR_AUCTION_MIN_BID = "You must meet the min bid.";
+ERR_AUCTION_OUTBID_S = "You have been outbid on %s.";
+ERR_AUCTION_QUEST_ITEM = "You cannot sell a quest item.";
+ERR_AUCTION_REMOVED = "Auction cancelled.";
+ERR_AUCTION_REMOVED_S = "Your auction of %s has been cancelled by the seller.";
+ERR_AUCTION_REPAIR_ITEM = "You must repair that item before you auction it.";
+ERR_AUCTION_SOLD_S = "A buyer has been found for your auction of %s.";
+ERR_AUCTION_STARTED = "Auction created.";
+ERR_AUCTION_USED_CHARGES = "You cannot auction an item with used charges";
+ERR_AUCTION_WON_S = "You won an auction for %s";
+ERR_AUCTION_WRAPPED_ITEM = "You cannot auction a wrapped item.";
+ERR_AUTOFOLLOW_TOO_FAR = "Target is too far away.";
+ERR_AUTOLOOT_MONEY_S = "You loot %s";
+ERR_BADATTACKFACING = "You are facing the wrong way!";
+ERR_BADATTACKPOS = "You are too far away!";
+ERR_BAD_ON_USE_ENCHANT = "That item already has an activated ability";
+ERR_BAD_PLAYER_NAME_S = "Cannot find player '%s'.";
+ERR_BAG_FULL = "That bag is full.";
+ERR_BAG_IN_BAG = "Can't put non-empty bags in other bags.";
+ERR_BANKSLOT_FAILED_TOO_MANY = "You've reached your limit of bag slots!";
+ERR_BANKSLOT_INSUFFICIENT_FUNDS = "You can't afford that.";
+ERR_BANKSLOT_NOTBANKER = "That unit is not a banker!";
+ERR_BANK_FULL = "Your bank is full";
+ERR_BATTLEDGROUND_QUEUED_FOR_RATED = "You cannot queue for another battle while queued for a rated arena match";
+ERR_BATTLEGROUND_ALREADY_IN = "You are already in that battleground.";
+ERR_BATTLEGROUND_CANNOT_QUEUE_FOR_RATED = "You cannot queue for a rated match while queued for other battles";
+ERR_BATTLEGROUND_INFO_THROTTLED = "You can't do that yet";
+ERR_BATTLEGROUND_JOIN_FAILED = "Join as a group failed";
+ERR_BATTLEGROUND_JOIN_RANGE_INDEX = "Cannot join the queue unless all members of your party are in the same battleground level range.";
+ERR_BATTLEGROUND_JOIN_TIMED_OUT = "%s was unavailable to join the queue.";
+ERR_BATTLEGROUND_NOT_IN_BATTLEGROUND = "You can't do that in a battleground.";
+ERR_BATTLEGROUND_NOT_IN_TEAM = "Your group is not in the same team";
+ERR_BATTLEGROUND_TEAM_LEFT_QUEUE = "Your team has left the arena queue";
+ERR_BATTLEGROUND_TOO_MANY_QUEUES = "You can only be queued for 2 battles at once";
+ERR_BG_PLAYER_JOINED_SS = "|Hplayer:%s|h[%s]|h has joined the battle";
+ERR_BG_PLAYER_LEFT_S = "%s has left the battle";
+ERR_BN_BROADCAST_THROTTLE = "Please wait a few seconds before updating your broadcast message again.";
+ERR_BN_FRIEND_ALREADY = "That person is already your friend";
+ERR_BN_FRIEND_BLOCKED = "That person is on your blocked list";
+ERR_BN_FRIEND_REQUEST_SENT = "Real ID Friend request has been sent";
+ERR_BN_FRIEND_SELF = "You can't put yourself on your friend list";
+ERR_BUTTON_LOCKED = "That has already been used.";
+ERR_CANNOTCREATEDIRECTORY = "Cannot create directory %s.";
+ERR_CANNOTCREATEFILE = "Cannot create file %s.";
+ERR_CANNOT_IGNORE_BN_FRIEND = "You cannot ignore Real ID friends.";
+ERR_CANTATTACK_NOTSTANDING = "You have to be standing to attack anything!";
+ERR_CANT_DO_THAT_IN_A_GROUP = "You can't do that while in a group.";
+ERR_CANT_DO_THAT_WHILE_LFM = "You can't look for a group while looking for more.";
+ERR_CANT_EQUIP_EVER = "You can never use that item.";
+ERR_CANT_EQUIP_LEVEL_I = "You must reach level %d to use that item.";
+ERR_CANT_EQUIP_NEED_TALENT = "You do not have the required talent to equip that.";
+ERR_CANT_EQUIP_RANK = "You don't have the required rank for that item";
+ERR_CANT_EQUIP_RATING = "You don't have the personal or team rating required to buy that item";
+ERR_CANT_EQUIP_REPUTATION = "You don't have the required reputation for that item";
+ERR_CANT_EQUIP_SKILL = "You aren't skilled enough to use that item.";
+ERR_CANT_INTERACT_SHAPESHIFTED = "Can't speak while shapeshifted.";
+ERR_CANT_SPEAK_LANGAGE = "You cannot speak that language.";
+ERR_CANT_STACK = "This item cannot stack.";
+ERR_CANT_SWAP = "These items can't be swapped.";
+ERR_CANT_USE_DISARMED = "You cannot use an item that is disarmed.";
+ERR_CANT_USE_ITEM = "You can't use that item.";
+ERR_CANT_USE_ITEM_IN_ARENA = "You can't use that item in an arena.";
+ERR_CANT_WRAP_BAGS = "Bags can't be wrapped.";
+ERR_CANT_WRAP_BOUND = "Bound items can't be wrapped.";
+ERR_CANT_WRAP_EQUIPPED = "Equipped items can't be wrapped.";
+ERR_CANT_WRAP_STACKABLE = "Stackable items can't be wrapped.";
+ERR_CANT_WRAP_UNIQUE = "Unique items can't be wrapped.";
+ERR_CANT_WRAP_WRAPPED = "Wrapped items can't be wrapped.";
+ERR_CHAT_PLAYER_AMBIGUOUS_S = "%s: More than one player matches, type more of their server name";
+ERR_CHAT_PLAYER_NOT_FOUND_S = "No player named '%s' is currently playing.";
+ERR_CHAT_RESTRICTED = "Trial accounts cannot send unlimited tells, you must wait before you can send tells to more players.";
+ERR_CHAT_THROTTLED = "The number of messages that can be sent is limited, please wait to send another message.";
+ERR_CHAT_WHILE_DEAD = "You can't chat when you're dead!";
+ERR_CHAT_WRONG_FACTION = "You can only whisper to members of your alliance.";
+ERR_CHEST_IN_USE = "That is already being used.";
+ERR_CLICK_ON_ITEM_TO_FEED = "Click on an item to feed to your pet";
+ERR_CLIENT_LOCKED_OUT = "You can't do that right now.";
+ERR_COMBAT_DAMAGE_SSI = "%s hits %s for %d damage!";
+ERR_COMMAND_NEEDS_TARGET = "You must specify a target: / ";
+ERR_COMPLAINT_IN_SAME_GUILD = "You can not complain about another guild member.";
+ERR_COMSAT_CONNECT_FAIL = "Cannot connect to voice chat service.";
+ERR_COMSAT_DISCONNECT = "Connection lost to Voice Chat service.";
+ERR_COMSAT_RECONNECT_ATTEMPT = "Voice Chat service restored!";
+ERR_CORPSE_IS_NOT_IN_INSTANCE = "Your corpse is not in that instance";
+ERR_CURRENCY_FULL = "Can't carry that much currency.";
+ERR_DANCE_CREATE_DUPLICATE = "You already have a dance by that name";
+ERR_DANCE_DELETE_FAILED = "Failed to delete dance";
+ERR_DANCE_SAVE_FAILED = "Failed to save dance";
+ERR_DEATHBINDALREADYBOUND = "You are already bound here!";
+ERR_DEATHBIND_SUCCESS_S = "%s is now your home.";
+ERR_DECLINE_GROUP_S = "%s declines your group invitation.";
+ERR_DESTROY_NONEMPTY_BAG = "You can only do that with empty bags.";
+ERR_DIFFICULTY_CHANGE_ALREADY_STARTED = "A raid difficulty change is currently in progress.";
+ERR_DIFFICULTY_CHANGE_COMBAT = "Raid difficulty cannot be changed at this time. A player is in combat.";
+ERR_DIFFICULTY_CHANGE_COOLDOWN_S = "Raid difficulty has changed recently, and may not change again for %s.";
+ERR_DIFFICULTY_CHANGE_ENCOUNTER = "Raid difficulty cannot be changed at this time. An encounter is in progress.";
+ERR_DIFFICULTY_CHANGE_PLAYER_BUSY = "Raid difficulty cannot be changed at this time. A player is busy.";
+ERR_DIFFICULTY_CHANGE_WORLDSTATE = "Raid difficulty cannot be changed at this time. An event is in progress.";
+ERR_DISMOUNT_NOPET = "INTERNAL ERROR, YOU DON'T HAVE A PET TO DISMOUNT";
+ERR_DISMOUNT_NOTMOUNTED = "You're not mounted!";
+ERR_DISMOUNT_NOTYOURPET = "INTERNAL ERROR, DISMOUNTING A NON-PET";
+ERR_DOOR_LOCKED = "The door is locked.";
+ERR_DROP_BOUND_ITEM = "You can't drop a soulbound item.";
+ERR_DUEL_CANCELLED = "Duel cancelled.";
+ERR_DUEL_REQUESTED = "You have requested a duel.";
+ERR_DUNGEON_DIFFICULTY_CHANGED_S = "Dungeon Difficulty set to %s.";
+ERR_DUNGEON_DIFFICULTY_FAILED = "Unable to change Dungeon Difficulty";
+ERR_EAT_WHILE_MOVNG = "You can't eat while moving.";
+ERR_EMBLEMERROR_NOTABARDGEOSET = "Change back to your normal form first!";
+ERR_EQUIP_TRADE_ITEM = "That item is currently being traded";
+ERR_EXHAUSTION_EXHAUSTED = "You feel exhausted.";
+ERR_EXHAUSTION_NORMAL = "You feel normal.";
+ERR_EXHAUSTION_RESTED = "You feel rested.";
+ERR_EXHAUSTION_TIRED = "You feel tired.";
+ERR_EXHAUSTION_WELLRESTED = "You feel well rested.";
+ERR_FEIGN_DEATH_RESISTED = "Resisted";
+ERR_FILTERING_YOU_S = "Unable to send chat to %s because your message contained reserved words.";
+ERR_FISH_ESCAPED = "Your fish got away!";
+ERR_FISH_NOT_HOOKED = "No fish are hooked.";
+ERR_FOOD_COOLDOWN = "You are too full to eat more now.";
+ERR_FRIEND_ADDED_S = "%s added to friends.";
+ERR_FRIEND_ALREADY_S = "%s is already your friend.";
+ERR_FRIEND_DB_ERROR = "Friend lookup database error.";
+ERR_FRIEND_DELETED = "Friend removed because the character no longer exists.";
+ERR_FRIEND_ERROR = "Unknown friend response from server.";
+ERR_FRIEND_LIST_FULL = "You don't have room for any more friends.";
+ERR_FRIEND_NOT_FOUND = "Player not found.";
+ERR_FRIEND_OFFLINE_S = "%s has gone offline.";
+ERR_FRIEND_ONLINE_SS = "|Hplayer:%s|h[%s]|h has come online.";
+ERR_FRIEND_REMOVED_S = "%s removed from friends list.";
+ERR_FRIEND_SELF = "You can't put yourself on your friend list.";
+ERR_FRIEND_WRONG_FACTION = "Friends must be part of your alliance.";
+ERR_GENERIC_NO_TARGET = "You have no target.";
+ERR_GENERIC_NO_VALID_TARGETS = "No valid targets.";
+ERR_GENERIC_STUNNED = "You are stunned";
+ERR_GMRESPONSE_DB_ERROR = "Error retrieving GM response.";
+ERR_GROUP_ACTION_THROTTLED = "You have attempted too many group actions in a short period of time. Please wait momentarily before attempting further group actions.";
+ERR_GROUP_DISBANDED = "Your group has been disbanded.";
+ERR_GROUP_FULL = "Your party is full.";
+ERR_GROUP_JOIN_BATTLEGROUND_DESERTERS = "You cannot join the battleground yet because you or one of your party members is flagged as a Deserter.";
+ERR_GROUP_JOIN_BATTLEGROUND_FAIL = "Your group has joined a battleground queue, but you are not eligible";
+ERR_GROUP_JOIN_BATTLEGROUND_S = "Your group has joined the queue for %s";
+ERR_GROUP_JOIN_BATTLEGROUND_TOO_MANY = "Your group is too big to join that battleground";
+ERR_GROUP_SWAP_FAILED = "Players in raid combat cannot change raid subgroups";
+ERR_GUILDEMBLEM_COLORSPRESENT = "Your guild already has an emblem!";
+ERR_GUILDEMBLEM_INVALIDVENDOR = "That's not an emblem vendor!";
+ERR_GUILDEMBLEM_INVALID_TABARD_COLORS = "Invalid Guild Emblem colors.";
+ERR_GUILDEMBLEM_NOGUILD = "You are not part of a guild!";
+ERR_GUILDEMBLEM_NOTENOUGHMONEY = "You can't afford to do that.";
+ERR_GUILDEMBLEM_NOTGUILDMASTER = "Only guild leaders can create emblems.";
+ERR_GUILDEMBLEM_SAME = "Not saved, your tabard is already like that.";
+ERR_GUILDEMBLEM_SUCCESS = "Guild Emblem saved.";
+ERR_GUILD_ACCEPT = "You have joined the guild.";
+ERR_GUILD_BANK_BOUND_ITEM = "You cannot store soulbound items in the guild bank";
+ERR_GUILD_BANK_CONJURED_ITEM = "You cannot store conjured items in the guild bank";
+ERR_GUILD_BANK_EQUIPPED_ITEM = "You must unequip that item first";
+ERR_GUILD_BANK_FULL = "This guild bank tab is full";
+ERR_GUILD_BANK_QUEST_ITEM = "You cannot store quest items in the guild bank";
+ERR_GUILD_BANK_WRAPPED_ITEM = "You cannot store wrapped items in the guild bank";
+ERR_GUILD_CREATE_S = "%s created.";
+ERR_GUILD_DECLINE_S = "%s declines your guild invitation.";
+ERR_GUILD_DEMOTE_SSS = "%s has demoted %s to %s.";
+ERR_GUILD_DISBANDED = "Guild has been disbanded.";
+ERR_GUILD_DISBAND_S = "%s has disbanded the guild.";
+ERR_GUILD_DISBAND_SELF = "You have disbanded the guild.";
+ERR_GUILD_FOUNDER_S = "Congratulations, you are a founding member of %s!";
+ERR_GUILD_INTERNAL = "Internal guild error.";
+ERR_GUILD_INVITE_S = "You have invited %s to join your guild.";
+ERR_GUILD_JOIN_S = "%s has joined the guild.";
+ERR_GUILD_LEADER_CHANGED_SS = "%s has made %s the new Guild Master.";
+ERR_GUILD_LEADER_IS_S = "%s is the leader of your guild.";
+ERR_GUILD_LEADER_LEAVE = "You must promote a new Guild Master using /gleader before leaving the guild.";
+ERR_GUILD_LEADER_S = "%s has been promoted to Guild Master.";
+ERR_GUILD_LEADER_SELF = "You are now the Guild Master.";
+ERR_GUILD_LEAVE_RESULT = "You have left the guild.";
+ERR_GUILD_LEAVE_S = "%s has left the guild.";
+ERR_GUILD_NAME_EXISTS_S = "There is already a guild named \"%s\".";
+ERR_GUILD_NOT_ALLIED = "You cannot invite players from the opposing alliance";
+ERR_GUILD_NOT_ENOUGH_MONEY = "The guild bank does not have enough money";
+ERR_GUILD_PERMISSIONS = "You don't have permission to do that.";
+ERR_GUILD_PLAYER_NOT_FOUND_S = "\"%s\" not found.";
+ERR_GUILD_PLAYER_NOT_IN_GUILD = "You are not in a guild.";
+ERR_GUILD_PLAYER_NOT_IN_GUILD_S = "%s is not in your guild.";
+ERR_GUILD_PROMOTE_SSS = "%s has promoted %s to %s.";
+ERR_GUILD_QUIT_S = "You are no longer a member of %s.";
+ERR_GUILD_RANKS_LOCKED = "Temporary guild error. Please try again!";
+ERR_GUILD_RANK_IN_USE = "That guild rank is currently in use.";
+ERR_GUILD_RANK_TOO_HIGH_S = "%s's rank is too high";
+ERR_GUILD_RANK_TOO_LOW_S = "%s is already at the lowest rank";
+ERR_GUILD_REMOVE_SELF = "You have been kicked out of the guild.";
+ERR_GUILD_REMOVE_SS = "%s has been kicked out of the guild by %s.";
+ERR_GUILD_WITHDRAW_LIMIT = "You cannot withdraw that much from the guild bank.";
+ERR_IGNORE_ADDED_S = "%s is now being ignored.";
+ERR_IGNORE_ALREADY_S = "%s is already being ignored.";
+ERR_IGNORE_AMBIGUOUS = "That name is ambiguous, type more of the player's server name";
+ERR_IGNORE_DELETED = "Ignore removed because the character no longer exists.";
+ERR_IGNORE_FULL = "You can't ignore any more players.";
+ERR_IGNORE_NOT_FOUND = "Player not found.";
+ERR_IGNORE_REMOVED_S = "%s is no longer being ignored.";
+ERR_IGNORE_SELF = "You can't ignore yourself.";
+ERR_IGNORING_YOU_S = "%s is ignoring you.";
+ERR_INITIATE_TRADE_S = "You have requested to trade with %s.";
+ERR_INSPECT_S = "%s is inspecting you.";
+ERR_INTERNAL_BAG_ERROR = "Internal Bag Error";
+ERR_INVALID_ATTACK_TARGET = "You cannot attack that target.";
+ERR_INVALID_FOLLOW_TARGET = "You can't follow that unit.";
+ERR_INVALID_GLYPH_SLOT = "That is not a valid glyph slot.";
+ERR_INVALID_INSPECT_TARGET = "You can't inspect that unit.";
+ERR_INVALID_ITEM_TARGET = "That item is not a valid target.";
+ERR_INVALID_PROMOTION_CODE = "Couldn't validate code, please try again.";
+ERR_INVALID_RAID_TARGET = "You cannot raid target enemy players";
+ERR_INVALID_TELEPORT_LOCATION = "You do not have a valid teleport location.";
+ERR_INVITED_ALREADY_IN_GROUP_SS = "|Hplayer:%s|h[%s]|h invited you to a group, but you could not accept because you are already in a group.";
+ERR_INVITED_TO_ARENA_TEAM = "You have already been invited into an arena team.";
+ERR_INVITED_TO_GROUP_SS = "|Hplayer:%s|h[%s]|h has invited you to join a group.";
+ERR_INVITED_TO_GUILD = "You have already been invited into a guild.";
+ERR_INVITED_TO_GUILD_SSS = "|Hplayer:%s|h[%s]|h invites you to join %s.";
+ERR_INVITE_IN_COMBAT = "You cannot invite a player in raid combat";
+ERR_INVITE_NO_PARTY_SERVER = "Could not create a party";
+ERR_INVITE_PARTY_BUSY = "Cannot invite additional players until the party is formed";
+ERR_INVITE_PLAYER_S = "You have invited %s to join your group.";
+ERR_INVITE_RESTRICTED = "Trial accounts cannot invite characters into groups.";
+ERR_INVITE_SELF = "You can't invite yourself to a group.";
+ERR_INVITE_UNKNOWN_REALM = "You cannot invite players from that realm";
+ERR_INV_FULL = "Inventory is full.";
+ERR_IN_NON_RANDOM_BG = "Can't queue for Random Battleground while in another Battleground queue.";
+ERR_IN_RANDOM_BG = "Can't do that while in a Random Battleground queue.";
+ERR_ITEM_CANT_BE_DESTROYED = "That item cannot be destroyed.";
+ERR_ITEM_COOLDOWN = "Item is not ready yet.";
+ERR_ITEM_INVENTORY_FULL_SATCHEL = "Your inventory is full. Your satchel has been delivered to your mailbox.";
+ERR_ITEM_LOCKED = "Item is locked.";
+ERR_ITEM_MAX_COUNT = "You can't carry any more of those items.";
+ERR_ITEM_MAX_COUNT_EQUIPPED_SOCKETED = "You have the maximum number of those gems socketed into equipped items.";
+ERR_ITEM_MAX_COUNT_SOCKETED = "You have the maximum number of those gems in your inventory or socketed into items.";
+ERR_ITEM_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED_IS = "You can only carry %d %s";
+ERR_ITEM_MAX_LIMIT_CATEGORY_EQUIPPED_EXCEEDED_IS = "You can only equip %d |4item:items; in the %s category";
+ERR_ITEM_MAX_LIMIT_CATEGORY_SOCKETED_EXCEEDED_IS = "You can only equip %d |4item:items; in the %s category";
+ERR_ITEM_NOT_FOUND = "The item was not found.";
+ERR_ITEM_UNIQUE_EQUIPABLE = "You cannot equip more than one of those.";
+ERR_ITEM_UNIQUE_EQUIPPABLE = "You cannot equip more than one of those.";
+ERR_ITEM_UNIQUE_EQUIPPABLE_SOCKETED = "You cannot socket more than one of those gems into a single item.";
+ERR_JOINED_GROUP_S = "%s joins the party.";
+ERR_KILLED_BY_S = "%s has slain you.";
+ERR_LEARN_ABILITY_S = "You have learned a new ability: %s.";
+ERR_LEARN_COMPANION_S = "You have added the pet %s to your collection.";
+ERR_LEARN_RECIPE_S = "You have learned how to create a new item: %s.";
+ERR_LEARN_SPELL_S = "You have learned a new spell: %s.";
+ERR_LEFT_GROUP_S = "%s leaves the party.";
+ERR_LEFT_GROUP_YOU = "You leave the group.";
+ERR_LFG_CANT_USE_BATTLEGROUND = "You cannot queue for a battleground or arena while using the dungeon system.";
+ERR_LFG_CANT_USE_DUNGEONS = "You cannot queue for a dungeon while using battlegrounds or arenas.";
+ERR_LFG_DESERTER_PARTY = "One or more party members has a deserter debuff.";
+ERR_LFG_DESERTER_PLAYER = "You can not queue for dungeons until your deserter debuff wears off.";
+ERR_LFG_GET_INFO_TIMEOUT = "Could not retrieve information about some party members.";
+ERR_LFG_GROUP_FULL = "Your group is already full.";
+ERR_LFG_INVALID_SLOT = "One or more dungeons was not valid.";
+ERR_LFG_JOINED_LIST = "You are now listed in the Raid Browser.";
+ERR_LFG_JOINED_QUEUE = "You are now queued in the Dungeon Finder.";
+ERR_LFG_LEADER_IS_LFM_S = "You can't do that while %s is looking for more members.";
+ERR_LFG_LEFT_LIST = "You are no longer listed in the Raid Browser.";
+ERR_LFG_LEFT_QUEUE = "You are no longer queued in the Dungeon Finder.";
+ERR_LFG_MEMBERS_NOT_PRESENT = "One or more party members are pending invites or disconnected.";
+ERR_LFG_MISMATCHED_SLOTS = "You cannot mix dungeons, raids, and random when picking dungeons.";
+ERR_LFG_NO_LFG_OBJECT = "Internal LFG Error.";
+ERR_LFG_NO_ROLES_SELECTED = "You must select at least one role.";
+ERR_LFG_NO_SLOTS_PARTY = "One or more party members do not meet the requirements for the chosen dungeons.";
+ERR_LFG_NO_SLOTS_PLAYER = "You do not meet the requirements for the chosen dungeons.";
+ERR_LFG_NO_SLOTS_SELECTED = "You did not select any valid slots.";
+ERR_LFG_PARTY_PLAYERS_FROM_DIFFERENT_REALMS = "The dungeon you chose does not support players from multiple realms.";
+ERR_LFG_PENDING = "You already have a pending match.";
+ERR_LFG_PLAYER_DECLINED_ROLE_CHECK = "%s has not selected any roles.";
+ERR_LFG_PROPOSAL_DECLINED_PARTY = "You have been removed from the Dungeon queue because someone in your party did not accept the invitation.";
+ERR_LFG_PROPOSAL_DECLINED_SELF = "You have been removed from the Dungeon queue because you did not accept the invitation.";
+ERR_LFG_PROPOSAL_FAILED = "Someone has declined the dungeon invite. You have been returned to the front of the dungeon queue.";
+ERR_LFG_RANDOM_COOLDOWN_PARTY = "One or more party members are on random dungeon cooldown.";
+ERR_LFG_RANDOM_COOLDOWN_PLAYER = "You can not queue for random dungeons while on random dungeon cooldown.";
+ERR_LFG_ROLE_CHECK_ABORTED = "Your group leader has cancelled the Role Check.";
+ERR_LFG_ROLE_CHECK_FAILED = "The Role Check has failed.";
+ERR_LFG_ROLE_CHECK_FAILED_NOT_VIABLE = "Role Check failed because your group is not viable.";
+ERR_LFG_ROLE_CHECK_FAILED_TIMEOUT = "Role Check failed because group member did not respond.";
+ERR_LFG_ROLE_CHECK_INITIATED = "A role check has been initiated. Your group will be queued when all members have selected a role.";
+ERR_LFG_TOO_MANY_MEMBERS = "You can not enter dungeons with more than 5 party members.";
+ERR_LOGGING_OUT = "You are logging out";
+ERR_LOGOUT_FAILED = "You can't logout now.";
+ERR_LOOT_BAD_FACING = "You must be facing the corpse to loot it.";
+ERR_LOOT_CANT_LOOT_THAT = "You don't meet the requirements to loot that item";
+ERR_LOOT_CANT_LOOT_THAT_NOW = "You can't loot that item now.";
+ERR_LOOT_DIDNT_KILL = "You don't have permission to loot that corpse.";
+ERR_LOOT_GONE = "Already looted";
+ERR_LOOT_LOCKED = "Someone is already looting that corpse.";
+ERR_LOOT_MASTER_INV_FULL = "That player's inventory is full";
+ERR_LOOT_MASTER_OTHER = "Can't assign item to that player";
+ERR_LOOT_MASTER_UNIQUE_ITEM = "Player has too many of that item already";
+ERR_LOOT_NOTSTANDING = "You need to be standing up to loot something!";
+ERR_LOOT_NO_UI = "You can't loot right now.";
+ERR_LOOT_PLAYER_NOT_FOUND = "Player not found";
+ERR_LOOT_ROLL_PENDING = "That item is still being rolled for.";
+ERR_LOOT_STUNNED = "You can't loot anything while stunned!";
+ERR_LOOT_TOO_FAR = "You are too far away to loot that corpse.";
+ERR_LOOT_WHILE_INVULNERABLE = "Cannot loot while invulnerable.";
+ERR_MAIL_ATTACHMENT_EXPIRED = "That item has expired.";
+ERR_MAIL_BAG = "You can't mail non-empty bags.";
+ERR_MAIL_BOUND_ITEM = "You can't mail soulbound items.";
+ERR_MAIL_CONJURED_ITEM = "You cannot mail conjured items";
+ERR_MAIL_DATABASE_ERROR = "Internal mail database error.";
+ERR_MAIL_INVALID_ATTACHMENT = "A mail attachment was invalid.";
+ERR_MAIL_INVALID_ATTACHMENT_SLOT = "You cannot attach more than 12 items to mail.";
+ERR_MAIL_LIMITED_DURATION_ITEM = "You cannot mail items with a limited duration";
+ERR_MAIL_QUEST_ITEM = "You can't mail quest items.";
+ERR_MAIL_REACHED_CAP = "You have reached the in-game cap of unique mail recipients";
+ERR_MAIL_SENT = "Mail sent.";
+ERR_MAIL_TARGET_NOT_FOUND = "Cannot find mail recipient.";
+ERR_MAIL_TOO_MANY_ATTACHMENTS = "A mail included too many attachments.";
+ERR_MAIL_TO_SELF = "You can't send mail to yourself.";
+ERR_MAIL_WRAPPED_COD = "You can't send wrapped items C.O.D.";
+ERR_MAX_SOCKETS = "That item cannot receive additional sockets";
+ERR_MEETING_STONE_GROUP_FULL = "You are already in a full group";
+ERR_MEETING_STONE_INVALID_LEVEL = "You do not meet the level requirements of this meeting stone.";
+ERR_MEETING_STONE_INVALID_TARGET = "No target selected";
+ERR_MEETING_STONE_IN_PROGRESS = "You are still seeking more members through the meeting stone.";
+ERR_MEETING_STONE_IN_QUEUE_S = "You are now in the queue to join a party for %s.";
+ERR_MEETING_STONE_LEFT_QUEUE_S = "You have left the queue to join a party for %s.";
+ERR_MEETING_STONE_MEMBER_ADDED_S = "%s has been added to the group by the meeting stone.";
+ERR_MEETING_STONE_MEMBER_STILL_IN_QUEUE = "Looking for a new party in the meeting stone queue.";
+ERR_MEETING_STONE_MUST_BE_LEADER = "You must be the party leader to interact with the meeting stone";
+ERR_MEETING_STONE_NEED_PARTY = "You need to be in a party to use a meeting stone";
+ERR_MEETING_STONE_NOT_FOUND = "Player not found.";
+ERR_MEETING_STONE_NOT_LEADER = "Only the party leader can leave the meeting stone queue";
+ERR_MEETING_STONE_NO_RAID_GROUP = "You cannot use a meeting stone while in a raid group";
+ERR_MEETING_STONE_OTHER_MEMBER_LEFT = "Party member has left. Looking for a new party in the meeting stone queue.";
+ERR_MEETING_STONE_SUCCESS = "Your group is complete, you have left the meeting stone queue.";
+ERR_MEETING_STONE_TARGET_INVALID_LEVEL = "Your target does not meet the level requirements of this meeting stone.";
+ERR_MEETING_STONE_TARGET_NOT_IN_PARTY = "Your target is not in the party";
+ERR_MOUNT_ALREADYMOUNTED = "You're already mounted.";
+ERR_MOUNT_FORCEDDISMOUNT = "You dismount before continuing.";
+ERR_MOUNT_INVALIDMOUNTEE = "You can't mount that unit.";
+ERR_MOUNT_LOOTING = "You can't mount while looting!";
+ERR_MOUNT_NOTMOUNTABLE = "That unit can't be mounted.";
+ERR_MOUNT_NOTYOURPET = "That mount isn't your pet!";
+ERR_MOUNT_OTHER = "UNKNOWN MOUNT ERROR";
+ERR_MOUNT_RACECANTMOUNT = "You can't mount because of your race.";
+ERR_MOUNT_SHAPESHIFTED = "You can't mount while shapeshifted.";
+ERR_MOUNT_TOOFARAWAY = "That mount is too far away.";
+ERR_MULTI_CAST_ACTION_TOTEM_S = "Only %s spells can go in that slot.";
+ERR_MUST_EQUIP_ITEM = "You must equip that item to use it.";
+ERR_MUST_REPAIR_DURABILITY = "You must repair that item's durability to use it.";
+ERR_NAME_CONSECUTIVE_SPACES = "Consecutive spaces are not allowed. Enter a new name.";
+ERR_NAME_DECLENSION_DOESNT_MATCH_BASE_NAME = "Your declensions must match your original name. Enter a new name.";
+ERR_NAME_INVALID = "That name contains invalid characters, Enter a new name.";
+ERR_NAME_INVALID_SPACE = "Names cannot start or end with a space. Enter a new name.";
+ERR_NAME_MIXED_LANGUAGES = "Names must use one language. Enter a new name.";
+ERR_NAME_NO_NAME = "Please enter a name.";
+ERR_NAME_PROFANE = "That name contains mature language. Enter a new name.";
+ERR_NAME_RESERVED = "That name is reserved. Enter a new name.";
+ERR_NAME_RUSSIAN_CONSECUTIVE_SILENT_CHARACTERS = "Consecutive silent characters are not allowed. Create a new name.";
+ERR_NAME_RUSSIAN_SILENT_CHARACTER_AT_BEGINNING_OR_END = "Silent characters are now allowed at the beginning or end of a name. Create a new name.";
+ERR_NAME_THREE_CONSECUTIVE = "You cannot use the same letter three times consecutively. Enter a new name.";
+ERR_NAME_TOO_LONG = "That name is too long. Enter a new name.";
+ERR_NAME_TOO_LONG2 = "That name is too long.";
+ERR_NAME_TOO_SHORT = "That name is too short. Enter a new name.";
+ERR_NEWTAXIPATH = "New flight path discovered!";
+ERR_NEW_GUIDE_S = "%s is now the Dungeon Guide.";
+ERR_NEW_GUIDE_YOU = "You are now the Dungeon Guide.";
+ERR_NEW_LEADER_S = "%s is now the group leader.";
+ERR_NEW_LEADER_YOU = "You are now the group leader.";
+ERR_NEW_LOOT_MASTER_S = "%s is now the loot master.";
+ERR_NOAMMO_S = "%s";
+ERR_NOEMOTEWHILERUNNING = "You can't do that while moving!";
+ERR_NOTYOURPET = "That is not your pet!";
+ERR_NOT_A_BAG = "Not a bag.";
+ERR_NOT_BARBER_SITTING = "You must be sitting in a barber chair";
+ERR_NOT_DURING_ARENA_MATCH = "You can't do that while in an arena match";
+ERR_NOT_ENOUGH_ARENA_POINTS = "You don't have enough arena points";
+ERR_NOT_ENOUGH_GOLD = "Not enough gold";
+ERR_NOT_ENOUGH_HONOR_POINTS = "You don't have enough honor points";
+ERR_NOT_ENOUGH_MONEY = "You don't have enough money.";
+ERR_NOT_EQUIPPABLE = "This item cannot be equipped.";
+ERR_NOT_IN_BATTLEGROUND = "You are not in a battleground";
+ERR_NOT_IN_COMBAT = "You can't do that while in combat";
+ERR_NOT_IN_GROUP = "You aren't in a party.";
+ERR_NOT_IN_RAID = "You are not in a raid group";
+ERR_NOT_LEADER = "You are not the party leader.";
+ERR_NOT_OWNER = "You don't own that item.";
+ERR_NOT_SAME_ACCOUNT = "Artifacts can only be mailed to your own characters.";
+ERR_NOT_WHILE_DISARMED = "You can't do that while disarmed";
+ERR_NOT_WHILE_FALLING = "You can't do that while jumping or falling";
+ERR_NOT_WHILE_FATIGUED = "You can't do that while fatigued";
+ERR_NOT_WHILE_MOUNTED = "You can't do that while mounted.";
+ERR_NOT_WHILE_SHAPESHIFTED = "You can't do that while shapeshifted.";
+ERR_NO_ARENA_CHARTER = "You don't have that arena team charter.";
+ERR_NO_ATTACK_TARGET = "There is nothing to attack.";
+ERR_NO_BANK_HERE = "You are too far away from a bank.";
+ERR_NO_BANK_SLOT = "You must purchase that bag slot first";
+ERR_NO_GUILD_CHARTER = "You don't have a guild charter.";
+ERR_NO_ITEMS_WHILE_SHAPESHIFTED = "Can't use items while shapeshifted.";
+ERR_NO_PET = "You don't have a pet!";
+ERR_NO_REPLY_TARGET = "You have nobody to reply to yet.";
+ERR_NO_SLOT_AVAILABLE = "No equipment slot is available for that item.";
+ERR_NULL_PETNAME = "Error, empty pet name entered.";
+ERR_OBJECT_IS_BUSY = "That object is busy.";
+ERR_ONLY_ONE_AMMO = "You can only equip one ammo pouch.";
+ERR_ONLY_ONE_BOLT = "You can only equip one quiver.";
+ERR_ONLY_ONE_QUIVER = "You can only equip one quiver.";
+ERR_OUT_OF_ENERGY = "Not enough energy";
+ERR_OUT_OF_FOCUS = "Not enough focus";
+ERR_OUT_OF_HEALTH = "Not enough health";
+ERR_OUT_OF_MANA = "Not enough mana";
+ERR_OUT_OF_POWER_DISPLAY = "Not enough %s";
+ERR_OUT_OF_RAGE = "Not enough rage";
+ERR_OUT_OF_RANGE = "Out of range.";
+ERR_OUT_OF_RUNES = "Not enough runes";
+ERR_OUT_OF_RUNIC_POWER = "Not enough runic power";
+ERR_PARTY_LFG_BOOT_COOLDOWN_S = "You must wait %s before initiating another player kick.";
+ERR_PARTY_LFG_BOOT_DUNGEON_COMPLETE = "Players cannot be kicked after the instance is complete.";
+ERR_PARTY_LFG_BOOT_IN_COMBAT = "Players cannot be kicked while in combat, or shortly after combat.";
+ERR_PARTY_LFG_BOOT_IN_PROGRESS = "Another kick vote is already in progress.";
+ERR_PARTY_LFG_BOOT_LIMIT = "You can not initiate any more party kicks.";
+ERR_PARTY_LFG_BOOT_LOOT_ROLLS = "Players cannot be kicked during loot rolls.";
+ERR_PARTY_LFG_BOOT_NOT_ELIGIBLE_S = "That player can not be kicked for another %s.";
+ERR_PARTY_LFG_BOOT_TOO_FEW_PLAYERS = "There are not enough players in the group to initate a vote.";
+ERR_PARTY_LFG_BOOT_VOTE_FAILED = "The vote to kick %s has failed.";
+ERR_PARTY_LFG_BOOT_VOTE_SUCCEEDED = "The vote to kick %s has passed.";
+ERR_PARTY_LFG_INVITE_RAID_LOCKED = "%s is locked to another instance.";
+ERR_PARTY_LFG_TELEPORT_IN_COMBAT = "You cannot teleport out of the dungeon while in combat.";
+ERR_PARTY_TARGET_AMBIGUOUS = "There were multiple players in the party with that name, please include realm name";
+ERR_PASSIVE_ABILITY = "You can't put a passive ability in the action bar.";
+ERR_PETITION_ALREADY_SIGNED = "You have already signed that charter.";
+ERR_PETITION_ALREADY_SIGNED_OTHER = "You've already signed another guild charter";
+ERR_PETITION_CREATOR = "You can't sign your own charter.";
+ERR_PETITION_DECLINED_S = "%s has declined to sign your petition.";
+ERR_PETITION_FULL = "That petition is full";
+ERR_PETITION_IN_GUILD = "You are already in a guild.";
+ERR_PETITION_NOT_ENOUGH_SIGNATURES = "You need more signatures.";
+ERR_PETITION_NOT_SAME_SERVER = "That player is not from your server";
+ERR_PETITION_OFFERED_S = "You have requested %s's signature.";
+ERR_PETITION_RESTRICTED_ACCOUNT = "Trial accounts may not sign guild charters.";
+ERR_PETITION_SIGNED = "Charter signed.";
+ERR_PETITION_SIGNED_S = "%s has signed your charter.";
+ERR_PET_BROKEN = "Your pet has run away";
+ERR_PET_LEARN_ABILITY_S = "Your pet has learned a new ability: %s.";
+ERR_PET_LEARN_SPELL_S = "Your pet has learned a new spell: %s.";
+ERR_PET_NOT_RENAMEABLE = "Your pet can't be renamed.";
+ERR_PET_SPELL_AFFECTING_COMBAT = "Your pet is in combat.";
+ERR_PET_SPELL_ALREADY_KNOWN_S = "Your pet already knows %s.";
+ERR_PET_SPELL_DEAD = "Your pet is dead.";
+ERR_PET_SPELL_NOT_BEHIND = "Your pet must be behind its target.";
+ERR_PET_SPELL_OUT_OF_RANGE = "Your pet is out of range.";
+ERR_PET_SPELL_ROOTED = "Your pet is unable to move.";
+ERR_PET_SPELL_TARGETS_DEAD = "Your pet's target is dead.";
+ERR_PET_SPELL_UNLEARNED_S = "Your pet has unlearned %s.";
+ERR_PLAYERLIST_JOINED_BATTLE = "%d players have joined the battle: %s";
+ERR_PLAYERLIST_LEFT_BATTLE = "%d players have left the battle: %s";
+ERR_PLAYERS_JOINED_BATTLE_D = "%d players have joined the battle.";
+ERR_PLAYERS_LEFT_BATTLE_D = "%d players have left the battle.";
+ERR_PLAYER_BUSY_S = "%s is busy right now.";
+ERR_PLAYER_DEAD = "You can't do that when you're dead.";
+ERR_PLAYER_DIED_S = "%s has died.";
+ERR_PLAYER_DIFFICULTY_CHANGED_S = "Difficulty set to %s.";
+ERR_PLAYER_JOINED_BATTLE_D = "%s has joined the battle.";
+ERR_PLAYER_LEFT_BATTLE_D = "%s has left the battle.";
+ERR_PLAYER_SILENCED = "A group leader has removed your voice privileges.";
+ERR_PLAYER_SILENCED_ECHO = "You have removed the voice privileges of %s.";
+ERR_PLAYER_UNSILENCED = "A group leader has restored your voice privileges.";
+ERR_PLAYER_UNSILENCED_ECHO = "You have restored the voice privileges of %s.";
+ERR_PLAYER_WRONG_FACTION = "Target is unfriendly.";
+ERR_PLAY_TIME_EXCEEDED = "Maximum play time exceeded";
+ERR_POTION_COOLDOWN = "You cannot drink any more yet.";
+ERR_PROFANE_CHAT_NAME = "You may not create custom channels with profane names.";
+ERR_PROFICIENCY_GAINED_S = "You have gained %s proficiency.";
+ERR_PROFICIENCY_NEEDED = "You do not have the required proficiency for that item.";
+ERR_PURCHASE_LEVEL_TOO_LOW = "You must reach level %d to purchase that item.";
+ERR_PVP_TOGGLE_OFF = "PvP combat toggled off";
+ERR_PVP_TOGGLE_ON = "PvP combat toggled on";
+ERR_QUEST_ACCEPTED_S = "Quest accepted: %s";
+ERR_QUEST_ADD_FOUND_SII = "%s: %d/%d";
+ERR_QUEST_ADD_ITEM_SII = "%s: %d/%d";
+ERR_QUEST_ADD_KILL_SII = "%s slain: %d/%d";
+ERR_QUEST_ADD_PLAYER_KILL_SII = "Players slain: %d/%d";
+ERR_QUEST_ALREADY_DONE = "You have completed that quest.";
+ERR_QUEST_ALREADY_DONE_DAILY = "You have completed that daily quest today.";
+ERR_QUEST_ALREADY_ON = "You are already on that quest";
+ERR_QUEST_COMPLETE_S = "%s completed.";
+ERR_QUEST_FAILED_BAG_FULL_S = "%s failed: Inventory is full.";
+ERR_QUEST_FAILED_CAIS = "You cannot complete quests once you have reached tired time";
+ERR_QUEST_FAILED_EXPANSION = "This quest requires an expansion enabled account.";
+ERR_QUEST_FAILED_LOW_LEVEL = "You are not high enough level for that quest.";
+ERR_QUEST_FAILED_MAX_COUNT_S = "%s failed: Duplicate item found.";
+ERR_QUEST_FAILED_MISSING_ITEMS = "You don't have the required items with you. Check storage.";
+ERR_QUEST_FAILED_NOT_ENOUGH_MONEY = "You don't have enough money for that quest";
+ERR_QUEST_FAILED_S = "%s failed.";
+ERR_QUEST_FAILED_TOO_MANY_DAILY_QUESTS_I = "You have already completed %d daily quests today";
+ERR_QUEST_FAILED_WRONG_RACE = "That quest is not available to your race.";
+ERR_QUEST_FORCE_REMOVED_S = "The quest %s has been removed from your quest log";
+ERR_QUEST_LOG_FULL = "Your quest log is full.";
+ERR_QUEST_MUST_CHOOSE = "You must choose a reward.";
+ERR_QUEST_NEED_PREREQS = "You don't meet the requirements for that quest";
+ERR_QUEST_OBJECTIVE_COMPLETE_S = "%s (Complete)";
+ERR_QUEST_ONLY_ONE_TIMED = "You can only be on one timed quest at a time";
+ERR_QUEST_PUSH_ACCEPTED_S = "%s has accepted your quest";
+ERR_QUEST_PUSH_ALREADY_DONE_S = "%s has completed that quest";
+ERR_QUEST_PUSH_BUSY_S = "%s is busy";
+ERR_QUEST_PUSH_DECLINED_S = "%s has declined your quest";
+ERR_QUEST_PUSH_DIFFERENT_SERVER_DAILY_S = "%s is not eligible for that quest today";
+ERR_QUEST_PUSH_INVALID_S = "%s is not eligible for that quest";
+ERR_QUEST_PUSH_LOG_FULL_S = "%s's quest log is full";
+ERR_QUEST_PUSH_NOT_DAILY_S = "That quest cannot be shared today";
+ERR_QUEST_PUSH_NOT_IN_PARTY_S = "You are not in a party";
+ERR_QUEST_PUSH_ONQUEST_S = "%s is already on that quest";
+ERR_QUEST_PUSH_SUCCESS_S = "Sharing quest with %s...";
+ERR_QUEST_PUSH_TIMER_EXPIRED_S = "Quest sharing timer has expired";
+ERR_QUEST_REWARD_EXP_I = "Experience gained: %d.";
+ERR_QUEST_REWARD_ITEM_MULT_IS = "Received %d of item: %s.";
+ERR_QUEST_REWARD_ITEM_S = "Received item: %s.";
+ERR_QUEST_REWARD_MONEY_S = "Received %s.";
+ERR_QUEST_UNKNOWN_COMPLETE = "Objective Complete.";
+ERR_RAID_DIFFICULTY_CHANGED_S = "Raid Difficulty set to %s.";
+ERR_RAID_DIFFICULTY_FAILED = "Unable to change Raid Difficulty";
+ERR_RAID_DISALLOWED_BY_LEVEL = "Character too low level for raid.";
+ERR_RAID_GROUP_FULL = "The instance is full.";
+ERR_RAID_GROUP_LOWLEVEL = "You are too low level to enter this instance.";
+ERR_RAID_GROUP_ONLY = "You must be in a raid group to enter this instance.";
+ERR_RAID_GROUP_REQUIREMENTS_UNMATCH = "You do not meet the requirements to enter this instance.";
+ERR_RAID_LEADER_READY_CHECK_START_S = "%s has initiated a ready check.";
+ERR_RAID_LOCKOUT_CHANGED_S = "Raid Lockout set to %s.";
+ERR_RAID_MEMBER_ADDED_S = "%s has joined the raid group.";
+ERR_RAID_MEMBER_REMOVED_S = "%s has left the raid group.";
+ERR_RAID_YOU_JOINED = "You have joined a raid group.";
+ERR_RAID_YOU_LEFT = "You have left the raid group.";
+ERR_READY_CHECK_IN_PROGRESS = "You are already running a ready check";
+ERR_READY_CHECK_THROTTLED = "You can't do that yet";
+ERR_RECEIVE_ITEM_S = "%s received.";
+ERR_REFER_A_FRIEND_DIFFERENT_FACTION = "You cannot grant levels to a character of the opposite faction";
+ERR_REFER_A_FRIEND_GRANT_LEVEL_MAX_I = "You cannot grant levels to players level %d or higher";
+ERR_REFER_A_FRIEND_INSUFFICIENT_GRANTABLE_LEVELS = "You have not earned enough levels to grant any more levels";
+ERR_REFER_A_FRIEND_INSUF_EXPAN_LVL = "That player does not have the required expansion to access this area";
+ERR_REFER_A_FRIEND_NOT_NOW = "You cannot grant that player a level right now.";
+ERR_REFER_A_FRIEND_NOT_REFERRED_BY = "You were not referred by that player";
+ERR_REFER_A_FRIEND_SUMMON_COOLDOWN = "You can only summon your friend once per hour";
+ERR_REFER_A_FRIEND_SUMMON_LEVEL_MAX_I = "You cannot summon players above level %d";
+ERR_REFER_A_FRIEND_SUMMON_OFFLINE_S = "%s is offline and cannot be summoned";
+ERR_REFER_A_FRIEND_TARGET_TOO_HIGH = "That player's level is too high";
+ERR_REFER_A_FRIEND_TOO_FAR = "That player is too far away";
+ERR_REMOVE_FROM_PVP_QUEUE_FACTION_CHANGE_NONE = "You have been removed from a PvP Queue because you changed your faction.";
+ERR_REMOVE_FROM_PVP_QUEUE_GRANT_LEVEL = "You have been removed from a PVP queue because another player has granted you a level";
+ERR_REMOVE_FROM_PVP_QUEUE_XP_GAIN = "You have been removed from a PVP queue because you have changed your XP gain settings";
+ERR_RESTRICTED_ACCOUNT = "Trial accounts cannot perform that action";
+ERR_SCALING_STAT_ITEM_LEVEL_EXCEEDED = "Your level is too high to use that item";
+ERR_SET_LOOT_FREEFORALL = "Looting changed to Free for All.";
+ERR_SET_LOOT_GROUP = "Looting changed to Group Loot.";
+ERR_SET_LOOT_MASTER = "Looting changed to Master Looter.";
+ERR_SET_LOOT_NBG = "Looting set to Need Before Greed.";
+ERR_SET_LOOT_ROUNDROBIN = "Looting changed to Round Robin.";
+ERR_SET_LOOT_THRESHOLD_S = "Loot threshold set to %s.";
+ERR_SHAPESHIFT_FORM_CANNOT_EQUIP = "Cannot equip item in this form";
+ERR_SKILL_GAINED_S = "You have gained the %s skill.";
+ERR_SKILL_UP_SI = "Your skill in %s has increased to %d.";
+ERR_SLOT_EMPTY = "That slot is empty.";
+ERR_SOCKETING_META_GEM_ONLY_IN_METASLOT = "Meta gems can only be placed in meta gem slots";
+ERR_SOCKETING_REQUIRES_META_GEM = "That slot requires a meta gem";
+ERR_SPECIFY_MASTER_LOOTER = "You must specify a loot master.";
+ERR_SPELL_ALREADY_KNOWN_S = "You already know %s.";
+ERR_SPELL_COOLDOWN = "Spell is not ready yet.";
+ERR_SPELL_FAILED_ALREADY_AT_FULL_HEALTH = "You are already at full Health";
+ERR_SPELL_FAILED_ALREADY_AT_FULL_MANA = "You are already at full Mana";
+ERR_SPELL_FAILED_ALREADY_AT_FULL_POWER_S = "You are already at full %s";
+ERR_SPELL_FAILED_EQUIPPED_ITEM = "Must have the proper item equipped";
+ERR_SPELL_FAILED_EQUIPPED_ITEM_CLASS_S = "%s";
+ERR_SPELL_FAILED_NOTUNSHEATHED = "You have to be unsheathed to do that!";
+ERR_SPELL_FAILED_REAGENTS = "%s";
+ERR_SPELL_FAILED_REAGENTS_GENERIC = "Missing reagent";
+ERR_SPELL_FAILED_S = "%s";
+ERR_SPELL_FAILED_SHAPESHIFT_FORM_S = "%s";
+ERR_SPELL_FAILED_TOTEMS = "%s";
+ERR_SPELL_OUT_OF_RANGE = "Out of range.";
+ERR_SPELL_UNLEARNED_S = "You have unlearned %s.";
+ERR_SPLIT_FAILED = "Couldn't split those items.";
+ERR_SYSTEM_DISABLED = "This system is currently disabled.";
+ERR_TALENT_WIPE_ERROR = "You have not spent any talent points.";
+ERR_TAME_FAILED = "%s.";
+ERR_TARGET_LOGGING_OUT = "That player is logging out";
+ERR_TARGET_NOT_IN_GROUP_S = "%s is not in your party.";
+ERR_TARGET_NOT_IN_INSTANCE_S = "%s is not in your instance.";
+ERR_TARGET_STUNNED = "Target is stunned";
+ERR_TAXINOPATH = "The selected path doesn't exist!";
+ERR_TAXINOPATHS = "You don’t know any flight locations connected to this one.";
+ERR_TAXINOSUCHPATH = "There is no direct path to that destination!";
+ERR_TAXINOTENOUGHMONEY = "You don't have enough money!";
+ERR_TAXINOTSTANDING = "You need to be standing to go anywhere.";
+ERR_TAXINOTVISITED = "You haven't reached that taxi node on foot yet!";
+ERR_TAXINOVENDORNEARBY = "There is no taxi vendor nearby!";
+ERR_TAXIPLAYERALREADYMOUNTED = "You are already mounted! Dismount first.";
+ERR_TAXIPLAYERBUSY = "You are busy and can't use the taxi service now.";
+ERR_TAXIPLAYERMOVING = "You are moving.";
+ERR_TAXIPLAYERSHAPESHIFTED = "You can't take a taxi while shapeshifted!";
+ERR_TAXISAMENODE = "You are already there!";
+ERR_TAXITOOFARAWAY = "You are too far away from the taxi stand!";
+ERR_TAXIUNSPECIFIEDSERVERERROR = "UNSPECIFIED TAXI SERVER ERROR";
+ERR_TICKET_ALREADY_EXISTS = "You already have a GM ticket.";
+ERR_TICKET_CREATE_ERROR = "Error creating GM ticket.";
+ERR_TICKET_DB_ERROR = "Error retrieving GM ticket.";
+ERR_TICKET_NO_TEXT = "You must enter text for your ticket.";
+ERR_TICKET_TEXT_TOO_LONG = "Your ticket text was too long.";
+ERR_TICKET_UPDATE_ERROR = "Error updating GM ticket.";
+ERR_TOOBUSYTOFOLLOW = "You're too busy to follow anything!";
+ERR_TOO_FAR_TO_ATTACK = "You are too far away from your victim!";
+ERR_TOO_FAR_TO_INTERACT = "You need to be closer to interact with that target.";
+ERR_TOO_FEW_TO_SPLIT = "Tried to split more than number in stack.";
+ERR_TOO_MANY_CHAT_CHANNELS = "You can only be in 10 channels at a time.";
+ERR_TOO_MANY_SOCKETS = "That item has too many sockets";
+ERR_TOO_MANY_SPECIAL_BAGS = "You cannot equip another bag of that type";
+ERR_TOO_MUCH_GOLD = "At gold limit";
+ERR_TRADE_BAG = "You can't trade non-empty bags.";
+ERR_TRADE_BAG_FULL = "Trade failed, you don't have enough space.";
+ERR_TRADE_BLOCKED_S = "%s has requested to trade. You have refused.";
+ERR_TRADE_BOUND_ITEM = "You can't trade a soulbound item.";
+ERR_TRADE_CANCELLED = "Trade cancelled.";
+ERR_TRADE_COMPLETE = "Trade complete.";
+ERR_TRADE_EQUIPPED_BAG = "You can't trade equipped bags.";
+ERR_TRADE_GROUND_ITEM = "You can't trade an item from the ground.";
+ERR_TRADE_MAX_COUNT_EXCEEDED = "You have too many of a unique item.";
+ERR_TRADE_NOT_ON_TAPLIST = "You may only trade bound items to players that were originally eligible to loot the item";
+ERR_TRADE_QUEST_ITEM = "You can't trade a quest item.";
+ERR_TRADE_REQUEST_S = "%s has requested to trade with you.";
+ERR_TRADE_SELF = "You can't trade with yourself.";
+ERR_TRADE_TARGET_BAG_FULL = "Trade failed, target doesn't have enough space.";
+ERR_TRADE_TARGET_DEAD = "You can't trade with dead players.";
+ERR_TRADE_TARGET_MAX_COUNT_EXCEEDED = "Your trade partner has too many of a unique item.";
+ERR_TRADE_TARGET_MAX_LIMIT_CATEGORY_COUNT_EXCEEDED_IS = "Your trade partner can only carry %d %s";
+ERR_TRADE_TEMP_ENCHANT_BOUND = "You may not trade an item with a temporary enhancement.";
+ERR_TRADE_TOO_FAR = "Trade target is too far away.";
+ERR_TRADE_WRONG_REALM = "You may only trade conjured items to players from other realms";
+ERR_UNHEALTHY_TIME = "You are in unhealthy time, you should log off now.";
+ERR_UNINVITE_YOU = "You have been removed from the group.";
+ERR_UNIT_NOT_FOUND = "Unknown unit.";
+ERR_UNKNOWN_MACRO_OPTION_S = "Unknown macro option: %s";
+ERR_USER_SQUELCHED = "Your chat and mail privileges have been temporarily suspended pending Game Master review.";
+ERR_USE_BAD_ANGLE = "You aren't facing the right angle!";
+ERR_USE_CANT_IMMUNE = "You can't do that while you are immune.";
+ERR_USE_CANT_OPEN = "You can't open that.";
+ERR_USE_DESTROYED = "That is destroyed.";
+ERR_USE_LOCKED = "Item is locked.";
+ERR_USE_LOCKED_WITH_ITEM_S = "Requires %s";
+ERR_USE_LOCKED_WITH_SPELL_KNOWN_SI = "Requires %s %d";
+ERR_USE_LOCKED_WITH_SPELL_S = "Requires %s";
+ERR_USE_OBJECT_MOVING = "Object is in motion.";
+ERR_USE_PREVENTED_BY_MECHANIC_S = "Can't use while %s.";
+ERR_USE_SPELL_FOCUS = "Object is a spell focus.";
+ERR_USE_TOO_FAR = "You are too far away.";
+ERR_VENDOR_DOESNT_BUY = "You cannot sell items to this merchant";
+ERR_VENDOR_HATES_YOU = "That merchant doesn't like you.";
+ERR_VENDOR_MISSING_TURNINS = "You do not have the required items for that purchase";
+ERR_VENDOR_NOT_INTERESTED = "The merchant doesn't want that item.";
+ERR_VENDOR_SOLD_OUT = "That item is currently sold out.";
+ERR_VENDOR_TOO_FAR = "You are too far away.";
+ERR_VOICESESSION_FULL = "The voice session you are attempting to join is full.";
+ERR_VOICE_CHAT_PARENTAL_DISABLE_ALL = "Voice Chat has been disabled by Parental Controls.";
+ERR_VOICE_CHAT_PARENTAL_DISABLE_MIC = "Microphone has been disabled by Parental Controls.";
+ERR_VOICE_IGNORE_ADDED_S = "%s is now being voice muted.";
+ERR_VOICE_IGNORE_ALREADY_S = "%s is already being voice muted.";
+ERR_VOICE_IGNORE_AMBIGUOUS = "That name is ambiguous, type more of the player's server name.";
+ERR_VOICE_IGNORE_DELETED = "Voice mute removed because the character no longer exists.";
+ERR_VOICE_IGNORE_FULL = "You can't voice mute any more players.";
+ERR_VOICE_IGNORE_NOT_FOUND = "Player not found.";
+ERR_VOICE_IGNORE_REMOVED_S = "%s is no longer being voice muted.";
+ERR_VOICE_IGNORE_SELF = "You can't voice mute yourself.";
+ERR_WRONG_BAG_TYPE = "That item doesn't go in that container.";
+ERR_WRONG_BAG_TYPE_SUBCLASS = "Only %s can be placed in that.";
+ERR_WRONG_DIRECTION_FOR_ATTACK = "You aren't facing the right way to attack!";
+ERR_WRONG_SLOT = "That item does not go in that slot.";
+ERR_YELL_RESTRICTED = "Trial accounts cannot yell.";
+ERR_ZONE_EXPLORED = "Discovered: %s";
+ERR_ZONE_EXPLORED_XP = "Discovered %s: %d experience gained";
+ESES = "Spanish (EU)";
+ESMX = "Spanish (Latin American)";
+EVADE = "Evade";
+EVENTS_LABEL = "Events";
+EXAMPLE_SPELL_FIREBALL = "Fireball";
+EXAMPLE_SPELL_FROSTBOLT = "Frostbolt";
+EXAMPLE_TARGET_MONSTER = "Monster";
+EXAMPLE_TEXT = "Example Text:";
+EXHAUSTION_LABEL = "Fatigue";
+EXHAUST_TOOLTIP1 = "|cffffd200%s|r\n|cffffffff%d%% of normal experience\ngained from monsters.|r";
+EXHAUST_TOOLTIP2 = "\n|cffff0000You should rest at an Inn.|r";
+EXHAUST_TOOLTIP3 = "\n\nIn this condition, you can get\n%d more monster experience\nbefore the next rest state.";
+EXHAUST_TOOLTIP4 = "\n\n|cffffd200Resting|r\n|cffffffffYou must rest for %d additional\nminutes to become|r |cffffd200Fully Rested|r|cffffffff.|r";
+EXIT = "Exit";
+EXIT_GAME = "Exit Game";
+EXOTICS = "Exotic Weapons";
+EXPANSION_NAME0 = "Classic";
+EXPANSION_NAME1 = "The Burning Crusade";
+EXPANSION_NAME2 = "Wrath of the Lich King";
+EXPERIENCE_COLON = "Experience:";
+EXPERTISE_ABBR = "Expr";
+EXTENDED = "|cff00ff00Extended|r";
+EXTEND_RAID_LOCK = "Extend Raid Lock";
+EXTRA_ATTACKS = "Extra Attacks";
+EYE_SEPARATION = "Depth Amount";
+English = "";
+FACIAL_HAIR_EARRINGS = "Earrings";
+FACIAL_HAIR_FEATURES = "Features";
+FACIAL_HAIR_HAIR = "Hair";
+FACIAL_HAIR_HORNS = "Horn Style";
+FACIAL_HAIR_MARKINGS = "Markings";
+FACIAL_HAIR_NORMAL = "Facial Hair";
+FACIAL_HAIR_PIERCINGS = "Piercings";
+FACIAL_HAIR_TUSKS = "Tusks";
+FACING_WRONG_DIRECTION = "You aren't facing the right direction!";
+FACTION = "Faction";
+FACTION_ALLIANCE = "Alliance";
+FACTION_CONTROLLED_TERRITORY = "(%s Territory)";
+FACTION_HORDE = "Horde";
+FACTION_INACTIVE = "Inactive";
+FACTION_OTHER = "Other";
+FACTION_STANDING_CHANGED = "You are now %s with %s.";
+FACTION_STANDING_DECREASED = "Reputation with %s decreased by %d.";
+FACTION_STANDING_DECREASED_GENERIC = "Reputation with %s decreased.";
+FACTION_STANDING_INCREASED = "Reputation with %s increased by %d.";
+FACTION_STANDING_INCREASED_BONUS = "Reputation with %s increased by %d. (+%.1f Refer-A-Friend bonus)";
+FACTION_STANDING_INCREASED_GENERIC = "Reputation with %s increased.";
+FACTION_STANDING_LABEL1 = "Hated";
+FACTION_STANDING_LABEL1_FEMALE = "Hated";
+FACTION_STANDING_LABEL2 = "Hostile";
+FACTION_STANDING_LABEL2_FEMALE = "Hostile";
+FACTION_STANDING_LABEL3 = "Unfriendly";
+FACTION_STANDING_LABEL3_FEMALE = "Unfriendly";
+FACTION_STANDING_LABEL4 = "Neutral";
+FACTION_STANDING_LABEL4_FEMALE = "Neutral";
+FACTION_STANDING_LABEL5 = "Friendly";
+FACTION_STANDING_LABEL5_FEMALE = "Friendly";
+FACTION_STANDING_LABEL6 = "Honored";
+FACTION_STANDING_LABEL6_FEMALE = "Honored";
+FACTION_STANDING_LABEL7 = "Revered";
+FACTION_STANDING_LABEL7_FEMALE = "Revered";
+FACTION_STANDING_LABEL8 = "Exalted";
+FACTION_STANDING_LABEL8_FEMALE = "Exalted";
+FAILED = "Failed";
+FAILURES = "Failures";
+FAR = "Far";
+FARCLIP = "View Distance";
+FEATURES_LABEL = "Features";
+FEATURES_SUBTEXT = "These options allow you to enable and disable full game features.";
+FEATURE_BECOMES_AVAILABLE_AT_LEVEL = "This feature becomes available at level %d.";
+FEAT_OF_STRENGTH_DESCRIPTION = "Feats of Strength are accomplishments that players will find very difficult if not impossible to earn. Worth no points, Feats of Strength are a collection of past glories on Azeroth.";
+FEEDPET_LOG_FIRSTPERSON = "Your pet begins eating the %s.";
+FEEDPET_LOG_THIRDPERSON = "%s's pet begins eating a %s.";
+FEETSLOT = "Feet";
+FEMALE = "Female";
+FERAL_DRUID_ITEM_AP = "Increases attack power by %d in Cat, Bear, Dire Bear, and Moonkin forms only.";
+FILTER = "Filter";
+FILTERS = "Filters";
+FILTER_BY_ENEMIES_COMBATLOG_TOOLTIP = "Actions performed by hostile creatures and pets.";
+FILTER_BY_FRIENDS_COMBATLOG_TOOLTIP = "Actions performed by friendly players, pets, and creatures.";
+FILTER_BY_HOSTILE_PLAYERS_COMBATLOG_TOOLTIP = "Actions performed by hostile players.";
+FILTER_BY_ME_COMBATLOG_TOOLTIP = "Actions performed by you, your traps, and your spells.";
+FILTER_BY_NEUTRAL_COMBATLOG_TOOLTIP = "Actions performed by neutral creatures.";
+FILTER_BY_PET_COMBATLOG_TOOLTIP = "Actions performed by your pets, summoned guardians, and charmed players.";
+FILTER_BY_UNKNOWN_COMBATLOG_TOOLTIP = "Actions performed by undefined sources such as falling, acid, or lava.";
+FILTER_NAME = "Filter Name";
+FILTER_TO_FRIENDS_COMBATLOG_TOOLTIP = "Actions performed on friendly players, pets, and creatures.";
+FILTER_TO_HOSTILE_COMBATLOG_TOOLTIP = "Actions performed on hostile pets and creatures.";
+FILTER_TO_HOSTILE_PLAYERS_COMBATLOG_TOOLTIP = "Actions performed on hostile players.";
+FILTER_TO_ME_COMBATLOG_TOOLTIP = "Actions performed on you.";
+FILTER_TO_NEUTRAL_COMBATLOG_TOOLTIP = "Actions performed on neutral creatures.";
+FILTER_TO_PET_COMBATLOG_TOOLTIP = "Actions performed on your pets, summoned guardians, and charmed players.";
+FILTER_TO_UNKNOWN_COMBATLOG_TOOLTIP = "Actions performed on invisible targets.";
+FIND_A_GROUP = "Find Group";
+FIND_DUNGEON = "Find Dungeon";
+FINGER0SLOT = "Finger";
+FINGER0SLOT_UNIQUE = "Ring 1";
+FINGER1SLOT = "Finger";
+FINGER1SLOT_UNIQUE = "Ring 2";
+FIRST_AVAILABLE = "First Available";
+FIRST_AVAILABLE_TOOLTIP = "Join the queue to enter the first available battleground. If you select \"first available\" and another party member enters a \"first available\" battleground, then your preference will be changed to that battleground.";
+FIRST_NUMBER_CAP = " K";
+FIX_LAG = "Reduce Input Lag";
+FLAG_COUNT_TEMPLATE = "x %d";
+FLOOR = "Areas";
+FLOOR_NUMBER = "Area %d";
+FOCUS = "Focus";
+FOCUSTARGET = "Set Focus Target";
+FOCUS_CAST_KEY_TEXT = "Focus Cast Key";
+FOCUS_COST = "%d Focus";
+FOCUS_COST_PER_TIME = "%d Focus, plus %d per sec";
+FOCUS_TOKEN_NOT_FOUND = "";
+FOLLOW = "Follow";
+FOLLOW_TERRAIN = "Follow Terrain";
+FONT_SIZE = "Font Size";
+FONT_SIZE_TEMPLATE = "%d pt";
+FOOD_TIMER = "You are too full to eat more now.";
+FOREIGN_SERVER_LABEL = " (*)";
+FORMATED_HOURS = "%d |4Hour:Hours;";
+FORMATTING = "Formatting";
+FPS_ABBR = "fps";
+FRAMERATE_LABEL = "FPS:";
+FREE_FOR_ALL_TERRITORY = "(PvP Area)";
+FRFR = "French";
+FRIEND = "Friend";
+FRIENDLY = "Friendly";
+FRIENDS = "Friends";
+FRIENDS_FRIENDS_CHOICE_EVERYONE = "Everyone";
+FRIENDS_FRIENDS_CHOICE_MUTUAL = "Mutual Friends";
+FRIENDS_FRIENDS_CHOICE_POTENTIAL = "Potential Friends";
+FRIENDS_FRIENDS_HEADER = "Friends of %s";
+FRIENDS_FRIENDS_MUTUAL_TEXT = "(Mutual)";
+FRIENDS_FRIENDS_REQUESTED_TEXT = "(request sent)";
+FRIENDS_FRIENDS_WAITING = "Searching...";
+FRIENDS_LEVEL_TEMPLATE = "Level %d %s";
+FRIENDS_LIST = "Friends List";
+FRIENDS_LIST_AVAILABLE = "Available";
+FRIENDS_LIST_AWAY = "Away";
+FRIENDS_LIST_BUSY = "Busy";
+FRIENDS_LIST_ENTER_TEXT = "Tell your friends what you're doing";
+FRIENDS_LIST_NOTE_OFFLINE_TEMPLATE = "|cff999999(%s)|r";
+FRIENDS_LIST_NOTE_TEMPLATE = "(%s)";
+FRIENDS_LIST_OFFLINE = "Offline";
+FRIENDS_LIST_OFFLINE_TEMPLATE = "|cff999999%s - Offline|r";
+FRIENDS_LIST_ONLINE = "Online";
+FRIENDS_LIST_PLAYING = "Also Playing:";
+FRIENDS_LIST_REALM = "Realm: ";
+FRIENDS_LIST_STATUS_TOOLTIP = "Status: |cffffffff%s";
+FRIENDS_LIST_TEMPLATE = "|cffffffff- %s|r %s";
+FRIENDS_LIST_WOW_TEMPLATE = "%1$s, %2$d %3$s";
+FRIENDS_LIST_ZONE = "Zone: ";
+FRIENDS_TOOLTIP_TOO_MANY_CHARACTERS = "(%d more |4character:characters;)";
+FRIENDS_TOOLTIP_WOW_TOON_TEMPLATE = "%1$s, %2$s %3$s %4$s";
+FROM = "From:";
+FUEL = "Fuel";
+FULLDATE = "%1$s, %2$s %3$d %4$d";
+FULLDATE_AND_TIME = "%1$s, %2$s";
+FULLDATE_MONTH_APRIL = "April";
+FULLDATE_MONTH_AUGUST = "August";
+FULLDATE_MONTH_DECEMBER = "December";
+FULLDATE_MONTH_FEBRUARY = "February";
+FULLDATE_MONTH_JANUARY = "January";
+FULLDATE_MONTH_JULY = "July";
+FULLDATE_MONTH_JUNE = "June";
+FULLDATE_MONTH_MARCH = "March";
+FULLDATE_MONTH_MAY = "May";
+FULLDATE_MONTH_NOVEMBER = "November";
+FULLDATE_MONTH_OCTOBER = "October";
+FULLDATE_MONTH_SEPTEMBER = "September";
+FULL_SCREEN_GLOW = "Full-Screen Glow Effect";
+FULL_SIZE_FOCUS_FRAME_TEXT = "Larger Focus Frame";
+FULL_TEXT_COMBATLOG_TOOLTIP = "Show combat log entries as full sentences.";
+GAIN_EXPERIENCE = "|cffffffff%d|r Experience";
+GAME = "Game";
+GAMEFIELD_DESELECT_TEXT = "Sticky Targeting";
+GAMEOPTIONS_MENU = "Options";
+GAMES = "Games";
+GAMETIME_TOOLTIP_CALENDAR_INVITES = "You have pending calendar invites.";
+GAMETIME_TOOLTIP_TOGGLE_CALENDAR = "Click to show the calendar.";
+GAMETIME_TOOLTIP_TOGGLE_CLOCK = "Click to show clock settings.";
+GAME_SOUND_OUTPUT = "Game Sound Output";
+GAME_VERSION_LABEL = "Version";
+GAMMA = "Gamma";
+GEARSETS_POPUP_TEXT = "Enter Set Name (Max 16 Characters):";
+GEARSETS_TITLE = "Gear Manager";
+GENERAL = "General";
+GENERAL_LABEL = "General";
+GENERAL_MACROS = "General Macros";
+GENERAL_SPELLS = "General";
+GENERAL_SUBTEXT = "These options allow you to change the size and detail in which your video hardware renders the game.";
+GIVE_LOOT = "Give Loot To:";
+GLANCING_TRAILER = " (glancing)";
+GLOBAL_CHANNELS = "Global Channels";
+GLYPHS = "Glyphs";
+GLYPH_EMPTY = "Empty";
+GLYPH_EMPTY_DESC = "Use a Glyph from your inventory to inscribe your spellbook.";
+GLYPH_FILLED = "Filled";
+GLYPH_INACTIVE = "Empty";
+GLYPH_LOCKED = "Locked";
+GLYPH_SLOT_REMOVE_TOOLTIP = "";
+GLYPH_SLOT_TOOLTIP1 = "Unlocked at level 15.";
+GLYPH_SLOT_TOOLTIP2 = "Unlocked at level 15.";
+GLYPH_SLOT_TOOLTIP3 = "Unlocked at level 50.";
+GLYPH_SLOT_TOOLTIP4 = "Unlocked at level 30.";
+GLYPH_SLOT_TOOLTIP5 = "Unlocked at level 70.";
+GLYPH_SLOT_TOOLTIP6 = "Unlocked at level 80.";
+GMSURVEYRATING1 = "Bad";
+GMSURVEYRATING2 = "Poor";
+GMSURVEYRATING3 = "Average";
+GMSURVEYRATING4 = "Good";
+GMSURVEYRATING5 = "Excellent";
+GMSURVEY_BLOCK_TEXT = "Compared with other customer service experiences I have had:";
+GMSURVEY_EXCELLENT = "5 (Excellent)";
+GMSURVEY_POOR = "1 (Poor)";
+GMSURVEY_REQUEST_TEXT = "Please answer the following questions:";
+GMSURVEY_SUBMITTED = "Your survey has been submitted";
+GMSURVEY_TITLE = "Game Master (GM) Customer Service Survey";
+GM_CHAT = "Chatting with a GM";
+GM_CHAT_LAST_SESSION = "In your last session, you were speaking with %s.";
+GM_CHAT_OPEN = "Open GM Chat Log";
+GM_CHAT_STATUS_READY = "GM Chat Request";
+GM_CHAT_STATUS_READY_DESCRIPTION = "A GM would like to chat with you. Click here to begin.";
+GM_EMAIL_NAME = "Customer Support";
+GM_RESPONSE_ALERT = "You have received a ticket response. Click here to read it.";
+GM_RESPONSE_FRAME_HEADER = "Game Master Response:";
+GM_RESPONSE_ISSUE_HEADER = "Issue:";
+GM_RESPONSE_MESSAGE_HEADER = "Game Master (GM) Response:";
+GM_RESPONSE_MORE_HELP = "Need More Help";
+GM_RESPONSE_POPUP_MUST_RESOLVE_RESPONSE = "You cannot do that until you read your current GM response.";
+GM_RESPONSE_POPUP_NEED_MORE_HELP_WARNING = "You will no longer be able to view your response message if you request more help. Are you sure you want to open a follow-up ticket?";
+GM_RESPONSE_POPUP_RESOLVE_CONFIRM = "You will no longer be able to view your response message if you mark it as read. Are you sure you want to mark your message read?";
+GM_RESPONSE_POPUP_VIEW_RESPONSE = "View Response";
+GM_RESPONSE_RESOLVE = "Message Read";
+GM_SURVEY_NOT_APPLICABLE = "N/A";
+GM_TICKET_ESCALATED = "Your ticket has been escalated.";
+GM_TICKET_HIGH_VOLUME = "We are currently experiencing a high volume of petitions.";
+GM_TICKET_SERVICE_SOON = "Your ticket will be serviced soon.";
+GM_TICKET_UNAVAILABLE = "Wait time currently unavailable.";
+GM_TICKET_WAIT_TIME = "Approximate time remaining:\n%s";
+GOLD_AMOUNT = "%d Gold";
+GOLD_AMOUNT_SYMBOL = "g";
+GOLD_AMOUNT_TEXTURE = "%d\124TInterface\\MoneyFrame\\UI-GoldIcon:%d:%d:2:0\124t";
+GOLD_PER_DAY = "Max Gold/Day";
+GOODBYE = "Goodbye";
+GOSSIP_OPTIONS = "Gossip Options";
+GREED = "Greed";
+GREED_NEWBIE = "You'll take the item, but only if nobody else really wants it.";
+GROUND_DENSITY = "Ground Clutter Density";
+GROUND_RADIUS = "Ground Clutter Radius";
+GROUP = "Group";
+GROUPS = "Groups";
+GROUP_INVITE = "Group Invite";
+GUIDE = "Guide";
+GUIDE_TOOLTIP = "Indicates that you have some dungeon experience and are comfortable instructing the group in how to overcome the encounters.";
+GUILD = "Guild";
+GUILDADDRANK_BUTTON_TOOLTIP = "Click to add rank";
+GUILDBANK_AVAILABLE_MONEY = "Available Amount:";
+GUILDBANK_BUYTAB_MONEY_FORMAT = "%s purchased a guild bank tab for %s";
+GUILDBANK_DEPOSIT = "Amount to deposit:";
+GUILDBANK_DEPOSIT_FORMAT = "%s deposited %s";
+GUILDBANK_DEPOSIT_MONEY_FORMAT = "%s deposited %s";
+GUILDBANK_INFO_TITLE_FORMAT = "%s Info";
+GUILDBANK_LOG_QUANTITY = " x %d";
+GUILDBANK_LOG_TITLE_FORMAT = "%s Log";
+GUILDBANK_MOVE_FORMAT = "%s moved %s x %d from %s to %s";
+GUILDBANK_NAME_CONFIG = "%s Config:";
+GUILDBANK_POPUP_TEXT = "Enter Guild Bank Tab Name:";
+GUILDBANK_REMAINING_MONEY = "Remaining Daily Withdrawals for %s: |cffffffff%s|r";
+GUILDBANK_REPAIR = "Remaining amount for today's Guild Bank repairs:";
+GUILDBANK_REPAIR_MONEY_FORMAT = "%s withdrew %s for repairs";
+GUILDBANK_TAB_COLON = "Guild Bank Tab:";
+GUILDBANK_TAB_DEPOSIT_ONLY = "Deposit Only";
+GUILDBANK_TAB_FULL_ACCESS = "Full Access";
+GUILDBANK_TAB_LOCKED = "Locked";
+GUILDBANK_TAB_NUMBER = "Tab%d";
+GUILDBANK_TAB_WITHDRAW_ONLY = "Withdraw Only";
+GUILDBANK_WITHDRAW = "Amount to withdraw:";
+GUILDBANK_WITHDRAWFORTAB_MONEY_FORMAT = "%s withdrew %s to purchase a guild bank tab";
+GUILDBANK_WITHDRAW_FORMAT = "%s |cffff2020withdrew|r %s";
+GUILDBANK_WITHDRAW_MONEY_FORMAT = "%s |cffff2020withdrew|r %s";
+GUILDCONTROL = "Guild Control";
+GUILDCONTROL_ALLOWRANK = "Allow this rank to:";
+GUILDCONTROL_DEPOSIT_ITEMS = "Deposit Items";
+GUILDCONTROL_OPTION1 = "Guildchat Listen";
+GUILDCONTROL_OPTION10 = "Edit Public Note";
+GUILDCONTROL_OPTION11 = "View Officer Note";
+GUILDCONTROL_OPTION12 = "Edit Officer Note";
+GUILDCONTROL_OPTION13 = "Modify Guild Info";
+GUILDCONTROL_OPTION14 = "Create Guild Event";
+GUILDCONTROL_OPTION15 = "Repair";
+GUILDCONTROL_OPTION15_TOOLTIP = "Use guild funds for repairs";
+GUILDCONTROL_OPTION16 = "Gold";
+GUILDCONTROL_OPTION16_TOOLTIP = "Withdraw gold from the guild bank";
+GUILDCONTROL_OPTION17 = "Create Guild Event";
+GUILDCONTROL_OPTION2 = "Guildchat Speak";
+GUILDCONTROL_OPTION3 = "Officerchat Listen";
+GUILDCONTROL_OPTION4 = "Officerchat Speak";
+GUILDCONTROL_OPTION5 = "Promote";
+GUILDCONTROL_OPTION6 = "Demote";
+GUILDCONTROL_OPTION7 = "Invite Member";
+GUILDCONTROL_OPTION8 = "Remove Member";
+GUILDCONTROL_OPTION9 = "Set MOTD";
+GUILDCONTROL_RANKLABEL = "Rank Label:";
+GUILDCONTROL_SELECTRANK = "Select guild rank to modify:";
+GUILDCONTROL_UPDATE_TEXT = "Update Tab Text";
+GUILDCONTROL_VIEW_TAB = "View Tab";
+GUILDCONTROL_WITHDRAW_GOLD = "Withdraw:";
+GUILDCONTROL_WITHDRAW_ITEMS = "Withdraw Items(stacks/day):";
+GUILDEVENT_TYPE_DEMOTE = "%s demotes %s to %s";
+GUILDEVENT_TYPE_INVITE = "%s invites %s";
+GUILDEVENT_TYPE_JOIN = "%s joins the guild";
+GUILDEVENT_TYPE_PROMOTE = "%s promotes %s to %s";
+GUILDEVENT_TYPE_QUIT = "%s leaves the guild";
+GUILDEVENT_TYPE_REMOVE = "%s removes %s from the guild";
+GUILDMEMBER_ALERT = "Guild Member Alert";
+GUILDMOTD_BUTTON_TOOLTIP = "Click to View the Guild Message Of The Day";
+GUILDNOTE_BUTTON_TOOLTIP = "Click to View your Guild's Message of the Day";
+GUILDOFFICERNOTE_BUTTON_TOOLTIP = "Click to View the selected player's Officer's Note";
+GUILDREMOVERANK_BUTTON_TOOLTIP = "Click to remove this rank";
+GUILD_ACHIEVEMENT = "Guild Announce";
+GUILD_BANK = "Guild Bank";
+GUILD_BANK_LOG = "Log";
+GUILD_BANK_LOG_TIME = "( %s ago )";
+GUILD_BANK_MONEY_LOG = "Money Log";
+GUILD_BANK_TAB_INFO = "Info";
+GUILD_CHARTER = "Guild Charter";
+GUILD_CHARTER_CREATOR = "Guild Master: %s";
+GUILD_CHARTER_PURCHASE = "Purchase a Guild Charter";
+GUILD_CHARTER_REGISTER = "Register a Guild Charter";
+GUILD_CHARTER_TEMPLATE = "%s Guild Charter";
+GUILD_CHARTER_TITLE = "Guild Name: %s";
+GUILD_CHAT = "Guild Chat";
+GUILD_CREST_DESIGN = "Design a Guild Crest";
+GUILD_EVENT_LOG = "Log";
+GUILD_FRAME_TITLE = "Guild Roster";
+GUILD_HELP_TEXT_LINE1 = "For now, to create a guild type 'guildcreate ' in the console.";
+GUILD_HELP_TEXT_LINE2 = "'/ginfo' gives some basic information about your guild";
+GUILD_HELP_TEXT_LINE3 = "'/g ' sends a chat message to all members of your guild";
+GUILD_HELP_TEXT_LINE4 = "'/o ' sends a chat message to all officers in your guild";
+GUILD_HELP_TEXT_LINE5 = "'/ginvite ' invites another player to join your guild";
+GUILD_HELP_TEXT_LINE6 = "'/gremove ' removes a player from your guild";
+GUILD_HELP_TEXT_LINE7 = "'/gpromote ' promotes a player one rank within your guild";
+GUILD_HELP_TEXT_LINE8 = "'/gdemote ' demotes a player one rank within your guild";
+GUILD_HELP_TEXT_LINE9 = "'/gmotd ' sets the guild's message of the day";
+GUILD_HELP_TEXT_LINE10 = "'/gquit' removes you from your guild";
+GUILD_HELP_TEXT_LINE11 = "'/groster' gives an entire guild roster";
+GUILD_HELP_TEXT_LINE12 = "'/gleader ' sets another player as the guild leader";
+GUILD_HELP_TEXT_LINE13 = "'/gdisband' disbands your guild";
+GUILD_INFORMATION = "Guild Information";
+GUILD_INFO_EDITLABEL = "Click here to set message";
+GUILD_INFO_TEMPLATE = "Guild created %1$d-%2$d-%3$d, %4$d players, %5$d accounts";
+GUILD_INVITATION = "%s invites you to join the guild: %s";
+GUILD_LEAVE = "Leave Guild";
+GUILD_MEMBER_OPTIONS = "Guild Member Options";
+GUILD_MEMBER_TEMPLATE = "%s, %s";
+GUILD_MESSAGE = "Guild Chat";
+GUILD_MOTD = "Guild MOTD";
+GUILD_MOTD_EDITLABEL = "Click here to set the Guild Message Of The Day.";
+GUILD_MOTD_LABEL = "Guild Message Of The Day:";
+GUILD_MOTD_LABEL2 = "Guild Message of the Day";
+GUILD_MOTD_TEMPLATE = "Guild Message of the Day: %s";
+GUILD_NAME = "Guild Name";
+GUILD_NAME_TEMPLATE = "Guild: %s";
+GUILD_NOTES_LABEL = "Player Notes:";
+GUILD_NOTE_EDITLABEL = "Click here to set a Public Note.";
+GUILD_NOT_ALLIED_S = "%s is not part of your alliance.";
+GUILD_OFFICERNOTES_LABEL = "Officer's Notes";
+GUILD_OFFICERNOTE_EDITLABEL = "Click here to set an Officer's Note.";
+GUILD_OFFICER_NOTE = "Guild Officer Note";
+GUILD_ONLINE_LABEL = "Online";
+GUILD_PETITION_LEADER_INSTRUCTIONS = "Select a player you wish to invite and click . To create this guild, turn it in to the guild registrar when you have filled the charter.";
+GUILD_PETITION_MEMBER_INSTRUCTIONS = "Click the button to become a charter member of this guild.";
+GUILD_PROMOTE = "Promote to Guildmaster";
+GUILD_RANK0_DESC = "Guild Master";
+GUILD_RANK1_DESC = "Officer";
+GUILD_RANK2_DESC = "Veteran";
+GUILD_RANK3_DESC = "Member";
+GUILD_RANK4_DESC = "Initiate";
+GUILD_REGISTRAR_PURCHASE_TEXT = "To create a guild you must purchase this charter, get 9 unique player signatures, and return the charter to me. Please enter the desired name for your guild.";
+GUILD_ROSTER_TEMPLATE = "%d players, %d accounts";
+GUILD_STATUS = "Guild Status";
+GUILD_TEMPLATE = "%s of %s";
+GUILD_TITLE_TEMPLATE = "%s of %s";
+GUILD_TOTAL = "|cffffffff%d|r |4Guild Member:Guild Members;";
+GUILD_TOTALONLINE = "(|cffffffff%d|r |cff00ff00Online|r)";
+HAIR_HORNS_COLOR = "Horn Color";
+HAIR_HORNS_STYLE = "Horn Style";
+HAIR_NORMAL_COLOR = "Hair Color";
+HAIR_NORMAL_STYLE = "Hair Style";
+HANDSSLOT = "Hands";
+HAPPINESS = "Happiness";
+HARASSMENT = "Harassment";
+HARASSMENT_POLICY_TEXT = "For more information about our harassment policy please go to:\nwww.worldofwarcraft.com/policy/harassment.shtml";
+HARASSMENT_TEXT = "Please select one of the following options:";
+HARDWARE = "Hardware";
+HARDWARE_CURSOR = "Hardware Cursor";
+HARMFUL_AURA_COMBATLOG_TOOLTIP = "Show when you gain or lose a harmful aura.";
+HATRED = "Hatred";
+HAVE_MAIL = "You have unread mail";
+HAVE_MAIL_FROM = "Unread mail from:";
+HEADSLOT = "Head";
+HEAD_BOB = "Head Bob";
+HEALER = "Healer";
+HEALING_DONE_TOOLTIP = "The total amount of healing done.";
+HEALS = "Heals";
+HEALTH = "Health";
+HEALTH_COLON = "Health:";
+HEALTH_COST = "%d Health";
+HEALTH_COST_PER_TIME = "%d Health, plus %d per sec";
+HEALTH_LOW = "Health Low";
+HELPFRAME_ACCOUNT_BULLET1 = "Help setting up new accounts or making changes to existing accounts";
+HELPFRAME_ACCOUNT_BULLET2 = "Canceling your World of Warcraft account";
+HELPFRAME_ACCOUNT_BULLET3 = "Problems with Authentication Keys";
+HELPFRAME_ACCOUNT_BULLET4 = "Payment options";
+HELPFRAME_ACCOUNT_BULLET_TITLE1 = "Billing & Account services can help with these kinds of issues:";
+HELPFRAME_ACCOUNT_BUTTON_TEXT = "Report Account/Billing Issue";
+HELPFRAME_ACCOUNT_ENDTEXT = "For assistance with any issues like these, please contact Billing & Account Services:|n|nBy Phone at: |cffffd200(800) 59-BLIZZARD|r|nBy Web at: |cffffd200http://us.blizzard.com/support/index.xml?gameId=11|r|nBy Email at: |cffffd200billing@blizzard.com|r |n|nWe also recommend you check the Account Management page at: |n|n|cffffd200www.worldofwarcraft.com/account|r |n|nOn the Account Management page, you can view your subscription information, add game cards, and access other important account functions and options.";
+HELPFRAME_ACCOUNT_TEXT = "Having problems setting up your account or need to make changes to your billing options?";
+HELPFRAME_ACCOUNT_TITLE = "Billing & Account Services";
+HELPFRAME_BUG_BUTTON_DESCRIPTION = "Report a bug or error in the game";
+HELPFRAME_BUG_BUTTON_TEXT = "Submit a Bug:";
+HELPFRAME_CHARACTER_BULLET1 = "Ability/Attribute loss or distortion";
+HELPFRAME_CHARACTER_BULLET2 = "Unable to log in to World of Warcraft";
+HELPFRAME_CHARACTER_BULLET3 = "Skill level is showing as negative";
+HELPFRAME_CHARACTER_BULLET4 = "Profession no longer listed";
+HELPFRAME_CHARACTER_BULLET5 = "Talents malfunctioning or missing";
+HELPFRAME_CHARACTER_BULLET_TITLE1 = "The following are examples of character issues:";
+HELPFRAME_CHARACTER_BUTTON_TEXT = "Report Character Issue";
+HELPFRAME_CHARACTER_TEXT = "Issues regarding abilities, professions, reputation, and talents";
+HELPFRAME_CHARACTER_TITLE = "Character";
+HELPFRAME_ENVIRONMENTAL_BULLET1 = "Unable to interact with a forge";
+HELPFRAME_ENVIRONMENTAL_BULLET2 = "Able to walk/jump through a wall";
+HELPFRAME_ENVIRONMENTAL_BULLET3 = "Getting ported to the wrong graveyard";
+HELPFRAME_ENVIRONMENTAL_BULLET4 = "Falling through the world";
+HELPFRAME_ENVIRONMENTAL_BULLET5 = "Player died and would like a port back to original location";
+HELPFRAME_ENVIRONMENTAL_BULLET6 = "Inquiry of a location that is difficult to find";
+HELPFRAME_ENVIRONMENTAL_BULLET_TITLE1 = "The following are examples of environmental issues:";
+HELPFRAME_ENVIRONMENTAL_BULLET_TITLE2 = "The following are not considered environment issues:";
+HELPFRAME_ENVIRONMENTAL_BUTTON_TEXT = "Report Environmental Issue";
+HELPFRAME_ENVIRONMENTAL_TEXT = "Issues that deal with a character not being able to interact with the environment or operate in the environment";
+HELPFRAME_ENVIRONMENTAL_TITLE = "Environmental";
+HELPFRAME_GENERAL_BUTTON_DESCRIPTION = "Basic game play questions/information";
+HELPFRAME_GENERAL_BUTTON_TEXT = "General Game Play Question:";
+HELPFRAME_GMTALK_ISSUE1 = "This includes information about: quests, non-player characters (NPCs), items, locations, or anything else that the player could possibly find out through exploration and/or interaction with the world or other players.";
+HELPFRAME_GMTALK_ISSUE1_HEADER = "Game Hints";
+HELPFRAME_GMTALK_ISSUE2 = "This includes information about: an upcoming patch (what, when, how), upcoming content additions, game play changes, and future rule changes.";
+HELPFRAME_GMTALK_ISSUE2_HEADER = "Meta-Game Hints";
+HELPFRAME_GMTALK_ISSUE3 = "Most PVP issues can be resolved through the PVP game mechanics. GM's will not be able to assist in many cases. The exceptions to this rule are any behaviors that fall under the World of Warcraft Harassment Policy. For special rules designated for PvP activity, please go to:";
+HELPFRAME_GMTALK_ISSUE3_HEADER = "PvP";
+HELPFRAME_GMTALK_TEXT1 = "Game Masters are normally available to assist 24 hours a day. The next available Game Master will be able to assist you no matter which character you are currently playing on. Please keep in mind wait times may vary, and there are some issues that Game Masters will |cffffd200NOT|r be able to assist you with. Those issues include, but are |cffffd200NOT|r limited to the following:";
+HELPFRAME_GMTALK_TEXT2 = "Additionally, we encourage all players to first utilize the forums and the website to pursue information about their respective issues at |cffffd200www.worldofwarcraft.com|r , and request that specific attention be paid to our game policies at |cffffd200www.worldofwarcraft.com/policy/|r .";
+HELPFRAME_GMTALK_TITLE = "Talk to a Game Master";
+HELPFRAME_GM_BUTTON_DESCRIPTION = "Contact a GM for personal assistance";
+HELPFRAME_GM_BUTTON_TEXT = "Page a GM:";
+HELPFRAME_GUILD_BULLET1 = "Unable to add/remove guild members";
+HELPFRAME_GUILD_BULLET2 = "Not able to form a guild";
+HELPFRAME_GUILD_BULLET3 = "Unable to reassign or rename ranks within the guild";
+HELPFRAME_GUILD_BULLET_TITLE1 = "The following are examples of guild issues:";
+HELPFRAME_GUILD_BUTTON_TEXT = "Report Guild Issue";
+HELPFRAME_GUILD_TEXT = "Any problems associated with the creation or functionality of a guild";
+HELPFRAME_GUILD_TITLE = "Guild";
+HELPFRAME_HARASSMENT_BUTTON_DESCRIPTION = "Physical or Verbal actions which cause other players distress can be considered in this option";
+HELPFRAME_HARASSMENT_BUTTON_TEXT = "Harassment:";
+HELPFRAME_HOME_TEXT = "The following are the types of issues that a GM can assist with:";
+HELPFRAME_ITEM_BULLET1 = "Item lost after crashing";
+HELPFRAME_ITEM_BULLET2 = "Weapon proc not activating";
+HELPFRAME_ITEM_BULLET3 = "Enchantment or add-ons not working appropriately";
+HELPFRAME_ITEM_BULLET4 = "Scammed items";
+HELPFRAME_ITEM_BULLET5 = "Item accidentally sold to a vendor and was not able to repurchase";
+HELPFRAME_ITEM_BULLET6 = "Inquiries about how to obtain an item";
+HELPFRAME_ITEM_BULLET7 = "Requests for items";
+HELPFRAME_ITEM_BULLET_TITLE1 = "The following are examples of item issues:";
+HELPFRAME_ITEM_BULLET_TITLE2 = "The following are NOT considered item issues:";
+HELPFRAME_ITEM_BUTTON_TEXT = "Report Item Issue";
+HELPFRAME_ITEM_TEXT = "Issues regarding any problem dealing with item functionality or possession";
+HELPFRAME_ITEM_TITLE = "Item";
+HELPFRAME_LAG_TEXT1 = "Lag is often caused by having a large number of players in one location, such as a city or Battleground. It can also be caused by high latency between your computer and the WoW servers. Submitting this report will help us detect and hopefully address lag problems you might be experiencing. \n\nWhat type of lag are you experiencing? Click on a button below to submit a report.";
+HELPFRAME_LAG_TITLE = "Report Lag";
+HELPFRAME_NONQUEST_BULLET1 = "Creeps permanently evading";
+HELPFRAME_NONQUEST_BULLET2 = "NPC is not pathing correctly";
+HELPFRAME_NONQUEST_BULLET3 = "Creeps over-spawning or under-spawning";
+HELPFRAME_NONQUEST_BULLET4 = "Vendor NPC not itemized or not responding";
+HELPFRAME_NONQUEST_BULLET5 = "Request for Non-Quest NPC/Creep spawn or despawn";
+HELPFRAME_NONQUEST_BULLET6 = "Request for Non-Quest NPC/Creep information";
+HELPFRAME_NONQUEST_BULLET7 = "Problem with Quest related NPCs or Creeps";
+HELPFRAME_NONQUEST_BULLET_TITLE1 = "The following are examples of Non-Quest NPC/Creep issues:";
+HELPFRAME_NONQUEST_BULLET_TITLE2 = "The following are NOT considered Non-quest NPC/Creep issues:";
+HELPFRAME_NONQUEST_BUTTON_TEXT = "Report Non-Quest NPC/Creep Issue";
+HELPFRAME_NONQUEST_TEXT = "Issues that deal with NPCs and Creeps functioning or interacting incorrectly";
+HELPFRAME_NONQUEST_TITLE = "Non-Quest NPC/Creep";
+HELPFRAME_OPENTICKET_EDITTEXT = "Your Current Issue:";
+HELPFRAME_OPENTICKET_FOLLOWUPTEXT = "Describe Your Follow-Up Issue:";
+HELPFRAME_OPENTICKET_TEXT = "Describe Your Issue:";
+HELPFRAME_OTHER_BUTTON_DESCRIPTION = "Any issues that require GM assistance";
+HELPFRAME_OTHER_BUTTON_TEXT = "Other Issues:";
+HELPFRAME_QUEST_BULLET1 = "A quest related NPC or object is not functioning appropriately";
+HELPFRAME_QUEST_BULLET2 = "Unable to acquire quest related items";
+HELPFRAME_QUEST_BULLET3 = "Quest creep not dropping a required quest item";
+HELPFRAME_QUEST_BULLET4 = "Request for Quest NPC/Creep information";
+HELPFRAME_QUEST_BULLET5 = "Request for information that would simplify a quest";
+HELPFRAME_QUEST_BULLET_TITLE1 = "The following are examples of Quest/Quest NPC issues:";
+HELPFRAME_QUEST_BULLET_TITLE2 = "The following are NOT considered Quest/Quest NPC issues:";
+HELPFRAME_QUEST_BUTTON_TEXT = "Report Quest/NPC Issue";
+HELPFRAME_QUEST_TEXT = "An issue that results in the inability to initiate or complete a quest";
+HELPFRAME_QUEST_TITLE = "Quest/Quest NPC";
+HELPFRAME_REPORTISSUE_BULLET1 = "Harassment by other players";
+HELPFRAME_REPORTISSUE_BULLET2 = "Minor bugs such as display glitches";
+HELPFRAME_REPORTISSUE_BULLET_TITLE1 = "Examples include:";
+HELPFRAME_REPORTISSUE_TEXT1 = "Use this page to let us know about any problems you notice in the game that don't require an immediate Game Master response.";
+HELPFRAME_REPORTISSUE_TEXT2 = "We will only contact you if we require more information. However, we will still work hard to solve the problem.";
+HELPFRAME_REPORTISSUE_TITLE = "Report a Problem";
+HELPFRAME_REPORTLAG_TEXT1 = "Your lag report has been successfully submitted.";
+HELPFRAME_STUCK_BUTTON_DESCRIPTION = "Physically stuck in an area of the map";
+HELPFRAME_STUCK_BUTTON_TEXT = "Stuck:";
+HELPFRAME_STUCK_TEXT1 = "If you find yourself stuck and unable to move, please try the auto-unstuck feature prior to petitioning a GM. In most cases, this should solve the problem. Activating the auto-unstuck command will first attempt to use your hearthstone to port you back to your inn. If this is not possible, it will attempt to nudge your character out of position.\n\nPlease note this option can only be used every 5 minutes. Using the auto-unstuck option will log your character and location so that we can verify and fix the location in the future.";
+HELPFRAME_STUCK_TITLE = "Character Stuck";
+HELPFRAME_SUGGESTION_BUTTON_DESCRIPTION = "All general suggestions and feedback about the game";
+HELPFRAME_SUGGESTION_BUTTON_TEXT = "Send a Suggestion:";
+HELPFRAME_TECHNICAL_BULLET1 = "Decline in game performance (game becomes slow or choppy)";
+HELPFRAME_TECHNICAL_BULLET2 = "Display errors (black boxes, flickering objects, distortions, etc)";
+HELPFRAME_TECHNICAL_BULLET3 = "Cinematics or in-game movies not playing correctly";
+HELPFRAME_TECHNICAL_BULLET4 = "Sound issues (no sound or music, static, looping effects, etc)";
+HELPFRAME_TECHNICAL_BULLET5 = "Connection/disconnection problems";
+HELPFRAME_TECHNICAL_BULLET6 = "Crashes or error messages of any kind occurring during gameplay";
+HELPFRAME_TECHNICAL_BULLET7 = "Any other technical game issue";
+HELPFRAME_TECHNICAL_BULLET_TITLE1 = "The following are examples of Technical issues:";
+HELPFRAME_TECHNICAL_BULLET_TITLE2 = "You may find that a solution for your issue has already been posted on the Technical Support Forum, located on the World of Warcraft site at:\n\nwww.worldofwarcraft.com\n\nIf your technical issue is not addressed by the solutions posted there, please contact our Technical Support Department:\n\nBy Phone at: (949) 955-1382\nBy Web at: http://us.blizzard.com/support/index.xml?gameId=11\nBy Email at: wowtech@blizzard.com";
+HELPFRAME_TECHNICAL_BUTTON_TEXT = "Report Technical Issue";
+HELPFRAME_TECHNICAL_TEXT = "Our Technical Support team is available to help you with any technical issues that occur while you are using World of Warcraft.";
+HELPFRAME_TECHNICAL_TITLE = "Technical Support";
+HELPFRAME_WELCOME_TEXT1 = "For assistance with in-game support, please use the following options to submit a petition for GM assistance or report an issue.";
+HELPFRAME_WELCOME_TITLE = "Customer Support";
+HELP_BUTTON = "Help Request";
+HELP_FRAME_TITLE = "Customer Support";
+HELP_LABEL = "Help";
+HELP_SUBTEXT = "These options allow you to change the behavior of the help systems within the game.";
+HELP_TEXT_LINE1 = "WoW help:";
+HELP_TEXT_LINE2 = "- 'x' to sit/stand";
+HELP_TEXT_LINE3 = "- To group/inspect/trade: target another player, right click their portrait";
+HELP_TEXT_LINE4 = "- 'F1-F5' to target self/groupmates";
+HELP_TEXT_LINE5 = "- 'Shift-1 through Shift-6' to access extra action bars. Shift up/down and Shift-mousewheel also work.";
+HELP_TEXT_LINE6 = "- 'Numlock' to autorun";
+HELP_TEXT_LINE7 = "- 'z' to draw/sheathe your weapons";
+HELP_TEXT_LINE8 = "- 'v' to see nearby targets. Also useful for target selection";
+HELP_TEXT_LINE9 = "- Tab to target nearest enemy";
+HELP_TEXT_LINE10 = "- '1' or 't' to attack current target (selects nearest enemy if no current target)";
+HELP_TEXT_LINE11 = "- 'PageUp/PageDown' to scroll chat pane";
+HELP_TEXT_LINE12 = "- 'r' or '/r' to reply to the last tell";
+HELP_TEXT_LINE13 = "- /who to get a list of players";
+HELP_TEXT_LINE14 = "- /chat for a list of chat commands";
+HELP_TEXT_LINE15 = "- For help with the new macro UI type /macrohelp";
+HELP_TEXT_SIMPLE = "Type '/help' for a listing of a few commands.";
+HELP_TICKET_ABANDON = "Abandon My Ticket";
+HELP_TICKET_ABANDON_CONFIRM = "Really abandon current GM ticket?";
+HELP_TICKET_EDIT = "Edit My Ticket";
+HELP_TICKET_EDIT_ABANDON = "You currently have an open ticket. Please choose an option.";
+HELP_TICKET_OPEN = "Open a Ticket";
+HELP_TICKET_QUEUE_DISABLED = "GM Help Tickets are currently unavailable.";
+HEROIC_PREFIX = "Heroic: %s";
+HERTZ = "Hz";
+HIDE = "Hide";
+HIDE_OUTDOOR_WORLD_STATE_TEXT = "Hide Zone Objective Tracker";
+HIDE_PARTY_INTERFACE_TEXT = "Hide Party Interface in Raid";
+HIDE_PULLOUT_BG = "Hide Background";
+HIGH = "High";
+HIGHLIGHTING = "Highlighting:";
+HIGHLIGHT_ABILITY_COMBATLOG_TOOLTIP = "Highlight ability names in combat messages.";
+HIGHLIGHT_DAMAGE_COMBATLOG_TOOLTIP = "Highlight damage numbers in combat messages.";
+HIGHLIGHT_KILL_COMBATLOG_TOOLTIP = "Highlights the entire line when you or a party member makes a kill.";
+HIGHLIGHT_SCHOOL_COMBATLOG_TOOLTIP = "Highlight the school of a spell in combat messages.";
+HIGH_BIDDER = "High Bidder";
+HIT = "Hit";
+HK = "HK";
+HOME = "Home";
+HOME_INN = "your inn";
+HONOR = "Honor";
+HONORABLE_KILLS = "Honorable Kills";
+HONORABLE_KILLS_TOOLTIP = "Enemy players that you or the group you are in did damage to before they died";
+HONOR_CONTRIBUTION_POINTS = "Honor";
+HONOR_ESTIMATED_TOOLTIP = "Honor Gained Today";
+HONOR_GAINED = "Honor Gained";
+HONOR_GAINED_TOOLTIP = "Total honor gained.";
+HONOR_HIGHEST_RANK = "Highest Rank";
+HONOR_LASTWEEK = "Last Week";
+HONOR_LIFETIME = "Lifetime";
+HONOR_POINTS = "Honor Points";
+HONOR_STANDING = "Standing";
+HONOR_THIS_SESSION = "Today";
+HONOR_TODAY = "Today";
+HONOR_YESTERDAY = "Yesterday";
+HOSTILE = "Hostile";
+HOURS = "|4Hour:Hours;";
+HOURS_ABBR = "%d |4Hr:Hr;";
+HOUR_ONELETTER_ABBR = "%d h";
+HP = "HP";
+HP_TEMPLATE = "%d Health";
+HUNTER_AGILITY_TOOLTIP = "Increases attack power with both melee and ranged weapons, and improves chance to score a critical hit with all weapons.|nIncreases armor and chance to dodge attacks.";
+HUNTER_INTELLECT_TOOLTIP = "Increases mana points and chance to score a critical hit with spells.\nIncreases the rate at which weapon skills improve.";
+ICON_TAG_RAID_TARGET_CIRCLE1 = "rt2";
+ICON_TAG_RAID_TARGET_CIRCLE2 = "rt2";
+ICON_TAG_RAID_TARGET_CROSS1 = "rt7";
+ICON_TAG_RAID_TARGET_CROSS2 = "X";
+ICON_TAG_RAID_TARGET_DIAMOND1 = "rt3";
+ICON_TAG_RAID_TARGET_DIAMOND2 = "rt3";
+ICON_TAG_RAID_TARGET_MOON1 = "rt5";
+ICON_TAG_RAID_TARGET_MOON2 = "rt5";
+ICON_TAG_RAID_TARGET_SKULL1 = "rt8";
+ICON_TAG_RAID_TARGET_SKULL2 = "rt8";
+ICON_TAG_RAID_TARGET_SQUARE1 = "rt6";
+ICON_TAG_RAID_TARGET_SQUARE2 = "rt6";
+ICON_TAG_RAID_TARGET_STAR1 = "rt1";
+ICON_TAG_RAID_TARGET_STAR2 = "rt1";
+ICON_TAG_RAID_TARGET_TRIANGLE1 = "rt4";
+ICON_TAG_RAID_TARGET_TRIANGLE2 = "rt4";
+ID = "ID";
+IDLE_MESSAGE = "You have been inactive for some time and will be logged out of the game. If you wish to remain logged in, hit the cancel button.";
+IGNORE = "Ignore";
+IGNORED = "Ignored";
+IGNORE_DIALOG = "Ignore";
+IGNORE_ERRORS = "Ignore";
+IGNORE_LIST = "Ignore List";
+IGNORE_PLAYER = "Ignore Player";
+IGR_BILLING_NAG_DIALOG = "Your IGR's playtime is about to expire, you will be disconnected shortly.";
+IMMUNE = "Immune";
+IMPORTANT_PEOPLE_IN_GROUP = "Players in Group:";
+IM_STYLE = "IM Style";
+INBOX = "Inbox";
+INBOX_TOO_MUCH_MAIL = "Your inbox is full.";
+INBOX_TOO_MUCH_MAIL_TOOLTIP = "Not all of your mail can be displayed.|nPlease delete some mail to make room.";
+INCOMPLETE = "Incomplete";
+INCREASE_POTENTIAL = "Increases potential in |cffffffff%s|r by |cffffffff%d|r";
+INDIVIDUALS = "Individuals";
+INPUT_CHINESE = "CH";
+INPUT_JAPANESE = "JP";
+INPUT_KOREAN = "KO";
+INPUT_ROMAN = "A";
+INSCRIPTION = "Inscription";
+INSPECT = "Inspect";
+INSPECT_NOTIFY = "%s is inspecting you.";
+INSTANCE = "Instance";
+INSTANCE_BOOT_TIMER = "You are not in this instance's group. You will be teleported to the nearest graveyard in %d %s.";
+INSTANCE_DIFFICULTY_FORMAT = "(%s)";
+INSTANCE_ID = "Instance ID: %d";
+INSTANCE_LEAVE = "Leave Instance";
+INSTANCE_LOCK_SEPARATOR = "%s|n|n%s";
+INSTANCE_LOCK_TIMER = "You have entered an instance already in progress! You will be saved to %1$s in %2$s!";
+INSTANCE_LOCK_TIMER_PREVIOUSLY_SAVED = "You have entered an |cffffd200extended|r instance. You will be saved to %1$s in %2$s!";
+INSTANCE_RESET_FAILED = "Cannot reset %s. There are players still inside the instance.";
+INSTANCE_RESET_FAILED_OFFLINE = "Cannot reset %s. There are players offline in your party.";
+INSTANCE_RESET_FAILED_ZONING = "Cannot reset %s. There are players in your party attempting to zone into an instance.";
+INSTANCE_RESET_SUCCESS = "%s has been reset.";
+INSTANCE_SAVED = "You are now saved to this instance";
+INSTANCE_SHUTDOWN_MESSAGE = "Not enough players. The game will end in %s";
+INSTANCE_UNAVAILABLE_OTHER_EXPANSION_TOO_LOW = "%s does not have the correct World of Warcraft expansion.";
+INSTANCE_UNAVAILABLE_OTHER_GEAR_TOO_HIGH = "%s's gear is too good.";
+INSTANCE_UNAVAILABLE_OTHER_GEAR_TOO_LOW = "%s must obtain better gear.";
+INSTANCE_UNAVAILABLE_OTHER_LEVEL_TOO_HIGH = "%s's level is too high.";
+INSTANCE_UNAVAILABLE_OTHER_LEVEL_TOO_LOW = "%s must advance to a higher level.";
+INSTANCE_UNAVAILABLE_OTHER_MISSING_ITEM = "%s does not have the required item.";
+INSTANCE_UNAVAILABLE_OTHER_OTHER = "%s does not meet the requirements for this dungeon.";
+INSTANCE_UNAVAILABLE_OTHER_QUEST_NOT_COMPLETED = "%s has not completed the required quest.";
+INSTANCE_UNAVAILABLE_OTHER_RAID_LOCKED = "%s is already locked to this instance.";
+INSTANCE_UNAVAILABLE_SELF_EXPANSION_TOO_LOW = "You do not have the World of Warcraft expansion.";
+INSTANCE_UNAVAILABLE_SELF_GEAR_TOO_HIGH = "Your gear is too good.";
+INSTANCE_UNAVAILABLE_SELF_GEAR_TOO_LOW = "You must obtain better gear.";
+INSTANCE_UNAVAILABLE_SELF_LEVEL_TOO_HIGH = "Your level is too high.";
+INSTANCE_UNAVAILABLE_SELF_LEVEL_TOO_LOW = "You must advance to a higher level.";
+INSTANCE_UNAVAILABLE_SELF_MISSING_ITEM = "You do not have the required item.";
+INSTANCE_UNAVAILABLE_SELF_OTHER = "You do not meet the requirements for this dungeon.";
+INSTANCE_UNAVAILABLE_SELF_QUEST_NOT_COMPLETED = "You have not completed the required quest.";
+INSTANCE_UNAVAILABLE_SELF_RAID_LOCKED = "You are already locked to this instance.";
+INT = "Int";
+INTELLECT_COLON = "Intellect:";
+INTELLECT_TOOLTIP = "Increases Mana points as well as chance to Critical Hit\nwith magic spells. Intellect also grants a higher chance\nto increase melee skills. (It does not affect professions\nthough.) ";
+INTERFACE_ACTION_BLOCKED = "Interface action failed because of an AddOn";
+INTERFACE_OPTIONS = "Interface Options";
+INTERNAL_STRING_ERROR = "Internal String Error %d";
+INTERRUPT = "Interrupt";
+INTERRUPTED = "Interrupted";
+INTERRUPTS = "Interrupts";
+INT_GENERAL_DURATION_DAYS = "%d |4day:days;";
+INT_GENERAL_DURATION_HOURS = "%d |4hour:hours;";
+INT_GENERAL_DURATION_MIN = "%d |4minute:minutes;";
+INT_GENERAL_DURATION_SEC = "%d |4second:seconds;";
+INT_SPELL_DURATION_DAYS = "%d |4day:days;";
+INT_SPELL_DURATION_HOURS = "%d |4hour:hrs;";
+INT_SPELL_DURATION_MIN = "%d min";
+INT_SPELL_DURATION_SEC = "%d sec";
+INT_SPELL_POINTS_SPREAD_TEMPLATE = "%d to %d";
+INVENTORY_FULL = "Inventory is full.";
+INVENTORY_TOOLTIP = "Inventory";
+INVERT_MOUSE = "Invert Mouse";
+INVITATION = "%s invites you to a group.";
+INVITE = "Invite";
+INVITE_CONVERSATION_INSTRUCTIONS = "Choose up to |cffffffff%d|r |4friend:friends; to invite to the conversation.";
+INVITE_FRIEND_TO_CONVERSATION = "Invite Friend";
+INVITE_TO_CONVERSATION = "Invite To Conversation";
+INVTYPE_2HWEAPON = "Two-Hand";
+INVTYPE_AMMO = "Ammo";
+INVTYPE_BAG = "Bag";
+INVTYPE_BODY = "Shirt";
+INVTYPE_CHEST = "Chest";
+INVTYPE_CLOAK = "Back";
+INVTYPE_FEET = "Feet";
+INVTYPE_FINGER = "Finger";
+INVTYPE_HAND = "Hands";
+INVTYPE_HEAD = "Head";
+INVTYPE_HOLDABLE = "Held In Off-hand";
+INVTYPE_LEGS = "Legs";
+INVTYPE_NECK = "Neck";
+INVTYPE_QUIVER = "Quiver";
+INVTYPE_RANGED = "Ranged";
+INVTYPE_RANGEDRIGHT = "Ranged";
+INVTYPE_RELIC = "Relic";
+INVTYPE_ROBE = "Chest";
+INVTYPE_SHIELD = "Off Hand";
+INVTYPE_SHOULDER = "Shoulder";
+INVTYPE_TABARD = "Tabard";
+INVTYPE_THROWN = "Thrown";
+INVTYPE_TRINKET = "Trinket";
+INVTYPE_WAIST = "Waist";
+INVTYPE_WEAPON = "One-Hand";
+INVTYPE_WEAPONMAINHAND = "Main Hand";
+INVTYPE_WEAPONMAINHAND_PET = "Main Attack";
+INVTYPE_WEAPONOFFHAND = "Off Hand";
+INVTYPE_WRIST = "Wrist";
+ITEMPRESENTINOFFHAND = "Cannot wield, there's something already in your second hand!";
+ITEMS = "Items";
+ITEMSLOTTEXT = "Item Slots";
+ITEMS_EQUIPPED = "%d |4item:items; equipped";
+ITEMS_IN_INVENTORY = "%d |4item:items; in inventory";
+ITEMS_NOT_IN_INVENTORY = "%d |4item:items; missing";
+ITEMS_VARIABLE_QUANTITY = "%d |4Item:Items;";
+ITEM_ACCOUNTBOUND = "Account Bound";
+ITEM_BIND_ON_EQUIP = "Binds when equipped";
+ITEM_BIND_ON_PICKUP = "Binds when picked up";
+ITEM_BIND_ON_USE = "Binds when used";
+ITEM_BIND_QUEST = "Quest Item";
+ITEM_BIND_TO_ACCOUNT = "Binds to account";
+ITEM_CANT_BE_DESTROYED = "That item cannot be destroyed.";
+ITEM_CLASSES_ALLOWED = "Classes: %s";
+ITEM_CONJURED = "Conjured Item";
+ITEM_COOLDOWN_TIME = "Cooldown remaining: %s";
+ITEM_COOLDOWN_TIME_DAYS = "Cooldown remaining: %d |4day:days;";
+ITEM_COOLDOWN_TIME_HOURS = "Cooldown remaining: %d |4hour:hours;";
+ITEM_COOLDOWN_TIME_MIN = "Cooldown remaining: %d min";
+ITEM_COOLDOWN_TIME_SEC = "Cooldown remaining: %d sec";
+ITEM_COOLDOWN_TOTAL = "(%s Cooldown)";
+ITEM_COOLDOWN_TOTAL_DAYS = "(%d |4Day:Days; Cooldown)";
+ITEM_COOLDOWN_TOTAL_HOURS = "(%d |4Hour:Hours; Cooldown)";
+ITEM_COOLDOWN_TOTAL_MIN = "(%d Min Cooldown)";
+ITEM_COOLDOWN_TOTAL_SEC = "(%d Sec Cooldown)";
+ITEM_CREATED_BY = "|cff00ff00|r";
+ITEM_DELTA_DESCRIPTION = "If you replace this item, the following stat changes will occur:";
+ITEM_DISENCHANT_ANY_SKILL = "Disenchantable";
+ITEM_DISENCHANT_MIN_SKILL = "Disenchanting requires %s (%d)";
+ITEM_DISENCHANT_NOT_DISENCHANTABLE = "Cannot be disenchanted";
+ITEM_DURATION_DAYS = "Duration: %d |4day:days;";
+ITEM_DURATION_HOURS = "Duration: %d |4hour:hrs;";
+ITEM_DURATION_MIN = "Duration: %d min";
+ITEM_DURATION_SEC = "Duration: %d sec";
+ITEM_ENCHANT_DISCLAIMER = "Item will not be traded!";
+ITEM_ENCHANT_TIME_LEFT_DAYS = "%s (%d |4day:days;)";
+ITEM_ENCHANT_TIME_LEFT_HOURS = "%s (%d |4hour:hours;)";
+ITEM_ENCHANT_TIME_LEFT_MIN = "%s (%d min)";
+ITEM_ENCHANT_TIME_LEFT_SEC = "%s (%d sec)";
+ITEM_HEROIC = "Heroic";
+ITEM_HEROIC_EPIC = "Heroic Epic";
+ITEM_LEVEL = "Item Level %d";
+ITEM_LEVEL_AND_MIN = "Level %d (min %d)";
+ITEM_LEVEL_RANGE = "Requires level %d to %d";
+ITEM_LEVEL_RANGE_CURRENT = "Requires level %d to %d (%d)";
+ITEM_LIMIT_CATEGORY = "Unique: %s (%d)";
+ITEM_LIMIT_CATEGORY_MULTIPLE = "Unique-Equipped: %s (%d)";
+ITEM_LOOT = "Item Loot";
+ITEM_MILLABLE = "Millable";
+ITEM_MIN_LEVEL = "Requires Level %d";
+ITEM_MIN_SKILL = "Requires %s (%d)";
+ITEM_MISSING = "%s missing";
+ITEM_MOD_AGILITY = "%c%d Agility";
+ITEM_MOD_AGILITY_SHORT = "Agility";
+ITEM_MOD_ARMOR_PENETRATION_RATING = "Increases your armor penetration rating by %d.";
+ITEM_MOD_ARMOR_PENETRATION_RATING_SHORT = "Armor Penetration Rating";
+ITEM_MOD_ATTACK_POWER = "Increases attack power by %d.";
+ITEM_MOD_ATTACK_POWER_SHORT = "Attack Power";
+ITEM_MOD_BLOCK_RATING = "Increases your shield block rating by %d.";
+ITEM_MOD_BLOCK_RATING_SHORT = "Block Rating";
+ITEM_MOD_BLOCK_VALUE = "Increases the block value of your shield by %d.";
+ITEM_MOD_BLOCK_VALUE_SHORT = "Block Value";
+ITEM_MOD_CRIT_MELEE_RATING = "Improves melee critical strike rating by %d.";
+ITEM_MOD_CRIT_MELEE_RATING_SHORT = "Critical Strike Rating (Melee)";
+ITEM_MOD_CRIT_RANGED_RATING = "Improves ranged critical strike rating by %d.";
+ITEM_MOD_CRIT_RANGED_RATING_SHORT = "Critical Strike Rating (Ranged)";
+ITEM_MOD_CRIT_RATING = "Improves critical strike rating by %d.";
+ITEM_MOD_CRIT_RATING_SHORT = "Critical Strike Rating";
+ITEM_MOD_CRIT_SPELL_RATING = "Improves spell critical strike rating by %d.";
+ITEM_MOD_CRIT_SPELL_RATING_SHORT = "Critical Strike Rating (Spell)";
+ITEM_MOD_CRIT_TAKEN_MELEE_RATING = "Improves melee critical avoidance rating by %d.";
+ITEM_MOD_CRIT_TAKEN_MELEE_RATING_SHORT = "Critical Strike Avoidance Rating (Melee)";
+ITEM_MOD_CRIT_TAKEN_RANGED_RATING = "Improves ranged critical avoidance rating by %d.";
+ITEM_MOD_CRIT_TAKEN_RANGED_RATING_SHORT = "Critical Strike Avoidance Rating (Ranged)";
+ITEM_MOD_CRIT_TAKEN_RATING = "Improves critical avoidance rating by %d.";
+ITEM_MOD_CRIT_TAKEN_RATING_SHORT = "Critical Strike Avoidance Rating";
+ITEM_MOD_CRIT_TAKEN_SPELL_RATING = "Improves spell critical avoidance rating by %d.";
+ITEM_MOD_CRIT_TAKEN_SPELL_RATING_SHORT = "Critical Strike Avoidance Rating (Spell)";
+ITEM_MOD_DAMAGE_PER_SECOND_SHORT = "Damage Per Second";
+ITEM_MOD_DEFENSE_SKILL_RATING = "Increases defense rating by %d.";
+ITEM_MOD_DEFENSE_SKILL_RATING_SHORT = "Defense Rating";
+ITEM_MOD_DODGE_RATING = "Increases your dodge rating by %d.";
+ITEM_MOD_DODGE_RATING_SHORT = "Dodge Rating";
+ITEM_MOD_EXPERTISE_RATING = "Increases your expertise rating by %d.";
+ITEM_MOD_EXPERTISE_RATING_SHORT = "Expertise Rating";
+ITEM_MOD_FERAL_ATTACK_POWER = "Increases attack power by %d in Cat, Bear, Dire Bear, and Moonkin forms only.";
+ITEM_MOD_FERAL_ATTACK_POWER_SHORT = "Attack Power In Forms";
+ITEM_MOD_HASTE_MELEE_RATING = "Improves melee haste rating by %d.";
+ITEM_MOD_HASTE_MELEE_RATING_SHORT = "Haste Rating (Melee)";
+ITEM_MOD_HASTE_RANGED_RATING = "Improves ranged haste rating by %d.";
+ITEM_MOD_HASTE_RANGED_RATING_SHORT = "Haste Rating (Ranged)";
+ITEM_MOD_HASTE_RATING = "Improves haste rating by %d.";
+ITEM_MOD_HASTE_RATING_SHORT = "Haste Rating";
+ITEM_MOD_HASTE_SPELL_RATING = "Improves spell haste rating by %d.";
+ITEM_MOD_HASTE_SPELL_RATING_SHORT = "Haste Rating (Spell)";
+ITEM_MOD_HEALTH = "%c%d Health";
+ITEM_MOD_HEALTH_REGEN = "Restores %d health per 5 sec.";
+ITEM_MOD_HEALTH_REGENERATION = "Restores %d health per 5 sec.";
+ITEM_MOD_HEALTH_REGENERATION_SHORT = "Health Regeneration";
+ITEM_MOD_HEALTH_REGEN_SHORT = "Health Per 5 Sec.";
+ITEM_MOD_HEALTH_SHORT = "Health";
+ITEM_MOD_HIT_MELEE_RATING = "Improves melee hit rating by %d.";
+ITEM_MOD_HIT_MELEE_RATING_SHORT = "Hit Rating (Melee)";
+ITEM_MOD_HIT_RANGED_RATING = "Improves ranged hit rating by %d.";
+ITEM_MOD_HIT_RANGED_RATING_SHORT = "Hit Rating (Ranged)";
+ITEM_MOD_HIT_RATING = "Improves hit rating by %d.";
+ITEM_MOD_HIT_RATING_SHORT = "Hit Rating";
+ITEM_MOD_HIT_SPELL_RATING = "Improves spell hit rating by %d.";
+ITEM_MOD_HIT_SPELL_RATING_SHORT = "Hit Rating (Spell)";
+ITEM_MOD_HIT_TAKEN_MELEE_RATING = "Improves melee hit avoidance rating by %d.";
+ITEM_MOD_HIT_TAKEN_MELEE_RATING_SHORT = "Hit Avoidance Rating (Melee)";
+ITEM_MOD_HIT_TAKEN_RANGED_RATING = "Improves ranged hit avoidance rating by %d.";
+ITEM_MOD_HIT_TAKEN_RANGED_RATING_SHORT = "Hit Avoidance Rating (Ranged)";
+ITEM_MOD_HIT_TAKEN_RATING = "Improves hit avoidance rating by %d.";
+ITEM_MOD_HIT_TAKEN_RATING_SHORT = "Hit Avoidance Rating";
+ITEM_MOD_HIT_TAKEN_SPELL_RATING = "Improves spell hit avoidance rating by %d.";
+ITEM_MOD_HIT_TAKEN_SPELL_RATING_SHORT = "Hit Avoidance Rating (Spell)";
+ITEM_MOD_INTELLECT = "%c%d Intellect";
+ITEM_MOD_INTELLECT_SHORT = "Intellect";
+ITEM_MOD_MANA = "%c%d Mana";
+ITEM_MOD_MANA_REGENERATION = "Restores %d mana per 5 sec.";
+ITEM_MOD_MANA_REGENERATION_SHORT = "Mana Regeneration";
+ITEM_MOD_MANA_SHORT = "Mana";
+ITEM_MOD_MELEE_ATTACK_POWER_SHORT = "Melee Attack Power";
+ITEM_MOD_PARRY_RATING = "Increases your parry rating by %d.";
+ITEM_MOD_PARRY_RATING_SHORT = "Parry Rating";
+ITEM_MOD_POWER_REGEN0_SHORT = "Mana Per 5 Sec.";
+ITEM_MOD_POWER_REGEN1_SHORT = "Rage Per 5 Sec.";
+ITEM_MOD_POWER_REGEN2_SHORT = "Focus Per 5 Sec.";
+ITEM_MOD_POWER_REGEN3_SHORT = "Energy Per 5 Sec.";
+ITEM_MOD_POWER_REGEN4_SHORT = "Happiness Per 5 Sec.";
+ITEM_MOD_POWER_REGEN5_SHORT = "Runes Per 5 Sec.";
+ITEM_MOD_POWER_REGEN6_SHORT = "Runic Power Per 5 Sec.";
+ITEM_MOD_RANGED_ATTACK_POWER = "Increases ranged attack power by %d.";
+ITEM_MOD_RANGED_ATTACK_POWER_SHORT = "Ranged Attack Power";
+ITEM_MOD_RESILIENCE_RATING = "Improves your resilience rating by %d.";
+ITEM_MOD_RESILIENCE_RATING_SHORT = "Resilience Rating";
+ITEM_MOD_SPELL_DAMAGE_DONE = "Increases damage done by magical spells and effects by up to %d.";
+ITEM_MOD_SPELL_DAMAGE_DONE_SHORT = "Bonus Damage";
+ITEM_MOD_SPELL_HEALING_DONE = "Increases healing done by magical spells and effects by up to %d.";
+ITEM_MOD_SPELL_HEALING_DONE_SHORT = "Bonus Healing";
+ITEM_MOD_SPELL_PENETRATION = "Increases spell penetration by %d.";
+ITEM_MOD_SPELL_PENETRATION_SHORT = "Spell Penetration";
+ITEM_MOD_SPELL_POWER = "Increases spell power by %d.";
+ITEM_MOD_SPELL_POWER_SHORT = "Spell Power";
+ITEM_MOD_SPIRIT = "%c%d Spirit";
+ITEM_MOD_SPIRIT_SHORT = "Spirit";
+ITEM_MOD_STAMINA = "%c%d Stamina";
+ITEM_MOD_STAMINA_SHORT = "Stamina";
+ITEM_MOD_STRENGTH = "%c%d Strength";
+ITEM_MOD_STRENGTH_SHORT = "Strength";
+ITEM_MOUSE_OVER = "Mouse over icon for more info";
+ITEM_NAMES = "Item Names";
+ITEM_NAMES_SHOW_BRACES_COMBATLOG_TOOLTIP = "Show braces around item names.";
+ITEM_NO_DROP = "No Drop";
+ITEM_OPENABLE = "";
+ITEM_PROPOSED_ENCHANT = "Will receive %s.";
+ITEM_PROSPECTABLE = "Prospectable";
+ITEM_PURCHASED_COLON = "Item Purchased:";
+ITEM_QUALITY0_DESC = "Poor";
+ITEM_QUALITY1_DESC = "Common";
+ITEM_QUALITY2_DESC = "Uncommon";
+ITEM_QUALITY3_DESC = "Rare";
+ITEM_QUALITY4_DESC = "Epic";
+ITEM_QUALITY5_DESC = "Legendary";
+ITEM_QUALITY6_DESC = "Artifact";
+ITEM_QUALITY7_DESC = "Heirloom";
+ITEM_QUANTITY_TEMPLATE = "%d %s";
+ITEM_RACES_ALLOWED = "Races: %s";
+ITEM_RANDOM_ENCHANT = "";
+ITEM_READABLE = "";
+ITEM_REFUND_MSG = "Item was refunded. Received a refund of:";
+ITEM_REQ_ARENA_RATING = "Requires personal and team arena rating of %d";
+ITEM_REQ_ARENA_RATING_3V3 = "Requires personal and team arena rating of %d|nin 3v3 or 5v5 brackets";
+ITEM_REQ_ARENA_RATING_5V5 = "Requires personal and team arena rating of %d|nin 5v5 brackets";
+ITEM_REQ_PURCHASE_GROUP = "Requires %s";
+ITEM_REQ_REPUTATION = "Requires %s - %s";
+ITEM_REQ_SKILL = "Requires %s";
+ITEM_RESIST_ALL = "%c%d to All Resistances";
+ITEM_RESIST_SINGLE = "%c%d %s Resistance";
+ITEM_SET_BONUS = "Set: %s";
+ITEM_SET_BONUS_GRAY = "(%d) Set: %s";
+ITEM_SET_NAME = "%s (%d/%d)";
+ITEM_SIGNABLE = "";
+ITEM_SLOTS_IGNORED = "%d |4slot:slots; ignored";
+ITEM_SOCKETABLE = "";
+ITEM_SOCKETING = "Item Socketing";
+ITEM_SOCKET_BONUS = "Socket Bonus: %s";
+ITEM_SOLD_COLON = "Item Sold:";
+ITEM_SOULBOUND = "Soulbound";
+ITEM_SPELL_CHARGES = "%d |4Charge:Charges;";
+ITEM_SPELL_CHARGES_NONE = "No charges";
+ITEM_SPELL_EFFECT = "Effect: %s";
+ITEM_SPELL_KNOWN = "Already known";
+ITEM_SPELL_TRIGGER_ONEQUIP = "Equip:";
+ITEM_SPELL_TRIGGER_ONPROC = "Chance on hit:";
+ITEM_SPELL_TRIGGER_ONUSE = "Use:";
+ITEM_STARTS_QUEST = "This Item Begins a Quest";
+ITEM_SUFFIX_TEMPLATE = "%s %s";
+ITEM_TEXT_FROM = "From,";
+ITEM_UNIQUE = "Unique";
+ITEM_UNIQUE_EQUIPPABLE = "Unique-Equipped";
+ITEM_UNIQUE_MULTIPLE = "Unique (%d)";
+ITEM_UNSELLABLE = "No sell price";
+ITEM_WRAPPED_BY = "|cff00ff00|r";
+ITEM_WRITTEN_BY = "Written by %s";
+ITEM_WRONG_CLASS = "That item can't be used by players of your class!";
+ITEM_WRONG_RACE = "That item can't be used by players of your race!";
+ITUNES_SHOW_ALL_TRACK_CHANGES = "Display all iTunes track changes";
+ITUNES_SHOW_ALL_TRACK_CHANGES_TOOLTIP = "Show track names in a pop up window automatically when tracks change in iTunes.";
+ITUNES_SHOW_FEEDBACK = "Display iTunes remote feedback";
+ITUNES_SHOW_FEEDBACK_TOOLTIP = "Show track names in a pop up window when you change tracks using the iTunes remote.";
+JOIN = "Join";
+JOINED_PARTY = "%s joins the party.";
+JOIN_AS_GROUP = "Join as Group";
+JOIN_AS_GROUP_TOOLTIP = "A group leader may select this option to add the entire group to the battleground queue. Your group will enter the battleground at the same time.";
+JOIN_AS_PARTY = "Join as Party";
+JOIN_NEW_CHANNEL = "Join New Channel";
+KBASE_ARTICLE_COUNT = "%d - %d of %d articles";
+KBASE_ARTICLE_ID = "Article Id: %d";
+KBASE_CHARSTUCK = "Character Stuck";
+KBASE_DEFAULT_SEARCH_TEXT = "Type your keywords here.";
+KBASE_ERROR_LOAD_FAILURE = "The Knowledge Base is currently unavailable. Please refer to http://us.blizzard.com/support/index.xml?gameId=11 for help with support issues, or submit a petition using the button below.";
+KBASE_ERROR_NO_RESULTS = "There were no articles matching your search criteria.";
+KBASE_GMTALK = "Talk to a GM";
+KBASE_HOT_ISSUE = "Hot Issue";
+KBASE_LAG = "Report Lag";
+KBASE_RECENTLY_UPDATED = "Recently Updated";
+KBASE_REPORTISSUE = "Report Problem";
+KBASE_SEARCH_RESULTS = "Search Results";
+KBASE_TOP_ISSUES = "Top Issues";
+KEY1 = "Key 1";
+KEY2 = "Key 2";
+KEYBINDINGFRAME_MOUSEWHEEL_ERROR = "Can't bind mousewheel to actions with up and down states";
+KEYRING = "Keyring";
+KEY_APOSTROPHE = "'";
+KEY_BACKSLASH = "\\";
+KEY_BACKSPACE = "Backspace";
+KEY_BACKSPACE_MAC = "Delete";
+KEY_BINDING = "Key Binding";
+KEY_BINDINGS = "Key Bindings";
+KEY_BINDINGS_MAC = "Bindings";
+KEY_BOUND = "Key Bound Successfully";
+KEY_BUTTON1 = "Left Mouse Button";
+KEY_BUTTON10 = "Mouse Button 10";
+KEY_BUTTON11 = "Mouse Button 11";
+KEY_BUTTON12 = "Mouse Button 12";
+KEY_BUTTON13 = "Mouse Button 13";
+KEY_BUTTON14 = "Mouse Button 14";
+KEY_BUTTON15 = "Mouse Button 15";
+KEY_BUTTON16 = "Mouse Button 16";
+KEY_BUTTON17 = "Mouse Button 17";
+KEY_BUTTON18 = "Mouse Button 18";
+KEY_BUTTON19 = "Mouse Button 19";
+KEY_BUTTON2 = "Right Mouse Button";
+KEY_BUTTON20 = "Mouse Button 20";
+KEY_BUTTON21 = "Mouse Button 21";
+KEY_BUTTON22 = "Mouse Button 22";
+KEY_BUTTON23 = "Mouse Button 23";
+KEY_BUTTON24 = "Mouse Button 24";
+KEY_BUTTON25 = "Mouse Button 25";
+KEY_BUTTON26 = "Mouse Button 26";
+KEY_BUTTON27 = "Mouse Button 27";
+KEY_BUTTON28 = "Mouse Button 28";
+KEY_BUTTON29 = "Mouse Button 29";
+KEY_BUTTON3 = "Middle Mouse";
+KEY_BUTTON30 = "Mouse Button 30";
+KEY_BUTTON31 = "Mouse Button 31";
+KEY_BUTTON4 = "Mouse Button 4";
+KEY_BUTTON5 = "Mouse Button 5";
+KEY_BUTTON6 = "Mouse Button 6";
+KEY_BUTTON7 = "Mouse Button 7";
+KEY_BUTTON8 = "Mouse Button 8";
+KEY_BUTTON9 = "Mouse Button 9";
+KEY_COMMA = ",";
+KEY_DELETE = "Delete";
+KEY_DELETE_MAC = "Del";
+KEY_DOWN = "Down Arrow";
+KEY_END = "End";
+KEY_ENTER = "Enter";
+KEY_ENTER_MAC = "Return";
+KEY_ESCAPE = "Escape";
+KEY_HOME = "Home";
+KEY_INSERT = "Insert";
+KEY_INSERT_MAC = "Help";
+KEY_LEFT = "Left Arrow";
+KEY_LEFTBRACKET = "[";
+KEY_MINUS = "-";
+KEY_MOUSEWHEELDOWN = "Mouse Wheel Down";
+KEY_MOUSEWHEELUP = "Mouse Wheel Up";
+KEY_NUMLOCK = "Num Lock";
+KEY_NUMLOCK_MAC = "Clear";
+KEY_NUMPAD0 = "Num Pad 0";
+KEY_NUMPAD1 = "Num Pad 1";
+KEY_NUMPAD2 = "Num Pad 2";
+KEY_NUMPAD3 = "Num Pad 3";
+KEY_NUMPAD4 = "Num Pad 4";
+KEY_NUMPAD5 = "Num Pad 5";
+KEY_NUMPAD6 = "Num Pad 6";
+KEY_NUMPAD7 = "Num Pad 7";
+KEY_NUMPAD8 = "Num Pad 8";
+KEY_NUMPAD9 = "Num Pad 9";
+KEY_NUMPADDECIMAL = "Num Pad .";
+KEY_NUMPADDIVIDE = "Num Pad /";
+KEY_NUMPADMINUS = "Num Pad -";
+KEY_NUMPADMULTIPLY = "Num Pad *";
+KEY_NUMPADPLUS = "Num Pad +";
+KEY_PAGEDOWN = "Page Down";
+KEY_PAGEUP = "Page Up";
+KEY_PAUSE = "Pause";
+KEY_PAUSE_MAC = "F15";
+KEY_PERIOD = ".";
+KEY_PLUS = "+";
+KEY_PRINTSCREEN = "Print Screen";
+KEY_PRINTSCREEN_MAC = "F13";
+KEY_RIGHT = "Right Arrow";
+KEY_RIGHTBRACKET = "]";
+KEY_SCROLLLOCK = "Scroll Lock";
+KEY_SCROLLLOCK_MAC = "F14";
+KEY_SEMICOLON = ";";
+KEY_SLASH = "/";
+KEY_SPACE = "Spacebar";
+KEY_TAB = "Tab";
+KEY_TILDE = "~";
+KEY_UNBOUND_ERROR = "|cffff0000%s Function is Now Unbound!|r";
+KEY_UP = "Up Arrow";
+KILLING_BLOWS = "Killing Blows";
+KILLING_BLOW_TOOLTIP = "Enemy players to whom you have personally delivered the killing blow.";
+KILLS = "Kills";
+KILLS_COMBATLOG_TOOLTIP = "Show messages when a member of your party kills something.";
+KILLS_PVP = "Kills";
+KNOWLEDGEBASE_FRAME_TITLE = "Knowledge Base";
+KNOWLEDGE_BASE = "Knowledge Base";
+KNOWN_TALENTS_HEADER = "My Talents";
+KOKR = "Korean";
+LABEL_NOTE = "Note";
+LALT_KEY_TEXT = "Left ALT";
+LANGUAGE = "Language";
+LANGUAGES_LABEL = "Languages";
+LANGUAGES_SUBTEXT = "These options allow you to modify language settings for the game.";
+LASTONLINE = "Last Online";
+LASTONLINE_DAYS = "%d |4day:days;";
+LASTONLINE_HOURS = "%d |4hour:hours;";
+LASTONLINE_MINS = "< an hour";
+LASTONLINE_MINUTES = "%d |4minute:minutes;";
+LASTONLINE_MONTHS = "%d |4month:months;";
+LASTONLINE_SECS = "< a minute";
+LASTONLINE_YEARS = "%d |4year:years;";
+LAST_ONLINE_COLON = "Last Online:";
+LATEST_UNLOCKED_ACHIEVEMENTS = "Recent Achievements";
+LATEST_UPDATED_STATS = "Latest Updated Statistics";
+LAUGH_WORD1 = "lol";
+LAUGH_WORD2 = "rofl";
+LAUGH_WORD3 = "hehe";
+LAUGH_WORD4 = "haha";
+LAUGH_WORD5 = "haha";
+LAUGH_WORD6 = "haha";
+LAUGH_WORD7 = "haha";
+LAUGH_WORD8 = "haha";
+LAUGH_WORD9 = "rofl";
+LCTRL_KEY_TEXT = "Left CTRL";
+LEADER = "Leader";
+LEADER_TOOLTIP = "Indicates that you are willing to lead a group.";
+LEARN = "Learn";
+LEARN_SKILL_TEMPLATE = "Learn %s";
+LEAVE_ALL = "Leave All";
+LEAVE_ARENA = "Leave Arena";
+LEAVE_BATTLEGROUND = "Leave Battleground";
+LEAVE_CONVERSATION = "Leave Conversation";
+LEAVE_QUEUE = "Leave Queue";
+LEAVE_VEHICLE = "Leave Vehicle";
+LEAVE_ZONE = "Leave %s";
+LEAVING_COMBAT = "Leaving Combat";
+LEFT_PARTY = "%s leaves the party.";
+LEGSSLOT = "Legs";
+LESS_THAN_ONE_MINUTE = "< 1 minute";
+LEVEL = "Level";
+LEVEL_ABBR = "Lvl";
+LEVEL_GAINED = "Level %d";
+LEVEL_GRANT = "%s wishes to grant you one level";
+LEVEL_RANGE = "Level Range";
+LEVEL_REQUIRED = "Req level %d";
+LEVEL_TOO_LOW = "You must reach level %d to equip this item.";
+LEVEL_UP = "Congratulations, you have reached level %d!";
+LEVEL_UP_CHAR_POINTS = "You have gained %d talent |4point:points;.";
+LEVEL_UP_HEALTH = "You have gained %d hit points.";
+LEVEL_UP_HEALTH_MANA = "You have gained %d hit points and %d mana.";
+LEVEL_UP_SKILL_POINTS = "You now have %d free |4profession:professions;.";
+LEVEL_UP_STAT = "Your %s increases by %d.";
+LFD_HOLIDAY_REWARD_EXPLANATION1 = "Your first victory per day will earn you:";
+LFD_HOLIDAY_REWARD_EXPLANATION2 = "Each victory subsequent to the first each day will earn you:";
+LFD_LEVEL_FORMAT_RANGE = "(%d - %d)";
+LFD_LEVEL_FORMAT_SINGLE = "(%d)";
+LFD_RANDOM_EXPLANATION = "Using the Dungeon Finder to do a Random Dungeon will earn you extra rewards.";
+LFD_RANDOM_REWARD_EXPLANATION1 = "The first random dungeon that you complete each day will earn you:";
+LFD_RANDOM_REWARD_EXPLANATION2 = "Random dungeons which you complete subsequent to the first each day will earn you:";
+LFD_RANDOM_REWARD_PUG_EXPLANATION = "You will also receive the following rewards. They scale with the number of random players included in your group:";
+LFD_REWARDS = "Rewards";
+LFGWIZARD_TITLE = "Choose an Action";
+LFG_DESERTER_OTHER = "One of your group members has recently deserted a Dungeon Finder group and may not yet queue for another.";
+LFG_DESERTER_YOU = "You recently deserted a Dungeon Finder group and may not queue again for:";
+LFG_DISABLED_LFM_TOOLTIP = "You cannot Look For Group while Looking For More.";
+LFG_DISABLED_PARTY_TOOLTIP = "You cannot Look For Group while in a party.";
+LFG_LABEL = "I would like to join a group";
+LFG_OFFER_CONTINUE = "A player has left your Dungeon group. Would you like to find another player to finish %s?";
+LFG_RANDOM_COOLDOWN_OTHER = "One of your group members has recently queued for a Random Dungeon and may not yet queue for another.";
+LFG_RANDOM_COOLDOWN_YOU = "You recently queued for a Random Dungeon.\nYou may queue for another in:";
+LFG_ROLES_TITLE = "I can fulfill the role of:";
+LFG_ROLE_CHECK_ROLE_CHOSEN = "%s has chosen: %s";
+LFG_STATISTIC_AVERAGE_WAIT = "Average Wait Time: %s";
+LFG_STATISTIC_AVERAGE_WAIT_UNKNOWN = "The wait time for %1$s is unknown.";
+LFG_STATISTIC_MATCHES_MADE = "%2$d matches made for %1$s in the last hour.";
+LFG_STATISTIC_PARTIES_IN_QUEUE = "%2$d parties looking for more people for %1$s";
+LFG_STATISTIC_PLAYERS_IN_QUEUE = "%2$d individual players queued for %1$s";
+LFG_TITLE = "Looking For Group";
+LFG_TOOLTIP_ROLES = "Roles:";
+LFG_TYPE_ANY_DUNGEON = "Any Dungeon";
+LFG_TYPE_ANY_HEROIC_DUNGEON = "Any Heroic Dungeon";
+LFG_TYPE_BATTLEGROUND = "Battleground";
+LFG_TYPE_DAILY_DUNGEON = "Daily Dungeon";
+LFG_TYPE_DAILY_HEROIC_DUNGEON = "Daily Heroic Dungeon";
+LFG_TYPE_DUNGEON = "Dungeon";
+LFG_TYPE_HEROIC_DUNGEON = "Heroic Dungeon";
+LFG_TYPE_NONE = "None";
+LFG_TYPE_QUEST = "Quest (Group)";
+LFG_TYPE_RAID = "Raid";
+LFG_TYPE_RANDOM_DUNGEON = "Random Dungeon";
+LFG_TYPE_ZONE = "Zone";
+LFM_DISABLED_LFG_TOOLTIP = "You must either be in a party or currently be looking for a group to join Looking For More.";
+LFM_NAME_TEMPLATE = "%s - Level %s %s";
+LFM_NUM_RAID_MEMBER_TEMPLATE = "%d members in raid group";
+LFM_TITLE = "Looking For More";
+LINK_TRADESKILL_TOOLTIP = "Click here to create a link to your profession.";
+LIST_ME = "List My Name";
+LIST_MY_GROUP = "List My Group";
+LOCALE_INFORMATION = "Locale Information";
+LOCATION_COLON = "Location:";
+LOCK = "Lock";
+LOCKED = "Locked";
+LOCKED_WITH_ITEM = "Requires %s";
+LOCKED_WITH_SPELL = "Requires %s";
+LOCKED_WITH_SPELL_KNOWN = "Requires %s";
+LOCK_ACTIONBAR_TEXT = "Lock ActionBars";
+LOCK_BATTLEFIELDMINIMAP = "Lock Zone Map";
+LOCK_CHANNELPULLOUT_LABEL = "Lock Channel Roster";
+LOCK_EXPIRE = "Lock Expire";
+LOCK_FOCUS_FRAME = "Lock Frame Position";
+LOCK_WINDOW = "Lock Window";
+LOGOUT = "Logout";
+LOG_PERIODIC_EFFECTS = "Periodic Damage";
+LOOKING = "Looking";
+LOOKING_FOR = "Looking For:";
+LOOKING_FOR_DUNGEON = "Dungeon Finder";
+LOOKING_FOR_GROUP_LABEL = "I'm looking for a group for:";
+LOOKING_FOR_GROUP_LABEL2 = "I'm also looking for a group for:";
+LOOKING_FOR_GROUP_TEXT = "Let other players know what dungeon, raid, quest, or zone you are interested in.";
+LOOKING_FOR_MORE = "Looking For More";
+LOOKING_FOR_MORE_TEXT = "Find additional group members for a dungeon, raid, quest, or zone.";
+LOOKING_FOR_RAID = "Raid Browser";
+LOOK_FOR_GROUP = "Look For Group";
+LOOK_FOR_MORE = "Look For More";
+LOOT = "Loot";
+LOOTER = "Looter";
+LOOT_FREE_FOR_ALL = "Loot: Free for All";
+LOOT_GONE = "Item already looted.";
+LOOT_GROUP_LOOT = "Loot: Group Loot";
+LOOT_ITEM = "%s receives loot: %s.";
+LOOT_ITEM_CREATED_SELF = "You create: %s.";
+LOOT_ITEM_CREATED_SELF_MULTIPLE = "You create: %sx%d.";
+LOOT_ITEM_MULTIPLE = "%s receives loot: %sx%d.";
+LOOT_ITEM_PUSHED_SELF = "You receive item: %s.";
+LOOT_ITEM_PUSHED_SELF_MULTIPLE = "You receive item: %sx%d.";
+LOOT_ITEM_SELF = "You receive loot: %s.";
+LOOT_ITEM_SELF_MULTIPLE = "You receive loot: %sx%d.";
+LOOT_KEY_TEXT = "Loot Key";
+LOOT_MASTER_LOOTER = "Loot: Master Looter";
+LOOT_METHOD = "Loot Method";
+LOOT_MONEY = "%s loots %s.";
+LOOT_MONEY_SPLIT = "Your share of the loot is %s.";
+LOOT_NEED_BEFORE_GREED = "Loot: Need Before Greed";
+LOOT_NEXT_PAGE = "Switch Page";
+LOOT_NO_DROP = "Looting %s will bind it to you.";
+LOOT_NO_DROP_DISENCHANT = "Disenchanting %s will destroy it.";
+LOOT_PROMOTE = "Promote to Master Looter";
+LOOT_ROLL_ALL_PASSED = "Everyone passed on: %s";
+LOOT_ROLL_DISENCHANT = "%s has selected Disenchant for: %s";
+LOOT_ROLL_DISENCHANT_SELF = "You have selected Disenchant for: %s";
+LOOT_ROLL_GREED = "%s has selected Greed for: %s";
+LOOT_ROLL_GREED_SELF = "You have selected Greed for: %s";
+LOOT_ROLL_INELIGIBLE_REASON1 = "Your class may not roll need on this item.";
+LOOT_ROLL_INELIGIBLE_REASON2 = "You already have the maximum amount of this item.";
+LOOT_ROLL_INELIGIBLE_REASON3 = "This item may not be disenchanted.";
+LOOT_ROLL_INELIGIBLE_REASON4 = "You do not have an Enchanter of skill %d in your group.";
+LOOT_ROLL_INELIGIBLE_REASON5 = "Need rolls are disabled for this item.";
+LOOT_ROLL_NEED = "%s has selected Need for: %s";
+LOOT_ROLL_NEED_SELF = "You have selected Need for: %s";
+LOOT_ROLL_PASSED = "%s passed on: %s";
+LOOT_ROLL_PASSED_AUTO = "%s automatically passed on: %s because he cannot loot that item.";
+LOOT_ROLL_PASSED_AUTO_FEMALE = "%s automatically passed on: %s because she cannot loot that item.";
+LOOT_ROLL_PASSED_SELF = "You passed on: %s";
+LOOT_ROLL_PASSED_SELF_AUTO = "You automatically passed on: %s because you cannot loot that item.";
+LOOT_ROLL_ROLLED_DE = "Disenchant Roll - %d for %s by %s";
+LOOT_ROLL_ROLLED_GREED = "Greed Roll - %d for %s by %s";
+LOOT_ROLL_ROLLED_NEED = "Need Roll - %d for %s by %s";
+LOOT_ROLL_WON = "%s won: %s";
+LOOT_ROLL_WON_NO_SPAM_DE = "%1$s won: %3$s |cff818181(Disenchant - %2$d)|r";
+LOOT_ROLL_WON_NO_SPAM_GREED = "%1$s won: %3$s |cff818181(Greed - %2$d)|r";
+LOOT_ROLL_WON_NO_SPAM_NEED = "%1$s won: %3$s |cff818181(Need - %2$d)|r";
+LOOT_ROLL_YOU_WON = "You won: %s";
+LOOT_ROLL_YOU_WON_NO_SPAM_DE = "You won: %2$s |cff818181(Disenchant - %1$d)|r";
+LOOT_ROLL_YOU_WON_NO_SPAM_GREED = "You won: %2$s |cff818181(Greed - %1$d)|r";
+LOOT_ROLL_YOU_WON_NO_SPAM_NEED = "You won: %2$s |cff818181(Need - %1$d)|r";
+LOOT_ROUND_ROBIN = "Loot: Round Robin";
+LOOT_THRESHOLD = "Loot Threshold";
+LOOT_UNDER_MOUSE_TEXT = "Open Loot Window at Mouse";
+LOSS = "Loss";
+LOW = "Low";
+LSHIFT_KEY_TEXT = "Left SHIFT";
+LUA_ERROR = "Lua Error";
+MACRO = "Macro";
+MACROFRAME_CHAR_LIMIT = "%d/255 Characters Used";
+MACROS = "Macros";
+MACRO_ACTION_FORBIDDEN = "A macro script has been blocked from an action only available to the Blizzard UI.";
+MACRO_HELP_TEXT_LINE1 = "Macro Help:";
+MACRO_HELP_TEXT_LINE2 = "- To bring up the macro UI type /macro or choose it from the chat command menu";
+MACRO_HELP_TEXT_LINE3 = "- Use the macro UI to automate chat text, emotes, and slash commands";
+MACRO_HELP_TEXT_LINE4 = "- To cast a spell from a macro use the following syntax: /cast ()";
+MACRO_HELP_TEXT_LINE5 = "- Shift click a spell in your spellbook with the macro UI open to add it to your macro";
+MACRO_POPUP_CHOOSE_ICON = "Choose an Icon:";
+MACRO_POPUP_TEXT = "Enter Macro Name (Max 16 Characters):";
+MAC_OPTIONS = "Mac Options";
+MAGE_INTELLECT_TOOLTIP = "Increases mana points and chance to score a critical hit with spells.\nIncreases the rate at which weapon skills improve.";
+MAGIC_RESISTANCES_COLON = "Magic Resistances:";
+MAIL_COD_ERROR = "C.O.D. must be <= %d";
+MAIL_COD_ERROR_COLORBLIND = "C.O.D. must be <= %1$d%2$s";
+MAIL_LABEL = "Mail";
+MAIL_LETTER_TOOLTIP = "Click to make a permanent\ncopy of this letter.";
+MAIL_LOOT_KEY_TEXT = "Loot Mail Key";
+MAIL_MULTIPLE_ITEMS = "Multiple items";
+MAIL_REPLY_PREFIX = "RE:";
+MAIL_RETURN = "Return";
+MAIL_SUBJECT_LABEL = "Subject:";
+MAIL_TO_LABEL = "To:";
+MAINASSIST = "Main Assist";
+MAINHANDSLOT = "Main Hand";
+MAINMENUBAR_FPS_LABEL = "Framerate: %.0f fps";
+MAINMENUBAR_LATENCY_LABEL = "Latency: %.0f ms";
+MAINMENU_BUTTON = "Game Menu";
+MAINTANK = "Main Tank";
+MAIN_ASSIST = "Main Assist";
+MAIN_MENU = "Options";
+MAIN_TANK = "Main Tank";
+MAJOR_GLYPH = "Major Glyph";
+MAKE_INTERACTABLE = "Make Interactive";
+MAKE_MODERATOR = "Make Moderator";
+MAKE_UNINTERACTABLE = "Make Noninteractive";
+MALE = "Male";
+MANA = "Mana";
+MANAGE_ACCOUNT = "Manage Account";
+MANAGE_ACCOUNT_URL = "http://signup.worldofwarcraft.com";
+MANA_COLON = "Mana:";
+MANA_COST = "%d Mana";
+MANA_COST_PER_TIME = "%d Mana, plus %d per sec";
+MANA_LOW = "Mana Low";
+MANA_REGEN = "Mana Regen";
+MANA_REGEN_ABBR = "Regen";
+MANA_REGEN_FROM_SPIRIT = "Increases Mana Regeneration by %d Per 5 Seconds while not casting";
+MANA_REGEN_TOOLTIP = "%d mana regenerated every 5 seconds while not casting\n%d mana regenerated every 5 seconds while casting";
+MAP_QUEST_DIFFICULTY_TEXT = "Quest Difficulty Color";
+MARKED_AFK = "You are now Away.";
+MARKED_AFK_MESSAGE = "You are now Away: %s";
+MARKED_DND = "You are now Busy: %s.";
+MASTERY_POINTS_SPENT = "%1$s Talents: %2$s";
+MASTER_LOOTER = "Master Looter";
+MASTER_VOLUME = "Master Volume";
+MATCHMAKING_MATCH_S = "You have been matched to a group for %s.";
+MATCHMAKING_PENDING = "Waiting to complete the match....";
+MAXIMUM = "Maximum";
+MAX_FOLLOW_DIST = "Max Camera Distance";
+MAX_HP_TEMPLATE = "%d Max health";
+MEETINGSTONE_LEVEL = "Level %d-%d";
+MEETINGSTONE_TOOLTIP = "Looking for more for %s";
+MELEE = "Melee";
+MELEE_ATTACK = "Melee Attack";
+MELEE_ATTACK_POWER = "Melee Attack Power";
+MELEE_ATTACK_POWER_TOOLTIP = "Increases damage with melee weapons by %.1f damage per second.";
+MELEE_COMBATLOG_TOOLTIP = "Shows natural melee swings.";
+MELEE_CRIT_CHANCE = "Crit Chance";
+MELEE_RANGE = "Melee Range";
+MEMBERS = "Members";
+MERCHANT = "Merchant";
+MERCHANT_ARENA_POINTS = "%d Arena Points";
+MERCHANT_BUYBACK = "Merchant Buyback";
+MERCHANT_HONOR_POINTS = "%d Honor Points";
+MERCHANT_PAGE_NUMBER = "Page %s of %s";
+MERCHANT_STOCK = "(%d)";
+MESSAGE_SOURCES = "Message Sources";
+MESSAGE_TYPES = "Message Types";
+META_GEM = "Meta";
+MILLISECONDS_ABBR = "ms";
+MINIMAP_LABEL = "Minimap";
+MINIMAP_TRACKING_AUCTIONEER = "Auctioneer";
+MINIMAP_TRACKING_BANKER = "Banker";
+MINIMAP_TRACKING_BATTLEMASTER = "BattleMaster";
+MINIMAP_TRACKING_FLIGHTMASTER = "FlightMaster";
+MINIMAP_TRACKING_INNKEEPER = "Innkeeper";
+MINIMAP_TRACKING_MAILBOX = "Mailbox";
+MINIMAP_TRACKING_REPAIR = "Repair";
+MINIMAP_TRACKING_STABLEMASTER = "StableMaster";
+MINIMAP_TRACKING_TOOLTIP_NONE = "Click to choose tracking type";
+MINIMAP_TRACKING_TRAINER_CLASS = "Class Trainer";
+MINIMAP_TRACKING_TRAINER_PROFESSION = "Profession Trainers";
+MINIMAP_TRACKING_TRIVIAL_QUESTS = "Low Level Quests";
+MINIMAP_TRACKING_VENDOR_AMMO = "Ammunition";
+MINIMAP_TRACKING_VENDOR_FOOD = "Food & Drink";
+MINIMAP_TRACKING_VENDOR_POISON = "Poisons";
+MINIMAP_TRACKING_VENDOR_REAGENT = "Reagents";
+MINIMIZE = "Minimize";
+MINIMUM = "Minimum";
+MINOR_GLYPH = "Minor Glyph";
+MINS_ABBR = "Mins";
+MINUTES = "|4Minute:Minutes;";
+MINUTES_ABBR = "%d |4Min:Min;";
+MINUTE_ONELETTER_ABBR = "%d m";
+MISCELLANEOUS = "Miscellaneous";
+MISS = "Miss";
+MISSES = "Misses";
+MODE = "Mode";
+MODIFIERS_COLON = "Modifiers:";
+MONEY = "Money";
+MONEY_COLON = "Money:";
+MONEY_LOOT = "Money Loot";
+MONSTER_BOSS_EMOTE = "Boss Emote";
+MONSTER_BOSS_WHISPER = "Boss Whisper";
+MONTH_APRIL = "April";
+MONTH_AUGUST = "August";
+MONTH_DECEMBER = "December";
+MONTH_FEBRUARY = "February";
+MONTH_JANUARY = "January";
+MONTH_JULY = "July";
+MONTH_JUNE = "June";
+MONTH_MARCH = "March";
+MONTH_MAY = "May";
+MONTH_NOVEMBER = "November";
+MONTH_OCTOBER = "October";
+MONTH_SEPTEMBER = "September";
+MORE_REAGENTS = "More Reagents";
+MOTD_COLON = "MOTD:";
+MOUNT = "Mount";
+MOUNTS = "Mounts";
+MOUSE_LABEL = "Mouse";
+MOUSE_LOOK_SPEED = "Mouse Look Speed";
+MOUSE_SENSITIVITY = "Mouse Sensitivity";
+MOUSE_SUBTEXT = "These options allow you to change the way the mouse behaves inside the game.";
+MOVE_FILTER_DOWN = "Move Filter Down";
+MOVE_FILTER_UP = "Move Filter Up";
+MOVE_TO_CONVERSATION_WINDOW = "Move to Conversation Window";
+MOVE_TO_INACTIVE = "Move to Inactive";
+MOVE_TO_NEW_WINDOW = "Move to New Window";
+MOVE_TO_WHISPER_WINDOW = "Move to Whisper Window";
+MOVIE_RECORDING_AIC = "Apple Intermediate";
+MOVIE_RECORDING_AIC_TOOLTIP = "Exclusive to MacOS X. This codec is the fastest to compress.";
+MOVIE_RECORDING_CANCEL_CONFIRMATION = "Do you really want to cancel this movie? This will delete the uncompressed part of the movie. If you are currently recording, you will lose the entire movie.";
+MOVIE_RECORDING_CODEC_TOOLTIP = "Changes the compression method.";
+MOVIE_RECORDING_COMPRESSBUTTON = "Compress";
+MOVIE_RECORDING_COMPRESSDIALOG = "Compress...";
+MOVIE_RECORDING_COMPRESSING = "Compressing";
+MOVIE_RECORDING_COMPRESSING_CANCEL_NEWBIE_TOOLTIP = "This will finish the compression early. You will lose the part that is still not compressed. The part that is currently compressed will be saved on your hard drive.";
+MOVIE_RECORDING_COMPRESSING_CANCEL_TOOLTIP = "Cancel Compression";
+MOVIE_RECORDING_COMPRESSION = "Compression";
+MOVIE_RECORDING_COMPRESSION_STARTED = "Movie compression for \"%s\" started.";
+MOVIE_RECORDING_COMPRESS_TOOLTIP = "This will search for uncompressed movies and ask you if you want to compress, delete or ignore them.";
+MOVIE_RECORDING_DATA_RATE = "Recording Data Rate:";
+MOVIE_RECORDING_DATA_RATE_TOOLTIP = "This is how much data needs to be written to your hard drive every second. If the game becomes very choppy while recording then it might be that the data rate is too high for your hard drive. The game will stop recording if it cannot write the data fast enough.";
+MOVIE_RECORDING_DV = "DV";
+MOVIE_RECORDING_DV_TOOLTIP = "DV is the primary codec for most camcorders and iMovie.";
+MOVIE_RECORDING_ENABLE_COMPRESSION = "Compress After Recording";
+MOVIE_RECORDING_ENABLE_COMPRESSION_TOOLTIP = "If this is checked, the movie will be compressed when you stop recording. Otherwise, you will need to use the compress button to finish processing the movies.";
+MOVIE_RECORDING_ENABLE_CURSOR = "Record the Cursor";
+MOVIE_RECORDING_ENABLE_CURSOR_TOOLTIP = "If this is checked, you will see the cursor in the movie. Regardless of this setting, you will see the cursor while playing.";
+MOVIE_RECORDING_ENABLE_GUI = "Record the User Interface";
+MOVIE_RECORDING_ENABLE_GUI_TOOLTIP = "If this is checked, you will see the user interface in the movie. Regardless of this setting, you will see the user interface while playing.";
+MOVIE_RECORDING_ENABLE_ICON = "Show Recording Icon";
+MOVIE_RECORDING_ENABLE_ICON_TOOLTIP = "If this is checked, you will see a movie camera icon appear on the minimap frame while recording. If the user interface is recorded, this will also appear in the movie.";
+MOVIE_RECORDING_ENABLE_RECOVER = "Compress at Log In";
+MOVIE_RECORDING_ENABLE_RECOVER_TOOLTIP = "If this is checked, the game will offer the choice of compressing, ignoring, or deleting any pending movies when you log in.";
+MOVIE_RECORDING_ENABLE_SOUND = "Record Sound";
+MOVIE_RECORDING_ENABLE_SOUND_TOOLTIP = "If this is checked, sound will be recorded in the movie.";
+MOVIE_RECORDING_FPS_FOURTH = "1/4 Game Framerate";
+MOVIE_RECORDING_FPS_HALF = "1/2 Game Framerate";
+MOVIE_RECORDING_FPS_THIRD = "1/3 Game Framerate";
+MOVIE_RECORDING_FRAMERATE = "Framerate";
+MOVIE_RECORDING_FRAMERATE_TOOLTIP = "Changes the framerate of the movie. If you choose a fixed framerate, the game framerate will be capped to this while recording. Reduce to increase performance. ";
+MOVIE_RECORDING_FULL_RESOLUTION = "Full resolution";
+MOVIE_RECORDING_GUI_OFF = "Recording of the user interface is off.";
+MOVIE_RECORDING_GUI_ON = "Recording of the user interface is on.";
+MOVIE_RECORDING_H264 = "H.264";
+MOVIE_RECORDING_H264_TOOLTIP = "This codec is supported natively by Apple devices like the iPod, iPhone and AppleTV. This codec has the best ratio quality/size but it is also the slowest to compress.";
+MOVIE_RECORDING_MJPEG = "Motion JPEG";
+MOVIE_RECORDING_MJPEG_TOOLTIP = "This codec is faster to compress than H.264 but it will generate a bigger file. ";
+MOVIE_RECORDING_MPEG4 = "MPEG-4";
+MOVIE_RECORDING_MPEG4_TOOLTIP = "MPEG-4 is supported by many digital cameras and iMovie.";
+MOVIE_RECORDING_PIXLET = "Pixlet";
+MOVIE_RECORDING_QUALITY_TOOLTIP = "Controls the movie quality. This will affect the final compression. Increasing the quality will also increase the amount of disk space used by the movie and the compression speed.";
+MOVIE_RECORDING_RECORDING = "Recording Time: ";
+MOVIE_RECORDING_RECORDING_STARTED = "Movie recording of \"%s\" started.";
+MOVIE_RECORDING_RECORDING_STOPPED = "Movie recording of \"%s\" stopped.";
+MOVIE_RECORDING_RECOVERING = "Recovering frame #";
+MOVIE_RECORDING_RESOLUTION_TOOLTIP = "Changes the resolution of the movie. You can record a longer movie if the resolution is smaller.";
+MOVIE_RECORDING_TIME = "Available Recording Time:";
+MOVIE_RECORDING_TIME_TOOLTIP = "This is how long you can record a movie before you run out of disk space. The game will stop recording after that time.";
+MOVIE_RECORDING_UNCOMPRESSED_RGB = "Uncompressed RGB";
+MOVIE_RECORDING_WARNING_COMPRESSING = "You cannot start recording while compressing a movie.";
+MOVIE_RECORDING_WARNING_DISK_FULL = "You don't have enough free space on your hard drive to record movies.";
+MOVIE_RECORDING_WARNING_NO_MOVIE = "There is no movie to compress.";
+MOVIE_RECORDING_WARNING_PERF = "Recording stopped - the movie recording settings may be too high for this system configuration.";
+MOVIE_RECORDING_WARNING_REQUIREMENTS = "Your system doesn't presently meet the minimum requirements to record movies. MacOS X 10.4.9, Quicktime 7.1.6 and a shader capable graphic card are required.";
+MP = "MP";
+MULTIPLE_DUNGEONS = "Multiple Dungeons";
+MULTISAMPLE = "Multisampling";
+MULTISAMPLING_FORMAT_STRING = "%d-bit color %d-bit depth %dx multisample";
+MULTI_CAST_TOOLTIP_NO_TOTEM = "No Totem";
+MUSIC_DISABLED = "Music Disabled";
+MUSIC_ENABLED = "Music Enabled";
+MUSIC_VOLUME = "Music";
+MUTE = "Mute";
+MUTED = "Muted";
+MUTED_LIST = "Muted List";
+MUTE_PLAYER = "Mute Player";
+NAME = "Name";
+NAMES_LABEL = "Names";
+NAMES_SUBTEXT = "These options allow you to control which names are visible within the game field while you play.";
+NAME_CHAT_WINDOW = "Enter chat window name";
+NEAR = "Near";
+NECKSLOT = "Neck";
+NEED = "Need";
+NEED_NEWBIE = "You really want the item.";
+NET_PROMOTER_HIGH = "In a heartbeat";
+NET_PROMOTER_LOW = "Not a chance";
+NEVER = "Never";
+NEW = "New";
+NEWBIE_TOOLTIP_ABANDONQUEST = "Abandons the selected quest, removing it from the Quest Log. Any quest that you abandon can be accepted again at some later date. There is no penalty for abandoning a quest.";
+NEWBIE_TOOLTIP_ACHIEVEMENT = "View information about your achievements and statistics.";
+NEWBIE_TOOLTIP_ADDFRIEND = "Adds a player to your friends list. You will be notified whenever a friend logs on or off. Other players do not know whether they are on your friends list.";
+NEWBIE_TOOLTIP_ADDMEMBER = "Adds a new player to the guild.";
+NEWBIE_TOOLTIP_ADDTEAMMEMBER = "Adds a new player to the team.";
+NEWBIE_TOOLTIP_ALLIANCE = "A proud member of the Alliance, opposed to members of the Horde (Orcs, Trolls, Tauren, Undead, Blood Elves).";
+NEWBIE_TOOLTIP_AUTO_JOIN_VOICE = "Allows the automatic joining of\nvoice chat when not already\nin another voice chat session.";
+NEWBIE_TOOLTIP_BATTLEFIELDMINIMAP_OPTIONS = "Right-click to get a list of customizable options for this window. Left-click and drag to move the window.";
+NEWBIE_TOOLTIP_BATTLEFIELD_GROUP_JOIN = "If you are the leader of a group, this button will add your current group to the battleground queue. Your group will be guaranteed to get into the same battleground instance at the same time. Any group member added after you click this button or a group member in a queue for another battleground will not be guaranteed entrance to the same battleground.";
+NEWBIE_TOOLTIP_CHANNELPULLOUT_OPTIONS = "Right-click to get a list of customizable options for this window. Left-click and drag to move the window.";
+NEWBIE_TOOLTIP_CHANNELTAB = "Allows you to view or modify your text and voice chat channels.";
+NEWBIE_TOOLTIP_CHARACTER = "Information about your character, including equipment, combat statistics, skills, and reputation.";
+NEWBIE_TOOLTIP_CHATMENU = "Commands used for communicating with others. With the Chat menu, you can talk to people standing nearby, send a private message to one person, chat with party members, wave at a friend, or create a macro.";
+NEWBIE_TOOLTIP_CHATOPTIONS = "Right-click to get a list of customizable options for this window. Left-click and drag to move the window.";
+NEWBIE_TOOLTIP_CHAT_OVERFLOW = "Not all chat tabs can be displayed. Left-click to see all chat tabs.";
+NEWBIE_TOOLTIP_DEMOTE = "Demotes the selected player one rank lower.";
+NEWBIE_TOOLTIP_DISHONORABLE_KILLS = "Each time you assist in killing a civilian in PvP that is too low of a level to give you experience (a gray level number), you will get a dishonorable kill. Each dishonorable kill you get immediately reduces your overall ranking slightly, and each additional dishonorable kill you get during a single day has a larger effect than the last one. Dishonorable kills are directly applied to your ranking.";
+NEWBIE_TOOLTIP_DISPLAY_CHANNEL_PULLOUT = "Click and drag to display a roster window that lists players with voice chat enabled in this channel.";
+NEWBIE_TOOLTIP_ENCHANTSLOT = "Drop an item into this slot to permit other players to unlock a container, or enchant or poison an item. An item placed in this slot will not be traded; rather, it will simply return to its owner's inventory.";
+NEWBIE_TOOLTIP_ENTER_BATTLEGROUND = "Join the queue to enter this battleground when space becomes available. This will result in a longer wait than selecting \"First Available\".";
+NEWBIE_TOOLTIP_EQUIPMENT_MANAGER = "Use the Equipment Manager to save Equipment Sets and switch back and forth between them quickly later.";
+NEWBIE_TOOLTIP_EQUIPMENT_MANAGER_IGNORE_SLOT = "Prevents what you're wearing here from being saved with Equipment Sets.";
+NEWBIE_TOOLTIP_EQUIPMENT_MANAGER_PLACE_IN_BAGS = "Take off this piece of equipment and put it in your bags.";
+NEWBIE_TOOLTIP_EQUIPMENT_MANAGER_UNIGNORE_SLOT = "Stops preventing what you're wearing here from being saved with Equipment Sets.";
+NEWBIE_TOOLTIP_FIRST_AVAILABLE = "Join the queue to enter the first available battleground. If you select \"First Available\" and another party member enters a \"First Available\" battleground, then your preference will be changed to that battleground. ";
+NEWBIE_TOOLTIP_FRAMERATE = "Indicates how smoothly the game animates. Low framerate can be improved by changing your video options.";
+NEWBIE_TOOLTIP_FRIENDSTAB = "Allows you to manage a list of players you enjoy playing with. You receive notifications of friends logging on or off.";
+NEWBIE_TOOLTIP_GROUPINVITE = "Invites the selected player to join a group.";
+NEWBIE_TOOLTIP_GUILDCONTROL = "Allows you to customize the names of each rank in your guild, along with its privileges.";
+NEWBIE_TOOLTIP_GUILDGROUPINVITE = "Invites the selected guild member to join a group.";
+NEWBIE_TOOLTIP_GUILDPUBLICNOTE = "Click to view your public note. This is information that other players will see about you in the guild UI. If you click on the note itself, you will be able to edit it.";
+NEWBIE_TOOLTIP_GUILDREMOVE = "Removes the selected player from the guild.";
+NEWBIE_TOOLTIP_GUILDTAB = "Allows you to view information about your guild, and players in it. If you are an officer, you can also manage your guild from this tab.";
+NEWBIE_TOOLTIP_GUILD_INFORMATION = "Click to see additional information about your guild. If you are an officer or the guild leader, you can put information here for your guild members to read.";
+NEWBIE_TOOLTIP_GUILD_MEMBER_OPTIONS = "Right-click a guild member for more options.";
+NEWBIE_TOOLTIP_HEALTHBAR = "The amount of health you currently have. If your health reaches zero, you will die. Health automatically regenerates when you are out of combat.";
+NEWBIE_TOOLTIP_HELP = "Access the Online Knowledge Base or speak to a Game Master (GM) about a problem you are having. ";
+NEWBIE_TOOLTIP_HONORABLE_KILLS = "Each time you or a group you are part of does damage to an enemy player in PvP that is subsequently killed you gain an honorable kill. You only get an honorable kill if the target’s difficulty is green or better (the target would give you experience if it were a monster). Only enemy players give honorable kills.";
+NEWBIE_TOOLTIP_HONOR_CONTRIBUTION_POINTS = "Honor is what you gain by making honorable kills in PvP combat. How much honor you gain per kill is determined by how much damage you (or your group) did to the player that was killed, with more damage done equaling more honor. This honor gain is split amongst the members of your group or raid group. Also you will gain less honor for killing the same player over and over again in a short period of time, so after a few kills of the same player you will get little or no honor from killing them.";
+NEWBIE_TOOLTIP_HONOR_STANDING = "Standing is how you are doing compared to all other players on your side (Horde or Alliance). If your standing is 150, then there were 149 players who gained more honor than you did during that time period. You must get at least 25 Honorable Kills in a week in order to be eligible to gain Standing and Rank.";
+NEWBIE_TOOLTIP_HORDE = "A proud member of the Horde, opposed to members of the Alliance (Night Elves, Dwarves, Humans, Gnomes, Draenei).";
+NEWBIE_TOOLTIP_IGNOREPLAYER = "Adds a player to your ignore list. You will no longer see messages or other text from players on your ignore list, nor will these players be able to communicate with you in any other way.";
+NEWBIE_TOOLTIP_IGNORETAB = "Allows you to modify the list of players whom you are currently ignoring.";
+NEWBIE_TOOLTIP_LATENCY = "The time it takes to talk with the game server. Consistently high (red) latencies may indicate a problem with your Internet connection.";
+NEWBIE_TOOLTIP_LFGPARENT = "A tool to help you find a group to join or find additional players to complete your newly created or existing group.";
+NEWBIE_TOOLTIP_LFMTAB = "Click here to look for members to add to your existing group.";
+NEWBIE_TOOLTIP_MAINMENU = "Modify your settings, change your hotkeys or exit the game.";
+NEWBIE_TOOLTIP_MANABAR0 = "The amount of mana you currently have. Players require mana in order to cast spells. Mana automatically regenerates if you have not cast a spell in the past five seconds.";
+NEWBIE_TOOLTIP_MANABAR1 = "Warriors (and Druids in Bear Form or Dire Bear Form) require Rage in order to use their abilities.";
+NEWBIE_TOOLTIP_MANABAR2 = "Hunters require focus to use their abilities. Focus generates while standing still.";
+NEWBIE_TOOLTIP_MANABAR3 = "Rogues (and Druids in Cat Form) require Energy in order to use their abilities.";
+NEWBIE_TOOLTIP_MANABAR4 = "The amount of happiness your pet currently has. Content pets inflict normal damage on their enemies, whereas Happy pets inflict enhanced damage, and unhappy pets inflict reduced damage. Happiness goes down when your pet dies or as it grows hungry, while feeding your pet will increase its happiness.";
+NEWBIE_TOOLTIP_MEMORY = "How much memory your AddOns are using. You can get to the addon management page from the character select screen.";
+NEWBIE_TOOLTIP_MINIMAPTOGGLE = "Toggle display of the minimap.";
+NEWBIE_TOOLTIP_MUTEPLAYER = "Adds a player to your mute list. You will no longer hear voice chat from players on your mute list.";
+NEWBIE_TOOLTIP_PARTYOPTIONS = "If you belong to a party, you can right-click your portrait to bring up the Party Options menu. This menu will allow you to quit the party or see what looting rules the party is using. A party leader can add or remove party members, as well as change the party's looting rules.";
+NEWBIE_TOOLTIP_PLAYEROPTIONS = "Right-click to bring up special commands for interacting with another player. You can inspect their equipment, issue a party invite, initiate a trade, or challenge a player to a duel. A group leader can promote or remove that player from the group.";
+NEWBIE_TOOLTIP_PROMOTE = "Promotes the selected player one rank higher.";
+NEWBIE_TOOLTIP_PVP = "View information about your honor and your arena team.";
+NEWBIE_TOOLTIP_PVPFFA = "You can now attack and be attacked by any player in the game.";
+NEWBIE_TOOLTIP_QUESTLOG = "A list of all the active quests you currently have. You can have up to 25 active quests at one time.";
+NEWBIE_TOOLTIP_RAF_SUMMON_LINKED = "Click here to summon a linked party member.";
+NEWBIE_TOOLTIP_RAIDTAB = "Allows you to view or modify your raid group. Raid groups are groups of more than 5 people used to defeat very difficult challenges at high levels.";
+NEWBIE_TOOLTIP_RANK = "Rank is the final result of all the honor system calculations. Based upon a comparison between your standing for the week versus your current rank, your rank may either rise, fall, or stay the same. Higher level players rise more quickly in rank (and fall more slowly) than lower level players. In addition, rank increases more quickly at low ranks than at high ranks.";
+NEWBIE_TOOLTIP_RANK_POSITION = "Your position within the rank. This bar will tell you how close you are to attaining the next rank or falling to the previous rank. This will only be updated each week when ranking is updated.";
+NEWBIE_TOOLTIP_REMOVEFRIEND = "Removes the selected player from your friends list.";
+NEWBIE_TOOLTIP_REMOVEPLAYER = "Removes the selected player from your ignore list.";
+NEWBIE_TOOLTIP_SENDMESSAGE = "Sends a private message to the selected player.";
+NEWBIE_TOOLTIP_SHAREQUEST = "Shares the selected quest with any party members who are eligible for the quest. Certain quests, such as those granted by items, cannot be shared.";
+NEWBIE_TOOLTIP_SOCIAL = "Information about other people in the game. You can use the Social window to manage your friends list and ignore list, as well as see who is online.";
+NEWBIE_TOOLTIP_SPELLBOOK = "To prepare a spell or ability for use, open the Spellbook & Abilities window, left-click the spell or ability and drag it down to your action bar.";
+NEWBIE_TOOLTIP_STOPIGNORE = "Removes the selected player from your ignore list.";
+NEWBIE_TOOLTIP_STOPWATCH_PLAYPAUSEBUTTON = "Play/Pause";
+NEWBIE_TOOLTIP_STOPWATCH_RESETBUTTON = "Reset";
+NEWBIE_TOOLTIP_TALENTS = "The array of talents available to enhance and specialize your character.";
+NEWBIE_TOOLTIP_TRACKQUEST = "Add or remove the selected quest from your quest watch list. You can click on a quest in your quest watch list to see the details of that quest.";
+NEWBIE_TOOLTIP_UNIT_DUEL = "Challenges the selected player to a duel. The first player to reach zero hit points loses the duel.";
+NEWBIE_TOOLTIP_UNIT_FOLLOW = "Causes you to begin following the selected player. You will automatically continue to follow the player until this auto follow mode is disrupted.";
+NEWBIE_TOOLTIP_UNIT_FREE_FOR_ALL = "Under free-for-all rules, all group members may loot a monster that they help the group to kill. Money is automatically divided between group members.";
+NEWBIE_TOOLTIP_UNIT_GROUP_LOOT = "Under group loot rules, players take turns looting just like in round-robin with the exception that all group members will be eligible to roll for items over the loot threshold.";
+NEWBIE_TOOLTIP_UNIT_INSPECT = "Inspects any armor and weapons that the selected player has equipped.";
+NEWBIE_TOOLTIP_UNIT_INVITE = "Invites the selected player to join a group.";
+NEWBIE_TOOLTIP_UNIT_LEAVE_PARTY = "Removes the player from their current party.";
+NEWBIE_TOOLTIP_UNIT_LOOT_THRESHOLD = "Items of this quality or higher will be able to be rolled on by the group when looted from a monster.";
+NEWBIE_TOOLTIP_UNIT_MASTER_LOOTER = "Under master-looter rules, the group leader is the only group member allowed to loot items at or above the threshold. Items below threshold and money are distributed via the round robin rules.";
+NEWBIE_TOOLTIP_UNIT_NEED_BEFORE_GREED = "Under need-before-greed rules, loot is distributed round-robin style. Any items over the loot threshold can only be rolled on by group members that can use the item.";
+NEWBIE_TOOLTIP_UNIT_OPT_OUT_LOOT = "If enabled, you will only be able to receive loot by looting quest items, looting items that everyone passes on, or being given loot by the master looter.";
+NEWBIE_TOOLTIP_UNIT_PET_ABANDON = "Abandons your pet, letting it return to the wild. Once you abandon a pet, you can never regain its companionship.";
+NEWBIE_TOOLTIP_UNIT_PET_DISMISS = "Dismisses your controlled minion.";
+NEWBIE_TOOLTIP_UNIT_PET_PAPERDOLL = "Information about your pet, including its combat statistics, spell resistances, and diet.";
+NEWBIE_TOOLTIP_UNIT_PET_RENAME = "Gives your pet a new name that you specify. A pet can only be renamed once.";
+NEWBIE_TOOLTIP_UNIT_PROMOTE = "Surrenders your leadership of the group, naming the selected player to succeed you.";
+NEWBIE_TOOLTIP_UNIT_ROUND_ROBIN = "Under round-robin rules, group members take turns looting the monsters that they help the group to kill. Money is automatically divided between group members.";
+NEWBIE_TOOLTIP_UNIT_TRADE = "Initiates a trade with the selected player.";
+NEWBIE_TOOLTIP_UNIT_UNINVITE = "Removes the selected player from the group.";
+NEWBIE_TOOLTIP_UNIT_VOTE_TO_KICK = "Starts a vote to remove the selected player from the group.";
+NEWBIE_TOOLTIP_UNMUTE = "Removes the selected player from your mute list.";
+NEWBIE_TOOLTIP_VOICE_CHAT_SELECTOR = "This menu allows you to select the Voice Chat channel you would like to listen and speak in. Right click to see a list of available voice chat channels.";
+NEWBIE_TOOLTIP_WHOTAB = "Allows you to locate other players in the world.";
+NEWBIE_TOOLTIP_WORLDMAP = "As you explore a zone, more areas of interest will become visible on the world map. You can use left-click to zoom in, or right-click to zoom out.";
+NEWBIE_TOOLTIP_XPBAR = "The amount of experience (XP) you have earned. The color of the XP bar indicates your rest state: light blue for Rested, and purple for Normal. Rested players earn twice the experience they would normally gain from slaying a monster. Characters become less rested when they kill monsters, and more rested by spending time at or logging out at an inn or city.";
+NEW_ACHIEVEMENT_EARNED = "You have earned the achievement '%s'.";
+NEW_CHAT_WINDOW = "Create New Window";
+NEW_CONVERSATION_INSTRUCTIONS = "Choose |cffffffff2|r friends to start a conversation.";
+NEW_LEADER = "New Leader";
+NEW_TITLE_EARNED = "You have earned the title '%s'.";
+NEXT = "Next";
+NEXT_ABILITY = "Next Ability";
+NEXT_BATTLE = "Next Battle: %1$02d:%2$02d:%3$02d";
+NO = "No";
+NONE = "None";
+NONEQUIPSLOT = "Created Items";
+NONE_CAPS = "NONE";
+NONE_KEY = "None";
+NORMAL_QUEST_DISPLAY = "|cff000000%s|r";
+NOTE = "Public Note";
+NOTE_COLON = "Note:";
+NOTE_SUBMITTED = "Note submitted";
+NOTE_SUBMIT_FAILED = "Note submission failed";
+NOT_APPLICABLE = "N/A";
+NOT_BOUND = "Not Bound";
+NOT_ENOUGH_MANA = "You don't have enough mana to cast %s.";
+NOT_IN_GROUP = "You are no longer in a party.";
+NOT_TAMEABLE = "Cannot be Tamed";
+NOT_YET_SIGNED = "";
+NO_ATTACHMENTS = "No Attachments";
+NO_BIDS = "No Bids";
+NO_COMPLETED_ACHIEVEMENTS = "You have not earned any achievements recently";
+NO_DAILY_QUESTS_REMAINING = "You cannot complete any more daily quests today.";
+NO_EMPTY_KEYRING_SLOTS_ERROR = "Your keyring is full.";
+NO_EQUIPMENT_SLOTS_AVAILABLE = "No equipment slot is available for that item.";
+NO_FRIEND_REQUESTS = "You have no friend requests";
+NO_GUILDBANK_TABS = "Your guild has not purchased any guild bank space.";
+NO_LFD_WHILE_LFR = "You may not queue for a Dungeon while you are listed in the Raid Browser.";
+NO_LFR_WHILE_LFD = "You may not list yourself in the Raid Browser while you are queued for a Dungeon.";
+NO_RAIDS_AVAILABLE = "There are no raids available at your level.";
+NO_RAID_INSTANCES_SAVED = "You are not saved to any instances";
+NO_RESPONSE = "No Response";
+NO_UPDATED_STATS_TEXT = "You have no recently updated stats";
+NO_VIEWABLE_GUILDBANK_LOGS = "You do not have any permission to view any Guild Bank logs.";
+NO_VIEWABLE_GUILDBANK_TABS = "You do not have permission to view any Guild Bank tabs.";
+NO_VOICE_SESSIONS = "No Channel";
+NUMBER_OF_RESULTS_TEMPLATE = "Items %d - %d ( %d total )";
+NUM_FREE_SLOTS = "%d Empty |4Slot:Slots; (Total)";
+NUM_GUILDBANK_TABS_PURCHASED = "(%d/%d tabs purchased)";
+NUM_RAID_MEMBERS = "%d Raid Members";
+OBJECTIVES_IGNORE_CURSOR_TEXT = "Disable Mouseover";
+OBJECTIVES_LABEL = "Objectives|TInterface\\OptionsFrame\\UI-OptionsFrame-NewFeatureIcon:0:0:0:-1|t";
+OBJECTIVES_SHOW_QUEST_MAP = "Show Quest Map";
+OBJECTIVES_STOP_TRACKING = "Stop Tracking";
+OBJECTIVES_SUBTEXT = "These options allow you to customize how game objectives like Quests and Achievements are displayed in the user interface,";
+OBJECTIVES_TRACKER_LABEL = "Objectives";
+OBJECTIVES_VIEW_ACHIEVEMENT = "Open Achievement";
+OBJECTIVES_VIEW_IN_ACHIEVEMENTS = "Open Achievements";
+OBJECTIVES_VIEW_IN_QUESTLOG = "Open Quest Details";
+OBJECTIVES_WATCH_QUESTS_ARENA = "You cannot track quests while in an Arena.";
+OBJECTIVES_WATCH_TOO_MANY = "You don't have space to track any more objectives, stop tracking some first.";
+OBJECT_ALPHA = "Object Alpha";
+OFF = "Off";
+OFFICER = "Officer";
+OFFICER_CHAT = "Officer Chat";
+OFFICER_NOTE_COLON = "Officer's Note";
+OKAY = "Okay";
+OLD_TITLE_LOST = "You have lost the title '%s'.";
+ONLY_EMPTY_BAGS = "Only empty bags can be picked up!";
+ON_COOLDOWN = "On Cooldown";
+OPACITY = "Opacity";
+OPENING = "Opening";
+OPENMAIL = "Open Mail";
+OPEN_LOCK_OTHER = "%s performs %s on %s.";
+OPEN_LOCK_SELF = "You perform %s on %s.";
+OPEN_RAID_BROWSER = "Open Raid Browser";
+OPTIONAL = "optional";
+OPTIONAL_PARENS = "(optional)";
+OPTIONS_BRIGHTNESS = "Brightness";
+OPTIONS_MENU = "Options Menu";
+OPTIONS_SHADERS = "Shaders";
+OPTION_CHAT_STYLE_CLASSIC = "The chat entry box will work as it previously did. There will be a single entry box always attached to the primary Chat Frame.";
+OPTION_CHAT_STYLE_IM = "When clicking the tab of a Chat Frame, the entry box will attach to it. Each window's entry box will maintain its own saved state and history.";
+OPTION_CONVERSATION_MODE_INLINE = "Real ID Conversations will be displayed similarly to channels. They may be moved to a new window by right-clicking on the Conversation name in chat.";
+OPTION_CONVERSATION_MODE_POPOUT = "New Real ID Conversations will be displayed in a new tab.";
+OPTION_LOGOUT_REQUIREMENT = "Requires logout to take effect.";
+OPTION_PREVIEW_TALENT_CHANGES_DESCRIPTION = "If enabled, you will be able to review your talents in the Talent Interface before spending your talent points.";
+OPTION_RESTART_REQUIREMENT = "Requires game restart to take effect.";
+OPTION_STEREO_CONVERGENCE = "Changes the 3D depth of the screen.";
+OPTION_STEREO_SEPARATION = "Changes the amount of separation created by 3D depth.";
+OPTION_TOOLTIP_ADVANCED_OBJECTIVES = "Allows you to resize, reposition, collapse and expand the Objectives frame.";
+OPTION_TOOLTIP_ADVANCED_WORLD_MAP = "Enabling this will allow you to move the smaller world map by right-clicking its title bar.";
+OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY1 = "Never show the aggro warning system.";
+OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY2 = "Only show the aggro warning system in instances.";
+OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY3 = "Only show the aggro warning system while in a party (including raids).";
+OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY4 = "Always show the aggro warning system.";
+OPTION_TOOLTIP_ALWAYS_SHOW_MULTIBARS = "Check this option to always display extra actionbars.";
+OPTION_TOOLTIP_AMBIENCE_VOLUME = "Adjusts the ambient sound volume.";
+OPTION_TOOLTIP_ANIMATION = "PLACE_HOLDER";
+OPTION_TOOLTIP_ANISOTROPIC = "Increases texture sharpness, particularly for textures viewed at an angle. Decrease to improve performance.";
+OPTION_TOOLTIP_ASSIST_ATTACK = "Automatically attack a target when you acquire it by using \"/assist\".";
+OPTION_TOOLTIP_AUTO_DISMOUNT_FLYING = "If enabled, your character will automatically dismount before casting while flying.";
+OPTION_TOOLTIP_AUTO_FOLLOW_SPEED = "Adjust the camera movement speed in Always and Smart following styles.";
+OPTION_TOOLTIP_AUTO_JOIN_GUILD_CHANNEL = "Check this option to automatically join the Guild Recruitment chat channel based upon whether or not you are in a guild.";
+OPTION_TOOLTIP_AUTO_LOOT_ALT_KEY = "Use the \"ALT\" key to Loot when \"Auto Loot\" is checked, and to Auto Loot when it is not.";
+OPTION_TOOLTIP_AUTO_LOOT_CTRL_KEY = "Use the \"CTRL\" key to Loot when \"Auto Loot\" is checked, and to Auto Loot when it is not.";
+OPTION_TOOLTIP_AUTO_LOOT_DEFAULT = "Sets Auto Looting as the default action when clicking on lootable things. (Looting when this is checked, or Auto Looting when it is not, is performed by holding the Loot Key / Auto Loot Key)";
+OPTION_TOOLTIP_AUTO_LOOT_KEY_TEXT = "Key to use to auto loot";
+OPTION_TOOLTIP_AUTO_LOOT_NONE_KEY = "Do not apply a key.";
+OPTION_TOOLTIP_AUTO_LOOT_SHIFT_KEY = "Use the \"SHIFT\" key to Loot when \"Auto Loot\" is checked, and to Auto Loot when it is not.";
+OPTION_TOOLTIP_AUTO_QUEST_PROGRESS = "Quests are automatically watched for 5 minutes when you achieve a quest objective.";
+OPTION_TOOLTIP_AUTO_QUEST_WATCH = "Automatically track quests with objectives as soon as you obtain them.";
+OPTION_TOOLTIP_AUTO_RANGED_COMBAT = "If enabled, your character will automatically switch between auto attack and auto shot.";
+OPTION_TOOLTIP_AUTO_SELF_CAST = "When this is enabled, friendly target spells that you cast while you have a non friendly target or no target will automatically be self cast.";
+OPTION_TOOLTIP_AUTO_SELF_CAST_ALT_KEY = "Use the \"ALT\" key to cast friendly target spells on yourself even if an enemy is targeted, or there is no target.";
+OPTION_TOOLTIP_AUTO_SELF_CAST_CTRL_KEY = "Use the \"CTRL\" key to cast friendly target spells on yourself even if an enemy is targeted, or there is no target.";
+OPTION_TOOLTIP_AUTO_SELF_CAST_KEY_TEXT = "When held this key will allow self casting, even if an enemy is targeted.";
+OPTION_TOOLTIP_AUTO_SELF_CAST_NONE_KEY = "No key set.";
+OPTION_TOOLTIP_AUTO_SELF_CAST_SHIFT_KEY = "Use the \"SHIFT\" key to cast friendly target spells on yourself even if an enemy is targeted, or there is no target.";
+OPTION_TOOLTIP_BLOCK_TRADES = "Block all incoming trade requests.";
+OPTION_TOOLTIP_CAMERA1 = "Set the camera to stay where placed, except when your character is moving. (only adjusts horizontal position)";
+OPTION_TOOLTIP_CAMERA2 = "Set the camera to always prefer being behind your character.";
+OPTION_TOOLTIP_CAMERA3 = "Set the camera to stay where set, and never auto adjust.";
+OPTION_TOOLTIP_CAMERA4 = "Set the camera to stay where placed, except when your character is moving.";
+OPTION_TOOLTIP_CAMERA_ALWAYS = "Set the camera to always prefer being behind your character.";
+OPTION_TOOLTIP_CAMERA_NEVER = "Set the camera to stay where set, and never auto adjust.";
+OPTION_TOOLTIP_CAMERA_SMART = "Set the camera to stay where placed, except when your character is moving. (only adjusts horizontal position)";
+OPTION_TOOLTIP_CAMERA_SMARTER = "Set the camera to stay where placed, except when your character is moving.";
+OPTION_TOOLTIP_CHARACTER_SHADOWS = "Enables character shadows for all characters within the game. Disabling this can sometimes improve performance.";
+OPTION_TOOLTIP_CHAT_BUBBLES = "Shows /say and /yell text in speech bubbles above characters' heads.";
+OPTION_TOOLTIP_CHAT_LOCKED = "Locks all chat windows so they cannot accidentally be altered.";
+OPTION_TOOLTIP_CHAT_MOUSE_WHEEL_SCROLL = "Check to make the mouse wheel scroll through chat when the cursor is over a chat window.";
+OPTION_TOOLTIP_CHAT_WHOLE_WINDOW_CLICKABLE = "Clicking anywhere in a Chat Frame will cause it to receive focus.";
+OPTION_TOOLTIP_CINEMATIC_SUBTITLES = "Enables subtitles during the intro cinematic.";
+OPTION_TOOLTIP_CLEAR_AFK = "Automatically exit Away mode\nupon moving or talking.";
+OPTION_TOOLTIP_CLICKCAMERA_LOCKED = "Sets the camera to always be aligned with your character when changing direction with click-to-move.";
+OPTION_TOOLTIP_CLICKCAMERA_NEVER = "Sets the camera to not move when changing direction with click-to-move.";
+OPTION_TOOLTIP_CLICKCAMERA_SMART = "Sets the camera to follow your character after a brief delay when changing direction with click-to-move. (Recommended Mode) ";
+OPTION_TOOLTIP_CLICK_CAMERA1 = "Sets the camera to follow your character after a brief delay when changing direction with click-to-move. (Recommended Mode)";
+OPTION_TOOLTIP_CLICK_CAMERA2 = "Sets the camera to always be aligned with your character when changing direction with click-to-move.";
+OPTION_TOOLTIP_CLICK_CAMERA3 = "Sets the camera to not move when changing direction with click-to-move.";
+OPTION_TOOLTIP_CLICK_CAMERA_STYLE = "Determines the way the camera follows the player while in Click-to-Move mode.";
+OPTION_TOOLTIP_CLICK_TO_MOVE = "Use mouse clicks to move your character to destinations.";
+OPTION_TOOLTIP_COMBAT_TEXT_MODE = "Sets the direction that combat text scrolls.";
+OPTION_TOOLTIP_COMBAT_TEXT_SCROLL_DOWN = "Scroll combat text down instead of up.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_AURAS = "Shows a message when the player gains or loses an aura.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_AURA_FADE = "Shows a message when an aura fades from the player.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_COMBAT_STATE = "Shows a message when you enter or leave combat. ";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_COMBO_POINTS = "Shows the number of combo points you have each time you acquire a new one.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_DODGE_PARRY_MISS = "Shows attacks against you that dodge, parry, or miss.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_ENERGIZE = "Shows all instant gains of mana, rage, and energy.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_FRIENDLY_NAMES = "Shows the name of a friendly caster when they cast a heal spell on you.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_HONOR_GAINED = "Shows the honor you gain from killing other players.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_LOW_HEALTH_MANA = "Shows a message when you fall below 20% mana or health.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_PERIODIC_ENERGIZE = "Shows all periodic gains of mana, rage, and energy.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_REACTIVES = "Shows when reactive class specific abilities and spells become available (e.g. Overpower for warriors).";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_REPUTATION = "Shows a message when the player gains or loses reputation with a faction.";
+OPTION_TOOLTIP_COMBAT_TEXT_SHOW_RESISTANCES = "Shows when you resist taking damage from attacks or spells.";
+OPTION_TOOLTIP_CONSOLIDATE_BUFFS = "Filters certain buffs into a buff consolidation box. Short term buffs are displayed in the box. Very long term buffs are displayed in the box until they are about to expire.";
+OPTION_TOOLTIP_DEATH_EFFECT = "Uncheck to disable glowing effect while in ghost form. Disabling this can sometimes improve performance.";
+OPTION_TOOLTIP_DESKTOP_GAMMA = "Use the same gamma settings as your desktop.";
+OPTION_TOOLTIP_DISABLE_SPAM_FILTER = "Disables spam filtering on chat text.";
+OPTION_TOOLTIP_DISPLAY_FREE_BAG_SLOTS = "Displays remaining inventory space on the backpack icon.";
+OPTION_TOOLTIP_ENABLE_ALL_SHADERS = "Enables all pixel shaders.";
+OPTION_TOOLTIP_ENABLE_AMBIENCE = "Enable ambient sounds.";
+OPTION_TOOLTIP_ENABLE_BGSOUND = "Enable to allow sounds to play even when World of Warcraft is in the background.";
+OPTION_TOOLTIP_ENABLE_DSP_EFFECTS = "Special voice modulation effects for Death Knights. Disable to improve performance.";
+OPTION_TOOLTIP_ENABLE_EMOTE_SOUNDS = "Toggles emote sounds on and off.";
+OPTION_TOOLTIP_ENABLE_ERROR_SPEECH = "Enables speech from errors (e.g. \"Target out of range\").";
+OPTION_TOOLTIP_ENABLE_GROUP_SPEECH = "Enables speech from groupmates.";
+OPTION_TOOLTIP_ENABLE_HARDWARE = "Enables the use of hardware for 3D sound management. This may alter your sound performance.";
+OPTION_TOOLTIP_ENABLE_MICROPHONE = "Enables your microphone.";
+OPTION_TOOLTIP_ENABLE_MUSIC = "Enable background music.";
+OPTION_TOOLTIP_ENABLE_MUSIC_LOOPING = "Enable to continuously play background music.";
+OPTION_TOOLTIP_ENABLE_PET_SOUNDS = "Toggles pet idle and aggro sounds on and off.";
+OPTION_TOOLTIP_ENABLE_REVERB = "Enables reverb sound effects. This will affect performance.";
+OPTION_TOOLTIP_ENABLE_SOFTWARE_HRTF = "Enables software emulation for headphone surround sound.";
+OPTION_TOOLTIP_ENABLE_SOUND = "Enables or disables all sound.";
+OPTION_TOOLTIP_ENABLE_SOUNDFX = "Enables or disables game sound effects.";
+OPTION_TOOLTIP_ENABLE_SOUND_AT_CHARACTER = "Listen to sound from the character's point of view rather than the camera.";
+OPTION_TOOLTIP_ENABLE_STEREO_VIDEO = "Enables stereoscopic (3D) video.";
+OPTION_TOOLTIP_ENABLE_VOICECHAT = "Voice Chat is not monitored by Blizzard Entertainment, and your gameplay experience may change based on interaction with other players.";
+OPTION_TOOLTIP_ENVIRONMENT_DETAIL = "Controls how far you can see objects. Decrease to improve performance.";
+OPTION_TOOLTIP_FARCLIP = "Changes how far you can see. Decreasing this may greatly improve performance.";
+OPTION_TOOLTIP_FIX_LAG = "Enabling this reduces user interface lag, but may drastically reduce frame rates.";
+OPTION_TOOLTIP_FOCUS_CAST_ALT_KEY = "Use the \"ALT\" key to cast targeted spells on your Focus Target.";
+OPTION_TOOLTIP_FOCUS_CAST_CTRL_KEY = "Use the \"CTRL\" key to cast targeted spells on your Focus Target.";
+OPTION_TOOLTIP_FOCUS_CAST_NONE_KEY = "No key set.";
+OPTION_TOOLTIP_FOCUS_CAST_SHIFT_KEY = "Use the \"SHIFT\" key to cast targeted spells on your Focus Target.";
+OPTION_TOOLTIP_FOLLOW_TERRAIN = "Automatically change the camera angle based on the terrain. If your character climbs a slope, the camera will rotate upwards; if you descend, it will rotate downwards.";
+OPTION_TOOLTIP_FULL_SCREEN_GLOW = "Enables a full screen effect that softens edges and lighting. Disabling this can sometimes improve performance.";
+OPTION_TOOLTIP_FULL_SIZE_FOCUS_FRAME = "Increases the size of the Focus Frame to that of the Target Frame.";
+OPTION_TOOLTIP_GAMEFIELD_DESELECT = "Checking this will prevent the deselection of targets by clicking on the gamefield. Targets can only be cleared by pressing escape or clicking another target.";
+OPTION_TOOLTIP_GAMMA = "Controls the brightness of the game. Increase brightness until you can clearly see all 21 levels of gray bars below.";
+OPTION_TOOLTIP_GROUND_DENSITY = "Controls the number of ground clutter items, like grass and foliage. Decrease to improve performance.";
+OPTION_TOOLTIP_GROUND_RADIUS = "Controls the draw distance of ground clutter items like grass and foliage. Decrease to improve performance.";
+OPTION_TOOLTIP_GUILDMEMBER_ALERT = "Show a message when your guild members login and logout.";
+OPTION_TOOLTIP_HARDWARE_CURSOR = "Enable this option for a more responsive cursor unless you have cursor problems.";
+OPTION_TOOLTIP_HEAD_BOB = "Simulate head bobbing when in first-person perspective.";
+OPTION_TOOLTIP_HIDE_OUTDOOR_WORLD_STATE = "Checking this will hide the interface for tracking zone wide objectives.";
+OPTION_TOOLTIP_HIDE_PARTY_INTERFACE = "Click this to hide your party's portraits and health bars.";
+OPTION_TOOLTIP_INVERT_MOUSE = "Invert the way that the mouse affects camera pitch.";
+OPTION_TOOLTIP_LOCALE = "Select which language you would like to play in.";
+OPTION_TOOLTIP_LOCK_ACTIONBAR = "Prevents the user from picking up/dragging spells on the action bar. This function can be bound to a function key in the keybindings interface.";
+OPTION_TOOLTIP_LOG_PERIODIC_EFFECTS = "Display damage caused by periodic effects such as Rend and Shadow Word: Pain.";
+OPTION_TOOLTIP_LONG_RANGE_NAMEPLATE = "Turning this option on will increase the range at which name plates appear.";
+OPTION_TOOLTIP_LOOT_KEY_TEXT = "Key to use to single loot a corpse";
+OPTION_TOOLTIP_LOOT_UNDER_MOUSE = "When checked the loot window will open up under the current mouse location.";
+OPTION_TOOLTIP_MAP_QUEST_DIFFICULTY = "Color quest titles by difficulty when displayed with the World Map.";
+OPTION_TOOLTIP_MAP_TRACK_QUEST = "Add or remove the selected quest from your quest watch list.|nYou can also shift-click on a quest or its icon.";
+OPTION_TOOLTIP_MASTER_VOLUME = "Adjusts the master sound volume.";
+OPTION_TOOLTIP_MAX_FOLLOW_DIST = "Adjust the maximum distance the camera will follow behind you.";
+OPTION_TOOLTIP_MOUSE_LOOK_SPEED = "Adjust the speed at which you turn the camera when using mouse look.";
+OPTION_TOOLTIP_MOUSE_SENSITIVITY = "Adjust the speed at which the mouse cursor moves.";
+OPTION_TOOLTIP_MULTISAMPLING = "Increase multisampling to smooth out model edges. Increasing multisampling can severely reduce performance.";
+OPTION_TOOLTIP_MUSIC_VOLUME = "Adjusts the background music volume.";
+OPTION_TOOLTIP_OBJECTIVES_IGNORE_CURSOR = "Locks the Objectives frame and keeps it from being displayed on mouseover.";
+OPTION_TOOLTIP_OBJECT_ALPHA = "PLACE_HOLDER";
+OPTION_TOOLTIP_PARTICLE_DENSITY = "Controls the number of particles used in effects caused by spells, fires, etc. Decrease to improve performance.";
+OPTION_TOOLTIP_PARTY_CHAT_BUBBLES = "Shows party chat text in speech bubbles above party members' heads.";
+OPTION_TOOLTIP_PET_NAMEPLATES = "Toggles displaying of name plates on your pets, totems, and guardians.";
+OPTION_TOOLTIP_PET_SPELL_DAMAGE = "Show spell damage caused by your pet.";
+OPTION_TOOLTIP_PHONG_SHADING = "Enable this option for smooth lighting across characters.";
+OPTION_TOOLTIP_PLAYER_DETAIL = "Controls the resolution of player textures. Decreasing this may slightly improve performance.";
+OPTION_TOOLTIP_PLAY_AGGRO_SOUNDS = "Enable the playing of alert sounds when aggro advances to a higher level.";
+OPTION_TOOLTIP_PROFANITY_FILTER = "Enable mature language filtering.";
+OPTION_TOOLTIP_PROFANITY_FILTER_WITH_WARNING = "Enable mature language filtering.\n\n|cffff0000Warning:|r Battle.net is unavailable, so this setting may not be saved.";
+OPTION_TOOLTIP_PROJECTED_TEXTURES = "Enables the projecting of textures to the environment. Disabling this may greatly improve performance.";
+OPTION_TOOLTIP_PUSHTOTALK_SOUND = "Plays a small sound whenever you press your Push-to-Talk key.";
+OPTION_TOOLTIP_REMOVE_CHAT_DELAY = "Check to show chat windows immediately upon mouseover.";
+OPTION_TOOLTIP_ROTATE_MINIMAP = "Check this to rotate the entire minimap instead of the player arrow.";
+OPTION_TOOLTIP_SCROLL_ARC = "Scrolls the text in arcs away from the player.";
+OPTION_TOOLTIP_SCROLL_DOWN = "Scrolls combat text towards the bottom of the screen.";
+OPTION_TOOLTIP_SCROLL_UP = "Scrolls combat text towards the top of the screen.";
+OPTION_TOOLTIP_SECURE_ABILITY_TOGGLE = "When selected you will be protected from toggling your abilities off if accidently hitting the button more than once in a short period of time.";
+OPTION_TOOLTIP_SHADOW_QUALITY = "Controls the quality of rendered character and environment shadows. Decrease to improve performance.";
+OPTION_TOOLTIP_SHOW_ARENA_ENEMY_CASTBAR = "Show the spells that players on the enemy arena team are casting.";
+OPTION_TOOLTIP_SHOW_ARENA_ENEMY_FRAMES = "Show enemy unit frames in arenas.";
+OPTION_TOOLTIP_SHOW_ARENA_ENEMY_PETS = "Show the portraits of the pets belonging to the enemy arena team.";
+OPTION_TOOLTIP_SHOW_BATTLENET_TOASTS = "Enable this to have Battle.net system messages appear in a popup window.";
+OPTION_TOOLTIP_SHOW_BUFF_DURATION = "Toggle text counters for buff durations on and off.";
+OPTION_TOOLTIP_SHOW_CASTABLE_BUFFS = "Show only buffs you can cast on friendly targets. Only applies to raids.";
+OPTION_TOOLTIP_SHOW_CASTABLE_DEBUFFS = "Show only the debuffs you applied on enemy targets.";
+OPTION_TOOLTIP_SHOW_CHAT_ICONS = "Controls whether or not icon links in auto-joined chat channels (such as Trade) are displayed as icons.";
+OPTION_TOOLTIP_SHOW_CLASS_COLOR_IN_V_KEY = "Toggles class colors in the background of Nameplate health bar for enemy players.";
+OPTION_TOOLTIP_SHOW_CLOAK = "Uncheck this box to hide your character's cloak.";
+OPTION_TOOLTIP_SHOW_CLOCK = "Displays the clock button on the minimap.";
+OPTION_TOOLTIP_SHOW_COMBAT_HEALING = "Display amount of healing you did to the target.";
+OPTION_TOOLTIP_SHOW_COMBAT_TEXT = "Checking this will enable additional combat messages to appear in the playfield.";
+OPTION_TOOLTIP_SHOW_DAMAGE = "Display damage numbers over hostile creatures when damaged.";
+OPTION_TOOLTIP_SHOW_DISPELLABLE_DEBUFFS = "Show only debuffs you can dispel on friendly targets. Only applies to raids.";
+OPTION_TOOLTIP_SHOW_FULLSCREEN_STATUS = "Shows a screen edge flash when you have a fullscreen UI up and you are in combat.";
+OPTION_TOOLTIP_SHOW_GUILD_NAMES = "Always display player guild names in the game world.";
+OPTION_TOOLTIP_SHOW_HELM = "Uncheck this box to hide your character's helm.";
+OPTION_TOOLTIP_SHOW_ITEM_LEVEL = "Display item level in the tooltip for certain items.";
+OPTION_TOOLTIP_SHOW_LOOT_SPAM = "Uncheck this to hide individual loot roll messages and only show the winner.";
+OPTION_TOOLTIP_SHOW_LUA_ERRORS = "Shows error messages related to UI functionality.";
+OPTION_TOOLTIP_SHOW_MULTIBAR1 = "Toggles an optional actionbar in the bottom left area of the screen.";
+OPTION_TOOLTIP_SHOW_MULTIBAR2 = "Toggles an optional actionbar in the bottom right area of the screen.";
+OPTION_TOOLTIP_SHOW_MULTIBAR3 = "Toggles an optional actionbar on the right side of the screen.";
+OPTION_TOOLTIP_SHOW_MULTIBAR4 = "Toggles an additional optional actionbar on the right side of the screen.";
+OPTION_TOOLTIP_SHOW_NEWBIE_TIPS = "Show detailed information about various user interface elements. Advanced players may want to turn this off.";
+OPTION_TOOLTIP_SHOW_NPC_NAMES = "Always display NPC names in the game world.";
+OPTION_TOOLTIP_SHOW_NUMERIC_THREAT = "Check this to show threat on targets as a percentage.";
+OPTION_TOOLTIP_SHOW_OTHER_TARGET_EFFECTS = "Display effects such as Silence and Snare on other players' targets.";
+OPTION_TOOLTIP_SHOW_OWN_NAME = "Shows your character's name.";
+OPTION_TOOLTIP_SHOW_PARTY_BACKGROUND = "Show a background behind party members and enemy arena team members.";
+OPTION_TOOLTIP_SHOW_PARTY_PETS = "Show the portraits of your party members' pets.";
+OPTION_TOOLTIP_SHOW_PARTY_TEXT = "Always display the text on health, mana, rage, or energy status bars on party members.";
+OPTION_TOOLTIP_SHOW_PET_MELEE_DAMAGE = "Show damage caused by your pet.";
+OPTION_TOOLTIP_SHOW_PLAYER_NAMES = "Always display player names in the game world.";
+OPTION_TOOLTIP_SHOW_PLAYER_TITLES = "Always display player titles in the game world.";
+OPTION_TOOLTIP_SHOW_QUEST_FADING = "Check this to make quest text appear instantly.";
+OPTION_TOOLTIP_SHOW_QUEST_OBJECTIVES_ON_MAP = "If enabled, you will be able to look at your map to see the locations of certain quest objectives.";
+OPTION_TOOLTIP_SHOW_RAID_RANGE = "Show the range of raid members when they are far away by fading out their health bars.";
+OPTION_TOOLTIP_SHOW_TARGET_CASTBAR = "Show the spell that your current target is casting.";
+OPTION_TOOLTIP_SHOW_TARGET_CASTBAR_IN_V_KEY = "If the Name Plate is displayed for your current target, show the enemy cast bar with the target's health bar in the game field.";
+OPTION_TOOLTIP_SHOW_TARGET_EFFECTS = "Display effects such as Silence and Snare on your target.";
+OPTION_TOOLTIP_SHOW_TARGET_OF_TARGET = "Toggles the display of the target of your target.";
+OPTION_TOOLTIP_SHOW_TIPOFTHEDAY = "Uncheck this to hide the tip of the day in the load screens.";
+OPTION_TOOLTIP_SHOW_TOAST_BROADCAST = "Displays a Battle.net message when a Real ID friend updates their broadcast.";
+OPTION_TOOLTIP_SHOW_TOAST_CONVERSATION = "Displays a Battle.net message when you join a conversation with Real ID friends.";
+OPTION_TOOLTIP_SHOW_TOAST_FRIEND_REQUEST = "Displays a Battle.net message when you receive Real ID friend requests.";
+OPTION_TOOLTIP_SHOW_TOAST_OFFLINE = "Displays a Battle.net message when a Real ID friend goes offline.";
+OPTION_TOOLTIP_SHOW_TOAST_ONLINE = "Displays a Battle.net message when a Real ID friend comes online.";
+OPTION_TOOLTIP_SHOW_TOAST_WINDOW = "Enabling this option will also display Battle.net messages in a toast window.";
+OPTION_TOOLTIP_SHOW_TUTORIALS = "Display tutorials which help introduce you to WoW.";
+OPTION_TOOLTIP_SHOW_UNIT_NAMES = "Display unit names in the game world.";
+OPTION_TOOLTIP_SIMPLE_CHAT = "Sets up a main chat window and a combat log that cannot be reconfigured.";
+OPTION_TOOLTIP_SIMPLE_QUEST_WATCH_TEXT = "Automatically manages the size and position of the Objectives tracking frame.";
+OPTION_TOOLTIP_SMART_PIVOT = "Lets you free look when the camera is on the ground.";
+OPTION_TOOLTIP_SOUND_CHANNELS = "Changes the number of active software sound channels.";
+OPTION_TOOLTIP_SOUND_OUTPUT = "Selects where you would like to hear your game sounds.";
+OPTION_TOOLTIP_SOUND_QUALITY = "Adjusts the quality of game sounds.\nDecrease to improve performance.";
+OPTION_TOOLTIP_SOUND_VOLUME = "Adjusts the sound effect volume.";
+OPTION_TOOLTIP_SPELL_DETAIL = "Controls the detail level of spell effects. Decrease to improve performance.";
+OPTION_TOOLTIP_STATUS_BAR = "Always display the text on your XP, health, mana, rage, energy, or happiness status bars.";
+OPTION_TOOLTIP_STATUS_TEXT_PARTY = "Always display the text on your party's health, mana, rage, or energy bars.";
+OPTION_TOOLTIP_STATUS_TEXT_PERCENT = "Always display status text using percentage values.";
+OPTION_TOOLTIP_STATUS_TEXT_PET = "Always display the text on your pet's health, mana, or focus bars.";
+OPTION_TOOLTIP_STATUS_TEXT_PLAYER = "Always display the text on your character's health, mana, rage, or energy bars.";
+OPTION_TOOLTIP_STATUS_TEXT_TARGET = "Always display the text on your target's health, mana, rage, energy, or focus bars.";
+OPTION_TOOLTIP_STEREO_HARDWARE_CURSOR = "While enabling this option may improve performance, the 3D cursor functionality will not work with it enabled.";
+OPTION_TOOLTIP_STOP_AUTO_ATTACK = "Stop auto attacking when you switch targets.";
+OPTION_TOOLTIP_TARGETOFTARGET1 = "Sets Target of Target to display when you are in a raid.";
+OPTION_TOOLTIP_TARGETOFTARGET2 = "Sets Target of Target to display when you are in a party.";
+OPTION_TOOLTIP_TARGETOFTARGET3 = "Sets Target of Target to display when solo.";
+OPTION_TOOLTIP_TARGETOFTARGET4 = "Sets Target of Target to display when you are in a raid or a party.";
+OPTION_TOOLTIP_TARGETOFTARGET5 = "Sets Target of Target to always display.";
+OPTION_TOOLTIP_TARGETOFTARGET_ALWAYS = "Sets Target of Target to always display.";
+OPTION_TOOLTIP_TARGETOFTARGET_PARTY = "Sets Target of Target to display when you are in a party.";
+OPTION_TOOLTIP_TARGETOFTARGET_RAID = "Sets Target of Target to display when you are in a raid.";
+OPTION_TOOLTIP_TARGETOFTARGET_RAID_AND_PARTY = "Sets Target of Target to display when you are in a raid or a party.";
+OPTION_TOOLTIP_TARGETOFTARGET_SOLO = "Sets Target of Target to display when solo.";
+OPTION_TOOLTIP_TERRAIN_HIGHLIGHTS = "Enables specular highlights on terrain. Disabling this can sometimes improve performance.";
+OPTION_TOOLTIP_TERRAIN_TEXTURE = "Sets the rate at which one type of terrain blends to another.";
+OPTION_TOOLTIP_TEXTURE_DETAIL = "Controls the level of all texture detail. Decreasing this may slightly improve performance.";
+OPTION_TOOLTIP_TIMESTAMPS = "Select the format of timestamps for chat messages.";
+OPTION_TOOLTIP_TOAST_DURATION = "Adjust the duration of the toast window.";
+OPTION_TOOLTIP_TRILINEAR = "Enables high quality filtering of texture maps. Turn this feature off to increase performance.";
+OPTION_TOOLTIP_TRIPLE_BUFFER = "Enables triple buffering of frames when vertical sync is enabled. Selecting triple buffering may even out frame rate spikes, but may also cause slight input lag.";
+OPTION_TOOLTIP_UI_SCALE = "Changes the size of the game’s user interface.";
+OPTION_TOOLTIP_UNIT_NAMEPLATES_ALLOW_OVERLAP = "Unit Nameplates can overlap if units are visually in a line. Turn this off to keep each Unit Nameplate seperate from each other.";
+OPTION_TOOLTIP_UNIT_NAMEPLATES_SHOW_ENEMIES = "Turn this on to display Unit Nameplates for enemies.";
+OPTION_TOOLTIP_UNIT_NAMEPLATES_SHOW_ENEMY_GUARDIANS = "Turn this on to display Unit Nameplates for enemy guardians";
+OPTION_TOOLTIP_UNIT_NAMEPLATES_SHOW_ENEMY_PETS = "Turn this on to display Unit Nameplates for enemy pets";
+OPTION_TOOLTIP_UNIT_NAMEPLATES_SHOW_ENEMY_TOTEMS = "Turn this on to display Unit Nameplates for enemy totems";
+OPTION_TOOLTIP_UNIT_NAMEPLATES_SHOW_FRIENDLY_GUARDIANS = "Turn this on to display Unit Nameplates for friendly guardians";
+OPTION_TOOLTIP_UNIT_NAMEPLATES_SHOW_FRIENDLY_PETS = "Turn this on to display Unit Nameplates for friendly pets.";
+OPTION_TOOLTIP_UNIT_NAMEPLATES_SHOW_FRIENDLY_TOTEMS = "Turn this on to display Unit Nameplates for friendly totems";
+OPTION_TOOLTIP_UNIT_NAMEPLATES_SHOW_FRIENDS = "Turn this on to display Unit Nameplates for friendly units";
+OPTION_TOOLTIP_UNIT_NAME_ENEMY = "Show enemy players' names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_ENEMY_GUARDIANS = "Show enemy guardian names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_ENEMY_PETS = "Show enemy pet names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_ENEMY_TOTEMS = "Show enemy totem names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_FRIENDLY = "Show friendly players' names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_FRIENDLY_GUARDIANS = "Show friendly guardian names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_FRIENDLY_PETS = "Show friendly pet names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_FRIENDLY_TOTEMS = "Show friendly totem names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_GUILD = "Show players' guild names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_NONCOMBAT_CREATURE = "Show critter and vanity pet names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_NPC = "Show NPC names in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_OWN = "Display your character's name in the game world.";
+OPTION_TOOLTIP_UNIT_NAME_PLAYER_TITLE = "Show player titles in the game world.";
+OPTION_TOOLTIP_USE_COLORBLIND_MODE = "Displays unit reactions and item qualities in tooltips and adds additional information to several other interfaces.";
+OPTION_TOOLTIP_USE_ENGLISH_AUDIO = "Check this box to override your language setting and use english audio.";
+OPTION_TOOLTIP_USE_REFRESH = "Changes the monitor refresh rates. Higher rates flicker less.";
+OPTION_TOOLTIP_USE_RESOLUTION = "Changes the screen resolution of the game. Decrease to improve performance.";
+OPTION_TOOLTIP_USE_UBERTOOLTIPS = "Enable detailed tooltips in the lower right hand corner of the screen.";
+OPTION_TOOLTIP_USE_UISCALE = "Check to use the UI Scale Slider, uncheck to use the system default scale.";
+OPTION_TOOLTIP_USE_WEATHER_SHADER = "Uncheck this if weather effects are causing your computer to crash.";
+OPTION_TOOLTIP_VERTEX_ANIMATION_SHADERS = "Enables the use of vertex shaders to speed animation. Enable this to maximize performance.";
+OPTION_TOOLTIP_VERTICAL_SYNC = "Synchronizes your framerate to some fraction of your monitor's refresh rate. Enable this if you see excessive screen tearing in game.";
+OPTION_TOOLTIP_VOICE_ACTIVATION_SENSITIVITY = "Adjusts the sensitivity of the microphone.";
+OPTION_TOOLTIP_VOICE_AMBIENCE = "Adjusts the ambient sound volume during voice chat.";
+OPTION_TOOLTIP_VOICE_INPUT = "Selects your microphone or the controller it is connected to.";
+OPTION_TOOLTIP_VOICE_INPUT_VOLUME = "Adjusts the volume of your voice.";
+OPTION_TOOLTIP_VOICE_MUSIC = "Adjusts the game music volume during voice chat.";
+OPTION_TOOLTIP_VOICE_OUTPUT = "Selects where you would like to hear incoming voice chat.";
+OPTION_TOOLTIP_VOICE_OUTPUT_VOLUME = "Adjusts the volume of others' voices.";
+OPTION_TOOLTIP_VOICE_SOUND = "Adjusts the game sound volume during voice chat.";
+OPTION_TOOLTIP_VOICE_TYPE1 = "Requires the pressing of a key before speaking in voice chat.";
+OPTION_TOOLTIP_VOICE_TYPE2 = "Allows for the transmission of voice chat by just speaking.";
+OPTION_TOOLTIP_WATCH_FRAME_WIDTH = "Increases the width of the Objectives tracker.";
+OPTION_TOOLTIP_WATER_COLLISION = "Set the camera to be above water when your character is above water, and below water when your character is below water.";
+OPTION_TOOLTIP_WEATHER_DETAIL = "Controls the intensity of weather effects. Decrease to improve performance.";
+OPTION_TOOLTIP_WINDOWED_MAXIMIZED = "Check to maximize window and remove borders.";
+OPTION_TOOLTIP_WINDOWED_MODE = "Check to play in a non-fullscreen window.\n\nIf this is checked the game will use your desktop gamma and you will not be able to adjust it via the slider below.";
+OPTION_TOOLTIP_WINDOW_LOCK = "Enable this to prevent resizing the game window.";
+OPTION_TOOLTIP_WORLD_LOD = "Check this to enable dynamic reduction of terrain polygon detail. Check to increase performance.";
+OPTION_TOOLTIP_WORLD_PVP_DISPLAY1 = "This will show the World PVP objectives when you are in PVP zones.";
+OPTION_TOOLTIP_WORLD_PVP_DISPLAY2 = "This will show the World PVP objectives when you are near PVP points of interest.";
+OPTION_TOOLTIP_WORLD_PVP_DISPLAY3 = "This will turn off the World PVP objectives.";
+OPTION_TOOLTIP_WORLD_PVP_DISPLAY_ALWAYS = "This will show the World PVP objectives when you are in PVP zones.";
+OPTION_TOOLTIP_WORLD_PVP_DISPLAY_DYNAMIC = "This will show the World PVP objectives when you are near PVP points of interest.";
+OPTION_TOOLTIP_WORLD_PVP_DISPLAY_NEVER = "This will turn off the World PVP objectives.";
+OPTION_TOOLTIP_WOW_MOUSE = "Enable this option if you have a World of Warcraft Gaming Mouse and you wish to bind keys to the extra buttons.";
+OPTION_TOOLTIP_XP_BAR = "Always display the text on your XP bar.";
+OPTION_UI_DEPTH = "Changes the base depth of the UI.";
+OPTION_USE_EQUIPMENT_MANAGER_DESCRIPTION = "This allows you to save sets of equipment. You will then be able to equip a set by clicking on the icon. Once enabled, the Equipment Manager can be accessed through the character frame.";
+OPT_OUT_LOOT_TITLE = "Pass on Loot: %s";
+OPT_OUT_LOOT_TOGGLE_OFF = "You are now eligible for random loot.";
+OPT_OUT_LOOT_TOGGLE_ON = "You are now passing on random loot.";
+OR_CAPS = "OR";
+OTHER = "Other";
+OTHER_MESSAGES = "Other Messages";
+OUTBID = "Outbid";
+OUTBID_BY = "Outbid by";
+OUT_OF_ENERGY = "Not enough energy";
+OUT_OF_FOCUS = "Not enough focus";
+OUT_OF_HEALTH = "Not enough health";
+OUT_OF_MANA = "Not enough mana";
+OUT_OF_POWER_DISPLAY = "Not enough %s";
+OUT_OF_RAGE = "Not enough rage";
+PAGE_NUMBER = "Page %d";
+PALADIN_INTELLECT_TOOLTIP = "Increases mana points and chance to score a critical hit with spells.\nIncreases the rate at which weapon skills improve.";
+PALADIN_STRENGTH_TOOLTIP = "Increases attack power with melee weapons.\nIncreases the amount of damage that can be blocked with a shield.";
+PAPERDOLLFRAME_TOOLTIP_FORMAT = "%s";
+PAPERDOLL_SELECT_TITLE = "Select a Title";
+PARENS_TEMPLATE = "(%s)";
+PARRIED = "Parried";
+PARRY = "Parry";
+PARRY_CHANCE = "Parry Chance";
+PARTICLE_DENSITY = "Particle Density";
+PARTY = "Party";
+PARTYRAID_LABEL = "Party & Raid";
+PARTYRAID_SUBTEXT = "These options can be used to change the display and behavior of party and raid frames within the UI.";
+PARTY_CHAT_BUBBLES_TEXT = "Party Chat Bubbles";
+PARTY_INVITE = "Invite";
+PARTY_LEADER = "Party Leader";
+PARTY_LEAVE = "Leave party";
+PARTY_MESSAGE = "Party Chat";
+PARTY_OPTIONS_LABEL = "Party Options";
+PARTY_PROMOTE = "Promote to Leader";
+PARTY_PROMOTE_GUIDE = "Promote to Guide";
+PARTY_QUEST_STATUS_NONE = "There are no nearby party members on this quest.";
+PARTY_QUEST_STATUS_ON = "Nearby party members that are on this quest:";
+PARTY_SILENCE = "Silence in Party";
+PARTY_UNINVITE = "Uninvite";
+PARTY_UNSILENCE = "Unsilence in Party";
+PASS = "Pass";
+PASSIVE_PARENS = "(Passive)";
+PASSWORD = "Password";
+PENDING_INVITE = "Pending";
+PENDING_INVITE_LIST = "Pending List";
+PERCENT_SYMBOL = "%%";
+PERIODIC = "Periodic";
+PERIODIC_MESSAGES = "Periodic Effects";
+PET = "Pet";
+PETITION_CREATOR = "Created by %s";
+PETITION_NUM_SIGNATURES = "%d |4signature:signatures;";
+PETITION_TITLE = "Petition: %s";
+PETS = "Pets";
+PETTAME_ANOTHERSUMMONACTIVE = "You have an active summon already";
+PETTAME_CANTCONTROLEXOTIC = "You are unable to control exotic creatures";
+PETTAME_CREATUREALREADYOWNED = "Creature is already controlled";
+PETTAME_DEAD = "Your pet is dead";
+PETTAME_INTERNALERROR = "Internal pet error";
+PETTAME_INVALIDCREATURE = "Creature not found";
+PETTAME_NOPETAVAILABLE = "You do not have a pet to summon";
+PETTAME_NOTDEAD = "Your pet is not dead";
+PETTAME_NOTTAMEABLE = "Creature not tameable";
+PETTAME_TOOHIGHLEVEL = "Creature is too high level for you to tame";
+PETTAME_TOOMANY = "You have too many pets already";
+PETTAME_UNITSCANTTAME = "You cannot tame creatures";
+PETTAME_UNKNOWNERROR = "Unknown taming error";
+PET_ABANDON = "Abandon";
+PET_ACTION_ATTACK = "Attack";
+PET_ACTION_DISMISS = "Dismiss";
+PET_ACTION_FOLLOW = "Follow";
+PET_ACTION_WAIT = "Stay";
+PET_AGGRESSIVE = "Aggressive";
+PET_ATTACK = "Attack";
+PET_BONUS_TOOLTIP_ARMOR = "Increases your pet's Armor by %d";
+PET_BONUS_TOOLTIP_INTELLECT = "Increases your pet's Intellect by %d";
+PET_BONUS_TOOLTIP_RANGED_ATTACK_POWER = "Increases your pet's Attack Power by %d";
+PET_BONUS_TOOLTIP_RESISTANCE = "Increases your pet's Resistance by %d";
+PET_BONUS_TOOLTIP_SPELLDAMAGE = "Increases your pet's Spell Damage by %d";
+PET_BONUS_TOOLTIP_STAMINA = "Increases your pet's Stamina by %d";
+PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_FIRE = "Your Fire Damage increases your pet's Attack Power by %d and Spell Damage by %d";
+PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_SHADOW = "Your Shadow Damage increases your pet's Attack Power by %d and Spell Damage by %d";
+PET_DAMAGE_PERCENTAGE = "Causes %d%% of normal damage";
+PET_DEFENSIVE = "Defensive";
+PET_DIET_TEMPLATE = "Diet: %s";
+PET_DISMISS = "Dismiss";
+PET_FOLLOW = "Follow";
+PET_HAPPINESS1 = "Unhappy";
+PET_HAPPINESS2 = "Content";
+PET_HAPPINESS3 = "Happy";
+PET_INFO = "Pet Info";
+PET_MODE_AGGRESSIVE = "Aggressive";
+PET_MODE_DEFENSIVE = "Defensive";
+PET_MODE_PASSIVE = "Passive";
+PET_PAPERDOLL = "Pet Details";
+PET_PASSIVE = "Passive";
+PET_RENAME = "Rename";
+PET_RENAME_CONFIRMATION = "Name your pet '%s'?";
+PET_RENAME_LABEL = "Enter desired name of pet:";
+PET_SPELLS_TEMPLATE = "Tamed Abilities: %s";
+PET_SPELL_NOPATH = "No path available for your pet";
+PET_TIME_LEFT_MINUTES = "%d min left";
+PET_TIME_LEFT_SECONDS = "%d sec left";
+PET_TYPE_DEMON = "Demon";
+PET_TYPE_PET = "Pet";
+PET_WAIT = "Stay";
+PHONG_SHADING = "Smooth Shading";
+PHYSICAL_HARASSMENT = "Physical Harassment";
+PHYSICAL_HARASSMENT_DESCRIPTION = "If the sole purpose or intent of any action is to continually upset, aggravate, or otherwise annoy another player, that action may be considered physical harassment or �grief play�. Before reporting physical harassment, make sure that the situation that is being petitioned falls outside the realm of the PvP policy (www.worldofwarcraft.com/policy/pvp.shtml). ";
+PHYSICAL_HARASSMENT_TEXT1 = "The following are NOT considered physical harassment:";
+PHYSICAL_HARASSMENT_TEXT2 = "Attacking a creep or NPC that another player has already engaged";
+PHYSICAL_HARASSMENT_TEXT3 = "Continually attacking and/or killing an NPC";
+PHYSICAL_HARASSMENT_TEXT4 = "\"Spawn camping\" (\"claiming\" a spawn point in order to repeatedly attack a creep)";
+PHYSICAL_HARASSMENT_TEXT5 = "\"Corpse camping\" (waiting by a player's corpse to attack them as they resurrect)";
+PHYSICAL_HARASSMENT_TEXT6 = "\"Training\" (leading enemies to another player to force combat)";
+PIXEL_SHADERS = "Special Effects";
+PLAYBACK = "Playback";
+PLAYED = "Played";
+PLAYER = "Player";
+PLAYERSTAT_BASE_STATS = "Base Stats";
+PLAYERSTAT_DEFENSES = "Defenses";
+PLAYERSTAT_MELEE_COMBAT = "Melee";
+PLAYERSTAT_RANGED_COMBAT = "Ranged";
+PLAYERSTAT_SPELL_COMBAT = "Spell";
+PLAYERS_IN_GROUP = "Members";
+PLAYER_COUNT_ALLIANCE = "%d Alliance |4Player:Players;";
+PLAYER_COUNT_HORDE = "%d Horde |4Player:Players;";
+PLAYER_DETAIL = "Player Textures";
+PLAYER_DIFFICULTY1 = "Normal";
+PLAYER_DIFFICULTY2 = "Heroic";
+PLAYER_IS_PVP_AFK = "|cffff64ff%s (Inactive)|r";
+PLAYER_LEVEL = "Level %s %s %s";
+PLAYER_LEVEL_UP = "Level Up";
+PLAYER_LIST_DELIMITER = ", ";
+PLAYER_LOGOUT_FAILED = "Logout Failed";
+PLAYER_LOGOUT_FAILED_ERROR = "You can't log out because you can't sit down right now.";
+PLAYER_MESSAGES = "Player Messages";
+PLAYER_NOT_FOUND = "Can't find that player.";
+PLAYER_OFFLINE = "Offline";
+PLAYER_OPTIONS_LABEL = "Player Options";
+PLAYER_SERVER_FIRST_ACHIEVEMENT = "|Hplayer:%s|h[%s]|h has earned the achievement $a!";
+PLAYER_STATUS = "Player Status";
+PLAYER_V_PLAYER = "Player vs. Player";
+PLAYTIME_TIRED = "You have more than 3 hours of online time. You will receive 1/2 money and XP during this period. Your rest state will reset in %d hours of offline time. Please go rest. ";
+PLAYTIME_TIRED_ABILITY = "You have more than 3 hours of online time. You cannot perform this action during this period. Your rest state will reset in %d hours of offline time. Please go rest. ";
+PLAYTIME_UNHEALTHY = "You have more than 5 hours of online time. You will not be able to gain loot, XP, or complete quests. Your rest state will reset in %d hours of offline time. Please log out to get rest and exercise.";
+PLAYTIME_UNHEALTHY_ABILITY = "You have more than 5 hours of online time. You cannot perform this action. Your rest state will reset in %d hours of offline time. Please log out to get rest and exercise.";
+PLAY_AGGRO_SOUNDS = "Play Aggro Sounds";
+PLUS_AMMO_DAMAGE_TEMPLATE = "+ %g damage per second";
+PLUS_AMMO_SCHOOL_DAMAGE_TEMPLATE = "+ %g %s damage per second";
+PLUS_DAMAGE_TEMPLATE = "+ %d - %d Damage";
+PLUS_DAMAGE_TEMPLATE_WITH_SCHOOL = "+%d - %d %s Damage";
+PLUS_SINGLE_DAMAGE_TEMPLATE = "+ %d Damage";
+PLUS_SINGLE_DAMAGE_TEMPLATE_WITH_SCHOOL = "+%d %s Damage";
+POP_IN_CHAT = "Pop In Chat";
+POP_OUT_CHAT = "Pop Out Chat";
+POTION_TIMER = "You cannot drink any more yet.";
+POWER_ABBR = "PWR";
+POWER_DISPLAY_COST = "%d %s";
+POWER_DISPLAY_COST_PER_TIME = "%d %s, plus %d per sec";
+POWER_GAINS = "Power Gains";
+POWER_GAINS_COMBATLOG_TOOLTIP = "Show messages when a spell or ability restores mana, energy, rage, focus, or happiness.";
+POWER_TYPE_BLOOD_POWER = "Blood Power";
+POWER_TYPE_HEAT = "Heat";
+POWER_TYPE_OOZE = "Ooze";
+POWER_TYPE_PYRITE = "Pyrite";
+POWER_TYPE_STEAM = "Steam Pressure";
+POWER_TYPE_WRATH = "Wrath";
+PREFERENCES = "Preferences";
+PRESS_TAB = "Press Tab";
+PREV = "Prev";
+PREVIEW_TALENT_CHANGES = "Preview Talent Changes";
+PREVIOUS = "Previous";
+PRIEST_INTELLECT_TOOLTIP = "Increases mana points and chance to score a critical hit with spells.\nIncreases the rate at which weapon skills improve.";
+PRIMARY = "Primary";
+PRIMARY_SKILLS = "Primary Skills:";
+PROC_EVENT0_DESC = "No Proc Trigger Assigned. Tell Kevin.";
+PROC_EVENT1024_DESC = "when hit by spell";
+PROC_EVENT128_DESC = "on swing";
+PROC_EVENT16_DESC = "on dodge";
+PROC_EVENT1_DESC = "on hit";
+PROC_EVENT2048_DESC = "when hit by %s spell";
+PROC_EVENT256_DESC = "on cast";
+PROC_EVENT2_DESC = "when attacked";
+PROC_EVENT32_DESC = "on parry";
+PROC_EVENT3_DESC = "on hit or when attacked";
+PROC_EVENT4_DESC = "on killing blow";
+PROC_EVENT512_DESC = "on %s cast";
+PROC_EVENT64_DESC = "on block";
+PROC_EVENT8_DESC = "every tick";
+PROFANITY_FILTER = "Mature Language Filter";
+PROFESSION_CONFIRMATION1 = "You may only know two professions at any one time. Would you like to learn |cffffd200%s|r as your first one?";
+PROFESSION_CONFIRMATION2 = "You may only know two professions at any one time. Would you like to learn |cffffd200%s|r as your second one?";
+PROFFESSION_CONFIRMATION2 = "You may only learn two professions at any one time. Would you like to learn %s as your second one?";
+PROFICIENCIES = "Proficiencies:";
+PROFICIENCIES_COLON = "Proficiencies:";
+PROFICIENCY_NEEDED = "You do not have the required proficiency for that item.";
+PROJECTED_TEXTURES = "Projected Textures";
+PTT_BOUND = "Key Bound";
+PUBLICNOTE_BUTTON_TOOLTIP = "Click to View Your Public Note";
+PUBLIC_NOTE = "Public Note";
+PURCHASE = "Purchase";
+PURCHASED_BY_COLON = "Purchased By:";
+PURCHASE_TAB_TEXT = "Do you wish to purchase this tab?";
+PUSHTOTALK_SOUND_TEXT = "Push-to-Talk Sound";
+PUSH_TO_TALK = "Push-to-Talk";
+PVP = "PvP";
+PVPBATTLEGROUND_WINTERGRASPTIMER = "Wintergrasp|n|cffffffff%s|r";
+PVPBATTLEGROUND_WINTERGRASPTIMER_CANNOT_QUEUE = "|cffffffffYou cannot queue for Wintergrasp|nat this time. You will be allowed to|nqueue shortly before the battle starts.|r";
+PVPBATTLEGROUND_WINTERGRASPTIMER_CAN_QUEUE = "|cffffffffYou are now eligible to queue for|nWintergrasp. Please visit a Wintergrasp|nBattlemaster in any major city.|r";
+PVPBATTLEGROUND_WINTERGRASPTIMER_TOOLTIP = "Next Wintergrasp Battle: |cffffffff%s|r";
+PVPFFA = "Free for All PVP";
+PVP_DISABLED = "PvP Disabled";
+PVP_ENABLED = "PvP";
+PVP_FLAG = "Player vs. Player";
+PVP_LABEL_ARENA = "ARENA:";
+PVP_LABEL_HONOR = "HONOR:";
+PVP_MEDAL1 = "Protector of Stormwind";
+PVP_MEDAL2 = "Overlord of Orgrimmar";
+PVP_MEDAL3 = "Thane of Ironforge";
+PVP_MEDAL4 = "High Sentinel of Darnassus";
+PVP_MEDAL5 = "Deathlord of the Undercity";
+PVP_MEDAL6 = "Chieftain of Thunderbluff";
+PVP_MEDAL7 = "Avenger of Gnomeregan";
+PVP_MEDAL8 = "Voodoo Boss of Sen�jin";
+PVP_MINIMAP = "Show PvP Minimap";
+PVP_OPTIONS = "Player vs. Player";
+PVP_POLICY_URL = "|cffffd200http://www.worldofwarcraft.com/policy/pvp.shtml|r";
+PVP_RANK_0_0 = "Scout";
+PVP_RANK_0_0_FEMALE = "Scout";
+PVP_RANK_0_1 = "Private";
+PVP_RANK_0_1_FEMALE = "Private";
+PVP_RANK_10_0 = "Stone Guard";
+PVP_RANK_10_0_FEMALE = "Stone Guard";
+PVP_RANK_10_1 = "Knight";
+PVP_RANK_10_1_FEMALE = "Knight";
+PVP_RANK_11_0 = "Blood Guard";
+PVP_RANK_11_0_FEMALE = "Blood Guard";
+PVP_RANK_11_1 = "Knight-Lieutenant";
+PVP_RANK_11_1_FEMALE = "Knight-Lieutenant";
+PVP_RANK_12_0 = "Legionnaire";
+PVP_RANK_12_0_FEMALE = "Legionnaire";
+PVP_RANK_12_1 = "Knight-Captain";
+PVP_RANK_12_1_FEMALE = "Knight-Captain";
+PVP_RANK_13_0 = "Centurion";
+PVP_RANK_13_0_FEMALE = "Centurion";
+PVP_RANK_13_1 = "Knight-Champion";
+PVP_RANK_13_1_FEMALE = "Knight-Champion";
+PVP_RANK_14_0 = "Champion";
+PVP_RANK_14_0_FEMALE = "Champion";
+PVP_RANK_14_1 = "Lieutenant Commander";
+PVP_RANK_14_1_FEMALE = "Lieutenant Commander";
+PVP_RANK_15_0 = "Lieutenant General";
+PVP_RANK_15_0_FEMALE = "Lieutenant General";
+PVP_RANK_15_1 = "Commander";
+PVP_RANK_15_1_FEMALE = "Commander";
+PVP_RANK_16_0 = "General";
+PVP_RANK_16_0_FEMALE = "General";
+PVP_RANK_16_1 = "Marshal";
+PVP_RANK_16_1_FEMALE = "Marshal";
+PVP_RANK_17_0 = "Warlord";
+PVP_RANK_17_0_FEMALE = "Warlord";
+PVP_RANK_17_1 = "Field Marshal";
+PVP_RANK_17_1_FEMALE = "Field Marshal";
+PVP_RANK_18_0 = "High Warlord";
+PVP_RANK_18_0_FEMALE = "High Warlord";
+PVP_RANK_18_1 = "Grand Marshal";
+PVP_RANK_18_1_FEMALE = "Grand Marshal";
+PVP_RANK_19_0 = "Leader";
+PVP_RANK_19_0_FEMALE = "Leader";
+PVP_RANK_19_1 = "Leader";
+PVP_RANK_19_1_FEMALE = "Leader";
+PVP_RANK_1_0 = "Pariah";
+PVP_RANK_1_0_FEMALE = "Pariah";
+PVP_RANK_1_1 = "Pariah";
+PVP_RANK_1_1_FEMALE = "Pariah";
+PVP_RANK_2_0 = "Outlaw";
+PVP_RANK_2_0_FEMALE = "Outlaw";
+PVP_RANK_2_1 = "Outlaw";
+PVP_RANK_2_1_FEMALE = "Outlaw";
+PVP_RANK_3_0 = "Exiled";
+PVP_RANK_3_0_FEMALE = "Exiled";
+PVP_RANK_3_1 = "Exiled";
+PVP_RANK_3_1_FEMALE = "Exiled";
+PVP_RANK_4_0 = "Dishonored";
+PVP_RANK_4_0_FEMALE = "Dishonored";
+PVP_RANK_4_1 = "Dishonored";
+PVP_RANK_4_1_FEMALE = "Dishonored";
+PVP_RANK_5_0 = "Scout";
+PVP_RANK_5_0_FEMALE = "Scout";
+PVP_RANK_5_1 = "Private";
+PVP_RANK_5_1_FEMALE = "Private";
+PVP_RANK_6_0 = "Grunt";
+PVP_RANK_6_0_FEMALE = "Grunt";
+PVP_RANK_6_1 = "Corporal";
+PVP_RANK_6_1_FEMALE = "Corporal";
+PVP_RANK_7_0 = "Sergeant";
+PVP_RANK_7_0_FEMALE = "Sergeant";
+PVP_RANK_7_1 = "Sergeant";
+PVP_RANK_7_1_FEMALE = "Sergeant";
+PVP_RANK_8_0 = "Senior Sergeant";
+PVP_RANK_8_0_FEMALE = "Senior Sergeant";
+PVP_RANK_8_1 = "Master Sergeant";
+PVP_RANK_8_1_FEMALE = "Master Sergeant";
+PVP_RANK_9_0 = "First Sergeant";
+PVP_RANK_9_0_FEMALE = "First Sergeant";
+PVP_RANK_9_1 = "Sergeant Major";
+PVP_RANK_9_1_FEMALE = "Sergeant Major";
+PVP_RANK_LEADER = "Leader";
+PVP_RATING = "Rating:";
+PVP_REPORT_AFK = "Report player Away";
+PVP_REPORT_AFK_ALL = "Report all of the above";
+PVP_REPORT_AFK_ALREADY_NOTIFIED = "Report Away player: You have already reported this player.";
+PVP_REPORT_AFK_GENERIC_FAILURE = "Report Away player failed.";
+PVP_REPORT_AFK_NOT_SAME_TEAM = "Report Away player failed: You are not on the same team.";
+PVP_REPORT_AFK_PLAYER_NOT_VALID = "Report Away player failed: Not a valid player.";
+PVP_REPORT_AFK_SUCCEEDED = "Report Away player succeeded.";
+PVP_REPORT_AFK_SYSTEM_DISABLED = "Notify system has been disabled.";
+PVP_REPORT_AFK_SYSTEM_ENABLED = "Notify system has been enabled.";
+PVP_REQUIRED_FOR_CAPTURE = "You must be flagged for PvP in order to help capture this objective.";
+PVP_TEAMSIZE = "(%dv%d)";
+PVP_TEAMTYPE = "%dv%d";
+PVP_TOGGLE_OFF_VERBOSE = "You will be unflagged for PvP combat after five minutes of non-PvP action in friendly territory.";
+PVP_TOGGLE_ON_VERBOSE = "You are now flagged for PvP combat and will remain so until toggled off.";
+PVP_YOUR_RATING = "Your Rating";
+PVP_ZONE_OBJECTIVES = "Show PvP Zone Objectives";
+QUALITY = "Quality";
+QUESTLOG_BUTTON = "Quest Log";
+QUESTLOG_NO_QUESTS_TEXT = "No Active Quests";
+QUESTS_COLON = "Quests:";
+QUESTS_LABEL = "Quests";
+QUESTS_SUBTEXT = "These options allow you to customize the behaviors of the game's quest interface.";
+QUEST_ACCEPT = "%s is starting %s\nWould you like to as well?";
+QUEST_ACCEPT_LOG_FULL = "%s is starting %s\nYour quest log is full. You can join this\nquest if you make room in your quest log.";
+QUEST_COMPLETE = "Quest completed";
+QUEST_DASH = "- ";
+QUEST_DESCRIPTION = "Description";
+QUEST_DETAILS = "Quest Details";
+QUEST_FACTION_NEEDED = "%s: %s / %s";
+QUEST_FACTION_NEEDED_NOPROGRESS = "%s: %s";
+QUEST_FAILED = "Quest completion failed.";
+QUEST_FAILED_TAG = "- Failed";
+QUEST_HARD = "(Hard)";
+QUEST_INTERMEDIATE_ITEMS_NEEDED = "%s: (%d)";
+QUEST_ITEMS_NEEDED = "%s: %d/%d";
+QUEST_ITEMS_NEEDED_NOPROGRESS = "%s x %d";
+QUEST_LOG = "Quest Log";
+QUEST_LOG_COUNT_TEMPLATE = "Quests: |cffffffff%d/%d|r";
+QUEST_LOG_DAILY_COUNT_TEMPLATE = "Daily: |cffffffff%d/%d|r";
+QUEST_LOG_DAILY_TOOLTIP = "You can only complete %d Daily quests each day.\nThe new day starts in %s.";
+QUEST_MONSTERS_KILLED = "%s slain: %d/%d";
+QUEST_MONSTERS_KILLED_NOPROGRESS = "%s x %d";
+QUEST_OBJECTIVES = "Quest Objectives";
+QUEST_OBJECTS_FOUND = "%s: %d/%d";
+QUEST_OBJECTS_FOUND_NOPROGRESS = "%s x %d";
+QUEST_PLAYERS_KILLED = "Players slain: %d/%d";
+QUEST_PLAYERS_KILLED_NOPROGRESS = "Players x %d";
+QUEST_REWARDS = "Rewards";
+QUEST_SUGGESTED_GROUP_NUM = "Suggested Players [%d]";
+QUEST_SUGGESTED_GROUP_NUM_TAG = "Group: %d";
+QUEST_TIMERS = "Quest Timers";
+QUEST_TOOLTIP_ACTIVE = "You are on this quest";
+QUEST_TOOLTIP_REQUIREMENTS = "Requirements:";
+QUEST_WATCH_NO_OBJECTIVES = "This quest has no objectives to track";
+QUEST_WATCH_TOOLTIP = "Shift-click a quest to add or remove a quest from your quest watch list.";
+QUEST_WATCH_TOO_MANY = "You may only watch %d quests at a time.";
+QUEUED_FOR = "Queued for %s";
+QUEUED_FOR_SHORT = "Queued for:";
+QUEUE_TIME_UNAVAILABLE = "Unavailable";
+QUICKBUTTON_NAME_DEFAULT = "Default";
+QUICKBUTTON_NAME_EVERYTHING = "Everything";
+QUICKBUTTON_NAME_EVERYTHING_TOOLTIP = "Show all combat messages.";
+QUICKBUTTON_NAME_FRIENDS = "Friends";
+QUICKBUTTON_NAME_KILLS = "Kills";
+QUICKBUTTON_NAME_KILLS_TOOLTIP = "Show all deaths and kills.";
+QUICKBUTTON_NAME_ME = "What happened to me?";
+QUICKBUTTON_NAME_ME_TOOLTIP = "Show everything done to me.";
+QUICKBUTTON_NAME_SELF = "Self";
+QUICKBUTTON_NAME_SELF_TOOLTIP = "Show messages of actions done by you and done to you.";
+QUICK_BUTTON_COMBATLOG_TOOLTIP = "Places a shortcut to this filter on the chat window.";
+QUIT = "Quit";
+QUIT_NOW = "Exit now";
+QUIT_TIMER = "%d %s until exit";
+RACE = "Race";
+RACE_CLASS_ONLY = "%s Only";
+RACIAL_SKILLS = "%s Skills:";
+RAF_GRANT_LEVEL = "Grant a Level";
+RAF_SUMMON = "Summon Friend";
+RAF_SUMMON_LINKED = "Summon Linked Friend";
+RAF_SUMMON_WITH_COOLDOWN = "Summon Friend (%s)";
+RAGE = "Rage";
+RAGE_COST = "%d Rage";
+RAGE_COST_PER_TIME = "%d Rage, plus %d per sec";
+RAID = "Raid";
+RAIDOPTIONS_MENU = "Raid Options";
+RAID_AND_PARTY = "Raid & Party";
+RAID_ASSISTANT = "Raid Assistant";
+RAID_ASSISTANT_TOKEN = "(A)";
+RAID_BOSS_MESSAGE = "Raid Boss";
+RAID_BROWSER_DESCRIPTION = "Find a Raid Group or Assemble a Raid";
+RAID_CONTROL = "Raid Control";
+RAID_DESCRIPTION = "Raids are groups of more than 5 people and are typically used to defeat unique challenges at high levels.\n\n|cffffffff- Raid members cannot earn credit toward most non-raid quests. Specifically, they will not receive non-raid quest credit for killing creatures or collecting items.\n\n- Raids grant substantially less experience for defeating monsters than normal groups.\n\n- Raids allow you to overcome challenges that might otherwise be nearly impossible.|r";
+RAID_DIFFICULTY = "Raid Difficulty";
+RAID_DIFFICULTY1 = "10 Player";
+RAID_DIFFICULTY2 = "25 Player";
+RAID_DIFFICULTY3 = "10 Player (Heroic)";
+RAID_DIFFICULTY4 = "25 Player (Heroic)";
+RAID_DIFFICULTY_10PLAYER = "10 Player";
+RAID_DIFFICULTY_10PLAYER_HEROIC = "10 Player (Heroic)";
+RAID_DIFFICULTY_20PLAYER = "20 Player";
+RAID_DIFFICULTY_25PLAYER = "25 Player";
+RAID_DIFFICULTY_25PLAYER_HEROIC = "25 Player (Heroic)";
+RAID_DIFFICULTY_40PLAYER = "40 Player";
+RAID_GROUPS = "Raid Groups";
+RAID_INFO = "Raid Info";
+RAID_INFORMATION = "Raid Information";
+RAID_INFO_DESC = "Your saved raid instance status.";
+RAID_INSTANCE_EXPIRED = "Your instance lock for %s has expired.";
+RAID_INSTANCE_EXPIRES = "Expires in %1$s";
+RAID_INSTANCE_EXPIRES_EXPIRED = "Expired";
+RAID_INSTANCE_EXPIRES_EXTENDED = "Expires in %1$s (extended)";
+RAID_INSTANCE_INFO_FMT = "%s (ID=%lx): %s";
+RAID_INSTANCE_INFO_HDR = "Raid Instance Time Remaining:";
+RAID_INSTANCE_LOCK_EXTENDED = "Your instance lock for %s has been extended.";
+RAID_INSTANCE_LOCK_NOT_EXTENDED = "Your instance lock for %s is no longer extended.";
+RAID_INSTANCE_WARNING_HOURS = "Your instance lock for %s will expire in %d |4hour:hours;.";
+RAID_INSTANCE_WARNING_MIN = "Your instance lock for %s will expire in %d |4minute:minutes;!";
+RAID_INSTANCE_WARNING_MIN_SOON = "Your instance lock for %s will expire in %d |4minute:minutes;.";
+RAID_INSTANCE_WELCOME = "Welcome to %s. Instance locks are scheduled to expire in %s.";
+RAID_INSTANCE_WELCOME_DH = "%s will expire in %d days %d hours.";
+RAID_INSTANCE_WELCOME_EXTENDED = "Welcome to %s. Your instance lock has been extended.";
+RAID_INSTANCE_WELCOME_HM = "%s will expire in %d hours %d minutes.";
+RAID_INSTANCE_WELCOME_LOCKED = "Welcome to %s. Your instance lock is scheduled to expire in %s.";
+RAID_INSTANCE_WELCOME_LOCKED_EXTENDED = "Welcome to %s. Your instance lock is scheduled to expire in %s (extended).";
+RAID_LEADER = "Raid Leader";
+RAID_LEADER_TOKEN = "(L)";
+RAID_MEMBERS_AFK = "The following players are Away: %s";
+RAID_MEMBER_NOT_READY = "%s is not ready";
+RAID_MESSAGE = "Raid";
+RAID_SILENCE = "Silence in Raid";
+RAID_TARGET_1 = "Star";
+RAID_TARGET_2 = "Circle";
+RAID_TARGET_3 = "Diamond";
+RAID_TARGET_4 = "Triangle";
+RAID_TARGET_5 = "Moon";
+RAID_TARGET_6 = "Square";
+RAID_TARGET_7 = "Cross";
+RAID_TARGET_8 = "Skull";
+RAID_TARGET_ICON = "Raid Target Icon";
+RAID_TARGET_NONE = "None";
+RAID_UNSILENCE = "Unsilence in Raid";
+RAID_WARNING = "Raid Warning";
+RAID_WARNING_MESSAGE = "Raid Warning";
+RALT_KEY_TEXT = "Right ALT";
+RANDOM_BATTLEGROUND = "Random Battleground";
+RANDOM_BATTLEGROUND_EXPLANATION = "Completing Random Battlegrounds will earn you extra rewards.";
+RANDOM_DUNGEON_IS_READY = "Your Random Dungeon group is ready!";
+RANDOM_ROLL_RESULT = "%s rolls %d (%d-%d)";
+RANGED = "Ranged";
+RANGEDSLOT = "Ranged";
+RANGED_ATTACK = "Ranged Attack";
+RANGED_ATTACK_POWER = "Ranged Attack Power";
+RANGED_ATTACK_POWER_TOOLTIP = "Increases damage with ranged weapons by %.1f damage per second.";
+RANGED_ATTACK_TOOLTIP = "Ranged Attack Rating";
+RANGED_COMBATLOG_TOOLTIP = "Shows attacks from bows, guns, thrown weapons, and wands.";
+RANGED_CRIT_CHANCE = "Crit Chance";
+RANGED_DAMAGE_TOOLTIP = "Ranged Damage";
+RANGE_DAMAGE_COMBATLOG_TOOLTIP = "Show ranged shots that deal full or partial damage.";
+RANGE_MISSED_COMBATLOG_TOOLTIP = "Show ranged shots that fail to deal damage.";
+RANK = "Rank";
+RANK_COLON = "Rank:";
+RANK_POSITION = "Rank Position";
+RARITY = "Rarity";
+RATING = "Rating";
+RATINGS_MENU = "Rating";
+RATINGS_TEXT = "The text for Korean Ratings.";
+RATING_CHANGE_TOOLTIP = "Total rating change";
+RCTRL_KEY_TEXT = "Right CTRL";
+REACTIVATE_RAID_LOCK = "Reactivate Raid Lock";
+READY = "Ready";
+READY_CHECK = "Ready Check";
+READY_CHECK_ALL_READY = "Everyone is Ready";
+READY_CHECK_FINISHED = "Ready check finished";
+READY_CHECK_MESSAGE = "%s has initiated a ready check.\n|cffffffffAre you ready?|r";
+READY_CHECK_NO_AFK = "No players are Away";
+READY_CHECK_START = "Starting ready check...";
+READY_CHECK_YOU_WERE_AFK = "You were Away for a ready check";
+RECOVER_CORPSE = "Resurrect now?";
+RECOVER_CORPSE_INSTANCE = "You must enter the instance to recover your corpse";
+RECOVER_CORPSE_TIMER = "%d %s until resurrection";
+RED_GEM = "Red";
+REFLECT = "Reflect";
+REFRESH = "Refresh";
+REFRESH_RATE = "Refresh";
+REFUND_TIME_REMAINING = "You may sell this item to a vendor within %s for a full refund.";
+RELICSLOT = "Relic";
+REMOVE = "Remove";
+REMOVE_BLOCK = "Remove";
+REMOVE_CHAT_DELAY_TEXT = "Remove Chat Hover Delay";
+REMOVE_FRIEND = "Remove Friend";
+REMOVE_FRIEND_CONFIRMATION = "Are you sure you want to remove %s as a Real ID friend?";
+REMOVE_GUILDMEMBER_LABEL = "Are you sure you want to remove %s from the guild?";
+REMOVE_IGNORE = "Remove";
+REMOVE_MODERATOR = "Remove Moderator";
+REMOVE_MUTE = "Remove";
+REMOVE_PLAYER = "Remove Player";
+RENAME_ARENA_TEAM = "Rename Team";
+RENAME_ARENA_TEAM_LABEL = "Enter a new Arena Team name:";
+RENAME_CHAT_WINDOW = "Rename Window";
+RENAME_GUILD = "Rename Guild";
+RENAME_GUILD_LABEL = "Enter new guild name:";
+REPAIR_ALL_ITEMS = "Repair All Items";
+REPAIR_AN_ITEM = "Repair an Item";
+REPAIR_COST = "Repair cost:";
+REPAIR_ITEMS = "Repair Items";
+REPLACE_ENCHANT = "Do you want to replace \"%s\" with \"%s\"?";
+REPLY_MESSAGE = "Reply";
+REPORT_MULTIPLE_PVP_AFK_SENT = "Notification sent for all selected players.";
+REPORT_PHYSICAL_HARASSMENT = "Report Physical Harassment";
+REPORT_PVP_AFK_SENT = "Notification sent for %s.";
+REPORT_SPAM = "Report Spam";
+REPORT_SPAM_CONFIRMATION = "Are you sure you want to report %s for spamming?";
+REPORT_VERBAL_HARASSMENT = "Report Verbal Harassment";
+REPUTATION = "Reputation";
+REPUTATION_ABBR = "Reputation";
+REPUTATION_AT_WAR_DESCRIPTION = "This determines how you will interact with members of this faction. If you have at war checked then your default behavior will be to attack them. If you do not have it checked you will not be able to attack them. ";
+REPUTATION_FACTION_DESCRIPTION = "These are the factions that you have interacted with.";
+REPUTATION_MOVE_TO_INACTIVE = "Moves the reputation bar to the bottom of your list under the inactive heading. Useful for reputations you are no longer interested in tracking.";
+REPUTATION_SHOW_AS_XP = "Displays this reputation bar along the bottom of your screen just above your action bar.";
+REPUTATION_STANDING_DESCRIPTION = "The further to the right your standing bar is the closer you are to improving your reputation to the next tier with that faction. The Standing Levels in order are Hated, Hostile, Unfriendly, Neutral, Friendly, Honored, Revered and Exalted.";
+REPUTATION_STATUS_AT_PEACE = "While this box is unchecked you are at peace.";
+REPUTATION_STATUS_AT_WAR = "You are currently at war with this group.";
+REPUTATION_STATUS_NOT_AT_PEACE = "While this box is checked you are at war.";
+REPUTATION_STATUS_PERMANENT_AT_PEACE = "You cannot go to war with your own people!";
+REPUTATION_STATUS_PERMANENT_AT_WAR = "You can never be at peace with the %s.";
+REQUEST_SIGNATURE = "Request Signature";
+REQUIRED_MONEY = "Required Money:";
+REQUIRES_LABEL = "Requires:";
+REQUIRES_RUNIC_POWER = "Requires Runic Power";
+RESET = "Reset";
+RESETS_IN = "Expires in";
+RESET_ALL_WINDOWS = "Reset Chat Windows";
+RESET_CHAT_WINDOW = "This will reset your chat windows to default settings.\nYou will lose any custom settings.";
+RESET_FAILED_NOTIFY = "The party leader has attempted to reset the instance you are in. Please zone out to allow the instance to reset.";
+RESET_INSTANCES = "Reset all instances";
+RESET_TO_DEFAULT = "Reset To Default";
+RESET_TUTORIALS = "Reset Tutorials";
+RESILIENCE = "Resilience";
+RESILIENCE_ABBR = "Resil";
+RESILIENCE_TOOLTIP = "Reduces chance to be critically hit by %.2f%%.\nReduces the effect of mana-drains and the damage of critical strikes by %.2f%%.\nProvides %.2f%% additional damage reduction against all damage done by players and their pets or minions.";
+RESIST = "Resist";
+RESISTANCE0_NAME = "Armor";
+RESISTANCE1_NAME = "Holy Resistance";
+RESISTANCE2_NAME = "Fire Resistance";
+RESISTANCE3_NAME = "Nature Resistance";
+RESISTANCE4_NAME = "Frost Resistance";
+RESISTANCE5_NAME = "Shadow Resistance";
+RESISTANCE6_NAME = "Arcane Resistance";
+RESISTANCE_EXCELLENT = "Excellent";
+RESISTANCE_FAIR = "Fair";
+RESISTANCE_GOOD = "Good";
+RESISTANCE_LABEL = "Resistance";
+RESISTANCE_NONE = "None";
+RESISTANCE_POOR = "Poor";
+RESISTANCE_TEMPLATE = "%d %s";
+RESISTANCE_TOOLTIP_SUBTEXT = "Increases the ability to resist %s-based attacks, spells and abilities.\nResistance against level %d: |cffffffff%s|r";
+RESISTANCE_TYPE0 = "armor";
+RESISTANCE_TYPE1 = "holy";
+RESISTANCE_TYPE2 = "fire";
+RESISTANCE_TYPE3 = "nature";
+RESISTANCE_TYPE4 = "frost";
+RESISTANCE_TYPE5 = "shadow";
+RESISTANCE_TYPE6 = "arcane";
+RESISTANCE_VERYGOOD = "Very Good";
+RESIST_TRAILER = " (%d resisted)";
+RESOLUTION = "Resolution";
+RESOLUTION_LABEL = "Resolution";
+RESOLUTION_SUBTEXT = "These options allow you to change the size and detail in which your video hardware renders the game.";
+RESURRECT = "Resurrections";
+RESURRECTABLE = "Resurrectable";
+RESURRECT_REQUEST = "%s wants to resurrect you. You will be afflicted with resurrection sickness.";
+RESURRECT_REQUEST_NO_SICKNESS = "%s wants to resurrect you";
+RESURRECT_REQUEST_NO_SICKNESS_TIMER = "%s wants to resurrect you and will be able to in %d %s";
+RESURRECT_REQUEST_TIMER = "%s wants to resurrect you and will be able to in %d %s. You will be afflicted with resurrection sickness.";
+RETRIEVING_ITEM_INFO = "Retrieving item information";
+RETURN_TO_GAME = "Return to Game";
+RETURN_TO_WORLD = "Leave Battleground";
+REWARD_AURA = "The following spell will be cast on you:";
+REWARD_CHOICES = "You will be able to choose one of these rewards:";
+REWARD_CHOOSE = "Choose your reward:";
+REWARD_ITEMS = "You will also receive:";
+REWARD_ITEMS_ONLY = "You will receive:";
+REWARD_REPUTATION = " %s:";
+REWARD_REPUTATION_TEXT = "Reputation awards:";
+REWARD_SPELL = "You will learn:";
+REWARD_TITLE = "You shall be granted the title:";
+REWARD_TRADESKILL_SPELL = "You will learn how to create:";
+RID_FRIEND_REQUEST_INFO = "This should be a person you know and trust in real life. You will be able to chat with them no matter which Blizzard game you are playing. If you accept their friend invite your real name will be displayed to all of their friends.";
+RIGHT_CLICK_MESSAGE = "|cffffffff for PvP Options|r";
+ROGUE_AGILITY_TOOLTIP = "Increases attack power with both melee and ranged weapons, and improves the chance to score a critical hit with all weapons.|nIncreases armor and chance to dodge attacks.";
+ROLE = "Role";
+ROLE_CHECK_IN_PROGRESS_TOOLTIP = "Waiting for all players to confirm their roles...";
+ROLE_DESCRIPTION1 = "Indicates that you are willing to take on the role of dealing damage to enemies.";
+ROLE_DESCRIPTION2 = "Indicates that you are willing to protect allies from harm by ensuring that enemies are attacking you instead of them.";
+ROLE_DESCRIPTION3 = "Indicates that you are willing to heal your allies when they take damage.";
+ROLL_DISENCHANT = "Disenchant";
+ROLL_DISENCHANT_NEWBIE = "You want to Greed the item, but you want it disenchanted if you win the roll.";
+ROTATE_MINIMAP = "Rotate Minimap";
+RSHIFT_KEY_TEXT = "Right SHIFT";
+RUNES = "Runes";
+RUNE_COST_BLOOD = "%d Blood";
+RUNE_COST_FROST = "%d Frost";
+RUNE_COST_ONGOING = "Ongoing";
+RUNE_COST_UNHOLY = "%d Unholy";
+RUNIC_POWER = "Runic Power";
+RUNIC_POWER_COST = "%d Runic Power";
+RUNIC_POWER_COST_PER_TIME = "%d Runic Power, plus %d per sec";
+RURU = "Russian";
+RUSSIAN_DECLENSION = "Declensions";
+RUSSIAN_DECLENSION_1 = "Genitive Case";
+RUSSIAN_DECLENSION_2 = "Dative Case";
+RUSSIAN_DECLENSION_3 = "Accusative Case";
+RUSSIAN_DECLENSION_4 = "Instrumental Case";
+RUSSIAN_DECLENSION_5 = "Prepositional Case";
+RUSSIAN_DECLENSION_EXAMPLE_1 = "I always travel with %s.";
+RUSSIAN_DECLENSION_EXAMPLE_2 = "First thing yesterday I bonked %s on the head.";
+RUSSIAN_DECLENSION_EXAMPLE_3 = "Today I met %s again.";
+RUSSIAN_DECLENSION_EXAMPLE_4 = "Now I am friends with %s.";
+RUSSIAN_DECLENSION_EXAMPLE_5 = "Although I know nothing about %s.";
+SALE_PRICE_COLON = "Sale Price:";
+SANCTUARY_TERRITORY = "(Sanctuary)";
+SAVE = "Save";
+SAVE_CHANGES = "Save Changes";
+SAY = "Say";
+SAY_MESSAGE = "Say";
+SCORE_DAMAGE_DONE = "Damage\nDone";
+SCORE_FLAGS_CAPTURED = "Flags\nCaptured";
+SCORE_FLAGS_RETURNED = "Flags\nReturned";
+SCORE_HEALING_DONE = "Healing\nDone";
+SCORE_HONORABLE_KILLS = "Honorable\nKills";
+SCORE_HONOR_GAINED = "Honor\nGained";
+SCORE_KILLING_BLOWS = "Killing\nBlows";
+SCORE_POWER_UPS = "Power Ups";
+SCORE_RATING_CHANGE = "Rating\nChange";
+SCORE_TEAM_SKILL = "Matchmaking\nValue";
+SCREENSHOT_FAILURE = "Screen Capture Failed";
+SCREENSHOT_SUCCESS = "Screen Captured";
+SEARCH = "Search";
+SEARCHING_FOR_GROUPS_NEEDS = "You are queued as:";
+SEARCHING_FOR_ITEMS = "Searching for Items";
+SECONDARY = "Secondary";
+SECONDARYHANDSLOT = "Off Hand";
+SECONDARY_SKILLS = "Secondary Skills:";
+SECONDS = "|4Second:Seconds;";
+SECONDS_ABBR = "%d |4Sec:Sec;";
+SECOND_NUMBER_CAP = " M";
+SECOND_ONELETTER_ABBR = "%d s";
+SECURE_ABILITY_TOGGLE = "Secure Ability Toggle";
+SELECT_CATEGORY = "--> Select a Category";
+SELFMUTED = "|cffff0000(Self muted)|r";
+SELL_PRICE = "Sell Price";
+SENDMAIL = "Send Mail";
+SENDMAIL_TEXT = "Add item and /or money here";
+SEND_BUG = "Submit Bug";
+SEND_LABEL = "Send";
+SEND_MAIL_COST = "Postage:";
+SEND_MESSAGE = "Send Message";
+SEND_MONEY = "Send Money";
+SEND_MONEY_CONFIRMATION = "Really send %s the following amount?";
+SEND_REQUEST = "Send Request";
+SEND_SUGGEST = "Send Suggestion";
+SERVER_CHANNELS = "Server Channels";
+SERVER_FIRST_ACHIEVEMENT = "%s has earned the achievement $a!";
+SERVER_MESSAGE_COLON = "Alert:";
+SERVER_MESSAGE_PREFIX = "[SERVER]";
+SETTINGS = "Settings";
+SET_COMMENT_LABEL = "Set Comment:";
+SET_FOCUS = "Set Focus";
+SET_FRIENDNOTE_LABEL = "Set Notes for %s:";
+SET_GUILDMOTD_LABEL = "Set Guild Message Of The Day:";
+SET_GUILDOFFICERNOTE_LABEL = "Set Officer Note:";
+SET_GUILDPLAYERNOTE_LABEL = "Set Player Note:";
+SET_MAIN_ASSIST = "Promote to Main Assist";
+SET_MAIN_TANK = "Promote to Main Tank";
+SET_NOTE = "Set Note";
+SET_RAID_ASSISTANT = "Promote to Assistant";
+SET_RAID_LEADER = "Promote to Raid Leader";
+SHADOW_QUALITY = "Shadow Quality";
+SHAMAN_INTELLECT_TOOLTIP = "Increases mana points and chance to score a critical hit with spells.\nIncreases the rate at which weapon skills improve.";
+SHAMAN_STRENGTH_TOOLTIP = "Increases attack power with melee weapons.\nIncreases the amount of damage that can be blocked with a shield.";
+SHARDS = "Shards";
+SHARE_QUEST = "Share Quest";
+SHARE_QUEST_ABBREV = "Share";
+SHARE_QUEST_TEXT = "Allows you to share a quest with a party\nmember if they are eligible for the quest.\nCertain quests, such as quests\ngranted by items, cannot be shared.";
+SHIELDSLOT = "Shield";
+SHIELD_BLOCK_TEMPLATE = "%d Block";
+SHIFT_KEY = "SHIFT key";
+SHIFT_KEY_TEXT = "SHIFT";
+SHIRTSLOT = "Shirt";
+SHORTDATE = "%2$d/%1$02d/%3$02d";
+SHOULDERSLOT = "Shoulders";
+SHOW_ALL_SPELL_RANKS = "Show all spell ranks";
+SHOW_ARENA_ENEMY_CASTBAR_TEXT = "Show Cast Bars";
+SHOW_ARENA_ENEMY_FRAMES_TEXT = "Arena Enemy Frames";
+SHOW_ARENA_ENEMY_PETS_TEXT = "Show Pets";
+SHOW_BATTLEFIELDMINIMAP_PLAYERS = "Show Teammates";
+SHOW_BATTLENET_TOASTS = "Battle.net Toasts";
+SHOW_BRACES = "Show Braces";
+SHOW_BRACES_COMBATLOG_TOOLTIP = "Display braces around hyperlinks in combat log messages.";
+SHOW_BUFFS = "Show Buffs";
+SHOW_BUFF_DURATION_TEXT = "Buff Durations";
+SHOW_CASTABLE_BUFFS_TEXT = "Castable Buffs";
+SHOW_CASTABLE_DEBUFFS_TEXT = "Castable Debuffs";
+SHOW_CHAT_ICONS = "Icons in Chat";
+SHOW_CLASS_COLOR = "Show Class Color";
+SHOW_CLASS_COLOR_IN_V_KEY = "Class Colors in Nameplates";
+SHOW_CLOAK = "Show Cloak";
+SHOW_CLOCK = "Show Clock";
+SHOW_COMBAT_HEALING = "Healing";
+SHOW_COMBAT_TEXT_TEXT = "Enable My Floating Combat Text";
+SHOW_DAMAGE_TEXT = "Target Damage";
+SHOW_DEBUFFS = "Show Debuffs";
+SHOW_DISPELLABLE_DEBUFFS_TEXT = "Dispellable Debuffs";
+SHOW_ENEMY_CAST = "Cast Bars";
+SHOW_FACTION_ON_MAINSCREEN = "Show as Experience Bar";
+SHOW_FREE_BAG_SLOTS_TEXT = "Show Free Bag Slots";
+SHOW_FRIENDS_LIST = "Show Friends List";
+SHOW_FULLSCREEN_STATUS_TEXT = "Screen Edge Flash";
+SHOW_GUILD_NAMES = "Player Guild Names";
+SHOW_HELM = "Show Helm";
+SHOW_IGNORE_LIST = "Show Ignore List";
+SHOW_ITEM_LEVEL = "Show Item Level";
+SHOW_LOOT_SPAM = "Detailed Loot Information";
+SHOW_LUA_ERRORS = "Display Lua Errors";
+SHOW_MAP = "Show Map";
+SHOW_MULTIBAR1_TEXT = "Bottom Left Bar";
+SHOW_MULTIBAR2_TEXT = "Bottom Right Bar";
+SHOW_MULTIBAR3_TEXT = "Right Bar";
+SHOW_MULTIBAR4_TEXT = "Right Bar 2";
+SHOW_NEWBIE_TIPS_TEXT = "Beginner Tooltips";
+SHOW_NPC_NAMES = "NPC Names";
+SHOW_NUMERIC_THREAT = "Show Aggro Percentages";
+SHOW_OFFLINE_MEMBERS = "Show Offline Members";
+SHOW_ON_BACKPACK = "Show on Backpack";
+SHOW_OTHER_TARGET_EFFECTS = "Show for other players' targets";
+SHOW_OWN_NAME = "Show Own Name";
+SHOW_PARTY_BACKGROUND_TEXT = "Party/Arena Background";
+SHOW_PARTY_PETS_TEXT = "Party Members' Pets";
+SHOW_PARTY_TEXT_TEXT = "Numeric Party Health";
+SHOW_PET_MELEE_DAMAGE = "Pet Damage";
+SHOW_PET_NAMEPLATES = "Pet Name Plates";
+SHOW_PET_SPELL_DAMAGE = "Show pet spell damage";
+SHOW_PLAYER_NAMES = "Player Names";
+SHOW_PLAYER_TITLES = "Player Titles";
+SHOW_QUEST_FADING_TEXT = "Instant Quest Text";
+SHOW_QUEST_OBJECTIVES_ON_MAP_TEXT = "Show Quest Objectives";
+SHOW_QUICK_BUTTON = "Show Quick Button";
+SHOW_RAID_RANGE_TEXT = "Range in Raid Interface";
+SHOW_TARGET = "Show Target";
+SHOW_TARGET_CASTBAR = "On Targets";
+SHOW_TARGET_CASTBAR_IN_V_KEY = "On Nameplates";
+SHOW_TARGET_EFFECTS = "Target Effects";
+SHOW_TARGET_OF_TARGET_TEXT = "Target of Target";
+SHOW_TIMESTAMP = "Show Timestamp";
+SHOW_TIPOFTHEDAY_TEXT = "Loading Screen Tips";
+SHOW_TOAST_BROADCAST_TEXT = "Broadcast Updates";
+SHOW_TOAST_CONVERSATION_TEXT = "Conversation Notifications";
+SHOW_TOAST_FRIEND_REQUEST_TEXT = "Real ID Friend Requests";
+SHOW_TOAST_OFFLINE_TEXT = "Offline Friends";
+SHOW_TOAST_ONLINE_TEXT = "Online Friends";
+SHOW_TOAST_WINDOW_TEXT = "Show Toast Window";
+SHOW_TUTORIALS = "Tutorials";
+SHOW_UNIT_NAMES = "Show Unit Names";
+SIGN_CHARTER = "Sign Charter";
+SILVER_AMOUNT = "%d Silver";
+SILVER_AMOUNT_SYMBOL = "s";
+SILVER_AMOUNT_TEXTURE = "%d\124TInterface\\MoneyFrame\\UI-SilverIcon:%d:%d:2:0\124t";
+SIMPLE_CHAT_OPTION_ENABLE_INTERRUPT = "Enabling Simple Chat will cause your chat window settings to be lost. Are you sure you want to enable Simple Chat?";
+SIMPLE_CHAT_TEXT = "Simple Chat";
+SIMPLE_QUEST_WATCH_TEXT = "Simple Objective Tracking";
+SINGLE_DAMAGE_TEMPLATE = "%d Damage";
+SINGLE_DAMAGE_TEMPLATE_WITH_SCHOOL = "%d %s Damage";
+SINGLE_PAGE_RESULTS_TEMPLATE = "%d Items";
+SKILL = "Skill";
+SKILLS = "Skills";
+SKILLS_ABBR = "Skills";
+SKILLUPS = "Skill-ups";
+SKILL_DESCRIPTION = "|cffffffff%s|r %s";
+SKILL_INCREMENT_COST = "Costs %s%d|r Skill points to increase.";
+SKILL_INCREMENT_COST_SINGULAR = "Costs %s%d|r Skill point to increase.";
+SKILL_LEARNING_COST = "Learning this skill: %s%d|r Skill points.";
+SKILL_LEARNING_COST_SINGULAR = "Learning this skill: %s%d|r Skill point.";
+SKILL_LEVEL = "Skill Level";
+SKILL_POINTS_TOOLTIP = "Skill points are used to learn specialized skills\nat various trainers throughout the world.";
+SKILL_RANK_UP = "Your skill in %s has increased to %d.";
+SKIN_COLOR = "Skin Color";
+SLASH_ACHIEVEMENTUI1 = "/ach";
+SLASH_ACHIEVEMENTUI2 = "/ach";
+SLASH_ACHIEVEMENTUI3 = "/achieve";
+SLASH_ACHIEVEMENTUI4 = "/achieve";
+SLASH_ACHIEVEMENTUI5 = "/achievement";
+SLASH_ACHIEVEMENTUI6 = "/achievement";
+SLASH_ACHIEVEMENTUI7 = "/achievements";
+SLASH_ACHIEVEMENTUI8 = "/achievements";
+SLASH_ASSIST1 = "/a";
+SLASH_ASSIST2 = "/assist";
+SLASH_ASSIST3 = "/a";
+SLASH_ASSIST4 = "/assist";
+SLASH_BATTLEGROUND1 = "/bg";
+SLASH_BATTLEGROUND2 = "/battleground";
+SLASH_BATTLEGROUND3 = "/bg";
+SLASH_BATTLEGROUND4 = "/battleground";
+SLASH_BENCHMARK1 = "/timetest";
+SLASH_BENCHMARK2 = "/timetest";
+SLASH_CALENDAR1 = "/calendar";
+SLASH_CALENDAR2 = "/calendar";
+SLASH_CANCELAURA1 = "/cancelaura";
+SLASH_CANCELAURA2 = "/cancelaura";
+SLASH_CANCELFORM1 = "/cancelform";
+SLASH_CANCELFORM2 = "/cancelform";
+SLASH_CAST1 = "/cast";
+SLASH_CAST2 = "/spell";
+SLASH_CAST3 = "/cast";
+SLASH_CAST4 = "/spell";
+SLASH_CASTRANDOM1 = "/castrandom";
+SLASH_CASTRANDOM2 = "/castrandom";
+SLASH_CASTSEQUENCE1 = "/castsequence";
+SLASH_CASTSEQUENCE2 = "/castsequence";
+SLASH_CHANGEACTIONBAR1 = "/changeactionbar";
+SLASH_CHANGEACTIONBAR2 = "/changeactionbar";
+SLASH_CHANNEL1 = "/c";
+SLASH_CHANNEL2 = "/csay";
+SLASH_CHANNEL3 = "/c";
+SLASH_CHANNEL4 = "/csay";
+SLASH_CHATLOG1 = "/chatlog";
+SLASH_CHATLOG2 = "/chatlog";
+SLASH_CHAT_AFK1 = "/afk";
+SLASH_CHAT_AFK2 = "/afk";
+SLASH_CHAT_AFK3 = "/away";
+SLASH_CHAT_AFK4 = "/away";
+SLASH_CHAT_ANNOUNCE1 = "/announce";
+SLASH_CHAT_ANNOUNCE2 = "/ann";
+SLASH_CHAT_ANNOUNCE3 = "/announce";
+SLASH_CHAT_ANNOUNCE4 = "/ann";
+SLASH_CHAT_BAN1 = "/ban";
+SLASH_CHAT_BAN2 = "/ban";
+SLASH_CHAT_CINVITE1 = "/cinvite";
+SLASH_CHAT_CINVITE2 = "/chatinvite";
+SLASH_CHAT_CINVITE3 = "/cinvite";
+SLASH_CHAT_CINVITE4 = "/chatinvite";
+SLASH_CHAT_DND1 = "/dnd";
+SLASH_CHAT_DND2 = "/dnd";
+SLASH_CHAT_DND3 = "/dnd";
+SLASH_CHAT_DND4 = "/busy";
+SLASH_CHAT_DND5 = "/busy";
+SLASH_CHAT_DND6 = "/busy";
+SLASH_CHAT_HELP1 = "/chat";
+SLASH_CHAT_HELP2 = "/chathelp";
+SLASH_CHAT_HELP3 = "/chat";
+SLASH_CHAT_HELP4 = "/chat";
+SLASH_CHAT_HELP5 = "/chathelp";
+SLASH_CHAT_KICK1 = "/ckick";
+SLASH_CHAT_KICK2 = "/ckick";
+SLASH_CHAT_MODERATE1 = "/moderate";
+SLASH_CHAT_MODERATE2 = "/moderate";
+SLASH_CHAT_MODERATOR1 = "/mod";
+SLASH_CHAT_MODERATOR2 = "/moderator";
+SLASH_CHAT_MODERATOR3 = "/mod";
+SLASH_CHAT_MODERATOR4 = "/moderator";
+SLASH_CHAT_MUTE1 = "/mute";
+SLASH_CHAT_MUTE2 = "/squelch";
+SLASH_CHAT_MUTE3 = "/unvoice";
+SLASH_CHAT_MUTE4 = "/mute";
+SLASH_CHAT_MUTE5 = "/squelch";
+SLASH_CHAT_MUTE6 = "/unvoice";
+SLASH_CHAT_OWNER1 = "/owner";
+SLASH_CHAT_OWNER2 = "/owner";
+SLASH_CHAT_PASSWORD1 = "/password";
+SLASH_CHAT_PASSWORD2 = "/pass";
+SLASH_CHAT_PASSWORD3 = "/password";
+SLASH_CHAT_PASSWORD4 = "/password";
+SLASH_CHAT_PASSWORD5 = "/pass";
+SLASH_CHAT_UNBAN1 = "/unban";
+SLASH_CHAT_UNBAN2 = "/unban";
+SLASH_CHAT_UNMODERATOR1 = "/unmod";
+SLASH_CHAT_UNMODERATOR2 = "/unmoderator";
+SLASH_CHAT_UNMODERATOR3 = "/unmod";
+SLASH_CHAT_UNMODERATOR4 = "/unmoderator";
+SLASH_CHAT_UNMUTE1 = "/unmute";
+SLASH_CHAT_UNMUTE2 = "/unsquelch";
+SLASH_CHAT_UNMUTE3 = "/voice";
+SLASH_CHAT_UNMUTE4 = "/unmute";
+SLASH_CHAT_UNMUTE5 = "/unsquelch";
+SLASH_CHAT_UNMUTE6 = "/voice";
+SLASH_CLEAR1 = "/clear";
+SLASH_CLEAR2 = "/clear";
+SLASH_CLEARFOCUS1 = "/clearfocus";
+SLASH_CLEARFOCUS2 = "/clearfocus";
+SLASH_CLEARMAINASSIST1 = "/clearma";
+SLASH_CLEARMAINASSIST2 = "/clearmainassist";
+SLASH_CLEARMAINASSIST3 = "/clearma";
+SLASH_CLEARMAINASSIST4 = "/clearmainassist";
+SLASH_CLEARMAINTANK1 = "/clearmt";
+SLASH_CLEARMAINTANK2 = "/clearmaintank";
+SLASH_CLEARMAINTANK3 = "/clearmt";
+SLASH_CLEARMAINTANK4 = "/clearmaintank";
+SLASH_CLEARTARGET1 = "/cleartarget";
+SLASH_CLEARTARGET2 = "/cleartarget";
+SLASH_CLICK1 = "/click";
+SLASH_CLICK2 = "/click";
+SLASH_COMBATLOG1 = "/combatlog";
+SLASH_COMBATLOG2 = "/combatlog";
+SLASH_CONSOLE1 = "/console";
+SLASH_CONSOLE2 = "/console";
+SLASH_DISABLE_ADDONS1 = "/disableaddons";
+SLASH_DISMOUNT1 = "/dismount";
+SLASH_DISMOUNT2 = "/dismount";
+SLASH_DUEL1 = "/duel";
+SLASH_DUEL2 = "/duel";
+SLASH_DUEL_CANCEL1 = "/yield";
+SLASH_DUEL_CANCEL2 = "/concede";
+SLASH_DUEL_CANCEL3 = "/forfeit";
+SLASH_DUEL_CANCEL4 = "/yield";
+SLASH_DUEL_CANCEL5 = "/concede";
+SLASH_DUEL_CANCEL6 = "/forfeit";
+SLASH_DUMP1 = "/dump";
+SLASH_DUMP2 = "/dump";
+SLASH_DUNGEONS1 = "/dungeonfinder";
+SLASH_DUNGEONS2 = "/dungeonfinder";
+SLASH_DUNGEONS3 = "/lfd";
+SLASH_DUNGEONS4 = "/lfd";
+SLASH_DUNGEONS5 = "/df";
+SLASH_DUNGEONS6 = "/df";
+SLASH_EMOTE1 = "/e";
+SLASH_EMOTE2 = "/em";
+SLASH_EMOTE3 = "/emote";
+SLASH_EMOTE4 = "/me";
+SLASH_EMOTE5 = "/e";
+SLASH_EMOTE6 = "/em";
+SLASH_EMOTE7 = "/emote";
+SLASH_EMOTE8 = "/me";
+SLASH_ENABLE_ADDONS1 = "/enableaddons";
+SLASH_EQUIP1 = "/equip";
+SLASH_EQUIP2 = "/eq";
+SLASH_EQUIP3 = "/equip";
+SLASH_EQUIP4 = "/eq";
+SLASH_EQUIP_SET1 = "/equipset";
+SLASH_EQUIP_SET2 = "/equipset";
+SLASH_EQUIP_TO_SLOT1 = "/equipslot";
+SLASH_EQUIP_TO_SLOT2 = "/equipslot";
+SLASH_EVENTTRACE1 = "/eventtrace";
+SLASH_EVENTTRACE2 = "/eventtrace";
+SLASH_EVENTTRACE3 = "/etrace";
+SLASH_EVENTTRACE4 = "/etrace";
+SLASH_FOCUS1 = "/focus";
+SLASH_FOCUS2 = "/focus";
+SLASH_FOLLOW1 = "/f";
+SLASH_FOLLOW2 = "/follow";
+SLASH_FOLLOW3 = "/fol";
+SLASH_FOLLOW4 = "/f";
+SLASH_FOLLOW5 = "/follow";
+SLASH_FOLLOW6 = "/fol";
+SLASH_FOLLOW7 = "/f";
+SLASH_FRAMESTACK1 = "/framestack";
+SLASH_FRAMESTACK2 = "/framestack";
+SLASH_FRAMESTACK3 = "/fstack";
+SLASH_FRAMESTACK4 = "/fstack";
+SLASH_FRIENDS1 = "/friends";
+SLASH_FRIENDS2 = "/friend";
+SLASH_FRIENDS3 = "/friends";
+SLASH_FRIENDS4 = "/friend";
+SLASH_GUILD1 = "/g";
+SLASH_GUILD2 = "/gc";
+SLASH_GUILD3 = "/gu";
+SLASH_GUILD4 = "/guild";
+SLASH_GUILD5 = "/g";
+SLASH_GUILD6 = "/gc";
+SLASH_GUILD7 = "/gu";
+SLASH_GUILD8 = "/guild";
+SLASH_GUILD9 = "/g";
+SLASH_GUILD_DEMOTE1 = "/gdemote";
+SLASH_GUILD_DEMOTE2 = "/guilddemote";
+SLASH_GUILD_DEMOTE3 = "/gdemote";
+SLASH_GUILD_DEMOTE4 = "/guilddemote";
+SLASH_GUILD_DISBAND1 = "/gdisband";
+SLASH_GUILD_DISBAND2 = "/guilddisband";
+SLASH_GUILD_DISBAND3 = "/gdisband";
+SLASH_GUILD_DISBAND4 = "/guilddisband";
+SLASH_GUILD_HELP1 = "/ghelp";
+SLASH_GUILD_HELP2 = "/guildhelp";
+SLASH_GUILD_HELP3 = "/guildhelp";
+SLASH_GUILD_HELP4 = "/guildhelp";
+SLASH_GUILD_HELP5 = "/ghelp";
+SLASH_GUILD_INFO1 = "/ginfo";
+SLASH_GUILD_INFO2 = "/guildinfo";
+SLASH_GUILD_INFO3 = "/ginfo";
+SLASH_GUILD_INFO4 = "/guildinfo";
+SLASH_GUILD_INVITE1 = "/ginvite";
+SLASH_GUILD_INVITE2 = "/guildinvite";
+SLASH_GUILD_INVITE3 = "/ginvite";
+SLASH_GUILD_INVITE4 = "/guildinvite";
+SLASH_GUILD_LEADER1 = "/gleader";
+SLASH_GUILD_LEADER2 = "/guildleader";
+SLASH_GUILD_LEADER3 = "/gleader";
+SLASH_GUILD_LEADER4 = "/guildleader";
+SLASH_GUILD_LEADER_REPLACE = "/greplace";
+SLASH_GUILD_LEAVE1 = "/gquit";
+SLASH_GUILD_LEAVE2 = "/guildquit";
+SLASH_GUILD_LEAVE3 = "/gquit";
+SLASH_GUILD_LEAVE4 = "/guildquit";
+SLASH_GUILD_MOTD1 = "/gmotd";
+SLASH_GUILD_MOTD2 = "/guildmotd";
+SLASH_GUILD_MOTD3 = "/gmotd";
+SLASH_GUILD_MOTD4 = "/guildmotd";
+SLASH_GUILD_PROMOTE1 = "/gpromote";
+SLASH_GUILD_PROMOTE2 = "/guildpromote";
+SLASH_GUILD_PROMOTE3 = "/gpromote";
+SLASH_GUILD_PROMOTE4 = "/guildpromote";
+SLASH_GUILD_ROSTER1 = "/groster";
+SLASH_GUILD_ROSTER2 = "/guildroster";
+SLASH_GUILD_ROSTER3 = "/groster";
+SLASH_GUILD_ROSTER4 = "/guildroster";
+SLASH_GUILD_UNINVITE1 = "/gremove";
+SLASH_GUILD_UNINVITE2 = "/guildremove";
+SLASH_GUILD_UNINVITE3 = "/gremove";
+SLASH_GUILD_UNINVITE4 = "/guildremove";
+SLASH_GUILD_WHO1 = "/glist";
+SLASH_GUILD_WHO2 = "/gwho";
+SLASH_GUILD_WHO3 = "/whoguild";
+SLASH_GUILD_WHO4 = "/glist";
+SLASH_GUILD_WHO5 = "/gwho";
+SLASH_GUILD_WHO6 = "/whoguild";
+SLASH_HELP1 = "/h";
+SLASH_HELP2 = "/help";
+SLASH_HELP3 = "/?";
+SLASH_HELP4 = "/h";
+SLASH_HELP5 = "/h";
+SLASH_HELP6 = "/help";
+SLASH_IGNORE1 = "/ignore";
+SLASH_IGNORE2 = "/ignore";
+SLASH_INSPECT1 = "/ins";
+SLASH_INSPECT2 = "/inspect";
+SLASH_INSPECT3 = "/ins";
+SLASH_INSPECT4 = "/inspect";
+SLASH_INVITE1 = "/i";
+SLASH_INVITE2 = "/inv";
+SLASH_INVITE3 = "/invite";
+SLASH_INVITE4 = "/i";
+SLASH_INVITE5 = "/inv";
+SLASH_INVITE6 = "/invite";
+SLASH_INVITE7 = "/i";
+SLASH_JOIN1 = "/join";
+SLASH_JOIN2 = "/channel";
+SLASH_JOIN3 = "/chan";
+SLASH_JOIN4 = "/join";
+SLASH_JOIN5 = "/join";
+SLASH_JOIN6 = "/channel";
+SLASH_JOIN7 = "/chan";
+SLASH_LEAVE1 = "/leave";
+SLASH_LEAVE2 = "/chatleave";
+SLASH_LEAVE3 = "/chatexit";
+SLASH_LEAVE4 = "/leave";
+SLASH_LEAVE5 = "/leave";
+SLASH_LEAVE6 = "/chatleave";
+SLASH_LEAVE7 = "/chatexit";
+SLASH_LEAVEVEHICLE1 = "/leavevehicle";
+SLASH_LEAVEVEHICLE2 = "/leavevehicle";
+SLASH_LIST_CHANNEL1 = "/chatlist";
+SLASH_LIST_CHANNEL2 = "/chatwho";
+SLASH_LIST_CHANNEL3 = "/chatinfo";
+SLASH_LIST_CHANNEL4 = "/chatlist";
+SLASH_LIST_CHANNEL5 = "/chatlist";
+SLASH_LIST_CHANNEL6 = "/chatwho";
+SLASH_LIST_CHANNEL7 = "/chatinfo";
+SLASH_LOGOUT1 = "/logout";
+SLASH_LOGOUT2 = "/camp";
+SLASH_LOGOUT3 = "/logout";
+SLASH_LOGOUT4 = "/camp";
+SLASH_LOOT_FFA1 = "/ffa";
+SLASH_LOOT_FFA2 = "/ffa";
+SLASH_LOOT_GROUP1 = "/group";
+SLASH_LOOT_GROUP2 = "/group";
+SLASH_LOOT_MASTER1 = "/master";
+SLASH_LOOT_MASTER2 = "/master";
+SLASH_LOOT_NEEDBEFOREGREED1 = "/needbeforegreed";
+SLASH_LOOT_NEEDBEFOREGREED2 = "/needbeforegreed";
+SLASH_LOOT_ROUNDROBIN1 = "/roundrobin";
+SLASH_LOOT_ROUNDROBIN2 = "/roundrobin";
+SLASH_LOOT_SETTHRESHOLD1 = "/threshold";
+SLASH_LOOT_SETTHRESHOLD2 = "/threshold";
+SLASH_MACRO1 = "/macro";
+SLASH_MACRO2 = "/m";
+SLASH_MACRO3 = "/m";
+SLASH_MACRO4 = "/macro";
+SLASH_MACROHELP1 = "/macrohelp";
+SLASH_MACROHELP2 = "/macrohelp";
+SLASH_MACROHELP3 = "/macrohelp";
+SLASH_MAINASSISTOFF1 = "/maoff";
+SLASH_MAINASSISTOFF2 = "/mainassistoff";
+SLASH_MAINASSISTOFF3 = "/maoff";
+SLASH_MAINASSISTOFF4 = "/mainassistoff";
+SLASH_MAINASSISTON1 = "/ma";
+SLASH_MAINASSISTON2 = "/mainassist";
+SLASH_MAINASSISTON3 = "/ma";
+SLASH_MAINASSISTON4 = "/mainassist";
+SLASH_MAINTANKOFF1 = "/mtoff";
+SLASH_MAINTANKOFF2 = "/maintankoff";
+SLASH_MAINTANKOFF3 = "/mtoff";
+SLASH_MAINTANKOFF4 = "/maintankoff";
+SLASH_MAINTANKON1 = "/mt";
+SLASH_MAINTANKON2 = "/maintank";
+SLASH_MAINTANKON3 = "/mt";
+SLASH_MAINTANKON4 = "/maintank";
+SLASH_OFFICER1 = "/o";
+SLASH_OFFICER2 = "/osay";
+SLASH_OFFICER3 = "/o";
+SLASH_OFFICER4 = "/osay";
+SLASH_OFFICER5 = "/officer";
+SLASH_OFFICER6 = "/officer";
+SLASH_PARTY1 = "/p";
+SLASH_PARTY2 = "/party";
+SLASH_PARTY3 = "/p";
+SLASH_PARTY4 = "/party";
+SLASH_PARTY5 = "/p";
+SLASH_PET_AGGRESSIVE1 = "/petaggressive";
+SLASH_PET_AGGRESSIVE2 = "/petaggressive";
+SLASH_PET_ATTACK1 = "/petattack";
+SLASH_PET_ATTACK2 = "/petattack";
+SLASH_PET_AUTOCASTOFF1 = "/petautocastoff";
+SLASH_PET_AUTOCASTOFF2 = "/petautocastoff";
+SLASH_PET_AUTOCASTON1 = "/petautocaston";
+SLASH_PET_AUTOCASTON2 = "/petautocaston";
+SLASH_PET_AUTOCASTTOGGLE1 = "/petautocasttoggle";
+SLASH_PET_AUTOCASTTOGGLE2 = "/petautocasttoggle";
+SLASH_PET_DEFENSIVE1 = "/petdefensive";
+SLASH_PET_DEFENSIVE2 = "/petdefensive";
+SLASH_PET_FOLLOW1 = "/petfollow";
+SLASH_PET_FOLLOW2 = "/petfollow";
+SLASH_PET_PASSIVE1 = "/petpassive";
+SLASH_PET_PASSIVE2 = "/petpassive";
+SLASH_PET_STAY1 = "/petstay";
+SLASH_PET_STAY2 = "/petstay";
+SLASH_PLAYED1 = "/played";
+SLASH_PLAYED2 = "/played";
+SLASH_PROMOTE1 = "/pr";
+SLASH_PROMOTE2 = "/promote";
+SLASH_PROMOTE3 = "/pr";
+SLASH_PROMOTE4 = "/promote";
+SLASH_PVP1 = "/pvp";
+SLASH_PVP2 = "/pvp";
+SLASH_QUIT1 = "/quit";
+SLASH_QUIT2 = "/exit";
+SLASH_QUIT3 = "/quit";
+SLASH_QUIT4 = "/exit";
+SLASH_RAID1 = "/raid";
+SLASH_RAID2 = "/raid";
+SLASH_RAID3 = "/ra";
+SLASH_RAID4 = "/rsay";
+SLASH_RAID5 = "/ra";
+SLASH_RAID6 = "/rsay";
+SLASH_RAIDBROWSER1 = "/raidbrowser";
+SLASH_RAIDBROWSER2 = "/lfr";
+SLASH_RAIDBROWSER3 = "/rb";
+SLASH_RAIDBROWSER4 = "/raidbrowser";
+SLASH_RAIDBROWSER5 = "/lfr";
+SLASH_RAIDBROWSER6 = "/rb";
+SLASH_RAID_INFO1 = "/raidinfo";
+SLASH_RAID_INFO2 = "/raidinfo";
+SLASH_RAID_WARNING1 = "/rw";
+SLASH_RAID_WARNING2 = "/rw";
+SLASH_RANDOM1 = "/random";
+SLASH_RANDOM2 = "/rand";
+SLASH_RANDOM3 = "/rnd";
+SLASH_RANDOM4 = "/random";
+SLASH_RANDOM5 = "/rand";
+SLASH_RANDOM6 = "/rnd";
+SLASH_RANDOM7 = "/roll";
+SLASH_READYCHECK1 = "/readycheck";
+SLASH_READYCHECK2 = "/readycheck";
+SLASH_RELOAD1 = "/reload";
+SLASH_RELOAD2 = "/reload";
+SLASH_REMOVEFRIEND1 = "/removefriend";
+SLASH_REMOVEFRIEND2 = "/remfriend";
+SLASH_REMOVEFRIEND3 = "/removefriend";
+SLASH_REMOVEFRIEND4 = "/remfriend";
+SLASH_REPLY1 = "/r";
+SLASH_REPLY2 = "/reply";
+SLASH_REPLY3 = "/r";
+SLASH_REPLY4 = "/reply";
+SLASH_RESETCHAT1 = "/resetchat";
+SLASH_RESETCHAT2 = "/resetchat";
+SLASH_SAVEGUILDROSTER1 = "/saveguildroster";
+SLASH_SAVEGUILDROSTER2 = "/saveguildroster";
+SLASH_SAY1 = "/s";
+SLASH_SAY2 = "/say";
+SLASH_SAY3 = "/s";
+SLASH_SAY4 = "/say";
+SLASH_SCRIPT1 = "/script";
+SLASH_SCRIPT2 = "/run";
+SLASH_SCRIPT3 = "/script";
+SLASH_SCRIPT4 = "/run";
+SLASH_SET_TITLE1 = "/settitle";
+SLASH_SET_TITLE2 = "/settitle";
+SLASH_STARTATTACK1 = "/startattack";
+SLASH_STARTATTACK2 = "/startattack";
+SLASH_STOPATTACK1 = "/stopattack";
+SLASH_STOPATTACK2 = "/stopattack";
+SLASH_STOPCASTING1 = "/stopcasting";
+SLASH_STOPCASTING2 = "/stopcasting";
+SLASH_STOPMACRO1 = "/stopmacro";
+SLASH_STOPMACRO2 = "/stopmacro";
+SLASH_STOPWATCH1 = "/stopwatch";
+SLASH_STOPWATCH2 = "/timer";
+SLASH_STOPWATCH3 = "/sw";
+SLASH_STOPWATCH4 = "/stopwatch";
+SLASH_STOPWATCH5 = "/timer";
+SLASH_STOPWATCH6 = "/sw";
+SLASH_STOPWATCH_PARAM_PAUSE1 = "pause";
+SLASH_STOPWATCH_PARAM_PAUSE2 = "pause";
+SLASH_STOPWATCH_PARAM_PLAY1 = "play";
+SLASH_STOPWATCH_PARAM_PLAY2 = "play";
+SLASH_STOPWATCH_PARAM_STOP1 = "stop";
+SLASH_STOPWATCH_PARAM_STOP2 = "clear";
+SLASH_STOPWATCH_PARAM_STOP3 = "reset";
+SLASH_STOPWATCH_PARAM_STOP4 = "stop";
+SLASH_STOPWATCH_PARAM_STOP5 = "clear";
+SLASH_STOPWATCH_PARAM_STOP6 = "reset";
+SLASH_SWAPACTIONBAR1 = "/swapactionbar";
+SLASH_SWAPACTIONBAR2 = "/swapactionbar";
+SLASH_TARGET1 = "/target";
+SLASH_TARGET2 = "/tar";
+SLASH_TARGET3 = "/target";
+SLASH_TARGET4 = "/tar";
+SLASH_TARGET_EXACT1 = "/targetexact";
+SLASH_TARGET_EXACT2 = "/targetexact";
+SLASH_TARGET_LAST_ENEMY1 = "/targetlastenemy";
+SLASH_TARGET_LAST_ENEMY2 = "/targetlastenemy";
+SLASH_TARGET_LAST_FRIEND1 = "/targetlastfriend";
+SLASH_TARGET_LAST_FRIEND2 = "/targetlastfriend";
+SLASH_TARGET_LAST_TARGET1 = "/targetlasttarget";
+SLASH_TARGET_LAST_TARGET2 = "/targetlasttarget";
+SLASH_TARGET_NEAREST_ENEMY1 = "/targetenemy";
+SLASH_TARGET_NEAREST_ENEMY2 = "/targetenemy";
+SLASH_TARGET_NEAREST_ENEMY_PLAYER1 = "/targetenemyplayer";
+SLASH_TARGET_NEAREST_ENEMY_PLAYER2 = "/targetenemyplayer";
+SLASH_TARGET_NEAREST_FRIEND1 = "/targetfriend";
+SLASH_TARGET_NEAREST_FRIEND2 = "/targetfriend";
+SLASH_TARGET_NEAREST_FRIEND_PLAYER1 = "/targetfriendplayer";
+SLASH_TARGET_NEAREST_FRIEND_PLAYER2 = "/targetfriendplayer";
+SLASH_TARGET_NEAREST_PARTY1 = "/targetparty";
+SLASH_TARGET_NEAREST_PARTY2 = "/targetparty";
+SLASH_TARGET_NEAREST_RAID1 = "/targetraid";
+SLASH_TARGET_NEAREST_RAID2 = "/targetraid";
+SLASH_TEAM_CAPTAIN1 = "/teamcaptain";
+SLASH_TEAM_CAPTAIN2 = "/tcaptain";
+SLASH_TEAM_CAPTAIN3 = "/teamcaptain";
+SLASH_TEAM_CAPTAIN4 = "/tcaptain";
+SLASH_TEAM_DISBAND1 = "/teamdisband";
+SLASH_TEAM_DISBAND2 = "/tdisband";
+SLASH_TEAM_DISBAND3 = "/teamdisband";
+SLASH_TEAM_DISBAND4 = "/tdisband";
+SLASH_TEAM_INVITE1 = "/teaminvite";
+SLASH_TEAM_INVITE2 = "/tinvite";
+SLASH_TEAM_INVITE3 = "/teaminvite";
+SLASH_TEAM_INVITE4 = "/tinvite";
+SLASH_TEAM_QUIT1 = "/teamquit";
+SLASH_TEAM_QUIT2 = "/tquit";
+SLASH_TEAM_QUIT3 = "/teamquit";
+SLASH_TEAM_QUIT4 = "/tquit";
+SLASH_TEAM_UNINVITE1 = "/teamremove";
+SLASH_TEAM_UNINVITE2 = "/tremove";
+SLASH_TEAM_UNINVITE3 = "/teamremove";
+SLASH_TEAM_UNINVITE4 = "/tremove";
+SLASH_TIME1 = "/time";
+SLASH_TIME2 = "/time";
+SLASH_TOKEN1 = "/token";
+SLASH_TOKEN2 = "/token";
+SLASH_TOKEN3 = "/tk";
+SLASH_TOKEN4 = "/tk";
+SLASH_TRADE1 = "/tr";
+SLASH_TRADE2 = "/trade";
+SLASH_TRADE3 = "/tr";
+SLASH_TRADE4 = "/trade";
+SLASH_UNIGNORE1 = "/unignore";
+SLASH_UNIGNORE2 = "/unignore";
+SLASH_UNINVITE1 = "/u";
+SLASH_UNINVITE2 = "/un";
+SLASH_UNINVITE3 = "/kick";
+SLASH_UNINVITE4 = "/uninvite";
+SLASH_UNINVITE5 = "/u";
+SLASH_UNINVITE6 = "/un";
+SLASH_UNINVITE7 = "/uninvite";
+SLASH_UNINVITE8 = "/kick";
+SLASH_UNINVITE9 = "/votekick";
+SLASH_UNINVITE10 = "/votekick";
+SLASH_USE1 = "/use";
+SLASH_USE2 = "/use";
+SLASH_USERANDOM1 = "/userandom";
+SLASH_USERANDOM2 = "/userandom";
+SLASH_USE_TALENT_SPEC1 = "/usetalents";
+SLASH_USE_TALENT_SPEC2 = "/usetalents";
+SLASH_VOICEMACRO1 = "/v";
+SLASH_VOICEMACRO2 = "/v";
+SLASH_WHISPER1 = "/w";
+SLASH_WHISPER2 = "/whisper";
+SLASH_WHISPER3 = "/t";
+SLASH_WHISPER4 = "/tell";
+SLASH_WHISPER5 = "/send";
+SLASH_WHISPER6 = "/w";
+SLASH_WHISPER7 = "/whisper";
+SLASH_WHISPER8 = "/t";
+SLASH_WHISPER9 = "/tell";
+SLASH_WHISPER10 = "/send";
+SLASH_WHO1 = "/who";
+SLASH_WHO2 = "/who";
+SLASH_YELL1 = "/y";
+SLASH_YELL2 = "/yell";
+SLASH_YELL3 = "/sh";
+SLASH_YELL4 = "/shout";
+SLASH_YELL5 = "/y";
+SLASH_YELL6 = "/yell";
+SLASH_YELL7 = "/sh";
+SLASH_YELL8 = "/shout";
+SLURRED_SPEECH = "%s ...hic!";
+SMART_PIVOT = "Smart Pivot";
+SOCIALS = "Socials";
+SOCIAL_BUTTON = "Social";
+SOCIAL_LABEL = "Social";
+SOCIAL_SUBTEXT = "These options allow you to control and modify your interactions with other players you encounter in Azeroth.";
+SOCKET_GEMS = "Socket Gems";
+SOCKET_ITEM_MIN_SKILL = "Socket Requires %s (%d)";
+SOCKET_ITEM_REQ_LEVEL = "Socket Requires Level %d";
+SOCKET_ITEM_REQ_SKILL = "Socket Requires %s";
+SOLD_BY_COLON = "Sold By:";
+SOLO = "Solo";
+SORT_QUEST = "Sort Quest";
+SOUNDOPTIONS_MENU = "Sound & Voice";
+SOUND_CHANNELS = "Sound Channels";
+SOUND_DISABLED = "All sound is currently disabled";
+SOUND_EFFECTS_DISABLED = "Sound Effects Disabled";
+SOUND_EFFECTS_ENABLED = "Sound Effects Enabled";
+SOUND_LABEL = "Sound";
+SOUND_OPTIONS = "Sound Options";
+SOUND_QUALITY = "Sound Quality";
+SOUND_SUBTEXT = "These options control sound hardware and the types and volumes of sounds within the game.";
+SOUND_VOLUME = "Sound";
+SPEAKERMODE = "Speaker Mode";
+SPEAKERMODE_HEADPHONES = "Headphones";
+SPEAKERMODE_STEREO = "Stereo";
+SPEAKERMODE_SURROUND = "Surround Sound";
+SPECIAL = "Special";
+SPECIAL_SKILLS = "%s Skills:";
+SPECIFIC_DUNGEONS = "Specific Dungeons";
+SPECIFIC_DUNGEON_IS_READY = "A group has been formed for:";
+SPEED = "Speed";
+SPEED_ABBR = "SPD";
+SPELLBOOK = "Spellbook";
+SPELLBOOK_ABILITIES_BUTTON = "Spellbook & Abilities";
+SPELLBOOK_BUTTON = "Spellbook";
+SPELLDISMISSPETOTHER = "%s's %s is dismissed.";
+SPELLDISMISSPETSELF = "Your %s is dismissed.";
+SPELLHAPPINESSDRAINOTHER = "%s's %s loses %d happiness.";
+SPELLHAPPINESSDRAINSELF = "Your %s loses %d happiness.";
+SPELLS = "Spells";
+SPELLS_COMBATLOG_TOOLTIP = "Shows messages about spells and special abilities.";
+SPELL_BONUS = "Spell Bonus";
+SPELL_CASTING = "Spell Casting";
+SPELL_CASTING_COMBATLOG_TOOLTIP = "Show messages about spell casting.";
+SPELL_CAST_CHANNELED = "Channeled";
+SPELL_CAST_FAILED_COMBATLOG_TOOLTIP = "Show messages when a spell cannot be cast or fails to cast.";
+SPELL_CAST_START_COMBATLOG_TOOLTIP = "Show messages when a spell begins casting.";
+SPELL_CAST_SUCCESS_COMBATLOG_TOOLTIP = "Show messages when a spell successfully completes.";
+SPELL_CAST_TIME_INSTANT = "Instant cast";
+SPELL_CAST_TIME_INSTANT_NO_MANA = "Instant";
+SPELL_CAST_TIME_MIN = "%.3g min cast";
+SPELL_CAST_TIME_RANGED = "Attack speed +%.3g sec";
+SPELL_CAST_TIME_SEC = "%.3g sec cast";
+SPELL_COLOR_BY_SCHOOL_COMBATLOG_TOOLTIP = "Color spell names by school.";
+SPELL_CREATE_COMBATLOG_TOOLTIP = "Show messages when a spell or ability creates an object.";
+SPELL_CRIT_CHANCE = "Crit Chance";
+SPELL_DAMAGE_COMBATLOG_TOOLTIP = "Show messages when a spell or ability deals damage.";
+SPELL_DAMAGE_NUMBER_COMBATLOG_TOOLTIP = "Colorizes the damage number on non-melee swings.";
+SPELL_DAMAGE_SCHOOL_COMBATLOG_TOOLTIP = "Color the damage school name. (e.g. shadow)";
+SPELL_DETAIL = "Spell Detail";
+SPELL_DRAIN_COMBATLOG_TOOLTIP = "Show messages when a spell or ability reduces mana, energy, rage, focus or happiness.";
+SPELL_DURATION = "Lasts %s";
+SPELL_DURATION_DAYS = "%.2f |4day:days;";
+SPELL_DURATION_HOURS = "%.2f |4hour:hrs;";
+SPELL_DURATION_MIN = "%.2f min";
+SPELL_DURATION_SEC = "%.2f sec";
+SPELL_DURATION_UNTIL_CANCELLED = "until cancelled";
+SPELL_EQUIPPED_ITEM = "Requires %s";
+SPELL_EQUIPPED_ITEM_NOSPACE = "Requires %s";
+SPELL_EXTRA_ATTACKS_COMBATLOG_TOOLTIP = "Show messages when a spell or ability grants additional attacks, such as Windfury Weapon or Sword Specialization.";
+SPELL_FAILED_AFFECTING_COMBAT = "You are in combat";
+SPELL_FAILED_ALREADY_BEING_TAMED = "That creature is already being tamed";
+SPELL_FAILED_ALREADY_HAVE_CHARM = "You already control a charmed creature";
+SPELL_FAILED_ALREADY_HAVE_SUMMON = "You already control a summoned creature";
+SPELL_FAILED_ALREADY_OPEN = "Already open";
+SPELL_FAILED_ARTISAN_RIDING_REQUIREMENT = "Requires artisan riding skill";
+SPELL_FAILED_AURA_BOUNCED = "A more powerful spell is already active";
+SPELL_FAILED_BAD_IMPLICIT_TARGETS = "No target";
+SPELL_FAILED_BAD_TARGETS = "Invalid target";
+SPELL_FAILED_BM_OR_INVISGOD = "The spell cannot be cast on beastmaster or invis god targets.";
+SPELL_FAILED_CANT_BE_CHARMED = "Target can't be charmed";
+SPELL_FAILED_CANT_BE_DISENCHANTED = "Item cannot be disenchanted";
+SPELL_FAILED_CANT_BE_DISENCHANTED_SKILL = "Your Enchanting skill is not high enough to disenchant that";
+SPELL_FAILED_CANT_BE_MILLED = "You cannot mill that";
+SPELL_FAILED_CANT_BE_PROSPECTED = "There are no gems in this";
+SPELL_FAILED_CANT_CAST_ON_TAPPED = "Target is tapped";
+SPELL_FAILED_CANT_DO_THAT_RIGHT_NOW = "You can't do that right now.";
+SPELL_FAILED_CANT_DUEL_WHILE_INVISIBLE = "You can't start a duel while invisible";
+SPELL_FAILED_CANT_DUEL_WHILE_STEALTHED = "You can't start a duel while stealthed";
+SPELL_FAILED_CANT_STEALTH = "You are too close to enemies";
+SPELL_FAILED_CASTER_AURASTATE = "You can't do that yet";
+SPELL_FAILED_CASTER_DEAD = "You are dead";
+SPELL_FAILED_CASTER_DEAD_FEMALE = "You are dead";
+SPELL_FAILED_CAST_NOT_HERE = "You can't cast that here";
+SPELL_FAILED_CHARMED = "Can't do that while charmed";
+SPELL_FAILED_CHEST_IN_USE = "That is already being used";
+SPELL_FAILED_CONFUSED = "Can't do that while confused";
+SPELL_FAILED_CUSTOM_ERROR_1 = "Something bad happened, and we want to display a custom message!";
+SPELL_FAILED_CUSTOM_ERROR_10 = "You cannot summon another gargoyle yet.";
+SPELL_FAILED_CUSTOM_ERROR_11 = "Requires Corpse Dust if the target is not dead and humanoid.";
+SPELL_FAILED_CUSTOM_ERROR_12 = "Can only be placed near Shatterhorn";
+SPELL_FAILED_CUSTOM_ERROR_13 = "You must first select a Proto-Drake Egg.";
+SPELL_FAILED_CUSTOM_ERROR_14_NONE = "You must be close to a marked tree.";
+SPELL_FAILED_CUSTOM_ERROR_15 = "You must target a Fjord Turkey.";
+SPELL_FAILED_CUSTOM_ERROR_16 = "You must target a Fjord Hawk.";
+SPELL_FAILED_CUSTOM_ERROR_17 = "You are too far from the bouy.";
+SPELL_FAILED_CUSTOM_ERROR_18 = "Must be used near an oil slick.";
+SPELL_FAILED_CUSTOM_ERROR_19 = "You must be closer to the buoy!";
+SPELL_FAILED_CUSTOM_ERROR_2 = "Alex broke your quest! Thank him later!";
+SPELL_FAILED_CUSTOM_ERROR_20 = "You may only call for the aid of a Wyrmrest Vanquisher in Wyrmrest Temple, The Dragon Wastes, Galakrond's Rest or The Wicked Coil.";
+SPELL_FAILED_CUSTOM_ERROR_21 = "That can only be used on a Ice Heart Jormungar Spawn.";
+SPELL_FAILED_CUSTOM_ERROR_22 = "You must be closer to a sinkhole to use your map.";
+SPELL_FAILED_CUSTOM_ERROR_23 = "You may only call down a stampede on Harold Lane.";
+SPELL_FAILED_CUSTOM_ERROR_24 = "You may only use the Pouch of Crushed Bloodspore on Gammothra or other magnataur in the Bloodspore Plains and Gammoth.";
+SPELL_FAILED_CUSTOM_ERROR_25 = "Requires the magmawyrm resurrection chamber in the back of the Maw of Neltharion.";
+SPELL_FAILED_CUSTOM_ERROR_26 = "You may only call down a Wintergarde Gryphon in Wintergarde Keep or the Carrion Fields.";
+SPELL_FAILED_CUSTOM_ERROR_27 = "What are you doing? Only aim that thing at Wilhelm!";
+SPELL_FAILED_CUSTOM_ERROR_28 = "Not enough health!";
+SPELL_FAILED_CUSTOM_ERROR_29 = "There are no nearby corpses to use";
+SPELL_FAILED_CUSTOM_ERROR_3 = "This spell may only be used on Helpless Wintergarde Villagers that have not been rescued.";
+SPELL_FAILED_CUSTOM_ERROR_30 = "You've created enough ghouls. Return to Gothik the Harvester at Death's Breach.";
+SPELL_FAILED_CUSTOM_ERROR_31 = "Your companion does not want to come here. Go further from the Sundered Shard.";
+SPELL_FAILED_CUSTOM_ERROR_32 = "Must be in Cat Form";
+SPELL_FAILED_CUSTOM_ERROR_33 = "Only Death Knights may enter Ebon Hold.";
+SPELL_FAILED_CUSTOM_ERROR_34 = "Must be in Cat Form, Bear Form, or Dire Bear Form";
+SPELL_FAILED_CUSTOM_ERROR_35 = "You must be within range of a Helpless Wintergarde Villager.";
+SPELL_FAILED_CUSTOM_ERROR_36 = "You cannot target an elemental or mechanical corpse.";
+SPELL_FAILED_CUSTOM_ERROR_37 = "This teleport crystal cannot be used until the teleport crystal in Dalaran has been used at least once.";
+SPELL_FAILED_CUSTOM_ERROR_38 = "You are already holding something in your hand. You must throw the creature in your hand before picking up another.";
+SPELL_FAILED_CUSTOM_ERROR_39 = "You don't have anything to throw! Find a Vargul and use Gymer Grab to pick one up!";
+SPELL_FAILED_CUSTOM_ERROR_4 = "Requires that you be wearing the Warsong Orc Disguise.";
+SPELL_FAILED_CUSTOM_ERROR_40 = "Bouldercrag's War Horn can only be used within 10 yards of Valduran the Stormborn.";
+SPELL_FAILED_CUSTOM_ERROR_41 = "You are not carrying a passenger. There is nobody to drop off.";
+SPELL_FAILED_CUSTOM_ERROR_42 = "You cannot build any more siege vehicles.";
+SPELL_FAILED_CUSTOM_ERROR_43 = "You are already carrying a captured Argent Crusader. You must return to the Argent Vanguard infirmary and drop off your passenger before you may pick up another.";
+SPELL_FAILED_CUSTOM_ERROR_44 = "You can't do that while rooted.";
+SPELL_FAILED_CUSTOM_ERROR_45 = "Requires a nearby target.";
+SPELL_FAILED_CUSTOM_ERROR_46 = "Nothing left to discover.";
+SPELL_FAILED_CUSTOM_ERROR_47 = "No targets close enough to bluff.";
+SPELL_FAILED_CUSTOM_ERROR_48 = "Your Iron Rune Construct is out of range.";
+SPELL_FAILED_CUSTOM_ERROR_49 = "Requires Grand Master Engineer";
+SPELL_FAILED_CUSTOM_ERROR_5 = "You must be closer to a plague wagon in order to drop off your 7th Legion Siege Engineer.";
+SPELL_FAILED_CUSTOM_ERROR_50 = "You can't use that mount.";
+SPELL_FAILED_CUSTOM_ERROR_51 = "There is nobody to eject!";
+SPELL_FAILED_CUSTOM_ERROR_52 = "The target must be bound to you.";
+SPELL_FAILED_CUSTOM_ERROR_53 = "Target must be undead.";
+SPELL_FAILED_CUSTOM_ERROR_54 = "You have no target or your target is too far away.";
+SPELL_FAILED_CUSTOM_ERROR_55 = "Missing Reagents: Dark Matter";
+SPELL_FAILED_CUSTOM_ERROR_56 = "You can't use that item";
+SPELL_FAILED_CUSTOM_ERROR_57 = "You can't do that while Cycloned";
+SPELL_FAILED_CUSTOM_ERROR_58 = "Target is already affected by a scroll";
+SPELL_FAILED_CUSTOM_ERROR_59 = "That anti-venom is not strong enough to dispel that poison";
+SPELL_FAILED_CUSTOM_ERROR_6 = "You cannot target friendly units outside your party.";
+SPELL_FAILED_CUSTOM_ERROR_60 = "You must have a lance equipped.";
+SPELL_FAILED_CUSTOM_ERROR_61 = "You must be near the Maiden of Winter's Breath Lake.";
+SPELL_FAILED_CUSTOM_ERROR_62 = "You have learned everything from that book";
+SPELL_FAILED_CUSTOM_ERROR_63_NONE = "Your pet is dead";
+SPELL_FAILED_CUSTOM_ERROR_64_NONE = "There are no valid targets within range.";
+SPELL_FAILED_CUSTOM_ERROR_65 = "Only GMs may use that. Your account has been reported for investigation.";
+SPELL_FAILED_CUSTOM_ERROR_66 = "You must reach level 58 to use this portal.";
+SPELL_FAILED_CUSTOM_ERROR_67 = "You already have the maximum amount of honor.";
+SPELL_FAILED_CUSTOM_ERROR_7 = "You must target a weakened chill nymph.";
+SPELL_FAILED_CUSTOM_ERROR_75 = "You must have a demonic circle active.";
+SPELL_FAILED_CUSTOM_ERROR_76 = "You already have maximum rage";
+SPELL_FAILED_CUSTOM_ERROR_77 = "Requires Engineering (350)";
+SPELL_FAILED_CUSTOM_ERROR_78 = "Your soul belongs to the Lich King";
+SPELL_FAILED_CUSTOM_ERROR_79 = "Your attendant already has an Argent Pony";
+SPELL_FAILED_CUSTOM_ERROR_8 = "The Imbued Scourge Shroud will only work when equipped in the Temple City of En'kilah.";
+SPELL_FAILED_CUSTOM_ERROR_83 = "You must have a Fire Totem active.";
+SPELL_FAILED_CUSTOM_ERROR_84 = "You may not bite other vampires.";
+SPELL_FAILED_CUSTOM_ERROR_85 = "Your pet is already at your level.";
+SPELL_FAILED_CUSTOM_ERROR_86 = "You do not meet the level requirements for this item.";
+SPELL_FAILED_CUSTOM_ERROR_87 = "There are too many Mutated Abominations.";
+SPELL_FAILED_CUSTOM_ERROR_88 = "The potions have all been depleted by Professor Putricide.";
+SPELL_FAILED_CUSTOM_ERROR_9 = "Requires Corpse Dust";
+SPELL_FAILED_CUSTOM_ERROR_90 = "Requires level 65";
+SPELL_FAILED_CUSTOM_ERROR_96 = "You already have the max number of recruits.";
+SPELL_FAILED_CUSTOM_ERROR_97 = "You already have the max number of volunteers.";
+SPELL_FAILED_CUSTOM_ERROR_98 = "Frostmourne has rendered you unable to ressurect.";
+SPELL_FAILED_CUSTOM_ERROR_99 = "You can't mount while affected by that shapeshift.";
+SPELL_FAILED_DAMAGE_IMMUNE = "You can't do that while you are immune";
+SPELL_FAILED_EQUIPPED_ITEM = "Must have the proper item equipped";
+SPELL_FAILED_EQUIPPED_ITEM_CLASS = "Must have a %s equipped";
+SPELL_FAILED_EQUIPPED_ITEM_CLASS_MAINHAND = "Must have a %s equipped in the main hand";
+SPELL_FAILED_EQUIPPED_ITEM_CLASS_OFFHAND = "Must have a %s equipped in the offhand";
+SPELL_FAILED_ERROR = "Internal error";
+SPELL_FAILED_EXPERT_RIDING_REQUIREMENT = "Requires expert riding skill";
+SPELL_FAILED_FISHING_TOO_LOW = "Requires Fishing %d";
+SPELL_FAILED_FIZZLE = "Fizzled";
+SPELL_FAILED_FLEEING = "Can't do that while fleeing";
+SPELL_FAILED_FOOD_LOWLEVEL = "That food's level is not high enough for your pet";
+SPELL_FAILED_GLYPH_SOCKET_LOCKED = "You cannot inscribe a Glyph there yet.";
+SPELL_FAILED_HIGHLEVEL = "Target is too high level";
+SPELL_FAILED_IMMUNE = "Immune";
+SPELL_FAILED_INCORRECT_AREA = "You are in the wrong zone.";
+SPELL_FAILED_INTERRUPTED = "Interrupted";
+SPELL_FAILED_INTERRUPTED_COMBAT = "Interrupted";
+SPELL_FAILED_INVALID_GLYPH = "That Glyph cannot be inscribed there.";
+SPELL_FAILED_ITEM_ALREADY_ENCHANTED = "Item is already enchanted";
+SPELL_FAILED_ITEM_AT_MAX_CHARGES = "Item already has the maximum number of charges.";
+SPELL_FAILED_ITEM_ENCHANT_TRADE_WINDOW = "Item cannot be enchanted in trade";
+SPELL_FAILED_ITEM_GONE = "Item is gone";
+SPELL_FAILED_ITEM_NOT_FOUND = "Tried to enchant an item that didn't exist";
+SPELL_FAILED_ITEM_NOT_READY = "Item is not ready yet";
+SPELL_FAILED_LEVEL_REQUIREMENT = "You are not high enough level";
+SPELL_FAILED_LEVEL_REQUIREMENT_PET = "Your pet is not high enough level";
+SPELL_FAILED_LIMIT_CATEGORY_EXCEEDED = "You have too many of that item already";
+SPELL_FAILED_LINE_OF_SIGHT = "Target not in line of sight";
+SPELL_FAILED_LOWLEVEL = "Target is too low level";
+SPELL_FAILED_LOW_CASTLEVEL = "Skill not high enough";
+SPELL_FAILED_MAINHAND_EMPTY = "Your weapon hand is empty";
+SPELL_FAILED_MIN_SKILL = "Your skill is not high enough. Requires %s (%d).";
+SPELL_FAILED_MOVING = "Can't do that while moving";
+SPELL_FAILED_NEED_AMMO = "Ammo needs to be in the paper doll ammo slot before it can be fired.";
+SPELL_FAILED_NEED_AMMO_POUCH = "Requires: %s";
+SPELL_FAILED_NEED_EXOTIC_AMMO = "Requires exotic ammo: %s";
+SPELL_FAILED_NEED_MORE_ITEMS = "Requires %d %s.";
+SPELL_FAILED_NOPATH = "No path available";
+SPELL_FAILED_NOTHING_TO_DISPEL = "Nothing to dispel";
+SPELL_FAILED_NOTHING_TO_STEAL = "Nothing to steal";
+SPELL_FAILED_NOT_BEHIND = "You must be behind your target.";
+SPELL_FAILED_NOT_FISHABLE = "Your cast didn't land in fishable water";
+SPELL_FAILED_NOT_FLYING = "You are flying.";
+SPELL_FAILED_NOT_HERE = "You can't use that here.";
+SPELL_FAILED_NOT_IDLE = "Can't use while Idle";
+SPELL_FAILED_NOT_INACTIVE = "Can't use while Inactive";
+SPELL_FAILED_NOT_INFRONT = "You must be in front of your target.";
+SPELL_FAILED_NOT_IN_ARENA = "You can't do that in an arena.";
+SPELL_FAILED_NOT_IN_BARBERSHOP = "You can't do that while in the barber shop";
+SPELL_FAILED_NOT_IN_BATTLEGROUND = "You can't do that in a battleground.";
+SPELL_FAILED_NOT_IN_CONTROL = "You are not in control of your actions";
+SPELL_FAILED_NOT_IN_RAID_INSTANCE = "You can't do that in a raid instance.";
+SPELL_FAILED_NOT_KNOWN = "Spell not learned";
+SPELL_FAILED_NOT_MOUNTED = "You are mounted.";
+SPELL_FAILED_NOT_ON_DAMAGE_IMMUNE = "Spell cannot be cast on a damage immune target.";
+SPELL_FAILED_NOT_ON_GROUND = "Cannot use on the ground";
+SPELL_FAILED_NOT_ON_MOUNTED = "Spell cannot be cast on a mounted unit.";
+SPELL_FAILED_NOT_ON_SHAPESHIFT = "Cannot be cast on shapeshifted target.";
+SPELL_FAILED_NOT_ON_STEALTHED = "Spell cannot be cast on stealthed target.";
+SPELL_FAILED_NOT_ON_TAXI = "You are in flight";
+SPELL_FAILED_NOT_ON_TRANSPORT = "You are on a transport";
+SPELL_FAILED_NOT_READY = "Not yet recovered";
+SPELL_FAILED_NOT_SHAPESHIFT = "You are in shapeshift form";
+SPELL_FAILED_NOT_STANDING = "You must be standing to do that";
+SPELL_FAILED_NOT_TRADEABLE = "You can only use this on an object you own";
+SPELL_FAILED_NOT_TRADING = "Tried to enchant a trade item, but not trading";
+SPELL_FAILED_NOT_UNSHEATHED = "You must be unsheathed";
+SPELL_FAILED_NOT_WHILE_FATIGUED = "Can't cast while fatigued";
+SPELL_FAILED_NOT_WHILE_GHOST = "Can't cast as ghost";
+SPELL_FAILED_NOT_WHILE_LOOTING = "You are busy looting";
+SPELL_FAILED_NOT_WHILE_TRADING = "Can't cast while trading";
+SPELL_FAILED_NO_AMMO = "Out of ammo";
+SPELL_FAILED_NO_CHAMPION = "You haven't selected a champion";
+SPELL_FAILED_NO_CHARGES_REMAIN = "No charges remain";
+SPELL_FAILED_NO_COMBO_POINTS = "That ability requires combo points";
+SPELL_FAILED_NO_DUELING = "Dueling isn't allowed here.";
+SPELL_FAILED_NO_EDIBLE_CORPSES = "There are no nearby corpses to eat";
+SPELL_FAILED_NO_ENDURANCE = "Not enough endurance";
+SPELL_FAILED_NO_EVASIVE_CHARGES = "You need Evasive Charges";
+SPELL_FAILED_NO_FISH = "There aren't any fish here";
+SPELL_FAILED_NO_ITEMS_WHILE_SHAPESHIFTED = "Can't use items while shapeshifted";
+SPELL_FAILED_NO_MAGIC_TO_CONSUME = "No magic to consume";
+SPELL_FAILED_NO_MOUNTS_ALLOWED = "You can't mount here.";
+SPELL_FAILED_NO_PET = "You do not have a pet";
+SPELL_FAILED_NO_PLAYTIME = "You can not do this. You have more than 5 hours of online time";
+SPELL_FAILED_ONLY_ABOVEWATER = "Cannot use while swimming";
+SPELL_FAILED_ONLY_BATTLEGROUNDS = "Can only use in battlegrounds";
+SPELL_FAILED_ONLY_DAYTIME = "Can only use during the day";
+SPELL_FAILED_ONLY_INDOORS = "Can only use indoors";
+SPELL_FAILED_ONLY_IN_ARENA = "You can only do that in an arena.";
+SPELL_FAILED_ONLY_MOUNTED = "Can only use while mounted";
+SPELL_FAILED_ONLY_NIGHTTIME = "Can only use during the night";
+SPELL_FAILED_ONLY_OUTDOORS = "Can only use outside";
+SPELL_FAILED_ONLY_SHAPESHIFT = "Must be in %s";
+SPELL_FAILED_ONLY_STEALTHED = "You must be in stealth mode.";
+SPELL_FAILED_ONLY_UNDERWATER = "Can only use while swimming";
+SPELL_FAILED_OUT_OF_RANGE = "Out of range";
+SPELL_FAILED_PACIFIED = "Can't use that ability while pacified";
+SPELL_FAILED_PARTIAL_PLAYTIME = "You can not do this. You have more than 3 hours of online time. ";
+SPELL_FAILED_PET_CAN_RENAME = "You can already rename your pet";
+SPELL_FAILED_POSSESSED = "You are possessed";
+SPELL_FAILED_PREVENTED_BY_MECHANIC = "Can't do that while %s";
+SPELL_FAILED_REAGENTS = "Missing reagent: %s";
+SPELL_FAILED_REPUTATION = "Your reputation isn't high enough";
+SPELL_FAILED_REQUIRES_AREA = "You need to be in %s.";
+SPELL_FAILED_REQUIRES_SPELL_FOCUS = "Requires %s";
+SPELL_FAILED_ROCKET_PACK = "You're too far away from Zafod's Transponster! The rocket pack won't fire.";
+SPELL_FAILED_ROOTED = "You are unable to move";
+SPELL_FAILED_SILENCED = "Can't do that while silenced";
+SPELL_FAILED_SPELL_IN_PROGRESS = "Another action is in progress";
+SPELL_FAILED_SPELL_LEARNED = "You have already learned the spell";
+SPELL_FAILED_SPELL_UNAVAILABLE = "The spell is not available to you";
+SPELL_FAILED_SPELL_UNAVAILABLE_PET = "That ability is not available to your pet";
+SPELL_FAILED_STUNNED = "Can't do that while stunned";
+SPELL_FAILED_SUMMON_PENDING = "A summon is already pending";
+SPELL_FAILED_TARGETS_DEAD = "Your target is dead";
+SPELL_FAILED_TARGET_AFFECTING_COMBAT = "Target is in combat";
+SPELL_FAILED_TARGET_AURASTATE = "You can't do that yet";
+SPELL_FAILED_TARGET_CANNOT_BE_RESURRECTED = "Target cannot be resurrected";
+SPELL_FAILED_TARGET_DUELING = "Target is currently dueling";
+SPELL_FAILED_TARGET_ENEMY = "Target is hostile";
+SPELL_FAILED_TARGET_ENRAGED = "Target is too enraged to be charmed";
+SPELL_FAILED_TARGET_FREEFORALL = "Target is currently in free-for-all PvP combat";
+SPELL_FAILED_TARGET_FRIENDLY = "Target is friendly";
+SPELL_FAILED_TARGET_IN_COMBAT = "The target can't be in combat";
+SPELL_FAILED_TARGET_IS_PLAYER = "Can't target players";
+SPELL_FAILED_TARGET_IS_PLAYER_CONTROLLED = "Can't target player controlled units";
+SPELL_FAILED_TARGET_IS_TRIVIAL = "Can't target trivial";
+SPELL_FAILED_TARGET_LOCKED_TO_RAID_INSTANCE = "Target is locked to another raid instance";
+SPELL_FAILED_TARGET_NOT_DEAD = "Target is alive";
+SPELL_FAILED_TARGET_NOT_GHOST = "Target is not a ghost";
+SPELL_FAILED_TARGET_NOT_IN_INSTANCE = "Target must be in this instance";
+SPELL_FAILED_TARGET_NOT_IN_PARTY = "Target is not in your party";
+SPELL_FAILED_TARGET_NOT_IN_RAID = "Target is not in your party or raid group";
+SPELL_FAILED_TARGET_NOT_IN_SANCTUARY = "Target is not in a sanctuary";
+SPELL_FAILED_TARGET_NOT_LOOTED = "Creature must be looted first";
+SPELL_FAILED_TARGET_NOT_PLAYER = "Target is not a player";
+SPELL_FAILED_TARGET_NO_POCKETS = "No pockets to pick";
+SPELL_FAILED_TARGET_NO_RANGED_WEAPONS = "Target has no ranged weapons equipped";
+SPELL_FAILED_TARGET_NO_WEAPONS = "Target has no weapons equipped";
+SPELL_FAILED_TARGET_ON_TAXI = "Your target is in flight";
+SPELL_FAILED_TARGET_UNSKINNABLE = "Creature is not skinnable";
+SPELL_FAILED_TOO_CLOSE = "Target too close";
+SPELL_FAILED_TOO_MANY_OF_ITEM = "You have too many of that item already";
+SPELL_FAILED_TOO_SHALLOW = "Water too shallow";
+SPELL_FAILED_TOTEMS = "Requires %s";
+SPELL_FAILED_TOTEM_CATEGORY = "Requires %s";
+SPELL_FAILED_TRANSFORM_UNUSABLE = "You can't use the new item";
+SPELL_FAILED_TRY_AGAIN = "Failed attempt";
+SPELL_FAILED_UNIQUE_GLYPH = "That Glyph is already inscribed in your spellbook.";
+SPELL_FAILED_UNIT_NOT_BEHIND = "Target needs to be behind you.";
+SPELL_FAILED_UNIT_NOT_INFRONT = "Target needs to be in front of you.";
+SPELL_FAILED_UNKNOWN = "Unknown reason";
+SPELL_FAILED_WRONG_PET_FOOD = "Your pet doesn't like that food.";
+SPELL_FAILED_WRONG_WEATHER = "The weather isn't right for that";
+SPELL_HASTE = "Haste Rating";
+SPELL_HASTE_ABBR = "Haste";
+SPELL_HASTE_TOOLTIP = "Increases the speed that your spells cast by %.2f%%.";
+SPELL_HEAL_COMBATLOG_TOOLTIP = "Show messages when a spell or ability heals damage.";
+SPELL_INSTAKILL_COMBATLOG_TOOLTIP = "Show messages about special spell types, such as those that inflict durability loss or share damage with a pet.";
+SPELL_INSTANT_EFFECT = "Instant effect";
+SPELL_INTERRUPT_COMBATLOG_TOOLTIP = "Show messages when a spell or ability interrupts another spell.";
+SPELL_LASTING_EFFECT = "%s effect";
+SPELL_MESSAGES = "Spell Messages";
+SPELL_MISSED_COMBATLOG_TOOLTIP = "Show messages when a spell or ability fails to deal damage. This includes dodges, parries, blocks, deflections, immunes, absorbs and evades.";
+SPELL_NAMES = "Spell Names";
+SPELL_NAMES_COMBATLOG_TOOLTIP = "Color spell names.";
+SPELL_NAMES_SHOW_BRACES_COMBATLOG_TOOLTIP = "Show braces around spell names.";
+SPELL_NOT_SHAPESHIFTED = "Can't do that while shapeshifted.";
+SPELL_NOT_SHAPESHIFTED_NOSPACE = "Can't do that while shapeshifted.";
+SPELL_ON_NEXT_RANGED = "Attack speed";
+SPELL_ON_NEXT_SWING = "Next melee";
+SPELL_OTHER_MESSAGES = "Spell Messages (cont'd)";
+SPELL_PASSIVE = "Passive";
+SPELL_PASSIVE_EFFECT = "Passive";
+SPELL_PENETRATION = "Penetration";
+SPELL_PENETRATION_TOOLTIP = "Spell Penetration %d (Reduces enemy resistances by %d)";
+SPELL_PERIODIC_COMBATLOG_TOOLTIP = "Show spells that perform an effect incrementally.";
+SPELL_PERIODIC_DAMAGE_COMBATLOG_TOOLTIP = "Show messages when a spell or ability periodically deals damage, such as Shadow Word: Pain or Corruption.";
+SPELL_PERIODIC_HEAL_COMBATLOG_TOOLTIP = "Show messages when a spell or ability periodically heals damage, such as Renew or Rejuvenation.";
+SPELL_PERIODIC_MISSED_COMBATLOG_TOOLTIP = "Show messages when a spell or ability fails to periodically deal damage. This includes immunes, absorbs and evades.";
+SPELL_PERIODIC_OTHER_COMBATLOG_TOOLTIP = "Show messages when a spell or ability periodically performs any other effect, such as restoring or draining mana.";
+SPELL_POINTS_SPREAD_TEMPLATE = "%.1f to %.1f";
+SPELL_RANGE = "%s yd range";
+SPELL_RANGE_AREA = "Area around caster";
+SPELL_RANGE_DUAL = "%1$s: %2$s yd range";
+SPELL_RANGE_UNLIMITED = "Unlimited range";
+SPELL_REAGENTS = "Reagents: |n";
+SPELL_RECAST_TIME_INSTANT = "Instant cooldown";
+SPELL_RECAST_TIME_MIN = "%.3g min cooldown";
+SPELL_RECAST_TIME_SEC = "%.3g sec cooldown";
+SPELL_REQUIRED_FORM = "Requires %s";
+SPELL_REQUIRED_FORM_NOSPACE = "Requires %s";
+SPELL_RESURRECT_COMBATLOG_TOOLTIP = "Show messages when a spell or ability resurrects another player or creature.";
+SPELL_SCHOOL0_CAP = "Physical";
+SPELL_SCHOOL0_NAME = "physical";
+SPELL_SCHOOL1_CAP = "Holy";
+SPELL_SCHOOL1_NAME = "holy";
+SPELL_SCHOOL2_CAP = "Fire";
+SPELL_SCHOOL2_NAME = "fire";
+SPELL_SCHOOL3_CAP = "Nature";
+SPELL_SCHOOL3_NAME = "nature";
+SPELL_SCHOOL4_CAP = "Frost";
+SPELL_SCHOOL4_NAME = "frost";
+SPELL_SCHOOL5_CAP = "Shadow";
+SPELL_SCHOOL5_NAME = "shadow";
+SPELL_SCHOOL6_CAP = "Arcane";
+SPELL_SCHOOL6_NAME = "arcane";
+SPELL_SCHOOLALL = "all";
+SPELL_SCHOOLMAGICAL = "magical";
+SPELL_SKILL_LINE = "%s";
+SPELL_STAT1_NAME = "Strength";
+SPELL_STAT2_NAME = "Agility";
+SPELL_STAT3_NAME = "Stamina";
+SPELL_STAT4_NAME = "Intellect";
+SPELL_STAT5_NAME = "Spirit";
+SPELL_STATALL = "all stats";
+SPELL_SUMMON_COMBATLOG_TOOLTIP = "Show messages when a spell or ability summons a creature or creates an object.";
+SPELL_TARGET_CENTER_CASTER = "caster";
+SPELL_TARGET_CENTER_LOC = "target location";
+SPELL_TARGET_CHAIN_TEMPLATE = "Target %s, chains up to %d";
+SPELL_TARGET_CONE_TEMPLATE = "Target %s in %d yd cone from %s";
+SPELL_TARGET_CREATURE_TYPE12_DESC = "all %s";
+SPELL_TARGET_CREATURE_TYPE13_DESC = "enemy %s";
+SPELL_TARGET_CREATURE_TYPE1_DESC = "%s";
+SPELL_TARGET_CREATURE_TYPE2_DESC = "friendly %s";
+SPELL_TARGET_CREATURE_TYPE3_DESC = "enemy %s";
+SPELL_TARGET_CREATURE_TYPE8_DESC = "%s pet";
+SPELL_TARGET_CREATURE_TYPE_DEAD12_DESC = "all dead %s";
+SPELL_TARGET_CREATURE_TYPE_DEAD13_DESC = "dead enemy %s";
+SPELL_TARGET_CREATURE_TYPE_DEAD1_DESC = "dead %s";
+SPELL_TARGET_CREATURE_TYPE_DEAD2_DESC = "dead friendly %s";
+SPELL_TARGET_CREATURE_TYPE_DEAD3_DESC = "dead enemy %s";
+SPELL_TARGET_CREATURE_TYPE_DEAD8_DESC = "dead %s pet";
+SPELL_TARGET_MULTIPLE_TEMPLATE = "Target %s within %d yd of %s";
+SPELL_TARGET_TEMPLATE = "Target %s";
+SPELL_TARGET_TYPE0_DESC = "caster";
+SPELL_TARGET_TYPE10_DESC = "off-hand item";
+SPELL_TARGET_TYPE11_DESC = "party";
+SPELL_TARGET_TYPE12_DESC = "all";
+SPELL_TARGET_TYPE13_DESC = "enemies";
+SPELL_TARGET_TYPE14_DESC = "party members";
+SPELL_TARGET_TYPE15_DESC = "master";
+SPELL_TARGET_TYPE16_DESC = "raid member";
+SPELL_TARGET_TYPE17_DESC = "raid members";
+SPELL_TARGET_TYPE1_DESC = "any";
+SPELL_TARGET_TYPE2_DESC = "friendly";
+SPELL_TARGET_TYPE3_DESC = "enemy";
+SPELL_TARGET_TYPE4_DESC = "party member";
+SPELL_TARGET_TYPE5_DESC = "item";
+SPELL_TARGET_TYPE6_DESC = "location";
+SPELL_TARGET_TYPE7_DESC = "object";
+SPELL_TARGET_TYPE8_DESC = "pet";
+SPELL_TARGET_TYPE9_DESC = "main-hand item";
+SPELL_TARGET_TYPE_DEAD11_DESC = "dead party members";
+SPELL_TARGET_TYPE_DEAD12_DESC = "all dead";
+SPELL_TARGET_TYPE_DEAD13_DESC = "dead enemies";
+SPELL_TARGET_TYPE_DEAD14_DESC = "dead party members";
+SPELL_TARGET_TYPE_DEAD16_DESC = "dead raid member";
+SPELL_TARGET_TYPE_DEAD17_DESC = "dead raid members";
+SPELL_TARGET_TYPE_DEAD1_DESC = "dead";
+SPELL_TARGET_TYPE_DEAD2_DESC = "dead friendly";
+SPELL_TARGET_TYPE_DEAD3_DESC = "dead enemy";
+SPELL_TARGET_TYPE_DEAD4_DESC = "dead party member";
+SPELL_TARGET_TYPE_DEAD8_DESC = "dead pet";
+SPELL_TIMER = "%s Failed: You haven't recovered yet.";
+SPELL_TIME_REMAINING_DAYS = "%d |4day:days; remaining";
+SPELL_TIME_REMAINING_HOURS = "%d |4hour:hours; remaining";
+SPELL_TIME_REMAINING_MIN = "%d |4minute:minutes; remaining";
+SPELL_TIME_REMAINING_SEC = "%d |4second:seconds; remaining";
+SPELL_TOTEMS = "Tools: ";
+SPELL_USE_ALL_ENERGY = "Uses 100% Energy";
+SPELL_USE_ALL_FOCUS = "Uses 100% focus";
+SPELL_USE_ALL_HEALTH = "Uses 100% health";
+SPELL_USE_ALL_MANA = "Uses 100% mana";
+SPELL_USE_ALL_POWER_DISPLAY = "Uses 100% %s";
+SPELL_USE_ALL_RAGE = "Uses 100% rage";
+SPI = "Spi";
+SPIRIT_COLON = "Spirit:";
+SPIRIT_HEALER_RELEASE_RED = "|cffff2020Spirit Healer|r";
+SPIRIT_TOOLTIP = "Increases Health and Mana regeneration rates. Spirit affects all\ncharacters' Mana and Hit Point regeneration rates in and\nout of combat.";
+STA = "Sta";
+STABLED_PETS = "Stabled Pets:";
+STABLES = "Stables";
+STABLE_PET_INFO_TEXT = "%1$s Level %2$d %3$s|n%4$s";
+STABLE_PET_INFO_TOOLTIP_TEXT = "Level %1$d %2$s|n%3$s";
+STABLE_SLOT_TEXT = "Do you wish to purchase another stable slot?";
+STACKS = "%d |4Stack:Stacks;";
+STAMINA_COLON = "Stamina:";
+STAMINA_TOOLTIP = "Increases health points";
+STANDING = "Standing";
+START = "Start";
+STARTING_PRICE = "Starting Price";
+STARTUP_TEXT_LINE1 = "Type '/help for a listing of a few commands.";
+STARTUP_TEXT_LINE2 = "";
+STARTUP_TEXT_LINE3 = "";
+STARTUP_TEXT_LINE4 = "";
+STATISTICS = "Statistics";
+STATS_LABEL = "Stats:";
+STATUS = "Status";
+STATUSTEXT_LABEL = "Status Text";
+STATUSTEXT_SUBTEXT = "These options allow you to display detailed information on status bars throughout the game.";
+STATUS_BAR_TEXT = "Status Bar Text";
+STATUS_TEXT = "Status Text";
+STATUS_TEXT_PARTY = "Party";
+STATUS_TEXT_PERCENT = "Display Percentages";
+STATUS_TEXT_PET = "Pet";
+STATUS_TEXT_PLAYER = "Player";
+STATUS_TEXT_TARGET = "Target";
+STAT_ATTACK_POWER = "Increases Attack Power by %d\n";
+STAT_BLOCK = "Block";
+STAT_BLOCK_TOOLTIP = "Increases Block Value by %d";
+STAT_DODGE = "Dodge";
+STAT_EXPERTISE = "Expertise";
+STAT_FORMAT = "%s:";
+STAT_PARRY = "Parry";
+STAT_RESILIENCE = "Resilience";
+STAT_TEMPLATE = "%s Stats";
+STEREO_HARDWARE_CURSOR = "Hardware Cursor";
+STEREO_VIDEO_LABEL = "Stereo";
+STEREO_VIDEO_SUBTEXT = "These options allow you to change details having to do with stereoscopic (3D) viewing.";
+STOPWATCH_TIME_UNIT = "%02d";
+STOPWATCH_TITLE = "Stopwatch";
+STOP_AUTO_ATTACK = "Stop Auto Attack";
+STOP_IGNORE = "Remove Player";
+STR = "Str";
+STRENGTH_COLON = "Strength:";
+STRENGTH_TOOLTIP = "Adds to your Attack Power, Damage-Per-Second. Strength\ndoes not affect Critical Hit chances at all. Strength does\nnot improve your chance to block, but rather the amount\nblocked when you succeed. This amount is determined in\npart by Strength (and the other part by your shield). ";
+STRING_ENVIRONMENTAL_DAMAGE_DROWNING = "Drowning";
+STRING_ENVIRONMENTAL_DAMAGE_FALLING = "Falling";
+STRING_ENVIRONMENTAL_DAMAGE_FATIGUE = "Fatigue";
+STRING_ENVIRONMENTAL_DAMAGE_FIRE = "Fire";
+STRING_ENVIRONMENTAL_DAMAGE_LAVA = "Lava";
+STRING_ENVIRONMENTAL_DAMAGE_SLIME = "Slime";
+STRING_SCHOOL_ARCANE = "Arcane";
+STRING_SCHOOL_CHAOS = "Chaos";
+STRING_SCHOOL_CHROMATIC = "Chromatic";
+STRING_SCHOOL_DIVINE = "Divine";
+STRING_SCHOOL_ELEMENTAL = "Elemental";
+STRING_SCHOOL_FIRE = "Fire";
+STRING_SCHOOL_FIRESTORM = "Firestorm";
+STRING_SCHOOL_FLAMESTRIKE = "Flamestrike";
+STRING_SCHOOL_FROST = "Frost";
+STRING_SCHOOL_FROSTFIRE = "Frostfire";
+STRING_SCHOOL_FROSTSTORM = "Froststorm";
+STRING_SCHOOL_FROSTSTRIKE = "Froststrike";
+STRING_SCHOOL_HOLY = "Holy";
+STRING_SCHOOL_HOLYFIRE = "Holyfire";
+STRING_SCHOOL_HOLYFROST = "Holyfrost";
+STRING_SCHOOL_HOLYSTORM = "Holystorm";
+STRING_SCHOOL_HOLYSTRIKE = "Holystrike";
+STRING_SCHOOL_MAGIC = "Magic";
+STRING_SCHOOL_NATURE = "Nature";
+STRING_SCHOOL_PHYSICAL = "Physical";
+STRING_SCHOOL_SHADOW = "Shadow";
+STRING_SCHOOL_SHADOWFLAME = "Shadowflame";
+STRING_SCHOOL_SHADOWFROST = "Shadowfrost";
+STRING_SCHOOL_SHADOWHOLY = "Twilight";
+STRING_SCHOOL_SHADOWLIGHT = "Twilight";
+STRING_SCHOOL_SHADOWSTORM = "Plague";
+STRING_SCHOOL_SHADOWSTRIKE = "Shadowstrike";
+STRING_SCHOOL_SPELLFIRE = "Spellfire";
+STRING_SCHOOL_SPELLFROST = "Spellfrost";
+STRING_SCHOOL_SPELLSHADOW = "Spellshadow";
+STRING_SCHOOL_SPELLSTORM = "Spellstorm";
+STRING_SCHOOL_SPELLSTRIKE = "Spellstrike";
+STRING_SCHOOL_STORMSTRIKE = "Stormstrike";
+STRING_SCHOOL_UNKNOWN = "Unknown";
+STUCK_BUTTON2_TEXT = "Still not working, Page a GM";
+STUCK_BUTTON_TEXT = "Auto-Unstuck";
+STUN = "Stun";
+STUNNED = "Stunned";
+STUN_CAPS = "STUN";
+SUBCATEGORY = "Subcategory";
+SUBMIT = "Submit";
+SUCCESS = "Success";
+SUGGESTFRAME_TITLE = "Suggestions and Bugs";
+SUGGEST_SUBMITTED = "Suggestion submitted";
+SUGGEST_SUBMIT_FAILED = "Suggestion submission failed";
+SUGGEST_TOOLTIP_TEXT = "Please enter your bug or suggestion here.\nYour name, race, class, level, and location\nwill be automatically submitted.";
+SUMMARY_ACHIEVEMENT_INCOMPLETE = "Achievement Incomplete";
+SUMMARY_ACHIEVEMENT_INCOMPLETE_TEXT = "Satisfy the requirements for each achievement to gain points, rewards, and glory!";
+SUMMON = "Summon";
+SUMMONS = "Summons";
+SWING_DAMAGE_COMBATLOG_TOOLTIP = "Shows melee swings that deal full or partial damage.";
+SWING_MISSED_COMBATLOG_TOOLTIP = "Show melee swings that do not deal damage.";
+SYSTEM_DEFAULT = "System Default";
+SYSTEM_MESSAGES = "System Messages";
+TABARDSLOT = "Tabard";
+TABARDVENDORALREADYSETGREETING = "You already have a tabard, but feel free to browse.";
+TABARDVENDORCOST = "Cost:";
+TABARDVENDORGREETING = "Greetings! Choose the symbol and colors of your guild.";
+TABARDVENDORNOGUILDGREETING = "You must be a guild master to purchase a tabard, but feel free to browse.";
+TAKE_ATTACHMENTS = "Take Attachments:";
+TAKE_GM_SURVEY = "Would you like to take the time to fill out our GM performance survey?";
+TALENTS = "Talents";
+TALENTS_BUTTON = "Talents";
+TALENTS_INVOLUNTARILY_RESET = "Your talents have been reset.";
+TALENTS_INVOLUNTARILY_RESET_PET = "Your pet's talents have been reset.";
+TALENT_ACTIVE_SPEC_STATUS = "These are your active talents";
+TALENT_POINTS = "Talent Points";
+TALENT_POINTS_TOOLTIP = "Talent Points are spent through the talent interface and are used\nto acquire special talents that improve your ability to fight.";
+TALENT_SPECTAB_TOOLTIP_ACTIVE = "These are your active talents";
+TALENT_SPECTAB_TOOLTIP_POINTS_SPENT = "%1$s%2$s: %3$s%4$d points|r";
+TALENT_SPEC_ACTIVATE = "Activate These Talents";
+TALENT_SPEC_PET_PRIMARY = "Pet Talents";
+TALENT_SPEC_PRIMARY = "Primary Talents";
+TALENT_SPEC_PRIMARY_GLYPH = "Primary Glyphs";
+TALENT_SPEC_SECONDARY = "Secondary Talents";
+TALENT_SPEC_SECONDARY_GLYPH = "Secondary Glyphs";
+TALENT_TOOLTIP_ADDPREVIEWPOINT = "Left click to add a point";
+TALENT_TOOLTIP_LEARNTALENTGROUP = "Click to finalize your preview talent points.";
+TALENT_TOOLTIP_REMOVEPREVIEWPOINT = "Right click to remove a point";
+TALENT_TOOLTIP_RESETTALENTGROUP = "Click to reset your preview talent points.";
+TALENT_TRAINER = "Talent Trainer";
+TAMEABLE = "Tameable";
+TAMEABLE_EXOTIC = "Tameable (Exotic)";
+TANK = "Tank";
+TARGET = "Target";
+TARGETFOCUS = "Target Focused Unit";
+TARGETICONS = "Target Icons";
+TARGET_ICON_SET = "|Hplayer:%s|h[%s]|h sets |TInterface\\TargetingFrame\\UI-RaidTargetingIcon_%d:0|t on %s.";
+TARGET_TOKEN_NOT_FOUND = "";
+TASKS_COLON = "Tasks:";
+TAXINODEYOUAREHERE = "You are here";
+TAXISAMENODE = "You are already there!";
+TEAM = "Team";
+TEAM_KICK = "Remove from Team";
+TEAM_LEAVE = "Leave Team";
+TEAM_PROMOTE = "Promote to Captain";
+TEAM_SKILL_TOOLTIP = "Matchmaking Value is the number that was used to find an oppenent for this match.";
+TELEPORT_OUT_OF_DUNGEON = "Teleport Out Of Dungeon";
+TELEPORT_TO_DUNGEON = "Teleport To Dungeon";
+TERRAIN_HIGHLIGHTS = "Specular Lighting";
+TERRAIN_MIP = "Terrain Blending";
+TEST_TAG_TEST = "do not translate";
+TEXTURE_DETAIL = "Texture Resolution";
+TEXT_MODE_A = "A";
+TEXT_MODE_A_STRING_1 = "%s %s %s %s %s. %s";
+TEXT_MODE_A_STRING_2 = "%1$s %3$s %2$s %4$s %5$s. %6$s";
+TEXT_MODE_A_STRING_3 = "%1$s %5$s %3$s %4$s %2$s. %6$s";
+TEXT_MODE_A_STRING_4 = "$timestamp $source $spell $action $dest $value.$result";
+TEXT_MODE_A_STRING_5 = "$timestamp $source $spell $action $dest $value.$result";
+TEXT_MODE_A_STRING_ACTION = "|Haction:%s|h%s|h";
+TEXT_MODE_A_STRING_BRACE_ITEM = "|c%s[|r%s|c%s]|r";
+TEXT_MODE_A_STRING_BRACE_SPELL = "|c%s[|r%s|c%s]|r";
+TEXT_MODE_A_STRING_BRACE_UNIT = "|c%s[|r%s|c%s]|r";
+TEXT_MODE_A_STRING_DEST = "$destIcon$destString";
+TEXT_MODE_A_STRING_DEST_ICON = "|Hicon:%d:dest|h%s|h";
+TEXT_MODE_A_STRING_DEST_UNIT = "%s|Hunit:%s:%s|h%s|h";
+TEXT_MODE_A_STRING_ITEM = "|Hitem:%s|h%s|h";
+TEXT_MODE_A_STRING_POSSESSIVE = "%s's";
+TEXT_MODE_A_STRING_POSSESSIVE_STRING = "'s";
+TEXT_MODE_A_STRING_RESULT = " ($resultString)";
+TEXT_MODE_A_STRING_RESULT_ABSORB = "(%d Absorbed)";
+TEXT_MODE_A_STRING_RESULT_BLOCK = "(%d Blocked)";
+TEXT_MODE_A_STRING_RESULT_CRITICAL = "(Critical)";
+TEXT_MODE_A_STRING_RESULT_CRITICAL_SPELL = "(Critical)";
+TEXT_MODE_A_STRING_RESULT_CRUSHING = "(Crushing)";
+TEXT_MODE_A_STRING_RESULT_FORMAT = "$resultAmount $resultType";
+TEXT_MODE_A_STRING_RESULT_GLANCING = "(Glancing)";
+TEXT_MODE_A_STRING_RESULT_OVERHEALING = "(%d Overhealed)";
+TEXT_MODE_A_STRING_RESULT_OVERKILLING = "(%d Overkill)";
+TEXT_MODE_A_STRING_RESULT_REFLECT = "Reflected";
+TEXT_MODE_A_STRING_RESULT_RESIST = "(%d Resisted)";
+TEXT_MODE_A_STRING_RESULT_VULNERABILITY = "(%d Vulnerability Damage)";
+TEXT_MODE_A_STRING_SOURCE = "$sourceIcon$sourceString";
+TEXT_MODE_A_STRING_SOURCE_ICON = "|Hicon:%s:source|h%s|h";
+TEXT_MODE_A_STRING_SOURCE_UNIT = "%s|Hunit:%s:%s|h%s|h";
+TEXT_MODE_A_STRING_SPELL = "|Hspell:%s:%s|h%s|h";
+TEXT_MODE_A_STRING_SPELL_EXTRA = "|Hspell:%s:%s|h%s|h";
+TEXT_MODE_A_STRING_SPELL_EXTRA_LINK = "|Hspell:%s:%s|h%s|h (SpellID:%d)";
+TEXT_MODE_A_STRING_SPELL_LINK = "|Hspell:%s:%s|h%s|h (SpellID:%d)";
+TEXT_MODE_A_STRING_TIMESTAMP = "%s> %s";
+TEXT_MODE_A_STRING_TOKEN_ICON = "$icon";
+TEXT_MODE_A_STRING_VALUE = "$amount$amountType";
+TEXT_MODE_A_STRING_VALUE_SCHOOL = "%s %s";
+TEXT_MODE_A_STRING_VALUE_TYPE = "%s (%s)";
+TEXT_MODE_A_TIMESTAMP = "%H:%M:%S";
+THIS_DUNGEON_IN_PROGRESS = "This Dungeon is In Progress.";
+THREAT_TOOLTIP = "%d%% Threat";
+TICKET_STATUS = "You have an open ticket.";
+TICKET_TYPE1 = "Game Play";
+TICKET_TYPE2 = "Harassment";
+TICKET_TYPE3 = "Stuck";
+TICKET_TYPE4 = "Bug";
+TIMEMANAGER_12HOUR = "%d";
+TIMEMANAGER_24HOUR = "%02d";
+TIMEMANAGER_24HOURMODE = "24 Hour Mode";
+TIMEMANAGER_ALARM_DISABLED = "Alarm Disabled";
+TIMEMANAGER_ALARM_ENABLED = "Alarm Enabled";
+TIMEMANAGER_ALARM_MESSAGE = "Alarm Message";
+TIMEMANAGER_ALARM_TIME = "Alarm Time";
+TIMEMANAGER_ALARM_TOOLTIP_TURN_OFF = "Click to turn off alarm.";
+TIMEMANAGER_AM = "AM";
+TIMEMANAGER_LOCALTIME = "Use Local Time";
+TIMEMANAGER_MINUTE = "%02d";
+TIMEMANAGER_PM = "PM";
+TIMEMANAGER_SHOW_STOPWATCH = "Show Stopwatch";
+TIMEMANAGER_TICKER_12HOUR = "%d:%02d";
+TIMEMANAGER_TICKER_24HOUR = "%02d:%02d";
+TIMEMANAGER_TITLE = "Clock";
+TIMEMANAGER_TOOLTIP_LOCALTIME = "Local time:";
+TIMEMANAGER_TOOLTIP_REALMTIME = "Realm time:";
+TIMEMANAGER_TOOLTIP_TITLE = "Time Info";
+TIMESTAMPS_LABEL = "Chat Timestamps|TInterface\\OptionsFrame\\UI-OptionsFrame-NewFeatureIcon:0:0:0:-1|t";
+TIMESTAMP_COMBATLOG_TOOLTIP = "Display the timestamp for combat log messages.";
+TIMESTAMP_FORMAT_HHMM = "%I:%M ";
+TIMESTAMP_FORMAT_HHMMSS = "%I:%M:%S ";
+TIMESTAMP_FORMAT_HHMMSS_24HR = "%H:%M:%S ";
+TIMESTAMP_FORMAT_HHMMSS_AMPM = "%I:%M:%S %p ";
+TIMESTAMP_FORMAT_HHMM_24HR = "%H:%M ";
+TIMESTAMP_FORMAT_HHMM_AMPM = "%I:%M %p ";
+TIMESTAMP_FORMAT_NONE = "None";
+TIME_DAYHOURMINUTESECOND = "%d |4day:days;, %d |4hour:hours;, %d |4minute:minutes;, %d |4second:seconds;";
+TIME_ELAPSED = "Time Elapsed:";
+TIME_IN_QUEUE = "Time In Queue: %s";
+TIME_PLAYED_LEVEL = "Time played this level: %s";
+TIME_PLAYED_MSG = "Time Played";
+TIME_PLAYED_TOTAL = "Total time played: %s";
+TIME_REMAINING = "Time Remaining:";
+TIME_TEMPLATE_LONG = "%d days, %d hours, %d minutes, %d seconds";
+TIME_TO_PORT = "Battleground closing in";
+TIME_TO_PORT_ARENA = "Arena closing in";
+TIME_TWELVEHOURAM = "%d:%02d AM";
+TIME_TWELVEHOURPM = "%d:%02d PM";
+TIME_TWENTYFOURHOURS = "%d:%02d";
+TIME_UNIT_DELIMITER = " ";
+TIME_UNKNOWN = "Unknown";
+TIME_UNTIL_DELETED = "Time until message is deleted";
+TIME_UNTIL_RETURNED = "Time until message is returned";
+TITLE_DOESNT_EXIST = "You don't have that title.";
+TITLE_REWARD = "Reward: %s";
+TITLE_TEMPLATE = "%s of the %s";
+TOAST_DURATION_TEXT = "Toast Duration";
+TOGGLESTICKYCAMERA = "Toggle Camera Lock";
+TOGGLE_BATTLEFIELDMINIMAP_TOOLTIP = "Toggle on/off the in game Zone Map. Shortcut: Shift-M";
+TOKENS = "Tokens";
+TOKEN_MOVE_TO_UNUSED = "Moves this currency to the bottom of your list under the unused heading. Useful for currencies you are no longer interested in tracking.";
+TOKEN_OPTIONS = "Currency Options";
+TOKEN_SHOW_ON_BACKPACK = "Checking this option will allow you to track this currency type on your backpack.\n\nYou can also Shift-click a currency to add or remove it from your backpack.";
+TOOLTIP_ARENA_POINTS = "Arena Points are gained by being victorious in arena combat. You can trade in these arena points for fabulous prizes!";
+TOOLTIP_HONOR_POINTS = "Honor is gained by killing members of the opposite faction in PvP combat. You can use honor points to purchase special items.";
+TOOLTIP_RAID_CLASS_BUTTON = "Click and drag this button to create a raid window for this class.";
+TOOLTIP_RAID_CONTROL_TIP = "CTRL Drag - for Class";
+TOOLTIP_RAID_DRAG_TIP = "Click and drag to create a single raid window for this player.";
+TOOLTIP_RAID_SHIFT_TIP = "Hold down the SHIFT key and drag to create a single raid window for this player.";
+TOOLTIP_TALENT_LEARN = "Click to learn";
+TOOLTIP_TALENT_NEXT_RANK = "Next rank:";
+TOOLTIP_TALENT_PREREQ = "Requires %1$d |4point:points; in %2$s";
+TOOLTIP_TALENT_RANK = "Rank %d/%d";
+TOOLTIP_TALENT_TIER_POINTS = "Requires %1$d points in %2$s Talents";
+TOOLTIP_TRACKER_FILTER_ACHIEVEMENTS = "Uncheck this to hide tracked achievements.";
+TOOLTIP_TRACKER_FILTER_COMPLETED_QUESTS = "Uncheck this to hide completed quests.";
+TOOLTIP_TRACKER_FILTER_REMOTE_ZONES = "Uncheck this to hide quests that are not in your current zone.";
+TOOLTIP_TRACKER_SORT_DIFFICULTY_HIGH = "Check this to sort quests in decreasing order of difficulty.";
+TOOLTIP_TRACKER_SORT_DIFFICULTY_LOW = "Check this to sort quests in increasing order of difficulty.";
+TOOLTIP_TRACKER_SORT_MANUAL = "Check this to be able to list the quests in any order you want.";
+TOOLTIP_TRACKER_SORT_PROXIMITY = "Check this to sort quests by the distance from their map locations to you.";
+TOOLTIP_UNIT_LEVEL = "Level %s";
+TOOLTIP_UNIT_LEVEL_CLASS = "Level %s %s";
+TOOLTIP_UNIT_LEVEL_CLASS_TYPE = "Level %s %s (%s)";
+TOOLTIP_UNIT_LEVEL_RACE_CLASS = "Level %s %s %s";
+TOOLTIP_UNIT_LEVEL_RACE_CLASS_TYPE = "Level %s %s %s (%s)";
+TOOLTIP_UNIT_LEVEL_TYPE = "Level %s (%s)";
+TOO_FAR_TO_LOOT = "You are too far away to loot that corpse!";
+TOO_MANY_LUA_ERRORS = "Your AddOns are experiencing a large number of errors and may be slowing down the game. You can turn on display of Lua errors in the interface options.";
+TOO_MANY_WATCHED_TOKENS = "You may only watch %d currencies at a time";
+TOTAL_MEM_KB_ABBR = "AddOn Memory: %.0f KB";
+TOTAL_MEM_MB_ABBR = "AddOn Memory: %.2f MB";
+TRACKER_FILTER_ACHIEVEMENTS = "Achievements";
+TRACKER_FILTER_COMPLETED_QUESTS = "Completed Quests";
+TRACKER_FILTER_LABEL = "Display";
+TRACKER_FILTER_REMOTE_ZONES = "Remote Zones";
+TRACKER_SORT_DIFFICULTY_HIGH = "Difficulty High";
+TRACKER_SORT_DIFFICULTY_LOW = "Difficulty Low";
+TRACKER_SORT_LABEL = "Sort Quests";
+TRACKER_SORT_MANUAL = "Manual";
+TRACKER_SORT_MANUAL_BOTTOM = "Move to Bottom";
+TRACKER_SORT_MANUAL_DOWN = "Move Down";
+TRACKER_SORT_MANUAL_TOP = "Move to Top";
+TRACKER_SORT_MANUAL_UP = "Move Up";
+TRACKER_SORT_MANUAL_WARNING = "Quest sorting changed to Manual";
+TRACKER_SORT_PROXIMITY = "Proximity";
+TRACK_ACHIEVEMENT = "Track";
+TRACK_ACHIEVEMENT_TOOLTIP = "Check to track this achievement.";
+TRACK_QUEST = "Track Quest";
+TRACK_QUEST_ABBREV = "Track";
+TRADE = "Trade";
+TRADEFRAME_ENCHANT_SLOT_LABEL = "Will not be traded";
+TRADEFRAME_NOT_MODIFIED_TEXT = "Item not yet modified";
+TRADESKILLS = "Tradeskills";
+TRADESKILL_LOG_FIRSTPERSON = "You create %s.";
+TRADESKILL_LOG_THIRDPERSON = "%s creates %s.";
+TRADESKILL_SERVICE_LEARN = "Recipes";
+TRADESKILL_SERVICE_PASSIVE = "Passive";
+TRADESKILL_SERVICE_STEP = "Development Skills";
+TRADE_POTENTIAL_BIND_ENCHANT = "Having this item enchanted will bind it to you.";
+TRADE_SKILLS = "Professions";
+TRADE_SKILL_TITLE = "%s";
+TRADE_WITH_QUESTION = "Trade with %s?";
+TRAIN = "Train";
+TRAINER_CAST_TIME_INSTANT = "Cast time: |cffffffffInstant|r";
+TRAINER_CAST_TIME_MIN = "Cast time: |cffffffff%d min|r";
+TRAINER_CAST_TIME_SEC = "Cast time: |cffffffff%d sec|r";
+TRAINER_COOLDOWN_TIME_INSTANT = "Cooldown: |cffffffffInstant|r";
+TRAINER_COOLDOWN_TIME_MIN = "Cooldown: |cffffffff%d min|r";
+TRAINER_COOLDOWN_TIME_SEC = "Cooldown: |cffffffff%d sec|r";
+TRAINER_COST_SP = "|cffffffff%d|r Skill points";
+TRAINER_COST_SP_RED = "|cffff2020%d|r Skill points";
+TRAINER_COST_TP = "|cffffffff%d|r Talent points";
+TRAINER_COST_TP_RED = "|cffff2020%d|r Talent points";
+TRAINER_LIST_SP = "%d SP";
+TRAINER_MANA_COST = "Mana cost: |cffffffff%d|r";
+TRAINER_MANA_COST_PER_TIME = "Mana cost: |cffffffff%d, plus %d per sec|r";
+TRAINER_RANGE = "Range: |cffffffff%s (%d)|r";
+TRAINER_REQ_ABILITY = "|cffffffff%s|r";
+TRAINER_REQ_ABILITY_RED = "|cffff2020%s|r";
+TRAINER_REQ_LEVEL = "Level |cffffffff%d|r";
+TRAINER_REQ_LEVEL_RED = "Level |cffff2020%d|r";
+TRAINER_REQ_SKILL_RANK = "%s (|cffffffff%d|r)";
+TRAINER_REQ_SKILL_RANK_RED = "%s (|cffff2020%d|r)";
+TRANSFER_ABORT_DIFFICULTY1 = "Normal difficulty mode is not available for %s.";
+TRANSFER_ABORT_DIFFICULTY2 = "Heroic difficulty mode is not available for %s.";
+TRANSFER_ABORT_DIFFICULTY3 = "Epic difficulty mode is not available for %s.";
+TRANSFER_ABORT_INSUF_EXPAN_LVL1 = "You must have The Burning Crusade expansion installed to access this area.";
+TRANSFER_ABORT_INSUF_EXPAN_LVL2 = "You must have The Wrath of the Lich King expansion installed to access this area.";
+TRANSFER_ABORT_MAP_NOT_ALLOWED = "Map cannot be entered at this time.";
+TRANSFER_ABORT_MAX_PLAYERS = "Transfer Aborted: instance is full";
+TRANSFER_ABORT_NEED_GROUP = "Transfer Aborted: you must be in a raid group to enter this instance";
+TRANSFER_ABORT_NOT_FOUND = "Transfer Aborted: instance not found";
+TRANSFER_ABORT_REALM_ONLY = "Transfer Aborted: all players in the party must be from the same realm";
+TRANSFER_ABORT_TOO_MANY_INSTANCES = "You have entered too many instances recently.";
+TRANSFER_ABORT_TOO_MANY_REALM_INSTANCES = "Additional instances cannot be launched, please try again later.";
+TRANSFER_ABORT_UNIQUE_MESSAGE1 = "Until you've escaped The Lich King's grasp, you cannot leave this place!";
+TRANSFER_ABORT_ZONE_IN_COMBAT = "Unable to zone in while an encounter is in progress.";
+TRILINEAR_FILTERING = "Trilinear Filtering";
+TRINKET0SLOT = "Trinket";
+TRINKET0SLOT_UNIQUE = "Trinket 1";
+TRINKET1SLOT = "Trinket";
+TRINKET1SLOT_UNIQUE = "Trinket 2";
+TRIPLE_BUFFER = "Triple Buffering";
+TRIVIAL_QUEST_DISPLAY = "|cff000000%s (low level)|r";
+TURN_IN_ITEMS = "Required items:";
+TURN_IN_QUEST = "Turn in";
+TUTORIAL1 = "Get quests by talking to quest givers. Quest givers have exclamation points over their heads.|n|nTo talk to them, move close and |cffffd200Right Click|r on them.";
+TUTORIAL2 = "Use the A, S, D and W keys to move your character.";
+TUTORIAL3 = "You can turn your character by |cffffd200holding the Right Mouse Button|r and moving the mouse.|n|nYou can look around by holding the Left Mouse Button and moving the mouse.";
+TUTORIAL4 = "|cffffd200Right Click|r on friendly characters to talk to them.|n|nYou might need to move closer to them before you can Right Click.";
+TUTORIAL5 = "To fight enemies, first use |cffffd200Left Click|r to target them. Then click on one of the abilities on the action bar across the bottom of your screen.|n|nYou should use ranged abilities while the target is still far away. Other abilities require you to be close to your target, particularly if your class specializes in melee weapons.";
+TUTORIAL6 = "Many of your abilities are weapon attacks or combat spells.|n|nDepending on your class you might have defensive abilities or even healing spells on your action bar.";
+TUTORIAL7 = "If you defeat an enemy and see sparkles on its corpse, that means it has loot.|n|n|cffffd200Right Click|r on a creature's corpse to loot it. This will open a loot window. Then |cffffd200Right Click|r on any items in that window to move them to your backpack.";
+TUTORIAL8 = "An item went into your backpack.|n|nYou can click on the |cffffd200Backpack Button|r in the lower right part of the screen to open your backpack. Move the mouse over the item to see what it is.";
+TUTORIAL9 = "Some items can be used. |cffffd200Right Click|r on an item to use it.|n|nYou can drag an item onto your action bar if you want to use it without opening your backpack.";
+TUTORIAL10 = "You received a bag. Now you will be able to carry more items.|n|nMove the bag to an empty bag space next to your backpack. Click on a bag to open it.";
+TUTORIAL11 = "You can eat food to gain health faster. |cffffd200Right Click|r on food to eat it.";
+TUTORIAL12 = "You can drink to regain your mana faster. |cffffd200Right Click|r on a beverage to drink it.|n|nYou don't need to drink if your class does not use mana.";
+TUTORIAL13 = "You can learn a new talent in the talent interface.|n|nOpen the talents page by clicking the pulsing |cffffd200Talents Button|r on your action bar.";
+TUTORIAL14 = "You can go to your class trainer to learn new skills. |cffffd200Right Click|r on trainers to talk to them.|n|nTrainers are found in many towns or cities and always in your starting area. You may have to search around a little to find your trainer.";
+TUTORIAL15 = "You can move spells and abilities to your action bar by clicking the |cffffd200Spellbook & Abilities Button|r at the bottom center of the screen and then dragging the ability icon to your action bar.|n|nYou can also use a spell or ability from the Spellbook directly by clicking on it.";
+TUTORIAL16 = "You can look at your reputation with different groups in the world under the Reputation tab.|n|nClick on the |cffffd200Character Info Button|r to find the Reputation tab.";
+TUTORIAL17 = "You can respond to that player by hitting the R key and then typing a message, or by typing /tell and then the message.";
+TUTORIAL18 = "You can invite another player to your group by |cffffd200Right Clicking|r their portrait and selecting the |cffffd200Invite|r option from the popup menu.|n|nYou can leave a group by Right Clicking on your own portrait and choosing the option to leave the party.";
+TUTORIAL19 = "That’s another real person playing a character. You can tell by the blue name above their head.";
+TUTORIAL20 = "|cffffd200Right Clicking|r an item in the vendor pane will buy that item if you have enough money.|n|nWhile the vendor pane is open, Right Clicking an item in your backpack will sell the item.";
+TUTORIAL21 = "You can view current quests by clicking on the |cffffd200Quest Log Button|r near the bottom middle of your screen.|n|nYou can view quest locations by clicking on the |cffffd200World Map Button|r at the top right of your screen.";
+TUTORIAL22 = "If there is another player you have enjoyed playing with, add them to your friends list! Click on the |cffffd200Social Button|r and add them to your list of friends.|n|nYou can only add friends from your own realm.";
+TUTORIAL23 = "You can send a message by hitting the Enter key, typing a message, and then hitting Enter again. Other players nearby will hear what you say.";
+TUTORIAL24 = "You can equip items by first clicking the |cffffd200Character Info Button|r near the bottom of the screen, and then the |cffffd200Backpack Button|r at the bottom right of your screen.|n|nThen just drag an equippable item from your backpack onto your character.";
+TUTORIAL25 = "You are now a ghost. You can return to life by either finding your corpse or talking to a nearby spirit healer.|n|nYour corpse shows up as an icon in the minimap at the upper right hand portion of the screen.";
+TUTORIAL26 = "You are rested. Being rested gives you a temporary bonus to experience from killing monsters.";
+TUTORIAL27 = "If you stray into deep and uncharted waters, you will see a Fatigue bar. If you become completely fatigued, you will begin to drown.";
+TUTORIAL28 = "Swimming is much like walking, except you can steer upwards and downwards by holding down the |cffffd200Right Mouse Button|r and looking in the direction you want to go.";
+TUTORIAL29 = "You will see a Breath bar pop up when your character becomes submerged in water. If you run out of breath, you will begin to drown.";
+TUTORIAL30 = "You are now resting, indicated by your portrait glowing yellow. Time spent resting or logged out gives you a temporary bonus to experience from killing monsters.|n|nYou can quickly return to inns to rest by using your hearthstone.";
+TUTORIAL31 = "Hearthstones can be used to transport you from your current location to the inn where you set your hearthstone.";
+TUTORIAL32 = "You are engaging in Player vs. Player combat. While you are participating in Player vs. Player combat the symbol of your alliance will appear next to your portrait and you can be attacked by enemy players.";
+TUTORIAL33 = "You can press the |cffffd200Spacebar|r to make your character jump. You can use jumping to get past obstacles or just for fun.";
+TUTORIAL34 = "You have completed your first quest! To collect your reward, you need to turn in the quest to a specific quest giver. Usually this is the same questgiver who gave you the quest.|n|nYou can see nearby questgivers as |cffffd200?|r on your minimap in the upper right of your screen. |cffffd200Right Click|r on a quest giver to talk to him or her.";
+TUTORIAL35 = "This is a flight master who trains flying beasts to carry passengers from one location to another. For a minimal fee, you can swiftly travel to other flight masters that you have spoken to in the past.|n|nWhen you discover a new city, finding the flight master will allow you to return easily in the future.";
+TUTORIAL36 = "The durability of one of your items is getting low. The character icon below your minimap indicates the damaged item in yellow.|n|nFind a vendor in town to repair the item before it breaks.";
+TUTORIAL37 = "One of your items has broken! The character icon below your minimap indicates the broken item in red.|n|nYou can get the item repaired by a vendor in town. Until you do, you will gain no benefit from the item.";
+TUTORIAL38 = "Your character can learn professions such as Cooking or Blacksmithing, which will allow you to find or create items of value.|n|nTo learn more about professions ask a guard in a major city for directions to the profession trainers.";
+TUTORIAL39 = "You may want to invite other players to team up with you to more easily overcome your enemies.|n|nMany difficult quests can be quickly completed in a group, as quest credit is shared by the group. Moreover, groups earn bonus experience, relative to solo players.";
+TUTORIAL40 = "You have learned a new spell or ability! Use the |cffffd200Spellbook & Abilities Button|r near the bottom of your screen to open your Spellbook. |cffffd200Left Click and drag|r a spell or ability to move it to your Action Bar.|n|nThe Spellbook is organized by category, as indicated by the tabs sticking out from the right side of the book.";
+TUTORIAL41 = "You have accepted an elite quest. Such quests are best undertaken in a group, for they will take you into areas inhabited by elite creatures.|n|nElite creatures are significantly tougher than normal monsters; however, they are worth more experience. You can tell an elite creature by the golden dragon border around its portrait.";
+TUTORIAL42 = "To get started, you should begin a |cffffd200Quest|r.|n|nThere's a quest giver right in front of you. Tutorial tips will help you along the way.|n|nThank you for playing, and good luck in your adventures!";
+TUTORIAL43 = "A quest giver with a gray '!' over its head has a quest that you are too low level to accept. Check back once you gain a few levels.";
+TUTORIAL44 = "You have obtained a ranged weapon. To use it, first equip the weapon by opening your |cffffd200Character Info|r and your |cffffd200Backpack|r and dragging the item onto your character.|n|nThen, open up your |cffffd200Spellbook|r and drag the |cffffd200Shoot|r or |cffffd200Throw|r ability onto your action bar.|n|nOnly hunters, warriors and rogues may use ranged weapons. Mages, priests and warlocks may use wands.";
+TUTORIAL45 = "You cannot fire bows and guns without ammunition. To purchase ammunition, visit a gun or bow merchant in a city. To equip ammunition, |cffffd200Right Click|r it.";
+TUTORIAL46 = "You have joined a raid group: a group with an increased limit of 40 members, though usually 10 or 25. Raid groups are necessary to enter the most challenging dungeons or to defeat the most powerful enemies, typically at high level.|n|n|cffff2020While in a raid group, you will not earn credit towards most quests. To leave a raid group, Right Click on your character portrait and select Leave party.|r";
+TUTORIAL47 = "You have gained access to the totem bar! You will gain an action button on this bar whenever you gain access to a new totem element.|n|nThis bar can hold one totem spell per totem element. At higher level you will gain the ability to drop multiple totems at once.";
+TUTORIAL48 = "You are now in a queue to enter a battleground. You may check your status by moving your mouse cursor over the icon on your minimap.";
+TUTORIAL49 = "You are now eligible to join battle. Click \"Enter Battle\" in the dialog or right click the battleground icon on the minimap.";
+TUTORIAL50 = "You now have a keyring to hold your keys.This |cffffd200Keyring Button|r appears to the left of your bags on your action bar.";
+TUTORIAL51 = "You can enter dungeons or find groups for dungeons by using the |cffffd200Dungeon Finder|r. The Dungeon Finder is accessed from the eye button near the middle of your action bar.";
+TUTORIAL52 = "Congratulations, you have received your first companion. This little fellow will follow you during all of your adventures in Azeroth and beyond.|n|nYou can see all of your companions by clicking the |cffffd200Character Info Button|r and then looking for the Pets tab.";
+TUTORIAL53 = "Congratulations, you have learned how to summon your first mount. This mighty steed will carry you throughout your adventures in Azeroth and beyond.|n|nTo see all of your mounts, click the |cffffd200Character Info Button|r and look for the Pets tab. You can drag your favorite mount onto your action bar to summon it more easily.";
+TUTORIAL54 = "You have attracted the attention of a hostile creature.|n|nA red glow means the creature is attacking you. A yellow glow means you are in danger of being attacked. An orange glow means the creature is attacking you, but may soon change targets.";
+TUTORIAL55 = "Congratulations! You just gained a level and became more powerful.|n|nYou can visit your class trainer and see if he or she has new abilities that you can learn.";
+TUTORIAL56 = "In the upper left corner of your screen is your health bar in green. When your health bar reaches zero, you will die, so be careful.|n|nBelow your health bar is a second bar representing the resource your class uses to power your special abilities, such as rage, energy or mana. Both bars will refill slowly over time.";
+TUTORIAL57 = "Just as you have a green health bar, enemies do too. When an enemy is selected, you can see their health bar at the top of the screen and gauge how close you are to defeating them.";
+TUTORIAL58 = "Your bags are full so you won't be able to pick up any more loot. To free up some bag space, visit vendor characters and sell them some of your junk.|n|nThere are usually vendors in every city, town or outpost.";
+TUTORIAL59 = "To free up bag space or make some money you can sell some of the items you have collected.|n|nLocate a vendor and |cffffd200Right Click|r them. Then open your bags and |cffffd200Right Click|r on any items you want to sell.";
+TUTORIAL60 = "Remember, your character has special abilities on the action bar on the lower part of your screen.|n|nUsing those abilities will kill an enemy much faster than just swinging your weapon.";
+TUTORIAL61 = "This is a trial version of World of Warcraft. Some features are not available. To experience all of the game go to www.worldofwarcraft.com.";
+TUTORIAL_TITLE1 = "Quest Givers";
+TUTORIAL_TITLE2 = "Movement";
+TUTORIAL_TITLE3 = "Camera";
+TUTORIAL_TITLE4 = "Targeting";
+TUTORIAL_TITLE5 = "Combat Mode";
+TUTORIAL_TITLE6 = "Spells and Abilities";
+TUTORIAL_TITLE7 = "Looting";
+TUTORIAL_TITLE8 = "Backpack";
+TUTORIAL_TITLE9 = "Using Items";
+TUTORIAL_TITLE10 = "Bags";
+TUTORIAL_TITLE11 = "Food";
+TUTORIAL_TITLE12 = "Drink";
+TUTORIAL_TITLE13 = "Learning Talents";
+TUTORIAL_TITLE14 = "Trainers";
+TUTORIAL_TITLE15 = "Spellbook & Abilities";
+TUTORIAL_TITLE16 = "Reputation";
+TUTORIAL_TITLE17 = "Replying to Tells";
+TUTORIAL_TITLE18 = "Grouping";
+TUTORIAL_TITLE19 = "Players";
+TUTORIAL_TITLE20 = "Vendors";
+TUTORIAL_TITLE21 = "Quest Log";
+TUTORIAL_TITLE22 = "Friends";
+TUTORIAL_TITLE23 = "Chatting";
+TUTORIAL_TITLE24 = "Equippable Items";
+TUTORIAL_TITLE25 = "Death";
+TUTORIAL_TITLE26 = "Rested";
+TUTORIAL_TITLE27 = "Fatigue";
+TUTORIAL_TITLE28 = "Swimming";
+TUTORIAL_TITLE29 = "Breath";
+TUTORIAL_TITLE30 = "Resting";
+TUTORIAL_TITLE31 = "Hearthstones";
+TUTORIAL_TITLE32 = "Player vs. Player Combat";
+TUTORIAL_TITLE33 = "Jumping";
+TUTORIAL_TITLE34 = "Quest Completion";
+TUTORIAL_TITLE35 = "Travel";
+TUTORIAL_TITLE36 = "Damaged Items";
+TUTORIAL_TITLE37 = "Broken Items";
+TUTORIAL_TITLE38 = "Professions";
+TUTORIAL_TITLE39 = "Groups";
+TUTORIAL_TITLE40 = "The Spellbook";
+TUTORIAL_TITLE41 = "Elite Quests";
+TUTORIAL_TITLE42 = "Welcome to World of Warcraft!";
+TUTORIAL_TITLE43 = "Unavailable Quest Givers";
+TUTORIAL_TITLE44 = "Ranged Weapons";
+TUTORIAL_TITLE45 = "Ammunition";
+TUTORIAL_TITLE46 = "Raid Groups";
+TUTORIAL_TITLE47 = "Totem Bar";
+TUTORIAL_TITLE48 = "Battleground Queue";
+TUTORIAL_TITLE49 = "Port to Battleground";
+TUTORIAL_TITLE50 = "Keyrings";
+TUTORIAL_TITLE51 = "Dungeon Finder";
+TUTORIAL_TITLE52 = "Companions";
+TUTORIAL_TITLE53 = "Mounts";
+TUTORIAL_TITLE54 = "Threat Warnings";
+TUTORIAL_TITLE55 = "Ding!";
+TUTORIAL_TITLE56 = "Player Status";
+TUTORIAL_TITLE57 = "Enemy Status";
+TUTORIAL_TITLE58 = "Full Bags";
+TUTORIAL_TITLE59 = "Freeing Up Bag Space";
+TUTORIAL_TITLE60 = "Special Abilities";
+TUTORIAL_TITLE61 = "Trial Version";
+TWOHANDEDWEAPONBEINGWIELDED = "Cannot wield in second hand, you are holding a 2-handed item!";
+TWO_HANDED = "Two Handed Weapon";
+TYPE = "Type";
+TYPE_LFR_COMMENT_HERE = "Type your comment here. This will be seen by other players using the Raid Browser.";
+UIOPTIONS_MENU = "Interface";
+UI_DEPTH = "UI Depth";
+UI_HIDDEN = "UI Hidden. Press %s to show it again.";
+UI_SCALE = "UI Scale";
+UKNOWNBEING = "Unknown Being";
+UNABLE_TO_REFUND_ITEM = "Sorry, unable to refund that item.";
+UNAVAILABLE = "Unavailable";
+UNBIND = "Unbind Key";
+UNEXTEND_RAID_LOCK = "Remove Raid Lock Extension";
+UNITFRAME_LABEL = "UnitFrames";
+UNITFRAME_SUBTEXT = "These options can be used to change the display and behavior of unit frames within the UI.";
+UNITNAME_SUMMON_TITLE1 = "%s's Pet";
+UNITNAME_SUMMON_TITLE10 = "%s's Mount";
+UNITNAME_SUMMON_TITLE11 = "%s's Lightwell";
+UNITNAME_SUMMON_TITLE12 = "%s's Butler";
+UNITNAME_SUMMON_TITLE2 = "%s's Guardian";
+UNITNAME_SUMMON_TITLE3 = "%s's Minion";
+UNITNAME_SUMMON_TITLE4 = "%s's Totem";
+UNITNAME_SUMMON_TITLE5 = "%s's Companion";
+UNITNAME_SUMMON_TITLE6 = "%s's Runeblade";
+UNITNAME_SUMMON_TITLE7 = "%s's Construct";
+UNITNAME_SUMMON_TITLE8 = "%s's Opponent";
+UNITNAME_SUMMON_TITLE9 = "%s's Vehicle";
+UNITNAME_TITLE = "%s";
+UNITNAME_TITLE_CHARM = "%s's Minion";
+UNITNAME_TITLE_COMPANION = "%s's Companion";
+UNITNAME_TITLE_CREATION = "%s's Creation";
+UNITNAME_TITLE_GUARDIAN = "%s's Guardian";
+UNITNAME_TITLE_MINION = "%s's Minion";
+UNITNAME_TITLE_OPPONENT = "%s's Opponent";
+UNITNAME_TITLE_PET = "%s's Pet";
+UNITNAME_TITLE_SQUIRE = "%s's Squire";
+UNIT_COLORS = "Unit Colors:";
+UNIT_LETHAL_LEVEL_DEAD_TEMPLATE = "Level ?? Corpse";
+UNIT_LETHAL_LEVEL_TEMPLATE = "Level ??";
+UNIT_LEVEL_DEAD_TEMPLATE = "Level %d Corpse";
+UNIT_LEVEL_TEMPLATE = "Level %d";
+UNIT_NAMEPLATES = "Unit Nameplates";
+UNIT_NAMEPLATES_ALLOW_OVERLAP = "Allow Overlapping Unit Nameplates";
+UNIT_NAMEPLATES_SHOW_ENEMIES = "Enemy Units";
+UNIT_NAMEPLATES_SHOW_ENEMY_GUARDIANS = "Guardians";
+UNIT_NAMEPLATES_SHOW_ENEMY_PETS = "Pets";
+UNIT_NAMEPLATES_SHOW_ENEMY_TOTEMS = "Totems";
+UNIT_NAMEPLATES_SHOW_FRIENDLY_GUARDIANS = "Guardians";
+UNIT_NAMEPLATES_SHOW_FRIENDLY_PETS = "Pets";
+UNIT_NAMEPLATES_SHOW_FRIENDLY_TOTEMS = "Totems";
+UNIT_NAMEPLATES_SHOW_FRIENDS = "Friendly Units";
+UNIT_NAMES = "Unit Names";
+UNIT_NAMES_COMBATLOG_TOOLTIP = "Color unit names.";
+UNIT_NAMES_SHOW_BRACES_COMBATLOG_TOOLTIP = "Show braces around unit names.";
+UNIT_NAME_ENEMY = "Enemy Players";
+UNIT_NAME_ENEMY_GUARDIANS = "Guardians";
+UNIT_NAME_ENEMY_PETS = "Pets";
+UNIT_NAME_ENEMY_TOTEMS = "Totems";
+UNIT_NAME_FRIENDLY = "Friendly Players";
+UNIT_NAME_FRIENDLY_GUARDIANS = "Guardians";
+UNIT_NAME_FRIENDLY_PETS = "Pets";
+UNIT_NAME_FRIENDLY_TOTEMS = "Totems";
+UNIT_NAME_GUILD = "Guild Names";
+UNIT_NAME_NONCOMBAT_CREATURE = "Critters and Vanity Pets";
+UNIT_NAME_NPC = "NPC Names";
+UNIT_NAME_OWN = "My Name";
+UNIT_NAME_PLAYER_TITLE = "Titles";
+UNIT_PLUS_LEVEL_TEMPLATE = "Level %d Elite";
+UNIT_PVP_NAME = "%s %s%s";
+UNIT_SKINNABLE_BOLTS = "Requires Engineering";
+UNIT_SKINNABLE_HERB = "Requires Herbalism";
+UNIT_SKINNABLE_LEATHER = "Skinnable";
+UNIT_SKINNABLE_ROCK = "Requires Mining";
+UNIT_TYPE_LETHAL_LEVEL_TEMPLATE = "Level ?? %s";
+UNIT_TYPE_LEVEL_TEMPLATE = "Level %d %s";
+UNIT_TYPE_PLUS_LEVEL_TEMPLATE = "Level %d Elite %s";
+UNIT_YOU = "You";
+UNIT_YOU_DEST = "You";
+UNIT_YOU_DEST_POSSESSIVE = "Your";
+UNIT_YOU_SOURCE = "You";
+UNIT_YOU_SOURCE_POSSESSIVE = "Your";
+UNKNOWN = "Unknown";
+UNKNOWNOBJECT = "Unknown";
+UNLEARN = "Unlearn";
+UNLEARN_SKILL = "Do you want to unlearn %s?";
+UNLEARN_SKILL_TOOLTIP = "Unlearn this profession";
+UNLIMITED = "Unlimited";
+UNLIST_ME = "Unlist My Name";
+UNLIST_MY_GROUP = "Unlist My Group";
+UNLOCK_FOCUS_FRAME = "Unlock Frame";
+UNLOCK_WINDOW = "Unlock Window";
+UNMUTE = "Unmute";
+UNSPENT_TALENT_POINTS = "Unspent Talents: %s";
+UNTRACK_ACHIEVEMENT_TOOLTIP = "Uncheck to stop tracking this achievement.";
+UNUSED = "Unused";
+UPDATE = "Update";
+USABLE_ITEMS = "Usable Items";
+USE = "Use";
+USED = "Already Known";
+USE_COLON = "Use:";
+USE_COLORBLIND_MODE = "Colorblind Mode";
+USE_ENGLISH_AUDIO = "Use English Audio";
+USE_EQUIPMENT_MANAGER = "Use Equipment Manager";
+USE_FULL_TEXT_MODE = "Use Verbose Mode";
+USE_GUILDBANK_REPAIR = "Do you want to use guild funds for repair?";
+USE_ITEM = "Use Item";
+USE_NO_DROP = "Using this item will bind it to you.";
+USE_PERSONAL_FUNDS = "Use Personal Funds";
+USE_SOULSTONE = "Reincarnate";
+USE_UBERTOOLTIPS = "Enhanced Tooltips";
+USE_UISCALE = "Use UI Scale";
+USE_WEATHER_SHADER = "Weather Shaders";
+VEHICLE_LEAVE = "Leave";
+VEHICLE_STEAM = "Steam";
+VERBAL_HARASSMENT = "Verbal Harassment";
+VERBAL_HARASSMENT_DESCRIPTION = "Verbal abuse from one player to another.";
+VERBAL_HARASSMENT_TEXT1 = "Below are some tips to deal with verbal harassment:";
+VERBAL_HARASSMENT_TEXT2 = "Ask the harassing player to stop, and place him/her on your ignore list.";
+VERBAL_HARASSMENT_TEXT3 = "Ensure that you do not instigate further harassment.";
+VERBAL_HARASSMENT_TEXT4 = "Immediately report all language that is racist, extremely sexual, and/or violent; this type of language is always considered harassment.";
+VERTEX_ANIMATION_SHADERS = "Vertex Animation Shaders";
+VERTICAL_SYNC = "Vertical Sync";
+VICTORY_TEXT0 = "Horde Wins";
+VICTORY_TEXT1 = "Alliance Wins";
+VICTORY_TEXT_ARENA0 = "Green Team Wins";
+VICTORY_TEXT_ARENA1 = "Gold Team Wins";
+VICTORY_TEXT_ARENA_DRAW = "Draw";
+VICTORY_TEXT_ARENA_WINS = "%s Wins";
+VIDEOOPTIONS_MENU = "Video";
+VIDEO_QUALITY_LABEL1 = "Low";
+VIDEO_QUALITY_LABEL2 = "Fair";
+VIDEO_QUALITY_LABEL3 = "Good";
+VIDEO_QUALITY_LABEL4 = "High";
+VIDEO_QUALITY_LABEL5 = "Ultra";
+VIDEO_QUALITY_LABEL6 = "Custom";
+VIDEO_QUALITY_S = "Video Quality: %s";
+VIDEO_QUALITY_SUBTEXT1 = "These are the lowest recommended graphics settings for the game. These settings provide excellent performance.";
+VIDEO_QUALITY_SUBTEXT2 = "Medium texture detail, short draw distance, low spell effect detail. These settings provide good performance.";
+VIDEO_QUALITY_SUBTEXT3 = "High texture detail, medium draw distance, medium spell effect detail. These settings balance performance and quality.";
+VIDEO_QUALITY_SUBTEXT4 = "High texture detail, farthest draw distance, high spell effect detail. These settings provide very high quality.";
+VIDEO_QUALITY_SUBTEXT5 = "These settings provide the very best quality and should only be used on high-end systems.";
+VIDEO_QUALITY_SUBTEXT6 = "Allows you to customize individual draw distances, detail levels, and effects. Performance and quality will vary by setting.";
+VIEW_FRIENDS_OF_FRIENDS = "View Friends";
+VOICE = "Voice";
+VOICECHAT_DISABLED = "Voice Chat Disabled";
+VOICECHAT_DISABLED_TEXT = "Voice Chat has been disabled because another copy of the game was running when you started this one, or because your computer cannot support it.";
+VOICEMACRO_0_Dw_0 = "Help me!";
+VOICEMACRO_0_Dw_0_FEMALE = "Help me!";
+VOICEMACRO_0_Dw_1 = "I need help!";
+VOICEMACRO_0_Dw_1_FEMALE = "I need help!";
+VOICEMACRO_0_Gn_0 = "Could you help, please?";
+VOICEMACRO_0_Gn_0_FEMALE = "Can I get some help?";
+VOICEMACRO_0_Gn_1 = "Please, help me!";
+VOICEMACRO_0_Gn_1_FEMALE = "Please, help me!";
+VOICEMACRO_0_Gn_2_FEMALE = "I need help!";
+VOICEMACRO_0_Hu_0 = "I require aid!";
+VOICEMACRO_0_Hu_0_FEMALE = "I need help!";
+VOICEMACRO_0_Hu_1 = "Aid me!";
+VOICEMACRO_0_Hu_1_FEMALE = "Help me!";
+VOICEMACRO_0_Ni_0 = "Aid me!";
+VOICEMACRO_0_Ni_0_FEMALE = "Aid me!";
+VOICEMACRO_0_Ni_1 = "To my side!";
+VOICEMACRO_0_Ni_1_FEMALE = "Assist me!";
+VOICEMACRO_0_Ni_2 = "Assist me!";
+VOICEMACRO_0_Or_0 = "I need help!";
+VOICEMACRO_0_Or_0_FEMALE = "I need help!";
+VOICEMACRO_0_Or_1 = "Aid me!";
+VOICEMACRO_0_Or_1_FEMALE = "Aid me!";
+VOICEMACRO_0_Sc_0 = "I need help!";
+VOICEMACRO_0_Sc_0_FEMALE = "Need your help!";
+VOICEMACRO_0_Sc_1 = "Help me!";
+VOICEMACRO_0_Sc_1_FEMALE = "Help me!";
+VOICEMACRO_0_Ta_0 = "Give me aid!";
+VOICEMACRO_0_Ta_0_FEMALE = "Aid me!";
+VOICEMACRO_0_Ta_1 = "Help!";
+VOICEMACRO_0_Ta_1_FEMALE = "Help!";
+VOICEMACRO_0_Ta_2 = "Aid me!";
+VOICEMACRO_0_Tr_0 = "Help me!";
+VOICEMACRO_0_Tr_0_FEMALE = "Help me!";
+VOICEMACRO_0_Tr_1 = "Assist me!";
+VOICEMACRO_0_Tr_1_FEMALE = "Assist me!";
+VOICEMACRO_10_Dw_0 = "Open fire!";
+VOICEMACRO_10_Dw_0_FEMALE = "Shoot to kill!";
+VOICEMACRO_10_Dw_1 = "Fire!";
+VOICEMACRO_10_Dw_1_FEMALE = "Open fire!";
+VOICEMACRO_10_Gn_0 = "Hurry, fire!";
+VOICEMACRO_10_Gn_0_FEMALE = "Shoot!";
+VOICEMACRO_10_Gn_1 = "Shoot!";
+VOICEMACRO_10_Gn_1_FEMALE = "Fire now!";
+VOICEMACRO_10_Hu_0 = "Fire at will!";
+VOICEMACRO_10_Hu_0_FEMALE = "Attack!";
+VOICEMACRO_10_Hu_1 = "Fire!";
+VOICEMACRO_10_Hu_1_FEMALE = "Fire!";
+VOICEMACRO_10_Ni_0 = "Fire at will!";
+VOICEMACRO_10_Ni_0_FEMALE = "Strike quickly!";
+VOICEMACRO_10_Ni_1 = "Fire!";
+VOICEMACRO_10_Ni_1_FEMALE = "Fire!";
+VOICEMACRO_10_Or_0 = "Shoot!";
+VOICEMACRO_10_Or_0_FEMALE = "Open fire!";
+VOICEMACRO_10_Or_1 = "Let 'em have it!";
+VOICEMACRO_10_Or_1_FEMALE = "Fire!";
+VOICEMACRO_10_Or_2_FEMALE = "Shoot!";
+VOICEMACRO_10_Sc_0 = "Shoot to kill!";
+VOICEMACRO_10_Sc_0_FEMALE = "Fire!";
+VOICEMACRO_10_Sc_1 = "Open fire!";
+VOICEMACRO_10_Sc_1_FEMALE = "Open fire!";
+VOICEMACRO_10_Ta_0 = "Unleash your fury!";
+VOICEMACRO_10_Ta_0_FEMALE = "Fire away!";
+VOICEMACRO_10_Ta_1 = "Strike now!";
+VOICEMACRO_10_Ta_1_FEMALE = "Strike now!";
+VOICEMACRO_10_Tr_0 = "Shoot 'em!";
+VOICEMACRO_10_Tr_0_FEMALE = "Shoot them!";
+VOICEMACRO_10_Tr_1 = "Light 'em up!";
+VOICEMACRO_10_Tr_1_FEMALE = "Light 'em up!";
+VOICEMACRO_12_Dw_0 = "How's it hanging?";
+VOICEMACRO_12_Dw_0_FEMALE = "Greetings.";
+VOICEMACRO_12_Dw_1 = "Hello.";
+VOICEMACRO_12_Dw_1_FEMALE = "Hi, there.";
+VOICEMACRO_12_Dw_2 = "Greetings.";
+VOICEMACRO_12_Dw_2_FEMALE = "How are you?";
+VOICEMACRO_12_Dw_3 = "How are you?";
+VOICEMACRO_12_Gn_0 = "Hello.";
+VOICEMACRO_12_Gn_0_FEMALE = "Hello.";
+VOICEMACRO_12_Gn_1 = "Greetings.";
+VOICEMACRO_12_Gn_1_FEMALE = "Greetings.";
+VOICEMACRO_12_Gn_2 = "Salutations.";
+VOICEMACRO_12_Gn_2_FEMALE = "Hi, there.";
+VOICEMACRO_12_Gn_3 = "Hi, there.";
+VOICEMACRO_12_Hu_0 = "Hi.";
+VOICEMACRO_12_Hu_0_FEMALE = "Hi.";
+VOICEMACRO_12_Hu_1 = "Good tidings.";
+VOICEMACRO_12_Hu_1_FEMALE = "Hello.";
+VOICEMACRO_12_Hu_2 = "Hail.";
+VOICEMACRO_12_Hu_2_FEMALE = "Greetings.";
+VOICEMACRO_12_Hu_3 = "Well met.";
+VOICEMACRO_12_Ni_0 = "Greetings.";
+VOICEMACRO_12_Ni_0_FEMALE = "Hello.";
+VOICEMACRO_12_Ni_1 = "Well met.";
+VOICEMACRO_12_Ni_1_FEMALE = "Greetings.";
+VOICEMACRO_12_Ni_2 = "Hi.";
+VOICEMACRO_12_Ni_2_FEMALE = "Well met.";
+VOICEMACRO_12_Ni_3_FEMALE = "Hi.";
+VOICEMACRO_12_Or_0 = "Thram-ka.";
+VOICEMACRO_12_Or_0_FEMALE = "Thram-ka.";
+VOICEMACRO_12_Or_1 = "Hey.";
+VOICEMACRO_12_Or_1_FEMALE = "Hey.";
+VOICEMACRO_12_Or_2 = "Hello.";
+VOICEMACRO_12_Or_2_FEMALE = "Greetings.";
+VOICEMACRO_12_Sc_0 = "Hello.";
+VOICEMACRO_12_Sc_0_FEMALE = "Hello.";
+VOICEMACRO_12_Sc_1 = "Hi, there.";
+VOICEMACRO_12_Sc_1_FEMALE = "Hi, there.";
+VOICEMACRO_12_Sc_2 = "Greetings.";
+VOICEMACRO_12_Sc_2_FEMALE = "Hey.";
+VOICEMACRO_12_Ta_0 = "Hi.";
+VOICEMACRO_12_Ta_0_FEMALE = "Hi.";
+VOICEMACRO_12_Ta_1 = "Hello.";
+VOICEMACRO_12_Ta_1_FEMALE = "Hello.";
+VOICEMACRO_12_Ta_2 = "Greetings.";
+VOICEMACRO_12_Ta_2_FEMALE = "How are you?";
+VOICEMACRO_12_Tr_0 = "Hey, there.";
+VOICEMACRO_12_Tr_0_FEMALE = "Hello.";
+VOICEMACRO_12_Tr_1 = "Hey, man.";
+VOICEMACRO_12_Tr_1_FEMALE = "Hey, there.";
+VOICEMACRO_12_Tr_2 = "What be happening?";
+VOICEMACRO_12_Tr_2_FEMALE = "Greetings.";
+VOICEMACRO_13_Dw_0 = "Farewell.";
+VOICEMACRO_13_Dw_0_FEMALE = "So long.";
+VOICEMACRO_13_Dw_1 = "Till we meet again.";
+VOICEMACRO_13_Dw_1_FEMALE = "Goodbye.";
+VOICEMACRO_13_Dw_2 = "See you.";
+VOICEMACRO_13_Dw_2_FEMALE = "See ya.";
+VOICEMACRO_13_Gn_0 = "Farewell.";
+VOICEMACRO_13_Gn_0_FEMALE = "Farewell.";
+VOICEMACRO_13_Gn_1 = "Goodbye.";
+VOICEMACRO_13_Gn_1_FEMALE = "Goodbye.";
+VOICEMACRO_13_Gn_2 = "It's been fun.";
+VOICEMACRO_13_Gn_2_FEMALE = "It's been quite an experience.";
+VOICEMACRO_13_Gn_3 = "I'll miss you.";
+VOICEMACRO_13_Gn_3_FEMALE = "I'll always treasure our time together.";
+VOICEMACRO_13_Hu_0 = "Farewell.";
+VOICEMACRO_13_Hu_0_FEMALE = "Goodbye.";
+VOICEMACRO_13_Hu_1 = "Till we meet again.";
+VOICEMACRO_13_Hu_1_FEMALE = "Till we meet again.";
+VOICEMACRO_13_Hu_2 = "It's been fun.";
+VOICEMACRO_13_Hu_2_FEMALE = "It's been fun.";
+VOICEMACRO_13_Ni_0 = "Good journey.";
+VOICEMACRO_13_Ni_0_FEMALE = "Goodbye.";
+VOICEMACRO_13_Ni_1 = "Goodbye.";
+VOICEMACRO_13_Ni_1_FEMALE = "I wish you well.";
+VOICEMACRO_13_Ni_2 = "I wish you well.";
+VOICEMACRO_13_Ni_2_FEMALE = "Till we meet again.";
+VOICEMACRO_13_Or_0 = "Until our paths cross again.";
+VOICEMACRO_13_Or_0_FEMALE = "Stay strong.";
+VOICEMACRO_13_Or_1 = "Stay strong.";
+VOICEMACRO_13_Or_1_FEMALE = "May you always be victorious.";
+VOICEMACRO_13_Or_2 = "May your blade be true.";
+VOICEMACRO_13_Or_2_FEMALE = "Until next time.";
+VOICEMACRO_13_Sc_0 = "Goodbye.";
+VOICEMACRO_13_Sc_0_FEMALE = "Goodbye.";
+VOICEMACRO_13_Sc_1 = "Have a bad day.";
+VOICEMACRO_13_Sc_1_FEMALE = "It's been real.";
+VOICEMACRO_13_Sc_2 = "Stay optimistic.";
+VOICEMACRO_13_Sc_2_FEMALE = "Good luck.";
+VOICEMACRO_13_Ta_0 = "Good journey.";
+VOICEMACRO_13_Ta_0_FEMALE = "Farewell.";
+VOICEMACRO_13_Ta_1 = "May our paths cross again.";
+VOICEMACRO_13_Ta_1_FEMALE = "Goodbye.";
+VOICEMACRO_13_Ta_2 = "May the wind be at your back.";
+VOICEMACRO_13_Ta_2_FEMALE = "May our paths cross again.";
+VOICEMACRO_13_Tr_0 = "Catch you later.";
+VOICEMACRO_13_Tr_0_FEMALE = "Goodbye.";
+VOICEMACRO_13_Tr_1 = "It been real.";
+VOICEMACRO_13_Tr_1_FEMALE = "So long.";
+VOICEMACRO_13_Tr_2 = "Smell you later.";
+VOICEMACRO_13_Tr_2_FEMALE = "Catch you later.";
+VOICEMACRO_14_Dw_0 = "Yes.";
+VOICEMACRO_14_Dw_0_FEMALE = "Sure.";
+VOICEMACRO_14_Dw_1 = "Sure.";
+VOICEMACRO_14_Dw_1_FEMALE = "Damn straight.";
+VOICEMACRO_14_Dw_2 = "Aye.";
+VOICEMACRO_14_Dw_2_FEMALE = "Of course.";
+VOICEMACRO_14_Dw_3 = "Damn straight.";
+VOICEMACRO_14_Gn_0 = "Sure.";
+VOICEMACRO_14_Gn_0_FEMALE = "Certainly.";
+VOICEMACRO_14_Gn_1 = "Affirmative.";
+VOICEMACRO_14_Gn_1_FEMALE = "Of course.";
+VOICEMACRO_14_Gn_2 = "Indubitably.";
+VOICEMACRO_14_Gn_2_FEMALE = "Indubitably.";
+VOICEMACRO_14_Hu_0 = "Certainly.";
+VOICEMACRO_14_Hu_0_FEMALE = "Yes.";
+VOICEMACRO_14_Hu_1 = "Sounds fine.";
+VOICEMACRO_14_Hu_1_FEMALE = "Sure.";
+VOICEMACRO_14_Hu_2 = "Uh huh.";
+VOICEMACRO_14_Hu_2_FEMALE = "Why not.";
+VOICEMACRO_14_Ni_0 = "Yes.";
+VOICEMACRO_14_Ni_0_FEMALE = "Yes.";
+VOICEMACRO_14_Ni_1 = "Of course.";
+VOICEMACRO_14_Ni_1_FEMALE = "Certainly.";
+VOICEMACRO_14_Ni_2 = "Naturally.";
+VOICEMACRO_14_Ni_2_FEMALE = "Naturally.";
+VOICEMACRO_14_Or_0 = "D'abu.";
+VOICEMACRO_14_Or_0_FEMALE = "D'abu.";
+VOICEMACRO_14_Or_1 = "Zug zug.";
+VOICEMACRO_14_Or_1_FEMALE = "Zug zug.";
+VOICEMACRO_14_Or_2 = "(grunt)";
+VOICEMACRO_14_Or_2_FEMALE = "(grunt)";
+VOICEMACRO_14_Or_3 = "Yes.";
+VOICEMACRO_14_Or_3_FEMALE = "Uh huh.";
+VOICEMACRO_14_Sc_0 = "Yes.";
+VOICEMACRO_14_Sc_0_FEMALE = "Yes.";
+VOICEMACRO_14_Sc_1 = "Certainly.";
+VOICEMACRO_14_Sc_1_FEMALE = "Why not.";
+VOICEMACRO_14_Sc_2 = "I suppose so.";
+VOICEMACRO_14_Sc_2_FEMALE = "I suppose so.";
+VOICEMACRO_14_Ta_0 = "Yes.";
+VOICEMACRO_14_Ta_0_FEMALE = "Yes.";
+VOICEMACRO_14_Ta_1 = "I believe so.";
+VOICEMACRO_14_Ta_1_FEMALE = "Naturally.";
+VOICEMACRO_14_Ta_2 = "It is meant to be.";
+VOICEMACRO_14_Ta_2_FEMALE = "Of course.";
+VOICEMACRO_14_Tr_0 = "Of course, man.";
+VOICEMACRO_14_Tr_0_FEMALE = "Sure thing.";
+VOICEMACRO_14_Tr_1 = "Sure thing.";
+VOICEMACRO_14_Tr_1_FEMALE = "Dig it.";
+VOICEMACRO_14_Tr_2 = "I be feeling you.";
+VOICEMACRO_14_Tr_2_FEMALE = "Yeah, man.";
+VOICEMACRO_14_Tr_3 = "I dig it.";
+VOICEMACRO_15_Dw_0 = "No.";
+VOICEMACRO_15_Dw_0_FEMALE = "No.";
+VOICEMACRO_15_Dw_1 = "Uh uh.";
+VOICEMACRO_15_Dw_1_FEMALE = "Get bent.";
+VOICEMACRO_15_Dw_2 = "No way.";
+VOICEMACRO_15_Dw_2_FEMALE = "Not a chance.";
+VOICEMACRO_15_Dw_3 = "Not on your life.";
+VOICEMACRO_15_Gn_0 = "No.";
+VOICEMACRO_15_Gn_0_FEMALE = "No way.";
+VOICEMACRO_15_Gn_1 = "No way.";
+VOICEMACRO_15_Gn_1_FEMALE = "Not on your life.";
+VOICEMACRO_15_Gn_2 = "I don't think so.";
+VOICEMACRO_15_Gn_2_FEMALE = "I don't think so.";
+VOICEMACRO_15_Hu_0 = "No.";
+VOICEMACRO_15_Hu_0_FEMALE = "No.";
+VOICEMACRO_15_Hu_1 = "Nay.";
+VOICEMACRO_15_Hu_1_FEMALE = "No way.";
+VOICEMACRO_15_Hu_2 = "I don't think so.";
+VOICEMACRO_15_Hu_2_FEMALE = "I don't think so.";
+VOICEMACRO_15_Hu_3 = "Not.";
+VOICEMACRO_15_Ni_0 = "No.";
+VOICEMACRO_15_Ni_0_FEMALE = "No.";
+VOICEMACRO_15_Ni_1 = "I don't think so.";
+VOICEMACRO_15_Ni_1_FEMALE = "I don't think so.";
+VOICEMACRO_15_Ni_2 = "Absolutely not.";
+VOICEMACRO_15_Ni_2_FEMALE = "Absolutely not.";
+VOICEMACRO_15_Or_0 = "No.";
+VOICEMACRO_15_Or_0_FEMALE = "No.";
+VOICEMACRO_15_Or_1 = "You must be joking.";
+VOICEMACRO_15_Or_1_FEMALE = "Not on your life.";
+VOICEMACRO_15_Or_2 = "(grunt)";
+VOICEMACRO_15_Or_2_FEMALE = "(grunt)";
+VOICEMACRO_15_Sc_0 = "No.";
+VOICEMACRO_15_Sc_0_FEMALE = "No.";
+VOICEMACRO_15_Sc_1 = "Not on your life.";
+VOICEMACRO_15_Sc_1_FEMALE = "Not on your life.";
+VOICEMACRO_15_Sc_2 = "I don't think so.";
+VOICEMACRO_15_Sc_2_FEMALE = "I don't think so.";
+VOICEMACRO_15_Ta_0 = "No.";
+VOICEMACRO_15_Ta_0_FEMALE = "No.";
+VOICEMACRO_15_Ta_1 = "I don't think so.";
+VOICEMACRO_15_Ta_1_FEMALE = "I don't think so.";
+VOICEMACRO_15_Ta_2 = "Never.";
+VOICEMACRO_15_Ta_2_FEMALE = "It is not meant to be.";
+VOICEMACRO_15_Tr_0 = "No.";
+VOICEMACRO_15_Tr_0_FEMALE = "No chance.";
+VOICEMACRO_15_Tr_1 = "No way.";
+VOICEMACRO_15_Tr_1_FEMALE = "No way.";
+VOICEMACRO_15_Tr_2 = "Hell, no.";
+VOICEMACRO_15_Tr_2_FEMALE = "Not on your life.";
+VOICEMACRO_15_Tr_3 = "Uh uh.";
+VOICEMACRO_16_Dw_0 = "Thank you.";
+VOICEMACRO_16_Dw_0_FEMALE = "Thank you.";
+VOICEMACRO_16_Dw_1 = "Thanks a lot.";
+VOICEMACRO_16_Dw_1_FEMALE = "Ah, you're nice.";
+VOICEMACRO_16_Dw_2 = "Ah, you're nice.";
+VOICEMACRO_16_Dw_2_FEMALE = "Thanks a lot.";
+VOICEMACRO_16_Dw_3 = "May your generosity be returned to you a hundred fold.";
+VOICEMACRO_16_Dw_3_FEMALE = "May your generosity be returned to you one hundred fold.";
+VOICEMACRO_16_Gn_0 = "Thank you.";
+VOICEMACRO_16_Gn_0_FEMALE = "How generous.";
+VOICEMACRO_16_Gn_1 = "I am in your debt.";
+VOICEMACRO_16_Gn_1_FEMALE = "How kind of you.";
+VOICEMACRO_16_Gn_2 = "Allow me to express my deepest thanks.";
+VOICEMACRO_16_Gn_2_FEMALE = "Much appreciated.";
+VOICEMACRO_16_Hu_0 = "Thank you.";
+VOICEMACRO_16_Hu_0_FEMALE = "Thank you.";
+VOICEMACRO_16_Hu_1 = "How generous.";
+VOICEMACRO_16_Hu_1_FEMALE = "How generous.";
+VOICEMACRO_16_Hu_2 = "How kind of you.";
+VOICEMACRO_16_Hu_2_FEMALE = "Much appreciated.";
+VOICEMACRO_16_Ni_0 = "Thank you.";
+VOICEMACRO_16_Ni_0_FEMALE = "Thank you.";
+VOICEMACRO_16_Ni_1 = "Excellent.";
+VOICEMACRO_16_Ni_1_FEMALE = "How generous.";
+VOICEMACRO_16_Ni_2 = "Much appreciated.";
+VOICEMACRO_16_Ni_2_FEMALE = "You are too kind.";
+VOICEMACRO_16_Or_0 = "I will return the favor.";
+VOICEMACRO_16_Or_0_FEMALE = "I won't forget this.";
+VOICEMACRO_16_Or_1 = "I won't forget this.";
+VOICEMACRO_16_Or_1_FEMALE = "Thank you.";
+VOICEMACRO_16_Or_2 = "Thank you.";
+VOICEMACRO_16_Or_2_FEMALE = "Thanks.";
+VOICEMACRO_16_Sc_0 = "I am in your debt.";
+VOICEMACRO_16_Sc_0_FEMALE = "Thank you.";
+VOICEMACRO_16_Sc_1 = "Gee, thanks.";
+VOICEMACRO_16_Sc_1_FEMALE = "Gee, thanks.";
+VOICEMACRO_16_Sc_2 = "Appreciated.";
+VOICEMACRO_16_Sc_2_FEMALE = "How generous.";
+VOICEMACRO_16_Ta_0 = "How generous.";
+VOICEMACRO_16_Ta_0_FEMALE = "Thank you.";
+VOICEMACRO_16_Ta_1 = "How kind of you.";
+VOICEMACRO_16_Ta_1_FEMALE = "How kind of you.";
+VOICEMACRO_16_Ta_2 = "I thank you.";
+VOICEMACRO_16_Ta_2_FEMALE = "You are too kind.";
+VOICEMACRO_16_Ta_3 = "May your ancestors forever guard your path.";
+VOICEMACRO_16_Tr_0 = "Thanks.";
+VOICEMACRO_16_Tr_0_FEMALE = "Thanks.";
+VOICEMACRO_16_Tr_1 = "Big thanks.";
+VOICEMACRO_16_Tr_1_FEMALE = "Big thanks.";
+VOICEMACRO_16_Tr_2 = "I owe you one.";
+VOICEMACRO_16_Tr_2_FEMALE = "I owe you one.";
+VOICEMACRO_17_Dw_0 = "No problem.";
+VOICEMACRO_17_Dw_0_FEMALE = "No problem.";
+VOICEMACRO_17_Dw_1 = "My pleasure.";
+VOICEMACRO_17_Dw_1_FEMALE = "My pleasure.";
+VOICEMACRO_17_Dw_2 = "Don't mention it.";
+VOICEMACRO_17_Dw_2_FEMALE = "You're welcome.";
+VOICEMACRO_17_Gn_0 = "No problem.";
+VOICEMACRO_17_Gn_0_FEMALE = "Any time.";
+VOICEMACRO_17_Gn_1 = "Any time.";
+VOICEMACRO_17_Gn_1_FEMALE = "Anything for a friend.";
+VOICEMACRO_17_Gn_2 = "You're welcome.";
+VOICEMACRO_17_Gn_2_FEMALE = "You're welcome.";
+VOICEMACRO_17_Hu_0 = "Always glad to help.";
+VOICEMACRO_17_Hu_0_FEMALE = "No problem.";
+VOICEMACRO_17_Hu_1 = "Nothing you wouldn't have done for me.";
+VOICEMACRO_17_Hu_1_FEMALE = "Anytime.";
+VOICEMACRO_17_Hu_2 = "At your service.";
+VOICEMACRO_17_Hu_2_FEMALE = "You're welcome.";
+VOICEMACRO_17_Ni_0 = "You're welcome.";
+VOICEMACRO_17_Ni_0_FEMALE = "My pleasure.";
+VOICEMACRO_17_Ni_1 = "My pleasure.";
+VOICEMACRO_17_Ni_1_FEMALE = "It was nothing.";
+VOICEMACRO_17_Ni_2 = "The honor was mine.";
+VOICEMACRO_17_Ni_2_FEMALE = "The honor was mine.";
+VOICEMACRO_17_Or_0 = "I would expect the same.";
+VOICEMACRO_17_Or_0_FEMALE = "Any time.";
+VOICEMACRO_17_Or_1 = "Honor required it.";
+VOICEMACRO_17_Or_1_FEMALE = "Anything for a friend.";
+VOICEMACRO_17_Or_2 = "It was nothing.";
+VOICEMACRO_17_Or_2_FEMALE = "You're welcome.";
+VOICEMACRO_17_Sc_0 = "Any time.";
+VOICEMACRO_17_Sc_0_FEMALE = "Any time.";
+VOICEMACRO_17_Sc_1 = "Eh.";
+VOICEMACRO_17_Sc_1_FEMALE = "Eh.";
+VOICEMACRO_17_Sc_2_FEMALE = "This doesn't mean I like you.";
+VOICEMACRO_17_Ta_0 = "It was nothing.";
+VOICEMACRO_17_Ta_0_FEMALE = "My pleasure.";
+VOICEMACRO_17_Ta_1 = "Always glad to help.";
+VOICEMACRO_17_Ta_1_FEMALE = "Always glad to help.";
+VOICEMACRO_17_Ta_2 = "Anything for an ally.";
+VOICEMACRO_17_Ta_2_FEMALE = "You are welcome.";
+VOICEMACRO_17_Tr_0 = "No problem.";
+VOICEMACRO_17_Tr_0_FEMALE = "No problem.";
+VOICEMACRO_17_Tr_1 = "Any time, man.";
+VOICEMACRO_17_Tr_1_FEMALE = "My pleasure.";
+VOICEMACRO_17_Tr_2 = "You scratch my back, I scratch yours.";
+VOICEMACRO_17_Tr_2_FEMALE = "Any time, man.";
+VOICEMACRO_18_Dw_0 = "Congratulations.";
+VOICEMACRO_18_Dw_0_FEMALE = "Congratulations.";
+VOICEMACRO_18_Dw_1 = "Fantastic.";
+VOICEMACRO_18_Dw_1_FEMALE = "Way to go.";
+VOICEMACRO_18_Dw_2 = "Brilliant.";
+VOICEMACRO_18_Dw_2_FEMALE = "Oh, that's great.";
+VOICEMACRO_18_Dw_3 = "Well done.";
+VOICEMACRO_18_Dw_3_FEMALE = "Brilliant.";
+VOICEMACRO_18_Dw_4 = "Way to go.";
+VOICEMACRO_18_Gn_0 = "Congratulations.";
+VOICEMACRO_18_Gn_0_FEMALE = "Congratulations.";
+VOICEMACRO_18_Gn_1 = "Well done.";
+VOICEMACRO_18_Gn_1_FEMALE = "Way to go.";
+VOICEMACRO_18_Gn_2 = "Good job.";
+VOICEMACRO_18_Gn_2_FEMALE = "Excellent.";
+VOICEMACRO_18_Gn_3_FEMALE = "Wonderful.";
+VOICEMACRO_18_Hu_0 = "Congratulations.";
+VOICEMACRO_18_Hu_0_FEMALE = "Congratulations.";
+VOICEMACRO_18_Hu_1 = "Excellent.";
+VOICEMACRO_18_Hu_1_FEMALE = "Excellent.";
+VOICEMACRO_18_Hu_2 = "Wonderful.";
+VOICEMACRO_18_Hu_2_FEMALE = "Hazzah.";
+VOICEMACRO_18_Ni_0 = "Congratulations.";
+VOICEMACRO_18_Ni_0_FEMALE = "Congratulations.";
+VOICEMACRO_18_Ni_1 = "You are worthy.";
+VOICEMACRO_18_Ni_1_FEMALE = "Well done.";
+VOICEMACRO_18_Ni_2 = "Excellent.";
+VOICEMACRO_18_Ni_2_FEMALE = "Excellent.";
+VOICEMACRO_18_Or_0 = "You should be proud.";
+VOICEMACRO_18_Or_0_FEMALE = "Skillfully done.";
+VOICEMACRO_18_Or_1 = "Good job.";
+VOICEMACRO_18_Or_1_FEMALE = "Not bad.";
+VOICEMACRO_18_Or_2 = "You are worthy.";
+VOICEMACRO_18_Or_2_FEMALE = "Congratulations.";
+VOICEMACRO_18_Sc_0 = "Congratulations.";
+VOICEMACRO_18_Sc_0_FEMALE = "Congratulations.";
+VOICEMACRO_18_Sc_1 = "Well done.";
+VOICEMACRO_18_Sc_1_FEMALE = "It's always somebody else.";
+VOICEMACRO_18_Sc_2 = "Good job.";
+VOICEMACRO_18_Sc_2_FEMALE = "Well, aren't you lucky.";
+VOICEMACRO_18_Sc_3_FEMALE = "Today certainly is your day.";
+VOICEMACRO_18_Ta_0 = "Well done.";
+VOICEMACRO_18_Ta_0_FEMALE = "Good job.";
+VOICEMACRO_18_Ta_1 = "You are worthy.";
+VOICEMACRO_18_Ta_1_FEMALE = "Excellent.";
+VOICEMACRO_18_Ta_2 = "Fate smiles upon you.";
+VOICEMACRO_18_Ta_2_FEMALE = "Fate smiles upon you.";
+VOICEMACRO_18_Tr_0 = "Good job.";
+VOICEMACRO_18_Tr_0_FEMALE = "Good job.";
+VOICEMACRO_18_Tr_1 = "Fantastic.";
+VOICEMACRO_18_Tr_1_FEMALE = "Way to go.";
+VOICEMACRO_18_Tr_2 = "They will speak of your exploits for generations.";
+VOICEMACRO_18_Tr_2_FEMALE = "Wonderful.";
+VOICEMACRO_19_Dw_0 = "Enough of this chit chat. Let's get to it, then.";
+VOICEMACRO_19_Dw_0_FEMALE = "I like tall men.";
+VOICEMACRO_19_Dw_1 = "You'd like to run your hands through my beard, wouldn't you?";
+VOICEMACRO_19_Dw_1_FEMALE = "I'll have you know I can flatten steel with my thighs.";
+VOICEMACRO_19_Dw_2 = "Let's get on with it, then. I've got a quest to do in fifteen minutes.";
+VOICEMACRO_19_Dw_2_FEMALE = "I'd like to see you in a kilt.";
+VOICEMACRO_19_Dw_3 = "You look pretty. I like your hair. Here's your drink. Are you ready now?";
+VOICEMACRO_19_Dw_3_FEMALE = "I won't fall for any bad pickup line. You've got to try two or three, at least.";
+VOICEMACRO_19_Dw_4 = "Where are you from? Not that it matters.";
+VOICEMACRO_19_Dw_4_FEMALE = "Enough with your flirting. I know you think all Dwarven women look the same.";
+VOICEMACRO_19_Dw_5 = "I must be asleep, cause you're a dream come true. Also, I'm slightly damp.";
+VOICEMACRO_19_Gn_0 = "I have a number of inventions I'd like to show you back at my place.";
+VOICEMACRO_19_Gn_0_FEMALE = "You are cute.";
+VOICEMACRO_19_Gn_1 = "Everyone keeps talking about beer goggles. I can't find the plans for them anywhere.";
+VOICEMACRO_19_Gn_1_FEMALE = "At this time I think you should purchase me an alcoholic beverage and engage in diminutive conversation with me in hopes of establishing a rapport.";
+VOICEMACRO_19_Gn_2 = "I like large posteriors, and I cannot prevaricate.";
+VOICEMACRO_19_Gn_2_FEMALE = "Your ability to form a complete sentence is a plus.";
+VOICEMACRO_19_Gn_3 = "Hey, nice apparatus.";
+VOICEMACRO_19_Gn_3_FEMALE = "I do not find you completely disagreeable.";
+VOICEMACRO_19_Gn_4_FEMALE = "I don't feel that the 1 to 10 scale is fine enough to capture subtle details of compatibility. I'd prefer a 12 dimensional compatibility scale with additional parameters for mechanical aptitude and torque.";
+VOICEMACRO_19_Hu_0 = "How you doing?";
+VOICEMACRO_19_Hu_0_FEMALE = "You've got me all a flutter.";
+VOICEMACRO_19_Hu_1 = "If I said you had a good body, would you hold it against me?";
+VOICEMACRO_19_Hu_1_FEMALE = "My turn offs are rude people, mean people, and people who aren't nice.";
+VOICEMACRO_19_Hu_2 = "Hey, baby cakes.";
+VOICEMACRO_19_Hu_2_FEMALE = "I need a hero.";
+VOICEMACRO_19_Hu_3 = "What's your sign?";
+VOICEMACRO_19_Hu_4 = "Are you tired, cause you've been running through my mind all day.";
+VOICEMACRO_19_Hu_5 = "Your tag's showing. It says, \"Made in heaven.\"";
+VOICEMACRO_19_Ni_0 = "You're an Emerald Dream come true.";
+VOICEMACRO_19_Ni_0_FEMALE = "If I wasn't purple, you'd see I was blushing.";
+VOICEMACRO_19_Ni_1 = "I hope you're not afraid of snakes.";
+VOICEMACRO_19_Ni_1_FEMALE = "Sure I've got exotic piercings.";
+VOICEMACRO_19_Ni_2 = "Baby, I'm mortal now. Time's a wasting.";
+VOICEMACRO_19_Ni_2_FEMALE = "I'm the type of girl my mother warned me about.";
+VOICEMACRO_19_Ni_3 = "I'm a force of nature.";
+VOICEMACRO_19_Ni_3_FEMALE = "There's nothing like sleeping in the forest under the moonlight.";
+VOICEMACRO_19_Ni_4 = "Wanna bring out the animal in me?";
+VOICEMACRO_19_Or_0 = "That armor looks good on you. It would also look good on my floor.";
+VOICEMACRO_19_Or_0_FEMALE = "You had me at zug zug.";
+VOICEMACRO_19_Or_1 = "This is true love. Do you think this happens every day?";
+VOICEMACRO_19_Or_1_FEMALE = "I'll give you crazy love.";
+VOICEMACRO_19_Or_2 = "You have six different smiles; one for when you're angry, one for when you tear flesh, one for when you chew flesh, one for when you loot bodies, one for when you skin game, and one for when you want to kill something.";
+VOICEMACRO_19_Or_2_FEMALE = "I like men who aren't afraid to cry; cry uncle.";
+VOICEMACRO_19_Or_3 = "I love you like a fat kid loves cake.";
+VOICEMACRO_19_Or_3_FEMALE = "You'll do. Let's go.";
+VOICEMACRO_19_Or_4 = "Lady, from the moment I see you I... I did not expect to get this far.";
+VOICEMACRO_19_Or_4_FEMALE = "Don't talk, just follow me.";
+VOICEMACRO_19_Or_5 = "Um, you look like a lady.";
+VOICEMACRO_19_Or_5_FEMALE = "Let's not ruin this moment with chit chat.";
+VOICEMACRO_19_Sc_0 = "I don't smell that bad for a dead dude, do I?";
+VOICEMACRO_19_Sc_0_FEMALE = "Nice butt.";
+VOICEMACRO_19_Sc_1 = "You have beautiful skin; no maggot holes at all.";
+VOICEMACRO_19_Sc_1_FEMALE = "One good thing about being dead, biological clock seems to have stopped.";
+VOICEMACRO_19_Sc_2 = "If rot was hot, I'd be a volcano.";
+VOICEMACRO_19_Sc_2_FEMALE = "Us Undead girls really know how to have a good time because, after all, what's the worst thing that could happen?";
+VOICEMACRO_19_Sc_3 = "Once you go dead, you never go back.";
+VOICEMACRO_19_Sc_3_FEMALE = "I can't wait to suck the juice out of your eyeballs.";
+VOICEMACRO_19_Sc_4 = "Check my breath. Is it bad enough for you?";
+VOICEMACRO_19_Sc_4_FEMALE = "I don't care that much about romance. I fell in love before, and look what happened to me.";
+VOICEMACRO_19_Sc_5 = "Don't mind the drool. It's just embalming fluid.";
+VOICEMACRO_19_Sc_5_FEMALE = "I don't need to get funky. I'm already there.";
+VOICEMACRO_19_Ta_0 = "You move me.";
+VOICEMACRO_19_Ta_0_FEMALE = "I'm tired of the same old bull.";
+VOICEMACRO_19_Ta_1 = "Hey, you into leather?";
+VOICEMACRO_19_Ta_1_FEMALE = "I want a man with soft hands. Preferably four of them.";
+VOICEMACRO_19_Ta_2 = "Free rides for the ladies.";
+VOICEMACRO_19_Ta_2_FEMALE = "I've got big soulful eyes, long eyelashes, and a wet tongue. What more could a guy want?";
+VOICEMACRO_19_Ta_3 = "Hey, you work out?";
+VOICEMACRO_19_Ta_3_FEMALE = "Come over here, sailor.";
+VOICEMACRO_19_Ta_4 = "You know, older bulls really only have one function.";
+VOICEMACRO_19_Ta_4_FEMALE = "Wanna see some good clog dancing?";
+VOICEMACRO_19_Ta_5 = "Are you comfortable with complicated machinery?";
+VOICEMACRO_19_Tr_0 = "Want some of my jungle love?";
+VOICEMACRO_19_Tr_0_FEMALE = "I know. My natural beauty is intimidating.";
+VOICEMACRO_19_Tr_1 = "We Trolls mate for life. 'Course, we believe in frequent reincarnation.";
+VOICEMACRO_19_Tr_1_FEMALE = "When enraged, and in heat, a female Troll can mate over eighty times in one night. Be you prepared?";
+VOICEMACRO_19_Tr_2 = "You look pretty. Pretty tasty.";
+VOICEMACRO_19_Tr_2_FEMALE = "Aren't you going to axe me out?";
+VOICEMACRO_19_Tr_3 = "I hope you're well rested. You're going to need your strength.";
+VOICEMACRO_19_Tr_3_FEMALE = "I won't bite you where it shows.";
+VOICEMACRO_19_Tr_4_FEMALE = "You're the type I'd like to sink my teeth into.";
+VOICEMACRO_1_Dw_0 = "Danger approaching!";
+VOICEMACRO_1_Dw_0_FEMALE = "Danger approaching!";
+VOICEMACRO_1_Dw_1 = "Heads up!";
+VOICEMACRO_1_Dw_1_FEMALE = "Heads up!";
+VOICEMACRO_1_Gn_0 = "Danger approaches!";
+VOICEMACRO_1_Gn_0_FEMALE = "Danger approaches!";
+VOICEMACRO_1_Hu_0 = "Guard yourself!";
+VOICEMACRO_1_Hu_0_FEMALE = "Guard yourself!";
+VOICEMACRO_1_Hu_1 = "On your guard!";
+VOICEMACRO_1_Hu_1_FEMALE = "On your guard!";
+VOICEMACRO_1_Ni_0 = "Beware!";
+VOICEMACRO_1_Ni_0_FEMALE = "Danger!";
+VOICEMACRO_1_Ni_1 = "Be alert!";
+VOICEMACRO_1_Ni_1_FEMALE = "Be alert!";
+VOICEMACRO_1_Or_0 = "Watch it!";
+VOICEMACRO_1_Or_0_FEMALE = "On your guard!";
+VOICEMACRO_1_Or_1 = "Incoming!";
+VOICEMACRO_1_Or_1_FEMALE = "Incoming!";
+VOICEMACRO_1_Or_2 = "On your guard!";
+VOICEMACRO_1_Sc_0 = "Danger!";
+VOICEMACRO_1_Sc_0_FEMALE = "Danger!";
+VOICEMACRO_1_Sc_1 = "Incoming!";
+VOICEMACRO_1_Sc_1_FEMALE = "Incoming!";
+VOICEMACRO_1_Ta_0 = "Danger approaches!";
+VOICEMACRO_1_Ta_0_FEMALE = "Danger approaches!";
+VOICEMACRO_1_Ta_1 = "On your guard!";
+VOICEMACRO_1_Ta_1_FEMALE = "On your guard!";
+VOICEMACRO_1_Ta_2_FEMALE = "Be watchful!";
+VOICEMACRO_1_Tr_0 = "There be danger!";
+VOICEMACRO_1_Tr_0_FEMALE = "There be danger!";
+VOICEMACRO_1_Tr_1 = "Bad things coming!";
+VOICEMACRO_1_Tr_1_FEMALE = "Bad things coming!";
+VOICEMACRO_20_Dw_0 = "Hi ho, hi ho... uh... second verse, same as the first.";
+VOICEMACRO_20_Dw_0_FEMALE = "No, they're not real, but thanks for noticing.";
+VOICEMACRO_20_Dw_1 = "Ah winter. Yes, winter.";
+VOICEMACRO_20_Dw_1_FEMALE = "I don't like to be underground. It reminds me of death.";
+VOICEMACRO_20_Dw_2 = "Oh, I'm having a wardrobe malfunction. Oh, there's my hammer.";
+VOICEMACRO_20_Dw_2_FEMALE = "I like my ale like I like my men; dark and rich.";
+VOICEMACRO_20_Dw_3 = "I don't have a drinking problem. I drink, I get drunk, I fall down, no problem.";
+VOICEMACRO_20_Dw_3_FEMALE = "It's like my father always used to say, \"Shut up, and get out.\"";
+VOICEMACRO_20_Dw_4 = "I don't drink anymore. 'Course, I don't drink any less, either.";
+VOICEMACRO_20_Dw_4_FEMALE = "My uncle has brass balls. No, really!";
+VOICEMACRO_20_Dw_5 = "I like my beer like I like my women; stout and bitter.";
+VOICEMACRO_20_Dw_5_FEMALE = "I give myself a Dutch oven pedicure every night. I've got no foot fungus at all. My toes are pristine.";
+VOICEMACRO_20_Dw_6 = "Oh, I'm just a social drinker. Every time someone says, \"I'll have a drink\", I say, \"So shall I.\"";
+VOICEMACRO_20_Gn_0 = "You know, I really wish I had a garden where I could put a couple of human statues.";
+VOICEMACRO_20_Gn_0_FEMALE = "I apologize profusely for any inconvenience my murderous rampage may have caused.";
+VOICEMACRO_20_Gn_1 = "I think that last vendor short changed me. Oh, that was a bad one.";
+VOICEMACRO_20_Gn_1_FEMALE = "I've discovered that getting pummeled by a blunt weapon can be quite painful.";
+VOICEMACRO_20_Gn_2 = "I do hope to find some interesting gadgets around here. I do love tinkering with things.";
+VOICEMACRO_20_Gn_2_FEMALE = "You know, squirrels can be deadly when cornered.";
+VOICEMACRO_20_Gn_3 = "I had an idea for a device that you could put small pieces of bread in to cook, but in the end I really didn't think there would be much of a market for it.";
+VOICEMACRO_20_Gn_3_FEMALE = "Some day, I hope to find the nuggets on a chicken.";
+VOICEMACRO_20_Gn_4 = "I'd like to give a shout out to my boys in Gnomeregan. Keeping it real Big-T, Snoop-Pup, and Little Dees. Y'all are short, but you're real, baby.";
+VOICEMACRO_20_Gn_5 = "I look bigger in those mirrors where things look bigger.";
+VOICEMACRO_20_Hu_0 = "Cover for me. I gotta whiz behind a tree.";
+VOICEMACRO_20_Hu_0_FEMALE = "Why does everyone automatically assume I know tailoring and cooking?";
+VOICEMACRO_20_Hu_1 = "So, an Orc walks into a bar with a parrot on his shoulder. The bartender says, \"Hey, where'd you get that?\" The parrot says, \"Durotar. They got 'em all over the place.\"";
+VOICEMACRO_20_Hu_1_FEMALE = "Do you ever feel like you're not in charge of your own destiny, like you're being controlled by an invisible hand?";
+VOICEMACRO_20_Hu_2 = "A duck walked into an apothecary and he said, \"Give me some chapstick, and put it on my bill.\"";
+VOICEMACRO_20_Hu_2_FEMALE = "Sometimes, I have trouble CONTROLLING THE VOLUME OF MY VOICE!";
+VOICEMACRO_20_Hu_3 = "How does a Tauren hide in a cherry tree? He paints his hooves red.";
+VOICEMACRO_20_Hu_3_FEMALE = "I like to fart in the tub.";
+VOICEMACRO_20_Hu_4 = "A guy walked up to me and said, \"I'm a teepee, I'm a wigwam, I'm a teepee, I'm a wigwam.\" I said, \"Relax, man, you're too tense.\"";
+VOICEMACRO_20_Hu_4_FEMALE = "Me and my girlfriends exchange clothes all the time. We're all the same size.";
+VOICEMACRO_20_Hu_5 = "So, I have this idea for a great movie. It's about two Gnomes who find a bracelet of power, and they have to take it to the Burning Steppes and cast it into The Cauldron. They form the Brotherhood of the Bracelet. Along the way, they're trailed by a murloc named Gottom who's obsessed with the bracelet, and nine bracelet bogeymen. It could be a three parter called \"Ruler of the Bracelet\". The first part would be called \"The Brotherhood of the Bracelet\", followed by \"A Couple of Towers\", with the climactic ending called \"Hey, the King's Back\".";
+VOICEMACRO_20_Hu_5_FEMALE = "I can't find anywhere to get my nails done.";
+VOICEMACRO_20_Hu_6_FEMALE = "I can't wait till this quest is done, and I can look for another Garibaldi artifact.";
+VOICEMACRO_20_Ni_0 = "Last night I went to an awesome stag party.";
+VOICEMACRO_20_Ni_0_FEMALE = "You know I have to keep moving at night or I'll disappear.";
+VOICEMACRO_20_Ni_1 = "You know those Ancient Protectors in Darnassas? They're not that old.";
+VOICEMACRO_20_Ni_1_FEMALE = "Actually, I'm more of a morning elf.";
+VOICEMACRO_20_Ni_2 = "Man, I was halfway through the Emerald Dream when I had to pee.";
+VOICEMACRO_20_Ni_2_FEMALE = "You know, Wisps are actually pretty useful for personal hygiene.";
+VOICEMACRO_20_Ni_3 = "Is that thing sharp? Could that thing cut me? I'm not immortal now, you know.";
+VOICEMACRO_20_Ni_3_FEMALE = "I think that guys just use the Emerald Dream as an excuse to avoid calling me back.";
+VOICEMACRO_20_Ni_4 = "I don't know about you, but I can't understand a thing those Wisps say. I usually just nod.";
+VOICEMACRO_20_Ni_4_FEMALE = "Oh, I'm dancing again. I hope all your friends are enjoying the show.";
+VOICEMACRO_20_Ni_5 = "Who wants to live forever?";
+VOICEMACRO_20_Ni_6 = "What? I didn't hear that.";
+VOICEMACRO_20_Ni_7 = "I don't mind the Gnomes, but I'm always worried about tripping over one.";
+VOICEMACRO_20_Or_0 = "I will crush and destroy and... ooo... shiny...";
+VOICEMACRO_20_Or_0_FEMALE = "Get between me and my food, and you'll lose a hand.";
+VOICEMACRO_20_Or_1 = "It's not easy being green.";
+VOICEMACRO_20_Or_1_FEMALE = "I have no respect for people with small piercings. I say go full hog. Put a spear through your head.";
+VOICEMACRO_20_Or_2 = "Man, dawg, you know, it's like I'm feeling you, but I'm not feeling you, you know?";
+VOICEMACRO_20_Or_2_FEMALE = "I feel very feminine, and I'll beat the crap out of anyone who disagrees.";
+VOICEMACRO_20_Or_3 = "I come from the Orcs. We eat with spoons and forks. We love to eat our pork.";
+VOICEMACRO_20_Or_3_FEMALE = "What's estrogen? Can you eat it?";
+VOICEMACRO_20_Or_4 = "Orc smash!";
+VOICEMACRO_20_Or_4_FEMALE = "I need to get my chest waxed again.";
+VOICEMACRO_20_Or_5 = "Stop poking me! Well, that was okay.";
+VOICEMACRO_20_Or_5_FEMALE = "Man, I think that boar meat's coming back on me. I gotta hit the can. Anyone have a hearthstone?";
+VOICEMACRO_20_Sc_0 = "I can't stand the smell of Orcs.";
+VOICEMACRO_20_Sc_0_FEMALE = "I'd paint my toenails, but I'm not sure where they fell off.";
+VOICEMACRO_20_Sc_1 = "I'm dead, and I'm pissed.";
+VOICEMACRO_20_Sc_1_FEMALE = "Yes, they're real. They're not mine, but they're real.";
+VOICEMACRO_20_Sc_2 = "Roses are gray, violets are gray. I'm dead and color blind.";
+VOICEMACRO_20_Sc_2_FEMALE = "I'm in a rotten mood.";
+VOICEMACRO_20_Sc_3 = "Hey diddle diddle, the mucus and the spittle, the corpse sank in the lagoon. The murloc said, \"Ahhh...\" to see such a sight, and the Dwarf spanked the baboon.";
+VOICEMACRO_20_Sc_3_FEMALE = "This stinks.";
+VOICEMACRO_20_Sc_4 = "Anyone have any odorant? Either \"wet dog\", \"fresh garbage\", or \"low tide\" would do.";
+VOICEMACRO_20_Sc_4_FEMALE = "You know, once you're dead, nothing smells bad anymore. Rotten eggs? No problem. Dead fish? Like a spring breeze.";
+VOICEMACRO_20_Sc_5_FEMALE = "You don't need deodorant when you don't have any armpits.";
+VOICEMACRO_20_Sc_6_FEMALE = "Ah, doornails.";
+VOICEMACRO_20_Sc_7_FEMALE = "I heard a knee slapper once, and skipped my kneecap right across a lake.";
+VOICEMACRO_20_Ta_0 = "Mess with the bull, you get the horns.";
+VOICEMACRO_20_Ta_0_FEMALE = "In my native tongue, my name means Dances with Tassels.";
+VOICEMACRO_20_Ta_1 = "Here's the beef.";
+VOICEMACRO_20_Ta_1_FEMALE = "I once laughed so hard, I milked all over the floor.";
+VOICEMACRO_20_Ta_2 = "Homogenized? No way. I like the ladies.";
+VOICEMACRO_20_Ta_2_FEMALE = "Happy Taurens come from Mulgore.";
+VOICEMACRO_20_Ta_3 = "You know, Taurens are born hunters. You ever see a Tauren catch a salmon out of a stream? It really is quite exciting. And, have you ever seen a Tauren stalk a python? 'Course you haven't. That's because Taurens are so adept at blending in with their surroundings.";
+VOICEMACRO_20_Ta_3_FEMALE = "You know how hard it is to get your groove on with the spirit of your great grandmother looking over you?";
+VOICEMACRO_20_Ta_4 = "Moo. Are you happy now?";
+VOICEMACRO_20_Tr_0 = "Cooking's done. Stew here.";
+VOICEMACRO_20_Tr_0_FEMALE = "Strong halitosis be but one of my feminine traits.";
+VOICEMACRO_20_Tr_1 = "I like my women dumpy and droopy with halitosis.";
+VOICEMACRO_20_Tr_1_FEMALE = "I feel pretty, oh so pretty (spit).";
+VOICEMACRO_20_Tr_2 = "I got a shrunken head. I just came out of the pool.";
+VOICEMACRO_20_Tr_2_FEMALE = "I got all this and personality, too.";
+VOICEMACRO_20_Tr_3 = "New Troll here.";
+VOICEMACRO_20_Tr_3_FEMALE = "The way to a man's heart be through his stomach, but I go through the rib cage.";
+VOICEMACRO_20_Tr_4 = "I kill two dwarves in the morning, I kill two dwarves at night. I kill two dwarves in the afternoon, and then I feel alright. I kill two dwarves in time of peace and two in time of war. I kill two dwarves before I kill two dwarves, and then I kill two more.";
+VOICEMACRO_20_Tr_4_FEMALE = "If cannibalism be wrong, I don't want to be right.";
+VOICEMACRO_20_Tr_5 = "I heard if you cut off an extremity, it'll regenerate a little bigger. Don't believe it.";
+VOICEMACRO_2_Dw_0 = "Charge!";
+VOICEMACRO_2_Dw_0_FEMALE = "Charge!";
+VOICEMACRO_2_Dw_1 = "For Khaz Modan!";
+VOICEMACRO_2_Dw_1_FEMALE = "By Muridan's beard!";
+VOICEMACRO_2_Gn_0 = "Get 'em!";
+VOICEMACRO_2_Gn_0_FEMALE = "For Gnomeregan!";
+VOICEMACRO_2_Gn_1 = "Attack!";
+VOICEMACRO_2_Gn_1_FEMALE = "Charge forth!";
+VOICEMACRO_2_Gn_2 = "For Gnomeregan!";
+VOICEMACRO_2_Hu_0 = "Charge!";
+VOICEMACRO_2_Hu_0_FEMALE = "Attack!";
+VOICEMACRO_2_Hu_1 = "To battle!";
+VOICEMACRO_2_Hu_1_FEMALE = "To battle!";
+VOICEMACRO_2_Ni_0 = "For Cenarius!";
+VOICEMACRO_2_Ni_0_FEMALE = "By Elune!";
+VOICEMACRO_2_Ni_1 = "Attack!";
+VOICEMACRO_2_Ni_1_FEMALE = "Attack for the goddess!";
+VOICEMACRO_2_Ni_2_FEMALE = "Charge forth!";
+VOICEMACRO_2_Or_0 = "Destroy them!";
+VOICEMACRO_2_Or_0_FEMALE = "Attack!";
+VOICEMACRO_2_Or_1 = "Slay them all!";
+VOICEMACRO_2_Or_1_FEMALE = "Slay them all!";
+VOICEMACRO_2_Or_2 = "Break their bones!";
+VOICEMACRO_2_Or_2_FEMALE = "Leave none alive!";
+VOICEMACRO_2_Sc_0 = "For the forsaken!";
+VOICEMACRO_2_Sc_0_FEMALE = "Rend flesh with me!";
+VOICEMACRO_2_Sc_1 = "Rend flesh with me!";
+VOICEMACRO_2_Sc_1_FEMALE = "For the forsaken!";
+VOICEMACRO_2_Ta_0 = "For Kalimdor!";
+VOICEMACRO_2_Ta_0_FEMALE = "For Kalimdor!";
+VOICEMACRO_2_Ta_1 = "Unleash your fury!";
+VOICEMACRO_2_Ta_1_FEMALE = "Attack!";
+VOICEMACRO_2_Ta_2 = "Charge!";
+VOICEMACRO_2_Tr_0 = "For Zul'jin!";
+VOICEMACRO_2_Tr_0_FEMALE = "For Zul'jin!";
+VOICEMACRO_2_Tr_1 = "Now, we kill!";
+VOICEMACRO_2_Tr_1_FEMALE = "We bring the pain to them!";
+VOICEMACRO_3_Dw_0 = "Run away!";
+VOICEMACRO_3_Dw_0_FEMALE = "Run away!";
+VOICEMACRO_3_Dw_1 = "Let's run!";
+VOICEMACRO_3_Dw_1_FEMALE = "Run!";
+VOICEMACRO_3_Dw_2 = "Run!";
+VOICEMACRO_3_Gn_0 = "Run!";
+VOICEMACRO_3_Gn_0_FEMALE = "Run!";
+VOICEMACRO_3_Gn_1 = "Let's get out of here!";
+VOICEMACRO_3_Gn_1_FEMALE = "Let's get outta here!";
+VOICEMACRO_3_Gn_2 = "Retreat!";
+VOICEMACRO_3_Gn_2_FEMALE = "Retreat!";
+VOICEMACRO_3_Hu_0 = "Run!";
+VOICEMACRO_3_Hu_0_FEMALE = "Run!";
+VOICEMACRO_3_Hu_1 = "Retreat!";
+VOICEMACRO_3_Hu_1_FEMALE = "Retreat!";
+VOICEMACRO_3_Ni_0 = "Retreat!";
+VOICEMACRO_3_Ni_0_FEMALE = "Run!";
+VOICEMACRO_3_Ni_1 = "Scatter!";
+VOICEMACRO_3_Ni_1_FEMALE = "Our foe is too strong!";
+VOICEMACRO_3_Or_0 = "Retreat!";
+VOICEMACRO_3_Or_0_FEMALE = "Retreat!";
+VOICEMACRO_3_Or_1 = "Run!";
+VOICEMACRO_3_Or_1_FEMALE = "Run!";
+VOICEMACRO_3_Sc_0 = "Move your carcass!";
+VOICEMACRO_3_Sc_0_FEMALE = "Run!";
+VOICEMACRO_3_Sc_1 = "Turn back!";
+VOICEMACRO_3_Sc_1_FEMALE = "Move your carcass!";
+VOICEMACRO_3_Ta_0 = "Run!";
+VOICEMACRO_3_Ta_0_FEMALE = "Retreat!";
+VOICEMACRO_3_Ta_1 = "Retreat!";
+VOICEMACRO_3_Ta_1_FEMALE = "Save your hide!";
+VOICEMACRO_3_Tr_0 = "Run!";
+VOICEMACRO_3_Tr_0_FEMALE = "Run for the hills!";
+VOICEMACRO_3_Tr_1 = "Get outta here!";
+VOICEMACRO_3_Tr_1_FEMALE = "Get outta here!";
+VOICEMACRO_4_Dw_0 = "Join my attack!";
+VOICEMACRO_4_Dw_0_FEMALE = "Join my attack!";
+VOICEMACRO_4_Dw_1 = "Attack this one!";
+VOICEMACRO_4_Dw_1_FEMALE = "Attack this one!";
+VOICEMACRO_4_Dw_2 = "Help me with this cretin!";
+VOICEMACRO_4_Gn_0 = "Please, join my fight!";
+VOICEMACRO_4_Gn_0_FEMALE = "Can I get some help over here?";
+VOICEMACRO_4_Gn_1 = "Help me attack over here!";
+VOICEMACRO_4_Gn_1_FEMALE = "Hey, help me attack over here!";
+VOICEMACRO_4_Hu_0 = "Aid my attack!";
+VOICEMACRO_4_Hu_0_FEMALE = "Aid my attack!";
+VOICEMACRO_4_Hu_1 = "Attack over here!";
+VOICEMACRO_4_Hu_1_FEMALE = "Attack over here!";
+VOICEMACRO_4_Ni_0 = "Assault my attacker!";
+VOICEMACRO_4_Ni_0_FEMALE = "Assault this foe!";
+VOICEMACRO_4_Ni_1 = "Smite my foe!";
+VOICEMACRO_4_Ni_1_FEMALE = "Over here!";
+VOICEMACRO_4_Ni_2_FEMALE = "Assault my attacker!";
+VOICEMACRO_4_Or_0 = "Attack over here!";
+VOICEMACRO_4_Or_0_FEMALE = "Attack over here!";
+VOICEMACRO_4_Or_1 = "Attack with me!";
+VOICEMACRO_4_Or_1_FEMALE = "Shed blood with me!";
+VOICEMACRO_4_Or_2 = "Shed blood with me!";
+VOICEMACRO_4_Or_2_FEMALE = "Join my attack!";
+VOICEMACRO_4_Sc_0 = "Join my fight!";
+VOICEMACRO_4_Sc_0_FEMALE = "Join the slaughter!";
+VOICEMACRO_4_Sc_1 = "Help me attack!";
+VOICEMACRO_4_Sc_1_FEMALE = "Help me attack!";
+VOICEMACRO_4_Ta_0 = "Fight at my side!";
+VOICEMACRO_4_Ta_0_FEMALE = "Fight at my side!";
+VOICEMACRO_4_Ta_1 = "Join my fight!";
+VOICEMACRO_4_Ta_1_FEMALE = "Join my fight!";
+VOICEMACRO_4_Tr_0 = "Strike this foe!";
+VOICEMACRO_4_Tr_0_FEMALE = "Strike this foe!";
+VOICEMACRO_4_Tr_1 = "Help me here!";
+VOICEMACRO_4_Tr_1_FEMALE = "This the one to fight!";
+VOICEMACRO_5_Dw_0 = "I've got no mana!";
+VOICEMACRO_5_Dw_0_FEMALE = "I've got no mana!";
+VOICEMACRO_5_Dw_1 = "I need more mana!";
+VOICEMACRO_5_Dw_1_FEMALE = "I need more mana!";
+VOICEMACRO_5_Gn_0 = "I need some mana!";
+VOICEMACRO_5_Gn_0_FEMALE = "My mana is running low!";
+VOICEMACRO_5_Gn_1 = "I'm short on mana!";
+VOICEMACRO_5_Gn_1_FEMALE = "I'm short on mana!";
+VOICEMACRO_5_Hu_0 = "I'm out of mana!";
+VOICEMACRO_5_Hu_0_FEMALE = "I'm out of mana!";
+VOICEMACRO_5_Hu_1 = "My mana is low!";
+VOICEMACRO_5_Hu_1_FEMALE = "I need more mana!";
+VOICEMACRO_5_Ni_0 = "My mana is low!";
+VOICEMACRO_5_Ni_0_FEMALE = "My mana is low!";
+VOICEMACRO_5_Ni_1 = "My mana has waned!";
+VOICEMACRO_5_Ni_1_FEMALE = "My mana is nearly gone!";
+VOICEMACRO_5_Or_0 = "I need mana!";
+VOICEMACRO_5_Or_0_FEMALE = "I need mana!";
+VOICEMACRO_5_Or_1 = "My mana is low!";
+VOICEMACRO_5_Or_1_FEMALE = "My mana is low!";
+VOICEMACRO_5_Sc_0 = "My mana is drained!";
+VOICEMACRO_5_Sc_0_FEMALE = "I need mana!";
+VOICEMACRO_5_Sc_1 = "I need mana!";
+VOICEMACRO_5_Sc_1_FEMALE = "My mana is exhausted!";
+VOICEMACRO_5_Ta_0 = "I need more mana!";
+VOICEMACRO_5_Ta_0_FEMALE = "My mana must be replenished!";
+VOICEMACRO_5_Ta_1 = "My mana is spent!";
+VOICEMACRO_5_Ta_1_FEMALE = "I need more mana!";
+VOICEMACRO_5_Tr_0 = "Me mana be running low!";
+VOICEMACRO_5_Tr_0_FEMALE = "Me mana running low!";
+VOICEMACRO_5_Tr_1 = "I be needing more mana!";
+VOICEMACRO_5_Tr_1_FEMALE = "I be needing more mana!";
+VOICEMACRO_6_Dw_0 = "I'll lead the way.";
+VOICEMACRO_6_Dw_0_FEMALE = "I'll lead the way.";
+VOICEMACRO_6_Dw_1 = "Follow me.";
+VOICEMACRO_6_Dw_1_FEMALE = "Follow me!";
+VOICEMACRO_6_Dw_2 = "Follow me, quick.";
+VOICEMACRO_6_Gn_0 = "I'll lead the way.";
+VOICEMACRO_6_Gn_0_FEMALE = "Follow me.";
+VOICEMACRO_6_Gn_1 = "Follow me.";
+VOICEMACRO_6_Hu_0 = "Follow me.";
+VOICEMACRO_6_Hu_0_FEMALE = "Follow me.";
+VOICEMACRO_6_Hu_1 = "I'll lead the way.";
+VOICEMACRO_6_Hu_1_FEMALE = "I'll lead the way.";
+VOICEMACRO_6_Ni_0 = "I'll lead the way.";
+VOICEMACRO_6_Ni_0_FEMALE = "I'll lead the way.";
+VOICEMACRO_6_Ni_1 = "Follow me.";
+VOICEMACRO_6_Ni_1_FEMALE = "Follow me.";
+VOICEMACRO_6_Or_0 = "Follow me.";
+VOICEMACRO_6_Or_0_FEMALE = "Follow me.";
+VOICEMACRO_6_Or_1 = "Come.";
+VOICEMACRO_6_Or_1_FEMALE = "Come.";
+VOICEMACRO_6_Sc_0 = "This way.";
+VOICEMACRO_6_Sc_0_FEMALE = "This way.";
+VOICEMACRO_6_Sc_1 = "I will lead the way.";
+VOICEMACRO_6_Sc_1_FEMALE = "Follow.";
+VOICEMACRO_6_Ta_0 = "Come with me.";
+VOICEMACRO_6_Ta_0_FEMALE = "Come with me.";
+VOICEMACRO_6_Ta_1 = "I'll lead the way.";
+VOICEMACRO_6_Ta_1_FEMALE = "Follow my trail.";
+VOICEMACRO_6_Tr_0 = "Follow me.";
+VOICEMACRO_6_Tr_0_FEMALE = "I lead the way.";
+VOICEMACRO_6_Tr_1 = "You go with me.";
+VOICEMACRO_6_Tr_1_FEMALE = "You go with me.";
+VOICEMACRO_7_Dw_0 = "Wait here.";
+VOICEMACRO_7_Dw_0_FEMALE = "Stay here.";
+VOICEMACRO_7_Dw_1 = "Stay put.";
+VOICEMACRO_7_Dw_1_FEMALE = "Wait here.";
+VOICEMACRO_7_Dw_2 = "Stay here.";
+VOICEMACRO_7_Gn_0 = "Stay here for a moment.";
+VOICEMACRO_7_Gn_0_FEMALE = "Stay here for a moment.";
+VOICEMACRO_7_Gn_1 = "Wait here, please.";
+VOICEMACRO_7_Gn_1_FEMALE = "Wait here, please.";
+VOICEMACRO_7_Hu_0 = "Stay put.";
+VOICEMACRO_7_Hu_0_FEMALE = "Stay put.";
+VOICEMACRO_7_Hu_1 = "Stay here.";
+VOICEMACRO_7_Hu_1_FEMALE = "Stay here.";
+VOICEMACRO_7_Hu_2 = "Wait here.";
+VOICEMACRO_7_Hu_2_FEMALE = "Wait here.";
+VOICEMACRO_7_Ni_0 = "Remain here.";
+VOICEMACRO_7_Ni_0_FEMALE = "Remain here.";
+VOICEMACRO_7_Ni_1 = "Wait here.";
+VOICEMACRO_7_Ni_1_FEMALE = "Wait here.";
+VOICEMACRO_7_Or_0 = "Remain here.";
+VOICEMACRO_7_Or_0_FEMALE = "Stay.";
+VOICEMACRO_7_Or_1 = "Stay here.";
+VOICEMACRO_7_Or_1_FEMALE = "Wait here.";
+VOICEMACRO_7_Sc_0 = "Wait.";
+VOICEMACRO_7_Sc_0_FEMALE = "Stay here.";
+VOICEMACRO_7_Sc_1 = "Stay here.";
+VOICEMACRO_7_Sc_1_FEMALE = "Don't move.";
+VOICEMACRO_7_Ta_0 = "Rest a moment.";
+VOICEMACRO_7_Ta_0_FEMALE = "Rest your haunches.";
+VOICEMACRO_7_Ta_1 = "Remain here.";
+VOICEMACRO_7_Ta_1_FEMALE = "Remain here.";
+VOICEMACRO_7_Ta_2 = "Stew here.";
+VOICEMACRO_7_Tr_0 = "You stay here.";
+VOICEMACRO_7_Tr_0_FEMALE = "You stay here.";
+VOICEMACRO_7_Tr_1 = "Stay put.";
+VOICEMACRO_7_Tr_1_FEMALE = "Stay put.";
+VOICEMACRO_7_Tr_2 = "Don't you be going nowhere.";
+VOICEMACRO_7_Tr_2_FEMALE = "Don't you be going nowhere.";
+VOICEMACRO_8_Dw_0 = "I need healing!";
+VOICEMACRO_8_Dw_0_FEMALE = "I need healing!";
+VOICEMACRO_8_Dw_1 = "Tend me wounds!";
+VOICEMACRO_8_Dw_1_FEMALE = "Tend me wounds!";
+VOICEMACRO_8_Dw_2 = "Heal me!";
+VOICEMACRO_8_Dw_2_FEMALE = "Heal me!";
+VOICEMACRO_8_Gn_0 = "Please, heal me!";
+VOICEMACRO_8_Gn_0_FEMALE = "Please, heal me!";
+VOICEMACRO_8_Gn_1 = "Would you please heal me?";
+VOICEMACRO_8_Gn_1_FEMALE = "Would you please heal me?";
+VOICEMACRO_8_Hu_0 = "I need healing!";
+VOICEMACRO_8_Hu_0_FEMALE = "I need healing.";
+VOICEMACRO_8_Hu_1 = "Heal me!";
+VOICEMACRO_8_Hu_1_FEMALE = "Heal me!";
+VOICEMACRO_8_Ni_0 = "Heal me!";
+VOICEMACRO_8_Ni_0_FEMALE = "Heal me!";
+VOICEMACRO_8_Ni_1 = "I need healing!";
+VOICEMACRO_8_Ni_1_FEMALE = "I need healing!";
+VOICEMACRO_8_Or_0 = "Heal me!";
+VOICEMACRO_8_Or_0_FEMALE = "Heal me!";
+VOICEMACRO_8_Or_1 = "I need healing!";
+VOICEMACRO_8_Or_1_FEMALE = "I need healing!";
+VOICEMACRO_8_Sc_0 = "Heal my flesh!";
+VOICEMACRO_8_Sc_0_FEMALE = "Heal me!";
+VOICEMACRO_8_Sc_1 = "Heal me!";
+VOICEMACRO_8_Sc_1_FEMALE = "Bind my wounds!";
+VOICEMACRO_8_Ta_0 = "Heal me!";
+VOICEMACRO_8_Ta_0_FEMALE = "Heal me!";
+VOICEMACRO_8_Ta_1 = "I need healing!";
+VOICEMACRO_8_Ta_1_FEMALE = "I need healing!";
+VOICEMACRO_8_Tr_0 = "Cure me!";
+VOICEMACRO_8_Tr_0_FEMALE = "I be in a bad way!";
+VOICEMACRO_8_Tr_1 = "Heal me!";
+VOICEMACRO_8_Tr_1_FEMALE = "Cure me!";
+VOICEMACRO_8_Tr_2 = "I be in a bad way.";
+VOICEMACRO_8_Tr_2_FEMALE = "Heal me!";
+VOICEMACRO_LABEL = "Voice Emote";
+VOICEMACRO_LABEL_AID1 = "aid";
+VOICEMACRO_LABEL_ATTACKMYTARGET1 = "assist";
+VOICEMACRO_LABEL_ATTACKMYTARGET2 = "as";
+VOICEMACRO_LABEL_CHARGE1 = "charge";
+VOICEMACRO_LABEL_CHEER1 = "cheer";
+VOICEMACRO_LABEL_CONGRATULATIONS1 = "grats";
+VOICEMACRO_LABEL_CONGRATULATIONS2 = "congrats";
+VOICEMACRO_LABEL_CONGRATULATIONS3 = "congratulations";
+VOICEMACRO_LABEL_FLEE1 = "flee";
+VOICEMACRO_LABEL_FLEE2 = "run";
+VOICEMACRO_LABEL_FLIRT1 = "flirt";
+VOICEMACRO_LABEL_FOLLOW1 = "followme";
+VOICEMACRO_LABEL_FOLLOWME1 = "followme";
+VOICEMACRO_LABEL_FOLLOWME2 = "follow";
+VOICEMACRO_LABEL_FOLLOWME3 = "fol";
+VOICEMACRO_LABEL_GOODBYE1 = "goodbye";
+VOICEMACRO_LABEL_GOODBYE2 = "bye";
+VOICEMACRO_LABEL_HEALME1 = "heal";
+VOICEMACRO_LABEL_HEALME2 = "healme";
+VOICEMACRO_LABEL_HELLO1 = "hello";
+VOICEMACRO_LABEL_HELP1 = "helpme";
+VOICEMACRO_LABEL_HELPME1 = "help";
+VOICEMACRO_LABEL_HELPME2 = "helpme";
+VOICEMACRO_LABEL_INCOMING1 = "incoming";
+VOICEMACRO_LABEL_INCOMING2 = "inc";
+VOICEMACRO_LABEL_JOKE1 = "silly";
+VOICEMACRO_LABEL_NO1 = "no";
+VOICEMACRO_LABEL_OPENFIRE1 = "fire";
+VOICEMACRO_LABEL_OPENFIRE2 = "openfire";
+VOICEMACRO_LABEL_OUTOFMANA1 = "oom";
+VOICEMACRO_LABEL_OUTOFMANA2 = "outofmana";
+VOICEMACRO_LABEL_RASPBERRY1 = "rasp";
+VOICEMACRO_LABEL_RASPBERRY2 = "raspberry";
+VOICEMACRO_LABEL_SILLY1 = "silly";
+VOICEMACRO_LABEL_THANKYOU1 = "thankyou";
+VOICEMACRO_LABEL_THANKYOU2 = "thanks";
+VOICEMACRO_LABEL_THANKYOU3 = "thank";
+VOICEMACRO_LABEL_TRAIN1 = "train";
+VOICEMACRO_LABEL_WAITHERE1 = "wait";
+VOICEMACRO_LABEL_WAITHERE2 = "waithere";
+VOICEMACRO_LABEL_YES1 = "yes";
+VOICEMACRO_LABEL_YOUREWELCOME1 = "welcome";
+VOICEMACRO_LABEL_YOUREWELCOME2 = "welc";
+VOICE_ACTIVATED = "Voice Activated";
+VOICE_ACTIVATION_SENSITIVITY = "Activation Sensitivity";
+VOICE_AMBIENCE = "Ambience";
+VOICE_CHAT = "Voice Chat";
+VOICE_CHAT_AUDIO_DUCKING = "Select the level game sounds should adjust to while listening or talking in voice chat.";
+VOICE_CHAT_BATTLEGROUND = "Battleground";
+VOICE_CHAT_MODE = "Voice Chat Mode";
+VOICE_CHAT_NORMAL = "Normal";
+VOICE_CHAT_OPTIONS = "Voice Options";
+VOICE_CHAT_OUTPUT_DEVICE = "Speakers";
+VOICE_CHAT_PARTY_RAID = "Party/Raid";
+VOICE_GAME_DUCKING = "Game Audio Fade";
+VOICE_INPUT_VOLUME = "Microphone Volume";
+VOICE_LABEL = "Voice";
+VOICE_LISTENING = "Listening";
+VOICE_MICROPHONE_TEST = "Microphone Test";
+VOICE_MIC_TEST_PLAY = "Play the recorded sample.";
+VOICE_MIC_TEST_RECORD = "Record a sample.";
+VOICE_MUSIC = "Music";
+VOICE_OUTPUT_VOLUME = "Speaker Volume";
+VOICE_SOUND = "Sound";
+VOICE_SUBTEXT = "These options control sound hardware and input settings for the voice chat system.";
+VOICE_TALKING = "Talking";
+VOLUME = "Volume";
+VOTE_BOOT_PLAYER = "A vote has been initiated to remove %1$s from the group.\n\nThe reason given was:\n|cffffd200%2$s|r\n\nDo you want to kick %1$s?";
+VOTE_BOOT_REASON_REQUIRED = "Please enter the reason to vote kick %s:";
+VOTE_TO_KICK = "Vote to Kick";
+VULNERABLE_TRAILER = " (+%d vulnerability bonus)";
+WAISTSLOT = "Waist";
+WARLOCK_INTELLECT_TOOLTIP = "Increases mana points and chance to score a critical hit with spells.\nIncreases the rate at which weapon skills improve.";
+WARRIOR_STRENGTH_TOOLTIP = "Increases attack power with melee weapons.\nIncreases the amount of damage that can be blocked with a shield.";
+WATCHFRAME_LOCK = "Lock Objectives Frame";
+WATCH_FRAME_WIDTH_TEXT = "Wider Objectives Tracker|TInterface\\OptionsFrame\\UI-OptionsFrame-NewFeatureIcon:0:0:0:-1|t";
+WATER_COLLISION = "Water Collision";
+WATER_DETAIL = "Water Detail";
+WEAPON_SKILL_RATING = "Weapon Skill Rating %d";
+WEAPON_SKILL_RATING_BONUS = " (+%d skill)";
+WEAPON_SPEED = "Speed";
+WEATHER_DETAIL = "Weather Intensity";
+WEEKDAY_FRIDAY = "Friday";
+WEEKDAY_MONDAY = "Monday";
+WEEKDAY_SATURDAY = "Saturday";
+WEEKDAY_SUNDAY = "Sunday";
+WEEKDAY_THURSDAY = "Thursday";
+WEEKDAY_TUESDAY = "Tuesday";
+WEEKDAY_WEDNESDAY = "Wednesday";
+WHISPER = "Whisper";
+WHISPER_MESSAGE = "Whisper";
+WHO = "Who";
+WHO_FRAME_SHOWN_TEMPLATE = "(%d displayed)";
+WHO_FRAME_TOTAL_TEMPLATE = "%d |4Person:People; Found";
+WHO_LIST = "Who List";
+WHO_LIST_FORMAT = "|Hplayer:%s|h[%s]|h: Level %d %s %s - %s";
+WHO_LIST_GUILD_FORMAT = "|Hplayer:%s|h[%s]|h: Level %d %s %s <%s> - %s";
+WHO_NUM_RESULTS = "%d |4player:players; total";
+WHO_TAG_CLASS = "c-";
+WHO_TAG_GUILD = "g-";
+WHO_TAG_NAME = "n-";
+WHO_TAG_RACE = "r-";
+WHO_TAG_ZONE = "z-";
+WIDESCREEN_TAG = "(Wide)";
+WIN = "Win";
+WINDOWED_MAXIMIZED = "Maximized";
+WINDOWED_MODE = "Windowed Mode";
+WINDOW_LOCK = "Disable Resize";
+WINTERGRASP_IN_PROGRESS = "In Progress";
+WIN_LOSS = "Win - Loss";
+WITHDRAW = "Withdraw";
+WORK_IN_PROGRESS = "Work in progress";
+WORLDMAP_BUTTON = "World Map";
+WORLD_APPEARANCE = "World Appearance";
+WORLD_LOD = "Level of Detail";
+WORLD_MAP = "World Map";
+WORLD_PORT_ROOT_TIMER = "You have fallen through the world. You will be rooted here for %d %s.";
+WORLD_PVP_DISPLAY = "Display World PVP Objectives";
+WORLD_PVP_ENTER = "You have been called to join the Wintergrasp battle! Join now?|nTime remaining: %d %s";
+WORLD_PVP_EXITED_BATTLE = "You have exited the battle for Wintergrasp.";
+WORLD_PVP_FAIL = "You cannot queue for Wintergrasp at this time.";
+WORLD_PVP_INVITED = "Would you like to join the Wintergrasp battle?";
+WORLD_PVP_INVITED_WARMUP = "The battle for Wintergrasp is about to begin! Would you like to join the queue?";
+WORLD_PVP_LOW_LEVEL = "You are too low level to do battle in Wintergrasp.";
+WORLD_PVP_PENDING = "Wintergrasp is full.|n You are queued but have not yet been called to battle. You will be ported out in a few moments.";
+WORLD_PVP_PENDING_REMOTE = "Wintergrasp is full.|n You are queued but have not yet been called to battle.";
+WORLD_PVP_QUEUED = "Wintergrasp is full.|nYou are queued for battle. Please wait.";
+WORLD_PVP_QUEUED_WARMUP = "You are in the queue for the upcoming Wintergrasp battle.";
+WOW_MOUSE = "Detect World of Warcraft Gaming Mouse";
+WOW_MOUSE_NOT_FOUND = "World of Warcraft Gaming Mouse could not be found. Re-enable the option in Interface Options when you have one connected.";
+WRISTSLOT = "Wrist";
+WRONG_SLOT_FOR_ITEM = "That item does not go in that slot.";
+XP = "XP";
+XPBAR_LABEL = "XP Bar";
+XP_BAR_TEXT = "Experience Bar Text";
+XP_TEXT = "|cffffffff%d / %d ( %d%% )|r\n\n";
+YELL = "Yell";
+YELLOW_GEM = "Yellow";
+YELL_MESSAGE = "Yell";
+YES = "Yes";
+YOU = "You";
+YOUR_BID = "Your bid:";
+YOUR_CLASS_MAY_NOT_PERFORM_ROLE = "Your class may not perform this role.";
+YOUR_ROLE = "Your Role";
+YOU_ARE_IN_DUNGEON_GROUP = "You are in a dungeon group.";
+YOU_ARE_LISTED_IN_LFR = "You are currently listed in the Raid Browser.";
+YOU_LOOT_MONEY = "You loot %s";
+YOU_MAY_NOT_QUEUE_FOR_DUNGEON = "You may not queue for this dungeon.";
+YOU_MAY_NOT_QUEUE_FOR_THIS = "You may not queue for this.";
+YOU_RECEIVED = "You Received:";
+ZHCN = "Simplified Chinese";
+ZHTW = "Traditional Chinese";
+ZONE = "Zone";
+ZONE_COLON = "Zone:";
+ZONE_UNDER_ATTACK = "|cffffff00%s is under attack!|r";
+ZOOM_IN = "Zoom In";
+ZOOM_OUT = "Zoom Out";
+ZOOM_OUT_BUTTON_TEXT = "Right Click On Map To Zoom Out";
+_RECORDING_WARNING_CORRUPTED = "This movie file is not valid.";
diff --git a/reference/FrameXML/GossipFrame.lua b/reference/FrameXML/GossipFrame.lua
new file mode 100644
index 0000000..401f66b
--- /dev/null
+++ b/reference/FrameXML/GossipFrame.lua
@@ -0,0 +1,173 @@
+
+NUMGOSSIPBUTTONS = 32;
+
+function GossipFrame_OnLoad(self)
+ self:RegisterEvent("GOSSIP_SHOW");
+ self:RegisterEvent("GOSSIP_CLOSED");
+end
+
+function GossipFrame_OnEvent(self, event, ...)
+ if ( event == "GOSSIP_SHOW" ) then
+ -- if there is only a non-gossip option, then go to it directly
+ if ( (GetNumGossipAvailableQuests() == 0) and (GetNumGossipActiveQuests() == 0) and (GetNumGossipOptions() == 1) and not ForceGossip() ) then
+ local text, gossipType = GetGossipOptions();
+ if ( gossipType ~= "gossip" ) then
+ SelectGossipOption(1);
+ return;
+ end
+ end
+
+ if ( not GossipFrame:IsShown() ) then
+ ShowUIPanel(self);
+ if ( not self:IsShown() ) then
+ CloseGossip();
+ return;
+ end
+ end
+ GossipFrameUpdate();
+ elseif ( event == "GOSSIP_CLOSED" ) then
+ HideUIPanel(self);
+ end
+end
+
+function GossipFrameUpdate()
+ GossipFrame.buttonIndex = 1;
+ GossipGreetingText:SetText(GetGossipText());
+ GossipFrameAvailableQuestsUpdate(GetGossipAvailableQuests());
+ GossipFrameActiveQuestsUpdate(GetGossipActiveQuests());
+ GossipFrameOptionsUpdate(GetGossipOptions());
+ for i=GossipFrame.buttonIndex, NUMGOSSIPBUTTONS do
+ _G["GossipTitleButton" .. i]:Hide();
+ end
+ GossipFrameNpcNameText:SetText(UnitName("npc"));
+ if ( UnitExists("npc") ) then
+ SetPortraitTexture(GossipFramePortrait, "npc");
+ else
+ GossipFramePortrait:SetTexture("Interface\\QuestFrame\\UI-QuestLog-BookIcon");
+ end
+
+ -- Set Spacer
+ if ( GossipFrame.buttonIndex > 1 ) then
+ GossipSpacerFrame:SetPoint("TOP", "GossipTitleButton"..GossipFrame.buttonIndex-1, "BOTTOM", 0, 0);
+ GossipSpacerFrame:Show();
+ else
+ GossipSpacerFrame:Hide();
+ end
+
+ -- Update scrollframe
+ GossipGreetingScrollFrame:SetVerticalScroll(0);
+end
+
+function GossipTitleButton_OnClick(self, button)
+ if ( self.type == "Available" ) then
+ SelectGossipAvailableQuest(self:GetID());
+ elseif ( self.type == "Active" ) then
+ SelectGossipActiveQuest(self:GetID());
+ else
+ SelectGossipOption(self:GetID());
+ end
+end
+
+function GossipFrameAvailableQuestsUpdate(...)
+ local titleButton;
+ local titleIndex = 1;
+ local titleButtonIcon;
+ local isTrivial, isDaily, isRepeatable;
+ for i=1, select("#", ...), 5 do
+ if ( GossipFrame.buttonIndex > NUMGOSSIPBUTTONS ) then
+ message("This NPC has too many quests and/or gossip options.");
+ end
+ titleButton = _G["GossipTitleButton" .. GossipFrame.buttonIndex];
+ titleButtonIcon = _G[titleButton:GetName() .. "GossipIcon"];
+ isTrivial = select(i+2, ...);
+ isDaily = select(i+3, ...);
+ isRepeatable = select(i+4, ...);
+ if ( isDaily ) then
+ titleButtonIcon:SetTexture("Interface\\GossipFrame\\DailyQuestIcon");
+ elseif ( isRepeatable ) then
+ titleButtonIcon:SetTexture("Interface\\GossipFrame\\DailyActiveQuestIcon");
+ else
+ titleButtonIcon:SetTexture("Interface\\GossipFrame\\AvailableQuestIcon");
+ end
+ if ( isTrivial ) then
+ titleButton:SetFormattedText(TRIVIAL_QUEST_DISPLAY, select(i, ...));
+ titleButtonIcon:SetVertexColor(0.5,0.5,0.5);
+ else
+ titleButton:SetFormattedText(NORMAL_QUEST_DISPLAY, select(i, ...));
+ titleButtonIcon:SetVertexColor(1,1,1);
+ end
+ GossipResize(titleButton);
+ titleButton:SetID(titleIndex);
+ titleButton.type="Available";
+ GossipFrame.buttonIndex = GossipFrame.buttonIndex + 1;
+ titleIndex = titleIndex + 1;
+ titleButton:Show();
+ end
+ if ( GossipFrame.buttonIndex > 1 ) then
+ titleButton = _G["GossipTitleButton" .. GossipFrame.buttonIndex];
+ titleButton:Hide();
+ GossipFrame.buttonIndex = GossipFrame.buttonIndex + 1;
+ end
+end
+
+function GossipFrameActiveQuestsUpdate(...)
+ local titleButton;
+ local titleIndex = 1;
+ local titleButtonIcon;
+ for i=1, select("#", ...), 4 do
+ if ( GossipFrame.buttonIndex > NUMGOSSIPBUTTONS ) then
+ message("This NPC has too many quests and/or gossip options.");
+ end
+ titleButton = _G["GossipTitleButton" .. GossipFrame.buttonIndex];
+ titleButtonIcon = _G[titleButton:GetName() .. "GossipIcon"];
+ if ( select(i+2, ...) ) then
+ titleButton:SetFormattedText(TRIVIAL_QUEST_DISPLAY, select(i, ...));
+ titleButtonIcon:SetVertexColor(0.5,0.5,0.5);
+ else
+ titleButton:SetFormattedText(NORMAL_QUEST_DISPLAY, select(i, ...));
+ titleButtonIcon:SetVertexColor(1,1,1);
+ end
+ GossipResize(titleButton);
+ titleButton:SetID(titleIndex);
+ titleButton.type="Active";
+ if ( select(i+3, ...) ) then
+ titleButtonIcon:SetTexture("Interface\\GossipFrame\\ActiveQuestIcon");
+ else
+ titleButtonIcon:SetTexture("Interface\\GossipFrame\\IncompleteQuestIcon");
+ end
+ GossipFrame.buttonIndex = GossipFrame.buttonIndex + 1;
+ titleIndex = titleIndex + 1;
+ titleButton:Show();
+ end
+ if ( titleIndex > 1 ) then
+ titleButton = _G["GossipTitleButton" .. GossipFrame.buttonIndex];
+ titleButton:Hide();
+ GossipFrame.buttonIndex = GossipFrame.buttonIndex + 1;
+ end
+end
+
+function GossipFrameOptionsUpdate(...)
+ local titleButton;
+ local titleIndex = 1;
+ local titleButtonIcon;
+ for i=1, select("#", ...), 2 do
+ if ( GossipFrame.buttonIndex > NUMGOSSIPBUTTONS ) then
+ message("This NPC has too many quests and/or gossip options.");
+ end
+ titleButton = _G["GossipTitleButton" .. GossipFrame.buttonIndex];
+ titleButton:SetText(select(i, ...));
+ GossipResize(titleButton);
+ titleButton:SetID(titleIndex);
+ titleButton.type="Gossip";
+ titleButtonIcon = _G[titleButton:GetName() .. "GossipIcon"];
+ titleButtonIcon:SetTexture("Interface\\GossipFrame\\" .. select(i+1, ...) .. "GossipIcon");
+ titleButtonIcon:SetVertexColor(1, 1, 1, 1);
+ GossipFrame.buttonIndex = GossipFrame.buttonIndex + 1;
+ titleIndex = titleIndex + 1;
+ titleButton:Show();
+ end
+end
+
+function GossipResize(titleButton)
+ titleButton:SetHeight( titleButton:GetTextHeight() + 2);
+end
diff --git a/reference/FrameXML/GossipFrame.xml b/reference/FrameXML/GossipFrame.xml
new file mode 100644
index 0000000..932e506
--- /dev/null
+++ b/reference/FrameXML/GossipFrame.xml
@@ -0,0 +1,596 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GossipTitleButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(GossipFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igQuestListOpen");
+ if ( StaticPopup_Visible("XP_LOSS") ) then
+ StaticPopup_Hide("XP_LOSS");
+ end
+
+
+
+ PlaySound("igQuestListClose");
+ CloseGossip();
+
+
+
+
+
diff --git a/reference/FrameXML/GraphicsQualityLevels.lua b/reference/FrameXML/GraphicsQualityLevels.lua
new file mode 100644
index 0000000..41f5d6d
--- /dev/null
+++ b/reference/FrameXML/GraphicsQualityLevels.lua
@@ -0,0 +1,98 @@
+GraphicsQualityLevels = {
+ [1] = { VideoOptionsEffectsPanelViewDistance = 177,
+ VideoOptionsEffectsPanelTerrainDetail = 0,
+ VideoOptionsEffectsPanelParticleDensity = 0.1,
+ VideoOptionsEffectsPanelEnvironmentDetail = 0.5,
+ VideoOptionsEffectsPanelClutterDensity = 16,
+ VideoOptionsEffectsPanelClutterRadius = 70,
+ VideoOptionsEffectsPanelShadowQuality = 0,
+ VideoOptionsEffectsPanelTextureResolution = 0,
+ VideoOptionsEffectsPanelTextureFiltering = 0,
+ VideoOptionsEffectsPanelWeatherIntensity = 0,
+ VideoOptionsEffectsPanelPlayerTexture = 8,
+ VideoOptionsEffectsPanelSpecularLighting = false,
+ VideoOptionsEffectsPanelFullScreenGlow = false,
+ VideoOptionsEffectsPanelDeathEffect = false,
+ VideoOptionsEffectsPanelProjectedTextures = false,
+ },
+ [2] = { VideoOptionsEffectsPanelViewDistance = 507,
+ VideoOptionsEffectsPanelTerrainDetail = 0,
+ VideoOptionsEffectsPanelParticleDensity = 0.4,
+ VideoOptionsEffectsPanelEnvironmentDetail = 0.75,
+ VideoOptionsEffectsPanelClutterDensity = 24,
+ VideoOptionsEffectsPanelClutterRadius = 80,
+ VideoOptionsEffectsPanelShadowQuality = 0,
+ VideoOptionsEffectsPanelTextureResolution = 0,
+ VideoOptionsEffectsPanelTextureFiltering = 1,
+ VideoOptionsEffectsPanelWeatherIntensity = 0,
+ VideoOptionsEffectsPanelPlayerTexture = 8,
+ VideoOptionsEffectsPanelSpecularLighting = true,
+ VideoOptionsEffectsPanelFullScreenGlow = true,
+ VideoOptionsEffectsPanelDeathEffect = true,
+ VideoOptionsEffectsPanelProjectedTextures = false,
+ },
+ [3] = { VideoOptionsEffectsPanelViewDistance = 727,
+ VideoOptionsEffectsPanelTerrainDetail = 0,
+ VideoOptionsEffectsPanelParticleDensity = 0.6,
+ VideoOptionsEffectsPanelEnvironmentDetail = 1.0,
+ VideoOptionsEffectsPanelClutterDensity = 48,
+ VideoOptionsEffectsPanelClutterRadius = 120,
+ VideoOptionsEffectsPanelShadowQuality = 1,
+ VideoOptionsEffectsPanelTextureResolution = 1,
+ VideoOptionsEffectsPanelTextureFiltering = 2,
+ VideoOptionsEffectsPanelWeatherIntensity = 2,
+ VideoOptionsEffectsPanelPlayerTexture = 9,
+ VideoOptionsEffectsPanelSpecularLighting = true,
+ VideoOptionsEffectsPanelFullScreenGlow = true,
+ VideoOptionsEffectsPanelDeathEffect = true,
+ VideoOptionsEffectsPanelProjectedTextures = true,
+ },
+ [4] = { VideoOptionsEffectsPanelViewDistance = 1057,
+ VideoOptionsEffectsPanelTerrainDetail = 1,
+ VideoOptionsEffectsPanelParticleDensity = 0.8,
+ VideoOptionsEffectsPanelEnvironmentDetail = 1.25,
+ VideoOptionsEffectsPanelClutterDensity = 56,
+ VideoOptionsEffectsPanelClutterRadius = 130,
+ VideoOptionsEffectsPanelShadowQuality = 4,
+ VideoOptionsEffectsPanelTextureResolution = 1,
+ VideoOptionsEffectsPanelTextureFiltering = 4,
+ VideoOptionsEffectsPanelWeatherIntensity = 3,
+ VideoOptionsEffectsPanelPlayerTexture = 9,
+ VideoOptionsEffectsPanelSpecularLighting = true,
+ VideoOptionsEffectsPanelFullScreenGlow = true,
+ VideoOptionsEffectsPanelDeathEffect = true,
+ VideoOptionsEffectsPanelProjectedTextures = true,
+ },
+ [5] = { VideoOptionsEffectsPanelViewDistance = 1277, --ULTRA mode
+ VideoOptionsEffectsPanelTerrainDetail = 1,
+ VideoOptionsEffectsPanelParticleDensity = 1.0,
+ VideoOptionsEffectsPanelEnvironmentDetail = 1.5,
+ VideoOptionsEffectsPanelClutterDensity = 64,
+ VideoOptionsEffectsPanelClutterRadius = 140,
+ VideoOptionsEffectsPanelShadowQuality = 5,
+ VideoOptionsEffectsPanelTextureResolution = 1,
+ VideoOptionsEffectsPanelTextureFiltering = 5,
+ VideoOptionsEffectsPanelWeatherIntensity = 3,
+ VideoOptionsEffectsPanelPlayerTexture = 9,
+ VideoOptionsEffectsPanelSpecularLighting = true,
+ VideoOptionsEffectsPanelFullScreenGlow = true,
+ VideoOptionsEffectsPanelDeathEffect = true,
+ VideoOptionsEffectsPanelProjectedTextures = true,
+ },
+ [6] = { VideoOptionsEffectsPanelViewDistance = 0,
+ VideoOptionsEffectsPanelTerrainDetail = 0,
+ VideoOptionsEffectsPanelParticleDensity = 0,
+ VideoOptionsEffectsPanelEnvironmentDetail = 0,
+ VideoOptionsEffectsPanelClutterDensity = 0,
+ VideoOptionsEffectsPanelClutterRadius = 0,
+ VideoOptionsEffectsPanelShadowQuality = 0,
+ VideoOptionsEffectsPanelTextureResolution = 0,
+ VideoOptionsEffectsPanelTextureFiltering = 0,
+ VideoOptionsEffectsPanelWeatherIntensity = 0,
+ VideoOptionsEffectsPanelPlayerTexture = 8,
+ VideoOptionsEffectsPanelSpecularLighting = false,
+ VideoOptionsEffectsPanelFullScreenGlow = false,
+ VideoOptionsEffectsPanelDeathEffect = false,
+ VideoOptionsEffectsPanelProjectedTextures = true,
+ },
+}
\ No newline at end of file
diff --git a/reference/FrameXML/GuildRegistrarFrame.lua b/reference/FrameXML/GuildRegistrarFrame.lua
new file mode 100644
index 0000000..134ac61
--- /dev/null
+++ b/reference/FrameXML/GuildRegistrarFrame.lua
@@ -0,0 +1,12 @@
+function GuildRegistrar_OnShow()
+ GuildRegistrarGreetingFrame:Show();
+ GuildRegistrarPurchaseFrame:Hide();
+ SetPortraitTexture(GuildRegistrarFramePortrait, "NPC");
+ GuildRegistrarFrameNpcNameText:SetText(UnitName("NPC"));
+end
+
+function GuildRegistrar_ShowPurchaseFrame()
+ GuildRegistrarPurchaseFrame:Show();
+ GuildRegistrarGreetingFrame:Hide();
+ MoneyFrame_Update("GuildRegistrarMoneyFrame", GetGuildCharterCost());
+end
\ No newline at end of file
diff --git a/reference/FrameXML/GuildRegistrarFrame.xml b/reference/FrameXML/GuildRegistrarFrame.xml
new file mode 100644
index 0000000..2df52e4
--- /dev/null
+++ b/reference/FrameXML/GuildRegistrarFrame.xml
@@ -0,0 +1,350 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(GuildRegistrarFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(GuildRegistrarFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BuyGuildCharter(GuildRegistrarFrameEditBox:GetText());
+ HideUIPanel(GuildRegistrarFrame);
+ ChatEdit_FocusActiveWindow();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BuyGuildCharter(self:GetText());
+ HideUIPanel(GuildRegistrarFrame);
+ ChatEdit_FocusActiveWindow();
+
+
+ ChatEdit_FocusActiveWindow();
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("GUILD_REGISTRAR_SHOW");
+ self:RegisterEvent("GUILD_REGISTRAR_CLOSED");
+
+
+ if ( event == "GUILD_REGISTRAR_SHOW" ) then
+ ShowUIPanel(GuildRegistrarFrame);
+ if ( not GuildRegistrarFrame:IsShown() ) then
+ CloseGuildRegistrar();
+ end
+ elseif ( event == "GUILD_REGISTRAR_CLOSED" ) then
+ HideUIPanel(GuildRegistrarFrame);
+ end
+
+
+ GuildRegistrar_OnShow();
+ PlaySound("igQuestListOpen");
+
+
+ PlaySound("igQuestListClose");
+ CloseGuildRegistrar();
+
+
+
+
diff --git a/reference/FrameXML/HealthBar.lua b/reference/FrameXML/HealthBar.lua
new file mode 100644
index 0000000..b127dd7
--- /dev/null
+++ b/reference/FrameXML/HealthBar.lua
@@ -0,0 +1,32 @@
+
+function HealthBar_OnValueChanged(self, value, smooth)
+ if ( not value ) then
+ return;
+ end
+ local r, g, b;
+ local min, max = self:GetMinMaxValues();
+ if ( (value < min) or (value > max) ) then
+ return;
+ end
+ if ( (max - min) > 0 ) then
+ value = (value - min) / (max - min);
+ else
+ value = 0;
+ end
+ if(smooth) then
+ if(value > 0.5) then
+ r = (1.0 - value) * 2;
+ g = 1.0;
+ else
+ r = 1.0;
+ g = value * 2;
+ end
+ else
+ r = 0.0;
+ g = 1.0;
+ end
+ b = 0.0;
+ if ( not self.lockColor ) then
+ self:SetStatusBarColor(r, g, b);
+ end
+end
diff --git a/reference/FrameXML/HelpFrame.lua b/reference/FrameXML/HelpFrame.lua
new file mode 100644
index 0000000..c104248
--- /dev/null
+++ b/reference/FrameXML/HelpFrame.lua
@@ -0,0 +1,460 @@
+-- global data
+HELPFRAME_BULLET_SPACING = -3;
+HELPFRAME_SECTION_SPACING = -20;
+GMTICKET_CHECK_INTERVAL = 600; -- 10 Minutes
+
+HELPFRAME_START_PAGE = "KBase";
+
+
+-- local data
+
+-- helpFrames contains the names of all the frames that can go into the frameStack
+local helpFrames = {
+ ["GMTalk"] = "HelpFrameGMTalk",
+ ["Stuck"] = "HelpFrameStuck",
+ ["ReportIssue"] = "HelpFrameReportIssue",
+ ["OpenTicket"] = "HelpFrameOpenTicket",
+ ["GMResponse"] = "HelpFrameViewResponse",
+ ["NeedMoreHelp"] = "HelpFrameOpenTicket",
+ ["Welcome"] = "HelpFrameWelcome",
+ ["KBase"] = "KnowledgeBaseFrame",
+ ["Lag"] = "HelpFrameLag",
+};
+-- openFrame is the current help frame that a player has opened.
+local openFrame;
+-- frameStack is a stack of all the help frames that a player has opened.
+-- For example, if I open the knowledge base, then open the stuck frame, then open the open ticket frame,
+-- frameStack would look like this:
+--
+-- frameStack: bottom [ KnowledgeBaseFrame, HelpFrameStuck ] top
+-- openFrame: HelpFrameOpenTicket
+--
+-- For usage, see:
+-- HelpFrame_ShowFrame(key)
+-- HelpFrame_PopFrame()
+-- HelpFrame_PopAllFrames()
+local frameStack = { };
+
+local refreshTime;
+local ticketQueueActive = true;
+
+local haveTicket = false; -- true if the server tells us we have an open ticket
+local haveResponse = false; -- true if we got a GM response to a previous ticket
+local needResponse = true; -- true if we want a GM to contact us when we open a new ticket
+
+
+--
+-- HelpFrame
+--
+
+function HelpFrame_OnLoad(self)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("UPDATE_GM_STATUS");
+ self:RegisterEvent("UPDATE_TICKET");
+ self:RegisterEvent("GMSURVEY_DISPLAY");
+ self:RegisterEvent("GMRESPONSE_RECEIVED");
+end
+
+function HelpFrame_OnShow(self)
+ UpdateMicroButtons();
+ PlaySound("igCharacterInfoOpen");
+ GetGMStatus();
+end
+
+function HelpFrame_OnHide(self)
+ PlaySound("igCharacterInfoClose");
+ UpdateMicroButtons();
+ if ( openFrame ) then
+ openFrame:Hide();
+ openFrame = nil;
+ end
+ HelpFrame_PopAllFrames();
+end
+
+function HelpFrame_OnEvent(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ GetGMTicket();
+ elseif ( event == "UPDATE_GM_STATUS" ) then
+ local status = ...;
+ if ( status == GMTICKET_QUEUE_STATUS_ENABLED ) then
+ ticketQueueActive = true;
+ else
+ ticketQueueActive = false;
+ HelpFrameStuckOpenTicket:Disable();
+ if ( status == GMTICKET_QUEUE_STATUS_DISABLED ) then
+ StaticPopup_Show("HELP_TICKET_QUEUE_DISABLED");
+ end
+ end
+ elseif ( event == "GMSURVEY_DISPLAY" ) then
+ -- If there's a survey to display then fill out info and return
+ TicketStatusTitleText:SetText(CHOSEN_FOR_GMSURVEY);
+ TicketStatusTime:Hide();
+ TicketStatusFrame:SetHeight(TicketStatusTitleText:GetHeight() + 20);
+ TicketStatusFrame:Show();
+ TicketStatusFrame.hasGMSurvey = true;
+ haveResponse = false;
+ haveTicket = false;
+ UIFrameFlash(TicketStatusFrameIcon, 0.75, 0.75, 20);
+ elseif ( event == "UPDATE_TICKET" ) then
+ local category, ticketDescription, ticketAge, oldestTicketTime, updateTime, assignedToGM, openedByGM = ...;
+ -- If there are args then the player has a ticket
+ if ( category ) then
+ -- Has an open ticket
+ TicketStatusTitleText:SetText(TICKET_STATUS);
+ TicketStatusFrame.hasGMSurvey = false;
+ HelpFrameOpenTicketEditBox:SetText(ticketDescription);
+ -- Setup estimated wait time
+ --[[
+ ticketAge - days
+ oldestTicketTime - days
+ updateTime - days
+ How recent is the data for oldest ticket time, measured in days. If this number 1 hour, we have bad data.
+ assignedToGM - see GMTICKET_ASSIGNEDTOGM_STATUS_* constants
+ openedByGM - see GMTICKET_OPENEDBYGM_STATUS_* constants
+ ]]
+ local statusText;
+ TicketStatusFrame.ticketTimer = nil;
+ if ( openedByGM == GMTICKET_OPENEDBYGM_STATUS_OPENED ) then
+ -- if ticket has been opened by a gm
+ if ( assignedToGM == GMTICKET_ASSIGNEDTOGM_STATUS_ESCALATED ) then
+ statusText = GM_TICKET_ESCALATED;
+ else
+ statusText = GM_TICKET_SERVICE_SOON;
+ end
+ else
+ -- convert from days to seconds
+ local estimatedWaitTime = (oldestTicketTime - ticketAge) * 24 * 60 * 60;
+ if ( estimatedWaitTime < 0 ) then
+ estimatedWaitTime = 0;
+ end
+
+ if ( oldestTicketTime < 0 or updateTime < 0 or updateTime > 0.042 ) then
+ statusText = GM_TICKET_UNAVAILABLE;
+ elseif ( estimatedWaitTime > 7200 ) then
+ -- if wait is over 2 hrs
+ statusText = GM_TICKET_HIGH_VOLUME;
+ elseif ( estimatedWaitTime > 300 ) then
+ -- if wait is over 5 mins
+ statusText = format(GM_TICKET_WAIT_TIME, SecondsToTime(estimatedWaitTime, 1));
+ TicketStatusFrame.ticketTimer = estimatedWaitTime;
+ else
+ statusText = GM_TICKET_SERVICE_SOON;
+ end
+ end
+ if ( statusText ) then
+ TicketStatusTime:Show();
+ TicketStatusTime:SetText(statusText);
+ end
+
+ haveResponse = false;
+ haveTicket = true;
+ HelpFrameOpenTicketSubmit:SetText(EDIT_TICKET);
+ HelpFrameOpenTicketLabel:SetText(HELPFRAME_OPENTICKET_EDITTEXT);
+
+ -- hide the buttons that open a ticket and show the buttons that edit a ticket
+ KnowledgeBaseFrameGMTalk:Hide();
+ KnowledgeBaseFrameReportIssue:Hide();
+ HelpFrameStuckOpenTicket:Hide();
+ KnowledgeBaseFrameEditTicket:Show();
+ KnowledgeBaseFrameAbandonTicket:Show();
+ else
+ -- the player does not have a ticket
+ HelpFrameOpenTicketEditBox:SetText("");
+ haveResponse = false;
+ haveTicket = false;
+ HelpFrameOpenTicketSubmit:SetText(SUBMIT);
+ HelpFrameOpenTicketLabel:SetText(HELPFRAME_OPENTICKET_TEXT);
+
+ -- hide the buttons that edit a ticket and show the buttons that open a ticket
+ KnowledgeBaseFrameGMTalk:Show();
+ KnowledgeBaseFrameReportIssue:Show();
+ HelpFrameStuckOpenTicket:Show();
+ KnowledgeBaseFrameEditTicket:Hide();
+ KnowledgeBaseFrameAbandonTicket:Hide();
+ end
+ elseif ( event == "GMRESPONSE_RECEIVED" ) then
+ local ticketDescription, response = ...;
+
+ haveResponse = true;
+ -- i know this is a little confusing since you can have a ticket while you have a response, but having a response
+ -- basically implies that you can't make a *new* ticket until you deal with the response...maybe it should be
+ -- called haveNewTicket but that would probably be even more confusing
+ haveTicket = false;
+
+ TicketStatusTitleText:SetText(GM_RESPONSE_ALERT);
+ TicketStatusTime:SetText("");
+ TicketStatusTime:Hide();
+ TicketStatusFrame.hasGMSurvey = false;
+
+ local descriptionSuffix = "\n";
+ HelpFrameViewResponseIssueBody:SetText(ticketDescription..descriptionSuffix);
+ local responseSuffix = "\n";
+ HelpFrameViewResponseMessageBody:SetText(response..responseSuffix);
+
+ -- clear out the open ticket edit box...the original design called for filling in the edit box with the ticketDescription in case
+ -- the player wanted to create a follow-up ticket, but creating a new ticket with your old ticket's text felt strange so I opted
+ -- to just clear out the text instead
+ HelpFrameOpenTicketEditBox:SetText("");
+ HelpFrameOpenTicketSubmit:SetText(SUBMIT);
+ HelpFrameOpenTicketLabel:SetText(HELPFRAME_OPENTICKET_FOLLOWUPTEXT);
+
+ -- hide the buttons that edit a ticket and show the buttons that open a ticket
+ -- the player shouldn't be able to edit or open a ticket while a response is up, but they will at least be able to view
+ -- the information on the various help pages this way
+ KnowledgeBaseFrameGMTalk:Show();
+ KnowledgeBaseFrameReportIssue:Show();
+ HelpFrameStuckOpenTicket:Show();
+ KnowledgeBaseFrameEditTicket:Hide();
+ KnowledgeBaseFrameAbandonTicket:Hide();
+ end
+end
+
+function HelpFrame_ShowFrame(key)
+ local frameName = helpFrames[key];
+ local frame = _G[frameName];
+ if ( not frame ) then
+ return;
+ end
+
+ -- Close previously opened frame
+ if ( openFrame ) then
+ if ( frame == openFrame ) then
+ -- the requested frame is the same as the open frame...do nothing
+ return;
+ end
+ openFrame:Hide();
+ tinsert(frameStack, openFrame);
+ end
+
+ if ( key == "OpenTicket" ) then
+ if ( not HelpFrame_IsGMTicketQueueActive() ) then
+ -- Petition queue is down and we're trying to go to the OpenTicket frame, show a dialog instead
+ HideUIPanel(HelpFrame);
+ StaticPopup_Show("HELP_TICKET_QUEUE_DISABLED");
+ return;
+ end
+ if ( haveResponse ) then
+ -- if we have a response that hasn't been dealt with and the player is trying to open a new ticket,
+ -- give them a warning dialog instead
+ HideUIPanel(HelpFrame);
+ StaticPopup_Show("GM_RESPONSE_MUST_RESOLVE_RESPONSE");
+ return;
+ end
+ end
+
+ ShowUIPanel(HelpFrame);
+ frame:Show();
+ openFrame = frame;
+end
+
+function HelpFrame_PopFrame()
+ if ( not openFrame) then
+ return;
+ end
+ openFrame:Hide();
+ local top = tremove(frameStack);
+ if ( not top ) then
+ HideUIPanel(HelpFrame);
+ return;
+ end
+ top:Show();
+ openFrame = top;
+end
+
+function HelpFrame_PopAllFrames()
+ while #frameStack > 0 do
+ tremove(frameStack);
+ end
+end
+
+function HelpFrame_IsGMTicketQueueActive()
+ return ticketQueueActive;
+end
+
+function HelpFrame_HaveGMTicket()
+ return haveTicket;
+end
+
+function HelpFrame_HaveGMResponse()
+ return haveResponse;
+end
+
+
+--
+-- HelpFrameGMTalk
+--
+
+function HelpFrameGMTalk_OnShow(self)
+ needResponse = true;
+end
+
+
+--
+-- HelpFrameReportIssue
+--
+
+function HelpFrameReportIssue_OnShow(self)
+ needResponse = false;
+end
+
+
+--
+-- HelpFrameStuck
+--
+
+function HelpFrameStuck_OnShow(self)
+ needResponse = true;
+end
+
+
+--
+-- HelpFrameOpenTicket
+--
+
+function HelpFrameOpenTicketCancel_OnClick()
+ GetGMTicket();
+ HelpFrame_PopFrame();
+end
+
+function HelpFrameOpenTicketSubmit_OnClick()
+ if ( haveResponse ) then
+ GMResponseNeedMoreHelp(HelpFrameOpenTicketEditBox:GetText());
+ else
+ if ( haveTicket ) then
+ UpdateGMTicket(HelpFrameOpenTicketEditBox:GetText());
+ else
+ NewGMTicket(HelpFrameOpenTicketEditBox:GetText(), needResponse);
+ end
+ end
+ HideUIPanel(HelpFrame);
+end
+
+
+--
+-- HelpFrameViewResponseButton
+--
+
+function HelpFrameViewResponseButton_OnLoad(self)
+ local width = self:GetWidth() - 20;
+ local deltaWidth = self:GetTextWidth() - width;
+ if ( deltaWidth > 0 ) then
+ self:SetWidth(width + deltaWidth + 40);
+ end
+end
+
+
+--
+-- HelpFrameViewResponseMoreHelp
+--
+
+function HelpFrameViewResponseMoreHelp_OnClick(self)
+ StaticPopup_Show("GM_RESPONSE_NEED_MORE_HELP");
+end
+
+
+--
+-- HelpFrameViewResponseIssueResolved
+--
+
+function HelpFrameViewResponseIssueResolved_OnClick(self)
+ StaticPopup_Show("GM_RESPONSE_RESOLVE_CONFIRM");
+end
+
+
+--
+-- TicketStatusFrame
+--
+
+function TicketStatusFrame_OnLoad(self)
+ self:RegisterEvent("UPDATE_TICKET");
+ self:RegisterEvent("GMRESPONSE_RECEIVED");
+end
+
+function TicketStatusFrame_OnEvent(self, event, ...)
+ if ( event == "UPDATE_TICKET" ) then
+ local category = ...;
+ if ( (category or self.hasGMSurvey) and (not GMChatStatusFrame or not GMChatStatusFrame:IsShown()) ) then
+ self:Show();
+ refreshTime = GMTICKET_CHECK_INTERVAL;
+ else
+ self:Hide();
+ end
+ elseif ( event == "GMRESPONSE_RECEIVED" ) then
+ if ( not GMChatStatusFrame or not GMChatStatusFrame:IsShown() ) then
+ self:Show();
+ else
+ self:Hide();
+ end
+ end
+end
+
+function TicketStatusFrame_OnUpdate(self, elapsed)
+ if ( haveTicket ) then
+ -- Every so often, query the server for our ticket status
+ if ( refreshTime ) then
+ refreshTime = refreshTime - elapsed;
+ if ( refreshTime <= 0 ) then
+ refreshTime = GMTICKET_CHECK_INTERVAL;
+ GetGMTicket();
+ end
+ end
+ if ( self.ticketTimer ) then
+ self.ticketTimer = self.ticketTimer - elapsed;
+ TicketStatusTime:SetFormattedText(GM_TICKET_WAIT_TIME, SecondsToTime(self.ticketTimer, 1));
+ end
+ end
+end
+
+function TicketStatusFrame_OnShow(self)
+ ConsolidatedBuffs:SetPoint("TOPRIGHT", self:GetParent(), "TOPRIGHT", -205, (-self:GetHeight()));
+end
+
+function TicketStatusFrame_OnHide(self)
+ if( not GMChatStatusFrame or not GMChatStatusFrame:IsShown() ) then
+ ConsolidatedBuffs:SetPoint("TOPRIGHT", "UIParent", "TOPRIGHT", -180, -13);
+ end
+end
+
+
+--
+-- TicketStatusFrameButton
+--
+
+function TicketStatusFrameButton_OnLoad(self)
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+ -- make sure this frame doesn't cover up the content in the parent
+ self:SetFrameLevel(self:GetParent():GetFrameLevel() - 1);
+end
+
+function TicketStatusFrameButton_OnClick(self)
+ if ( TicketStatusFrame.hasGMSurvey ) then
+ GMSurveyFrame_LoadUI();
+ ShowUIPanel(GMSurveyFrame);
+ TicketStatusFrame:Hide();
+ elseif ( StaticPopup_Visible("HELP_TICKET_ABANDON_CONFIRM") ) then
+ StaticPopup_Hide("HELP_TICKET_ABANDON_CONFIRM");
+ elseif ( StaticPopup_Visible("HELP_TICKET") ) then
+ StaticPopup_Hide("HELP_TICKET");
+ elseif ( StaticPopup_Visible("GM_RESPONSE_NEED_MORE_HELP") ) then
+ StaticPopup_Hide("GM_RESPONSE_NEED_MORE_HELP");
+ elseif ( StaticPopup_Visible("GM_RESPONSE_RESOLVE_CONFIRM") ) then
+ StaticPopup_Hide("GM_RESPONSE_RESOLVE_CONFIRM");
+ elseif ( StaticPopup_Visible("GM_RESPONSE_CANT_OPEN_TICKET") ) then
+ StaticPopup_Hide("GM_RESPONSE_CANT_OPEN_TICKET");
+ elseif ( not HelpFrame:IsShown() and not KnowledgeBaseFrame:IsShown() ) then
+ if ( haveResponse ) then
+ HelpFrame_ShowFrame("GMResponse");
+ elseif ( haveTicket ) then
+ StaticPopup_Show("HELP_TICKET");
+ end
+ end
+end
+
+function HelpReportLag(kind)
+ HideUIPanel(HelpFrame);
+ GMReportLag(STATIC_CONSTANTS[kind]);
+ StaticPopup_Show("LAG_SUCCESS");
+end
+
diff --git a/reference/FrameXML/HelpFrame.xml b/reference/FrameXML/HelpFrame.xml
new file mode 100644
index 0000000..b397677
--- /dev/null
+++ b/reference/FrameXML/HelpFrame.xml
@@ -0,0 +1,1219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth() + 40);
+ self:SetHeight(self:GetTextHeight() + 20);
+
+
+ HelpFrame_PopFrame();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth()+40);
+
+
+ HelpFrame_ShowFrame("OpenTicket");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HelpFrameReportIssueBullet1Text:SetText(HELPFRAME_REPORTISSUE_BULLET1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HelpFrameReportIssueBullet2Text:SetText(HELPFRAME_REPORTISSUE_BULLET2);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth()+40);
+
+
+ HelpFrame_ShowFrame("OpenTicket");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText = BUTTON_LAG_LOOT_TOOLTIP;
+ self.newbieText = BUTTON_LAG_LOOT_NEWBIE;
+
+
+ HelpReportLag("Loot");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText = BUTTON_LAG_AUCTIONHOUSE_TOOLTIP;
+ self.newbieText = BUTTON_LAG_AUCTIONHOUSE_NEWBIE;
+
+
+ HelpReportLag("AuctionHouse");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText = BUTTON_LAG_MAIL_TOOLTIP;
+ self.newbieText = BUTTON_LAG_MAIL_NEWBIE;
+
+
+ HelpReportLag("Mail");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText = BUTTON_LAG_CHAT_TOOLTIP;
+ self.newbieText = BUTTON_LAG_CHAT_NEWBIE;
+
+
+ HelpReportLag("Chat");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText = BUTTON_LAG_MOVEMENT_TOOLTIP;
+ self.newbieText = BUTTON_LAG_MOVEMENT_NEWBIE;
+
+
+ HelpReportLag("Movement");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText = BUTTON_LAG_SPELL_TOOLTIP;
+ self.newbieText = BUTTON_LAG_SPELL_NEWBIE;
+
+
+ HelpReportLag("Spell");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth()+40);
+
+
+ Stuck();
+ HideUIPanel(HelpFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth()+40);
+
+
+ HelpFrame_ShowFrame("OpenTicket");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent());
+
+
+
+ ScrollingEdit_OnUpdate(self, elapsed, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth()+40);
+
+
+ HelpFrame_ShowFrame("GMTalk");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth()+40);
+
+
+ HelpFrame_ShowFrame("ReportIssue");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth()+40);
+
+
+ HelpFrame_ShowFrame("Stuck");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/HistoryKeeper.lua b/reference/FrameXML/HistoryKeeper.lua
new file mode 100644
index 0000000..b00cb85
--- /dev/null
+++ b/reference/FrameXML/HistoryKeeper.lua
@@ -0,0 +1,24 @@
+local accessIDs = {};
+local nextAccessID = 1;
+
+local accessIDToType = {};
+local accessIDToTarget = {};
+
+function ChatHistory_GetAccessID(chatType, chatTarget)
+ if ( not accessIDs[ChatHistory_GetToken(chatType, chatTarget)] ) then
+ accessIDs[ChatHistory_GetToken(chatType, chatTarget)] = nextAccessID;
+ accessIDToType[nextAccessID] = chatType;
+ accessIDToTarget[nextAccessID] = chatTarget;
+ nextAccessID = nextAccessID + 1;
+ end
+ return accessIDs[ChatHistory_GetToken(chatType, chatTarget)];
+end
+
+function ChatHistory_GetChatType(accessID)
+ return accessIDToType[accessID], accessIDToTarget[accessID];
+end
+
+--Private functions
+function ChatHistory_GetToken(chatType, chatTarget)
+ return strlower(chatType)..";;"..(chatTarget and strlower(chatTarget) or "");
+end
\ No newline at end of file
diff --git a/reference/FrameXML/HonorFrame.lua b/reference/FrameXML/HonorFrame.lua
new file mode 100644
index 0000000..592c49d
--- /dev/null
+++ b/reference/FrameXML/HonorFrame.lua
@@ -0,0 +1,77 @@
+function HonorFrame_OnLoad(self)
+ self:RegisterEvent("PLAYER_PVP_KILLS_CHANGED");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("PLAYER_PVP_RANK_CHANGED");
+end
+
+function HonorFrame_OnEvent(self, event, ...)
+ if ( event == "PLAYER_PVP_KILLS_CHANGED" or event == "PLAYER_PVP_RANK_CHANGED") then
+ HonorFrame_Update();
+ elseif ( event == "PLAYER_ENTERING_WORLD" ) then
+ HonorFrame_Update(1);
+ end
+end
+
+function HonorFrame_Update(updateAll)
+ local hk, cp, dk, contribution, rank, highestRank, rankName, rankNumber;
+
+ -- This only gets set on player entering the world
+ if ( updateAll ) then
+ -- Yesterday's values
+ hk, contribution = GetPVPYesterdayStats();
+ HonorFrameYesterdayHKValue:SetText(hk);
+ HonorFrameYesterdayContributionValue:SetText(contribution);
+ -- This Week's values
+ --hk, contribution = GetPVPThisWeekStats();
+ --HonorFrameThisWeekHKValue:SetText(hk);
+ --HonorFrameThisWeekContributionValue:SetText(contribution);
+ -- Last Week's values
+ --hk, dk, contribution, rank = GetPVPLastWeekStats();
+ --HonorFrameLastWeekHKValue:SetText(hk);
+ --HonorFrameLastWeekContributionValue:SetText(contribution);
+ --HonorFrameLastWeekStandingValue:SetText(rank);
+ end
+
+ -- This session's values
+ hk, cp = GetPVPSessionStats();
+ HonorFrameCurrentHKValue:SetText(hk);
+ --HonorFrameCurrentDKValue:SetText(dk);
+
+ -- Lifetime stats
+ hk, highestRank = GetPVPLifetimeStats();
+ HonorFrameLifeTimeHKValue:SetText(hk);
+ --HonorFrameLifeTimeDKValue:SetText(dk);
+ rankName, rankNumber = GetPVPRankInfo(highestRank);
+ if ( not rankName ) then
+ rankName = NONE;
+ end
+ HonorFrameLifeTimeRankValue:SetText(rankName);
+
+ -- Set rank name and number
+ rankName, rankNumber = GetPVPRankInfo(UnitPVPRank("player"));
+ if ( not rankName ) then
+ rankName = NONE;
+ end
+ HonorFrameCurrentPVPTitle:SetText(rankName);
+ HonorFrameCurrentPVPRank:SetText("("..RANK.." "..rankNumber..")");
+
+ -- Set icon
+ if ( rankNumber > 0 ) then
+ HonorFramePvPIcon:SetTexture(format("%s%02d","Interface\\PvPRankBadges\\PvPRank",rankNumber));
+ HonorFramePvPIcon:Show();
+ else
+ HonorFramePvPIcon:Hide();
+ end
+
+ -- Set rank progress and bar color
+ local factionGroup, factionName = UnitFactionGroup("player");
+ if ( factionGroup == "Alliance" ) then
+ HonorFrameProgressBar:SetStatusBarColor(0.05, 0.15, 0.36);
+ else
+ HonorFrameProgressBar:SetStatusBarColor(0.63, 0.09, 0.09);
+ end
+ HonorFrameProgressBar:SetValue(GetPVPRankProgress());
+
+ -- Recenter rank text
+ HonorFrameCurrentPVPTitle:SetPoint("TOP", "HonorFrame", "TOP", - HonorFrameCurrentPVPRank:GetWidth()/2, -83);
+end
\ No newline at end of file
diff --git a/reference/FrameXML/HonorFrame.xml b/reference/FrameXML/HonorFrame.xml
new file mode 100644
index 0000000..d889fb7
--- /dev/null
+++ b/reference/FrameXML/HonorFrame.xml
@@ -0,0 +1,369 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(RANK, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_RANK, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(RANK_POSITION, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_RANK_POSITION, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/HonorFrameTemplates.xml b/reference/FrameXML/HonorFrameTemplates.xml
new file mode 100644
index 0000000..9371a03
--- /dev/null
+++ b/reference/FrameXML/HonorFrameTemplates.xml
@@ -0,0 +1,149 @@
+
+
+
+
+
+
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self)
+ GameTooltip:SetText(self.title, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(self.tooltip, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.title = HONORABLE_KILLS;
+ self.tooltip = NEWBIE_TOOLTIP_HONORABLE_KILLS;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.title = DISHONORABLE_KILLS;
+ self.tooltip = NEWBIE_TOOLTIP_DISHONORABLE_KILLS;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.title = HONOR_CONTRIBUTION_POINTS;
+ self.tooltip = NEWBIE_TOOLTIP_HONOR_CONTRIBUTION_POINTS;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.title = HONOR_STANDING;
+ self.tooltip = NEWBIE_TOOLTIP_HONOR_STANDING;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.title = RANK;
+ self.tooltip = NEWBIE_TOOLTIP_RANK;
+
+
+
+
diff --git a/reference/FrameXML/HybridScrollFrame.lua b/reference/FrameXML/HybridScrollFrame.lua
new file mode 100644
index 0000000..47944eb
--- /dev/null
+++ b/reference/FrameXML/HybridScrollFrame.lua
@@ -0,0 +1,216 @@
+--[[-----------------------------------------------------------------------------------------------
+
+-----------------------------------------------------------------------------------------------]]--
+
+local round = function (num) return math.floor(num + .5); end
+
+function HybridScrollFrame_OnLoad (self)
+ self:EnableMouse(true);
+end
+
+function HybridScrollFrame_OnValueChanged (self, value)
+ HybridScrollFrame_SetOffset(self, value);
+ HybridScrollFrame_UpdateButtonStates(self, value);
+end
+
+function HybridScrollFrame_UpdateButtonStates(self, currValue)
+ if ( not currValue ) then
+ currValue = self.scrollBar:GetValue();
+ end
+
+ self.scrollUp:Enable();
+ self.scrollDown:Enable();
+
+ local minVal, maxVal = self.scrollBar:GetMinMaxValues();
+ if ( currValue >= maxVal ) then
+ self.scrollBar.thumbTexture:Show();
+ if ( self.scrollDown ) then
+ self.scrollDown:Disable()
+ end
+ end
+ if ( currValue <= minVal ) then
+ self.scrollBar.thumbTexture:Show();
+ if ( self.scrollUp ) then
+ self.scrollUp:Disable();
+ end
+ end
+end
+
+function HybridScrollFrame_OnMouseWheel (self, delta, stepSize)
+ if ( not self.scrollBar:IsVisible() ) then
+ return;
+ end
+
+ local minVal, maxVal = 0, self.range;
+ stepSize = stepSize or self.stepSize or self.buttonHeight;
+ if ( delta == 1 ) then
+ self.scrollBar:SetValue(max(minVal, self.scrollBar:GetValue() - stepSize));
+ else
+ self.scrollBar:SetValue(min(maxVal, self.scrollBar:GetValue() + stepSize));
+ end
+end
+
+function HybridScrollFrameScrollButton_OnUpdate (self, elapsed)
+ self.timeSinceLast = self.timeSinceLast + elapsed;
+ if ( self.timeSinceLast >= ( self.updateInterval or 0.08 ) ) then
+ if ( not IsMouseButtonDown("LeftButton") ) then
+ self:SetScript("OnUpdate", nil);
+ elseif ( self:IsMouseOver() ) then
+ local parent = self.parent or self:GetParent():GetParent();
+ HybridScrollFrame_OnMouseWheel (parent, self.direction, (self.stepSize or parent.buttonHeight/3));
+ self.timeSinceLast = 0;
+ end
+ end
+end
+
+function HybridScrollFrameScrollButton_OnClick (self, button, down)
+ local parent = self.parent or self:GetParent():GetParent();
+
+ if ( down ) then
+ self.timeSinceLast = (self.timeToStart or -0.2);
+ self:SetScript("OnUpdate", HybridScrollFrameScrollButton_OnUpdate);
+ HybridScrollFrame_OnMouseWheel (parent, self.direction);
+ PlaySound("UChatScrollButton");
+ else
+ self:SetScript("OnUpdate", nil);
+ end
+end
+
+function HybridScrollFrame_Update (self, totalHeight, displayedHeight)
+ local range = totalHeight - self:GetHeight();
+ if ( range > 0 and self.scrollBar ) then
+ local minVal, maxVal = self.scrollBar:GetMinMaxValues();
+ if ( math.floor(self.scrollBar:GetValue()) >= math.floor(maxVal) ) then
+ self.scrollBar:SetMinMaxValues(0, range)
+ if ( math.floor(self.scrollBar:GetValue()) ~= math.floor(range) ) then
+ self.scrollBar:SetValue(range);
+ else
+ HybridScrollFrame_SetOffset(self, range); -- If we've scrolled to the bottom, we need to recalculate the offset.
+ end
+ else
+ self.scrollBar:SetMinMaxValues(0, range)
+ end
+ self.scrollBar:Enable();
+ HybridScrollFrame_UpdateButtonStates(self);
+ self.scrollBar:Show();
+ elseif ( self.scrollBar ) then
+ self.scrollBar:SetValue(0);
+ if ( self.scrollBar.doNotHide ) then
+ self.scrollBar:Disable();
+ self.scrollUp:Disable();
+ self.scrollDown:Disable();
+ self.scrollBar.thumbTexture:Hide();
+ else
+ self.scrollBar:Hide();
+ end
+ end
+
+ self.range = range;
+ self.scrollChild:SetHeight(displayedHeight);
+ self:UpdateScrollChildRect();
+end
+
+function HybridScrollFrame_GetOffset (self)
+ return math.floor(self.offset or 0), (self.offset or 0);
+end
+
+function HybridScrollFrameScrollChild_OnLoad (self)
+ self:GetParent().scrollChild = self;
+end
+
+function HybridScrollFrame_ExpandButton (self, offset, height)
+ self.largeButtonTop = round(offset);
+ self.largeButtonHeight = round(height)
+ HybridScrollFrame_SetOffset(self, self.scrollBar:GetValue());
+end
+
+function HybridScrollFrame_CollapseButton (self)
+ self.largeButtonTop = nil;
+ self.largeButtonHeight = nil;
+end
+
+function HybridScrollFrame_SetOffset (self, offset)
+ local buttons = self.buttons
+ local buttonHeight = self.buttonHeight;
+ local element, overflow;
+
+ local scrollHeight = 0;
+
+ local largeButtonTop = self.largeButtonTop
+ if ( largeButtonTop and offset >= largeButtonTop ) then
+ local largeButtonHeight = self.largeButtonHeight;
+ -- Initial offset...
+ element = largeButtonTop / buttonHeight;
+
+ if ( offset >= (largeButtonTop + largeButtonHeight) ) then
+ element = element + 1;
+
+ local leftovers = (offset - (largeButtonTop + largeButtonHeight) );
+
+ element = element + ( leftovers / buttonHeight );
+ overflow = element - math.floor(element);
+ scrollHeight = overflow * buttonHeight;
+ else
+ scrollHeight = math.abs(offset - largeButtonTop);
+ end
+ else
+ element = offset / buttonHeight;
+ overflow = element - math.floor(element);
+ scrollHeight = overflow * buttonHeight;
+ end
+
+ if ( math.floor(self.offset or 0) ~= math.floor(element) and self.update ) then
+ self.offset = element;
+ self.update();
+ else
+ self.offset = element;
+ end
+
+ self:SetVerticalScroll(scrollHeight);
+end
+
+function HybridScrollFrame_CreateButtons (self, buttonTemplate, initialOffsetX, initialOffsetY, initialPoint, initialRelative, offsetX, offsetY, point, relativePoint)
+ local scrollChild = self.scrollChild;
+ local button, buttonHeight, buttons, numButtons;
+
+ local buttonName = self:GetName() .. "Button";
+
+ initialPoint = initialPoint or "TOPLEFT";
+ initialRelative = initialRelative or "TOPLEFT";
+ point = point or "TOPLEFT";
+ relativePoint = relativePoint or "BOTTOMLEFT";
+ offsetX = offsetX or 0;
+ offsetY = offsetY or 0;
+
+ if ( self.buttons ) then
+ buttons = self.buttons;
+ buttonHeight = buttons[1]:GetHeight();
+ else
+ button = CreateFrame("BUTTON", buttonName .. 1, scrollChild, buttonTemplate);
+ buttonHeight = button:GetHeight();
+ button:SetPoint(initialPoint, scrollChild, initialRelative, initialOffsetX, initialOffsetY);
+ buttons = {}
+ tinsert(buttons, button);
+ end
+
+ self.buttonHeight = round(buttonHeight);
+
+ local numButtons = math.ceil(self:GetHeight() / buttonHeight) + 1;
+
+ for i = #buttons + 1, numButtons do
+ button = CreateFrame("BUTTON", buttonName .. i, scrollChild, buttonTemplate);
+ button:SetPoint(point, buttons[i-1], relativePoint, offsetX, offsetY);
+ tinsert(buttons, button);
+ end
+
+ scrollChild:SetWidth(self:GetWidth())
+ scrollChild:SetHeight(numButtons * buttonHeight);
+ self:SetVerticalScroll(0);
+ self:UpdateScrollChildRect();
+
+ self.buttons = buttons;
+ local scrollBar = self.scrollBar;
+ scrollBar:SetMinMaxValues(0, numButtons * buttonHeight)
+ scrollBar:SetValueStep(.005);
+ scrollBar:SetValue(0);
+end
diff --git a/reference/FrameXML/HybridScrollFrame.xml b/reference/FrameXML/HybridScrollFrame.xml
new file mode 100644
index 0000000..b99ddb2
--- /dev/null
+++ b/reference/FrameXML/HybridScrollFrame.xml
@@ -0,0 +1,165 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():GetParent().scrollUp = self;
+ self:Disable();
+ self:RegisterForClicks("LeftButtonUp", "LeftButtonDown");
+ self.direction = 1;
+
+
+ HybridScrollFrameScrollButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():GetParent().scrollDown = self;
+ self:Disable();
+ self:RegisterForClicks("LeftButtonUp", "LeftButtonDown");
+ self.direction = -1;
+
+
+ HybridScrollFrameScrollButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+ self:GetParent().scrollBar = self;
+
+
+ HybridScrollFrame_OnValueChanged(self:GetParent(), value);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HybridScrollFrame_OnLoad(self);
+
+
+ HybridScrollFrame_OnMouseWheel(self, delta);
+
+
+
+
+
+
+ HybridScrollFrameScrollChild_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/InterfaceOptionsFrame.lua b/reference/FrameXML/InterfaceOptionsFrame.lua
new file mode 100644
index 0000000..f6ae17d
--- /dev/null
+++ b/reference/FrameXML/InterfaceOptionsFrame.lua
@@ -0,0 +1,667 @@
+
+INTERFACEOPTIONS_ADDONCATEGORIES = {};
+
+local blizzardCategories = {};
+
+local next = next;
+local function SecureNext(elements, key)
+ return securecall(next, elements, key);
+end
+
+local tinsert = tinsert;
+local strlower = strlower;
+
+
+-- [[ InterfaceOptionsList functions ]] --
+
+function InterfaceOptionsList_DisplayPanel (frame)
+ if ( InterfaceOptionsFramePanelContainer.displayedPanel ) then
+ InterfaceOptionsFramePanelContainer.displayedPanel:Hide();
+ end
+
+ InterfaceOptionsFramePanelContainer.displayedPanel = frame;
+
+ frame:SetParent(InterfaceOptionsFramePanelContainer);
+ frame:ClearAllPoints();
+ frame:SetPoint("TOPLEFT", InterfaceOptionsFramePanelContainer, "TOPLEFT");
+ frame:SetPoint("BOTTOMRIGHT", InterfaceOptionsFramePanelContainer, "BOTTOMRIGHT");
+ frame:Show();
+end
+
+function InterfaceOptionsListButton_OnClick (self, mouseButton)
+ if ( mouseButton == "RightButton" ) then
+ if ( self.element.hasChildren ) then
+ OptionsListButtonToggle_OnClick(self.toggle);
+ end
+ return;
+ end
+
+ local parent = self:GetParent();
+ local buttons = parent.buttons;
+
+ OptionsList_ClearSelection(InterfaceOptionsFrameCategories, InterfaceOptionsFrameCategories.buttons);
+ OptionsList_ClearSelection(InterfaceOptionsFrameAddOns, InterfaceOptionsFrameAddOns.buttons);
+ OptionsList_SelectButton(parent, self);
+
+ InterfaceOptionsList_DisplayPanel(self.element);
+end
+
+function InterfaceOptionsListButton_ToggleSubCategories (self)
+ local element = self.element;
+
+ element.collapsed = not element.collapsed;
+ local collapsed = element.collapsed;
+
+ for _, category in SecureNext, blizzardCategories do
+ if ( category.parent == element.name ) then
+ if ( collapsed ) then
+ category.hidden = true;
+ else
+ category.hidden = false;
+ end
+ end
+ end
+
+ for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
+ if ( category.parent == element.name ) then
+ if ( collapsed ) then
+ category.hidden = true;
+ else
+ category.hidden = false;
+ end
+ end
+ end
+
+ InterfaceCategoryList_Update();
+ InterfaceAddOnsList_Update();
+end
+
+
+--Table to reuse! Yay reuse!
+local displayedElements = {}
+
+function InterfaceCategoryList_Update ()
+ --Redraw the scroll lists
+ local offset = FauxScrollFrame_GetOffset(InterfaceOptionsFrameCategoriesList);
+ local buttons = InterfaceOptionsFrameCategories.buttons;
+ local element;
+
+ for i, element in SecureNext, displayedElements do
+ displayedElements[i] = nil;
+ end
+
+ for i, element in SecureNext, blizzardCategories do
+ if ( not element.hidden ) then
+ tinsert(displayedElements, element);
+ end
+ end
+
+ local numButtons = #buttons;
+ local numCategories = #displayedElements;
+
+ if ( numCategories > numButtons and ( not InterfaceOptionsFrameCategoriesList:IsShown() ) ) then
+ OptionsList_DisplayScrollBar(InterfaceOptionsFrameCategories);
+ elseif ( numCategories <= numButtons and ( InterfaceOptionsFrameCategoriesList:IsShown() ) ) then
+ OptionsList_HideScrollBar(InterfaceOptionsFrameCategories);
+ end
+
+ FauxScrollFrame_Update(InterfaceOptionsFrameCategoriesList, numCategories, numButtons, buttons[1]:GetHeight());
+
+ local selection = InterfaceOptionsFrameCategories.selection;
+ if ( selection ) then
+ -- Store the currently selected element and clear all the buttons, we're redrawing.
+ OptionsList_ClearSelection(InterfaceOptionsFrameCategories, InterfaceOptionsFrameCategories.buttons);
+ end
+
+ for i = 1, numButtons do
+ element = displayedElements[i + offset];
+ if ( not element ) then
+ OptionsList_HideButton(buttons[i]);
+ else
+ OptionsList_DisplayButton(buttons[i], element);
+
+ if ( selection ) and ( selection == element ) and ( not InterfaceOptionsFrameCategories.selection ) then
+ OptionsList_SelectButton(InterfaceOptionsFrameCategories, buttons[i]);
+ end
+ end
+
+ end
+
+ if ( selection ) then
+ -- If there was a selected element before we cleared the button highlights, restore it, 'cause we're done.
+ -- Note: This theoretically might already have been done by OptionsList_SelectButton, but in the event that the selected button hasn't been drawn, this is still necessary.
+ InterfaceOptionsFrameCategories.selection = selection;
+ end
+end
+
+function InterfaceAddOnsList_Update ()
+ -- Might want to merge this into InterfaceCategoryList_Update depending on whether or not things get differentiated.
+ local offset = FauxScrollFrame_GetOffset(InterfaceOptionsFrameAddOnsList);
+ local buttons = InterfaceOptionsFrameAddOns.buttons;
+ local element;
+
+ for i, element in SecureNext, displayedElements do
+ displayedElements[i] = nil;
+ end
+
+ for i, element in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
+ if ( not element.hidden ) then
+ tinsert(displayedElements, element);
+ end
+ end
+
+ local numAddOnCategories = #displayedElements;
+ local numButtons = #buttons;
+
+ -- Show the AddOns tab if it's not empty.
+ if ( ( InterfaceOptionsFrameTab2 and not InterfaceOptionsFrameTab2:IsShown() ) and numAddOnCategories > 0 ) then
+ InterfaceOptionsFrameCategoriesTop:Hide();
+ InterfaceOptionsFrameAddOnsTop:Hide();
+ InterfaceOptionsFrameTab1:Show();
+ InterfaceOptionsFrameTab2:Show();
+ end
+
+ if ( numAddOnCategories > numButtons and ( not InterfaceOptionsFrameAddOnsList:IsShown() ) ) then
+ -- We need to show the scroll bar, we have more elements than buttons.
+ OptionsList_DisplayScrollBar(InterfaceOptionsFrameAddOns);
+ elseif ( numAddOnCategories <= numButtons and ( InterfaceOptionsFrameAddOnsList:IsShown() ) ) then
+ -- Hide the scrollbar, there's nothing to scroll.
+ OptionsList_HideScrollBar(InterfaceOptionsFrameAddOns);
+ end
+
+ FauxScrollFrame_Update(InterfaceOptionsFrameAddOnsList, numAddOnCategories, numButtons, buttons[1]:GetHeight());
+
+ local selection = InterfaceOptionsFrameAddOns.selection;
+ if ( selection ) then
+ OptionsList_ClearSelection(InterfaceOptionsFrameAddOns, InterfaceOptionsFrameAddOns.buttons);
+ end
+
+ for i = 1, #buttons do
+ element = displayedElements[i + offset]
+ if ( not element ) then
+ OptionsList_HideButton(buttons[i]);
+ else
+ OptionsList_DisplayButton(buttons[i], element);
+
+ if ( selection ) and ( selection == element ) and ( not InterfaceOptionsFrameAddOns.selection ) then
+ OptionsList_SelectButton(InterfaceOptionsFrameAddOns, buttons[i]);
+ end
+ end
+ end
+
+ if ( selection ) then
+ InterfaceOptionsFrameAddOns.selection = selection;
+ end
+end
+
+
+-- [[ InterfaceOptionsFrame ]] --
+
+function InterfaceOptionsFrame_Show ()
+ if ( InterfaceOptionsFrame:IsShown() ) then
+ InterfaceOptionsFrame:Hide();
+ else
+ InterfaceOptionsFrame:Show();
+ end
+end
+
+local function InterfaceOptionsFrame_RunOkayForCategory (category)
+ pcall(category.okay, category);
+end
+
+local function InterfaceOptionsFrame_RunDefaultForCategory (category)
+ pcall(category.default, category);
+end
+
+local function InterfaceOptionsFrame_RunCancelForCategory (category)
+ pcall(category.cancel, category);
+end
+
+local function InterfaceOptionsFrame_RunRefreshForCategory (category)
+ pcall(category.refresh, category);
+end
+
+function InterfaceOptionsFrameOkay_OnClick (self, button, apply)
+ --Iterate through registered panels and run their okay methods in a taint-safe fashion
+
+ for _, category in SecureNext, blizzardCategories do
+ securecall(InterfaceOptionsFrame_RunOkayForCategory, category);
+ end
+
+ for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
+ securecall(InterfaceOptionsFrame_RunOkayForCategory, category);
+ end
+
+ if ( InterfaceOptionsFrame.gameRestart ) then
+ StaticPopup_Show("CLIENT_RESTART_ALERT");
+ InterfaceOptionsFrame.gameRestart = nil;
+ elseif ( InterfaceOptionsFrame.logout ) then
+ StaticPopup_Show("CLIENT_LOGOUT_ALERT");
+ InterfaceOptionsFrame.logout = nil;
+ end
+
+ if ( not apply ) then
+ InterfaceOptionsFrame_Show();
+ end
+end
+
+function InterfaceOptionsFrameCancel_OnClick (self, button)
+ --Iterate through registered panels and run their cancel methods in a taint-safe fashion
+
+ for _, category in SecureNext, blizzardCategories do
+ securecall(InterfaceOptionsFrame_RunCancelForCategory, category);
+ end
+
+ for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
+ securecall(InterfaceOptionsFrame_RunCancelForCategory, category);
+ end
+
+ InterfaceOptionsFrame.gameRestart = nil;
+ InterfaceOptionsFrame.logout = nil;
+
+ InterfaceOptionsFrame_Show();
+end
+
+function InterfaceOptionsFrameDefaults_OnClick (self, button)
+ StaticPopup_Show("CONFIRM_RESET_INTERFACE_SETTINGS");
+end
+
+function InterfaceOptionsFrame_SetAllToDefaults ()
+ --Iterate through registered panels and run their default methods in a taint-safe fashion
+
+ for _, category in SecureNext, blizzardCategories do
+ securecall(InterfaceOptionsFrame_RunDefaultForCategory, category);
+ end
+
+ for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
+ securecall(InterfaceOptionsFrame_RunDefaultForCategory, category);
+ end
+
+ --Refresh the categories to pick up changes made.
+ InterfaceOptionsOptionsFrame_RefreshCategories();
+ InterfaceOptionsOptionsFrame_RefreshAddOns();
+end
+
+function InterfaceOptionsFrame_SetCurrentToDefaults ()
+ local displayedPanel = InterfaceOptionsFramePanelContainer.displayedPanel;
+ if ( not displayedPanel or not displayedPanel.default ) then
+ return;
+ end
+
+ displayedPanel.default(displayedPanel);
+ --Run the refresh method to refresh any values that were changed.
+ displayedPanel.refresh(displayedPanel);
+end
+
+function InterfaceOptionsOptionsFrame_RefreshCategories ()
+ for _, category in SecureNext, blizzardCategories do
+ securecall(InterfaceOptionsFrame_RunRefreshForCategory, category);
+ end
+end
+
+function InterfaceOptionsOptionsFrame_RefreshAddOns ()
+ for _, category in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
+ securecall(InterfaceOptionsFrame_RunRefreshForCategory, category);
+ end
+end
+
+uvarInfo = {
+ ["REMOVE_CHAT_DELAY"] = { default = "0", cvar = "removeChatDelay", event = "REMOVE_CHAT_DELAY_TEXT" },
+ ["SHOW_NEWBIE_TIPS"] = { default = "1", cvar = "showNewbieTips", event = "SHOW_NEWBIE_TIPS_TEXT" },
+ ["LOCK_ACTIONBAR"] = { default = "0", cvar = "lockActionBars", event = "LOCK_ACTIONBAR_TEXT" },
+ ["SHOW_BUFF_DURATIONS"] = { default = "0", cvar = "buffDurations", event = "SHOW_BUFF_DURATION_TEXT" },
+ ["ALWAYS_SHOW_MULTIBARS"] = { default = "0", cvar = "alwaysShowActionBars", event = "ALWAYS_SHOW_MULTIBARS_TEXT" },
+ ["SHOW_PARTY_PETS"] = { default = "1", cvar = "showPartyPets", event = "SHOW_PARTY_PETS_TEXT" },
+ ["QUEST_FADING_DISABLE"] = { default = "0", cvar = "questFadingDisable", event = "SHOW_QUEST_FADING_TEXT" },
+ ["SHOW_PARTY_BACKGROUND"] = { default = "0", cvar = "showPartyBackground", event = "SHOW_PARTY_BACKGROUND_TEXT" },
+ ["HIDE_PARTY_INTERFACE"] = { default = "0", cvar = "hidePartyInRaid", event = "HIDE_PARTY_INTERFACE_TEXT" },
+ ["SHOW_TARGET_OF_TARGET"] = { default = "0", cvar = "showTargetOfTarget", event = "SHOW_TARGET_OF_TARGET_TEXT" },
+ ["SHOW_TARGET_OF_TARGET_STATE"] = { default = "5", cvar = "targetOfTargetMode", event = "SHOW_TARGET_OF_TARGET_STATE" },
+ ["WORLD_PVP_OBJECTIVES_DISPLAY"] = { default = "2", cvar = "displayWorldPVPObjectives", event = "WORLD_PVP_OBJECTIVES_DISPLAY" },
+ ["AUTO_QUEST_WATCH"] = { default = "1", cvar = "autoQuestWatch", event = "AUTO_QUEST_WATCH_TEXT" },
+ ["LOOT_UNDER_MOUSE"] = { default = "0", cvar = "lootUnderMouse", event = "LOOT_UNDER_MOUSE_TEXT" },
+ ["AUTO_LOOT_DEFAULT"] = { default = "0", cvar = "autoLootDefault", event = "AUTO_LOOT_DEFAULT_TEXT" },
+ ["SHOW_COMBAT_TEXT"] = { default = "1", cvar = "enableCombatText", event = "SHOW_COMBAT_TEXT_TEXT" },
+ ["COMBAT_TEXT_SHOW_LOW_HEALTH_MANA"] = { default = "1", cvar = "fctLowManaHealth", event = "COMBAT_TEXT_SHOW_LOW_HEALTH_MANA_TEXT" },
+ ["COMBAT_TEXT_SHOW_AURAS"] = { default = "0", cvar = "fctAuras", event = "COMBAT_TEXT_SHOW_AURAS_TEXT" },
+ ["COMBAT_TEXT_SHOW_AURA_FADE"] = { default = "0", cvar = "fctAuras", event = "COMBAT_TEXT_SHOW_AURAS_TEXT" },
+ ["COMBAT_TEXT_SHOW_COMBAT_STATE"] = { default = "0", cvar = "fctCombatState", event = "COMBAT_TEXT_SHOW_COMBAT_STATE_TEXT" },
+ ["COMBAT_TEXT_SHOW_DODGE_PARRY_MISS"] = { default = "0", cvar = "fctDodgeParryMiss", event = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS_TEXT" },
+ ["COMBAT_TEXT_SHOW_RESISTANCES"] = { default = "0", cvar = "fctDamageReduction", event = "COMBAT_TEXT_SHOW_RESISTANCES_TEXT" },
+ ["COMBAT_TEXT_SHOW_REPUTATION"] = { default = "0", cvar = "fctRepChanges", event = "COMBAT_TEXT_SHOW_REPUTATION_TEXT" },
+ ["COMBAT_TEXT_SHOW_REACTIVES"] = { default = "0", cvar = "fctReactives", event = "COMBAT_TEXT_SHOW_REACTIVES_TEXT" },
+ ["COMBAT_TEXT_SHOW_FRIENDLY_NAMES"] = { default = "0", cvar = "fctFriendlyHealers", event = "COMBAT_TEXT_SHOW_FRIENDLY_NAMES_TEXT" },
+ ["COMBAT_TEXT_SHOW_COMBO_POINTS"] = { default = "0", cvar = "fctComboPoints", event = "COMBAT_TEXT_SHOW_COMBO_POINTS_TEXT" },
+ ["COMBAT_TEXT_SHOW_ENERGIZE"] = { default = "0", cvar = "fctEnergyGains", event = "COMBAT_TEXT_SHOW_ENERGIZE_TEXT" },
+ ["COMBAT_TEXT_SHOW_PERIODIC_ENERGIZE"] = { default = "0", cvar = "fctPeriodicEnergyGains", event = "COMBAT_TEXT_SHOW_PERIODIC_ENERGIZE_TEXT" },
+ ["COMBAT_TEXT_FLOAT_MODE"] = { default = "1", cvar = "combatTextFloatMode", event = "COMBAT_TEXT_FLOAT_MODE" },
+ ["COMBAT_TEXT_SHOW_HONOR_GAINED"] = { default = "0", cvar = "fctHonorGains", event = "COMBAT_TEXT_SHOW_HONOR_GAINED_TEXT" },
+ ["ALWAYS_SHOW_MULTIBARS"] = { default = "0", cvar = "alwaysShowActionBars", },
+ ["SHOW_CASTABLE_BUFFS"] = { default = "0", cvar = "showCastableBuffs", event = "SHOW_CASTABLE_BUFFS_TEXT" },
+ ["SHOW_DISPELLABLE_DEBUFFS"] = { default = "1", cvar = "showDispelDebuffs", event = "SHOW_DISPELLABLE_DEBUFFS_TEXT" },
+ ["SHOW_ARENA_ENEMY_FRAMES"] = { default = "1", cvar = "showArenaEnemyFrames", event = "SHOW_ARENA_ENEMY_FRAMES_TEXT" },
+ ["SHOW_ARENA_ENEMY_CASTBAR"] = { default = "1", cvar = "showArenaEnemyCastbar", event = "SHOW_ARENA_ENEMY_CASTBAR_TEXT" },
+ ["SHOW_ARENA_ENEMY_PETS"] = { default = "1", cvar = "showArenaEnemyPets", event = "SHOW_ARENA_ENEMY_PETS_TEXT" },
+ ["SHOW_CASTABLE_DEBUFFS"] = { default = "0", cvar = "showCastableDebuffs", event = "SHOW_CASTABLE_DEBUFFS_TEXT" },
+}
+
+function InterfaceOptionsFrame_InitializeUVars ()
+ -- Setup UVars that keep settings
+ for uvar, setting in SecureNext, uvarInfo do
+ _G[uvar] = setting.default;
+ end
+end
+
+function InterfaceOptionsFrame_LoadUVars ()
+ local variable, cvarValue
+ for uvar, setting in SecureNext, uvarInfo do
+ variable = _G[uvar];
+ cvarValue = GetCVar(setting.cvar);
+ if ( cvarValue == setting.default and variable ~= setting.default ) then
+ SetCVar(setting.cvar, variable, setting.event)
+ if ( setting.func ) then
+ setting.func()
+ end
+ elseif ( cvarValue ~= setting.default or ( not ( _G[uvar] ) ) ) then
+ if ( setting.func ) then
+ setting.func()
+ end
+ end
+ end
+end
+
+function InterfaceOptionsFrame_OnLoad (self)
+ --Make sure all the UVars get their default values set, since systems that require them to be defined will be loaded before anything in UIOptionsPanels
+ self:RegisterEvent("VARIABLES_LOADED");
+ InterfaceOptionsFrame_InitializeUVars();
+ PanelTemplates_SetNumTabs(self, 2);
+ InterfaceOptionsFrame.selectedTab = 1;
+ PanelTemplates_UpdateTabs(self);
+end
+
+function InterfaceOptionsFrame_OnEvent (self, event, ...)
+ if ( event == "VARIABLES_LOADED" ) then
+ InterfaceOptionsFrame_LoadUVars();
+ end
+end
+
+function InterfaceOptionsFrame_OnShow (self)
+ --Refresh the two category lists and display the "Controls" group of options if nothing is selected.
+ InterfaceCategoryList_Update();
+ InterfaceAddOnsList_Update();
+ if ( not InterfaceOptionsFramePanelContainer.displayedPanel ) then
+ InterfaceOptionsFrame_OpenToCategory(CONTROLS_LABEL);
+ end
+ --Refresh the categories to pick up changes made while the options frame was hidden.
+ InterfaceOptionsOptionsFrame_RefreshCategories();
+ InterfaceOptionsOptionsFrame_RefreshAddOns();
+end
+
+function InterfaceOptionsFrame_OnHide (self)
+ OptionsFrame_OnHide(InterfaceOptionsFrame);
+
+ if ( InterfaceOptionsFrame.gameRestart ) then
+ StaticPopup_Show("CLIENT_RESTART_ALERT");
+ InterfaceOptionsFrame.gameRestart = nil;
+ elseif ( InterfaceOptionsFrame.logout ) then
+ StaticPopup_Show("CLIENT_LOGOUT_ALERT");
+ InterfaceOptionsFrame.logout = nil;
+ end
+end
+
+function InterfaceOptionsFrame_TabOnClick ()
+ if ( InterfaceOptionsFrame.selectedTab == 1 ) then
+ InterfaceOptionsFrameCategories:Show();
+ InterfaceOptionsFrameAddOns:Hide();
+ InterfaceOptionsFrameTab1TabSpacer:Show();
+ InterfaceOptionsFrameTab2TabSpacer1:Hide();
+ InterfaceOptionsFrameTab2TabSpacer2:Hide();
+ else
+ InterfaceOptionsFrameCategories:Hide();
+ InterfaceOptionsFrameAddOns:Show();
+ InterfaceOptionsFrameTab1TabSpacer:Hide();
+ InterfaceOptionsFrameTab2TabSpacer1:Show();
+ InterfaceOptionsFrameTab2TabSpacer2:Show();
+ end
+end
+
+function InterfaceOptionsFrame_OpenToCategory (panel)
+ local panelName;
+ if ( type(panel) == "string" ) then
+ panelName = panel;
+ panel = nil;
+ end
+
+ assert(panelName or panel, 'Usage: InterfaceOptionsFrame_OpenToCategory("categoryName" or panel)');
+
+ local blizzardElement, elementToDisplay
+
+ for i, element in SecureNext, blizzardCategories do
+ if ( element == panel or (panelName and element.name and element.name == panelName) ) then
+ elementToDisplay = element;
+ blizzardElement = true;
+ break;
+ end
+ end
+
+ if ( not elementToDisplay ) then
+ for i, element in SecureNext, INTERFACEOPTIONS_ADDONCATEGORIES do
+ if ( element == panel or (panelName and element.name and element.name == panelName) ) then
+ elementToDisplay = element;
+ break;
+ end
+ end
+ end
+
+ if ( not elementToDisplay ) then
+ return;
+ end
+
+ if ( blizzardElement ) then
+ InterfaceOptionsFrameTab1:Click();
+ local buttons = InterfaceOptionsFrameCategories.buttons;
+ for i, button in SecureNext, buttons do
+ if ( button.element == elementToDisplay ) then
+ InterfaceOptionsListButton_OnClick(button);
+ elseif ( elementToDisplay.parent and button.element and (button.element.name == elementToDisplay.parent and button.element.collapsed) ) then
+ OptionsListButtonToggle_OnClick(button.toggle);
+ end
+ end
+
+ if ( not InterfaceOptionsFrame:IsShown() ) then
+ InterfaceOptionsFrame_Show();
+ end
+ else
+ InterfaceOptionsFrameTab2:Click();
+ local buttons = InterfaceOptionsFrameAddOns.buttons;
+ for i, button in SecureNext, buttons do
+ if ( button.element == elementToDisplay ) then
+ InterfaceOptionsListButton_OnClick(button);
+ elseif ( elementToDisplay.parent and button.element and (button.element.name == elementToDisplay.parent and button.element.collapsed) ) then
+ OptionsListButtonToggle_OnClick(button.toggle);
+ end
+ end
+
+ if ( not InterfaceOptionsFrame:IsShown() ) then
+ InterfaceOptionsFrame_Show();
+ end
+ end
+end
+
+
+---------------------------------------------------------------------------------------------------
+-- HOWTO: Add new categories of options
+--
+-- The new Interface Options frame allows authors to place their configuration
+-- frames (aka "panels") alongside the panels for modifying the default UI.
+--
+-- Adding a new panel to the Interface Options frame is a fairly straightforward process.
+-- Any frame can be used as a panel as long as it implements the required values and methods.
+-- Once a frame is ready to be used as a panel, it must be registered using the function
+-- InterfaceOptions_AddCategory, i.e. InterfaceOptions_AddCategory(panel)
+--
+-- Panels can be designated as sub-categories of existing options. These panels are listed
+-- with smaller text, offset, and tied to parent categories. The parent categories can be expanded
+-- or collapsed to toggle display of their sub-categories.
+--
+-- When players select a category of options from the Interface Options frame, the panel associated
+-- with that category will be anchored to the right hand side of the Interface Options frame and shown.
+--
+-- The following members and methods are used by the Interface Options frame to display and organize panels.
+--
+-- panel.name - string (required)
+-- The name of the AddOn or group of configuration options.
+-- This is the text that will display in the AddOn options list.
+--
+-- panel.parent - string (optional)
+-- Name of the parent of the AddOn or group of configuration options.
+-- This identifies "panel" as the child of another category.
+-- If the parent category doesn't exist, "panel" will be displayed as a regular category.
+--
+-- panel.okay - function (optional)
+-- This method will run when the player clicks "okay" in the Interface Options.
+--
+-- panel.cancel - function (optional)
+-- This method will run when the player clicks "cancel" in the Interface Options.
+-- Use this to revert their changes.
+--
+-- panel.default - function (optional)
+-- This method will run when the player clicks "defaults".
+-- Use this to revert their changes to your defaults.
+--
+-- panel.refresh - function (optional)
+-- This method will run when the Interface Options frame calls its OnShow function and after defaults
+-- have been applied via the panel.default method described above.
+-- Use this to refresh your panel's UI in case settings were changed without player interaction.
+--
+-- EXAMPLE -- Use XML to create a frame, and through its OnLoad function, make the frame a panel.
+--
+-- MyAddOn.xml
+--
+--
+--
+-- ExamplePanel_OnLoad(self);
+--
+--
+--
+--
+-- MyAddOn.lua
+-- function ExamplePanel_OnLoad (panel)
+-- panel.name = "My AddOn"
+-- InterfaceOptions_AddCategory(panel);
+-- end
+--
+-- EXAMPLE -- Dynamically create a frame and use it as a subcategory for "My AddOn".
+--
+-- local panel = CreateFrame("FRAME", "ExampleSubCategory");
+-- panel.name = "My SubCategory";
+-- panel.parent = "My AddOn";
+--
+-- InterfaceOptions_AddCategory(panel);
+--
+-- EXAMPLE -- Create a frame with a control, an okay and a cancel method
+--
+-- --[[ Create a frame to use as the panel ]] --
+-- local panel = CreateFrame("FRAME", "ExamplePanel");
+-- panel.name = "My AddOn";
+--
+-- -- [[ When the player clicks okay, set the original value to the current setting ]] --
+-- panel.okay =
+-- function (self)
+-- self.originalValue = MY_VARIABLE;
+-- end
+--
+-- -- [[ When the player clicks cancel, set the current setting to the original value ]] --
+-- panel.cancel =
+-- function (self)
+-- MY_VARIABLE = self.originalValue;
+-- end
+--
+-- -- [[ Add the panel to the Interface Options ]] --
+-- InterfaceOptions_AddCategory(panel);
+-------------------------------------------------------------------------------------------------
+
+
+function InterfaceOptions_AddCategory (frame, addOn, position)
+ if ( issecure() and ( not addOn ) ) then
+ local parent = frame.parent;
+ if ( parent ) then
+ for i = 1, #blizzardCategories do
+ if ( blizzardCategories[i].name == parent ) then
+ if ( blizzardCategories[i].hasChildren ) then
+ frame.hidden = ( blizzardCategories[i].collapsed );
+ else
+ frame.hidden = true;
+ blizzardCategories[i].hasChildren = true;
+ blizzardCategories[i].collapsed = true;
+ end
+ tinsert(blizzardCategories, i + 1, frame);
+ InterfaceCategoryList_Update();
+ return;
+ end
+ end
+ end
+
+ if ( position ) then
+ tinsert(blizzardCategories, position, frame);
+ else
+ tinsert(blizzardCategories, frame);
+ end
+
+ InterfaceCategoryList_Update();
+ elseif ( not type(frame) == "table" or not frame.name ) then
+ --Check to make sure that AddOn interface panels have the necessary attributes to work with the system.
+ return;
+ else
+ frame.okay = frame.okay or function () end;
+ frame.cancel = frame.cancel or function () end;
+ frame.default = frame.default or function () end;
+ frame.refresh = frame.refresh or function () end;
+
+ local categories = INTERFACEOPTIONS_ADDONCATEGORIES;
+
+ local name = strlower(frame.name);
+ local parent = frame.parent;
+ if ( parent ) then
+ for i = 1, #categories do
+ if ( categories[i].name == parent ) then
+ if ( not categories[i].hasChildren ) then
+ frame.hidden = true;
+ categories[i].hasChildren = true;
+ categories[i].collapsed = true;
+ tinsert(categories, i + 1, frame);
+ InterfaceAddOnsList_Update();
+ return;
+ end
+
+ frame.hidden = ( categories[i].collapsed );
+
+ local j = i + 1;
+ while ( categories[j] and categories[j].parent == parent ) do
+ -- Skip to the end of the list of children, add this there.
+ j = j + 1;
+ end
+
+ tinsert(categories, j, frame);
+ InterfaceAddOnsList_Update();
+ return;
+ end
+ end
+ end
+
+ for i = 1, #categories do
+ if ( ( not categories[i].parent ) and ( name < strlower(categories[i].name) ) ) then
+ tinsert(categories, i, frame);
+ InterfaceAddOnsList_Update();
+ return;
+ end
+ end
+
+ if ( position ) then
+ tinsert(categories, position, frame);
+ else
+ tinsert(categories, frame);
+ end
+ InterfaceAddOnsList_Update();
+ end
+end
diff --git a/reference/FrameXML/InterfaceOptionsFrame.xml b/reference/FrameXML/InterfaceOptionsFrame.xml
new file mode 100644
index 0000000..a902800
--- /dev/null
+++ b/reference/FrameXML/InterfaceOptionsFrame.xml
@@ -0,0 +1,288 @@
+
+
+
+
+
+
+
+
+ OptionsListButton_OnLoad(self, InterfaceOptionsListButton_ToggleSubCategories);
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ InterfaceOptionsListButton_OnClick(self, button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.labelText = CATEGORY;
+ OptionsList_OnLoad(self, "InterfaceOptionsListButtonTemplate");
+ self.update = InterfaceCategoryList_Update;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.labelText = ADDONS
+ OptionsList_OnLoad(self, "InterfaceOptionsListButtonTemplate");
+ self.update = InterfaceAddOnsList_Update;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(.6, .6, .6, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoTab");
+ PanelTemplates_Tab_OnClick(self, InterfaceOptionsFrame);
+ PanelTemplates_UpdateTabs(InterfaceOptionsFrame);
+ InterfaceOptionsFrame_TabOnClick();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoTab");
+ PanelTemplates_Tab_OnClick(self, InterfaceOptionsFrame);
+ PanelTemplates_UpdateTabs(InterfaceOptionsFrame);
+ InterfaceOptionsFrame_TabOnClick();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/InterfaceOptionsPanels.lua b/reference/FrameXML/InterfaceOptionsPanels.lua
new file mode 100644
index 0000000..f9fdada
--- /dev/null
+++ b/reference/FrameXML/InterfaceOptionsPanels.lua
@@ -0,0 +1,1824 @@
+local next = next;
+local function SecureNext(elements, key)
+ return securecall(next, elements, key);
+end
+
+
+-- [[ Generic Interface Options Panel ]] --
+
+function InterfaceOptionsPanel_CheckButton_OnClick (checkButton)
+ if ( checkButton:GetChecked() and checkButton.interruptCheck ) then
+ checkButton.interruptCheck(checkButton);
+ checkButton:SetChecked(false); --Make it look like the button wasn't changed, but after the interrupt function has had a chance to look at what it was set to.
+ return;
+ elseif ( not checkButton:GetChecked() and checkButton.interruptUncheck ) then
+ checkButton.interruptUncheck(checkButton);
+ checkButton:SetChecked(true); --Make it look like the button wasn't changed, but after the interrupt function has had a chance to look at what it was set to.
+ return;
+ end
+
+ InterfaceOptionsPanel_CheckButton_Update(checkButton);
+end
+
+function InterfaceOptionsPanel_CheckButton_Update (checkButton)
+ local setting = "0";
+ if ( checkButton:GetChecked() ) then
+ if ( not checkButton.invert ) then
+ setting = "1"
+ end
+ elseif ( checkButton.invert ) then
+ setting = "1"
+ end
+
+ checkButton.value = setting;
+
+ if ( checkButton.cvar ) then
+ BlizzardOptionsPanel_SetCVarSafe(checkButton.cvar, setting, checkButton.event);
+ end
+
+ if ( checkButton.uvar ) then
+ _G[checkButton.uvar] = setting;
+ end
+
+ if ( checkButton.dependentControls ) then
+ if ( checkButton:GetChecked() ) then
+ for _, control in SecureNext, checkButton.dependentControls do
+ control:Enable();
+ end
+ else
+ for _, control in SecureNext, checkButton.dependentControls do
+ control:Disable();
+ end
+ end
+ end
+
+ if ( checkButton.setFunc ) then
+ checkButton.setFunc(setting);
+ end
+end
+
+
+local function InterfaceOptionsPanel_CancelControl (control)
+ if ( control.oldValue ) then
+ if ( control.value and control.value ~= control.oldValue ) then
+ control:SetValue(control.oldValue);
+ end
+ elseif ( control.value ) then
+ if ( control:GetValue() ~= control.value ) then
+ control:SetValue(control.value);
+ end
+ end
+end
+
+local function InterfaceOptionsPanel_DefaultControl (control)
+ if ( control.defaultValue and control.value ~= control.defaultValue ) then
+ control:SetValue(control.defaultValue);
+ control.value = control.defaultValue;
+ end
+end
+
+local function InterfaceOptionsPanel_Okay (self)
+ for _, control in SecureNext, self.controls do
+ securecall(BlizzardOptionsPanel_OkayControl, control);
+ end
+end
+
+local function InterfaceOptionsPanel_Cancel (self)
+ for _, control in SecureNext, self.controls do
+ securecall(InterfaceOptionsPanel_CancelControl, control);
+ if ( control.setFunc ) then
+ control.setFunc(control:GetValue());
+ end
+ end
+end
+
+local function InterfaceOptionsPanel_Default (self)
+ for _, control in SecureNext, self.controls do
+ securecall(InterfaceOptionsPanel_DefaultControl, control);
+ if ( control.setFunc ) then
+ control.setFunc(control:GetValue());
+ end
+ end
+end
+
+local function InterfaceOptionsPanel_Refresh (self)
+ for _, control in SecureNext, self.controls do
+ securecall(BlizzardOptionsPanel_RefreshControl, control);
+ -- record values so we can cancel back to this state
+ control.oldValue = control.value;
+ end
+end
+
+
+function InterfaceOptionsPanel_OnLoad (self)
+ BlizzardOptionsPanel_OnLoad(self, nil, InterfaceOptionsPanel_Cancel, InterfaceOptionsPanel_Default, InterfaceOptionsPanel_Refresh);
+ InterfaceOptions_AddCategory(self);
+end
+
+
+-- [[ Controls Options Panel ]] --
+
+ControlsPanelOptions = {
+ deselectOnClick = { text = "GAMEFIELD_DESELECT_TEXT" },
+ autoDismountFlying = { text = "AUTO_DISMOUNT_FLYING_TEXT" },
+ autoClearAFK = { text = "CLEAR_AFK" },
+ blockTrades = { text = "BLOCK_TRADES" },
+ lootUnderMouse = { text = "LOOT_UNDER_MOUSE_TEXT" },
+ autoLootDefault = { text = "AUTO_LOOT_DEFAULT_TEXT" }, -- When this gets changed, the function SetAutoLootDefault needs to get run with its value.
+ autoLootKey = { text = "AUTO_LOOT_KEY_TEXT", default = "NONE" },
+}
+
+function InterfaceOptionsControlsPanelAutoLootKeyDropDown_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.defaultValue = "NONE";
+ self.oldValue = GetModifiedClick("AUTOLOOTTOGGLE");
+ self.value = self.oldValue or self.defaultValue;
+ self.tooltip = _G["OPTION_TOOLTIP_AUTO_LOOT_"..self.value.."_KEY"];
+
+ UIDropDownMenu_SetWidth(self, 90);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsControlsPanelAutoLootKeyDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ UIDropDownMenu_SetSelectedValue(self, value);
+ SetModifiedClick("AUTOLOOTTOGGLE", value);
+ SaveBindings(GetCurrentBindingSet());
+ self.tooltip = _G["OPTION_TOOLTIP_AUTO_LOOT_"..value.."_KEY"];
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsControlsPanelAutoLootKeyDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ if ( GetCVar("autoLootDefault") == "1" ) then
+ InterfaceOptionsControlsPanelAutoLootKeyDropDownLabel:SetText(LOOT_KEY_TEXT);
+ else
+ InterfaceOptionsControlsPanelAutoLootKeyDropDownLabel:SetText(AUTO_LOOT_KEY_TEXT);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsControlsPanelAutoLootKeyDropDown_OnClick(self)
+ InterfaceOptionsControlsPanelAutoLootKeyDropDown:SetValue(self.value);
+end
+
+function InterfaceOptionsControlsPanelAutoLootKeyDropDown_Initialize()
+ local selectedValue = UIDropDownMenu_GetSelectedValue(InterfaceOptionsControlsPanelAutoLootKeyDropDown);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = ALT_KEY;
+ info.func = InterfaceOptionsControlsPanelAutoLootKeyDropDown_OnClick;
+ info.value = "ALT";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = ALT_KEY;
+ info.tooltipText = OPTION_TOOLTIP_AUTO_LOOT_ALT_KEY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CTRL_KEY;
+ info.func = InterfaceOptionsControlsPanelAutoLootKeyDropDown_OnClick;
+ info.value = "CTRL";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CTRL_KEY;
+ info.tooltipText = OPTION_TOOLTIP_AUTO_LOOT_CTRL_KEY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = SHIFT_KEY;
+ info.func = InterfaceOptionsControlsPanelAutoLootKeyDropDown_OnClick;
+ info.value = "SHIFT";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = SHIFT_KEY;
+ info.tooltipText = OPTION_TOOLTIP_AUTO_LOOT_SHIFT_KEY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = NONE_KEY;
+ info.func = InterfaceOptionsControlsPanelAutoLootKeyDropDown_OnClick;
+ info.value = "NONE";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = NONE_KEY;
+ info.tooltipText = OPTION_TOOLTIP_AUTO_LOOT_NONE_KEY;
+ UIDropDownMenu_AddButton(info);
+end
+
+function InterfaceOptionsControlsPanelAutoLootKeyDropDown_Update (value)
+ if ( not InterfaceOptionsControlsPanelAutoLootKeyDropDownLabel ) then
+ return;
+ end
+
+ if ( value == "1" ) then
+ InterfaceOptionsControlsPanelAutoLootKeyDropDownLabel:SetText(LOOT_KEY_TEXT);
+ else
+ InterfaceOptionsControlsPanelAutoLootKeyDropDownLabel:SetText(AUTO_LOOT_KEY_TEXT);
+ end
+end
+
+-- [[ Combat Options Panel ]] --
+
+CombatPanelOptions = {
+ assistAttack = { text = "ASSIST_ATTACK" },
+ autoRangedCombat = { text = "AUTO_RANGED_COMBAT_TEXT" },
+ autoSelfCast = { text = "AUTO_SELF_CAST_TEXT" },
+ stopAutoAttackOnTargetChange = { text = "STOP_AUTO_ATTACK" },
+ showTargetOfTarget = { text = "SHOW_TARGET_OF_TARGET_TEXT" },
+ showTargetCastbar = { text = "SHOW_TARGET_CASTBAR" },
+ showVKeyCastbar = { text = "SHOW_TARGET_CASTBAR_IN_V_KEY" },
+ ShowClassColorInNameplate = { text = "SHOW_CLASS_COLOR_IN_V_KEY" },
+}
+
+function InterfaceOptionsCombatPanelTOTDropDown_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.cvar = "targetOfTargetMode";
+
+ local value = GetCVar(self.cvar);
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.value = value;
+ self.oldValue = value;
+ self.tooltip = _G["OPTION_TOOLTIP_TARGETOFTARGET" .. value];
+ _G[self.uvar] = value;
+
+ UIDropDownMenu_SetWidth(self, 110);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCombatPanelTOTDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ SetCVar(self.cvar, value);
+ _G[self.uvar] = value;
+ UIDropDownMenu_SetSelectedValue(self, value);
+ self.tooltip = _G["OPTION_TOOLTIP_TARGETOFTARGET" .. value];
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCombatPanelTOTDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsCombatPanelTOTDropDown_OnClick(self)
+ InterfaceOptionsCombatPanelTOTDropDown:SetValue(self.value);
+end
+
+function InterfaceOptionsCombatPanelTOTDropDown_Initialize(self)
+ local selectedValue = UIDropDownMenu_GetSelectedValue(self);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = RAID;
+ info.func = InterfaceOptionsCombatPanelTOTDropDown_OnClick;
+ info.value = "1"
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = RAID;
+ info.tooltipText = OPTION_TOOLTIP_TARGETOFTARGET_RAID;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = PARTY;
+ info.func = InterfaceOptionsCombatPanelTOTDropDown_OnClick;
+ info.value = "2"
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = PARTY;
+ info.tooltipText = OPTION_TOOLTIP_TARGETOFTARGET_PARTY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = SOLO;
+ info.func = InterfaceOptionsCombatPanelTOTDropDown_OnClick;
+ info.value = "3"
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = SOLO;
+ info.tooltipText = OPTION_TOOLTIP_TARGETOFTARGET_SOLO;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = RAID_AND_PARTY;
+ info.func = InterfaceOptionsCombatPanelTOTDropDown_OnClick;
+ info.value = "4"
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = RAID_AND_PARTY;
+ info.tooltipText = OPTION_TOOLTIP_TARGETOFTARGET_RAID_AND_PARTY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = ALWAYS;
+ info.func = InterfaceOptionsCombatPanelTOTDropDown_OnClick;
+ info.value = "5"
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = ALWAYS;
+ info.tooltipText = OPTION_TOOLTIP_TARGETOFTARGET_ALWAYS;
+ UIDropDownMenu_AddButton(info);
+end
+
+-- [[ Self Cast key dropdown ]] --
+function InterfaceOptionsCombatPanelSelfCastKeyDropDown_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.defaultValue = "NONE";
+ self.oldValue = GetModifiedClick("SELFCAST");
+ self.value = self.oldValue or self.defaultValue;
+ self.tooltip = _G["OPTION_TOOLTIP_AUTO_SELF_CAST_"..self.value.."_KEY"];
+
+ UIDropDownMenu_SetWidth(self, 90);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCombatPanelSelfCastKeyDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ UIDropDownMenu_SetSelectedValue(self, value);
+ SetModifiedClick("SELFCAST", value);
+ SaveBindings(GetCurrentBindingSet());
+ self.tooltip = _G["OPTION_TOOLTIP_AUTO_SELF_CAST_"..value.."_KEY"];
+ end;
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCombatPanelSelfCastKeyDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsCombatPanelSelfCastKeyDropDown_OnClick(self)
+ InterfaceOptionsCombatPanelSelfCastKeyDropDown:SetValue(self.value);
+end
+
+function InterfaceOptionsCombatPanelSelfCastKeyDropDown_Initialize()
+ local selectedValue = UIDropDownMenu_GetSelectedValue(InterfaceOptionsCombatPanelSelfCastKeyDropDown);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = ALT_KEY;
+ info.func = InterfaceOptionsCombatPanelSelfCastKeyDropDown_OnClick;
+ info.value = "ALT";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = ALT_KEY;
+ info.tooltipText = OPTION_TOOLTIP_AUTO_SELF_CAST_ALT_KEY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CTRL_KEY;
+ info.func = InterfaceOptionsCombatPanelSelfCastKeyDropDown_OnClick;
+ info.value = "CTRL";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CTRL_KEY;
+ info.tooltipText = OPTION_TOOLTIP_AUTO_SELF_CAST_CTRL_KEY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = SHIFT_KEY;
+ info.func = InterfaceOptionsCombatPanelSelfCastKeyDropDown_OnClick;
+ info.value = "SHIFT";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = SHIFT_KEY;
+ info.tooltipText = OPTION_TOOLTIP_AUTO_SELF_CAST_SHIFT_KEY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = NONE_KEY;
+ info.func = InterfaceOptionsCombatPanelSelfCastKeyDropDown_OnClick;
+ info.value = "NONE";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = NONE_KEY;
+ info.tooltipText = OPTION_TOOLTIP_AUTO_SELF_CAST_NONE_KEY;
+ UIDropDownMenu_AddButton(info);
+end
+
+-- [[ Focus Cast key dropdown ]] --
+function InterfaceOptionsCombatPanelFocusCastKeyDropDown_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.defaultValue = "NONE";
+ self.oldValue = GetModifiedClick("FOCUSCAST");
+ self.value = self.oldValue or self.defaultValue;
+ self.tooltip = _G["OPTION_TOOLTIP_FOCUS_CAST_"..self.value.."_KEY"];
+
+ UIDropDownMenu_SetWidth(self, 90);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCombatPanelFocusCastKeyDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ UIDropDownMenu_SetSelectedValue(self, value);
+ SetModifiedClick("FOCUSCAST", value);
+ SaveBindings(GetCurrentBindingSet());
+ self.tooltip = _G["OPTION_TOOLTIP_FOCUS_CAST_"..value.."_KEY"];
+ end;
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCombatPanelFocusCastKeyDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsCombatPanelFocusCastKeyDropDown_OnClick(self)
+ InterfaceOptionsCombatPanelFocusCastKeyDropDown:SetValue(self.value);
+end
+
+function InterfaceOptionsCombatPanelFocusCastKeyDropDown_Initialize()
+ local selectedValue = UIDropDownMenu_GetSelectedValue(InterfaceOptionsCombatPanelFocusCastKeyDropDown);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = ALT_KEY;
+ info.func = InterfaceOptionsCombatPanelFocusCastKeyDropDown_OnClick;
+ info.value = "ALT";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = ALT_KEY;
+ info.tooltipText = OPTION_TOOLTIP_FOCUS_CAST_ALT_KEY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CTRL_KEY;
+ info.func = InterfaceOptionsCombatPanelFocusCastKeyDropDown_OnClick;
+ info.value = "CTRL";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CTRL_KEY;
+ info.tooltipText = OPTION_TOOLTIP_FOCUS_CAST_CTRL_KEY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = SHIFT_KEY;
+ info.func = InterfaceOptionsCombatPanelFocusCastKeyDropDown_OnClick;
+ info.value = "SHIFT";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = SHIFT_KEY;
+ info.tooltipText = OPTION_TOOLTIP_FOCUS_CAST_SHIFT_KEY;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = NONE_KEY;
+ info.func = InterfaceOptionsCombatPanelFocusCastKeyDropDown_OnClick;
+ info.value = "NONE";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = NONE_KEY;
+ info.tooltipText = OPTION_TOOLTIP_FOCUS_CAST_NONE_KEY;
+ UIDropDownMenu_AddButton(info);
+end
+
+
+-- [[ Display Options Panel ]] --
+
+DisplayPanelOptions = {
+ rotateMinimap = { text = "ROTATE_MINIMAP" },
+ screenEdgeFlash = { text = "SHOW_FULLSCREEN_STATUS_TEXT" },
+ showLootSpam = { text = "SHOW_LOOT_SPAM" },
+ displayFreeBagSlots = { text = "DISPLAY_FREE_BAG_SLOTS" },
+ showClock = { text = "SHOW_CLOCK" },
+ movieSubtitle = { text = "CINEMATIC_SUBTITLES" },
+ threatShowNumeric = { text = "SHOW_NUMERIC_THREAT" },
+ threatPlaySounds = { text = "PLAY_AGGRO_SOUNDS" },
+ colorblindMode = { text = "USE_COLORBLIND_MODE" },
+ showItemLevel = { text = "SHOW_ITEM_LEVEL" },
+}
+
+function InterfaceOptionsDisplayPanel_OnLoad (self)
+ self.name = DISPLAY_LABEL;
+ self.options = DisplayPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+ self:SetScript("OnEvent", InterfaceOptionsDisplayPanel_OnEvent);
+end
+
+function InterfaceOptionsDisplayPanel_OnEvent (self, event, ...)
+ BlizzardOptionsPanel_OnEvent(self, event, ...);
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ local control;
+
+ control = InterfaceOptionsDisplayPanelShowClock;
+ control.setFunc(GetCVar(control.cvar));
+
+ control = InterfaceOptionsDisplayPanelRotateMinimap;
+ control.setFunc(GetCVar(control.cvar));
+ end
+end
+
+function InterfaceOptionsDisplayPanelShowClock_SetFunc(value)
+ if ( value == "1" ) then
+ TimeManager_LoadUI();
+ if ( TimeManagerClockButton_Show ) then
+ TimeManagerClockButton_Show();
+ end
+ else
+ if ( TimeManagerClockButton_Hide ) then
+ TimeManagerClockButton_Hide();
+ end
+ end
+end
+
+function InterfaceOptionsDisplayPanelShowAggroPercentage_SetFunc()
+ UnitFrame_Update(TargetFrame);
+ UnitFrame_Update(FocusFrame);
+end
+
+function InterfaceOptionsDisplayPanelPreviewTalentChanges_SetFunc()
+ if ( PlayerTalentFrame and PlayerTalentFrame:IsShown() and PlayerTalentFrame_Refresh ) then
+ PlayerTalentFrame_Refresh();
+ end
+end
+
+function InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay_OnEvent(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.cvar = "displayWorldPVPObjectives";
+
+ local value = GetCVar(self.cvar);
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.oldValue = value;
+ self.value = value;
+ self.tooltip = _G["OPTION_TOOLTIP_WORLD_PVP_DISPLAY"..value];
+
+ UIDropDownMenu_SetWidth(self, 90);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ WORLD_PVP_OBJECTIVES_DISPLAY = value;
+ WorldStateAlwaysUpFrame_Update();
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ SetCVar(self.cvar, value, self.event);
+ self.tooltip = _G["OPTION_TOOLTIP_WORLD_PVP_DISPLAY"..value];
+ UIDropDownMenu_SetSelectedValue(self, value);
+ WORLD_PVP_OBJECTIVES_DISPLAY = value;
+ WorldStateAlwaysUpFrame_Update();
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay_OnClick(self)
+ InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay:SetValue(self.value);
+end
+
+function InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay_Initialize()
+ local selectedValue = UIDropDownMenu_GetSelectedValue(InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = ALWAYS;
+ info.func = InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay_OnClick;
+ info.value = "1";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = ALWAYS;
+ info.tooltipText = OPTION_TOOLTIP_WORLD_PVP_DISPLAY_ALWAYS;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = DYNAMIC;
+ info.func = InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay_OnClick;
+ info.value = "2";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = DYNAMIC;
+ info.tooltipText = OPTION_TOOLTIP_WORLD_PVP_DISPLAY_DYNAMIC;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = NEVER;
+ info.func = InterfaceOptionsDisplayPanelWorldPVPObjectiveDisplay_OnClick;
+ info.value = "3";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = NEVER;
+ info.tooltipText = OPTION_TOOLTIP_WORLD_PVP_DISPLAY_NEVER;
+ UIDropDownMenu_AddButton(info);
+end
+
+
+function InterfaceOptionsDisplayPanelAggroWarningDisplay_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.cvar = "threatWarning";
+
+ local value = GetCVar(self.cvar);
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.value = value;
+ self.oldValue = value;
+ self.tooltip = _G["OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY"..(value+1)];
+
+ UIDropDownMenu_SetWidth(self, 90);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsDisplayPanelAggroWarningDisplay_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ SetCVar(self.cvar, value, self.event);
+ UIDropDownMenu_SetSelectedValue(self, value);
+ self.tooltip = _G["OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY"..(value+1)];
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsDisplayPanelAggroWarningDisplay_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsDisplayPanelAggroWarningDisplay_OnClick(self)
+ InterfaceOptionsDisplayPanelAggroWarningDisplay:SetValue(self.value);
+end
+
+function InterfaceOptionsDisplayPanelAggroWarningDisplay_Initialize()
+ local selectedValue = UIDropDownMenu_GetSelectedValue(InterfaceOptionsDisplayPanelAggroWarningDisplay);
+ local info = UIDropDownMenu_CreateInfo();
+ info.tooltipOnButton = 1;
+
+ info.text = ALWAYS;
+ info.func = InterfaceOptionsDisplayPanelAggroWarningDisplay_OnClick;
+ info.value = "3";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = ALWAYS;
+ info.tooltipText = OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY4;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = AGGRO_WARNING_IN_INSTANCE;
+ info.func = InterfaceOptionsDisplayPanelAggroWarningDisplay_OnClick;
+ info.value = "1";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = AGGRO_WARNING_IN_INSTANCE;
+ info.tooltipText = OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY2;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = AGGRO_WARNING_IN_PARTY;
+ info.func = InterfaceOptionsDisplayPanelAggroWarningDisplay_OnClick;
+ info.value = "2";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = AGGRO_WARNING_IN_PARTY;
+ info.tooltipText = OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY3;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = NEVER;
+ info.func = InterfaceOptionsDisplayPanelAggroWarningDisplay_OnClick;
+ info.value = "0";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = NEVER;
+ info.tooltipText = OPTION_TOOLTIP_AGGRO_WARNING_DISPLAY1;
+ UIDropDownMenu_AddButton(info);
+end
+
+-- [[ Objectives Options Panel ]] --
+
+ObjectivesPanelOptions = {
+ questFadingDisable = { text = "SHOW_QUEST_FADING_TEXT" },
+ autoQuestWatch = { text = "AUTO_QUEST_WATCH_TEXT" },
+ autoQuestProgress = { text = "AUTO_QUEST_PROGRESS_TEXT" },
+ mapQuestDifficulty = { text = "MAP_QUEST_DIFFICULTY_TEXT" },
+ advancedWorldMap = { text = "ADVANCED_WORLD_MAP_TEXT" },
+ watchFrameWidth = { text = "WATCH_FRAME_WIDTH_TEXT" },
+}
+
+function InterfaceOptionsObjectivesPanel_OnLoad (self)
+ self.name = OBJECTIVES_LABEL;
+ self.options = ObjectivesPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+ self:SetScript("OnEvent", InterfaceOptionsObjectivesPanel_OnEvent);
+end
+
+function InterfaceOptionsObjectivesPanel_OnEvent (self, event, ...)
+ BlizzardOptionsPanel_OnEvent(self, event, ...);
+end
+
+-- [[ Social Options Panel ]] --
+
+SocialPanelOptions = {
+ profanityFilter = { text = "PROFANITY_FILTER" }, --The tooltip text is also directly set in InterfaceOptionsSocialPanelProfanityFilter_UpdateDisplay
+ chatBubbles = { text="CHAT_BUBBLES_TEXT" },
+ chatBubblesParty = { text="PARTY_CHAT_BUBBLES_TEXT" },
+ spamFilter = { text="DISABLE_SPAM_FILTER" },
+ removeChatDelay = { text="REMOVE_CHAT_DELAY_TEXT" },
+ guildMemberNotify = { text="GUILDMEMBER_ALERT" },
+ guildRecruitmentChannel = { text="AUTO_JOIN_GUILD_CHANNEL" },
+ showChatIcons = { text="SHOW_CHAT_ICONS" },
+ wholeChatWindowClickable = { text = "CHAT_WHOLE_WINDOW_CLICKABLE" },
+ chatMouseScroll = { text = "CHAT_MOUSE_WHEEL_SCROLL" },
+}
+
+function InterfaceOptionsSocialPanel_OnLoad (self)
+ if ( not BNFeaturesEnabled() ) then
+ local conversationCheckBox = InterfaceOptionsSocialPanelConversationMode;
+ local timestampCheckBox = InterfaceOptionsSocialPanelTimestamps;
+ conversationCheckBox:UnregisterEvent("VARIABLES_LOADED");
+ conversationCheckBox:Hide();
+ timestampCheckBox:ClearAllPoints();
+ timestampCheckBox:SetPoint("TOPLEFT", conversationCheckBox);
+ end
+ self.name = SOCIAL_LABEL;
+ self.options = SocialPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+ self.okay = function (self)
+ InterfaceOptionsPanel_Okay(self);
+ end
+
+ self:RegisterEvent("BN_DISCONNECTED");
+ self:RegisterEvent("BN_CONNECTED");
+ self:SetScript("OnEvent", InterfaceOptionsSocialPanel_OnEvent);
+end
+
+function InterfaceOptionsSocialPanel_OnEvent(self, event, ...)
+ BlizzardOptionsPanel_OnEvent(self, event, ...);
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ local control;
+
+ control = InterfaceOptionsSocialPanelChatHoverDelay;
+ control.setFunc(GetCVar(control.cvar));
+ InterfaceOptionsSocialPanelProfanityFilter_UpdateDisplay();
+ elseif ( event == "BN_DISCONNECTED" or event == "BN_CONNECTED" ) then
+ InterfaceOptionsSocialPanelProfanityFilter_UpdateDisplay();
+ end
+end
+
+--If the option won't be saved due to Battle.net being down, we want to warn the person.
+function InterfaceOptionsSocialPanelProfanityFilter_UpdateDisplay()
+ if ( not BNFeaturesEnabled() or BNConnected() ) then
+ InterfaceOptionsSocialPanelProfanityFilterText:SetFontObject(GameFontHighlight);
+ InterfaceOptionsSocialPanelProfanityFilter.tooltipText = OPTION_TOOLTIP_PROFANITY_FILTER;
+ else
+ InterfaceOptionsSocialPanelProfanityFilterText:SetFontObject(GameFontRed);
+ InterfaceOptionsSocialPanelProfanityFilter.tooltipText = OPTION_TOOLTIP_PROFANITY_FILTER_WITH_WARNING;
+ end
+end
+
+function InterfaceOptionsSocialPanelProfanityFilter_SyncWithBattlenet()
+ local button = InterfaceOptionsSocialPanelProfanityFilter;
+ if ( BNFeaturesEnabledAndConnected() ) then
+ local isEnabled = BNGetMatureLanguageFilter();
+ button:SetChecked(isEnabled);
+ SetCVar(button.cvar, isEnabled and "1" or "0");
+ InterfaceOptionsPanel_CheckButton_Update(button);
+ end
+end
+
+function InterfaceOptionsSocialPanelChatMouseScroll_SetScrolling(receiveMouseScroll)
+ if ( receiveMouseScroll == "1" ) then
+ for _, frameName in pairs(CHAT_FRAMES) do
+ local frame = _G[frameName];
+ frame:SetScript("OnMouseWheel", FloatingChatFrame_OnMouseScroll);
+ frame:EnableMouseWheel(true);
+ end
+ else
+ for _, frameName in pairs(CHAT_FRAMES) do
+ local frame = _G[frameName];
+ frame:SetScript("OnMouseWheel", nil);
+ frame:EnableMouseWheel(false);
+ end
+ end
+end
+
+function InterfaceOptionsSocialPanelChatStyle_OnEvent (self, event, ...)
+ if ( event == "VARIABLES_LOADED" ) then
+ self.cvar = "chatStyle";
+
+ local value = GetCVar(self.cvar);
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.value = value;
+ self.oldValue = value;
+ self.tooltip = _G["OPTION_CHAT_STYLE_"..strupper(value)];
+
+ UIDropDownMenu_SetWidth(self, 90);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsSocialPanelChatStyle_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+ InterfaceOptionsSocialPanelChatStyle_SetChatStyle(value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ InterfaceOptionsSocialPanelChatStyle_SetChatStyle(value);
+ self.tooltip = _G["OPTION_CHAT_STYLE_"..strupper(value)];
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsSocialPanelChatStyle_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsSocialPanelChatStyle_OnClick(self)
+ InterfaceOptionsSocialPanelChatStyle:SetValue(self.value);
+end
+
+function InterfaceOptionsSocialPanelChatStyle_Initialize()
+ local selectedValue = UIDropDownMenu_GetSelectedValue(InterfaceOptionsSocialPanelChatStyle);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = IM_STYLE;
+ info.func = InterfaceOptionsSocialPanelChatStyle_OnClick;
+ info.value = "im";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+
+ info.tooltipTitle = IM_STYLE;
+ info.tooltipText = OPTION_CHAT_STYLE_IM;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CLASSIC_STYLE;
+ info.func = InterfaceOptionsSocialPanelChatStyle_OnClick;
+ info.value = "classic";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CLASSIC_STYLE;
+ info.tooltipText = OPTION_CHAT_STYLE_CLASSIC;
+ UIDropDownMenu_AddButton(info);
+end
+
+function InterfaceOptionsSocialPanelChatStyle_SetChatStyle(chatStyle)
+ SetCVar("chatStyle", chatStyle, "chatStyle");
+
+ if ( chatStyle == "classic" ) then
+ DEFAULT_CHAT_FRAME.editBox:SetParent(UIParent);
+ InterfaceOptionsSocialPanelWholeChatWindowClickable:Hide();
+ elseif ( chatStyle == "im" ) then
+ DEFAULT_CHAT_FRAME.editBox:SetParent(DEFAULT_CHAT_FRAME);
+ InterfaceOptionsSocialPanelWholeChatWindowClickable:Show();
+ else
+ error("Unhandled chat style: "..tostring(chatStyle));
+ end
+
+ for _, frameName in pairs(CHAT_FRAMES) do
+ local frame = _G[frameName];
+ ChatEdit_DeactivateChat(frame.editBox);
+ end
+ ChatEdit_ActivateChat(FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK).editBox);
+ ChatEdit_DeactivateChat(FCFDock_GetSelectedWindow(GENERAL_CHAT_DOCK).editBox);
+
+ UIDropDownMenu_SetSelectedValue(InterfaceOptionsSocialPanelChatStyle,chatStyle);
+end
+
+function InterfaceOptionsSocialPanelConversationMode_OnEvent (self, event, ...)
+ if ( event == "VARIABLES_LOADED" ) then
+ self.cvar = "conversationMode";
+
+ local value = GetCVar(self.cvar);
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.value = value;
+ self.oldValue = value;
+ self.tooltip = _G["OPTION_CONVERSATION_MODE_"..strupper(value)];
+
+ UIDropDownMenu_SetWidth(self, 90);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsSocialPanelConversationMode_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ SetCVar(self.cvar, self.value);
+ self.tooltip = _G["OPTION_CONVERSATION_MODE_"..strupper(value)];
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsSocialPanelConversationMode_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsSocialPanelConversationMode_OnClick(self)
+ InterfaceOptionsSocialPanelConversationMode:SetValue(self.value);
+end
+
+function InterfaceOptionsSocialPanelConversationMode_Initialize()
+ local selectedValue = UIDropDownMenu_GetSelectedValue(InterfaceOptionsSocialPanelConversationMode);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = CONVERSATION_MODE_POPOUT;
+ info.func = InterfaceOptionsSocialPanelConversationMode_OnClick;
+ info.value = "popout";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+
+ info.tooltipTitle = CONVERSATION_MODE_POPOUT;
+ info.tooltipText = OPTION_CONVERSATION_MODE_POPOUT;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CONVERSATION_MODE_INLINE;
+ info.func = InterfaceOptionsSocialPanelConversationMode_OnClick;
+ info.value = "inline";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CONVERSATION_MODE_INLINE;
+ info.tooltipText = OPTION_CONVERSATION_MODE_INLINE;
+ UIDropDownMenu_AddButton(info);
+end
+
+function InterfaceOptionsSocialPanelTimestamps_OnEvent (self, event, ...)
+ if ( event == "VARIABLES_LOADED" ) then
+ self.cvar = "showTimestamps";
+
+ local value = GetCVar(self.cvar);
+ if ( value == "none" ) then
+ CHAT_TIMESTAMP_FORMAT = nil;
+ else
+ CHAT_TIMESTAMP_FORMAT = value;
+ end
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.value = value;
+ self.oldValue = value;
+ self.tooltip = OPTION_TOOLTIP_TIMESTAMPS;
+
+ UIDropDownMenu_SetWidth(self, 110);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsSocialPanelTimestamps_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ SetCVar(self.cvar, self.value);
+ if ( value == "none" ) then
+ CHAT_TIMESTAMP_FORMAT = nil;
+ else
+ CHAT_TIMESTAMP_FORMAT = value;
+ end
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsSocialPanelTimestamps_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsSocialPanelTimestamps_Initialize()
+ local selectedValue = UIDropDownMenu_GetSelectedValue(InterfaceOptionsSocialPanelTimestamps);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.func = InterfaceOptionsSocialPanelTimestamps_OnClick;
+ info.value = "none";
+ info.text = TIMESTAMP_FORMAT_NONE;
+ info.checked = info.value == selectedValue;
+ UIDropDownMenu_AddButton(info, UIDROPDOWNMENU_MENU_LEVEL);
+
+ InterfaceOptionsSocialPanelTimestamps_AddTimestampFormat(TIMESTAMP_FORMAT_HHMM, info, selectedValue);
+ InterfaceOptionsSocialPanelTimestamps_AddTimestampFormat(TIMESTAMP_FORMAT_HHMMSS, info, selectedValue);
+ InterfaceOptionsSocialPanelTimestamps_AddTimestampFormat(TIMESTAMP_FORMAT_HHMM_AMPM, info, selectedValue);
+ InterfaceOptionsSocialPanelTimestamps_AddTimestampFormat(TIMESTAMP_FORMAT_HHMMSS_AMPM, info, selectedValue);
+ InterfaceOptionsSocialPanelTimestamps_AddTimestampFormat(TIMESTAMP_FORMAT_HHMM_24HR, info, selectedValue);
+ InterfaceOptionsSocialPanelTimestamps_AddTimestampFormat(TIMESTAMP_FORMAT_HHMMSS_24HR, info, selectedValue);
+end
+
+local exampleTime = {
+ year = 2010,
+ month = 12,
+ day = 15,
+ hour = 15,
+ min = 27,
+ sec = 32,
+}
+
+function InterfaceOptionsSocialPanelTimestamps_AddTimestampFormat(timestampFormat, infoTable, selectedValue)
+ assert(infoTable);
+ infoTable.func = InterfaceOptionsSocialPanelTimestamps_OnClick;
+ infoTable.value = timestampFormat;
+ infoTable.text = BetterDate(timestampFormat, time(exampleTime));
+ infoTable.checked = (selectedValue == timestampFormat);
+ UIDropDownMenu_AddButton(infoTable, UIDROPDOWNMENU_MENU_LEVEL);
+end
+
+function InterfaceOptionsSocialPanelTimestamps_OnClick(self)
+ InterfaceOptionsSocialPanelTimestamps:SetValue(self.value);
+end
+
+-- [[ ActionBars Options Panel ]] --
+
+ActionBarsPanelOptions = {
+ bottomLeftActionBar = { text = "SHOW_MULTIBAR1_TEXT", default = "0" },
+ bottomRightActionBar = { text = "SHOW_MULTIBAR2_TEXT", default = "0" },
+ rightActionBar = { text = "SHOW_MULTIBAR3_TEXT", default = "0" },
+ rightTwoActionBar = { text = "SHOW_MULTIBAR4_TEXT", default = "0" },
+ lockActionBars = { text = "LOCK_ACTIONBAR_TEXT" },
+ alwaysShowActionBars = { text = "ALWAYS_SHOW_MULTIBARS_TEXT" },
+ secureAbilityToggle = { text = "SECURE_ABILITY_TOGGLE" },
+}
+
+function InterfaceOptionsActionBarsPanel_OnLoad (self)
+ self.name = ACTIONBARS_LABEL;
+ self.options = ActionBarsPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+ self:SetScript("OnEvent", InterfaceOptionsActionBarsPanel_OnEvent);
+end
+
+function InterfaceOptionsActionBarsPanel_OnEvent (self, event, ...)
+ BlizzardOptionsPanel_OnEvent(self, event, ...);
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ local control;
+
+ control = InterfaceOptionsActionBarsPanelAlwaysShowActionBars;
+ control.setFunc(GetCVar(control.cvar));
+ end
+end
+
+function InterfaceOptions_UpdateMultiActionBars ()
+ if ( SHOW_MULTI_ACTIONBAR_1 == "0" ) then
+ SHOW_MULTI_ACTIONBAR_1 = nil;
+ end
+
+ if ( SHOW_MULTI_ACTIONBAR_2 == "0" ) then
+ SHOW_MULTI_ACTIONBAR_2 = nil;
+ end
+
+ if ( SHOW_MULTI_ACTIONBAR_3 == "0" ) then
+ SHOW_MULTI_ACTIONBAR_3 = nil;
+ end
+
+ if ( SHOW_MULTI_ACTIONBAR_4 == "0" ) then
+ SHOW_MULTI_ACTIONBAR_4 = nil;
+ end
+
+ if ( ALWAYS_SHOW_MULTIBARS == "0" ) then
+ ALWAYS_SHOW_MULTIBARS = nil;
+ end
+
+ if ( LOCK_ACTIONBAR == "0" ) then
+ LOCK_ACTIONBAR = nil;
+ end
+
+ SetActionBarToggles(SHOW_MULTI_ACTIONBAR_1, SHOW_MULTI_ACTIONBAR_2, SHOW_MULTI_ACTIONBAR_3, SHOW_MULTI_ACTIONBAR_4, ALWAYS_SHOW_MULTIBARS);
+ MultiActionBar_Update();
+ UIParent_ManageFramePositions();
+end
+
+-- [[ Names Options Panel ]] --
+
+NamePanelOptions = {
+ UnitNameOwn = { text = "UNIT_NAME_OWN" },
+ UnitNameNPC = { text = "UNIT_NAME_NPC" },
+ UnitNameNonCombatCreatureName = { text = "UNIT_NAME_NONCOMBAT_CREATURE" },
+ UnitNamePlayerGuild = { text = "UNIT_NAME_GUILD" },
+ UnitNamePlayerPVPTitle = { text = "UNIT_NAME_PLAYER_TITLE" },
+
+ UnitNameFriendlyPlayerName = { text = "UNIT_NAME_FRIENDLY" },
+ UnitNameFriendlyPetName = { text = "UNIT_NAME_FRIENDLY_PETS" },
+ UnitNameFriendlyGuardianName = { text = "UNIT_NAME_FRIENDLY_GUARDIANS" },
+ UnitNameFriendlyTotemName = { text = "UNIT_NAME_FRIENDLY_TOTEMS" },
+
+ UnitNameEnemyPlayerName = { text = "UNIT_NAME_ENEMY" },
+ UnitNameEnemyPetName = { text = "UNIT_NAME_ENEMY_PETS" },
+ UnitNameEnemyGuardianName = { text = "UNIT_NAME_ENEMY_GUARDIANS" },
+ UnitNameEnemyTotemName = { text = "UNIT_NAME_ENEMY_TOTEMS" },
+
+ nameplateShowFriends = { text = "UNIT_NAMEPLATES_SHOW_FRIENDS" },
+ nameplateShowFriendlyPets = { text = "UNIT_NAMEPLATES_SHOW_FRIENDLY_PETS" },
+ nameplateShowFriendlyGuardians = { text = "UNIT_NAMEPLATES_SHOW_FRIENDLY_GUARDIANS" },
+ nameplateShowFriendlyTotems = { text = "UNIT_NAMEPLATES_SHOW_FRIENDLY_TOTEMS" },
+ nameplateShowEnemies = { text = "UNIT_NAMEPLATES_SHOW_ENEMIES" },
+ nameplateShowEnemyPets = { text = "UNIT_NAMEPLATES_SHOW_ENEMY_PETS" },
+ nameplateShowEnemyGuardians = { text = "UNIT_NAMEPLATES_SHOW_ENEMY_GUARDIANS" },
+ nameplateShowEnemyTotems = { text = "UNIT_NAMEPLATES_SHOW_ENEMY_TOTEMS" },
+ nameplateAllowOverlap = { text = "UNIT_NAMEPLATES_ALLOW_OVERLAP" },
+}
+
+-- [[ Combat Text Options Panel ]] --
+
+FCTPanelOptions = {
+ enableCombatText = { text = "SHOW_COMBAT_TEXT_TEXT" },
+ fctCombatState = { text = "COMBAT_TEXT_SHOW_COMBAT_STATE_TEXT" },
+ fctDodgeParryMiss = { text = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS_TEXT" },
+ fctDamageReduction = { text = "COMBAT_TEXT_SHOW_RESISTANCES_TEXT" },
+ fctRepChanges = { text = "COMBAT_TEXT_SHOW_REPUTATION_TEXT" },
+ fctReactives = { text = "COMBAT_TEXT_SHOW_REACTIVES_TEXT" },
+ fctFriendlyHealers = { text = "COMBAT_TEXT_SHOW_FRIENDLY_NAMES_TEXT" },
+ fctComboPoints = { text = "COMBAT_TEXT_SHOW_COMBO_POINTS_TEXT" },
+ fctLowManaHealth = { text = "COMBAT_TEXT_SHOW_LOW_HEALTH_MANA_TEXT" },
+ fctEnergyGains = { text = "COMBAT_TEXT_SHOW_ENERGIZE_TEXT" },
+ fctPeriodicEnergyGains = { text = "COMBAT_TEXT_SHOW_PERIODIC_ENERGIZE_TEXT" },
+ fctHonorGains = { text = "COMBAT_TEXT_SHOW_HONOR_GAINED_TEXT" },
+ fctAuras = { text = "COMBAT_TEXT_SHOW_AURAS_TEXT" },
+ CombatDamage = { text = "SHOW_DAMAGE_TEXT" },
+ CombatLogPeriodicSpells = { text = "LOG_PERIODIC_EFFECTS" },
+ PetMeleeDamage = { text = "SHOW_PET_MELEE_DAMAGE" },
+ CombatHealing = { text = "SHOW_COMBAT_HEALING" },
+ fctSpellMechanics = { text = "SHOW_TARGET_EFFECTS" },
+ fctSpellMechanicsOther = { text = "SHOW_OTHER_TARGET_EFFECTS" },
+}
+
+function BlizzardOptionsPanel_UpdateCombatText ()
+ -- Fix for bug 106938. CombatText_UpdateDisplayedMessages only exists if the Blizzard_CombatText AddOn is loaded.
+ -- We need CombatText options to have their setFunc actually _exist_, so this function is used instead of CombatText_UpdateDisplayedMessages.
+ if ( CombatText_UpdateDisplayedMessages ) then
+ CombatText_UpdateDisplayedMessages();
+ end
+end
+
+function InterfaceOptionsCombatTextPanel_OnLoad (self)
+ self.name = COMBATTEXT_LABEL;
+ self.options = FCTPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+ self:SetScript("OnEvent", InterfaceOptionsCombatTextPanel_OnEvent);
+end
+
+function InterfaceOptionsCombatTextPanel_OnEvent (self, event, ...)
+ BlizzardOptionsPanel_OnEvent(self, event, ...);
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ local control;
+
+ -- run the enable FCT button's set func to refresh floating combat text and make sure the addon is loaded
+ control = InterfaceOptionsCombatTextPanelEnableFCT;
+ control.setFunc(GetCVar(control.cvar));
+
+ -- fix for bug 106687: self button can no longer be enabled if you're not a rogue or a druid
+ control = InterfaceOptionsCombatTextPanelComboPoints;
+ control.SetChecked =
+ function (self, checked)
+ local _, class = UnitClass("player");
+ if ( class ~= "ROGUE" and class ~= "DRUID" ) then
+ checked = false;
+ end
+ getmetatable(self).__index.SetChecked(self, checked);
+ end
+ control.Enable =
+ function (self)
+ local _, class = UnitClass("player");
+ if ( class ~= "ROGUE" and class ~= "DRUID" ) then
+ return;
+ end
+ getmetatable(self).__index.Enable(self);
+ local text = _G[self:GetName().."Text"];
+ local fontObject = text:GetFontObject();
+ _G[self:GetName().."Text"]:SetTextColor(fontObject:GetTextColor());
+ end
+ control.setFunc(GetCVar(control.cvar));
+ end
+end
+
+function InterfaceOptionsCombatTextPanelFCTDropDown_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.cvar = "combatTextFloatMode";
+
+ local value = GetCVar(self.cvar);
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.oldValue = value;
+ self.value = value;
+ self.tooltip = OPTION_TOOLTIP_COMBAT_TEXT_MODE;
+
+ UIDropDownMenu_SetWidth(self, 110);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCombatTextPanelFCTDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ COMBAT_TEXT_FLOAT_MODE = value;
+ if ( CombatText_UpdateDisplayedMessages ) then
+ -- If the CombatText AddOn has already been loaded, we need to reinit it to pick up the previous COMBAT_TEXT_FLOAT_MODE.
+ CombatText_UpdateDisplayedMessages();
+ end
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ SetCVar(self.cvar, value, self.event);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ COMBAT_TEXT_FLOAT_MODE = value;
+ if ( CombatText_UpdateDisplayedMessages ) then
+ CombatText_UpdateDisplayedMessages();
+ else
+ UIParentLoadAddOn("Blizzard_CombatText");
+ CombatText_UpdateDisplayedMessages();
+ end
+ end;
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCombatTextPanelFCTDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+ end
+end
+
+function InterfaceOptionsCombatTextPanelFCTDropDown_OnClick(self)
+ InterfaceOptionsCombatTextPanelFCTDropDown:SetValue(self.value);
+end
+
+function InterfaceOptionsCombatTextPanelFCTDropDown_Initialize(self)
+ local selectedValue = UIDropDownMenu_GetSelectedValue(self);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = COMBAT_TEXT_SCROLL_UP;
+ info.func = InterfaceOptionsCombatTextPanelFCTDropDown_OnClick;
+ info.value = "1";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = COMBAT_TEXT_SCROLL_UP;
+ info.tooltipText = OPTION_TOOLTIP_SCROLL_UP;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = COMBAT_TEXT_SCROLL_DOWN;
+ info.func = InterfaceOptionsCombatTextPanelFCTDropDown_OnClick;
+ info.value = "2";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = COMBAT_TEXT_SCROLL_DOWN;
+ info.tooltipText = OPTION_TOOLTIP_SCROLL_DOWN;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = COMBAT_TEXT_SCROLL_ARC;
+ info.func = InterfaceOptionsCombatTextPanelFCTDropDown_OnClick;
+ info.value = "3";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = COMBAT_TEXT_SCROLL_ARC;
+ info.tooltipText = OPTION_TOOLTIP_SCROLL_ARC;
+ UIDropDownMenu_AddButton(info);
+end
+
+-- [[ Status Text Options Panel ]] --
+
+StatusTextPanelOptions = {
+ xpBarText = { text = "XP_BAR_TEXT" },
+ playerStatusText = { text = "STATUS_TEXT_PLAYER" },
+ petStatusText = { text = "STATUS_TEXT_PET" },
+ partyStatusText = { text = "STATUS_TEXT_PARTY" },
+ targetStatusText = { text = "STATUS_TEXT_TARGET" },
+ statusTextPercentage = { text = "STATUS_TEXT_PERCENT" },
+}
+
+-- [[ UnitFrame Options Panel ]] --
+
+UnitFramePanelOptions = {
+ showPartyBackground = { text = "SHOW_PARTY_BACKGROUND_TEXT" },
+ hidePartyInRaid = { text = "HIDE_PARTY_INTERFACE_TEXT" },
+ showPartyPets = { text = "SHOW_PARTY_PETS_TEXT" },
+ showRaidRange = { text = "SHOW_RAID_RANGE_TEXT" },
+ showArenaEnemyFrames = { text = "SHOW_ARENA_ENEMY_FRAMES_TEXT" },
+ showArenaEnemyCastbar = { text = "SHOW_ARENA_ENEMY_CASTBAR_TEXT" },
+ showArenaEnemyPets = { text = "SHOW_ARENA_ENEMY_PETS_TEXT" },
+ fullSizeFocusFrame = { text = "FULL_SIZE_FOCUS_FRAME_TEXT" },
+}
+
+function BlizzardOptionsPanel_UpdateRaidPullouts ()
+ if ( type(NUM_RAID_PULLOUT_FRAMES) ~= "number" ) then
+ return;
+ end
+
+ local frame;
+ for i = 1, NUM_RAID_PULLOUT_FRAMES do
+ frame = _G["RaidPullout" .. i];
+ if ( frame and frame:IsShown() ) then
+ RaidPullout_Update(frame);
+ end
+ end
+end
+
+-- [[ Camera Options Panel ]] --
+
+CameraPanelOptions = {
+ cameraTerrainTilt = { text = "FOLLOW_TERRAIN" },
+ cameraBobbing = { text = "HEAD_BOB" },
+ cameraWaterCollision = { text = "WATER_COLLISION" },
+ cameraPivot = { text = "SMART_PIVOT" },
+ cameraYawSmoothSpeed = { text = "AUTO_FOLLOW_SPEED", minValue = 90, maxValue = 270, valueStep = 10 },
+ cameraDistanceMaxFactor = { text = "MAX_FOLLOW_DIST", minValue = 1, maxValue = 2, valueStep = 0.1 },
+}
+
+function InterfaceOptionsCameraPanel_OnLoad (self)
+ self.name = CAMERA_LABEL;
+ self.options = CameraPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self)
+
+ self:SetScript("OnEvent", InterfaceOptionsCameraPanel_OnEvent);
+end
+
+function InterfaceOptionsCameraPanel_OnEvent (self, event, ...)
+ BlizzardOptionsPanel_OnEvent(self, event, ...);
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ if ( GetCVar("cameraSmoothStyle") == "0" ) then
+ BlizzardOptionsPanel_Slider_Disable(InterfaceOptionsCameraPanelFollowSpeedSlider);
+ InterfaceOptionsCameraPanelFollowTerrain:Disable();
+ end
+ end
+end
+
+function InterfaceOptionsCameraPanelStyleDropDown_OnEvent(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.cvar = "cameraSmoothStyle";
+
+ local value = GetCVar(self.cvar);
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.value = value;
+ self.oldValue = value;
+ if ( value == "0" ) then
+ --For the purposes of tooltips and the dropdown list, value "0" in the CVar cameraSmoothStyle is actually "3".
+ self.tooltip = OPTION_TOOLTIP_CAMERA3;
+ else
+ self.tooltip = _G["OPTION_TOOLTIP_CAMERA"..value];
+ end
+
+ UIDropDownMenu_SetWidth(self, 180);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCameraPanelStyleDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ SetCVar(self.cvar, value, self.event);
+ UIDropDownMenu_SetSelectedValue(self, value);
+ if ( value == "0" ) then
+ --For the purposes of tooltips and the dropdown list, value "0" in the CVar cameraSmoothStyle is actually "3".
+ self.tooltip = OPTION_TOOLTIP_CAMERA3;
+ BlizzardOptionsPanel_Slider_Disable(InterfaceOptionsCameraPanelFollowSpeedSlider);
+ InterfaceOptionsCameraPanelFollowTerrain:Disable();
+ else
+ self.tooltip = _G["OPTION_TOOLTIP_CAMERA"..value];
+ BlizzardOptionsPanel_Slider_Enable(InterfaceOptionsCameraPanelFollowSpeedSlider);
+ InterfaceOptionsCameraPanelFollowTerrain:Enable();
+ end
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsCameraPanelStyleDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsCameraPanelStyleDropDown_OnClick(self)
+ InterfaceOptionsCameraPanelStyleDropDown:SetValue(self.value);
+end
+
+function InterfaceOptionsCameraPanelStyleDropDown_Initialize(self)
+ local selectedValue = UIDropDownMenu_GetSelectedValue(self);
+ local info = UIDropDownMenu_CreateInfo();
+ info.tooltipOnButton = 1;
+
+ info.text = CAMERA_SMART;
+ info.func = InterfaceOptionsCameraPanelStyleDropDown_OnClick;
+ info.value = "1";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CAMERA_SMART;
+ info.tooltipText = OPTION_TOOLTIP_CAMERA_SMART;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CAMERA_SMARTER;
+ info.func = InterfaceOptionsCameraPanelStyleDropDown_OnClick;
+ info.value = "4";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CAMERA_SMARTER;
+ info.tooltipText = OPTION_TOOLTIP_CAMERA_SMARTER;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CAMERA_ALWAYS;
+ info.func = InterfaceOptionsCameraPanelStyleDropDown_OnClick;
+ info.value = "2";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CAMERA_ALWAYS;
+ info.tooltipText = OPTION_TOOLTIP_CAMERA_ALWAYS;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CAMERA_NEVER;
+ info.func = InterfaceOptionsCameraPanelStyleDropDown_OnClick;
+ info.value = "0";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CAMERA_NEVER;
+ info.tooltipText = OPTION_TOOLTIP_CAMERA_NEVER;
+ UIDropDownMenu_AddButton(info);
+end
+
+-- [[ Buffs Options Panel ]] --
+
+BuffsPanelOptions = {
+ buffDurations = { text = "SHOW_BUFF_DURATION_TEXT" },
+ showDispelDebuffs = { text = "SHOW_DISPELLABLE_DEBUFFS_TEXT" },
+ showCastableBuffs = { text = "SHOW_CASTABLE_BUFFS_TEXT" },
+ consolidateBuffs = { text = "CONSOLIDATE_BUFFS_TEXT" },
+ showCastableDebuffs = { text = "SHOW_CASTABLE_DEBUFFS_TEXT" },
+}
+
+function InterfaceOptionsBuffsPanel_OnLoad (self)
+ self.name = BUFFOPTIONS_LABEL;
+ self.options = BuffsPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+ self:SetScript("OnEvent", InterfaceOptionsBuffsPanel_OnEvent);
+end
+
+function InterfaceOptionsBuffsPanel_OnEvent (self, event, ...)
+ BlizzardOptionsPanel_OnEvent(self, event, ...);
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ local control;
+ control = InterfaceOptionsBuffsPanelBuffDurations;
+ control.setFunc(GetCVar(control.cvar));
+ end
+end
+
+-- [[ Battle.net Options Panel ]] --
+
+BattlenetPanelOptions = {
+ showToastOnline = { text = "SHOW_TOAST_ONLINE_TEXT" },
+ showToastOffline = { text = "SHOW_TOAST_OFFLINE_TEXT" },
+ showToastBroadcast = { text = "SHOW_TOAST_BROADCAST_TEXT" },
+ showToastFriendRequest = { text = "SHOW_TOAST_FRIEND_REQUEST_TEXT" },
+ showToastConversation = { text = "SHOW_TOAST_CONVERSATION_TEXT" },
+ showToastWindow = { text = "SHOW_TOAST_WINDOW_TEXT" },
+ toastDuration = { text = "TOAST_DURATION_TEXT", minValue = 0, maxValue = 10, valueStep = 0.5 },
+}
+
+function InterfaceOptionsBattlenetPanel_OnLoad (self)
+ if ( BNFeaturesEnabled() ) then
+ self.name = BATTLENET_OPTIONS_LABEL;
+ self.options = BattlenetPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+ end
+end
+
+-- [[ Mouse Options Panel ]] --
+
+MousePanelOptions = {
+ mouseInvertPitch = { text = "INVERT_MOUSE" },
+ enableWoWMouse = { text = "WOW_MOUSE" },
+ autointeract = { text = "CLICK_TO_MOVE" },
+ mouseSpeed = { text = "MOUSE_SENSITIVITY", minValue = 0.5, maxValue = 1.5, valueStep = 0.05 },
+ cameraYawMoveSpeed = { text = "MOUSE_LOOK_SPEED", minValue = 90, maxValue = 270, valueStep = 10 },
+}
+
+function InterfaceOptionsMousePanelClickMoveStyleDropDown_OnEvent(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.cvar = "cameraSmoothTrackingStyle";
+
+ local value = GetCVar(self.cvar);
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.oldValue = value;
+ self.value = value;
+ if ( value == "0" ) then
+ --For the purposes of tooltips and dropdown lists, "0" in the CVar cameraSmoothTrackingStyle is "3".
+ self.tooltip = OPTION_TOOLTIP_CAMERA3;
+ else
+ self.tooltip = _G["OPTION_TOOLTIP_CAMERA"..value];
+ end
+
+ UIDropDownMenu_SetWidth(self, 180);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsMousePanelClickMoveStyleDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ self.SetValue =
+ function (self, value)
+ self.value = value;
+ SetCVar(self.cvar, value, self.event);
+ UIDropDownMenu_SetSelectedValue(self, value);
+ if ( value == "0" ) then
+ --For the purposes of tooltips and dropdown lists, "0" in the CVar cameraSmoothTrackingStyle is "3".
+ self.tooltip = OPTION_TOOLTIP_CAMERA3;
+ else
+ self.tooltip = _G["OPTION_TOOLTIP_CAMERA"..value];
+ end
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsMousePanelClickMoveStyleDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsMousePanelClickMoveStyleDropDown_OnClick(self)
+ InterfaceOptionsMousePanelClickMoveStyleDropDown:SetValue(self.value);
+end
+
+function InterfaceOptionsMousePanelClickMoveStyleDropDown_Initialize(self)
+ local selectedValue = UIDropDownMenu_GetSelectedValue(self);
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = CAMERA_SMART;
+ info.func = InterfaceOptionsMousePanelClickMoveStyleDropDown_OnClick;
+ info.value = "1";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CAMERA_SMART;
+ info.tooltipText = OPTION_TOOLTIP_CAMERA_SMART;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CAMERA_SMARTER;
+ info.func = InterfaceOptionsMousePanelClickMoveStyleDropDown_OnClick;
+ info.value = "4";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CAMERA_SMARTER;
+ info.tooltipText = OPTION_TOOLTIP_CAMERA_SMARTER;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CAMERA_ALWAYS;
+ info.func = InterfaceOptionsMousePanelClickMoveStyleDropDown_OnClick;
+ info.value = "2";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CAMERA_ALWAYS;
+ info.tooltipText = OPTION_TOOLTIP_CAMERA_ALWAYS;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = CAMERA_NEVER;
+ info.func = InterfaceOptionsMousePanelClickMoveStyleDropDown_OnClick;
+ info.value = "0";
+ if ( info.value == selectedValue ) then
+ info.checked = 1;
+ else
+ info.checked = nil;
+ end
+ info.tooltipTitle = CAMERA_NEVER;
+ info.tooltipText = OPTION_TOOLTIP_CAMERA_NEVER;
+ UIDropDownMenu_AddButton(info);
+end
+
+-- [[ Features Panel ]] --
+
+FeaturesPanelOptions = {
+ equipmentManager = { text = "USE_EQUIPMENT_MANAGER" },
+ previewTalents = { text = "PREVIEW_TALENT_CHANGES" },
+}
+
+-- [[ Help Options Panel ]] --
+
+HelpPanelOptions = {
+ showTutorials = { text = "SHOW_TUTORIALS" },
+ showGameTips = { text = "SHOW_TIPOFTHEDAY_TEXT" },
+ UberTooltips = { text = "USE_UBERTOOLTIPS" },
+ showNewbieTips = { text = "SHOW_NEWBIE_TIPS_TEXT" },
+ scriptErrors = { text = "SHOW_LUA_ERRORS" },
+}
+
+-- [[ Languages Options Panel ]] --
+
+LanguagesPanelOptions = {
+ useEnglishAudio = { text = "USE_ENGLISH_AUDIO" },
+}
+
+function InterfaceOptionsLanguagesPanel_OnLoad (panel)
+ -- Check and see if we have more than one locale. If we don't, then don't register this panel.
+ if ( #({GetExistingLocales()}) <= 1 ) then
+ return;
+ end
+
+ InterfaceOptionsPanel_OnLoad(panel);
+end
+
+function InterfaceOptionsLanguagesPanelLocaleDropDown_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ self.cvar = "locale";
+
+ local value = GetCVar(self.cvar);
+ self.defaultValue = GetCVarDefault(self.cvar);
+ self.oldValue = value;
+ self.value = value;
+ self.tooltip = OPTION_TOOLTIP_LOCALE;
+
+ UIDropDownMenu_SetWidth(self, 120);
+ UIDropDownMenu_Initialize(self, InterfaceOptionsLanguagesPanelLocaleDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, value);
+
+ self.SetValue =
+ function (self, value)
+ UIDropDownMenu_SetSelectedValue(self, value);
+ SetCVar("locale", value, self.event);
+ self.value = value;
+ if ( self.oldValue ~= value ) then
+ InterfaceOptionsFrame.gameRestart = true;
+ end
+ end
+ self.GetValue =
+ function (self)
+ return UIDropDownMenu_GetSelectedValue(self);
+ end
+ self.RefreshValue =
+ function (self)
+ UIDropDownMenu_Initialize(self, InterfaceOptionsLanguagesPanelLocaleDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, self.value);
+ end
+
+ self:UnregisterEvent(event);
+ end
+end
+
+function InterfaceOptionsLanguagesPanelLocaleDropDown_OnClick (self)
+ InterfaceOptionsLanguagesPanelLocaleDropDown:SetValue(self.value);
+end
+
+function InterfaceOptionsLanguagesPanelLocaleDropDown_Initialize (self)
+ local selectedValue = UIDropDownMenu_GetSelectedValue(self);
+ local info = UIDropDownMenu_CreateInfo();
+
+ InterfaceOptionsLanguagesPanelLocaleDropDown_InitializeHelper(info, selectedValue, GetExistingLocales());
+end
+
+function InterfaceOptionsLanguagesPanelLocaleDropDown_InitializeHelper (createInfo, selectedValue, ...)
+ for i = 1, select("#", ...) do
+ local value = select(i, ...);
+ if (value) then
+ createInfo.text = _G[strupper(value)];
+ createInfo.func = InterfaceOptionsLanguagesPanelLocaleDropDown_OnClick;
+ createInfo.value = value;
+ if ( createInfo.value == selectedValue ) then
+ createInfo.checked = 1;
+ else
+ createInfo.checked = nil;
+ end
+ UIDropDownMenu_AddButton(createInfo);
+ end
+ end
+end
diff --git a/reference/FrameXML/InterfaceOptionsPanels.xml b/reference/FrameXML/InterfaceOptionsPanels.xml
new file mode 100644
index 0000000..b25a4f5
--- /dev/null
+++ b/reference/FrameXML/InterfaceOptionsPanels.xml
@@ -0,0 +1,3801 @@
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ InterfaceOptionsPanel_CheckButton_OnClick(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.invert = true;
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "deselectOnClick";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "autoDismountFlying";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "autoClearAFK";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "blockTrades";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "lootUnderMouse";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "autoLootDefault";
+ self.setFunc = InterfaceOptionsControlsPanelAutoLootKeyDropDown_Update;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+
+ if ( not self.isDisabled ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+ self.name = CONTROLS_LABEL;
+ self.options = ControlsPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+ UIDropDownMenu_SetSelectedValue(InterfaceOptionsControlsPanelAutoLootKeyDropDown, GetModifiedClick("AUTOLOOTTOGGLE"));
+ UIDropDownMenu_EnableDropDown(InterfaceOptionsControlsPanelAutoLootKeyDropDown);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "assistAttack";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "autoRangedCombat";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "stopAutoAttackOnTargetChange";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "ShowClassColorInNameplate";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "autoSelfCast";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ if ( not self.isDisabled ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showTargetCastbar";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showVKeyCastbar";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showTargetOfTarget";
+ self.uvar = "SHOW_TARGET_OF_TARGET";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ self.cvar = "targetOfTargetMode";
+ self.uvar = "SHOW_TARGET_OF_TARGET_STATE";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatPanelTargetOfTarget, self);
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+
+ if ( not self.isDisabled ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ InterfaceOptionsCombatPanelTOTDropDown_OnEvent(self, event, ...);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ if ( not self.isDisabled ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+ self.name = COMBAT_LABEL;
+ self.options = CombatPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.text = _G[self:GetName().."Text"];
+ self.text:SetText(SHOW_CLOAK);
+ self.tooltipText = OPTION_TOOLTIP_SHOW_CLOAK;
+ self.defaultValue = "1";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+ self.GetValue = function (self) return ( (ShowingCloak() and "1") or "0" ); end
+ self.SetValue = function (self, value) self.value = value; self:SetChecked(value); ShowCloak(value); end
+ self:RegisterEvent("PLAYER_FLAGS_CHANGED");
+
+
+ local value = ((self:GetChecked() and "1") or "0")
+ if ( value == "1" ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ self:SetValue(value);
+
+
+ local arg1 = ...;
+ if ( arg1 == "player" ) then
+ self:SetChecked(ShowingCloak());
+ self.value = ((ShowingCloak() and "1") or "0");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.text = _G[self:GetName().."Text"];
+ self.text:SetText(SHOW_HELM);
+ self.tooltipText = OPTION_TOOLTIP_SHOW_HELM;
+ self.defaultValue = "1";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+ self.GetValue = function (self) return ( (ShowingHelm() and "1") or "0" ); end
+ self.SetValue = function (self, value) self.value = value; self:SetChecked(value); ShowHelm(value); end
+ self:RegisterEvent("PLAYER_FLAGS_CHANGED");
+
+
+ local value = ((self:GetChecked() and "1") or "0")
+ if ( value == "1" ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ self:SetValue(value);
+
+
+ local arg1 = ...;
+ if ( arg1 == "player" ) then
+ self:SetChecked(ShowingHelm());
+ self.value = ((ShowingHelm() and "1") or "0");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "rotateMinimap";
+ self.setFunc = function (value) Minimap_UpdateRotationSetting(); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "screenEdgeFlash";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showLootSpam";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "displayFreeBagSlots";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showClock";
+ self.setFunc = InterfaceOptionsDisplayPanelShowClock_SetFunc;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "threatShowNumeric";
+ self.setFunc = function (value) InterfaceOptionsDisplayPanelShowAggroPercentage_SetFunc(); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "threatPlaySounds";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "colorblindMode";
+ self.uvar = "ENABLE_COLORBLIND_MODE";
+ self.setFunc = function() WatchFrame_Update(); if ( IsAddOnLoaded("Blizzard_AchievementUI") ) then AchievementFrame_ForceUpdate(); end end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showItemLevel";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "movieSubtitle";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "questFadingDisable";
+ self.uvar = "QUEST_FADING_DISABLE";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "autoQuestWatch";
+ self.uvar = "AUTO_QUEST_WATCH";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "autoQuestProgress";
+ self.uvar = "AUTO_QUEST_PROGRESS";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "mapQuestDifficulty";
+ self.uvar = "MAP_QUEST_DIFFICULTY";
+ self.setFunc = function () WorldMapFrame_ResetQuestColors(); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "advancedWorldMap";
+ self.setFunc = function () WorldMapFrame_ToggleAdvanced(); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "watchFrameWidth";
+ self.uvar = "WATCH_FRAME_WIDTH";
+ self.setFunc = function () WatchFrame_SetWidth(WATCH_FRAME_WIDTH); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "profanityFilter";
+ self.setFunc = function(value) if (BNFeaturesEnabledAndConnected()) then BNSetMatureLanguageFilter(value == "1") end end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ InterfaceOptionsSocialPanelProfanityFilter_UpdateDisplay();
+ self:RegisterEvent("BN_MATURE_LANGUAGE_FILTER");
+ self:RegisterEvent("BN_CONNECTED");
+
+ InterfaceOptionsSocialPanelProfanityFilter_SyncWithBattlenet();
+
+
+ if ( event == "BN_MATURE_LANGUAGE_FILTER" or event == "BN_CONNECTED") then
+ InterfaceOptionsSocialPanelProfanityFilter_SyncWithBattlenet();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "chatBubbles";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "chatBubblesParty";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.invert = true;
+ self.cvar = "spamFilter";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "removeChatDelay";
+ self.uvar = "REMOVE_CHAT_DELAY";
+ self.setFunc = function (value) SetChatMouseOverDelay(value); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "guildMemberNotify";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "guildRecruitmentChannel";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "chatMouseScroll";
+ self.setFunc = function (value) InterfaceOptionsSocialPanelChatMouseScroll_SetScrolling(value); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ self:RegisterEvent("VARIABLES_LOADED");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "wholeChatWindowClickable";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ self:RegisterEvent("VARIABLES_LOADED");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ self:RegisterEvent("VARIABLES_LOADED");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.label = "bottomLeftActionBar";
+ self.uvar = "SHOW_MULTI_ACTIONBAR_1";
+ self.setFunc = InterfaceOptions_UpdateMultiActionBars;
+ self.GetValue = function () return self.value or ((select(1, GetActionBarToggles()) and "1") or "0"); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.label = "bottomRightActionBar";
+ self.uvar = "SHOW_MULTI_ACTIONBAR_2";
+ self.setFunc = InterfaceOptions_UpdateMultiActionBars;
+ self.GetValue = function () return self.value or ((select(2, GetActionBarToggles()) and "1") or "0"); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.label = "rightActionBar";
+ self.uvar = "SHOW_MULTI_ACTIONBAR_3";
+ self.setFunc = InterfaceOptions_UpdateMultiActionBars;
+ self.GetValue = function () return self.value or ((select(3, GetActionBarToggles()) and "1") or "0"); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.label = "rightTwoActionBar";
+ self.uvar = "SHOW_MULTI_ACTIONBAR_4";
+ self.setFunc = InterfaceOptions_UpdateMultiActionBars;
+ self.GetValue = function () return self.value or ((select(4, GetActionBarToggles()) and "1") or "0"); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsActionBarsPanelRight, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "lockActionBars";
+ self.uvar = "LOCK_ACTIONBAR";
+ self.setFunc = InterfaceOptions_UpdateMultiActionBars;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "alwaysShowActionBars";
+ self.uvar = "ALWAYS_SHOW_MULTIBARS";
+ self.setFunc = function (value) MultiActionBar_UpdateGridVisibility(); InterfaceOptions_UpdateMultiActionBars(); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "secureAbilityToggle";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameOwn";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameNPC";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameNonCombatCreatureName";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNamePlayerGuild";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNamePlayerPVPTitle";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameFriendlyPlayerName";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameFriendlyPetName";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameFriendlyGuardianName";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameFriendlyTotemName";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameEnemyPlayerName";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameEnemyPetName";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameEnemyGuardianName";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UnitNameEnemyTotemName";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "nameplateAllowOverlap";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "nameplateShowFriends";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "nameplateShowFriendlyPets";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsNamesPanelUnitNameplatesFriends, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "nameplateShowFriendlyGuardians";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsNamesPanelUnitNameplatesFriends, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "nameplateShowFriendlyTotems";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsNamesPanelUnitNameplatesFriends, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "nameplateShowEnemies";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "nameplateShowEnemyPets";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsNamesPanelUnitNameplatesEnemies, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "nameplateShowEnemyGuardians";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsNamesPanelUnitNameplatesEnemies, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "nameplateShowEnemyTotems";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent():GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsNamesPanelUnitNameplatesEnemies, self);
+
+
+
+
+
+
+
+
+ self.name = NAMES_LABEL;
+ self.options = NamePanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "CombatDamage";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "CombatLogPeriodicSpells";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelTargetDamage, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "PetMeleeDamage";
+ self.setFunc = function (value) SetCVar("PetSpellDamage", value); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelTargetDamage, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "CombatHealing";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctSpellMechanics";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctSpellMechanicsOther";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelTargetEffects, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "enableCombatText";
+ self.uvar = "SHOW_COMBAT_TEXT";
+ self.setFunc = function (value)
+ if ( value == "1" and not IsAddOnLoaded("Blizzard_CombatText") ) then
+ UIParentLoadAddOn("Blizzard_CombatText");
+ end
+ BlizzardOptionsPanel_UpdateCombatText();
+ end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+ if ( not self.isDisabled ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctDodgeParryMiss";
+ self.uvar = "COMBAT_TEXT_SHOW_DODGE_PARRY_MISS";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctDamageReduction";
+ self.uvar = "COMBAT_TEXT_SHOW_RESISTANCES";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctRepChanges";
+ self.uvar = "COMBAT_TEXT_SHOW_REPUTATION";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctReactives";
+ self.uvar = "COMBAT_TEXT_SHOW_REACTIVES";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctFriendlyHealers";
+ self.uvar = "COMBAT_TEXT_SHOW_FRIENDLY_NAMES";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctCombatState";
+ self.uvar = "COMBAT_TEXT_SHOW_COMBAT_STATE";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctComboPoints";
+ self.uvar = "COMBAT_TEXT_SHOW_COMBO_POINTS";
+ self.setFunc = function (value)
+ local _, class = UnitClass("player");
+ if ( class ~= "ROGUE" and class ~= "DRUID" ) then
+ self:SetChecked(false);
+ self:Disable();
+ end
+ BlizzardOptionsPanel_UpdateCombatText();
+ end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctLowManaHealth";
+ self.uvar = "COMBAT_TEXT_SHOW_LOW_HEALTH_MANA";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctEnergyGains";
+ self.uvar = "COMBAT_TEXT_SHOW_ENERGIZE";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctPeriodicEnergyGains";
+ self.uvar = "COMBAT_TEXT_SHOW_PERIODIC_ENERGIZE";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctHonorGains";
+ self.uvar = "COMBAT_TEXT_SHOW_HONOR_GAINED";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fctAuras";
+ self.uvar = "COMBAT_TEXT_SHOW_AURAS";
+ self.setFunc = BlizzardOptionsPanel_UpdateCombatText;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsCombatTextPanelEnableFCT, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "playerStatusText";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "petStatusText";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "partyStatusText";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "targetStatusText";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "statusTextPercentage";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "xpBarText";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+ self.name = STATUSTEXT_LABEL;
+ self.options = StatusTextPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showPartyBackground";
+ self.uvar = "SHOW_PARTY_BACKGROUND";
+ self.setFunc = function ()
+ UpdatePartyMemberBackground();
+ if ( UpdateArenaEnemyBackground ) then
+ UpdateArenaEnemyBackground();
+ end
+ end
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "hidePartyInRaid";
+ self.uvar = "HIDE_PARTY_INTERFACE";
+ self.setFunc = function (value) RaidOptionsFrame_UpdatePartyFrames(); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showPartyPets";
+ self.uvar = "SHOW_PARTY_PETS";
+ self.setFunc = function (value) for i=1, MAX_PARTY_MEMBERS do PartyMemberFrame_UpdatePet("PartyMemberFrame" .. i, i); end end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.setFunc = function (value)
+ if ( value == "1") then
+ RaidFrame.showRange = 1;
+ else
+ RaidFrame.showRange = nil;
+ end
+ end;
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showRaidRange";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showArenaEnemyFrames";
+ self.uvar = "SHOW_ARENA_ENEMY_FRAMES";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showArenaEnemyCastbar";
+ self.uvar = "SHOW_ARENA_ENEMY_CASTINGBAR";
+ self.setFunc = function (value)
+ if ( ArenaEnemyFrames ) then
+ local frame;
+ for i=1, MAX_ARENA_ENEMIES do
+ frame = _G["ArenaEnemyFrame" .. i .. "CastingBar"];
+ frame.showCastbar = (value == "1");
+ CastingBarFrame_UpdateIsShown(frame);
+ end
+ end
+ end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsUnitFramePanelArenaEnemyFrames, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showArenaEnemyPets";
+ self.uvar = "SHOW_ARENA_ENEMY_PETS";
+ self.setFunc = function (value)
+ if ( ArenaEnemyFrames ) then
+ for i=1, MAX_ARENA_ENEMIES do
+ ArenaEnemyFrame_UpdatePet(_G["ArenaEnemyFrame" .. i], i);
+ end
+ end
+ end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsUnitFramePanelArenaEnemyFrames, self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "fullSizeFocusFrame";
+ self.setFunc = function (value)
+ FocusFrame_SetSmallSize(value ~= "1", true);
+ end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+ self.name = UNITFRAME_LABEL;
+ self.options = UnitFramePanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "buffDurations";
+ self.uvar = "SHOW_BUFF_DURATIONS";
+ self.setFunc = function (value) BuffFrame_UpdatePositions(); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showDispelDebuffs";
+ self.setFunc = BlizzardOptionsPanel_UpdateRaidPullouts;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showCastableBuffs";
+ self.setFunc = BlizzardOptionsPanel_UpdateRaidPullouts;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "consolidateBuffs";
+ self.uvar = "CONSOLIDATE_BUFFS";
+ self.setFunc = function (value)
+ BuffFrame_Update();
+ end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showCastableDebuffs";
+ self.uvar = "SHOW_CASTABLE_DEBUFFS";
+ --self.setFunc = BlizzardOptionsPanel_UpdateRaidPullouts;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showToastOnline";
+ self.setFunc = function (value) BNet_UpdateToastEvent(self.cvar, value); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showToastOffline";
+ self.setFunc = function (value) BNet_UpdateToastEvent(self.cvar, value); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showToastBroadcast";
+ self.setFunc = function (value) BNet_UpdateToastEvent(self.cvar, value); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showToastFriendRequest";
+ self.setFunc = function (value) BNet_UpdateToastEvent(self.cvar, value); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showToastConversation";
+ self.setFunc = function (value) BNet_UpdateToastEvent(self.cvar, value); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showToastWindow";
+ self.setFunc = function(value) if ( value == "1" ) then BNet_EnableToasts(); else BNet_DisableToasts(); end; end
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "toastDuration";
+ self.SetDisplayValue = self.SetValue;
+ self.SetValue = function (self, value)
+ self:SetDisplayValue(value);
+ self.value = value;
+ SetCVar(self.cvar, value);
+ BNet_SetToastDuration(value);
+ end
+ _G[self:GetName().."Low"]:SetText(AUCTION_TIME_LEFT1);
+ _G[self:GetName().."High"]:SetText(AUCTION_TIME_LEFT3);
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsBattlenetPanelShowToastWindow, self);
+
+
+ self.value = value;
+ SetCVar(self.cvar, value);
+ BNet_SetToastDuration(value);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+
+ if ( not self.isDisabled ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "cameraYawSmoothSpeed";
+ self.SetDisplayValue = self.SetValue;
+ self.SetValue = function (self, value)
+ self:SetDisplayValue(value);
+ self.value = value;
+ SetCVar(self.cvar, value);
+ SetCVar("cameraPitchSmoothSpeed", value/4);
+ end
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ self.value = value;
+ SetCVar(self.cvar, value);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "cameraDistanceMaxFactor";
+ self.SetDisplayValue = self.SetValue;
+ self.SetValue = function (self, value)
+ self:SetDisplayValue(value);
+ self.value = value;
+ SetCVar(self.cvar, value);
+ end
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ self.value = value;
+ SetCVar(self.cvar, value);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "cameraTerrainTilt";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "cameraBobbing";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "cameraWaterCollision";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "cameraPivot";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+ InterfaceOptionsCameraPanel_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "mouseInvertPitch";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "autointeract";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "mouseSpeed";
+ self.SetDisplayValue = self.SetValue;
+ self.SetValue = function (self, value)
+ self:SetDisplayValue(value);
+ self.value = value;
+ SetCVar(self.cvar, value);
+ end
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ self.value = value;
+ SetCVar(self.cvar, value);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_SLIDER;
+ self.cvar = "cameraYawMoveSpeed";
+ self.SetDisplayValue = self.SetValue;
+ self.SetValue = function (self, value)
+ self:SetDisplayValue(value);
+ self.value = value;
+ SetCVar(self.cvar, value);
+ SetCVar("cameraPitchMoveSpeed", value/2);
+ end
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ self.value = value;
+ SetCVar(self.cvar, value);
+ SetCVar("cameraPitchMoveSpeed", value/2);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "enableWoWMouse";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ InterfaceOptionsPanel_CheckButton_OnClick(self);
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ DetectWowMouse();
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ BlizzardOptionsPanel_SetupDependentControl(InterfaceOptionsMousePanelClickToMove, self);
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+
+ if ( not self.isDisabled ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+ end
+
+
+ InterfaceOptionsMousePanelClickMoveStyleDropDown_OnEvent(self, event, ...);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+ self.name = MOUSE_LABEL;
+ self.options = MousePanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetFontObject(GameFontNormal);
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "equipmentManager";
+ self.setFunc = function(value) if ( value == "1" ) then GearManagerToggleButton:Show() else GearManagerToggleButton:Hide() end end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+ CanUseEquipmentSets();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetFontObject(GameFontNormal);
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "previewTalents";
+ self.setFunc = function (value) InterfaceOptionsDisplayPanelPreviewTalentChanges_SetFunc(); end;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+ self.name = FEATURES_LABEL;
+ self.options = FeaturesPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showTutorials";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showGameTips";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "UberTooltips";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "showNewbieTips";
+ self.uvar = "SHOW_NEWBIE_TIPS";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "scriptErrors";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( CanResetTutorials() ) then
+ self:Enable();
+ else
+ self:Disable();
+ end
+
+
+ PlaySound("gsTitleOptionOK");
+ ResetTutorials();
+ TutorialFrame_ClearQueue();
+ local tutorialsCheckButton = _G[self:GetParent():GetName() .. "ShowTutorials"];
+ if ( not tutorialsCheckButton:GetChecked() ) then
+ tutorialsCheckButton:Click()
+ end
+ TriggerTutorial(42);
+ TriggerTutorial(2);
+ TriggerTutorial(3);
+ TriggerTutorial(1);
+ self:Disable();
+
+
+
+
+
+
+
+
+ self.name = HELP_LABEL;
+ self.options = HelpPanelOptions;
+ InterfaceOptionsPanel_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_DROPDOWN;
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+
+ InterfaceOptionsLanguagesPanelLocaleDropDown_OnEvent(self, event, ...);
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.type = CONTROLTYPE_CHECKBOX;
+ self.cvar = "useEnglishAudio";
+ BlizzardOptionsPanel_RegisterControl(self, self:GetParent());
+
+
+
+
+
+
+ self.name = LANGUAGES_LABEL;
+ self.options = LanguagesPanelOptions;
+ InterfaceOptionsLanguagesPanel_OnLoad(self);
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/ItemButtonTemplate.lua b/reference/FrameXML/ItemButtonTemplate.lua
new file mode 100644
index 0000000..8df4b5c
--- /dev/null
+++ b/reference/FrameXML/ItemButtonTemplate.lua
@@ -0,0 +1,119 @@
+
+function SetItemButtonCount(button, count)
+ if ( not button ) then
+ return;
+ end
+
+ if ( not count ) then
+ count = 0;
+ end
+
+ button.count = count;
+ if ( count > 1 or (button.isBag and count > 0) ) then
+ if ( count > (button.maxDisplayCount or 9999) ) then
+ count = "*";
+ end
+ _G[button:GetName().."Count"]:SetText(count);
+ _G[button:GetName().."Count"]:Show();
+ else
+ _G[button:GetName().."Count"]:Hide();
+ end
+end
+
+function SetItemButtonStock(button, numInStock)
+ if ( not button ) then
+ return;
+ end
+
+ if ( not numInStock ) then
+ numInStock = "";
+ end
+
+ button.numInStock = numInStock;
+ if ( numInStock > 0 ) then
+ _G[button:GetName().."Stock"]:SetFormattedText(MERCHANT_STOCK, numInStock);
+ _G[button:GetName().."Stock"]:Show();
+ else
+ _G[button:GetName().."Stock"]:Hide();
+ end
+end
+
+function SetItemButtonTexture(button, texture)
+ if ( not button ) then
+ return;
+ end
+ if ( texture ) then
+ _G[button:GetName().."IconTexture"]:Show();
+ else
+ _G[button:GetName().."IconTexture"]:Hide();
+ end
+ _G[button:GetName().."IconTexture"]:SetTexture(texture);
+end
+
+function SetItemButtonTextureVertexColor(button, r, g, b)
+ if ( not button ) then
+ return;
+ end
+
+ _G[button:GetName().."IconTexture"]:SetVertexColor(r, g, b);
+end
+
+function SetItemButtonDesaturated(button, desaturated, r, g, b)
+ if ( not button ) then
+ return;
+ end
+ local icon = _G[button:GetName().."IconTexture"];
+ if ( not icon ) then
+ return;
+ end
+ local shaderSupported = icon:SetDesaturated(desaturated);
+
+ if ( not desaturated ) then
+ r = 1.0;
+ g = 1.0;
+ b = 1.0;
+ elseif ( not r or not shaderSupported ) then
+ r = 0.5;
+ g = 0.5;
+ b = 0.5;
+ end
+
+ icon:SetVertexColor(r, g, b);
+end
+
+function SetItemButtonNormalTextureVertexColor(button, r, g, b)
+ if ( not button ) then
+ return;
+ end
+
+ _G[button:GetName().."NormalTexture"]:SetVertexColor(r, g, b);
+end
+
+function SetItemButtonNameFrameVertexColor(button, r, g, b)
+ if ( not button ) then
+ return;
+ end
+
+ _G[button:GetName().."NameFrame"]:SetVertexColor(r, g, b);
+end
+
+function SetItemButtonSlotVertexColor(button, r, g, b)
+ if ( not button ) then
+ return;
+ end
+
+ _G[button:GetName().."SlotTexture"]:SetVertexColor(r, g, b);
+end
+
+function HandleModifiedItemClick(link)
+ if ( IsModifiedClick("CHATLINK") ) then
+ if ( ChatEdit_InsertLink(link) ) then
+ return true;
+ end
+ end
+ if ( IsModifiedClick("DRESSUP") ) then
+ DressUpItemLink(link);
+ return true;
+ end
+ return false;
+end
diff --git a/reference/FrameXML/ItemButtonTemplate.xml b/reference/FrameXML/ItemButtonTemplate.xml
new file mode 100644
index 0000000..7a51c54
--- /dev/null
+++ b/reference/FrameXML/ItemButtonTemplate.xml
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/ItemRef.lua b/reference/FrameXML/ItemRef.lua
new file mode 100644
index 0000000..fa01193
--- /dev/null
+++ b/reference/FrameXML/ItemRef.lua
@@ -0,0 +1,206 @@
+
+function SetItemRef(link, text, button, chatFrame)
+ if ( strsub(link, 1, 6) == "player" ) then
+ local namelink, isGMLink;
+ if ( strsub(link, 7, 8) == "GM" ) then
+ namelink = strsub(link, 10);
+ isGMLink = true;
+ else
+ namelink = strsub(link, 8);
+ end
+
+ local name, lineid, chatType, chatTarget = strsplit(":", namelink);
+ if ( name and (strlen(name) > 0) ) then
+ if ( IsModifiedClick("CHATLINK") ) then
+ local staticPopup;
+ staticPopup = StaticPopup_Visible("ADD_IGNORE");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_MUTE");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_FRIEND");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_GUILDMEMBER");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_TEAMMEMBER");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_RAIDMEMBER");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("CHANNEL_INVITE");
+ if ( staticPopup ) then
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ if ( ChatEdit_GetActiveWindow() ) then
+ ChatEdit_InsertLink(name);
+ elseif ( HelpFrameOpenTicketEditBox:IsVisible() ) then
+ HelpFrameOpenTicketEditBox:Insert(name);
+ else
+ SendWho(WHO_TAG_NAME..name);
+ end
+
+ elseif ( button == "RightButton" and (not isGMLink) ) then
+ FriendsFrame_ShowDropdown(name, 1, lineid, chatType, chatFrame);
+ else
+ ChatFrame_SendTell(name, chatFrame);
+ end
+ end
+ return;
+ elseif ( strsub(link, 1, 8) == "BNplayer" ) then
+ local namelink = strsub(link, 10);
+
+ local name, presenceID, lineid, chatType, chatTarget = strsplit(":", namelink);
+ if ( name and (strlen(name) > 0) ) then
+ if ( IsModifiedClick("CHATLINK") ) then
+ local staticPopup;
+ staticPopup = StaticPopup_Visible("ADD_IGNORE");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_MUTE");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_FRIEND");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_GUILDMEMBER");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_TEAMMEMBER");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("ADD_RAIDMEMBER");
+ if ( staticPopup ) then
+ -- If add ignore dialog is up then enter the name into the editbox
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ staticPopup = StaticPopup_Visible("CHANNEL_INVITE");
+ if ( staticPopup ) then
+ _G[staticPopup.."EditBox"]:SetText(name);
+ return;
+ end
+ if ( ChatEdit_GetActiveWindow() ) then
+ ChatEdit_InsertLink(name);
+ elseif ( HelpFrameOpenTicketEditBox:IsVisible() ) then
+ HelpFrameOpenTicketEditBox:Insert(name);
+ end
+
+ elseif ( button == "RightButton" ) then
+ if ( not BNIsSelf(presenceID) ) then
+ FriendsFrame_ShowBNDropdown(name, 1, nil, chatType, chatFrame, nil, BNet_GetPresenceID(name));
+ end
+ else
+ if ( not BNIsSelf(presenceID) ) then
+ ChatFrame_SendTell(name, chatFrame);
+ end
+ end
+ end
+ return;
+ elseif ( strsub(link, 1, 7) == "channel" ) then
+ if ( IsModifiedClick("CHATLINK") ) then
+ local chanLink = strsub(link, 9);
+ local chatType, chatTarget = strsplit(":", chanLink);
+ if ( strupper(chatType) == "BN_CONVERSATION" ) then
+ BNListConversation(chatTarget);
+ else
+ ToggleFriendsFrame(4);
+ end
+ elseif ( button == "LeftButton" ) then
+ local chanLink = strsub(link, 9);
+ local chatType, chatTarget = strsplit(":", chanLink);
+
+ if ( strupper(chatType) == "CHANNEL" ) then
+ if ( GetChannelName(tonumber(chatTarget))~=0 ) then
+ ChatFrame_OpenChat("/"..chatTarget, chatFrame);
+ end
+ elseif ( strupper(chatType) == "BN_CONVERSATION" ) then
+ if ( BNGetConversationInfo(chatTarget) ) then
+ ChatFrame_OpenChat("/"..(chatTarget + MAX_WOW_CHAT_CHANNELS), chatFrame);
+ end
+ else
+ ChatFrame_OpenChat("/"..chatType, chatFrame);
+ end
+ elseif ( button == "RightButton" ) then
+ local chanLink = strsub(link, 9);
+ local chatType, chatTarget = strsplit(":", chanLink);
+ if not ( (strupper(chatType) == "CHANNEL" and GetChannelName(tonumber(chatTarget)) == 0) or --Don't show the dropdown if this is a channel we are no longer in.
+ (strupper(chatType) == "BN_CONVERSATION" and not BNGetConversationInfo(chatTarget)) ) then --Or a conversation we are no longer in.
+ ChatChannelDropDown_Show(chatFrame, strupper(chatType), chatTarget, Chat_GetColoredChatName(strupper(chatType), chatTarget));
+ end
+ end
+ return;
+ elseif ( strsub(link, 1, 6) == "GMChat" ) then
+ GMChatStatusFrame_OnClick();
+ return;
+ end
+
+ if ( IsModifiedClick() ) then
+ local fixedLink = GetFixedLink(text);
+ HandleModifiedItemClick(fixedLink);
+ else
+ ShowUIPanel(ItemRefTooltip);
+ if ( not ItemRefTooltip:IsShown() ) then
+ ItemRefTooltip:SetOwner(UIParent, "ANCHOR_PRESERVE");
+ end
+ ItemRefTooltip:SetHyperlink(link);
+ end
+end
+
+function GetFixedLink(text)
+ local startLink = strfind(text, "|H");
+ if ( not strfind(text, "|c") ) then
+ if ( strsub(text, startLink + 2, startLink + 6) == "quest" ) then
+ --We'll always color it yellow. We really need to fix this for Cata. (It will appear the correct color in the chat log)
+ return (gsub(text, "(|H.+|h.+|h)", "|cffffff00%1|r", 1));
+ elseif ( strsub(text, startLink + 2, startLink + 12) == "achievement" ) then
+ return (gsub(text, "(|H.+|h.+|h)", "|cffffff00%1|r", 1));
+ elseif ( strsub(text, startLink + 2, startLink + 7) == "talent" ) then
+ return (gsub(text, "(|H.+|h.+|h)", "|cff4e96f7%1|r", 1));
+ elseif ( strsub(text, startLink + 2, startLink + 6) == "trade" ) then
+ return (gsub(text, "(|H.+|h.+|h)", "|cffffd000%1|r", 1));
+ elseif ( strsub(text, startLink + 2, startLink + 8) == "enchant" ) then
+ return (gsub(text, "(|H.+|h.+|h)", "|cffffd000%1|r", 1));
+ end
+ end
+
+ --Nothing to change.
+ return text;
+end
\ No newline at end of file
diff --git a/reference/FrameXML/ItemRef.xml b/reference/FrameXML/ItemRef.xml
new file mode 100644
index 0000000..64daed5
--- /dev/null
+++ b/reference/FrameXML/ItemRef.xml
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(ItemRefTooltip);
+
+
+
+
+
+
+
+
+
+ GameTooltip_OnLoad(self);
+ self:SetPadding(16);
+ self:RegisterForDrag("LeftButton");
+ self.shoppingTooltips = { ItemRefShoppingTooltip1, ItemRefShoppingTooltip2, ItemRefShoppingTooltip3 };
+ self.UpdateTooltip = function(self)
+ if ( not self.comparing and IsModifiedClick("COMPAREITEMS")) then
+ GameTooltip_ShowCompareItem(self);
+ self.comparing = true;
+ elseif ( self.comparing and not IsModifiedClick("COMPAREITEMS")) then
+ for _, frame in pairs(self.shoppingTooltips) do
+ frame:Hide();
+ end
+ self.comparing = false;
+ end
+ end
+
+
+ if ( IsModifiedClick("COMPAREITEMS") and self:IsMouseOver()) then
+ GameTooltip_ShowCompareItem(self, 1);
+ self.comparing = true;
+ end
+
+
+ self:StartMoving();
+
+
+ self:StopMovingOrSizing();
+ ValidateFramePosition(self);
+ if ( IsModifiedClick("COMPAREITEMS") ) then --We do this to choose where the comparison is shown
+ GameTooltip_ShowCompareItem(self, 1);
+ self.comparing = true;
+ end
+
+
+ self:SetScript("OnUpdate", self.UpdateTooltip);
+
+
+ for _, frame in pairs(self.shoppingTooltips) do
+ frame:Hide();
+ end
+ self.comparing = false;
+ self:SetScript("OnUpdate", nil);
+
+
+ GameTooltip_OnHide(self);
+ --While it is true that OnUpdate won't fire while the frame is hidden, we don't want to have to check-and-unregister when we show it
+ self:SetScript("OnUpdate", nil);
+
+
+
+
diff --git a/reference/FrameXML/ItemTextFrame.lua b/reference/FrameXML/ItemTextFrame.lua
new file mode 100644
index 0000000..311f512
--- /dev/null
+++ b/reference/FrameXML/ItemTextFrame.lua
@@ -0,0 +1,101 @@
+function ItemTextFrame_OnLoad(self)
+ self:RegisterEvent("ITEM_TEXT_BEGIN");
+ self:RegisterEvent("ITEM_TEXT_TRANSLATION");
+ self:RegisterEvent("ITEM_TEXT_READY");
+ self:RegisterEvent("ITEM_TEXT_CLOSED");
+ ItemTextScrollFrame.scrollBarHideable = 1;
+ ItemTextScrollFrameScrollBar:Hide();
+end
+
+function ItemTextFrame_OnEvent(self, event, ...)
+ if ( event == "ITEM_TEXT_BEGIN" ) then
+ ItemTextTitleText:SetText(ItemTextGetItem());
+ ItemTextScrollFrame:Hide();
+ ItemTextCurrentPage:Hide();
+ ItemTextStatusBar:Hide();
+ ItemTextPrevPageButton:Hide();
+ ItemTextNextPageButton:Hide();
+ local material = ItemTextGetMaterial();
+ if ( not material ) then
+ material = "Parchment";
+ end
+ local textColor = GetMaterialTextColors(material);
+ ItemTextPageText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ return;
+ elseif ( event == "ITEM_TEXT_TRANSLATION" ) then
+ local arg1 = ...;
+ ItemTextPrevPageButton:Hide();
+ ItemTextNextPageButton:Hide();
+ self.translationElapsed = 0;
+ ItemTextStatusBar:SetMinMaxValues(0, arg1);
+ ItemTextStatusBar:Show();
+ ShowUIPanel(self);
+ if ( not self:IsShown() ) then
+ CloseItemText();
+ end
+ return;
+ elseif ( event == "ITEM_TEXT_READY" ) then
+ local creator = ItemTextGetCreator();
+ if ( creator ) then
+ creator = "\n\n"..ITEM_TEXT_FROM.."\n"..creator.."\n\n\n";
+ ItemTextPageText:SetText("\n"..ItemTextGetText()..creator);
+ else
+ ItemTextPageText:SetText("\n"..ItemTextGetText().."\n\n");
+ end
+
+ ItemTextScrollFrameScrollBar:SetValue(0);
+ ItemTextScrollFrame:Show();
+ local page = ItemTextGetPage();
+ local next = ItemTextHasNextPage();
+ local material = ItemTextGetMaterial();
+ if ( not material ) then
+ material = "Parchment";
+ end
+ if ( material == "Parchment" ) then
+ ItemTextMaterialTopLeft:Hide();
+ ItemTextMaterialTopRight:Hide();
+ ItemTextMaterialBotLeft:Hide();
+ ItemTextMaterialBotRight:Hide();
+ else
+ ItemTextMaterialTopLeft:Show();
+ ItemTextMaterialTopRight:Show();
+ ItemTextMaterialBotLeft:Show();
+ ItemTextMaterialBotRight:Show();
+ ItemTextMaterialTopLeft:SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-TopLeft");
+ ItemTextMaterialTopRight:SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-TopRight");
+ ItemTextMaterialBotLeft:SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-BotLeft");
+ ItemTextMaterialBotRight:SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-BotRight");
+ end
+ if ( (page > 1) or next ) then
+ ItemTextCurrentPage:SetText(page);
+ ItemTextCurrentPage:Show();
+ if ( page > 1 ) then
+ ItemTextPrevPageButton:Show();
+ else
+ ItemTextPrevPageButton:Hide();
+ end
+ if ( next ) then
+ ItemTextNextPageButton:Show();
+ else
+ ItemTextNextPageButton:Hide();
+ end
+ end
+ ItemTextStatusBar:Hide();
+ ShowUIPanel(self);
+ if ( not self:IsShown() ) then
+ CloseItemText();
+ end
+ return;
+ elseif ( event == "ITEM_TEXT_CLOSED" ) then
+ HideUIPanel(self);
+ return;
+ end
+end
+
+function ItemTextFrame_OnUpdate(self, elapsed)
+ if ( ItemTextStatusBar:IsShown() ) then
+ elapsed = self.translationElapsed + elapsed;
+ ItemTextStatusBar:SetValue(elapsed);
+ self.translationElapsed = elapsed;
+ end
+end
diff --git a/reference/FrameXML/ItemTextFrame.xml b/reference/FrameXML/ItemTextFrame.xml
new file mode 100644
index 0000000..f3f7471
--- /dev/null
+++ b/reference/FrameXML/ItemTextFrame.xml
@@ -0,0 +1,344 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ ItemTextPrevPage();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ ItemTextNextPage();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOpen");
+
+
+ CloseItemText();
+ PlaySound("igMainMenuClose");
+
+
+
+
diff --git a/reference/FrameXML/KnowledgeBaseFrame.lua b/reference/FrameXML/KnowledgeBaseFrame.lua
new file mode 100644
index 0000000..c2df86f
--- /dev/null
+++ b/reference/FrameXML/KnowledgeBaseFrame.lua
@@ -0,0 +1,601 @@
+-- CONSTANTS
+KBASE_NUM_ARTICLES_PER_PAGE = 20;
+KBASE_NUM_FAKE_CATEGORIES = 1;
+KBASE_NUM_FAKE_SUBCATEGORIES = 1;
+KBASE_TOOLTIP_DELAY = .7;
+KBASE_SEARCH_BUTTON_DELAY = 1;
+
+-- Internal variables
+KBASE_CURRENT_PAGE = 1;
+KBASE_SEARCH_PERFORMED = 0;
+KBASE_SETUP_LOADED = 0;
+KBASE_ENABLE_SEARCH = 1;
+
+function KnowledgeBaseFrame_OnLoad(self)
+ self:RegisterEvent("UPDATE_GM_STATUS");
+ self:RegisterEvent("KNOWLEDGE_BASE_SETUP_LOAD_SUCCESS");
+ self:RegisterEvent("KNOWLEDGE_BASE_SETUP_LOAD_FAILURE");
+ self:RegisterEvent("KNOWLEDGE_BASE_QUERY_LOAD_SUCCESS");
+ self:RegisterEvent("KNOWLEDGE_BASE_QUERY_LOAD_FAILURE");
+ self:RegisterEvent("KNOWLEDGE_BASE_ARTICLE_LOAD_SUCCESS");
+ self:RegisterEvent("KNOWLEDGE_BASE_ARTICLE_LOAD_FAILURE");
+ self:RegisterEvent("KNOWLEDGE_BASE_SYSTEM_MOTD_UPDATE");
+ self:RegisterEvent("KNOWLEDGE_BASE_SERVER_MESSAGE");
+
+ -- ADDITIONAL LAYOUT
+ KnowledgeBaseFrame_DisableButtons();
+
+ KnowledgeBaseMotdText:SetWidth(KnowledgeBaseFrame:GetWidth() - KnowledgeBaseMotdLabel:GetWidth() - 80);
+ KnowledgeBaseMotdTextFrame:SetWidth(KnowledgeBaseMotdText:GetWidth())
+ KnowledgeBaseMotdTextFrame:SetHeight(KnowledgeBaseMotdText:GetHeight())
+
+ KnowledgeBaseServerMessageText:SetWidth(KnowledgeBaseFrame:GetWidth() - KnowledgeBaseServerMessageLabel:GetWidth() - 80);
+ KnowledgeBaseServerMessageTextFrame:SetWidth(KnowledgeBaseServerMessageText:GetWidth())
+ KnowledgeBaseServerMessageTextFrame:SetHeight(KnowledgeBaseServerMessageText:GetHeight())
+
+ KnowledgeBaseFrameEditBox:SetMaxBytes(128);
+ KnowledgeBaseFrameEditBox:SetText(KBASE_DEFAULT_SEARCH_TEXT);
+
+ KnowledgeBaseArticleListFrameCount:SetPoint("TOPRIGHT", "KnowledgeBaseArticleListFramePreviousButton", "TOPLEFT", -6, -7);
+
+ KnowledgeBaseArticleScrollChildFrameTitle:SetWidth(KnowledgeBaseArticleScrollChildFrame:GetWidth() - KnowledgeBaseArticleScrollChildFrameBackButton:GetWidth() - 10);
+ KnowledgeBaseArticleScrollChildFrameText:SetWidth(KnowledgeBaseArticleScrollChildFrame:GetWidth() - 10);
+ KnowledgeBaseArticleListFramePreviousButton:SetPoint("RIGHT", "KnowledgeBaseArticleListFrameNextButton", "LEFT", - (KnowledgeBaseArticleListFramePreviousButtonText:GetWidth() + KnowledgeBaseArticleListFrameNextButtonText:GetWidth() + 5), 0);
+end
+
+function KnowledgeBaseFrame_OnShow(self)
+ if ( KBASE_SETUP_LOADED == 0 ) then
+ KBSetup_BeginLoading(KBASE_NUM_ARTICLES_PER_PAGE, KBASE_CURRENT_PAGE);
+ end
+
+ GetGMStatus();
+ GetGMTicket();
+ KnowledgeBaseFrame_UpdateMotd();
+ KnowledgeBaseFrame_UpdateServerMessage();
+ KnowledgeBaseFrameEditBox:SetFocus();
+
+ HelpFrame.back = KnowledgeBaseFrameCancel;
+end
+
+function KnowledgeBaseFrame_OnEvent(self, event, ...)
+ if ( event == "KNOWLEDGE_BASE_SETUP_LOAD_SUCCESS" ) then
+ KBASE_SETUP_LOADED = 1;
+
+ UIDropDownMenu_Initialize(KnowledgeBaseFrameCategoryDropDown, KnowledgeBaseFrameCategoryDropDown_Initialize);
+ UIDropDownMenu_Initialize(KnowledgeBaseFrameSubCategoryDropDown, KnowledgeBaseFrameSubCategoryDropDown_Initialize);
+
+ local articleHeaderCount = KBSetup_GetArticleHeaderCount();
+ local totalArticleHeaderCount = KBSetup_GetTotalArticleCount();
+ KnowledgeBaseFrame_EnableButtons(articleHeaderCount, totalArticleHeaderCount);
+
+ if ( articleHeaderCount > 0 ) then
+ KnowledgeBaseArticleListFrame_PopulateArticleList(articleHeaderCount, totalArticleHeaderCount, KBSetup_GetArticleHeaderData);
+ KnowledgeBaseFrame_ShowSearchFrame();
+ else
+ KnowledgeBaseErrorFrame_SetErrorMessage(KBASE_ERROR_NO_RESULTS);
+ KnowledgeBaseFrame_ShowErrorFrame();
+ end
+ end
+
+ if ( event == "KNOWLEDGE_BASE_SETUP_LOAD_FAILURE" ) then
+ KnowledgeBaseErrorFrame_SetErrorMessage(KBASE_ERROR_LOAD_FAILURE);
+ KnowledgeBaseFrame_ShowErrorFrame();
+ KnowledgeBaseFrame_DisableButtons(nil);
+ -- enable top issues button, to give them a chance to get the ui loaded
+ KnowledgeBaseFrameTopIssuesButton:Enable();
+
+ KBASE_SETUP_LOADED = 0;
+ end
+
+ if ( event == "KNOWLEDGE_BASE_QUERY_LOAD_SUCCESS" ) then
+ KnowledgeBaseArticleListFrameTitle:SetText(KBASE_SEARCH_RESULTS);
+
+ local articleHeaderCount = KBQuery_GetArticleHeaderCount();
+ local totalArticleHeaderCount = KBQuery_GetTotalArticleCount();
+ KnowledgeBaseFrame_EnableButtons(KBQuery_GetArticleHeaderCount(), KBQuery_GetTotalArticleCount());
+
+ if ( articleHeaderCount > 0 ) then
+ KnowledgeBaseArticleListFrame_PopulateArticleList(articleHeaderCount, totalArticleHeaderCount, KBQuery_GetArticleHeaderData);
+ KnowledgeBaseFrame_ShowSearchFrame();
+ else
+ KnowledgeBaseErrorFrame_SetErrorMessage(KBASE_ERROR_NO_RESULTS);
+ KnowledgeBaseFrame_ShowErrorFrame();
+ end
+ end
+
+ if ( event == "KNOWLEDGE_BASE_QUERY_LOAD_FAILURE" ) then
+ KnowledgeBaseErrorFrame_SetErrorMessage(KBASE_ERROR_LOAD_FAILURE);
+ KnowledgeBaseFrame_ShowErrorFrame();
+ end
+
+ if ( event == "KNOWLEDGE_BASE_ARTICLE_LOAD_SUCCESS" ) then
+
+ local id, subject, subjectAlt, text, keywords, languageId, isHot = KBArticle_GetData();
+ KnowledgeBaseArticleScrollChildFrameTitle:SetText(subject);
+ KnowledgeBaseArticleScrollChildFrameText:SetText(text);
+ KnowledgeBaseArticleScrollChildFrameArticleId:SetFormattedText(KBASE_ARTICLE_ID, id);
+
+ KnowledgeBaseArticleScrollFrameScrollBar:SetValue(0);
+
+ KnowledgeBaseFrame_ShowArticleFrame();
+ end
+
+ if ( event == "KNOWLEDGE_BASE_ARTICLE_LOAD_FAILURE" ) then
+ KnowledgeBaseErrorFrame_SetErrorMessage(KBASE_ERROR_LOAD_FAILURE);
+ KnowledgeBaseFrame_ShowErrorFrame();
+ end
+
+ if ( event == "UPDATE_GM_STATUS" ) then
+ local status = ...;
+ if ( status == GMTICKET_QUEUE_STATUS_ENABLED ) then
+ GetGMTicket();
+ else
+ KnowledgeBaseFrameGMTalk:Disable();
+ KnowledgeBaseFrameReportIssue:Disable();
+ end
+ end
+
+ if ( event == "KNOWLEDGE_BASE_SYSTEM_MOTD_UPDATE" ) then
+ KnowledgeBaseFrame_UpdateMotd();
+ end
+
+ if ( event == "KNOWLEDGE_BASE_SERVER_MESSAGE" ) then
+ KnowledgeBaseFrame_UpdateServerMessage();
+ end
+end
+
+function KnowledgeBaseFrame_UpdateMotd()
+ local currentMotd = KBSystem_GetMOTD();
+ if ( currentMotd ) then
+ local singleLine = gsub(currentMotd, "\n", " ");
+ KnowledgeBaseMotdText:SetText(singleLine);
+ else
+ KnowledgeBaseMotdText:SetText(nil);
+ end
+ KnowledgeBaseUpdateTopPanelPositions();
+end
+
+function KnowledgeBaseFrame_UpdateServerMessage()
+ local currrentServerNotice = KBSystem_GetServerNotice();
+ if ( currrentServerNotice ) then
+ local closeBracketIndex = strfind(currrentServerNotice, "] ", 1, true);
+ if ( closeBracketIndex ) then
+ currrentServerNotice = strsub(currrentServerNotice, closeBracketIndex + 2);
+ end
+ KnowledgeBaseServerMessageText:SetText(currrentServerNotice);
+ else
+ KnowledgeBaseServerMessageText:SetText(nil);
+ end
+
+ KnowledgeBaseUpdateTopPanelPositions();
+end
+
+function KnowledgeBaseFrame_Search(resetCurrentPage)
+ if ( not KBSetup_IsLoaded() ) then
+ return;
+ end
+
+ KnowledgeBaseFrame_DisableButtons();
+
+ local categoryIndex = (UIDropDownMenu_GetSelectedID(KnowledgeBaseFrameCategoryDropDown) or 1) - KBASE_NUM_FAKE_CATEGORIES;
+ local subcategoryIndex = (UIDropDownMenu_GetSelectedID(KnowledgeBaseFrameSubCategoryDropDown) or 1) - KBASE_NUM_FAKE_SUBCATEGORIES;
+
+ local searchText = KnowledgeBaseFrameEditBox:GetText();
+ if ( searchText == KBASE_DEFAULT_SEARCH_TEXT ) then
+ searchText = "";
+ end
+
+ if ( resetCurrentPage == 1 ) then
+ KBASE_CURRENT_PAGE = 1;
+ end
+
+ KBQuery_BeginLoading(searchText,
+ categoryIndex,
+ subcategoryIndex,
+ KBASE_NUM_ARTICLES_PER_PAGE,
+ KBASE_CURRENT_PAGE);
+
+ KBASE_SEARCH_PERFORMED = 1;
+end
+
+function KnowledgeBaseFrame_LoadTopIssues()
+ KnowledgeBaseFrame_DisableButtons();
+ KBASE_SEARCH_PERFORMED = 0;
+ KBASE_CURRENT_PAGE = 1;
+ KBASE_SETUP_LOADED = 0;
+ KBSetup_BeginLoading(KBASE_NUM_ARTICLES_PER_PAGE, KBASE_CURRENT_PAGE);
+end
+
+function DisablePagingButton(button)
+ button:Disable();
+ local buttonText = _G[button:GetName() .. "Text"];
+ buttonText:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+end
+
+function EnablePagingButton(button)
+ button:Enable();
+ local buttonText = _G[button:GetName() .. "Text"];
+ buttonText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+end
+
+function KnowledgeBaseFrame_DisableButtons()
+ KBASE_ENABLE_SEARCH = 0;
+ KnowledgeBaseFrameTopIssuesButton:Disable();
+ KnowledgeBaseFrameSearchButton:Disable();
+
+ KnowledgeBaseFrameTopIssuesButton.enableDelay = KBASE_SEARCH_BUTTON_DELAY;
+ KnowledgeBaseFrameSearchButton.enableDelay = KBASE_SEARCH_BUTTON_DELAY;
+
+ UIDropDownMenu_DisableDropDown(KnowledgeBaseFrameCategoryDropDown);
+ UIDropDownMenu_DisableDropDown(KnowledgeBaseFrameSubCategoryDropDown);
+
+ DisablePagingButton(KnowledgeBaseArticleListFrameNextButton);
+ DisablePagingButton(KnowledgeBaseArticleListFramePreviousButton);
+end
+
+function KnowledgeBaseFrame_EnableButtons(articleCount, totalArticleCount)
+ KBASE_ENABLE_SEARCH = 1;
+
+ UIDropDownMenu_EnableDropDown(KnowledgeBaseFrameCategoryDropDown);
+ UpdateSubCategoryEnabledState();
+
+ if ( KBASE_CURRENT_PAGE == 1 ) then
+ DisablePagingButton(KnowledgeBaseArticleListFramePreviousButton);
+ else
+ EnablePagingButton(KnowledgeBaseArticleListFramePreviousButton);
+ end
+
+ if ( articleCount ) then
+ if (articleCount == KBASE_NUM_ARTICLES_PER_PAGE and (totalArticleCount > (KBASE_CURRENT_PAGE * KBASE_NUM_ARTICLES_PER_PAGE)) ) then
+ EnablePagingButton(KnowledgeBaseArticleListFrameNextButton);
+ else
+ DisablePagingButton(KnowledgeBaseArticleListFrameNextButton);
+ end
+ end
+end
+
+function KnowledgeBaseFrame_ShowSearchFrame()
+ KnowledgeBaseArticleListFrame:Show();
+ KnowledgeBaseArticleScrollFrame:Hide();
+ KnowledgeBaseErrorFrame:Hide();
+end
+
+function KnowledgeBaseFrame_ShowArticleFrame()
+ KnowledgeBaseArticleListFrame:Hide();
+ KnowledgeBaseArticleScrollFrame:Show();
+ KnowledgeBaseErrorFrame:Hide();
+end
+
+function KnowledgeBaseFrame_ShowErrorFrame()
+ KnowledgeBaseArticleListFrame:Hide();
+ KnowledgeBaseArticleScrollFrame:Hide();
+ KnowledgeBaseErrorFrame:Show();
+end
+
+function KnowledgeBaseFrameCategoryDropDown_OnLoad(self)
+ UIDropDownMenu_SetWidth(self, 120);
+ UIDropDownMenu_SetText(self, CATEGORY);
+end
+
+function KnowledgeBaseFrameCategoryDropDown_Initialize()
+ KnowledgeBaseFrameCategoryDropDown_AddInfo(0, ALL);
+ local numCategories = KBSetup_GetCategoryCount();
+ for i=1, numCategories do
+ local categoryId, categoryCaption = KBSetup_GetCategoryData(i);
+ KnowledgeBaseFrameCategoryDropDown_AddInfo(i, categoryCaption);
+ end
+end
+
+function KnowledgeBaseFrameCategoryDropDown_AddInfo(id, caption)
+ local info = UIDropDownMenu_CreateInfo();
+ info.value = id;
+ info.text = caption;
+ info.func = KnowledgeBaseFrameCategoryButton_OnClick;
+ local checked = nil;
+ local selectedId = UIDropDownMenu_GetSelectedID(KnowledgeBaseFrameCategoryDropDown);
+ if (selectedId and ((selectedId - KBASE_NUM_FAKE_CATEGORIES) == id)) then
+ checked = 1;
+ end
+ info.checked = checked;
+ UIDropDownMenu_AddButton(info);
+end
+
+function KnowledgeBaseFrameCategoryButton_OnClick(self)
+ local oldSelectedCategoryId = UIDropDownMenu_GetSelectedID(KnowledgeBaseFrameCategoryDropDown);
+ local selectedCategoryId = self:GetID();
+
+ if ( selectedCategoryId == oldSelectedCategoryId) then
+ return;
+ end
+
+ UIDropDownMenu_SetSelectedID(KnowledgeBaseFrameCategoryDropDown, selectedCategoryId);
+
+ UIDropDownMenu_SetSelectedID(KnowledgeBaseFrameSubCategoryDropDown, 0);
+ UIDropDownMenu_ClearAll(KnowledgeBaseFrameSubCategoryDropDown);
+ UIDropDownMenu_SetText(KnowledgeBaseFrameSubCategoryDropDown, SUBCATEGORY);
+
+ UpdateSubCategoryEnabledState();
+end
+
+function KnowledgeBaseFrameSubCategoryDropDown_OnLoad(self)
+ UIDropDownMenu_SetWidth(self, 120);
+ UIDropDownMenu_SetText(self, SUBCATEGORY);
+end
+
+function UpdateSubCategoryEnabledState()
+ local selectedCategoryId = UIDropDownMenu_GetSelectedID(KnowledgeBaseFrameCategoryDropDown);
+ if ( not selectedCategoryId or selectedCategoryId == 1 ) then
+ UIDropDownMenu_DisableDropDown(KnowledgeBaseFrameSubCategoryDropDown);
+ return;
+ end
+
+ local numSubCategories = KBSetup_GetSubCategoryCount(selectedCategoryId - KBASE_NUM_FAKE_CATEGORIES);
+ if ( numSubCategories == 0 ) then
+ UIDropDownMenu_DisableDropDown(KnowledgeBaseFrameSubCategoryDropDown);
+ else
+ UIDropDownMenu_EnableDropDown(KnowledgeBaseFrameSubCategoryDropDown);
+ end
+end
+
+function KnowledgeBaseFrameSubCategoryDropDown_Initialize()
+ local selectedCategoryId = UIDropDownMenu_GetSelectedID(KnowledgeBaseFrameCategoryDropDown);
+ if ( not selectedCategoryId or selectedCategoryId == 1 ) then
+ return;
+ end
+ selectedCategoryId = selectedCategoryId - KBASE_NUM_FAKE_CATEGORIES;
+
+ KnowledgeBaseFrameSubCategoryDropDown_AddInfo(0, ALL);
+ local numCategories = KBSetup_GetSubCategoryCount(selectedCategoryId);
+ for i=1, numCategories do
+ local categoryId, categoryCaption = KBSetup_GetSubCategoryData(selectedCategoryId, i);
+ KnowledgeBaseFrameSubCategoryDropDown_AddInfo(i, categoryCaption);
+ end
+
+ UpdateSubCategoryEnabledState();
+end
+
+function KnowledgeBaseFrameSubCategoryDropDown_AddInfo(id, caption)
+ local info = UIDropDownMenu_CreateInfo();
+ info.value = id;
+ info.text = caption;
+ info.func = KnowledgeBaseFrameSubCategoryButton_OnClick;
+ local checked = nil;
+ local selectedId = UIDropDownMenu_GetSelectedID(KnowledgeBaseFrameSubCategoryDropDown);
+ if (selectedId and ((selectedId - KBASE_NUM_FAKE_SUBCATEGORIES) == id)) then
+ checked = 1;
+ end
+ info.checked = checked;
+ UIDropDownMenu_AddButton(info);
+end
+
+function KnowledgeBaseFrameSubCategoryButton_OnClick(self)
+ UIDropDownMenu_SetSelectedID(KnowledgeBaseFrameSubCategoryDropDown, self:GetID());
+end
+
+function KnowledgeBaseArticleListFrame_HideArticleList()
+ for i=1, KBASE_NUM_ARTICLES_PER_PAGE do
+ local frame = _G["KnowledgeBaseArticleListItem" .. i];
+ frame:Hide();
+ end
+end
+
+function KnowledgeBaseArticleListFrame_PopulateArticleList(articleCount, totalArticleCount, dataFunc)
+ KnowledgeBaseArticleListFrame_HideArticleList();
+ for i=1, articleCount do
+ local articleId, articleHeader, isArticleHot, isArticleUpdated = dataFunc(i);
+ local frame = _G["KnowledgeBaseArticleListItem" .. i];
+ frame.number = i + ((KBASE_CURRENT_PAGE -1) * KBASE_NUM_ARTICLES_PER_PAGE);
+ frame.articleId = articleId;
+ frame.articleHeader = articleHeader;
+ frame.isArticleHot = isArticleHot;
+ frame.isArticleUpdated = isArticleUpdated;
+
+ KnowledgeBaseArticleListItem_Update(frame);
+ frame:Show();
+ end
+
+ KnowledgeBaseArticleListFrameCount:SetFormattedText(KBASE_ARTICLE_COUNT,
+ (((KBASE_CURRENT_PAGE -1) * KBASE_NUM_ARTICLES_PER_PAGE) + 1),
+ min(articleCount, (KBASE_CURRENT_PAGE * KBASE_NUM_ARTICLES_PER_PAGE)) + ((KBASE_CURRENT_PAGE -1) * KBASE_NUM_ARTICLES_PER_PAGE),
+ totalArticleCount);
+end
+
+function KnowledgeBaseArticleListItem_Update(frame)
+ local numberText = _G[frame:GetName() .. "Number"];
+ numberText:SetText(frame.number .. ".");
+
+ local updatedIcon = _G[frame:GetName() .. "UpdatedIcon"];
+
+ if ( frame.isArticleUpdated ) then
+ updatedIcon:Show();
+ else
+ updatedIcon:Hide();
+ end
+
+ local hotIcon = _G[frame:GetName() .. "HotIcon"];
+ if ( frame.isArticleHot ) then
+ hotIcon:Show();
+ else
+ hotIcon:Hide();
+ end
+
+ local titleText = _G[frame:GetName() .. "Title"];
+ titleText:SetText(frame.articleHeader);
+end
+
+function KnowledgeBaseUpdateTopPanelPositions()
+ if ( KnowledgeBaseMotdText:GetText() ) then
+ KnowledgeBaseMotdLabel:Show();
+ KnowledgeBaseMotdTextFrame:Show();
+ else
+ KnowledgeBaseMotdLabel:Hide();
+ KnowledgeBaseMotdTextFrame:Hide();
+ end
+
+ if ( KnowledgeBaseServerMessageText:GetText() ) then
+ KnowledgeBaseServerMessageLabel:Show();
+ KnowledgeBaseServerMessageTextFrame:Show();
+ else
+ KnowledgeBaseServerMessageLabel:Hide();
+ KnowledgeBaseServerMessageTextFrame:Hide();
+ end
+
+ if ( KnowledgeBaseMotdLabel:IsShown() ) then
+ KnowledgeBaseServerMessageLabel:SetPoint("TOPLEFT", KnowledgeBaseMotdLabel, "BOTTOMLEFT", 0, -5);
+ else
+ KnowledgeBaseServerMessageLabel:SetPoint("TOPLEFT", KnowledgeBaseMotdLabel, "TOPLEFT", 0, 0);
+ end
+end
+
+function KnowledgeBaseArticleListFrame_PreviousPage()
+
+ if ( KBASE_CURRENT_PAGE == 1 ) then
+ return;
+ end
+
+ KBASE_CURRENT_PAGE = KBASE_CURRENT_PAGE - 1;
+
+ KnowledgeBaseFrame_DisableButtons();
+
+ if ( KBASE_SEARCH_PERFORMED == 1 ) then
+ KnowledgeBaseFrame_Search(0);
+ else
+ KBASE_SETUP_LOADED = 0;
+ KBSetup_BeginLoading(KBASE_NUM_ARTICLES_PER_PAGE, KBASE_CURRENT_PAGE);
+ end
+end
+
+function KnowledgeBaseArticleListFrame_NextPage()
+
+ KBASE_CURRENT_PAGE = KBASE_CURRENT_PAGE + 1;
+
+ KnowledgeBaseFrame_DisableButtons();
+
+ if ( KBASE_SEARCH_PERFORMED == 1 ) then
+ KnowledgeBaseFrame_Search(0);
+ else
+ KBASE_SETUP_LOADED = 0;
+ KBSetup_BeginLoading(KBASE_NUM_ARTICLES_PER_PAGE, KBASE_CURRENT_PAGE);
+ end
+end
+
+function KnowledgeBaseErrorFrame_SetErrorMessage(message)
+ KnowledgeBaseErrorFrameText:SetText(message);
+end
+
+function KnowledgeBaseArticleListItem_OnClick(self)
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ local searchText = KnowledgeBaseFrameEditBox:GetText();
+ local searchType = 2;
+ if (searchText == KBASE_DEFAULT_SEARCH_TEXT or searchText == "") then
+ searchType = 1;
+ end
+ KBArticle_BeginLoading(self.articleId, searchType);
+end
+
+function KnowledgeBaseArticleListItem_OnEnter(self)
+ self.tooltipDelay = KBASE_TOOLTIP_DELAY;
+end
+
+function KnowledgeBaseArticleListItem_OnUpdate(self, ...)
+ if ( not self.tooltipDelay ) then
+ return;
+ end
+
+ local elapsed = ...;
+ self.tooltipDelay = self.tooltipDelay - elapsed;
+ if ( self.tooltipDelay > 0 ) then
+ return;
+ end
+
+ self.tooltipDelay = nil;
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT", 15);
+ GameTooltip:SetText(self.articleHeader, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, 1);
+
+ if ( self.isArticleHot ) then
+ GameTooltip:AddLine(KBASE_HOT_ISSUE);
+ GameTooltip:AddTexture("Interface\\HelpFrame\\HotIssueIcon");
+ end
+
+ if ( self.isArticleUpdated ) then
+ GameTooltip:AddLine(KBASE_RECENTLY_UPDATED);
+ GameTooltip:AddTexture("Interface\\GossipFrame\\AvailableQuestIcon");
+ end
+
+ GameTooltip:SetMinimumWidth(220, 1);
+ GameTooltip:Show();
+end
+
+function KnowledgeBaseArticleListItem_OnLeave(self)
+ self.tooltipDelay = nil;
+ GameTooltip:SetMinimumWidth(0, 0);
+ GameTooltip:Hide();
+end
+
+function KnowledgeBaseServerMessageTextFrame_OnEnter(self)
+ self.tooltipDelay = KBASE_TOOLTIP_DELAY;
+end
+
+function KnowledgeBaseServerMessageTextFrame_OnUpdate(self, elapsed)
+ if ( not self.tooltipDelay ) then
+ return;
+ end
+
+ self.tooltipDelay = self.tooltipDelay - elapsed;
+ if ( self.tooltipDelay > 0 ) then
+ return;
+ end
+
+ self.tooltipDelay = nil;
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT", 15);
+ GameTooltip:SetText(KnowledgeBaseServerMessageText:GetText(), HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, 1);
+ GameTooltip:SetMinimumWidth(220, 1);
+ GameTooltip:Show();
+end
+
+function KnowledgeBaseServerMessageTextFrame_OnLeave(self)
+ self.tooltipDelay = nil;
+ GameTooltip:SetMinimumWidth(0, 0);
+ GameTooltip:Hide();
+end
+
+function KnowledgeBaseMotdTextFrame_OnEnter(self)
+ self.tooltipDelay = KBASE_TOOLTIP_DELAY;
+end
+
+function KnowledgeBaseMotdTextFrame_OnUpdate(self, elapsed)
+ if ( not self.tooltipDelay ) then
+ return;
+ end
+
+ self.tooltipDelay = self.tooltipDelay - elapsed;
+ if ( self.tooltipDelay > 0 ) then
+ return;
+ end
+
+ self.tooltipDelay = nil;
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT", 15);
+ GameTooltip:SetText(KnowledgeBaseMotdText:GetText(), HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, 1);
+ GameTooltip:SetMinimumWidth(220, 1);
+ GameTooltip:Show();
+end
+
+function KnowledgeBaseMotdTextFrame_OnLeave(self)
+ self.tooltipDelay = nil;
+ GameTooltip:SetMinimumWidth(0, 0);
+ GameTooltip:Hide();
+end
+
+function SearchButton_OnUpdate(self, elapsed)
+ if ( KBASE_ENABLE_SEARCH == 0 or ( not self.enableDelay ) ) then
+ return;
+ end
+
+ self.enableDelay = self.enableDelay - elapsed;
+ if ( self.enableDelay > 0 ) then
+ return;
+ end
+
+ self.enableDelay = nil;
+ self:Enable();
+end
\ No newline at end of file
diff --git a/reference/FrameXML/KnowledgeBaseFrame.xml b/reference/FrameXML/KnowledgeBaseFrame.xml
new file mode 100644
index 0000000..582ac05
--- /dev/null
+++ b/reference/FrameXML/KnowledgeBaseFrame.xml
@@ -0,0 +1,742 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ KnowledgeBaseArticleListItem_OnClick(self, button, down);
+
+
+ KnowledgeBaseArticleListItem_OnEnter(self, motion);
+
+
+ KnowledgeBaseArticleListItem_OnLeave(self, motion);
+
+
+ KnowledgeBaseArticleListItem_OnUpdate(self, elapsed);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ KnowledgeBaseFrame_LoadTopIssues();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self:GetTextWidth()+40);
+ self:Disable()
+
+
+ GMChatFrame_Show();
+ HideUIPanel(HelpFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( KnowledgeBaseFrameSearchButton:IsEnabled() == 1 ) then
+ KnowledgeBaseFrame_Search(1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ KnowledgeBaseFrame_Search(1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ KnowledgeBaseArticleListFrame_NextPage();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ KnowledgeBaseArticleListFrame_PreviousPage();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ KnowledgeBaseFrame_ShowSearchFrame();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HelpFrame_ShowFrame("ReportIssue");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HelpFrame_ShowFrame("GMTalk");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("HELP_TICKET_ABANDON_CONFIRM");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HelpFrame_ShowFrame("OpenTicket");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HelpFrame_ShowFrame("Stuck");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HelpFrame_ShowFrame("Lag");
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/LFDFrame.lua b/reference/FrameXML/LFDFrame.lua
new file mode 100644
index 0000000..e31d8fd
--- /dev/null
+++ b/reference/FrameXML/LFDFrame.lua
@@ -0,0 +1,1213 @@
+EXPANSION_LEVEL = GetExpansionLevel(); --This doesn't change while logged in, so we just need to do it once.
+
+LFD_MAX_REWARDS = 2;
+
+NUM_LFD_CHOICE_BUTTONS = 15;
+TYPEID_DUNGEON = 1;
+TYPEID_HEROIC_DIFFICULTY = 5;
+TYPEID_RANDOM_DUNGEON = 6;
+
+NUM_LFD_MEMBERS = 5;
+
+LFD_STATISTIC_CHANGE_TIME = 10; --In secs.
+
+LFD_PROPOSAL_FAILED_CLOSE_TIME = 5;
+
+LFD_NUM_ROLES = 3;
+
+LFD_MAX_SHOWN_LEVEL_DIFF = 15;
+
+local NUM_STATISTIC_TYPES = 1;
+
+
+-------------------------------------
+-----------LFD Frame--------------
+-------------------------------------
+
+--General functions
+function LFDFrame_OnLoad(self)
+ self:RegisterEvent("LFG_PROPOSAL_UPDATE");
+ self:RegisterEvent("LFG_PROPOSAL_SHOW");
+ self:RegisterEvent("LFG_PROPOSAL_FAILED");
+ self:RegisterEvent("LFG_PROPOSAL_SUCCEEDED");
+ self:RegisterEvent("LFG_UPDATE");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("LFG_ROLE_CHECK_SHOW");
+ self:RegisterEvent("LFG_ROLE_CHECK_HIDE");
+ self:RegisterEvent("LFG_BOOT_PROPOSAL_UPDATE");
+ self:RegisterEvent("VOTE_KICK_REASON_NEEDED");
+ self:RegisterEvent("LFG_ROLE_UPDATE");
+ self:RegisterEvent("LFG_UPDATE_RANDOM_INFO");
+ self:RegisterEvent("LFG_OPEN_FROM_GOSSIP");
+ self:RegisterEvent("GOSSIP_CLOSED");
+end
+
+function LFDFrame_OnEvent(self, event, ...)
+ if ( event == "LFG_PROPOSAL_UPDATE" ) then
+ LFDDungeonReadyPopup_Update();
+ elseif ( event == "LFG_PROPOSAL_SHOW" ) then
+ LFDDungeonReadyPopup.closeIn = nil;
+ LFDDungeonReadyPopup:SetScript("OnUpdate", nil);
+ LFDDungeonReadyStatus_ResetReadyStates();
+ StaticPopupSpecial_Show(LFDDungeonReadyPopup);
+ LFDSearchStatus:Hide();
+ PlaySound("ReadyCheck");
+ elseif ( event == "LFG_PROPOSAL_FAILED" ) then
+ LFDDungeonReadyPopup_OnFail();
+ elseif ( event == "LFG_PROPOSAL_SUCCEEDED" ) then
+ LFGDebug("Proposal Hidden: Proposal succeeded.");
+ StaticPopupSpecial_Hide(LFDDungeonReadyPopup);
+ elseif ( event == "LFG_ROLE_CHECK_SHOW" ) then
+ StaticPopupSpecial_Show(LFDRoleCheckPopup);
+ LFDQueueFrameSpecificList_Update();
+ elseif ( event == "LFG_ROLE_CHECK_HIDE" ) then
+ StaticPopupSpecial_Hide(LFDRoleCheckPopup);
+ LFDQueueFrameSpecificList_Update();
+ elseif ( event == "LFG_BOOT_PROPOSAL_UPDATE" ) then
+ local voteInProgress, didVote, myVote, targetName, totalVotes, bootVotes, timeLeft, reason = GetLFGBootProposal();
+ if ( voteInProgress and not didVote and targetName ) then
+ StaticPopup_Show("VOTE_BOOT_PLAYER", targetName, reason);
+ else
+ StaticPopup_Hide("VOTE_BOOT_PLAYER");
+ end
+ elseif ( event == "VOTE_KICK_REASON_NEEDED" ) then
+ local targetName = ...;
+ StaticPopup_Show("VOTE_BOOT_REASON_REQUIRED", targetName, nil, targetName);
+ elseif ( event == "LFG_ROLE_UPDATE" ) then
+ LFG_UpdateRoleCheckboxes();
+ elseif ( event == "LFG_UPDATE_RANDOM_INFO" ) then
+ if ( not LFDQueueFrame.type or (type(LFDQueueFrame.type) == "number" and not IsLFGDungeonJoinable(LFDQueueFrame.type)) ) then
+ LFDQueueFrame.type = GetRandomDungeonBestChoice();
+ UIDropDownMenu_SetSelectedValue(LFDQueueFrameTypeDropDown, LFDQueueFrame.type);
+ end
+ --If we still don't have a value, we should go to specific.
+ if ( not LFDQueueFrame.type ) then
+ LFDQueueFrame.type = "specific";
+ UIDropDownMenu_SetSelectedValue(LFDQueueFrameTypeDropDown, LFDQueueFrame.type);
+ LFDQueueFrame_SetTypeSpecificDungeon();
+ elseif ( LFDQueueFrameRandom:IsShown() ) then
+ LFDQueueFrameRandom_UpdateFrame();
+ end
+ elseif ( event == "LFG_OPEN_FROM_GOSSIP" ) then
+ local dungeonID = ...;
+ LFDParentFrame.fromGossip = true;
+ ShowUIPanel(LFDParentFrame);
+ LFDQueueFrame_SetType(dungeonID);
+ elseif ( event == "GOSSIP_CLOSED" ) then
+ if ( LFDParentFrame.fromGossip ) then
+ HideUIPanel(LFDParentFrame);
+ end
+ end
+ LFDQueueFrame_UpdatePortrait();
+end
+
+function LFDFrame_OnShow(self)
+ LFDFrame_UpdateBackfill(true);
+end
+
+function LFDFrame_OnHide(self)
+ if ( self.fromGossip ) then
+ CloseGossip();
+ self.fromGossip = false;
+ end
+end
+
+function LFDQueueFrame_UpdatePortrait()
+ local mode, submode = GetLFGMode();
+ if ( mode == "queued" or mode == "rolecheck" ) then
+ EyeTemplate_StartAnimating(LFDParentFramePortrait);
+ else
+ EyeTemplate_StopAnimating(LFDParentFramePortrait);
+ end
+end
+
+--Backfill option
+function LFDFrame_UpdateBackfill(forceUpdate)
+ if ( CanPartyLFGBackfill() ) then
+ local name, lfgID, typeID = GetPartyLFGBackfillInfo();
+ LFDQueueFramePartyBackfillDescription:SetFormattedText(LFG_OFFER_CONTINUE, HIGHLIGHT_FONT_COLOR_CODE..name.."|r");
+ local mode, subMode = GetLFGMode();
+ if ( (forceUpdate or not LFDQueueFrame:IsVisible()) and mode ~= "queued" ) then
+ LFDQueueFramePartyBackfill:Show();
+ end
+ else
+ LFDQueueFramePartyBackfill:Hide();
+ end
+end
+
+--Role-related functions
+
+function LFDQueueFrame_SetRoles()
+ SetLFGRoles(LFDQueueFrameRoleButtonLeader.checkButton:GetChecked(),
+ LFDQueueFrameRoleButtonTank.checkButton:GetChecked(),
+ LFDQueueFrameRoleButtonHealer.checkButton:GetChecked(),
+ LFDQueueFrameRoleButtonDPS.checkButton:GetChecked());
+end
+
+function LFDFrameRoleCheckButton_OnClick(self)
+ LFDQueueFrame_SetRoles();
+end
+
+--Role-check popup functions
+function LFDRoleCheckPopupAccept_OnClick()
+ PlaySound("igCharacterInfoTab");
+ local oldLeader = GetLFGRoles();
+ SetLFGRoles(oldLeader,
+ LFDRoleCheckPopupRoleButtonTank.checkButton:GetChecked(),
+ LFDRoleCheckPopupRoleButtonHealer.checkButton:GetChecked(),
+ LFDRoleCheckPopupRoleButtonDPS.checkButton:GetChecked());
+ if ( CompleteLFGRoleCheck(true) ) then
+ StaticPopupSpecial_Hide(LFDRoleCheckPopup);
+ end
+end
+
+function LFDRoleCheckPopupDecline_OnClick()
+ PlaySound("igCharacterInfoTab");
+ StaticPopupSpecial_Hide(LFDRoleCheckPopup);
+ CompleteLFGRoleCheck(false);
+end
+
+function LFDRoleCheckPopup_Update()
+ LFGDungeonList_Setup();
+
+ LFG_UpdateRoleCheckboxes();
+
+ local inProgress, slots, members = GetLFGRoleUpdate();
+
+ local displayName;
+ if ( slots == 1 ) then
+ local dungeonType, dungeonID = GetLFGRoleUpdateSlot(1);
+ if ( dungeonType == TYPEID_RANDOM_DUNGEON ) then
+ displayName = A_RANDOM_DUNGEON;
+ elseif ( dungeonType == TYPEID_HEROIC_DIFFICULTY ) then
+ displayName = format(HEROIC_PREFIX, select(LFG_RETURN_VALUES.name, GetLFGDungeonInfo(dungeonID)));
+ else
+ displayName = select(LFG_RETURN_VALUES.name, GetLFGDungeonInfo(dungeonID));
+ end
+ else
+ displayName = MULTIPLE_DUNGEONS;
+ end
+ displayName = NORMAL_FONT_COLOR_CODE..displayName.."|r";
+
+ LFDRoleCheckPopupDescriptionText:SetFormattedText(QUEUED_FOR, displayName);
+
+ LFDRoleCheckPopupDescription:SetWidth(LFDRoleCheckPopupDescriptionText:GetWidth()+10);
+ LFDRoleCheckPopupDescription:SetHeight(LFDRoleCheckPopupDescriptionText:GetHeight());
+end
+
+function LFDRoleCheckPopupDescription_OnEnter(self)
+ local inProgress, slots, members = GetLFGRoleUpdate();
+
+ if ( slots <= 1 ) then
+ return;
+ end
+
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOM");
+ GameTooltip:AddLine(QUEUED_FOR_SHORT);
+
+ for i=1, slots do
+ local dungeonType, dungeonID = GetLFGRoleUpdateSlot(i);
+ local displayName;
+ if ( dungeonType == TYPEID_HEROIC_DIFFICULTY ) then
+ displayName = format(HEROIC_PREFIX, LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.name]);
+ else
+ displayName = LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.name];
+ end
+ GameTooltip:AddLine(" "..displayName);
+ end
+ GameTooltip:Show();
+end
+
+function LFDFrameRoleCheckButton_OnEnter(self)
+ if ( self.checkButton:IsEnabled() == 1 ) then
+ self.checkButton:LockHighlight();
+ end
+end
+
+--List functions
+function LFDQueueFrameSpecificListButton_SetDungeon(button, dungeonID, mode, submode)
+ local info = LFGGetDungeonInfoByID(dungeonID);
+ button.id = dungeonID;
+ if ( LFGIsIDHeader(dungeonID) ) then
+ local name = info[LFG_RETURN_VALUES.name];
+
+ button.instanceName:SetText(name);
+ button.instanceName:SetFontObject(QuestDifficulty_Header);
+ button.instanceName:SetPoint("RIGHT", button, "RIGHT", 0, 0);
+ button.level:Hide();
+
+ if ( info[LFG_RETURN_VALUES.typeID] == TYPEID_HEROIC_DIFFICULTY ) then
+ button.heroicIcon:Show();
+ button.instanceName:SetPoint("LEFT", button.heroicIcon, "RIGHT", 0, 1);
+ else
+ button.heroicIcon:Hide();
+ button.instanceName:SetPoint("LEFT", 40, 0);
+ end
+
+ button.expandOrCollapseButton:Show();
+ local isCollapsed = LFGCollapseList[dungeonID];
+ button.isCollapsed = isCollapsed;
+ if ( isCollapsed ) then
+ button.expandOrCollapseButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-UP");
+ else
+ button.expandOrCollapseButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP");
+ end
+ else
+ local name = info[LFG_RETURN_VALUES.name];
+ local minLevel, maxLevel = info[LFG_RETURN_VALUES.minLevel], info[LFG_RETURN_VALUES.maxLevel];
+ local minRecLevel, maxRecLevel = info[LFG_RETURN_VALUES.minRecLevel], info[LFG_RETURN_VALUES.maxRecLevel];
+ local recLevel = info[LFG_RETURN_VALUES.recLevel];
+
+ button.instanceName:SetText(name);
+ button.instanceName:SetPoint("RIGHT", button.level, "LEFT", -10, 0);
+
+ button.heroicIcon:Hide();
+ button.instanceName:SetPoint("LEFT", 40, 0);
+
+ if ( minLevel == maxLevel ) then
+ button.level:SetText(format(LFD_LEVEL_FORMAT_SINGLE, minLevel));
+ else
+ button.level:SetText(format(LFD_LEVEL_FORMAT_RANGE, minLevel, maxLevel));
+ end
+ button.level:Show();
+ local difficultyColor = GetQuestDifficultyColor(recLevel);
+ button.level:SetFontObject(difficultyColor.font);
+
+ if ( mode == "rolecheck" or mode == "queued" or mode == "listed" or not LFD_IsEmpowered()) then
+ button.instanceName:SetFontObject(QuestDifficulty_Header);
+ else
+ button.instanceName:SetFontObject(difficultyColor.font);
+ end
+
+
+ button.expandOrCollapseButton:Hide();
+
+ button.isCollapsed = false;
+ end
+
+ if ( LFGLockList[dungeonID] ) then
+ button.enableButton:Hide();
+ button.lockedIndicator:Show();
+ else
+ button.enableButton:Show();
+ button.lockedIndicator:Hide();
+ end
+
+ local enableState= LFGEnabledList;
+ if ( mode == "queued" or mode == "listed" ) then
+ enableState = LFGQueuedForList[dungeonID];
+ else
+ enableState = LFGEnabledList[dungeonID];
+ end
+
+ if ( enableState == 1 ) then --Some are checked, some aren't.
+ button.enableButton:SetCheckedTexture("Interface\\Buttons\\UI-MultiCheck-Up");
+ button.enableButton:SetDisabledCheckedTexture("Interface\\Buttons\\UI-MultiCheck-Disabled");
+ else
+ button.enableButton:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check");
+ button.enableButton:SetDisabledCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled");
+ end
+ button.enableButton:SetChecked(enableState and enableState ~= 0);
+
+ if ( mode == "rolecheck" or mode == "queued" or mode == "listed" or not LFD_IsEmpowered() ) then
+ button.enableButton:Disable();
+ else
+ button.enableButton:Enable();
+ end
+end
+
+function LFDQueueFrameSpecificList_Update()
+ if ( LFGDungeonList_Setup() ) then
+ return; --Setup will update the list.
+ end
+ FauxScrollFrame_Update(LFDQueueFrameSpecificListScrollFrame, LFDGetNumDungeons(), NUM_LFD_CHOICE_BUTTONS, 16);
+
+ local offset = FauxScrollFrame_GetOffset(LFDQueueFrameSpecificListScrollFrame);
+
+ local areButtonsBig = not LFDQueueFrameSpecificListScrollFrame:IsShown();
+
+ local mode, subMode = GetLFGMode();
+
+ for i = 1, NUM_LFD_CHOICE_BUTTONS do
+ local button = _G["LFDQueueFrameSpecificListButton"..i];
+ local dungeonID = LFDDungeonList[i+offset];
+ if ( dungeonID ) then
+ button:Show();
+ if ( areButtonsBig ) then
+ button:SetWidth(315);
+ else
+ button:SetWidth(295);
+ end
+ LFDQueueFrameSpecificListButton_SetDungeon(button, dungeonID, mode, subMode);
+ else
+ button:Hide();
+ end
+ end
+end
+
+function LFDList_SetHeaderCollapsed(headerID, isCollapsed)
+ SetLFGHeaderCollapsed(headerID, isCollapsed);
+ LFGCollapseList[headerID] = isCollapsed;
+ for _, dungeonID in pairs(LFDDungeonList) do
+ if ( LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.groupID] == headerID ) then
+ LFGCollapseList[dungeonID] = isCollapsed;
+ end
+ end
+ for _, dungeonID in pairs(LFDHiddenByCollapseList) do
+ if ( LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.groupID] == headerID ) then
+ LFGCollapseList[dungeonID] = isCollapsed;
+ end
+ end
+ LFDQueueFrame_Update();
+end
+
+function LFDQueueFrame_QueueForInstanceIfEnabled(queueID)
+ if ( not LFGIsIDHeader(queueID) and LFGEnabledList[queueID] and not LFGLockList[queueID] ) then
+ local info = LFGGetDungeonInfoByID(queueID);
+ SetLFGDungeon(queueID);
+ return true;
+ end
+ return false;
+end
+
+function LFDQueueFrame_Join()
+ if ( LFDQueueFrame.type == "specific" ) then --Random queue
+ ClearAllLFGDungeons();
+ for _, queueID in pairs(LFDDungeonList) do
+ LFDQueueFrame_QueueForInstanceIfEnabled(queueID);
+ end
+ for _, queueID in pairs(LFDHiddenByCollapseList) do
+ LFDQueueFrame_QueueForInstanceIfEnabled(queueID);
+ end
+ JoinLFG();
+ else
+ ClearAllLFGDungeons();
+ SetLFGDungeon(LFDQueueFrame.type);
+ JoinLFG();
+ end
+end
+
+function LFDQueueFrameDungeonChoiceEnableButton_OnClick(self, button)
+ local parent = self:GetParent();
+ local dungeonID = parent.id;
+ local isChecked = self:GetChecked();
+
+ PlaySound(isChecked and "igMainMenuOptionCheckBoxOff" or "igMainMenuOptionCheckBoxOff");
+ if ( LFGIsIDHeader(dungeonID) ) then
+ LFDList_SetHeaderEnabled(dungeonID, isChecked);
+ else
+ LFDList_SetDungeonEnabled(dungeonID, isChecked);
+ LFGListUpdateHeaderEnabledAndLockedStates(LFDDungeonList, LFGEnabledList, LFGLockList, LFDHiddenByCollapseList);
+ end
+ LFDQueueFrameSpecificList_Update();
+end
+
+function LFDList_SetDungeonEnabled(dungeonID, isEnabled)
+ SetLFGDungeonEnabled(dungeonID, isEnabled);
+ LFGEnabledList[dungeonID] = not not isEnabled; --Change to true/false.
+end
+
+function LFDList_SetHeaderEnabled(headerID, isEnabled)
+ for _, dungeonID in pairs(LFDDungeonList) do
+ if ( LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.groupID] == headerID ) then
+ LFDList_SetDungeonEnabled(dungeonID, isEnabled);
+ end
+ end
+ for _, dungeonID in pairs(LFDHiddenByCollapseList) do
+ if ( LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.groupID] == headerID ) then
+ LFDList_SetDungeonEnabled(dungeonID, isEnabled);
+ end
+ end
+ LFGEnabledList[headerID] = not not isEnabled; --Change to true/false.
+end
+
+function LFDQueueFrameDungeonListButton_OnEnter(self)
+ local dungeonID = self.id;
+ if ( self.lockedIndicator:IsShown() ) then
+ if ( LFGIsIDHeader(dungeonID) ) then
+ --GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ --GameTooltip:AddLine(YOU_MAY_NOT_QUEUE_FOR_CATEGORY, 1.0, 1.0, 1.0);
+ --GameTooltip:Show();
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_TOP");
+ GameTooltip:AddLine(YOU_MAY_NOT_QUEUE_FOR_DUNGEON, 1.0, 1.0, 1.0);
+ for i=1, GetLFDLockPlayerCount() do
+ local playerName, lockedReason = GetLFDLockInfo(dungeonID, i);
+ if ( lockedReason ~= 0 ) then
+ local who;
+ if ( i == 1 ) then
+ who = "SELF_";
+ else
+ who = "OTHER_";
+ end
+ GameTooltip:AddLine(format(_G["INSTANCE_UNAVAILABLE_"..who..(LFG_INSTANCE_INVALID_CODES[lockedReason] or "OTHER")], playerName));
+ end
+ end
+ GameTooltip:Show();
+ end
+ end
+end
+
+function LFDQueueFrameExpandOrCollapseButton_OnClick(self, button)
+ local parent = self:GetParent();
+ LFDList_SetHeaderCollapsed(parent.id, not parent.isCollapsed);
+end
+
+--Ready popup functions
+
+function LFDDungeonReadyPopup_OnFail()
+ PlaySound("LFG_Denied");
+ if ( LFDDungeonReadyDialog:IsShown() ) then
+ LFGDebug("Proposal Hidden: Proposal failed.");
+ StaticPopupSpecial_Hide(LFDDungeonReadyPopup);
+ elseif ( LFDDungeonReadyPopup:IsShown() ) then
+ LFDDungeonReadyPopup.closeIn = LFD_PROPOSAL_FAILED_CLOSE_TIME;
+ LFDDungeonReadyPopup:SetScript("OnUpdate", LFDDungeonReadyPopup_OnUpdate);
+ end
+end
+
+function LFDDungeonReadyPopup_OnUpdate(self, elapsed)
+ self.closeIn = self.closeIn - elapsed;
+ if ( self.closeIn < 0 ) then --We remove the OnUpdate and closeIn OnHide
+ LFGDebug("Proposal Hidden: Failure close timer expired.");
+ StaticPopupSpecial_Hide(LFDDungeonReadyPopup);
+ end
+end
+
+function LFDDungeonReadyPopup_Update()
+ local proposalExists, typeID, id, name, texture, role, hasResponded, totalEncounters, completedEncounters, numMembers, isLeader = GetLFGProposal();
+
+ if ( not proposalExists ) then
+ LFGDebug("Proposal Hidden: No proposal exists.");
+ StaticPopupSpecial_Hide(LFDDungeonReadyPopup);
+ return;
+ end
+
+ LFDDungeonReadyPopup.dungeonID = id;
+
+ if ( hasResponded ) then
+ LFDDungeonReadyStatus:Show();
+ LFDDungeonReadyDialog:Hide();
+
+ for i=1, numMembers do
+ LFDDungeonReadyStatus_UpdateIcon(_G["LFDDungeonReadyStatusPlayer"..i]);
+ end
+ for i=numMembers+1, NUM_LFD_MEMBERS do
+ _G["LFDDungeonReadyStatusPlayer"..i]:Hide();
+ end
+
+ if ( not LFDDungeonReadyPopup:IsShown() or StaticPopup_IsLastDisplayedFrame(LFDDungeonReadyPopup) ) then
+ LFDDungeonReadyPopup:SetHeight(LFDDungeonReadyStatus:GetHeight());
+ end
+ else
+ LFDDungeonReadyDialog:Show();
+ LFDDungeonReadyStatus:Hide();
+
+ local LFDDungeonReadyDialog = LFDDungeonReadyDialog; --Make a local copy.
+
+ if ( typeID == TYPEID_RANDOM_DUNGEON ) then
+ LFDDungeonReadyDialog.background:SetTexture("Interface\\LFGFrame\\UI-LFG-BACKGROUND-RANDOMDUNGEON");
+
+ LFDDungeonReadyDialog.label:SetText(RANDOM_DUNGEON_IS_READY);
+
+ LFDDungeonReadyDialog.instanceInfo:Hide();
+
+ if ( completedEncounters > 0 ) then
+ LFDDungeonReadyDialog.randomInProgress:Show();
+ LFDDungeonReadyPopup:SetHeight(223);
+ LFDDungeonReadyDialog.background:SetTexCoord(0, 1, 0, 1);
+ else
+ LFDDungeonReadyDialog.randomInProgress:Hide();
+ LFDDungeonReadyPopup:SetHeight(193);
+ LFDDungeonReadyDialog.background:SetTexCoord(0, 1, 0, 118/128);
+ end
+ else
+ LFDDungeonReadyDialog.randomInProgress:Hide();
+ LFDDungeonReadyPopup:SetHeight(223);
+ LFDDungeonReadyDialog.background:SetTexCoord(0, 1, 0, 1);
+ texture = "Interface\\LFGFrame\\UI-LFG-BACKGROUND-"..texture;
+ if ( not LFDDungeonReadyDialog.background:SetTexture(texture) ) then --We haven't added this texture yet. Default to the Deadmines.
+ LFDDungeonReadyDialog.background:SetTexture("Interface\\LFGFrame\\UI-LFG-BACKGROUND-Deadmines"); --DEBUG FIXME Default probably shouldn't be Deadmines
+ end
+
+ LFDDungeonReadyDialog.label:SetText(SPECIFIC_DUNGEON_IS_READY);
+ LFDDungeonReadyDialog_UpdateInstanceInfo(name, completedEncounters, totalEncounters);
+ LFDDungeonReadyDialog.instanceInfo:Show();
+ end
+
+
+ LFDDungeonReadyDialogRoleIconTexture:SetTexCoord(GetTexCoordsForRole(role));
+ LFDDungeonReadyDialogRoleLabel:SetText(_G[role]);
+ if ( isLeader ) then
+ LFDDungeonReadyDialogRoleIconLeaderIcon:Show();
+ else
+ LFDDungeonReadyDialogRoleIconLeaderIcon:Hide();
+ end
+
+ LFDDungeonReadyDialog_UpdateRewards(id);
+ end
+end
+
+function LFDDungeonReadyDialog_UpdateRewards(dungeonID)
+ local doneToday, moneyBase, moneyVar, experienceBase, experienceVar, numRewards = GetLFGDungeonRewards(dungeonID);
+
+ local numRandoms = 4 - GetNumPartyMembers();
+ local moneyAmount = moneyBase + moneyVar * numRandoms;
+ local experienceGained = experienceBase + experienceVar * numRandoms;
+
+ local rewardsOffset = 0;
+
+ if ( moneyAmount > 0 or experienceGained > 0 ) then --hasMiscReward ) then
+ LFDDungeonReadyDialogReward_SetMisc(LFDDungeonReadyDialogRewardsFrameReward1);
+ rewardsOffset = 1;
+ end
+
+ if ( moneyAmount == 0 and experienceGained == 0 and numRewards == 0 ) then
+ LFDDungeonReadyDialogRewardsFrameLabel:Hide();
+ else
+ LFDDungeonReadyDialogRewardsFrameLabel:Show();
+ end
+
+
+ for i = 1, numRewards do
+ local frameID = (i + rewardsOffset);
+ local frame = _G["LFDDungeonReadyDialogRewardsFrameReward"..frameID];
+ if ( not frame ) then
+ frame = CreateFrame("FRAME", "LFDDungeonReadyDialogRewardsFrameReward"..frameID, LFDDungeonReadyDialogRewardsFrame, LFDDungeonReadyRewardTemplate);
+ frame:SetID(frameID);
+ LFD_MAX_REWARDS = frameID;
+ end
+ LFDDungeonReadyDialogReward_SetReward(frame, dungeonID, i)
+ end
+
+ local usedButtons = numRewards + rewardsOffset;
+ --Hide the unused ones
+ for i = usedButtons + 1, LFD_MAX_REWARDS do
+ _G["LFDDungeonReadyDialogRewardsFrameReward"..i]:Hide();
+ end
+
+ if ( usedButtons > 0 ) then
+ --Set up positions
+ local positionPerIcon = 1/(2 * usedButtons) * LFDDungeonReadyDialogRewardsFrame:GetWidth();
+ local iconOffset = 2 * positionPerIcon - LFDDungeonReadyDialogRewardsFrameReward1:GetWidth();
+ LFDDungeonReadyDialogRewardsFrameReward1:SetPoint("CENTER", LFDDungeonReadyDialogRewardsFrame, "LEFT", positionPerIcon, 5);
+ for i = 2, usedButtons do
+ _G["LFDDungeonReadyDialogRewardsFrameReward"..i]:SetPoint("LEFT", "LFDDungeonReadyDialogRewardsFrameReward"..(i - 1), "RIGHT", iconOffset, 0);
+ end
+ end
+end
+
+function LFDDungeonReadyDialogReward_SetMisc(button)
+ SetPortraitToTexture(button.texture, "Interface\\Icons\\inv_misc_coin_02");
+ button.rewardID = 0;
+ button:Show();
+end
+
+function LFDDungeonReadyDialogReward_SetReward(button, dungeonID, rewardIndex)
+ local name, texturePath, quantity = GetLFGDungeonRewardInfo(dungeonID, rewardIndex);
+ if ( texturePath ) then --Otherwise, we may be waiting on the item data to come from the server.
+ SetPortraitToTexture(button.texture, texturePath);
+ end
+ button.rewardID = rewardIndex;
+ button:Show();
+end
+
+function LFDDungeonReadyDialogReward_OnEnter(self, dungeonID)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self.rewardID == 0 ) then
+ GameTooltip:AddLine(REWARD_ITEMS_ONLY);
+ local doneToday, moneyBase, moneyVar, experienceBase, experienceVar, numRewards = GetLFGDungeonRewards(LFDDungeonReadyPopup.dungeonID);
+ local numRandoms = 4 - GetNumPartyMembers();
+ local moneyAmount = moneyBase + moneyVar * numRandoms;
+ local experienceGained = experienceBase + experienceVar * numRandoms;
+
+ if ( experienceGained > 0 ) then
+ GameTooltip:AddLine(string.format(GAIN_EXPERIENCE, experienceGained));
+ end
+ if ( moneyAmount > 0 ) then
+ SetTooltipMoney(GameTooltip, moneyAmount, nil);
+ end
+ else
+ GameTooltip:SetLFGDungeonReward(LFDDungeonReadyPopup.dungeonID, self.rewardID);
+ end
+ GameTooltip:Show();
+end
+
+function LFDDungeonReadyDialog_UpdateInstanceInfo(name, completedEncounters, totalEncounters)
+ local instanceInfoFrame = LFDDungeonReadyDialogInstanceInfoFrame;
+ instanceInfoFrame.name:SetFontObject(GameFontNormalLarge);
+ instanceInfoFrame.name:SetText(name);
+ if ( instanceInfoFrame.name:GetWidth() + 20 > LFDDungeonReadyDialog:GetWidth() ) then
+ instanceInfoFrame.name:SetFontObject(GameFontNormal);
+ end
+
+ instanceInfoFrame.statusText:SetFormattedText(BOSSES_KILLED, completedEncounters, totalEncounters);
+end
+
+function LFDDungeonReadyDialogInstanceInfo_OnEnter(self)
+ local numBosses = select(8, GetLFGProposal());
+ local isHoliday = select(12, GetLFGProposal());
+
+ if ( numBosses == 0 or isHoliday) then
+ return;
+ end
+
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOM");
+ GameTooltip:AddLine(BOSSES)
+ for i=1, numBosses do
+ local bossName, texture, isKilled = GetLFGProposalEncounter(i);
+ if ( isKilled ) then
+ GameTooltip:AddDoubleLine(bossName, BOSS_DEAD, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ else
+ GameTooltip:AddDoubleLine(bossName, BOSS_ALIVE, GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b, GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b);
+ end
+ end
+ GameTooltip:Show();
+end
+
+function LFDDungeonReadyStatus_ResetReadyStates()
+ for i=1, NUM_LFD_MEMBERS do
+ local button = _G["LFDDungeonReadyStatusPlayer"..i];
+ button.readyStatus = "unknown";
+ end
+end
+
+function LFDDungeonReadyStatus_UpdateIcon(button)
+ local isLeader, role, level, responded, accepted, name, class = GetLFGProposalMember(button:GetID());
+
+ button.texture:SetTexCoord(GetTexCoordsForRole(role));
+
+ if ( not responded ) then
+ button.statusIcon:SetTexture(READY_CHECK_WAITING_TEXTURE);
+ elseif ( accepted ) then
+ if ( button.readyStatus ~= "accepted" ) then
+ button.readyStatus = "accepted";
+ PlaySound("LFG_RoleCheck");
+ end
+ button.statusIcon:SetTexture(READY_CHECK_READY_TEXTURE);
+ else
+ button.statusIcon:SetTexture(READY_CHECK_NOT_READY_TEXTURE);
+ end
+
+ button:Show();
+end
+
+function LFDQueueFrameTypeDropDown_SetUp(self)
+ UIDropDownMenu_SetWidth(self, 180);
+ UIDropDownMenu_Initialize(self, LFDQueueFrameTypeDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(LFDQueueFrameTypeDropDown, LFDQueueFrame.type);
+end
+
+local function isRandomDungeonDisplayable(id)
+ local name, typeID, minLevel, maxLevel, _, _, _, expansionLevel = GetLFGDungeonInfo(id);
+ local myLevel = UnitLevel("player");
+ return myLevel >= minLevel and myLevel <= maxLevel and EXPANSION_LEVEL >= expansionLevel;
+end
+
+function LFDQueueFrameTypeDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+
+ info.text = SPECIFIC_DUNGEONS;
+ info.value = "specific";
+ info.func = LFDQueueFrameTypeDropDownButton_OnClick;
+ info.checked = LFDQueueFrame.type == info.value;
+ UIDropDownMenu_AddButton(info);
+
+ for i=1, GetNumRandomDungeons() do
+ local id, name = GetLFGRandomDungeonInfo(i);
+ local isAvailable = IsLFGDungeonJoinable(id);
+ if ( isRandomDungeonDisplayable(id) ) then
+ if ( isAvailable ) then
+ info.text = name;
+ info.value = id;
+ info.isTitle = nil;
+ info.func = LFDQueueFrameTypeDropDownButton_OnClick;
+ info.disabled = nil;
+ info.checked = (LFDQueueFrame.type == info.value);
+ info.tooltipWhileDisabled = nil;
+ info.tooltipOnButton = nil;
+ info.tooltipTitle = nil;
+ info.tooltipText = nil;
+ UIDropDownMenu_AddButton(info);
+ else
+ info.text = name;
+ info.value = id;
+ info.isTitle = nil;
+ info.func = nil;
+ info.disabled = 1;
+ info.checked = nil;
+ info.tooltipWhileDisabled = 1;
+ info.tooltipOnButton = 1;
+ info.tooltipTitle = YOU_MAY_NOT_QUEUE_FOR_THIS;
+ info.tooltipText = LFDConstructDeclinedMessage(id);
+ UIDropDownMenu_AddButton(info);
+ end
+ end
+ end
+end
+
+function LFDQueueFrameTypeDropDownButton_OnClick(self)
+ LFDQueueFrame_SetType(self.value);
+end
+
+function LFDQueueFrame_SetType(value) --"specific" for the list or the record id for a single dungeon
+ LFDQueueFrame.type = value;
+ UIDropDownMenu_SetSelectedValue(LFDQueueFrameTypeDropDown, value);
+
+ if ( value == "specific" ) then
+ LFDQueueFrame_SetTypeSpecificDungeon();
+ else
+ LFDQueueFrame_SetTypeRandomDungeon();
+ LFDQueueFrameRandom_UpdateFrame();
+ end
+end
+
+function LFDQueueFrame_SetTypeRandomDungeon()
+ LFDQueueFrameBackground:SetTexture("Interface\\LFGFrame\\UI-LFG-BACKGROUND-QUESTPAPER")
+ LFDQueueFrameSpecific:Hide();
+ LFDQueueFrameRandom:Show();
+end
+
+function LFDQueueFrame_SetTypeSpecificDungeon()
+ LFDQueueFrameBackground:SetTexture("Interface\\LFGFrame\\UI-LFG-BACKGROUND-DUNGEONWALL");
+ LFDQueueFrameRandom:Hide();
+ LFDQueueFrameSpecific:Show();
+end
+
+function LFDConstructDeclinedMessage(dungeonID)
+ local returnVal;
+ for i=1, GetLFDLockPlayerCount() do
+ local playerName, lockedReason = GetLFDLockInfo(dungeonID, i);
+ if ( lockedReason ~= 0 ) then
+ local who;
+ if ( i == 1 ) then
+ who = "SELF_";
+ else
+ who = "OTHER_";
+ end
+ if ( returnVal ) then
+ returnVal = returnVal.."\n"..format(_G["INSTANCE_UNAVAILABLE_"..who..(LFG_INSTANCE_INVALID_CODES[lockedReason] or "OTHER")], playerName);
+ else
+ returnVal = format(_G["INSTANCE_UNAVAILABLE_"..who..(LFG_INSTANCE_INVALID_CODES[lockedReason] or "OTHER")], playerName);
+ end
+ end
+ end
+ return returnVal;
+end
+
+--Random frame functions
+NUM_LFD_RANDOM_REWARD_FRAMES = 1;
+function LFDQueueFrameRandom_UpdateFrame()
+ local parentName = "LFDQueueFrameRandomScrollFrameChildFrame"
+ local parentFrame = _G[parentName];
+
+ local dungeonID = LFDQueueFrame.type;
+
+ if ( not dungeonID ) then --We haven't gotten info on available dungeons yet.
+ return;
+ end
+
+ local holiday;
+ local difficulty;
+ local dungeonDescription;
+ local textureFilename;
+ local dungeonName, _,_,_,_,_,_,_,_,textureFilename,difficulty,_,dungeonDescription, isHoliday = GetLFGDungeonInfo(dungeonID);
+ local isHeroic = difficulty > 0;
+ local doneToday, moneyBase, moneyVar, experienceBase, experienceVar, numRewards = GetLFGDungeonRewards(dungeonID);
+ local numRandoms = 4 - GetNumPartyMembers();
+ local moneyAmount = moneyBase + moneyVar * numRandoms;
+ local experienceGained = experienceBase + experienceVar * numRandoms;
+
+
+ local backgroundTexture;
+ if ( isHeroic ) then
+ backgroundTexture = "Interface\\LFGFrame\\UI-LFG-BACKGROUND-HEROIC";
+ elseif ( isHoliday ) then
+ backgroundTexture = "Interface\\LFGFrame\\UI-LFG-HOLIDAY-BACKGROUND-"..textureFilename;
+ else
+ backgroundTexture = "Interface\\LFGFrame\\UI-LFG-BACKGROUND-QUESTPAPER";
+ end
+
+ if ( not LFDQueueFrameBackground:SetTexture(backgroundTexture) ) then
+ LFDQueueFrameBackground:SetTexture("Interface\\LFGFrame\\UI-LFG-BACKGROUND-QUESTPAPER");
+ end
+
+ local lastFrame = parentFrame.rewardsLabel;
+ if ( isHoliday ) then
+ if ( doneToday ) then
+ parentFrame.rewardsDescription:SetText(LFD_HOLIDAY_REWARD_EXPLANATION2);
+ else
+ parentFrame.rewardsDescription:SetText(LFD_HOLIDAY_REWARD_EXPLANATION1);
+ end
+ parentFrame.title:SetText(dungeonName);
+ parentFrame.description:SetText(dungeonDescription);
+ else
+ if ( doneToday ) then
+ parentFrame.rewardsDescription:SetText(LFD_RANDOM_REWARD_EXPLANATION2);
+ else
+ parentFrame.rewardsDescription:SetText(LFD_RANDOM_REWARD_EXPLANATION1);
+ end
+ parentFrame.title:SetText(LFG_TYPE_RANDOM_DUNGEON);
+ parentFrame.description:SetText(LFD_RANDOM_EXPLANATION);
+ end
+
+ for i=1, numRewards do
+ local frame = _G[parentName.."Item"..i];
+ if ( not frame ) then
+ frame = CreateFrame("Button", parentName.."Item"..i, _G[parentName], "LFDRandomDungeonLootTemplate");
+ frame:SetID(i);
+ NUM_LFD_RANDOM_REWARD_FRAMES = i;
+ if ( mod(i, 2) == 0 ) then
+ frame:SetPoint("LEFT", parentName.."Item"..(i-1), "RIGHT", 0, 0);
+ else
+ frame:SetPoint("TOPLEFT", parentName.."Item"..(i-2), "BOTTOMLEFT", 0, -5);
+ end
+ end
+
+ local name, texture, numItems = GetLFGDungeonRewardInfo(dungeonID, i);
+
+ _G[parentName.."Item"..i.."Name"]:SetText(name);
+ SetItemButtonTexture(frame, texture);
+ SetItemButtonCount(frame, numItems);
+ frame:Show();
+ lastFrame = frame;
+ end
+ for i=numRewards+1, NUM_LFD_RANDOM_REWARD_FRAMES do
+ _G[parentName.."Item"..i]:Hide();
+ end
+
+ if ( numRewards > 0 or ((moneyVar == 0 and experienceVar == 0) and (moneyAmount > 0 or experienceGained > 0)) ) then
+ parentFrame.rewardsLabel:Show();
+ parentFrame.rewardsDescription:Show();
+ lastFrame = parentFrame.rewardsDescription;
+ else
+ parentFrame.rewardsLabel:Hide();
+ parentFrame.rewardsDescription:Hide();
+ end
+
+ if ( numRewards > 0 ) then
+ lastFrame = _G[parentName.."Item"..(numRewards - mod(numRewards+1, 2))];
+ end
+
+ if ( moneyVar > 0 or experienceVar > 0 ) then
+ parentFrame.pugDescription:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", 0, -5);
+ parentFrame.pugDescription:Show();
+ lastFrame = parentFrame.pugDescription;
+ else
+ parentFrame.pugDescription:Hide();
+ end
+
+ if ( moneyAmount > 0 ) then
+ MoneyFrame_Update(parentFrame.moneyFrame, moneyAmount);
+ parentFrame.moneyLabel:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", 20, -10);
+ parentFrame.moneyLabel:Show();
+ parentFrame.moneyFrame:Show()
+
+ parentFrame.xpLabel:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", 0, -5);
+
+ lastFrame = parentFrame.moneyLabel;
+ else
+ parentFrame.moneyLabel:Hide();
+ parentFrame.moneyFrame:Hide();
+
+ end
+
+ if ( experienceGained > 0 ) then
+ parentFrame.xpAmount:SetText(experienceGained);
+
+ if ( lastFrame == parentFrame.moneyLabel ) then
+ parentFrame.xpLabel:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", 0, -5);
+ else
+ parentFrame.xpLabel:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", 20, -10);
+ end
+ parentFrame.xpLabel:Show();
+ parentFrame.xpAmount:Show();
+
+ lastFrame = parentFrame.xpLabel;
+ else
+ parentFrame.xpLabel:Hide();
+ parentFrame.xpAmount:Hide();
+ end
+
+ parentFrame.spacer:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", 0, -10);
+end
+
+function LFDQueueFrameRandomCooldownFrame_OnLoad(self)
+ self:SetFrameLevel(11); --This value also needs to be set when SetParent is called in LFDQueueFrameRandomCooldownFrame_Update.
+
+ self:RegisterEvent("PLAYER_ENTERING_WORLD"); --For logging in/reloading ui
+ self:RegisterEvent("UNIT_AURA"); --The cooldown is still technically a debuff
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+end
+
+function LFDQueueFrameRandomCooldownFrame_OnEvent(self, event, ...)
+ local arg1 = ...;
+ if ( event ~= "UNIT_AURA" or arg1 == "player" or strsub(arg1, 1, 5) == "party" ) then
+ LFDQueueFrameRandomCooldownFrame_Update();
+ end
+end
+
+function LFDQueueFrameRandomCooldownFrame_Update()
+ local cooldownFrame = LFDQueueFrameCooldownFrame;
+ local shouldShow = false;
+ local hasDeserter = false; --If we have deserter, we want to show this over the specific frame as well as the random frame.
+
+ local deserterExpiration = GetLFGDeserterExpiration();
+
+ local myExpireTime;
+ if ( deserterExpiration ) then
+ myExpireTime = deserterExpiration;
+ hasDeserter = true;
+ else
+ myExpireTime = GetLFGRandomCooldownExpiration();
+ end
+
+ cooldownFrame.myExpirationTime = myExpireTime;
+
+ for i = 1, GetNumPartyMembers() do
+ local nameLabel = _G["LFDQueueFrameCooldownFrameName"..i];
+ local statusLabel = _G["LFDQueueFrameCooldownFrameStatus"..i];
+ nameLabel:Show();
+ statusLabel:Show();
+
+ local _, classFilename = UnitClass("party"..i);
+ local classColor = classFilename and RAID_CLASS_COLORS[classFilename] or NORMAL_FONT_COLOR;
+ nameLabel:SetFormattedText("|cff%.2x%.2x%.2x%s|r", classColor.r * 255, classColor.g * 255, classColor.b * 255, UnitName("party"..i));
+
+ if ( UnitHasLFGDeserter("party"..i) ) then
+ statusLabel:SetFormattedText(RED_FONT_COLOR_CODE.."%s|r", DESERTER);
+ shouldShow = true;
+ hasDeserter = true;
+ elseif ( UnitHasLFGRandomCooldown("party"..i) ) then
+ statusLabel:SetFormattedText(RED_FONT_COLOR_CODE.."%s|r", ON_COOLDOWN);
+ shouldShow = true;
+ else
+ statusLabel:SetFormattedText(GREEN_FONT_COLOR_CODE.."%s|r", READY);
+ end
+ end
+ for i = GetNumPartyMembers() + 1, MAX_PARTY_MEMBERS do
+ local nameLabel = _G["LFDQueueFrameCooldownFrameName"..i];
+ local statusLabel = _G["LFDQueueFrameCooldownFrameStatus"..i];
+ nameLabel:Hide();
+ statusLabel:Hide();
+ end
+
+ if ( GetNumPartyMembers() == 0 ) then
+ cooldownFrame.description:SetPoint("TOP", 0, -85);
+ else
+ cooldownFrame.description:SetPoint("TOP", 0, -30);
+ end
+
+ if ( hasDeserter ) then
+ cooldownFrame:SetParent(LFDQueueFrame);
+ cooldownFrame:SetFrameLevel(11); --Setting a new parent changes the frame level, so we need to move it back to what we set in OnLoad.
+ else
+ cooldownFrame:SetParent(LFDQueueFrameRandom); --If nobody has deserter, the dungeon cooldown only prevents us from queueing for random.
+ cooldownFrame:SetFrameLevel(11);
+ end
+
+ if ( myExpireTime and GetTime() < myExpireTime ) then
+ shouldShow = true;
+ if ( deserterExpiration ) then
+ cooldownFrame.description:SetText(LFG_DESERTER_YOU);
+ else
+ cooldownFrame.description:SetText(LFG_RANDOM_COOLDOWN_YOU);
+ end
+ cooldownFrame.time:SetText(SecondsToTime(ceil(myExpireTime - GetTime())));
+ cooldownFrame.time:Show();
+
+ cooldownFrame:SetScript("OnUpdate", LFDQueueFrameRandomCooldownFrame_OnUpdate);
+ else
+ if ( hasDeserter ) then
+ cooldownFrame.description:SetText(LFG_DESERTER_OTHER);
+ else
+ cooldownFrame.description:SetText(LFG_RANDOM_COOLDOWN_OTHER);
+ end
+ cooldownFrame.time:Hide();
+
+ cooldownFrame:SetScript("OnUpdate", nil);
+ end
+
+ if ( shouldShow ) then
+ cooldownFrame:Show();
+ else
+ cooldownFrame:Hide();
+ end
+end
+
+function LFDQueueFrameRandomCooldownFrame_OnUpdate(self, elapsed)
+ local timeRemaining = self.myExpirationTime - GetTime();
+ if ( timeRemaining > 0 ) then
+ self.time:SetText(SecondsToTime(ceil(timeRemaining)));
+ else
+ LFDQueueFrameRandomCooldownFrame_Update();
+ end
+end
+
+--Queued status functions
+
+local NUM_TANKS = 1;
+local NUM_HEALERS = 1;
+local NUM_DAMAGERS = 3;
+
+function LFDSearchStatus_OnEvent(self, event, ...)
+ if ( event == "LFG_QUEUE_STATUS_UPDATE" ) then
+ LFDSearchStatus_Update();
+ end
+end
+
+function LFDSearchStatusPlayer_SetFound(button, isFound)
+ if ( isFound ) then
+ SetDesaturation(button.texture, false);
+ button.cover:Hide();
+ else
+ SetDesaturation(button.texture, true);
+ button.cover:Show();
+ end
+end
+
+function LFDSearchStatus_UpdateRoles()
+ local leader, tank, healer, damage = GetLFGRoles();
+ local currentIcon = 1;
+ if ( tank ) then
+ local icon = _G["LFDSearchStatusRoleIcon"..currentIcon]
+ icon:SetTexCoord(GetTexCoordsForRole("TANK"));
+ icon:Show();
+ currentIcon = currentIcon + 1;
+ end
+ if ( healer ) then
+ local icon = _G["LFDSearchStatusRoleIcon"..currentIcon]
+ icon:SetTexCoord(GetTexCoordsForRole("HEALER"));
+ icon:Show();
+ currentIcon = currentIcon + 1;
+ end
+ if ( damage ) then
+ local icon = _G["LFDSearchStatusRoleIcon"..currentIcon]
+ icon:SetTexCoord(GetTexCoordsForRole("DAMAGER"));
+ icon:Show();
+ currentIcon = currentIcon + 1;
+ end
+ for i=currentIcon, LFD_NUM_ROLES do
+ _G["LFDSearchStatusRoleIcon"..i]:Hide();
+ end
+ local extraWidth = 27*(currentIcon-1);
+ LFDSearchStatusLookingFor:SetPoint("BOTTOM", -extraWidth/2, 14);
+end
+
+local embeddedTankIcon = "|TInterface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES.blp:20:20:0:5:64:64:0:19:22:41|t";
+local embeddedHealerIcon = "|TInterface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES.blp:20:20:0:5:64:64:20:39:1:20|t";
+local embeddedDamageIcon = "|TInterface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES.blp:20:20:0:5:64:64:20:39:22:41|t";
+
+function LFDSearchStatus_Update()
+ local LFDSearchStatus = LFDSearchStatus;
+ local hasData, leaderNeeds, tankNeeds, healerNeeds, dpsNeeds, instanceType, instanceName, averageWait, tankWait, healerWait, damageWait, myWait, queuedTime = GetLFGQueueStats();
+
+ LFDSearchStatus_UpdateRoles();
+
+ if ( not hasData ) then
+ LFDSearchStatus:SetHeight(145);
+ LFDSearchStatusPlayer_SetFound(LFDSearchStatusTank1, false)
+ LFDSearchStatusPlayer_SetFound(LFDSearchStatusHealer1, false);
+ for i=1, NUM_DAMAGERS do
+ LFDSearchStatusPlayer_SetFound(_G["LFDSearchStatusDamage"..i], false);
+ end
+ LFDSearchStatus.statistic:Hide();
+ LFDSearchStatus.elapsedWait:SetFormattedText(TIME_IN_QUEUE, LESS_THAN_ONE_MINUTE);
+
+ LFDSearchStatus:SetScript("OnUpdate", nil);
+ return;
+ end
+
+ if ( instancetype == TYPEID_HEROIC_DIFFICULTY ) then
+ instanceName = format(HEROIC_PREFIX, instanceName);
+ end
+
+ --This won't work if we decide the makeup is, say, 3 healers, 1 damage, 1 tank.
+ LFDSearchStatusPlayer_SetFound(LFDSearchStatusTank1, (tankNeeds == 0))
+ LFDSearchStatusPlayer_SetFound(LFDSearchStatusHealer1, (healerNeeds == 0));
+ for i=1, NUM_DAMAGERS do
+ LFDSearchStatusPlayer_SetFound(_G["LFDSearchStatusDamage"..i], i <= (NUM_DAMAGERS - dpsNeeds));
+ end
+
+ LFDSearchStatus.queuedTime = queuedTime;
+ local elapsedTime = GetTime() - queuedTime;
+ LFDSearchStatus.elapsedWait:SetFormattedText(TIME_IN_QUEUE, (elapsedTime >= 60) and SecondsToTime(elapsedTime) or LESS_THAN_ONE_MINUTE);
+ LFDSearchStatus.elapsedWait:Show();
+
+ if ( myWait == -1 ) then
+ LFDSearchStatus.statistic:Hide();
+ LFDSearchStatus:SetHeight(145);
+ else
+ LFDSearchStatus.statistic:Show();
+ LFDSearchStatus:SetHeight(170);
+ LFDSearchStatus.statistic:SetFormattedText(LFG_STATISTIC_AVERAGE_WAIT, myWait == -1 and TIME_UNKNOWN or SecondsToTime(myWait, false, false, 1));
+ end
+ LFDSearchStatus:SetScript("OnUpdate", LFDSearchStatus_OnUpdate);
+end
+
+function LFDSearchStatus_OnUpdate(self, elapsed)
+ local elapsedTime = GetTime() - self.queuedTime;
+ self.elapsedWait:SetFormattedText(TIME_IN_QUEUE, (elapsedTime >= 60) and SecondsToTime(elapsedTime) or LESS_THAN_ONE_MINUTE);
+end
+
+function LFDQueueFrameFindGroupButton_Update()
+ local mode, subMode = GetLFGMode();
+ if ( mode == "queued" or mode == "rolecheck" or mode == "proposal") then
+ LFDQueueFrameFindGroupButton:SetText(LEAVE_QUEUE);
+ else
+ if ( GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0 ) then
+ LFDQueueFrameFindGroupButton:SetText(JOIN_AS_PARTY);
+ else
+ LFDQueueFrameFindGroupButton:SetText(FIND_A_GROUP);
+ end
+ end
+
+ if ( LFD_IsEmpowered() and mode ~= "proposal" and mode ~= "listed" ) then --During the proposal, they must use the proposal buttons to leave the queue.
+ if ( mode == "queued" or mode =="proposal" or mode == "rolecheck" or not LFDQueueFramePartyBackfill:IsVisible() ) then
+ LFDQueueFrameFindGroupButton:Enable();
+ else
+ LFDQueueFrameFindGroupButton:Disable();
+ end
+ LFRQueueFrameNoLFRWhileLFDLeaveQueueButton:Enable();
+ else
+ LFDQueueFrameFindGroupButton:Disable();
+ LFRQueueFrameNoLFRWhileLFDLeaveQueueButton:Disable();
+ end
+
+ if ( LFD_IsEmpowered() and mode ~= "proposal" and mode ~= "queued" ) then
+ LFDQueueFramePartyBackfillBackfillButton:Enable();
+ else
+ LFDQueueFramePartyBackfillBackfillButton:Disable();
+ end
+end
+
+LFDHiddenByCollapseList = {};
+function LFDQueueFrame_Update()
+ local enableList;
+
+ local mode, submode = GetLFGMode();
+
+ if ( LFD_IsEmpowered() and mode ~= "queued") then
+ enableList = LFGEnabledList;
+ else
+ enableList = LFGQueuedForList;
+ end
+
+ LFDDungeonList = GetLFDChoiceOrder(LFDDungeonList);
+
+ LFGQueueFrame_UpdateLFGDungeonList(LFDDungeonList, LFDHiddenByCollapseList, LFGLockList, LFGDungeonInfo, enableList, LFGCollapseList, LFD_CURRENT_FILTER);
+
+ LFDQueueFrameSpecificList_Update();
+end
+
+function LFDList_DefaultFilterFunction(dungeonID)
+ local info = LFGGetDungeonInfoByID(dungeonID)
+ local hasHeader = info[LFG_RETURN_VALUES.groupID] ~= 0;
+ local sufficientExpansion = EXPANSION_LEVEL >= info[LFG_RETURN_VALUES.expansionLevel];
+ local level = UnitLevel("player");
+ local sufficientLevel = level >= info[LFG_RETURN_VALUES.minLevel] and level <= info[LFG_RETURN_VALUES.maxLevel];
+ return (hasHeader and sufficientExpansion and sufficientLevel) and
+ ( level - LFD_MAX_SHOWN_LEVEL_DIFF <= info[LFG_RETURN_VALUES.recLevel] or (LFGLockList and not LFGLockList[dungeonID])); --If the server tells us we can join, who are we to complain?
+end
+
+LFD_CURRENT_FILTER = LFDList_DefaultFilterFunction
\ No newline at end of file
diff --git a/reference/FrameXML/LFDFrame.xml b/reference/FrameXML/LFDFrame.xml
new file mode 100644
index 0000000..0fd9610
--- /dev/null
+++ b/reference/FrameXML/LFDFrame.xml
@@ -0,0 +1,1803 @@
+
+
+
+
+
+ self.enableButton:SetScript("OnClick", LFDQueueFrameDungeonChoiceEnableButton_OnClick);
+ self.expandOrCollapseButton:SetScript("OnClick", LFDQueueFrameExpandOrCollapseButton_OnClick);
+ self:SetScript("OnEnter", LFDQueueFrameDungeonListButton_OnEnter);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.hasItem = 1;
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetLFGDungeonReward(LFDQueueFrame.type, self:GetID());
+ CursorUpdate(self);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ CursorOnUpdate(self, elapsed);
+
+
+ HandleModifiedItemClick(GetLFGDungeonRewardLink(LFDQueueFrame.type, self:GetID()));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LFGDebug("Proposal Hidden: Ready Status close button pressed.");
+ StaticPopupSpecial_Hide(LFDDungeonReadyPopup);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoTab");
+ LFGDebug("Proposal Hidden: Ready Dialog close button pressed.");
+ StaticPopupSpecial_Hide(LFDDungeonReadyPopup);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoTab");
+ AcceptProposal();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoTab");
+ RejectProposal();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("LFG_UPDATE_RANDOM_INFO")
+
+
+ if ( event == "LFG_UPDATE_RANDOM_INFO" ) then
+ --The rewards may have changed.
+ if ( self:IsShown() ) then
+ LFDDungeonReadyPopup_Update();
+ end
+ end
+
+
+ LFDDungeonReadyPopup_Update();
+
+ --Request new lock info (which comes with which rewards we're getting) in case the rewards changed.
+ RequestLFDPlayerLockInfo();
+ RequestLFDPartyLockInfo();
+
+
+ self.closeIn = nil;
+ self:SetScript("OnUpdate", nil);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("TANK"));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("HEALER"));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("DAMAGER"));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LFDRoleCheckPopup_Update();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.texture:SetTexCoord(GetTexCoordsForRole("TANK"));
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.texture:SetTexCoord(GetTexCoordsForRole("HEALER"));
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.texture:SetTexCoord(GetTexCoordsForRole("DAMAGER"));
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.texture:SetTexCoord(GetTexCoordsForRole("DAMAGER"));
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.texture:SetTexCoord(GetTexCoordsForRole("DAMAGER"));
+
+
+
+
+
+
+ self:RegisterEvent("LFG_QUEUE_STATUS_UPDATE");
+
+ self:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g, TOOLTIP_DEFAULT_COLOR.b);
+ self:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r, TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("TANK"));
+ self.background:SetTexCoord(GetBackgroundTexCoordsForRole("TANK"));
+ self.background:SetAlpha(0.6);
+ self.checkButton.onClick = LFDFrameRoleCheckButton_OnClick;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("HEALER"));
+ self.background:SetTexCoord(GetBackgroundTexCoordsForRole("HEALER"));
+ self.background:SetAlpha(0.4);
+ self.checkButton.onClick = LFDFrameRoleCheckButton_OnClick;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("DAMAGER"));
+ self.background:SetTexCoord(GetBackgroundTexCoordsForRole("DAMAGER"));
+ self.background:SetAlpha(0.6);
+ self.checkButton.onClick = LFDFrameRoleCheckButton_OnClick;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("GUIDE"));
+ self.checkButton.onClick = LFDFrameRoleCheckButton_OnClick;
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(GUIDE_TOOLTIP, nil, nil, nil, nil, 1);
+ LFDFrameRoleCheckButton_OnEnter(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local myName = self:GetName();
+ _G[myName.."ScrollBackground"]:SetParent(_G[myName.."ScrollBar"]);
+ _G[myName.."ScrollBackgroundTopLeft"]:SetParent(_G[myName.."ScrollBar"]);
+ _G[myName.."ScrollBackgroundBottomRight"]:SetParent(_G[myName.."ScrollBar"]);
+
+ _G[myName.."ScrollBar"]:SetPoint("BOTTOMLEFT", self, "BOTTOMRIGHT", 6, 14);
+
+ self.scrollBarHideable = true;
+ ScrollFrame_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local myName = self:GetName();
+ self.description:SetTextColor(1, 1, 1);
+ self.rewardsDescription:SetTextColor(1, 1, 1);
+ self.pugDescription:SetTextColor(1, 1, 1);
+ self.moneyLabel:SetTextColor(1, 1, 1);
+ self.xpLabel:SetTextColor(1, 1, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, 16, LFDQueueFrameSpecificList_Update);
+
+
+
+
+
+
+ LFDQueueFrame_Update();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local mode, subMode = GetLFGMode();
+ if ( mode == "queued" or mode == "listed" or mode == "rolecheck" ) then
+ LeaveLFG();
+ else
+ LFDQueueFrame_Join();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(self:GetParent():GetParent())
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Hide("LFG_OFFER_CONTINUE");
+ PartyLFGStartBackfill();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("UChatScrollButton");
+ self:GetParent():Hide();
+
+
+
+
+
+
+ LFDQueueFrameFindGroupButton_Update();
+
+
+ LFDQueueFrameFindGroupButton_Update();
+
+
+ self:SetFrameLevel(14);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LeaveLFG();
+
+
+
+
+
+
+ self:SetFrameLevel(16);
+
+
+
+
+
+
+ UpdateMicroButtons();
+ PlaySound("igCharacterInfoOpen");
+ RequestLFDPlayerLockInfo();
+ RequestLFDPartyLockInfo();
+
+
+ UpdateMicroButtons();
+ PlaySound("igCharacterInfoClose");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/LFGFrame.lua b/reference/FrameXML/LFGFrame.lua
new file mode 100644
index 0000000..eb74522
--- /dev/null
+++ b/reference/FrameXML/LFGFrame.lua
@@ -0,0 +1,507 @@
+-----
+--A note on nomenclature:
+--LFD is used for Dungeon-specific functions and values
+--LFR is used for Raid-specific functions and values
+--LFG is used for for generic functions/values that may be used for LFD, LFR, and any other LF_ system we may implement in the future.
+------
+
+--DEBUG FIXME:
+function LFGDebug(text, ...)
+ if ( GetCVarBool("lfgDebug") ) then
+ ConsolePrint("LFGLua: "..format(text, ...));
+ end
+end
+
+LFG_RETURN_VALUES = {
+ name = 1,
+ typeID = 2,
+ minLevel = 3,
+ maxLevel = 4,
+ recLevel = 5, --Recommended level
+ minRecLevel = 6, --Minimum recommended level
+ maxRecLevel = 7, --Maximum recommended level
+ expansionLevel = 8,
+ groupID = 9,
+ texture = 10,
+ difficulty = 11,
+ maxPlayers = 12,
+}
+
+LFG_INSTANCE_INVALID_CODES = { --Any other codes are unspecified conditions (e.g. attunements)
+ "EXPANSION_TOO_LOW",
+ "LEVEL_TOO_LOW",
+ "LEVEL_TOO_HIGH",
+ "GEAR_TOO_LOW",
+ "GEAR_TOO_HIGH",
+ "RAID_LOCKED",
+ [1001] = "LEVEL_TOO_LOW",
+ [1002] = "LEVEL_TOO_HIGH",
+ [1022] = "QUEST_NOT_COMPLETED",
+ [1025] = "MISSING_ITEM",
+
+}
+
+local tankIcon = "|TInterface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES.blp:16:16:0:%d:64:64:0:19:22:41|t";
+local healerIcon = "|TInterface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES.blp:16:16:0:%d:64:64:20:39:1:20|t";
+local damageIcon = "|TInterface\\LFGFrame\\UI-LFG-ICON-PORTRAITROLES.blp:16:16:0:%d:64:64:20:39:22:41|t";
+
+--Variables to store dungeon info in Lua
+--local LFDDungeonList, LFRRaidList, LFGDungeonInfo, LFGCollapseList, LFGEnabledList, LFDHiddenByCollapseList, LFGLockList;
+
+function LFGEventFrame_OnLoad(self)
+ self:RegisterEvent("LFG_UPDATE");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("LFG_LOCK_INFO_RECEIVED");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+
+ self:RegisterEvent("LFG_OFFER_CONTINUE");
+ self:RegisterEvent("LFG_ROLE_CHECK_ROLE_CHOSEN");
+
+ --These just update states (roles changeable, buttons clickable, etc.)
+ self:RegisterEvent("LFG_PROPOSAL_UPDATE");
+ self:RegisterEvent("LFG_PROPOSAL_SHOW");
+ self:RegisterEvent("LFG_ROLE_CHECK_SHOW");
+ self:RegisterEvent("LFG_ROLE_CHECK_HIDE");
+ self:RegisterEvent("LFG_BOOT_PROPOSAL_UPDATE");
+ self:RegisterEvent("LFG_ROLE_UPDATE");
+ self:RegisterEvent("LFG_UPDATE_RANDOM_INFO");
+ self:RegisterEvent("LFG_PROPOSAL_FAILED");
+end
+
+LFGQueuedForList = {};
+function LFGEventFrame_OnEvent(self, event, ...)
+ if ( event == "LFG_UPDATE" ) then
+ LFG_UpdateQueuedList();
+ elseif ( event == "PLAYER_ENTERING_WORLD" ) then
+ LFG_UpdateQueuedList();
+ LFG_UpdateRoleCheckboxes();
+ elseif ( event == "LFG_LOCK_INFO_RECEIVED" ) then
+ LFGLockList = GetLFDChoiceLockedState();
+ LFG_UpdateFramesIfShown();
+ elseif ( event == "PARTY_MEMBERS_CHANGED" ) then
+ LFG_UpdateQueuedList();
+ LFG_UpdateFramesIfShown();
+ if ( not CanPartyLFGBackfill() ) then
+ StaticPopup_Hide("LFG_OFFER_CONTINUE");
+ end
+ elseif ( event == "LFG_OFFER_CONTINUE" ) then
+ local displayName, lfgID, typeID = ...;
+ local dialog = StaticPopup_Show("LFG_OFFER_CONTINUE", NORMAL_FONT_COLOR_CODE..displayName.."|r");
+ if ( dialog ) then
+ dialog.data = lfgID;
+ dialog.data2 = typeID;
+ end
+ elseif ( event == "LFG_ROLE_CHECK_ROLE_CHOSEN" ) then
+ local player, isTank, isHealer, isDamage = ...;
+
+ --Yes, consecutive string concatenation == bad for garbage collection. But the alternative is either extremely unslightly or localization unfriendly. (Also, this happens fairly rarely)
+ local roleList;
+
+ --Horrible hack to deal with a bug in embedded font strings. FIXME
+ --The more icons with absolute sizes in a certain fontstring, the higher up the text goes. This offsets it to make the icons be in line with the text.
+ local numRoles = (isTank and 1 or 0) + (isHealer and 1 or 0) + (isDamage and 1 or 0);
+ local yOffset = 2*(numRoles-1)-2; --Formula derived through testing.
+
+ local tankIcon = format(tankIcon, yOffset);
+ local healerIcon = format(healerIcon, yOffset);
+ local damageIcon = format(damageIcon, yOffset);
+
+ if ( isTank ) then
+ roleList = tankIcon.." "..TANK;
+ end
+ if ( isHealer ) then
+ if ( roleList ) then
+ roleList = roleList..PLAYER_LIST_DELIMITER.." "..healerIcon.." "..HEALER;
+ else
+ roleList = healerIcon.." "..HEALER;
+ end
+ end
+ if ( isDamage ) then
+ if ( roleList ) then
+ roleList = roleList..PLAYER_LIST_DELIMITER.." "..damageIcon.." "..DAMAGER;
+ else
+ roleList = damageIcon.." "..DAMAGER;
+ end
+ end
+ assert(roleList);
+ ChatFrame_DisplayUsageError(string.format(LFG_ROLE_CHECK_ROLE_CHOSEN, player, roleList));
+ end
+
+ LFG_UpdateRolesChangeable();
+ LFG_UpdateFindGroupButtons();
+ LFG_UpdateLockedOutPanels();
+ LFDFrame_UpdateBackfill();
+end
+
+function LFG_UpdateLockedOutPanels()
+ local mode, submode = GetLFGMode();
+
+ if ( mode == "listed" ) then
+ LFDQueueFrameNoLFDWhileLFR:Show();
+ else
+ LFDQueueFrameNoLFDWhileLFR:Hide();
+ end
+
+ if ( mode == "queued" or mode == "proposal" or mode == "rolecheck" ) then
+ LFRQueueFrameNoLFRWhileLFD:Show();
+ else
+ LFRQueueFrameNoLFRWhileLFD:Hide();
+ end
+end
+
+function LFG_UpdateFindGroupButtons()
+ LFDQueueFrameFindGroupButton_Update();
+ LFRQueueFrameFindGroupButton_Update();
+end
+
+function LFG_UpdateQueuedList()
+ GetLFGQueuedList(LFGQueuedForList);
+ LFG_UpdateFramesIfShown();
+ MiniMapLFG_UpdateIsShown();
+end
+
+function LFG_UpdateFramesIfShown()
+ if ( LFDParentFrame:IsShown() ) then
+ LFDQueueFrame_Update();
+ end
+ if ( LFRParentFrame:IsShown() ) then
+ LFRQueueFrame_Update();
+ end
+end
+
+function LFG_PermanentlyDisableRoleButton(button)
+ button.permDisabled = true;
+ button:Disable();
+ SetDesaturation(button:GetNormalTexture(), true);
+ button.cover:Show();
+ button.cover:SetAlpha(0.7);
+ button.checkButton:Hide();
+ button.checkButton:Disable();
+ if ( button.background ) then
+ button.background:Hide();
+ end
+end
+
+function LFG_DisableRoleButton(button)
+ button:Disable();
+ button.cover:Show();
+ if ( not button.permDisabled ) then
+ button.cover:SetAlpha(0.5);
+ end
+ button.checkButton:Disable();
+ if ( button.background ) then
+ button.background:Hide();
+ end
+end
+
+function LFG_EnableRoleButton(button)
+ button.permDisabled = false;
+ button:Enable();
+ SetDesaturation(button:GetNormalTexture(), false);
+ button.cover:Hide();
+ button.checkButton:Show();
+ button.checkButton:Enable();
+ if ( button.background ) then
+ button.background:Show();
+ end
+end
+
+function LFG_UpdateAvailableRoles()
+ local canBeTank, canBeHealer, canBeDPS = GetAvailableRoles();
+
+ if ( canBeTank ) then
+ LFG_EnableRoleButton(LFDQueueFrameRoleButtonTank);
+ LFG_EnableRoleButton(LFRQueueFrameRoleButtonTank);
+ LFG_EnableRoleButton(LFDRoleCheckPopupRoleButtonTank);
+ else
+ LFG_PermanentlyDisableRoleButton(LFDQueueFrameRoleButtonTank);
+ LFG_PermanentlyDisableRoleButton(LFRQueueFrameRoleButtonTank);
+ LFG_PermanentlyDisableRoleButton(LFDRoleCheckPopupRoleButtonTank);
+ end
+
+ if ( canBeHealer ) then
+ LFG_EnableRoleButton(LFDQueueFrameRoleButtonHealer);
+ LFG_EnableRoleButton(LFRQueueFrameRoleButtonHealer);
+ LFG_EnableRoleButton(LFDRoleCheckPopupRoleButtonHealer);
+ else
+ LFG_PermanentlyDisableRoleButton(LFDQueueFrameRoleButtonHealer);
+ LFG_PermanentlyDisableRoleButton(LFRQueueFrameRoleButtonHealer);
+ LFG_PermanentlyDisableRoleButton(LFDRoleCheckPopupRoleButtonHealer);
+ end
+
+ if ( canBeDPS ) then
+ LFG_EnableRoleButton(LFDQueueFrameRoleButtonDPS);
+ LFG_EnableRoleButton(LFRQueueFrameRoleButtonDPS);
+ LFG_EnableRoleButton(LFDRoleCheckPopupRoleButtonDPS);
+ else
+ LFG_PermanentlyDisableRoleButton(LFDQueueFrameRoleButtonDPS);
+ LFG_PermanentlyDisableRoleButton(LFRQueueFrameRoleButtonDPS);
+ LFG_PermanentlyDisableRoleButton(LFDRoleCheckPopupRoleButtonDPS);
+ end
+
+ local canChangeLeader = (GetNumPartyMembers() == 0 or IsPartyLeader()) and (GetNumRaidMembers() == 0 or IsRaidLeader());
+ if ( canChangeLeader ) then
+ LFG_EnableRoleButton(LFDQueueFrameRoleButtonLeader);
+ else
+ LFG_PermanentlyDisableRoleButton(LFDQueueFrameRoleButtonLeader);
+ end
+end
+
+function LFG_UpdateRoleCheckboxes()
+ local leader, tank, healer, dps = GetLFGRoles();
+
+ LFDQueueFrameRoleButtonLeader.checkButton:SetChecked(leader);
+
+ LFDQueueFrameRoleButtonTank.checkButton:SetChecked(tank);
+ LFRQueueFrameRoleButtonTank.checkButton:SetChecked(tank);
+ LFDRoleCheckPopupRoleButtonTank.checkButton:SetChecked(tank);
+
+ LFDQueueFrameRoleButtonHealer.checkButton:SetChecked(healer);
+ LFRQueueFrameRoleButtonHealer.checkButton:SetChecked(healer);
+ LFDRoleCheckPopupRoleButtonHealer.checkButton:SetChecked(healer);
+
+ LFDQueueFrameRoleButtonDPS.checkButton:SetChecked(dps);
+ LFRQueueFrameRoleButtonDPS.checkButton:SetChecked(dps);
+ LFDRoleCheckPopupRoleButtonDPS.checkButton:SetChecked(dps);
+end
+
+function LFG_UpdateRolesChangeable()
+ local mode, subMode = GetLFGMode();
+ if ( mode == "queued" or mode == "listed" or mode == "rolecheck" or mode == "proposal" ) then
+ LFG_DisableRoleButton(LFDQueueFrameRoleButtonTank, true);
+ LFG_DisableRoleButton(LFRQueueFrameRoleButtonTank, true);
+
+ LFG_DisableRoleButton(LFDQueueFrameRoleButtonHealer, true);
+ LFG_DisableRoleButton(LFRQueueFrameRoleButtonHealer, true);
+
+ LFG_DisableRoleButton(LFDQueueFrameRoleButtonDPS, true);
+ LFG_DisableRoleButton(LFRQueueFrameRoleButtonDPS, true);
+
+ LFG_DisableRoleButton(LFDQueueFrameRoleButtonLeader, true);
+ else
+ LFG_UpdateAvailableRoles();
+ end
+end
+
+function LFGSpecificChoiceEnableButton_SetIsRadio(button, isRadio)
+ if ( isRadio ) then
+ button:SetSize(17, 17)
+ button:SetNormalTexture("Interface\\Buttons\\UI-RadioButton");
+ button:GetNormalTexture():SetTexCoord(0, 0.25, 0, 1);
+
+ button:SetHighlightTexture("Interface\\Buttons\\UI-RadioButton");
+ button:GetHighlightTexture():SetTexCoord(0.5, 0.75, 0, 1);
+
+ button:SetCheckedTexture("Interface\\Buttons\\UI-RadioButton");
+ button:GetCheckedTexture():SetTexCoord(0.25, 0.5, 0, 1);
+
+ button:SetPushedTexture("Interface\\Buttons\\UI-RadioButton");
+ button:GetPushedTexture():SetTexCoord(0, 0.25, 0, 1);
+
+ button:SetDisabledCheckedTexture("Interface\\Buttons\\UI-RadioButton");
+ button:GetDisabledCheckedTexture():SetTexCoord(0.75, 1, 0, 1);
+ else
+ button:SetSize(20, 20);
+ button:SetNormalTexture("Interface\\Buttons\\UI-CheckBox-Up");
+ button:GetNormalTexture():SetTexCoord(0, 1, 0, 1);
+
+ button:SetHighlightTexture("Interface\\Buttons\\UI-CheckBox-Highlight");
+ button:GetHighlightTexture():SetTexCoord(0, 1, 0, 1);
+
+ button:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check");
+ button:GetCheckedTexture():SetTexCoord(0, 1, 0, 1);
+
+ button:SetPushedTexture("Interface\\Buttons\\UI-CheckBox-Down");
+ button:GetPushedTexture():SetTexCoord(0, 1, 0, 1);
+
+ button:SetDisabledCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled");
+ button:GetDisabledCheckedTexture():SetTexCoord(0, 1, 0, 1);
+ end
+end
+
+--More functions
+
+function GetTexCoordsForRole(role)
+ local textureHeight, textureWidth = 256, 256;
+ local roleHeight, roleWidth = 67, 67;
+
+ if ( role == "GUIDE" ) then
+ return GetTexCoordsByGrid(1, 1, textureWidth, textureHeight, roleWidth, roleHeight);
+ elseif ( role == "TANK" ) then
+ return GetTexCoordsByGrid(1, 2, textureWidth, textureHeight, roleWidth, roleHeight);
+ elseif ( role == "HEALER" ) then
+ return GetTexCoordsByGrid(2, 1, textureWidth, textureHeight, roleWidth, roleHeight);
+ elseif ( role == "DAMAGER" ) then
+ return GetTexCoordsByGrid(2, 2, textureWidth, textureHeight, roleWidth, roleHeight);
+ else
+ error("Unknown role: "..tostring(role));
+ end
+end
+
+function GetBackgroundTexCoordsForRole(role)
+ local textureHeight, textureWidth = 128, 256;
+ local roleHeight, roleWidth = 75, 75;
+
+ if ( role == "TANK" ) then
+ return GetTexCoordsByGrid(2, 1, textureWidth, textureHeight, roleWidth, roleHeight);
+ elseif ( role == "HEALER" ) then
+ return GetTexCoordsByGrid(1, 1, textureWidth, textureHeight, roleWidth, roleHeight);
+ elseif ( role == "DAMAGER" ) then
+ return GetTexCoordsByGrid(3, 1, textureWidth, textureHeight, roleWidth, roleHeight);
+ else
+ error("Role does not have background: "..tostring(role));
+ end
+end
+
+-------Utility functions-----------
+function LFDGetNumDungeons()
+ return #LFDDungeonList;
+end
+
+function LFRGetNumDungeons()
+ return #LFRRaidList;
+end
+
+function LFGGetDungeonInfoByID(id)
+ return LFGDungeonInfo[id];
+end
+
+function LFGIsIDHeader(id)
+ return id < 0;
+end
+
+-------List filtering functions-----------
+local hasSetUp = false;
+function LFGDungeonList_Setup()
+ if ( not hasSetUp ) then
+ hasSetUp = true;
+ LFGDungeonInfo = GetLFDChoiceInfo(LFGDungeonInfo); --This will never change (without a patch).
+ LFGCollapseList = GetLFDChoiceCollapseState(LFGCollapseList); --We maintain this list in Lua
+ LFGEnabledList = GetLFDChoiceEnabledState(LFGEnabledList); --We maintain this list in Lua
+ LFGLockList = GetLFDChoiceLockedState(LFGLockList);
+
+ LFDQueueFrame_Update();
+ LFRQueueFrame_Update();
+ return true;
+ end
+ return false;
+end
+
+function LFGQueueFrame_UpdateLFGDungeonList(dungeonList, hiddenByCollapseList, lockList, dungeonInfo, enableList, collapseList, filter)
+ if ( LFGDungeonList_Setup() ) then
+ return;
+ end
+
+ table.wipe(hiddenByCollapseList);
+
+ --1. Remove all choices that don't match the filter.
+ LFGListFilterChoices(dungeonList, dungeonInfo, filter);
+
+ --2. Remove all headers that have no entries below them.
+ LFGListRemoveHeadersWithoutChildren(dungeonList);
+
+ --3. Update the enabled state of headers.
+ LFGListUpdateHeaderEnabledAndLockedStates(dungeonList, enableList, lockList, hiddenByCollapseList);
+
+ --4. Move the children of collapsed headers into the hiddenByCollapse list.
+ LFGListRemoveCollapsedChildren(dungeonList, collapseList, hiddenByCollapseList);
+end
+
+--filterFunc returns true if the object should be shown.
+function LFGListFilterChoices(list, infoList, filterFunc)
+ local currentPosition = 1;
+ while ( currentPosition <= #list ) do
+ local id = list[currentPosition];
+ local isHeader = LFGIsIDHeader(id);
+ if ( isHeader or filterFunc(id) ) then
+ currentPosition = currentPosition + 1;
+ else
+ tremove(list, currentPosition);
+ end
+ end
+end
+
+function LFGListRemoveHeadersWithoutChildren(list)
+ --This relies on unparented children coming first.
+ local currentPosition = 1;
+ --The discrepency between nextObject>IsChild< and >isHeader< is due to the way we want to handle empty values.
+ local nextObjectIsChild = not LFGIsIDHeader(list[1] or 0);
+ while ( currentPosition <= #list ) do
+ local isHeader = not nextObjectIsChild;
+ nextObjectIsChild = currentPosition < #list and not LFGIsIDHeader(list[currentPosition+1]);
+ if ( isHeader and not nextObjectIsChild ) then
+ tremove(list, currentPosition);
+ else
+ currentPosition = currentPosition + 1;
+ end
+ end
+end
+
+--false = no children so far
+--0 = all children unchecked
+--1 = some children checked, some unchecked
+--2 = all children checked
+function LFGListUpdateHeaderEnabledAndLockedStates(dungeonList, enabledList, lockList, hiddenByCollapseList)
+ for i=1, #dungeonList do
+ local id = dungeonList[i];
+ if ( LFGIsIDHeader(id) ) then
+ enabledList[id] = false;
+ lockList[id] = true;
+ elseif ( not lockList[id] ) then
+ local groupID = LFGGetDungeonInfoByID(id)[LFG_RETURN_VALUES.groupID];
+ lockList[groupID] = false;
+ local idState = enabledList[id];
+ local groupState = enabledList[groupID];
+ if ( idState ) then
+ if ( not groupState or groupState == 2 ) then
+ enabledList[groupID] = 2;
+ elseif ( groupState == 0 or groupState == 1 ) then
+ enabledList[groupID] = 1;
+ end
+ else
+ if ( not groupState or groupState == 0 ) then
+ enabledList[groupID] = 0;
+ elseif ( groupState == 1 or groupState == 2 ) then
+ enabledList[groupID] = 1;
+ end
+ end
+ end
+ end
+ for i=1, #hiddenByCollapseList do
+ local id = hiddenByCollapseList[i];
+ if ( LFGIsIDHeader(id) ) then
+ enabledList[id] = false;
+ lockList[id] = true;
+ elseif ( not lockList[id] ) then
+ local groupID = LFGGetDungeonInfoByID(id)[LFG_RETURN_VALUES.groupID];
+ lockList[groupID] = false;
+ local idState = enabledList[id];
+ local groupState = enabledList[groupID];
+ if ( idState ) then
+ if ( not groupState or groupState == 2 ) then
+ enabledList[groupID] = 2;
+ elseif ( groupState == 0 or groupState == 1 ) then
+ enabledList[groupID] = 1;
+ end
+ else
+ if ( not groupState or groupState == 0 ) then
+ enabledList[groupID] = 0;
+ elseif ( groupState == 1 or groupState == 2 ) then
+ enabledList[groupID] = 1;
+ end
+ end
+ end
+ end
+end
+
+function LFGListRemoveCollapsedChildren(list, collapseStateList, hiddenByCollapseList)
+ local currentPosition = 1;
+ while ( currentPosition <= #list ) do
+ local id = list[currentPosition];
+ if ( not LFGIsIDHeader(id) and collapseStateList[id] ) then
+ tinsert(hiddenByCollapseList, tremove(list, currentPosition));
+ else
+ currentPosition = currentPosition + 1;
+ end
+ end
+end
\ No newline at end of file
diff --git a/reference/FrameXML/LFGFrame.xml b/reference/FrameXML/LFGFrame.xml
new file mode 100644
index 0000000..2657b79
--- /dev/null
+++ b/reference/FrameXML/LFGFrame.xml
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ if ( self.onClick ) then
+ self.onClick(self, button);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(_G["ROLE_DESCRIPTION"..self:GetID()], nil, nil, nil, nil, 1);
+ if ( self.permDisabled ) then
+ GameTooltip:AddLine(YOUR_CLASS_MAY_NOT_PERFORM_ROLE, 1, 0, 0, 1);
+ end
+ GameTooltip:Show();
+ LFDFrameRoleCheckButton_OnEnter(self);
+
+
+ if ( self.checkButton:IsEnabled() == 1 ) then
+ self.checkButton:Click();
+ end
+
+
+ GameTooltip:Hide();
+ self.checkButton:UnlockHighlight();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GameTooltip:GetOwner() == self ) then
+ GameTooltip:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/LFRFrame.lua b/reference/FrameXML/LFRFrame.lua
new file mode 100644
index 0000000..b31a3fe
--- /dev/null
+++ b/reference/FrameXML/LFRFrame.lua
@@ -0,0 +1,736 @@
+--Extra lines added because looking upward was too much work.
+
+
+
+
+
+
+
+LFR_MAX_SHOWN_LEVEL_DIFF = 15;
+
+NUM_LFR_CHOICE_BUTTONS = 14;
+
+NUM_LFR_LIST_BUTTONS = 19;
+
+LFR_BROWSE_AUTO_REFRESH_TIME = 20;
+
+local heroicIcon = "|TInterface\\LFGFrame\\UI-LFG-ICON-HEROIC:16:13:-5:-3:32:32:0:16:0:20|t";
+
+function LFRFrame_OnLoad(self)
+ self:RegisterEvent("UPDATE_LFG_LIST");
+ self:RegisterEvent("LFG_UPDATE");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+
+ PanelTemplates_SetNumTabs(self, 2);
+ LFRFrame_SetActiveTab(1);
+
+ self.lastInGroup = GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0;
+end
+
+function LFRFrame_OnEvent(self, event, ...)
+ if ( event == "UPDATE_LFG_LIST" ) then
+ if ( LFRBrowseFrame:IsVisible() ) then
+ LFRBrowseFrameList_Update();
+ end
+ elseif ( event == "LFG_UPDATE" or event == "PARTY_MEMBERS_CHANGED" ) then
+ local inParty, joined, queued, noPartialClear, achievements, lfgComment, slotCount = GetLFGInfoServer();
+ local inGroup = GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0;
+ if ( inGroup ~= self.lastInGroup ) then
+ self.lastInGroup = inGroup;
+ LFRQueueFrameComment:SetText("");
+ LFRQueueFrameCommentExplanation:Show();
+ LFRQueueFrameComment:ClearFocus();
+ SetLFGComment("");
+ end
+ if ( not LFR_IsEmpowered() or (not LFRQueueFrameComment:HasFocus() and LFRQueueFrameComment:GetText() == "") ) then
+ if ( joined ) then
+ LFRQueueFrameComment:SetText(lfgComment);
+ if ( strtrim(lfgComment) == "" ) then
+ LFRQueueFrameCommentExplanation:Show();
+ else
+ LFRQueueFrameCommentExplanation:Hide();
+ end
+ end
+ LFRQueueFrameComment:ClearFocus();
+ end
+ end
+end
+
+function LFRQueueFrameFindGroupButton_Update()
+ local mode, subMode = GetLFGMode();
+ if ( mode == "listed" ) then
+ if ( GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0 ) then
+ LFRQueueFrameFindGroupButton:SetText(UNLIST_MY_GROUP);
+ LFDQueueFrameNoLFDWhileLFRLeaveQueueButton:SetText(UNLIST_MY_GROUP);
+ else
+ LFRQueueFrameFindGroupButton:SetText(UNLIST_ME);
+ LFDQueueFrameNoLFDWhileLFRLeaveQueueButton:SetText(UNLIST_ME);
+ end
+ else
+ if ( GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0 ) then
+ LFRQueueFrameFindGroupButton:SetText(LIST_MY_GROUP);
+ else
+ LFRQueueFrameFindGroupButton:SetText(LIST_ME);
+ end
+ end
+
+ if ( LFR_IsEmpowered() and mode ~= "proposal" and mode ~= "queued" and mode ~= "rolecheck" and (not LFRRaidList or LFRRaidList[1])) then --During the proposal, they must use the proposal buttons to leave the queue.
+ LFRQueueFrameFindGroupButton:Enable();
+ LFRQueueFrameAcceptCommentButton:Enable();
+ LFDQueueFrameNoLFDWhileLFRLeaveQueueButton:Enable();
+ else
+ LFRQueueFrameFindGroupButton:Disable();
+ LFRQueueFrameAcceptCommentButton:Disable();
+ LFDQueueFrameNoLFDWhileLFRLeaveQueueButton:Disable();
+ end
+end
+
+function LFR_CanQueueForLockedInstances()
+ return GetNumPartyMembers() > 0 or GetNumRaidMembers() > 0;
+end
+
+function LFR_CanQueueForMultiple()
+ return (GetNumPartyMembers() == 0 and GetNumRaidMembers() == 0);
+end
+
+function LFRQueueFrame_SetRoles()
+ local leader, tank, healer, damage = GetLFGRoles();
+
+ SetLFGRoles(leader,
+ LFRQueueFrameRoleButtonTank.checkButton:GetChecked(),
+ LFRQueueFrameRoleButtonHealer.checkButton:GetChecked(),
+ LFRQueueFrameRoleButtonDPS.checkButton:GetChecked());
+end
+
+function LFRFrameRoleCheckButton_OnClick(self)
+ LFRQueueFrame_SetRoles();
+end
+
+function LFRQueueFrameDungeonChoiceEnableButton_OnClick(self, button)
+ local parent = self:GetParent();
+ local dungeonID = parent.id;
+ local isChecked = self:GetChecked();
+
+ PlaySound(isChecked and "igMainMenuOptionCheckBoxOff" or "igMainMenuOptionCheckBoxOff");
+ if ( LFGIsIDHeader(dungeonID) ) then
+ LFRList_SetHeaderEnabled(dungeonID, isChecked);
+ elseif ( LFR_CanQueueForMultiple() ) then
+ LFRList_SetRaidEnabled(dungeonID, isChecked);
+ LFGListUpdateHeaderEnabledAndLockedStates(LFRRaidList, LFGEnabledList, LFGLockList, LFRHiddenByCollapseList);
+ else
+ LFRQueueFrame.selectedLFM = dungeonID;
+ end
+
+ LFRQueueFrameSpecificList_Update();
+end
+
+function LFRQueueFrameExpandOrCollapseButton_OnClick(self, button)
+ local parent = self:GetParent();
+ LFRList_SetHeaderCollapsed(parent.id, not parent.isCollapsed);
+end
+
+function LFRList_SetRaidEnabled(dungeonID, isEnabled)
+ SetLFGDungeonEnabled(dungeonID, isEnabled);
+ LFGEnabledList[dungeonID] = not not isEnabled; --Change to true/false
+end
+
+function LFRList_SetHeaderEnabled(headerID, isEnabled)
+ for _, dungeonID in pairs(LFRRaidList) do
+ if ( LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.groupID] == headerID ) then
+ LFRList_SetRaidEnabled(dungeonID, isEnabled);
+ end
+ end
+ for _, dungeonID in pairs(LFRHiddenByCollapseList) do
+ if ( LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.groupID] == headerID ) then
+ LFRList_SetRaidEnabled(dungeonID, isEnabled);
+ end
+ end
+ LFGEnabledList[headerID] = not not isEnabled; --Change to true/false
+end
+
+
+function LFRList_SetHeaderCollapsed(headerID, isCollapsed)
+ SetLFGHeaderCollapsed(headerID, isCollapsed);
+ LFGCollapseList[headerID] = isCollapsed;
+ for _, dungeonID in pairs(LFRRaidList) do
+ if ( LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.groupID] == headerID ) then
+ LFGCollapseList[dungeonID] = isCollapsed;
+ end
+ end
+ for _, dungeonID in pairs(LFRHiddenByCollapseList) do
+ if ( LFGGetDungeonInfoByID(dungeonID)[LFG_RETURN_VALUES.groupID] == headerID ) then
+ LFGCollapseList[dungeonID] = isCollapsed;
+ end
+ end
+ LFRQueueFrame_Update();
+end
+
+--List functions
+function LFRQueueFrameSpecificListButton_SetDungeon(button, dungeonID, mode, submode)
+ local info = LFGGetDungeonInfoByID(dungeonID);
+ button.id = dungeonID;
+ if ( LFGIsIDHeader(dungeonID) ) then
+ local name = info[LFG_RETURN_VALUES.name];
+
+ button.instanceName:SetText(name);
+ button.instanceName:SetFontObject(QuestDifficulty_Header);
+ button.instanceName:SetPoint("RIGHT", button, "RIGHT", 0, 0);
+ button.level:Hide();
+
+ if ( info[LFG_RETURN_VALUES.typeID] == TYPEID_HEROIC_DIFFICULTY ) then
+ button.heroicIcon:Show();
+ button.instanceName:SetPoint("LEFT", button.heroicIcon, "RIGHT", 0, 1);
+ else
+ button.heroicIcon:Hide();
+ button.instanceName:SetPoint("LEFT", 40, 0);
+ end
+
+ button.expandOrCollapseButton:Show();
+ local isCollapsed = LFGCollapseList[dungeonID];
+ button.isCollapsed = isCollapsed;
+ if ( isCollapsed ) then
+ button.expandOrCollapseButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-UP");
+ else
+ button.expandOrCollapseButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP");
+ end
+
+ else
+ local name = info[LFG_RETURN_VALUES.name];
+ local minLevel, maxLevel = info[LFG_RETURN_VALUES.minLevel], info[LFG_RETURN_VALUES.maxLevel];
+ local minRecLevel, maxRecLevel = info[LFG_RETURN_VALUES.minRecLevel], info[LFG_RETURN_VALUES.maxRecLevel];
+ local recLevel = info[LFG_RETURN_VALUES.recLevel];
+
+ button.instanceName:SetText(name);
+ button.instanceName:SetPoint("RIGHT", button.level, "LEFT", -10, 0);
+
+ button.heroicIcon:Hide();
+ button.instanceName:SetPoint("LEFT", 40, 0);
+
+ if ( minLevel == maxLevel ) then
+ button.level:SetText(format(LFD_LEVEL_FORMAT_SINGLE, minLevel));
+ else
+ button.level:SetText(format(LFD_LEVEL_FORMAT_RANGE, minLevel, maxLevel));
+ end
+ button.level:Show();
+ local difficultyColor = GetQuestDifficultyColor(recLevel);
+ button.level:SetFontObject(difficultyColor.font);
+
+ if ( mode == "rolecheck" or mode == "queued" or mode == "listed" or not LFR_IsEmpowered()) then
+ button.instanceName:SetFontObject(QuestDifficulty_Header);
+ else
+ button.instanceName:SetFontObject(difficultyColor.font);
+ end
+
+
+ button.expandOrCollapseButton:Hide();
+
+ button.isCollapsed = false;
+ end
+
+ --Could probably use being refactored.
+ if ( not LFR_CanQueueForLockedInstances() and LFGLockList[dungeonID] ) then
+ button.enableButton:Hide();
+ button.lockedIndicator:Show();
+ else
+ if ( LFR_CanQueueForMultiple() ) then
+ button.enableButton:Show();
+ LFGSpecificChoiceEnableButton_SetIsRadio(button.enableButton, false);
+ else
+ if ( LFGIsIDHeader(dungeonID) ) then
+ button.enableButton:Hide();
+ else
+ button.enableButton:Show();
+ LFGSpecificChoiceEnableButton_SetIsRadio(button.enableButton, true);
+ end
+ end
+ button.lockedIndicator:Hide();
+ end
+
+ local enableState;
+ if ( mode == "queued" or mode == "listed" ) then
+ enableState = LFGQueuedForList[dungeonID];
+ elseif ( not LFR_CanQueueForMultiple() ) then
+ enableState = dungeonID == LFRQueueFrame.selectedLFM;
+ else
+ enableState = LFGEnabledList[dungeonID];
+ end
+
+ if ( LFR_CanQueueForMultiple() ) then
+ if ( enableState == 1 ) then --Some are checked, some aren't.
+ button.enableButton:SetCheckedTexture("Interface\\Buttons\\UI-MultiCheck-Up");
+ button.enableButton:SetDisabledCheckedTexture("Interface\\Buttons\\UI-MultiCheck-Disabled");
+ else
+ button.enableButton:SetCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check");
+ button.enableButton:SetDisabledCheckedTexture("Interface\\Buttons\\UI-CheckBox-Check-Disabled");
+ end
+ button.enableButton:SetChecked(enableState and enableState ~= 0);
+ else
+ button.enableButton:SetChecked(enableState);
+ end
+
+ if ( mode == "rolecheck" or mode == "queued" or mode == "listed" or not LFR_IsEmpowered() ) then
+ button.enableButton:Disable();
+ else
+ button.enableButton:Enable();
+ end
+end
+
+
+function LFRQueueFrameSpecificList_Update()
+ if ( LFGDungeonList_Setup() ) then
+ return; --Setup will update the list.
+ end
+ FauxScrollFrame_Update(LFRQueueFrameSpecificListScrollFrame, LFRGetNumDungeons(), NUM_LFR_CHOICE_BUTTONS, 16);
+
+ local offset = FauxScrollFrame_GetOffset(LFRQueueFrameSpecificListScrollFrame);
+
+ local areButtonsBig = not LFRQueueFrameSpecificListScrollFrame:IsShown();
+
+ local mode, subMode = GetLFGMode();
+
+ for i = 1, NUM_LFR_CHOICE_BUTTONS do
+ local button = _G["LFRQueueFrameSpecificListButton"..i];
+ local dungeonID = LFRRaidList[i+offset];
+ if ( dungeonID ) then
+ button:Show();
+ if ( areButtonsBig ) then
+ button:SetWidth(315);
+ else
+ button:SetWidth(295);
+ end
+ LFRQueueFrameSpecificListButton_SetDungeon(button, dungeonID, mode, subMode);
+ else
+ button:Hide();
+ end
+ end
+
+ if ( LFRRaidList[1] ) then
+ LFRQueueFrameSpecificNoRaidsAvailable:Hide();
+ else
+ LFRQueueFrameSpecificNoRaidsAvailable:Show();
+ end
+end
+
+function LFRQueueFrame_QueueForInstanceIfEnabled(queueID)
+ if ( not LFGIsIDHeader(queueID) and LFGEnabledList[queueID] and (LFR_CanQueueForLockedInstances() or not LFGLockList[queueID]) ) then
+ local info = LFGGetDungeonInfoByID(queueID);
+ SetLFGDungeon(queueID);
+ return true;
+ end
+ return false;
+end
+
+function LFRQueueFrame_Join()
+ ClearAllLFGDungeons();
+
+ if ( LFR_CanQueueForMultiple() ) then
+ for _, queueID in pairs(LFRRaidList) do
+ LFRQueueFrame_QueueForInstanceIfEnabled(queueID);
+ end
+ for _, queueID in pairs(LFRHiddenByCollapseList) do
+ LFRQueueFrame_QueueForInstanceIfEnabled(queueID);
+ end
+ else
+ if ( LFRQueueFrame.selectedLFM ) then
+ SetLFGDungeon(LFRQueueFrame.selectedLFM);
+ end
+ end
+
+ if ( LFRQueueFrameComment:HasFocus() ) then
+ LFRQueueFrameComment:ClearFocus();
+ else
+ SetLFGComment(LFRQueueFrameComment:GetText());
+ end
+ JoinLFG();
+end
+
+LFRHiddenByCollapseList = {};
+function LFRQueueFrame_Update()
+ local enableList;
+
+ local mode, submode = GetLFGMode();
+ if ( LFR_IsEmpowered() and mode ~= "listed") then
+ enableList = LFGEnabledList;
+ else
+ enableList = LFGQueuedForList;
+ end
+
+ LFRRaidList = GetLFRChoiceOrder(LFRRaidList);
+
+ LFGQueueFrame_UpdateLFGDungeonList(LFRRaidList, LFRHiddenByCollapseList, LFGLockList, LFGDungeonInfo, enableList, LFGCollapseList, LFR_CURRENT_FILTER);
+
+ LFRQueueFrameSpecificList_Update();
+end
+
+function LFRList_DefaultFilterFunction(dungeonID)
+ local info = LFGGetDungeonInfoByID(dungeonID)
+ local hasHeader = info[LFG_RETURN_VALUES.groupID] ~= 0;
+ local sufficientExpansion = EXPANSION_LEVEL >= info[LFG_RETURN_VALUES.expansionLevel];
+ local level = UnitLevel("player");
+ local sufficientLevel = level >= info[LFG_RETURN_VALUES.minLevel] and level <= info[LFG_RETURN_VALUES.maxLevel];
+ return (hasHeader and sufficientExpansion and sufficientLevel) and
+ ( level - LFR_MAX_SHOWN_LEVEL_DIFF <= info[LFG_RETURN_VALUES.recLevel] or (LFGLockList and not LFGLockList[dungeonID])); --If the server tells us we can join, who are we to complain?
+end
+
+LFR_CURRENT_FILTER = LFRList_DefaultFilterFunction;
+
+-----------------------------------------------------------------------
+-----------------------LFR Browsing--------------------------------
+-----------------------------------------------------------------------
+local browseFrameLocal;
+function LFRBrowseFrame_OnLoad(self)
+ browseFrameLocal = self;
+end
+
+function LFRBrowseFrame_OnUpdateAlways(elapsed) --Actually called in UIParent_OnUpdate so that it can run while LFRBrowseFrame is hidden.
+ local timeToClear = browseFrameLocal.timeToClear;
+ if ( timeToClear ) then
+ if ( timeToClear < 0 ) then
+ SearchLFGLeave();
+ --We don't really have to do any of the other work done by SetSelectedValue, so why do it?
+ LFRBrowseFrameRaidDropDownText:SetText(NONE);
+ browseFrameLocal.timeToClear = nil;
+ else
+ browseFrameLocal.timeToClear = timeToClear - elapsed;
+ end
+ end
+end
+
+--We construct the list. This should only need to be called once (since we don't filter or change it), so we don't much worry about 1 garbage table.
+function GetFullRaidList()
+ LFGDungeonList_Setup();
+
+ local headerOrder = {};
+ local list = {};
+
+ local tempList = GetLFRChoiceOrder();
+ LFGListRemoveHeadersWithoutChildren(tempList);
+
+ for i=1, #tempList do
+ local id = tempList[i];
+ if ( LFGIsIDHeader(tempList[i]) ) then
+ tinsert(headerOrder, id);
+ list[tempList[i]] = {};
+ else
+ local parentID = LFGGetDungeonInfoByID(id)[LFG_RETURN_VALUES.groupID];
+ if ( parentID ~= 0 ) then
+ local parentTable = list[parentID];
+ tinsert(parentTable, id);
+ end
+ end
+ end
+ return headerOrder, list;
+end
+
+function LFRBrowseFrameRaidDropDown_SetUp(self)
+ UIDropDownMenu_SetWidth(self, 140);
+ UIDropDownMenu_Initialize(self, LFRBrowseFrameRaidDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(LFRBrowseFrameRaidDropDown, SearchLFGGetJoinedID() or "none");
+end
+
+function LFRBrowseFrameRaidDropDown_Initialize(self, level)
+ LFGDungeonList_Setup();
+ if ( not LFR_FULL_RAID_LIST_HEADER_ORDER ) then
+ LFR_FULL_RAID_LIST_HEADER_ORDER, LFR_FULL_RAID_LIST = GetFullRaidList();
+ end
+
+ local activeSearching = SearchLFGGetJoinedID() or "none";
+
+ local info = UIDropDownMenu_CreateInfo();
+
+ if ( not level or level == 1 ) then
+ info.text = NONE;
+ info.value = "none";
+ info.func = LFRBrowseFrameRaidDropDownButton_OnClick;
+ info.checked = activeSearching == info.value;
+ UIDropDownMenu_AddButton(info);
+
+ for _, groupID in ipairs(LFR_FULL_RAID_LIST_HEADER_ORDER) do
+ info.text = LFGGetDungeonInfoByID(groupID)[LFG_RETURN_VALUES.name];
+ info.value = groupID;
+ info.func = nil;
+ info.hasArrow = true;
+ info.checked = false;
+ UIDropDownMenu_AddButton(info, 1);
+ end
+ elseif ( level == 2 ) then
+ for _, dungeonID in ipairs(LFR_FULL_RAID_LIST[UIDROPDOWNMENU_MENU_VALUE]) do
+ local info = LFGGetDungeonInfoByID(dungeonID);
+ local maxPlayers = format(LFD_LEVEL_FORMAT_SINGLE, info[LFG_RETURN_VALUES.maxPlayers]);
+ info.text = maxPlayers.." "..info[LFG_RETURN_VALUES.name];
+ info.value = dungeonID;
+ info.func = LFRBrowseFrameRaidDropDownButton_OnClick;
+ info.checked = activeSearching == info.value;
+ UIDropDownMenu_AddButton(info, level);
+ end
+ end
+end
+
+function LFRBrowseFrameRaidDropDownButton_OnClick(self)
+ LFRBrowseFrameRaidDropDown.activeValue = self.value;
+ UIDropDownMenu_SetSelectedValue(LFRBrowseFrameRaidDropDown, self.value);
+ HideDropDownMenu(1); --Hide the category menu. It gets annoying.
+ if ( self.value == "none" ) then
+ SearchLFGLeave();
+ else
+ SearchLFGJoin(LFGGetDungeonInfoByID(self.value)[LFG_RETURN_VALUES.typeID], self.value);
+ end
+end
+
+function LFRFrame_SetActiveTab(tab)
+ if ( tab == 1 ) then
+ LFRParentFrame.activeTab = 1;
+ LFRQueueFrame:Show();
+ LFRBrowseFrame:Hide();
+ elseif ( tab == 2 ) then
+ LFRParentFrame.activeTab = 2;
+ LFRBrowseFrame:Show();
+ LFRQueueFrame:Hide();
+ end
+ PanelTemplates_SetTab(LFRParentFrame, tab);
+end
+
+function LFRBrowseFrameRefreshButton_OnUpdate(self, elapsed)
+ local timeLeft = self.timeUntilNextRefresh;
+ if ( timeLeft ) then
+ self.timeUntilNextRefresh = timeLeft - elapsed;
+ if ( self.timeUntilNextRefresh <= 0 ) then
+ RefreshLFGList();
+ end
+ end
+end
+
+function LFRBrowseFrameList_Update()
+ LFRBrowseFrameRefreshButton.timeUntilNextRefresh = LFR_BROWSE_AUTO_REFRESH_TIME;
+
+ local numResults, totalResults = SearchLFGGetNumResults();
+ FauxScrollFrame_Update(LFRBrowseFrameListScrollFrame, numResults, NUM_LFR_LIST_BUTTONS, 16);
+
+ local offset = FauxScrollFrame_GetOffset(LFRBrowseFrameListScrollFrame);
+
+ for i=1, NUM_LFR_LIST_BUTTONS do
+ local button = _G["LFRBrowseFrameListButton"..i];
+ if ( i <= numResults ) then
+ LFRBrowseFrameListButton_SetData(button, i + offset);
+ button:Show();
+ else
+ button:Hide();
+ end
+ end
+
+ if ( LFRBrowseFrame.selectedName ) then
+ local nameStillThere = false;
+ for i=1, numResults do
+ local name = SearchLFGGetResults(i);
+ if ( LFRBrowseFrame.selectedName == name ) then
+ nameStillThere = true;
+ break;
+ end
+ end
+ if ( not nameStillThere ) then
+ LFRBrowseFrame.selectedName = nil;
+ end
+ end
+
+ LFRBrowse_UpdateButtonStates();
+end
+
+function LFRBrowseFrameListButton_SetData(button, index)
+ local name, level, areaName, className, comment, partyMembers, status, class, encountersTotal, encountersComplete, isLeader, isTank, isHealer, isDamage = SearchLFGGetResults(index);
+
+ button.index = index;
+ button.unitName = name;
+ if ( LFRBrowseFrame.selectedName == name ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+ button.name:SetText(name);
+
+ button.level:SetText(level);
+
+ local classTextColor;
+ if ( class ) then
+ classTextColor = RAID_CLASS_COLORS[class];
+ else
+ classTextColor = NORMAL_FONT_COLOR;
+ end
+ button.class:SetText(className);
+ button.class:SetTextColor(classTextColor.r, classTextColor.g, classTextColor.b);
+
+
+ if ( partyMembers > 0 ) then
+ button.type = "party";
+ button.partyIcon:Show();
+ button.tankIcon:Hide();
+ button.healerIcon:Hide();
+ button.damageIcon:Hide();
+ else
+ button.type = "individual";
+ button.partyIcon:Hide();
+
+ if ( isTank ) then
+ button.tankIcon:Show()
+ else
+ button.tankIcon:Hide();
+ end
+
+ if ( isHealer ) then
+ button.healerIcon:Show();
+ else
+ button.healerIcon:Hide();
+ end
+
+ if ( isDamage ) then
+ button.damageIcon:Show();
+ else
+ button.damageIcon:Hide();
+ end
+ end
+
+ if ( name == UnitName("player") ) then
+ button:Disable();
+ button.name:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b)
+ button.level:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ button.class:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ button.tankIcon:SetTexture("Interface\\LFGFrame\\LFGRole_BW");
+ button.healerIcon:SetTexture("Interface\\LFGFrame\\LFGRole_BW");
+ button.damageIcon:SetTexture("Interface\\LFGFrame\\LFGRole_BW");
+ button.partyIcon:SetTexture("Interface\\LFGFrame\\LFGRole_BW");
+ else
+ button:Enable();
+ button.name:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b)
+ button.level:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ button.tankIcon:SetTexture("Interface\\LFGFrame\\LFGRole");
+ button.healerIcon:SetTexture("Interface\\LFGFrame\\LFGRole");
+ button.damageIcon:SetTexture("Interface\\LFGFrame\\LFGRole");
+ button.partyIcon:SetTexture("Interface\\LFGFrame\\LFGRole");
+ end
+end
+
+function LFRBrowseButton_OnEnter(self)
+ local name, level, areaName, className, comment, partyMembers, status, class, encountersTotal, encountersComplete, isLeader, isTank, isHealer, isDamage = SearchLFGGetResults(self.index);
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT", 27, -37);
+
+ if ( partyMembers > 0 ) then
+ GameTooltip:AddLine(LOOKING_FOR_RAID);
+
+ GameTooltip:AddLine(name);
+ GameTooltip:AddTexture("Interface\\LFGFrame\\LFGRole", 0, 0.25, 0, 1);
+
+ GameTooltip:AddLine(format(LFM_NUM_RAID_MEMBER_TEMPLATE, partyMembers));
+ -- Bogus texture to fix spacing
+ GameTooltip:AddTexture("");
+
+ --Display ignored party members and friend party members. (You probably won't care about the rest. Though guildys would be nice at some point...)
+ local displayedMembersLabel = false;
+ for i=1, partyMembers do
+ local name, level, relationship, className, areaName, comment = SearchLFGGetPartyResults(self.index, i);
+ if ( relationship ) then
+ if ( not displayedMembersLabel ) then
+ displayedMembersLabel = true;
+ GameTooltip:AddLine("\n"..IMPORTANT_PEOPLE_IN_GROUP);
+ end
+ if ( relationship == "ignored" ) then
+ GameTooltip:AddDoubleLine(name, IGNORED, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ elseif ( relationship == "friend" ) then
+ GameTooltip:AddDoubleLine(name, FRIEND, GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b, GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b);
+ end
+ end
+ end
+ else
+ GameTooltip:AddLine(name);
+ GameTooltip:AddLine(format(FRIENDS_LEVEL_TEMPLATE, level, className));
+ end
+
+ if ( comment and comment ~= "" ) then
+ GameTooltip:AddLine("\n"..comment, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, 1);
+ end
+
+ if ( partyMembers == 0 ) then
+ GameTooltip:AddLine("\n"..LFG_TOOLTIP_ROLES);
+ if ( isTank ) then
+ GameTooltip:AddLine(TANK);
+ GameTooltip:AddTexture("Interface\\LFGFrame\\LFGRole", 0.5, 0.75, 0, 1);
+ end
+ if ( isHealer ) then
+ GameTooltip:AddLine(HEALER);
+ GameTooltip:AddTexture("Interface\\LFGFrame\\LFGRole", 0.75, 1, 0, 1);
+ end
+ if ( isDamage ) then
+ GameTooltip:AddLine(DAMAGER);
+ GameTooltip:AddTexture("Interface\\LFGFrame\\LFGRole", 0.25, 0.5, 0, 1);
+ end
+ end
+
+ if ( encountersComplete > 0 ) then
+ GameTooltip:AddLine("\n"..BOSSES);
+ for i=1, encountersTotal do
+ local bossName, texture, isKilled = SearchLFGGetEncounterResults(self.index, i);
+ if ( isKilled ) then
+ GameTooltip:AddDoubleLine(bossName, BOSS_DEAD, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ else
+ GameTooltip:AddDoubleLine(bossName, BOSS_ALIVE, GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b, GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b);
+ end
+ end
+ elseif ( partyMembers > 0 and encountersTotal > 0) then
+ GameTooltip:AddLine("\n"..ALL_BOSSES_ALIVE);
+ end
+
+ GameTooltip:Show();
+end
+
+--this is used by the static popup for INSTANCE_LOCK_TIMER
+function InstanceLock_OnEnter(self)
+ GameTooltip:SetOwner(self:GetParent(), "ANCHOR_BOTTOM");
+ if ( self.encountersComplete > 0 ) then
+ GameTooltip:SetText(BOSSES);
+ for i=1, self.encountersTotal do
+ local bossName, texture, isKilled = GetInstanceLockTimeRemainingEncounter(i);
+ if ( isKilled ) then
+ GameTooltip:AddDoubleLine(bossName, BOSS_DEAD, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ else
+ GameTooltip:AddDoubleLine(bossName, BOSS_ALIVE, GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b, GREEN_FONT_COLOR.r, GREEN_FONT_COLOR.g, GREEN_FONT_COLOR.b);
+ end
+ end
+ else
+ GameTooltip:SetText(ALL_BOSSES_ALIVE);
+ end
+ GameTooltip:Show();
+end
+
+function LFRBrowseButton_OnClick(self)
+ if ( LFRBrowseFrame.selectedName == self.unitName ) then
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ LFRBrowseFrame.selectedName = nil;
+ LFRBrowseFrame.selectedType = nil;
+ self:UnlockHighlight();
+ else
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ LFRBrowseFrame.selectedName = self.unitName;
+ LFRBrowseFrame.selectedType = self.type;
+ --Unlock all other highlights
+ for i=1, NUM_LFR_LIST_BUTTONS do
+ _G["LFRBrowseFrameListButton"..i]:UnlockHighlight();
+ end
+ self:LockHighlight();
+ end
+ LFRBrowse_UpdateButtonStates();
+end
+
+function LFRBrowse_UpdateButtonStates()
+ local playerName = UnitName("player");
+ local selectedName = LFRBrowseFrame.selectedName;
+
+ if ( selectedName and selectedName ~= playerName ) then
+ LFRBrowseFrameSendMessageButton:Enable();
+ else
+ LFRBrowseFrameSendMessageButton:Disable();
+ end
+
+ if ( selectedName and selectedName ~= playerName and LFRBrowseFrame.selectedType ~= "party" and CanGroupInvite() ) then
+ LFRBrowseFrameInviteButton:Enable();
+ else
+ LFRBrowseFrameInviteButton:Disable();
+ end
+end
\ No newline at end of file
diff --git a/reference/FrameXML/LFRFrame.xml b/reference/FrameXML/LFRFrame.xml
new file mode 100644
index 0000000..b3f205b
--- /dev/null
+++ b/reference/FrameXML/LFRFrame.xml
@@ -0,0 +1,1114 @@
+
+
+
+
+
+
+ if ( self.sortType ) then
+ SearchLFGSort(self.sortType);
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.icon:SetPoint("CENTER", 1, -2);
+
+
+ self.icon:SetPoint("CENTER", 0, 0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.enableButton:SetScript("OnClick", LFRQueueFrameDungeonChoiceEnableButton_OnClick);
+ self.expandOrCollapseButton:SetScript("OnClick", LFRQueueFrameExpandOrCollapseButton_OnClick);
+ self:SetScript("OnEnter", LFDQueueFrameDungeonListButton_OnEnter);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("TANK"));
+ self.background:SetTexCoord(GetBackgroundTexCoordsForRole("TANK"));
+ self.background:SetAlpha(0.6);
+ self.checkButton.onClick = LFRFrameRoleCheckButton_OnClick;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("HEALER"));
+ self.background:SetTexCoord(GetBackgroundTexCoordsForRole("HEALER"));
+ self.background:SetAlpha(0.4);
+ self.checkButton.onClick = LFRFrameRoleCheckButton_OnClick;
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetNormalTexture():SetTexCoord(GetTexCoordsForRole("DAMAGER"));
+ self.background:SetTexCoord(GetBackgroundTexCoordsForRole("DAMAGER"));
+ self.background:SetAlpha(0.6);
+ self.checkButton.onClick = LFRFrameRoleCheckButton_OnClick;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( LFR_IsEmpowered() and (not LFRRaidList or LFRRaidList[1])) then
+ LFRQueueFrameCommentExplanation:Hide();
+ else
+ self:ClearFocus();
+ end
+
+
+ if ( strtrim(self:GetText()) == "" ) then
+ LFRQueueFrameCommentExplanation:Show();
+ end
+ SetLFGComment(self:GetText());
+ PlaySound("UChatScrollButton");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( LFR_IsEmpowered() and (not LFRRaidList or LFRRaidList[1])) then
+ LFRQueueFrameComment:SetFocus();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, 16, LFRQueueFrameSpecificList_Update);
+
+
+
+
+
+
+ LFRQueueFrame_Update();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local mode, subMode = GetLFGMode();
+ if ( mode == "queued" or mode == "listed" or mode == "rolecheck" ) then
+ LeaveLFG();
+ else
+ LFRQueueFrame_Join();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( LFRQueueFrameComment:HasFocus() ) then
+ LFRQueueFrameComment:ClearFocus();
+ else
+ --The comment is already set, so they didn't need to click this... we'll give some feedback anyway.
+ PlaySound("UChatScrollButton");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LeaveLFG();
+
+
+
+
+
+
+ self:SetFrameLevel(10);
+
+
+
+
+
+
+ RequestLFDPlayerLockInfo();
+ RequestLFDPartyLockInfo();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 97);
+ self.sortType = "name";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 34);
+ self.sortType = "level";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 80);
+ self.sortType = "class";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.icon:SetTexCoord(0.5, 0.75, 0, 1);
+ WhoFrameColumn_SetWidth(self, 25);
+ self.sortType = "tank";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.icon:SetTexCoord(0.75, 1, 0, 1);
+ WhoFrameColumn_SetWidth(self, 25);
+ self.sortType = "healer";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.icon:SetTexCoord(0.25, 0.5, 0, 1);
+ WhoFrameColumn_SetWidth(self, 25);
+ self.sortType = "damage";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.icon:SetTexCoord(0, 0.25, 0, 1);
+ WhoFrameColumn_SetWidth(self, 25);
+ self.sortType = "group";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, 16, LFRBrowseFrameList_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("UChatScrollButton");
+ ChatFrame_SendTell(LFRBrowseFrame.selectedName);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("UChatScrollButton");
+ InviteUnit(LFRBrowseFrame.selectedName);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("UChatScrollButton");
+ RefreshLFGList();
+
+
+
+
+
+
+
+
+ RefreshLFGList();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(CHOOSE_RAID, 1.0,1.0,1.0 );
+
+
+ LFRFrame_SetActiveTab(1);
+ PlaySound("igCharacterInfoTab");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(BROWSE, 1.0,1.0,1.0 );
+
+
+ LFRFrame_SetActiveTab(2);
+ PlaySound("igCharacterInfoTab");
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoOpen");
+ LFRBrowseFrame.timeToClear = nil; --Never clear browsing while shown.
+
+
+ PlaySound("igCharacterInfoClose");
+ LFRBrowseFrame.timeToClear = 40; --Clear all browsing after 40 seconds of being hidden.
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/Localization.lua b/reference/FrameXML/Localization.lua
new file mode 100644
index 0000000..b5beaec
--- /dev/null
+++ b/reference/FrameXML/Localization.lua
@@ -0,0 +1,15 @@
+
+-- This is a symbol available for people who need to know the locale (separate from GetLocale())
+LOCALE_enUS = true;
+
+function Localize()
+ -- Put all locale specific string adjustments here
+end
+
+function LocalizeFrames()
+ -- Put all locale specific UI adjustments here
+
+ -- Hide billing help option. If the number of help options changes this will need to change also.
+ CATEGORY_TO_NOT_DISPLAY = 9;
+
+end
diff --git a/reference/FrameXML/Localization.xml b/reference/FrameXML/Localization.xml
new file mode 100644
index 0000000..07fb7b7
--- /dev/null
+++ b/reference/FrameXML/Localization.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/reference/FrameXML/LocalizationPost.lua b/reference/FrameXML/LocalizationPost.lua
new file mode 100644
index 0000000..5625162
--- /dev/null
+++ b/reference/FrameXML/LocalizationPost.lua
@@ -0,0 +1,6 @@
+
+
+
+function LocalizePost()
+ -- Put all locale specific string adjustments here
+end
diff --git a/reference/FrameXML/LocalizationPost.xml b/reference/FrameXML/LocalizationPost.xml
new file mode 100644
index 0000000..a8dea10
--- /dev/null
+++ b/reference/FrameXML/LocalizationPost.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/LootFrame.lua b/reference/FrameXML/LootFrame.lua
new file mode 100644
index 0000000..28fe1b4
--- /dev/null
+++ b/reference/FrameXML/LootFrame.lua
@@ -0,0 +1,412 @@
+LOOTFRAME_NUMBUTTONS = 4;
+NUM_GROUP_LOOT_FRAMES = 4;
+MASTER_LOOT_THREHOLD = 4;
+
+function LootFrame_OnLoad(self)
+ self:RegisterEvent("LOOT_OPENED");
+ self:RegisterEvent("LOOT_SLOT_CLEARED");
+ self:RegisterEvent("LOOT_SLOT_CHANGED");
+ self:RegisterEvent("LOOT_CLOSED");
+ self:RegisterEvent("OPEN_MASTER_LOOT_LIST");
+ self:RegisterEvent("UPDATE_MASTER_LOOT_LIST");
+end
+
+function LootFrame_OnEvent(self, event, ...)
+ if ( event == "LOOT_OPENED" ) then
+ local autoLoot = ...;
+
+ self.page = 1;
+ LootFrame_Show(self);
+ if ( not self:IsShown()) then
+ CloseLoot(autoLoot == 0); -- The parameter tells code that we were unable to open the UI
+ end
+ elseif ( event == "LOOT_SLOT_CLEARED" ) then
+ local arg1 = ...;
+
+ if ( not self:IsShown() ) then
+ return;
+ end
+
+ local numLootToShow = LOOTFRAME_NUMBUTTONS;
+ if ( self.numLootItems > LOOTFRAME_NUMBUTTONS ) then
+ numLootToShow = numLootToShow - 1;
+ end
+ local slot = arg1 - ((self.page - 1) * numLootToShow);
+ if ( (slot > 0) and (slot < (numLootToShow + 1)) ) then
+ local button = _G["LootButton"..slot];
+ if ( button ) then
+ button:Hide();
+ end
+ end
+ -- try to move second page of loot items to the first page
+ local button;
+ local allButtonsHidden = 1;
+
+ for index = 1, LOOTFRAME_NUMBUTTONS do
+ button = _G["LootButton"..index];
+ if ( button:IsShown() ) then
+ allButtonsHidden = nil;
+ end
+ end
+ if ( allButtonsHidden and LootFrameDownButton:IsShown() ) then
+ LootFrame_PageDown();
+ end
+ return;
+ elseif ( event == "LOOT_SLOT_CHANGED" ) then
+ local arg1 = ...;
+
+ if ( not self:IsShown() ) then
+ return;
+ end
+
+ local numLootToShow = LOOTFRAME_NUMBUTTONS;
+ if ( self.numLootItems > LOOTFRAME_NUMBUTTONS ) then
+ numLootToShow = numLootToShow - 1;
+ end
+ local slot = arg1 - ((self.page - 1) * numLootToShow);
+ if ( (slot > 0) and (slot < (numLootToShow + 1)) ) then
+ local button = _G["LootButton"..slot];
+ if ( button ) then
+ LootFrame_UpdateButton(slot);
+ end
+ end
+ elseif ( event == "LOOT_CLOSED" ) then
+ StaticPopup_Hide("LOOT_BIND");
+ HideUIPanel(self);
+ return;
+ elseif ( event == "OPEN_MASTER_LOOT_LIST" ) then
+ ToggleDropDownMenu(1, nil, GroupLootDropDown, LootFrame.selectedLootButton, 0, 0);
+ return;
+ elseif ( event == "UPDATE_MASTER_LOOT_LIST" ) then
+ UIDropDownMenu_Refresh(GroupLootDropDown);
+ end
+end
+
+function LootFrame_UpdateButton(index)
+ local numLootItems = LootFrame.numLootItems;
+ --Logic to determine how many items to show per page
+ local numLootToShow = LOOTFRAME_NUMBUTTONS;
+ if ( numLootItems > LOOTFRAME_NUMBUTTONS ) then
+ numLootToShow = numLootToShow - 1;
+ end
+
+ local button = _G["LootButton"..index];
+ local slot = (numLootToShow * (LootFrame.page - 1)) + index;
+ if ( slot <= numLootItems ) then
+ if ( (LootSlotIsItem(slot) or LootSlotIsCoin(slot)) and index <= numLootToShow ) then
+ local texture, item, quantity, quality, locked = GetLootSlotInfo(slot);
+ local color = ITEM_QUALITY_COLORS[quality];
+ _G["LootButton"..index.."IconTexture"]:SetTexture(texture);
+ local text = _G["LootButton"..index.."Text"];
+ text:SetText(item);
+ if( locked ) then
+ SetItemButtonNameFrameVertexColor(button, 1.0, 0, 0);
+ SetItemButtonTextureVertexColor(button, 0.9, 0, 0);
+ SetItemButtonNormalTextureVertexColor(button, 0.9, 0, 0);
+ else
+ SetItemButtonNameFrameVertexColor(button, 0.5, 0.5, 0.5);
+ SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0);
+ end
+ text:SetVertexColor(color.r, color.g, color.b);
+ local countString = _G["LootButton"..index.."Count"];
+ if ( quantity > 1 ) then
+ countString:SetText(quantity);
+ countString:Show();
+ else
+ countString:Hide();
+ end
+ button.slot = slot;
+ button.quality = quality;
+ button:Show();
+ else
+ button:Hide();
+ end
+ else
+ button:Hide();
+ end
+end
+
+function LootFrame_Update()
+ for index = 1, LOOTFRAME_NUMBUTTONS do
+ LootFrame_UpdateButton(index);
+ end
+ if ( LootFrame.page == 1 ) then
+ LootFrameUpButton:Hide();
+ LootFramePrev:Hide();
+ else
+ LootFrameUpButton:Show();
+ LootFramePrev:Show();
+ end
+ local numItemsPerPage = LOOTFRAME_NUMBUTTONS;
+ if ( LootFrame.numLootItems > LOOTFRAME_NUMBUTTONS ) then
+ numItemsPerPage = numItemsPerPage - 1;
+ end
+ if ( LootFrame.page == ceil(LootFrame.numLootItems / numItemsPerPage) or LootFrame.numLootItems == 0 ) then
+ LootFrameDownButton:Hide();
+ LootFrameNext:Hide();
+ else
+ LootFrameDownButton:Show();
+ LootFrameNext:Show();
+ end
+end
+
+function LootFrame_PageDown()
+ LootFrame.page = LootFrame.page + 1;
+ LootFrame_Update();
+end
+
+function LootFrame_PageUp()
+ LootFrame.page = LootFrame.page - 1;
+ LootFrame_Update();
+end
+
+function LootFrame_Show(self)
+ ShowUIPanel(self);
+ self.numLootItems = GetNumLootItems();
+
+ if ( GetCVar("lootUnderMouse") == "1" ) then
+ -- position loot window under mouse cursor
+ local x, y = GetCursorPosition();
+ x = x / self:GetEffectiveScale();
+ y = y / self:GetEffectiveScale();
+
+ local posX = x - 175;
+ local posY = y + 25;
+
+ if (self.numLootItems > 0) then
+ posX = x - 40;
+ posY = y + 55;
+ posY = posY + 40;
+ end
+
+ if( posY < 350 ) then
+ posY = 350;
+ end
+
+ self:ClearAllPoints();
+ self:SetPoint("TOPLEFT", nil, "BOTTOMLEFT", posX, posY);
+ self:GetCenter();
+ self:Raise();
+ end
+
+ LootFrame_Update();
+ LootFramePortraitOverlay:SetTexture("Interface\\TargetingFrame\\TargetDead");
+end
+
+function LootFrame_OnShow(self)
+ if( self.numLootItems == 0 ) then
+ PlaySound("LOOTWINDOWOPENEMPTY");
+ elseif( IsFishingLoot() ) then
+ PlaySound("FISHING REEL IN");
+ LootFramePortraitOverlay:SetTexture("Interface\\LootFrame\\FishingLoot-Icon");
+ end
+end
+
+function LootFrame_OnHide()
+ CloseLoot();
+ -- Close any loot distribution confirmation windows
+ StaticPopup_Hide("CONFIRM_LOOT_DISTRIBUTION");
+end
+
+function LootButton_OnClick(self, button)
+ -- Close any loot distribution confirmation windows
+ StaticPopup_Hide("CONFIRM_LOOT_DISTRIBUTION");
+
+ LootFrame.selectedLootButton = self:GetName();
+ LootFrame.selectedSlot = self.slot;
+ LootFrame.selectedQuality = self.quality;
+ LootFrame.selectedItemName = _G[self:GetName().."Text"]:GetText();
+
+ LootSlot(self.slot);
+end
+
+function LootItem_OnEnter(self)
+ local slot = ((LOOTFRAME_NUMBUTTONS - 1) * (LootFrame.page - 1)) + self:GetID();
+ if ( LootSlotIsItem(slot) ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetLootItem(slot);
+ CursorUpdate(self);
+ end
+end
+
+function GroupLootDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, GroupLootDropDown_Initialize, "MENU");
+end
+
+function GroupLootDropDown_Initialize()
+ local candidate;
+ local info = UIDropDownMenu_CreateInfo();
+
+ if ( UIDROPDOWNMENU_MENU_LEVEL == 2 ) then
+ local lastIndex = UIDROPDOWNMENU_MENU_VALUE + 5 - 1;
+ for i=UIDROPDOWNMENU_MENU_VALUE, lastIndex do
+ candidate = GetMasterLootCandidate(i);
+ if ( candidate ) then
+ -- Add candidate button
+ info.text = candidate;
+ info.fontObject = GameFontNormalLeft;
+ info.value = i;
+ info.notCheckable = 1;
+ info.func = GroupLootDropDown_GiveLoot;
+ UIDropDownMenu_AddButton(info,UIDROPDOWNMENU_MENU_LEVEL);
+ end
+ end
+ return;
+ end
+
+ if ( GetNumRaidMembers() > 0 ) then
+ -- In a raid
+ info.isTitle = 1;
+ info.text = GIVE_LOOT;
+ info.fontObject = GameFontNormalLeft;
+ info.notCheckable = 1;
+ UIDropDownMenu_AddButton(info);
+
+ for i=1, 40, 5 do
+ for j=i, i+4 do
+ candidate = GetMasterLootCandidate(j);
+ if ( candidate ) then
+ -- Add raid group
+ info.isTitle = nil;
+ info.text = GROUP.." "..ceil(i/5);
+ info.fontObject = GameFontNormalLeft;
+ info.hasArrow = 1;
+ info.notCheckable = 1;
+ info.value = j;
+ info.func = nil;
+ UIDropDownMenu_AddButton(info);
+ break;
+ end
+ end
+ end
+ else
+ -- In a party
+ for i=1, MAX_PARTY_MEMBERS+1, 1 do
+ candidate = GetMasterLootCandidate(i);
+ if ( candidate ) then
+ -- Add candidate button
+ info.text = candidate;
+ info.fontObject = GameFontNormalLeft;
+ info.value = i;
+ info.notCheckable = 1;
+ info.value = i;
+ info.func = GroupLootDropDown_GiveLoot;
+ UIDropDownMenu_AddButton(info);
+ end
+ end
+ end
+end
+
+function GroupLootDropDown_GiveLoot(self)
+ if ( LootFrame.selectedQuality >= MASTER_LOOT_THREHOLD ) then
+ local dialog = StaticPopup_Show("CONFIRM_LOOT_DISTRIBUTION", ITEM_QUALITY_COLORS[LootFrame.selectedQuality].hex..LootFrame.selectedItemName..FONT_COLOR_CODE_CLOSE, self:GetText());
+ if ( dialog ) then
+ dialog.data = self.value;
+ end
+ else
+ GiveMasterLoot(LootFrame.selectedSlot, self.value);
+ end
+ CloseDropDownMenus();
+end
+
+function GroupLootFrame_OpenNewFrame(id, rollTime)
+ local frame;
+ for i=1, NUM_GROUP_LOOT_FRAMES do
+ frame = _G["GroupLootFrame"..i];
+ if ( not frame:IsShown() ) then
+ frame.rollID = id;
+ frame.rollTime = rollTime;
+ _G["GroupLootFrame"..i.."Timer"]:SetMinMaxValues(0, rollTime);
+ frame:Show();
+ return;
+ end
+ end
+end
+
+function GroupLootFrame_EnableLootButton(button)
+ button:Enable();
+ button:SetAlpha(1.0);
+ SetDesaturation(button:GetNormalTexture(), false);
+end
+
+function GroupLootFrame_DisableLootButton(button)
+ button:Disable();
+ button:SetAlpha(0.35);
+ SetDesaturation(button:GetNormalTexture(), true);
+end
+
+function GroupLootFrame_OnShow(self)
+ AlertFrame_FixAnchors();
+ local texture, name, count, quality, bindOnPickUp, canNeed, canGreed, canDisenchant, reasonNeed, reasonGreed, reasonDisenchant, deSkillRequired = GetLootRollItemInfo(self.rollID);
+ if (name == nil) then
+ self:Hide();
+ return;
+ end
+ if ( bindOnPickUp ) then
+ self:SetBackdrop({bgFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Background", edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Gold-Border", tile = true, tileSize = 32, edgeSize = 32, insets = { left = 11, right = 12, top = 12, bottom = 11 } } );
+ _G[self:GetName().."Corner"]:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Gold-Corner");
+ _G[self:GetName().."Decoration"]:Show();
+ else
+ self:SetBackdrop({bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", tile = true, tileSize = 32, edgeSize = 32, insets = { left = 11, right = 12, top = 12, bottom = 11 } } );
+ _G[self:GetName().."Corner"]:SetTexture("Interface\\DialogFrame\\UI-DialogBox-Corner");
+ _G[self:GetName().."Decoration"]:Hide();
+ end
+
+ local id = self:GetID();
+ _G["GroupLootFrame"..id.."IconFrameIcon"]:SetTexture(texture);
+ _G["GroupLootFrame"..id.."Name"]:SetText(name);
+ local color = ITEM_QUALITY_COLORS[quality];
+ _G["GroupLootFrame"..id.."Name"]:SetVertexColor(color.r, color.g, color.b);
+ if ( count > 1 ) then
+ _G["GroupLootFrame"..id.."IconFrameCount"]:SetText(count);
+ _G["GroupLootFrame"..id.."IconFrameCount"]:Show();
+ else
+ _G["GroupLootFrame"..id.."IconFrameCount"]:Hide();
+ end
+
+ if ( canNeed ) then
+ GroupLootFrame_EnableLootButton(self.needButton);
+ self.needButton.reason = nil;
+ else
+ GroupLootFrame_DisableLootButton(self.needButton);
+ self.needButton.reason = _G["LOOT_ROLL_INELIGIBLE_REASON"..reasonNeed];
+ end
+ if ( canGreed) then
+ GroupLootFrame_EnableLootButton(self.greedButton);
+ self.greedButton.reason = nil;
+ else
+ GroupLootFrame_DisableLootButton(self.greedButton);
+ self.greedButton.reason = _G["LOOT_ROLL_INELIGIBLE_REASON"..reasonGreed];
+ end
+ if ( canDisenchant) then
+ GroupLootFrame_EnableLootButton(self.disenchantButton);
+ self.disenchantButton.reason = nil;
+ else
+ GroupLootFrame_DisableLootButton(self.disenchantButton);
+ self.disenchantButton.reason = format(_G["LOOT_ROLL_INELIGIBLE_REASON"..reasonDisenchant], deSkillRequired);
+ end
+end
+
+function GroupLootFrame_OnHide (self)
+ AlertFrame_FixAnchors();
+end
+
+function GroupLootFrame_OnEvent(self, event, ...)
+ if ( event == "CANCEL_LOOT_ROLL" ) then
+ local arg1 = ...;
+ if ( arg1 == self.rollID ) then
+ self:Hide();
+ StaticPopup_Hide("CONFIRM_LOOT_ROLL", self.rollID);
+ end
+ end
+end
+
+function GroupLootFrame_OnUpdate(self, elapsed)
+ local left = GetLootRollTimeLeft(self:GetParent().rollID);
+ local min, max = self:GetMinMaxValues();
+ if ( (left < min) or (left > max) ) then
+ left = min;
+ end
+ self:SetValue(left);
+end
diff --git a/reference/FrameXML/LootFrame.xml b/reference/FrameXML/LootFrame.xml
new file mode 100644
index 0000000..c611603
--- /dev/null
+++ b/reference/FrameXML/LootFrame.xml
@@ -0,0 +1,553 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self.hasItem = 1;
+
+
+ LootItem_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ LootItem_OnEnter(self);
+ end
+ CursorOnUpdate(self);
+
+
+ if ( IsModifiedClick() ) then
+ HandleModifiedItemClick(GetLootSlotLink(self.slot));
+ else
+ LootButton_OnClick(self, button);
+ end
+
+
+
+
+
+
+
+
+
+ RollOnLoot(self:GetParent().rollID, self:GetID());
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip_AddNewbieTip(self, self.tooltipText, 1.0, 1.0, 1.0, self.newbieText);
+ if ( self:IsEnabled() ~= 1 ) then
+ GameTooltip:AddLine(self.reason, RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, true);
+ GameTooltip:Show();
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(LootFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.hasItem = 1;
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetLootRollItem(self:GetParent().rollID);
+ CursorUpdate(self);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetLootRollItem(self:GetParent().rollID);
+ end
+ CursorOnUpdate(self);
+
+
+ HandleModifiedItemClick(GetLootRollItemLink(self:GetParent().rollID));
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RollOnLoot(self:GetParent().rollID, 0);
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(PASS);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText=NEED;
+ self.newbieText=NEED_NEWBIE;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText=GREED;
+ self.newbieText=GREED_NEWBIE;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText=ROLL_DISENCHANT;
+ self.newbieText=ROLL_DISENCHANT_NEWBIE;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GroupLootFrame_OnUpdate(self, elapsed);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("CANCEL_LOOT_ROLL");
+
+
+
+
+ GroupLootFrame_OnHide(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/MacOptionsFrame.lua b/reference/FrameXML/MacOptionsFrame.lua
new file mode 100644
index 0000000..d7e12bd
--- /dev/null
+++ b/reference/FrameXML/MacOptionsFrame.lua
@@ -0,0 +1,389 @@
+MacOptionsFrameCheckButtons = { };
+MacOptionsFrameCheckButtons["MOVIE_RECORDING_ENABLE_GUI"] = { index = 1, cvar = "MovieRecordingGUI", tooltipText = MOVIE_RECORDING_ENABLE_GUI_TOOLTIP};
+MacOptionsFrameCheckButtons["MOVIE_RECORDING_ENABLE_SOUND"] = { index = 2, cvar = "MovieRecordingSound", tooltipText = MOVIE_RECORDING_ENABLE_SOUND_TOOLTIP};
+MacOptionsFrameCheckButtons["MOVIE_RECORDING_ENABLE_CURSOR"] = { index = 3, cvar = "MovieRecordingCursor", tooltipText = MOVIE_RECORDING_ENABLE_CURSOR_TOOLTIP};
+MacOptionsFrameCheckButtons["MOVIE_RECORDING_ENABLE_ICON"] = { index = 4, cvar = "MovieRecordingIcon", tooltipText = MOVIE_RECORDING_ENABLE_ICON_TOOLTIP};
+MacOptionsFrameCheckButtons["MOVIE_RECORDING_ENABLE_RECOVER"] = { index = 5, cvar = "MovieRecordingRecover", tooltipText = MOVIE_RECORDING_ENABLE_RECOVER_TOOLTIP};
+MacOptionsFrameCheckButtons["MOVIE_RECORDING_ENABLE_COMPRESSION"] = { index = 6, cvar = "MovieRecordingAutoCompress", tooltipText = MOVIE_RECORDING_ENABLE_COMPRESSION_TOOLTIP};
+MacOptionsFrameCheckButtons["ITUNES_SHOW_FEEDBACK"] = { index = 7, cvar = "iTunesRemoteFeedback", tooltipText = ITUNES_SHOW_FEEDBACK_TOOLTIP};
+MacOptionsFrameCheckButtons["ITUNES_SHOW_ALL_TRACK_CHANGES"] = { index = 8, cvar = "iTunesTrackDisplay", tooltipText = ITUNES_SHOW_ALL_TRACK_CHANGES_TOOLTIP};
+
+function MacOptionsFrame_OnLoad(self)
+ if(IsMacClient()) then
+ self:RegisterEvent("CVAR_UPDATE");
+ end
+end
+
+function MacOptionsFrame_OnEvent(self, event, ...)
+ if ( event == "CVAR_UPDATE" ) then
+ local arg1, arg2 = ...
+ local info = MacOptionsFrameCheckButtons[arg1];
+ if ( info ) then
+ info.value = arg2;
+ end
+ end
+end
+
+function MacOptionsFrame_DisableText(text)
+ text:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+end
+
+function MacOptionsFrame_DisableSlider(slider)
+ local name = slider:GetName();
+ local value = _G[name.."Value"];
+ _G[name.."Thumb"]:Hide();
+ MacOptionsFrame_DisableText( _G[name.."Text"] );
+ MacOptionsFrame_DisableText( _G[name.."Low"] );
+ MacOptionsFrame_DisableText( _G[name.."High"] );
+ slider:Disable();
+ if ( value ) then
+ value:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+end
+
+function MacOptionsFrame_Load()
+ for index, value in pairs(MacOptionsFrameCheckButtons) do
+ local button = _G["MacOptionsFrameCheckButton"..value.index];
+ local string = _G["MacOptionsFrameCheckButton"..value.index.."Text"];
+ local checked = 0;
+ checked = GetCVar(value.cvar);
+ button:SetChecked(checked);
+
+ string:SetText(_G[index]);
+ button.tooltipText = value.tooltipText;
+
+ if(not MovieRecording_IsSupported() and (value.index < 7)) then
+ MacOptionsFrame_DisableCheckBox(button);
+ else
+ MacOptionsFrame_EnableCheckBox(button);
+ end
+ end
+
+
+
+
+ if(not MovieRecording_IsSupported()) then
+ UIDropDownMenu_DisableDropDown(MacOptionsFrameResolutionDropDown);
+ UIDropDownMenu_DisableDropDown(MacOptionsFrameFramerateDropDown);
+ UIDropDownMenu_DisableDropDown(MacOptionsFrameCodecDropDown);
+ MacOptionsFrame_DisableSlider(MacOptionsFrameQualitySlider);
+ MacOptionsButtonCompress:Disable();
+
+ -- disable frame text
+ MacOptionsFrame_DisableText(MacOptionsFrameText1);
+ MacOptionsFrame_DisableText(MacOptionsFrameText2);
+ MacOptionsFrame_DisableText(MacOptionsFrameText3);
+ MacOptionsFrame_DisableText(MacOptionsFrameText4);
+
+ else
+ MacOptionsFrameQualitySlider:SetValue(GetCVar("MovieRecordingQuality"));
+ if GetCVar("MovieRecordingGUI") then
+ MacOptionsFrame_EnableCheckBox(_G["MacOptionsFrameCheckButton3"]);
+ else
+ MacOptionsFrame_DisableCheckBox(_G["MacOptionsFrameCheckButton3"]);
+ end
+ end
+ if(not MovieRecording_IsCursorRecordingSupported()) then
+ local button = _G["MacOptionsFrameCheckButton3"];
+ button:SetChecked(0);
+ MacOptionsFrame_DisableCheckBox(button);
+ end
+
+ -- make sure that if UI recording is not enabled, that we disable cursor recording (it's part of the UI)
+ if ( not MacOptionsFrameCheckButton1:GetChecked() ) then
+ MacOptionsFrameCheckButton3:SetChecked(0);
+ MacOptionsFrame_DisableCheckBox(MacOptionsFrameCheckButton3);
+ end
+
+end
+
+function MacOptionsFrame_Save()
+ for index, value in pairs(MacOptionsFrameCheckButtons) do
+ local button = _G["MacOptionsFrameCheckButton"..value.index];
+ if ( button:GetChecked() ) then
+ value.value = "1";
+ else
+ value.value = "0";
+ end
+
+ SetCVar(value.cvar, value.value, index);
+ end
+
+ local resolution, xIndex, width;
+ resolution = UIDropDownMenu_GetSelectedValue(MacOptionsFrameResolutionDropDown);
+ xIndex = strfind(resolution, "x");
+ width = strsub(resolution, 1, xIndex-1);
+
+ SetCVar("MovieRecordingWidth", width);
+ SetCVar("MovieRecordingFramerate", UIDropDownMenu_GetSelectedValue(MacOptionsFrameFramerateDropDown));
+ SetCVar("MovieRecordingCompression", UIDropDownMenu_GetSelectedValue(MacOptionsFrameCodecDropDown));
+
+ SetCVar("MovieRecordingQuality", MacOptionsFrameQualitySlider:GetValue());
+end
+
+function MacOptionsFrame_Cancel()
+ PlaySound("gsTitleOptionExit");
+ HideUIPanel(MacOptionsFrame);
+end
+
+function MacOptionsFrameResolutionDropDown_OnLoad(self)
+ if ( not IsMacClient() ) then
+ return;
+ end
+ local ratio, width;
+
+ UIDropDownMenu_Initialize(self, MacOptionsFrameResolutionDropDown_Initialize);
+
+ ratio = MovieRecording_GetAspectRatio();
+ width = min(GetCVar("MovieRecordingWidth"), MovieRecording_GetViewportWidth());
+ UIDropDownMenu_SetSelectedValue(self, width.."x"..floor(width*ratio), 1);
+ UIDropDownMenu_SetWidth(MacOptionsFrameResolutionDropDown, 110);
+end
+
+local function greaterThanTableSort(a, b) return a > b end
+
+function MacOptionsFrameResolutionDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+ local width, height, ratio, halfWidth, quarterWidth, oldWidth;
+
+ ratio = MovieRecording_GetAspectRatio();
+ width = MovieRecording_GetViewportWidth();
+ width = width - (width % 4);
+
+ oldWidth = GetCVar("MovieRecordingWidth");
+ oldWidth = oldWidth - (oldWidth % 4);
+
+ info.text = width.."x"..floor(width*ratio);
+ info.value = info.text;
+ info.func = MacOptionsFrameResolutionButton_OnClick;
+ info.checked = nil;
+ info.tooltipTitle = MOVIE_RECORDING_FULL_RESOLUTION;
+ UIDropDownMenu_AddButton(info);
+ info.tooltipTitle = nil;
+
+ halfWidth = width / 2;
+ halfWidth = halfWidth - (halfWidth % 4);
+ quarterWidth = width / 4;
+ quarterWidth = quarterWidth - (quarterWidth % 4);
+
+ local resWidth = { 4096, 2560, 1920, 1600, 1344, 1280, 1024, 960, 800, 640, 320 };
+ table.insert(resWidth, tonumber(oldWidth));
+ if halfWidth > 320 then
+ table.insert(resWidth, tonumber(halfWidth));
+ if quarterWidth > 320 then
+ table.insert(resWidth, tonumber(quarterWidth));
+ end
+ end
+
+ table.sort(resWidth, greaterThanTableSort);
+
+ local lastWidth = width;
+ for index, value in pairs(resWidth) do
+ if value < width and value ~= lastWidth then
+ height = floor(value * ratio);
+ info.text = value.."x"..height;
+ info.value = info.text;
+ info.func = MacOptionsFrameResolutionButton_OnClick;
+ info.checked = nil;
+ if value == tonumber(halfWidth) then
+ info.tooltipTitle = "Half Resolution";
+ elseif value == tonumber(quarterWidth) then
+ info.tooltipTitle = "Quarter Resolution";
+ else
+ info.tooltipTitle = nil;
+ end
+ UIDropDownMenu_AddButton(info);
+ lastWidth = value;
+ end
+ end
+end
+
+function MacOptionsFrameResolutionButton_OnClick(self)
+ UIDropDownMenu_SetSelectedValue(MacOptionsFrameResolutionDropDown, self.value);
+ MacOptionsFrame_UpdateTime();
+end
+
+function MacOptionsFrameFramerateDropDown_OnLoad(self)
+ if ( not IsMacClient() ) then
+ return;
+ end
+
+ UIDropDownMenu_Initialize(self, MacOptionsFrameFramerateDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, GetCVar("MovieRecordingFramerate"));
+ UIDropDownMenu_SetWidth(self, 110);
+end
+
+function MacOptionsFrameFramerateDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+ info.func = MacOptionsFrameFramerateDropDown_OnClick;
+ info.checked = nil;
+
+ info.text = MOVIE_RECORDING_FPS_HALF;
+ info.value = "2";
+ info.checked = nil;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = MOVIE_RECORDING_FPS_THIRD;
+ info.value = "3";
+ info.checked = nil;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = MOVIE_RECORDING_FPS_FOURTH;
+ info.value = "4";
+ info.checked = nil;
+ UIDropDownMenu_AddButton(info);
+
+ local fps = { "100", "90", "80", "70", "60", "50", "40", "30", "29.97", "25", "23.98", "20", "15", "10" };
+
+ for index, value in pairs(fps) do
+ info.text = value;
+ info.value = info.text;
+ info.checked = nil;
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function MacOptionsFrameCodecDropDown_OnClick(self)
+ UIDropDownMenu_SetSelectedValue(MacOptionsFrameCodecDropDown, self.value);
+ MacOptionsFrame_UpdateTime();
+end
+
+function MacOptionsFrameCodecDropDown_OnLoad(self)
+ if ( not IsMacClient() ) then
+ return;
+ end
+
+ UIDropDownMenu_Initialize(self, MacOptionsFrameCodecDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, tonumber(GetCVar("MovieRecordingCompression")));
+ UIDropDownMenu_SetWidth(self, 110);
+end
+
+function MacOptionsFrameCodecDropDown_Initialize()
+ local info = UIDropDownMenu_CreateInfo();
+ info.func = MacOptionsFrameCodecDropDown_OnClick;
+ info.checked = nil;
+
+ local codecType = { 1835692129,
+ 1635148593,
+ 1768124260,
+ 1836070006 };
+ local codecName = { MOVIE_RECORDING_MJPEG,
+ MOVIE_RECORDING_H264,
+ MOVIE_RECORDING_AIC,
+ MOVIE_RECORDING_MPEG4 };
+ local codecTooltip = { MOVIE_RECORDING_MJPEG_TOOLTIP,
+ MOVIE_RECORDING_H264_TOOLTIP,
+ MOVIE_RECORDING_AIC_TOOLTIP,
+ MOVIE_RECORDING_MPEG4_TOOLTIP };
+
+ for index, value in pairs(codecType) do
+ if ( MovieRecording_IsCodecSupported(value)) then
+ info.text = codecName[index];
+ info.value = value;
+ info.checked = nil;
+ info.tooltipTitle = codecName[index];
+ info.tooltipText = codecTooltip[index];
+ UIDropDownMenu_AddButton(info);
+ end
+ end
+end
+
+function MacOptionsFrameFramerateDropDown_OnClick(self)
+ UIDropDownMenu_SetSelectedValue(MacOptionsFrameFramerateDropDown, self.value);
+ MacOptionsFrame_UpdateTime();
+end
+
+function MacOptionsFrame_SetDefaults()
+ local checkButton, slider;
+ for index, value in pairs(MacOptionsFrameCheckButtons) do
+ checkButton = _G["MacOptionsFrameCheckButton"..value.index];
+ checkButton:SetChecked(GetCVarDefault(value.cvar));
+ end
+ if(not MovieRecording_IsCursorRecordingSupported()) then
+ local button = _G["MacOptionsFrameCheckButton3"];
+ button:SetChecked(0);
+ MacOptionsFrame_DisableCheckBox(button);
+ else
+ local button = _G["MacOptionsFrameCheckButton3"];
+ MacOptionsFrame_EnableCheckBox(button);
+ end
+
+ UIDropDownMenu_Initialize(MacOptionsFrameFramerateDropDown, MacOptionsFrameFramerateDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(MacOptionsFrameFramerateDropDown, "29.97");
+ UIDropDownMenu_Initialize(MacOptionsFrameCodecDropDown, MacOptionsFrameCodecDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(MacOptionsFrameCodecDropDown, 1635148593);
+ UIDropDownMenu_Initialize(MacOptionsFrameResolutionDropDown, MacOptionsFrameResolutionDropDown_Initialize);
+ local ratio = MovieRecording_GetAspectRatio();
+ UIDropDownMenu_SetSelectedValue(MacOptionsFrameResolutionDropDown, "640x"..floor(640*ratio));
+
+ MacOptionsFrameQualitySlider:SetValue(2);
+ MacOptionsFrame_UpdateTime();
+end
+
+function MacOptionsFrame_DisableCheckBox(checkBox)
+ --checkBox:SetChecked(0);
+ checkBox:Disable();
+ _G[checkBox:GetName().."Text"]:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+end
+
+function MacOptionsFrame_EnableCheckBox(checkBox, setChecked, checked, isWhite)
+ if ( setChecked ) then
+ checkBox:SetChecked(checked);
+ end
+ checkBox:Enable();
+ if ( isWhite ) then
+ _G[checkBox:GetName().."Text"]:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ else
+ _G[checkBox:GetName().."Text"]:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+
+end
+
+function MacOptionsFrame_UpdateTime()
+ local resolution, framerate, xIndex, width, sound;
+ framerate = UIDropDownMenu_GetSelectedValue(MacOptionsFrameFramerateDropDown);
+ if tonumber(framerate) >= 10 then
+ resolution = UIDropDownMenu_GetSelectedValue(MacOptionsFrameResolutionDropDown);
+ xIndex = strfind(resolution, "x");
+ width = tonumber(strsub(resolution, 1, xIndex-1));
+ if(MacOptionsFrameCheckButton2:GetChecked()) then
+ sound = 1;
+ else
+ sound = 0;
+ end
+
+ MacOptionsFrameText2:SetText(MovieRecording_MaxLength( tonumber(width),
+ tonumber(framerate),
+ tonumber(sound)));
+
+ local dataRate = MovieRecording_DataRate( tonumber(width),
+ tonumber(UIDropDownMenu_GetSelectedValue(MacOptionsFrameFramerateDropDown)),
+ tonumber(sound))
+ MacOptionsFrameText4:SetText(dataRate);
+ MovieRecordingFrameTextTooltip1:SetWidth(MacOptionsFrameText1:GetWidth() + MacOptionsFrameText2:GetWidth() + 2);
+ MovieRecordingFrameTextTooltip2:SetWidth(MacOptionsFrameText3:GetWidth() + MacOptionsFrameText4:GetWidth() + 2);
+ else
+ MacOptionsFrameText2:SetText("");
+ MacOptionsFrameText4:SetText("");
+ end
+end
+
+function MacOptionsCancelFrame_OnShow()
+ MacOptionsCancelFrameFileName:SetText(MovieRecording_GetMovieFullPath());
+
+ local fileNameWidth = MacOptionsCancelFrameFileName:GetWidth();
+ local questionWidth = MacOptionsCancelFrameQuestion:GetWidth();
+ local frameWidth = math.min(600, math.max(fileNameWidth, questionWidth));
+
+ MacOptionsCancelFrame:SetWidth(frameWidth + 40);
+ MacOptionsCancelFrameFileName:SetWidth(frameWidth);
+ MacOptionsCancelFrameQuestion:SetWidth(frameWidth);
+end
+
+function MacOptionsCompressFrame_OnShow()
+ local fileNameWidth = MacOptionsCompressFrameFileName:GetWidth();
+ local frameWidth = math.max(350, fileNameWidth);
+
+ MacOptionsCompressFrame:SetWidth(frameWidth + 40);
+ MacOptionsCompressFrameFileName:SetWidth(frameWidth);
+end
diff --git a/reference/FrameXML/MacOptionsFrame.xml b/reference/FrameXML/MacOptionsFrame.xml
new file mode 100644
index 0000000..c447670
--- /dev/null
+++ b/reference/FrameXML/MacOptionsFrame.xml
@@ -0,0 +1,871 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if(UIDropDownMenu_IsEnabled(MacOptionsFrameResolutionDropDown)) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(MOVIE_RECORDING_RESOLUTION_TOOLTIP, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if(UIDropDownMenu_IsEnabled(MacOptionsFrameFramerateDropDown)) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(MOVIE_RECORDING_FRAMERATE_TOOLTIP, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if(UIDropDownMenu_IsEnabled(MacOptionsFrameCodecDropDown)) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(MOVIE_RECORDING_CODEC_TOOLTIP, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MacOptionsFrameQualitySliderText:SetText(QUALITY);
+ self.tooltipText = MOVIE_RECORDING_QUALITY_TOOLTIP;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ MacOptionsFrame_EnableCheckBox(MacOptionsFrameCheckButton3);
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ MacOptionsFrameCheckButton3:SetChecked(0);
+ MacOptionsFrame_DisableCheckBox(MacOptionsFrameCheckButton3);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ MacOptionsFrame_UpdateTime();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ if( MovieRecording_IsRecording() ) then
+ MiniMapRecordingButton:Show();
+ end
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ MiniMapRecordingButton:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(MOVIE_RECORDING_COMPRESS_TOOLTIP, nil, nil, nil, nil, 1);
+
+
+
+ PlaySound("igMainMenuOption");
+ MovieRecording_SearchUncompressedMovie(true);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( MovieRecording_IsSupported() ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(MOVIE_RECORDING_TIME_TOOLTIP, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( MovieRecording_IsSupported() ) then
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(MOVIE_RECORDING_DATA_RATE_TOOLTIP, nil, nil, nil, nil, 1);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.15, 0.15, 0.15);
+ _G[self:GetName().."Title"]:SetText(BINDING_HEADER_MOVIE_RECORDING_SECTION);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.15, 0.15, 0.15);
+ _G[self:GetName().."Title"]:SetText(BINDING_HEADER_ITUNES_REMOTE);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("gsTitleOptionExit");
+ HideUIPanel(MacOptionsFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("gsTitleOptionOK");
+ MacOptionsFrame_Save();
+ HideUIPanel(MacOptionsFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ MacOptionsFrame_SetDefaults();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOption");
+ MacOptionsFrame_Save();
+ HideUIPanel(MacOptionsFrame);
+ KeyBindingFrame_LoadUI();
+ KeyBindingFrame.mode = 1;
+ ShowUIPanel(KeyBindingFrame);
+
+
+
+
+
+
+
+
+ MacOptionsFrame_Load();
+ UpdateMicroButtons();
+ Disable_BagButtons();
+ MacOptionsFrame_UpdateTime();
+
+
+ MacOptionsFrame_Cancel();
+ UpdateMicroButtons();
+ ShowUIPanel(GameMenuFrame);
+
+
+ if ( GetBindingFromClick(key) == "TOGGLEGAMEMENU" ) then
+ PlaySound("gsTitleOptionExit");
+ HideUIPanel(MacOptionsFrame);
+ MacOptionsFrame_Cancel();
+ elseif ( GetBindingFromClick(key) == "SCREENSHOT" ) then
+ RunBinding("SCREENSHOT");
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ MovieRecording_DeleteMovie(MacOptionsCompressFrameFileName:GetText());
+ MacOptionsCompressFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ MacOptionsCompressFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ MovieRecording_QueueMovieToCompress(MacOptionsCompressFrameFileName:GetText());
+ MacOptionsCompressFrame:Hide();
+
+
+
+
+
+
+ self:RegisterEvent("MOVIE_UNCOMPRESSED_MOVIE");
+
+
+ local arg1 = ...;
+ MacOptionsCompressFrameFileName:SetText(arg1);
+ HideUIPanel(MacOptionsFrame);
+ HideUIPanel(GameMenuFrame);
+ MacOptionsCompressFrame_OnShow();
+ self:Show();
+
+
+ MovieRecording_SearchUncompressedMovie(false);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ MacOptionsCancelFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ MovieRecording_Cancel();
+ MacOptionsCancelFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FolderPicker:Hide();
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/MailFrame.lua b/reference/FrameXML/MailFrame.lua
new file mode 100644
index 0000000..317646e
--- /dev/null
+++ b/reference/FrameXML/MailFrame.lua
@@ -0,0 +1,1102 @@
+INBOXITEMS_TO_DISPLAY = 7;
+STATIONERY_ICON_ROW_HEIGHT = 36;
+STATIONERYITEMS_TO_DISPLAY = 5;
+PACKAGEITEMS_TO_DISPLAY = 4;
+ATTACHMENTS_MAX = 16;
+ATTACHMENTS_MAX_SEND = 12;
+ATTACHMENTS_PER_ROW_SEND = 7;
+ATTACHMENTS_MAX_ROWS_SEND = 2;
+ATTACHMENTS_MAX_RECEIVE = 16;
+ATTACHMENTS_PER_ROW_RECEIVE = 7;
+ATTACHMENTS_MAX_ROWS_RECEIVE = 3;
+STATIONERY_PATH = "Interface\\Stationery\\";
+MAX_COD_AMOUNT = 10000;
+SEND_MAIL_TAB_LIST = {};
+SEND_MAIL_TAB_LIST[1] = "SendMailNameEditBox";
+SEND_MAIL_TAB_LIST[2] = "SendMailSubjectEditBox";
+SEND_MAIL_TAB_LIST[3] = "SendMailBodyEditBox";
+SEND_MAIL_TAB_LIST[4] = "SendMailMoneyGold";
+SEND_MAIL_TAB_LIST[5] = "SendMailMoneyCopper";
+
+function MailFrame_OnLoad(self)
+ -- Init pagenum
+ InboxFrame.pageNum = 1;
+ -- Tab Handling code
+ PanelTemplates_SetNumTabs(self, 2);
+ PanelTemplates_SetTab(self, 1);
+ -- Register for events
+ self:RegisterEvent("MAIL_SHOW");
+ self:RegisterEvent("MAIL_INBOX_UPDATE");
+ self:RegisterEvent("MAIL_CLOSED");
+ self:RegisterEvent("MAIL_SEND_INFO_UPDATE");
+ self:RegisterEvent("MAIL_SEND_SUCCESS");
+ self:RegisterEvent("MAIL_FAILED");
+ self:RegisterEvent("MAIL_SUCCESS");
+ self:RegisterEvent("CLOSE_INBOX_ITEM");
+ self:RegisterEvent("MAIL_LOCK_SEND_ITEMS");
+ self:RegisterEvent("MAIL_UNLOCK_SEND_ITEMS");
+ -- Set previous and next fields
+ MoneyInputFrame_SetPreviousFocus(SendMailMoney, SendMailBodyEditBox);
+ MoneyInputFrame_SetNextFocus(SendMailMoney, SendMailNameEditBox);
+end
+
+function MailFrame_OnEvent(self, event, ...)
+ if ( event == "MAIL_SHOW" ) then
+ ShowUIPanel(MailFrame);
+ if ( not MailFrame:IsShown() ) then
+ CloseMail();
+ return;
+ end
+
+ -- Update the roster so auto-completion works
+ if ( IsInGuild() and GetNumGuildMembers() == 0 ) then
+ GuildRoster();
+ end
+
+ OpenBackpack();
+ SendMailFrame_Update();
+ MailFrameTab_OnClick(nil, 1);
+ CheckInbox();
+ elseif ( event == "MAIL_INBOX_UPDATE" ) then
+ InboxFrame_Update();
+ OpenMail_Update();
+ elseif ( event == "MAIL_SEND_INFO_UPDATE" ) then
+ SendMailFrame_Update();
+ elseif ( event == "MAIL_SEND_SUCCESS" ) then
+ SendMailFrame_Reset();
+ PlaySound("igAbiliityPageTurn");
+ -- If open mail frame is open then switch the mail frame back to the inbox
+ if ( SendMailFrame.sendMode == "reply" ) then
+ MailFrameTab_OnClick(nil, 1);
+ end
+ elseif ( event == "MAIL_FAILED" ) then
+ SendMailMailButton:Enable();
+ elseif ( event == "MAIL_SUCCESS" ) then
+ SendMailMailButton:Enable();
+ if ( InboxNextPageButton:IsEnabled() ~= 0 ) then
+ InboxGetMoreMail();
+ end
+ elseif ( event == "MAIL_CLOSED" ) then
+ HideUIPanel(MailFrame);
+ SendMailFrameLockSendMail:Hide();
+ StaticPopup_Hide("CONFIRM_MAIL_ITEM_UNREFUNDABLE");
+ elseif ( event == "CLOSE_INBOX_ITEM" ) then
+ local arg1 = ...;
+ if ( arg1 == InboxFrame.openMailID ) then
+ HideUIPanel(OpenMailFrame);
+ end
+ elseif ( event == "MAIL_LOCK_SEND_ITEMS" ) then
+ local slotNum, itemLink = ...;
+ SendMailFrameLockSendMail:Show();
+ itemName, itemLink, itemRarity, itemLevel, itemMinLevel, itemType, itemSubType, itemStackCount, itemEquipLoc, itemTexture = GetItemInfo(itemLink);
+ local r, g, b = GetItemQualityColor(itemRarity)
+ StaticPopup_Show("CONFIRM_MAIL_ITEM_UNREFUNDABLE", nil, nil, {["texture"] = itemTexture, ["name"] = itemName, ["color"] = {r, g, b, 1}, ["link"] = itemLink, ["slot"] = slotNum});
+ elseif ( event == "MAIL_UNLOCK_SEND_ITEMS") then
+ SendMailFrameLockSendMail:Hide();
+ StaticPopup_Hide("CONFIRM_MAIL_ITEM_UNREFUNDABLE");
+ end
+end
+
+function MailFrameTab_OnClick(self, tabID)
+ if ( not tabID ) then
+ tabID = self:GetID();
+ end
+ PanelTemplates_SetTab(MailFrame, tabID);
+ if ( tabID == 1 ) then
+ -- Inbox tab clicked
+ InboxFrame:Show();
+ SendMailFrame:Hide();
+ MailFrameTopLeft:SetTexture("Interface\\ItemTextFrame\\UI-ItemText-TopLeft");
+ MailFrameTopRight:SetTexture("Interface\\Spellbook\\UI-SpellbookPanel-TopRight");
+ MailFrameBotLeft:SetTexture("Interface\\ItemTextFrame\\UI-ItemText-BotLeft");
+ MailFrameBotRight:SetTexture("Interface\\Spellbook\\UI-SpellbookPanel-BotRight");
+ MailFrameTopLeft:SetPoint("TOPLEFT", "MailFrame", "TOPLEFT", 0, 0);
+ SetSendMailShowing(false);
+ else
+ -- Sendmail tab clicked
+ InboxFrame:Hide();
+ SendMailFrame:Show();
+ MailFrameTopLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopLeft");
+ MailFrameTopRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopRight");
+ MailFrameBotLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-BotLeft");
+ MailFrameBotRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-BotRight");
+ MailFrameTopLeft:SetPoint("TOPLEFT", "MailFrame", "TOPLEFT", 2, -1);
+ SendMailFrame_Update();
+ SetSendMailShowing(true);
+
+ -- Set the send mode to dictate the flow after a mail is sent
+ SendMailFrame.sendMode = "send";
+ end
+ PlaySound("igSpellBookOpen");
+end
+
+-- Inbox functions
+
+function InboxFrame_Update()
+ local numItems, totalItems = GetInboxNumItems();
+ local index = ((InboxFrame.pageNum - 1) * INBOXITEMS_TO_DISPLAY) + 1;
+ local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemCount, wasRead, x, y, z, isGM, firstItemQuantity;
+ local icon, button, expireTime, senderText, subjectText, buttonIcon;
+
+ if ( totalItems > numItems ) then
+ if ( not InboxFrame.maxShownMails ) then
+ InboxFrame.maxShownMails = numItems;
+ end
+ InboxFrame.overflowMails = totalItems - numItems;
+ InboxFrame.shownMails = numItems;
+ else
+ InboxFrame.overflowMails = nil;
+ end
+
+ for i=1, INBOXITEMS_TO_DISPLAY do
+ if ( index <= numItems ) then
+ -- Setup mail item
+ packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemCount, wasRead, x, y, z, isGM, firstItemQuantity = GetInboxHeaderInfo(index);
+
+ -- Set icon
+ if ( packageIcon ) and ( not isGM ) then
+ icon = packageIcon;
+ else
+ icon = stationeryIcon;
+ end
+
+
+ -- If no sender set it to "Unknown"
+ if ( not sender ) then
+ sender = UNKNOWN;
+ end
+ button = _G["MailItem"..i.."Button"];
+ button:Show();
+ button.index = index;
+ button.hasItem = itemCount;
+ button.itemCount = itemCount;
+ SetItemButtonCount(button, firstItemQuantity);
+ buttonIcon = _G["MailItem"..i.."ButtonIcon"];
+ buttonIcon:SetTexture(icon);
+ subjectText = _G["MailItem"..i.."Subject"];
+ subjectText:SetText(subject);
+ senderText = _G["MailItem"..i.."Sender"];
+ senderText:SetText(sender);
+
+ -- If hasn't been read color the button yellow
+ if ( wasRead ) then
+ senderText:SetTextColor(0.75, 0.75, 0.75);
+ subjectText:SetTextColor(0.75, 0.75, 0.75);
+ _G["MailItem"..i.."ButtonSlot"]:SetVertexColor(0.5, 0.5, 0.5);
+ SetDesaturation(buttonIcon, 1);
+ else
+ senderText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ subjectText:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ _G["MailItem"..i.."ButtonSlot"]:SetVertexColor(1.0, 0.82, 0);
+ SetDesaturation(buttonIcon, nil);
+ end
+ -- Format expiration time
+ if ( daysLeft >= 1 ) then
+ daysLeft = GREEN_FONT_COLOR_CODE..format(DAYS_ABBR, floor(daysLeft)).." "..FONT_COLOR_CODE_CLOSE;
+ else
+ daysLeft = RED_FONT_COLOR_CODE..SecondsToTime(floor(daysLeft * 24 * 60 * 60))..FONT_COLOR_CODE_CLOSE;
+ end
+ expireTime = _G["MailItem"..i.."ExpireTime"];
+ expireTime:SetText(daysLeft);
+ -- Set expiration time tooltip
+ if ( InboxItemCanDelete(index) ) then
+ expireTime.tooltip = TIME_UNTIL_DELETED;
+ else
+ expireTime.tooltip = TIME_UNTIL_RETURNED;
+ end
+ expireTime:Show();
+ -- Is a C.O.D. package
+ if ( CODAmount > 0 ) then
+ _G["MailItem"..i.."ButtonCOD"]:Show();
+ _G["MailItem"..i.."ButtonCODBackground"]:Show();
+ button.cod = CODAmount;
+ else
+ _G["MailItem"..i.."ButtonCOD"]:Hide();
+ _G["MailItem"..i.."ButtonCODBackground"]:Hide();
+ button.cod = nil;
+ end
+ -- Contains money
+ if ( money > 0 ) then
+ button.money = money;
+ else
+ button.money = nil;
+ end
+ -- Set highlight
+ if ( InboxFrame.openMailID == index ) then
+ button:SetChecked(1);
+ SetPortraitToTexture("OpenMailFrameIcon", stationeryIcon);
+ else
+ button:SetChecked(nil);
+ end
+ else
+ -- Clear everything
+ _G["MailItem"..i.."Button"]:Hide();
+ _G["MailItem"..i.."Sender"]:SetText("");
+ _G["MailItem"..i.."Subject"]:SetText("");
+ _G["MailItem"..i.."ExpireTime"]:Hide();
+ end
+ index = index + 1;
+ end
+
+ -- Handle page arrows
+ if ( InboxFrame.pageNum == 1 ) then
+ InboxPrevPageButton:Disable();
+ else
+ InboxPrevPageButton:Enable();
+ end
+ if ( (InboxFrame.pageNum * INBOXITEMS_TO_DISPLAY) < numItems ) then
+ InboxNextPageButton:Enable();
+ else
+ InboxNextPageButton:Disable();
+ end
+ if ( totalItems > numItems) then
+ InboxTooMuchMail:Show();
+ else
+ InboxTooMuchMail:Hide();
+ end
+end
+
+function InboxFrame_OnClick(self, index)
+ if ( self:GetChecked() ) then
+ InboxFrame.openMailID = index;
+ OpenMailFrame.updateButtonPositions = true;
+ OpenMail_Update();
+ --OpenMailFrame:Show();
+ ShowUIPanel(OpenMailFrame);
+ PlaySound("igSpellBookOpen");
+ else
+ InboxFrame.openMailID = 0;
+ HideUIPanel(OpenMailFrame);
+ end
+ InboxFrame_Update();
+end
+
+function InboxFrame_OnModifiedClick(self, index)
+ local _, _, _, _, _, cod = GetInboxHeaderInfo(index);
+ if ( cod <= 0 ) then
+ AutoLootMailItem(index);
+ end
+ InboxFrame_OnClick(self, index);
+end
+
+function InboxFrameItem_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self.hasItem ) then
+ if ( self.itemCount == 1) then
+ GameTooltip:SetInboxItem(self.index);
+ else
+ GameTooltip:AddLine(MAIL_MULTIPLE_ITEMS.." ("..self.itemCount..")");
+ end
+ end
+ if (self.money) then
+ if ( self.hasItem ) then
+ GameTooltip:AddLine(" ");
+ end
+ GameTooltip:AddLine(ENCLOSED_MONEY, "", 1, 1, 1);
+ SetTooltipMoney(GameTooltip, self.money);
+ SetMoneyFrameColor("GameTooltipMoneyFrame1", "white");
+ elseif (self.cod) then
+ if ( self.hasItem ) then
+ GameTooltip:AddLine(" ");
+ end
+ GameTooltip:AddLine(COD_AMOUNT, "", 1, 1, 1);
+ SetTooltipMoney(GameTooltip, self.cod);
+ if ( self.cod > GetMoney() ) then
+ SetMoneyFrameColor("GameTooltipMoneyFrame1", "red");
+ else
+ SetMoneyFrameColor("GameTooltipMoneyFrame1", "white");
+ end
+ end
+ GameTooltip:Show();
+end
+
+function InboxNextPage()
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ InboxFrame.pageNum = InboxFrame.pageNum + 1;
+ InboxGetMoreMail();
+ InboxFrame_Update();
+end
+
+function InboxPrevPage()
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ InboxFrame.pageNum = InboxFrame.pageNum - 1;
+ InboxGetMoreMail();
+ InboxFrame_Update();
+end
+
+function InboxGetMoreMail()
+ -- get more mails if there is an overflow and less than max are being shown
+ if ( InboxFrame.overflowMails and InboxFrame.shownMails < InboxFrame.maxShownMails ) then
+ CheckInbox();
+ end
+end
+
+-- Open Mail functions
+
+function OpenMailFrame_OnHide()
+ StaticPopup_Hide("DELETE_MAIL");
+ if ( not InboxFrame.openMailID ) then
+ InboxFrame_Update();
+ PlaySound("igSpellBookClose");
+ return;
+ end
+
+ -- Determine if this is an auction temp invoice
+ local bodyText, texture, isTakeable, isInvoice = GetInboxText(InboxFrame.openMailID);
+ local isAuctionTempInvoice = false;
+ if ( isInvoice ) then
+ local invoiceType, itemName, playerName, bid, buyout, deposit, consignment, moneyDelay, etaHour, etaMin = GetInboxInvoiceInfo(InboxFrame.openMailID);
+ if (invoiceType == "seller_temp_invoice") then
+ isAuctionTempInvoice = true;
+ end
+ end
+
+ -- If mail contains no items, then delete it on close
+ local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemCount, wasRead, wasReturned, textCreated = GetInboxHeaderInfo(InboxFrame.openMailID);
+ if ( money == 0 and not itemCount and textCreated and not isAuctionTempInvoice ) then
+ DeleteInboxItem(InboxFrame.openMailID);
+ end
+ InboxFrame.openMailID = 0;
+ InboxFrame_Update();
+ PlaySound("igSpellBookClose");
+end
+
+function OpenMailFrame_UpdateButtonPositions(letterIsTakeable, textCreated, stationeryIcon, money)
+ if ( OpenMailFrame.activeAttachmentButtons ) then
+ while (#OpenMailFrame.activeAttachmentButtons > 0) do
+ tremove(OpenMailFrame.activeAttachmentButtons);
+ end
+ else
+ OpenMailFrame.activeAttachmentButtons = {};
+ end
+ if ( OpenMailFrame.activeAttachmentRowPositions ) then
+ while (#OpenMailFrame.activeAttachmentRowPositions > 0) do
+ tremove(OpenMailFrame.activeAttachmentRowPositions );
+ end
+ else
+ OpenMailFrame.activeAttachmentRowPositions = {};
+ end
+
+ local rowAttachmentCount = 0;
+
+ -- letter
+ if ( letterIsTakeable and not textCreated ) then
+ SetItemButtonTexture(OpenMailLetterButton, stationeryIcon);
+ tinsert(OpenMailFrame.activeAttachmentButtons, OpenMailLetterButton);
+ rowAttachmentCount = rowAttachmentCount + 1;
+ else
+ SetItemButtonTexture(OpenMailLetterButton, "");
+ end
+ -- money
+ if ( money == 0 ) then
+ SetItemButtonTexture(OpenMailMoneyButton, "");
+ else
+ SetItemButtonTexture(OpenMailMoneyButton, GetCoinIcon(money));
+ tinsert(OpenMailFrame.activeAttachmentButtons, OpenMailMoneyButton);
+ rowAttachmentCount = rowAttachmentCount + 1;
+ end
+ -- items
+ for i=1, ATTACHMENTS_MAX_RECEIVE do
+ local name, itemTexture, count, quality, canUse = GetInboxItem(InboxFrame.openMailID, i);
+ local attachmentButton = _G["OpenMailAttachmentButton"..i];
+ if ( name ) then
+ tinsert(OpenMailFrame.activeAttachmentButtons, attachmentButton);
+ rowAttachmentCount = rowAttachmentCount + 1;
+
+ SetItemButtonTexture(attachmentButton, itemTexture);
+ SetItemButtonCount(attachmentButton, count);
+ if ( canUse ) then
+ SetItemButtonTextureVertexColor(attachmentButton, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ else
+ SetItemButtonTextureVertexColor(attachmentButton, 1.0, 0.1, 0.1);
+ end
+ else
+ attachmentButton:Hide();
+ end
+
+ if ( rowAttachmentCount >= ATTACHMENTS_PER_ROW_RECEIVE ) then
+ tinsert(OpenMailFrame.activeAttachmentRowPositions, {cursorxstart=0,cursorxend=ATTACHMENTS_PER_ROW_RECEIVE - 1});
+ rowAttachmentCount = 0;
+ end
+ end
+ -- insert last row's position data
+ if ( rowAttachmentCount > 0 ) then
+ local xstart = (ATTACHMENTS_PER_ROW_RECEIVE - rowAttachmentCount) / 2;
+ local xend = xstart + rowAttachmentCount - 1;
+ tinsert(OpenMailFrame.activeAttachmentRowPositions, {cursorxstart=xstart,cursorxend=xend});
+ end
+
+ -- hide unusable attachment buttons
+ for i=ATTACHMENTS_MAX_RECEIVE + 1, ATTACHMENTS_MAX do
+ _G["OpenMailAttachmentButton"..i]:Hide();
+ end
+end
+
+function OpenMail_Update()
+ if ( not InboxFrame.openMailID ) then
+ return;
+ end
+ if ( CanComplainInboxItem(InboxFrame.openMailID) ) then
+ OpenMailReportSpamButton:Enable();
+ OpenMailReportSpamButton:Show();
+ else
+ OpenMailReportSpamButton:Hide();
+ end
+
+ -- Setup mail item
+ local packageIcon, stationeryIcon, sender, subject, money, CODAmount, daysLeft, itemCount, wasRead, wasReturned, textCreated, canReply = GetInboxHeaderInfo(InboxFrame.openMailID);
+ -- Set sender and subject
+ if ( not sender or not canReply ) then
+ OpenMailReplyButton:Disable();
+ else
+ OpenMailReplyButton:Enable();
+ end
+ if ( not sender ) then
+ sender = UNKNOWN;
+ end
+ -- Save sender name to pass to a potential spam report
+ InboxFrame.openMailSender = sender;
+ OpenMailSender:SetText(sender);
+ OpenMailSubject:SetText(subject);
+ -- Set Text
+ local bodyText, texture, isTakeable, isInvoice = GetInboxText(InboxFrame.openMailID);
+ OpenMailBodyText:SetText(bodyText);
+ if ( texture ) then
+ OpenStationeryBackgroundLeft:SetTexture(STATIONERY_PATH..texture.."1");
+ OpenStationeryBackgroundRight:SetTexture(STATIONERY_PATH..texture.."2");
+ end
+
+ -- Is an invoice
+ if ( isInvoice ) then
+ local invoiceType, itemName, playerName, bid, buyout, deposit, consignment, moneyDelay, etaHour, etaMin = GetInboxInvoiceInfo(InboxFrame.openMailID);
+ if ( playerName ) then
+ -- Setup based on whether player is the buyer or the seller
+ local buyMode;
+ if ( invoiceType == "buyer" ) then
+ if ( bid == buyout ) then
+ buyMode = "("..BUYOUT..")";
+ else
+ buyMode = "("..HIGH_BIDDER..")";
+ end
+ OpenMailInvoiceItemLabel:SetText(ITEM_PURCHASED_COLON.." "..itemName.." "..buyMode);
+ OpenMailInvoicePurchaser:SetText(SOLD_BY_COLON.." "..playerName);
+ OpenMailInvoiceAmountReceived:SetText(AMOUNT_PAID_COLON);
+ -- Clear buymode
+ OpenMailInvoiceBuyMode:SetText("");
+ -- Position amount paid
+ OpenMailInvoiceAmountReceived:SetPoint("TOPRIGHT", "OpenMailInvoiceSalePrice", "TOPRIGHT", 0, 0);
+ -- Update purchase price
+ MoneyFrame_Update("OpenMailTransactionAmountMoneyFrame", bid);
+ -- Position buy line
+ OpenMailArithmeticLine:SetPoint("TOP", "OpenMailInvoicePurchaser", "BOTTOMLEFT", 125, 0);
+ -- Not used for a purchase invoice
+ OpenMailInvoiceSalePrice:Hide();
+ OpenMailInvoiceDeposit:Hide();
+ OpenMailInvoiceHouseCut:Hide();
+ OpenMailDepositMoneyFrame:Hide();
+ OpenMailHouseCutMoneyFrame:Hide();
+ OpenMailSalePriceMoneyFrame:Hide();
+ OpenMailInvoiceNotYetSent:Hide();
+ OpenMailInvoiceMoneyDelay:Hide();
+ elseif (invoiceType == "seller") then
+ OpenMailInvoiceItemLabel:SetText(ITEM_SOLD_COLON.." "..itemName);
+ OpenMailInvoicePurchaser:SetText(PURCHASED_BY_COLON.." "..playerName);
+ OpenMailInvoiceAmountReceived:SetText(AMOUNT_RECEIVED_COLON);
+ -- Determine if auction was bought out or bid on
+ if ( bid == buyout ) then
+ OpenMailInvoiceBuyMode:SetText("("..BUYOUT..")");
+ else
+ OpenMailInvoiceBuyMode:SetText("("..HIGH_BIDDER..")");
+ end
+ -- Position amount received
+ OpenMailInvoiceAmountReceived:SetPoint("TOPRIGHT", "OpenMailInvoiceHouseCut", "BOTTOMRIGHT", 0, -18);
+ -- Position buy line
+ OpenMailArithmeticLine:SetPoint("TOP", "OpenMailInvoiceHouseCut", "BOTTOMRIGHT", 0, 9);
+ MoneyFrame_Update("OpenMailSalePriceMoneyFrame", bid);
+ MoneyFrame_Update("OpenMailDepositMoneyFrame", deposit);
+ MoneyFrame_Update("OpenMailHouseCutMoneyFrame", consignment);
+ SetMoneyFrameColor("OpenMailHouseCutMoneyFrame", "red");
+ MoneyFrame_Update("OpenMailTransactionAmountMoneyFrame", bid+deposit-consignment);
+
+ -- Show these guys if the player was the seller
+ OpenMailInvoiceSalePrice:Show();
+ OpenMailInvoiceDeposit:Show();
+ OpenMailInvoiceHouseCut:Show();
+ OpenMailDepositMoneyFrame:Show();
+ OpenMailHouseCutMoneyFrame:Show();
+ OpenMailSalePriceMoneyFrame:Show();
+ OpenMailInvoiceNotYetSent:Hide();
+ OpenMailInvoiceMoneyDelay:Hide();
+ elseif (invoiceType == "seller_temp_invoice") then
+ if ( bid == buyout ) then
+ buyMode = "("..BUYOUT..")";
+ else
+ buyMode = "("..HIGH_BIDDER..")";
+ end
+ OpenMailInvoiceItemLabel:SetText(ITEM_SOLD_COLON.." "..itemName.." "..buyMode);
+ OpenMailInvoicePurchaser:SetText(PURCHASED_BY_COLON.." "..playerName);
+ OpenMailInvoiceAmountReceived:SetText(AUCTION_INVOICE_PENDING_FUNDS_COLON);
+ -- Clear buymode
+ OpenMailInvoiceBuyMode:SetText("");
+ -- Position amount to be received
+ OpenMailInvoiceAmountReceived:SetPoint("TOPRIGHT", "OpenMailInvoiceSalePrice", "TOPRIGHT", 0, 0);
+ -- Update purchase price
+ MoneyFrame_Update("OpenMailTransactionAmountMoneyFrame", bid+deposit-consignment);
+ -- Position buy line
+ OpenMailArithmeticLine:SetPoint("TOP", "OpenMailInvoicePurchaser", "BOTTOMLEFT", 125, 0);
+ -- How long they have to wait to get the money
+ OpenMailInvoiceMoneyDelay:SetFormattedText(AUCTION_INVOICE_FUNDS_DELAY, GameTime_GetFormattedTime(etaHour, etaMin, true));
+ -- Not used for a temp sale invoice
+ OpenMailInvoiceSalePrice:Hide();
+ OpenMailInvoiceDeposit:Hide();
+ OpenMailInvoiceHouseCut:Hide();
+ OpenMailDepositMoneyFrame:Hide();
+ OpenMailHouseCutMoneyFrame:Hide();
+ OpenMailSalePriceMoneyFrame:Hide();
+ OpenMailInvoiceNotYetSent:Show();
+ OpenMailInvoiceMoneyDelay:Show();
+ end
+ OpenMailInvoiceFrame:Show();
+ end
+ else
+ OpenMailInvoiceFrame:Hide();
+ end
+
+ local itemButtonCount, itemRowCount = OpenMail_GetItemCounts(isTakeable, textCreated, money);
+ if ( OpenMailFrame.updateButtonPositions ) then
+ OpenMailFrame_UpdateButtonPositions(isTakeable, textCreated, stationeryIcon, money);
+ end
+ if ( OpenMailFrame.activeAttachmentRowPositions ) then
+ itemRowCount = #OpenMailFrame.activeAttachmentRowPositions;
+ end
+
+ -- record the original number of buttons that the mail needs
+ OpenMailFrame.itemButtonCount = itemButtonCount;
+
+ -- Determine starting position for buttons
+ local marginxl = 23 + 4;
+ local marginxr = 43 + 4;
+ local areax = OpenMailFrame:GetWidth() - marginxl - marginxr;
+ local iconx = OpenMailAttachmentButton1:GetWidth() + 2;
+ local icony = OpenMailAttachmentButton1:GetHeight() + 2;
+ local gapx1 = floor((areax - (iconx * ATTACHMENTS_PER_ROW_RECEIVE)) / (ATTACHMENTS_PER_ROW_RECEIVE - 1));
+ local gapx2 = floor((areax - (iconx * ATTACHMENTS_PER_ROW_RECEIVE) - (gapx1 * (ATTACHMENTS_PER_ROW_RECEIVE - 1))) / 2);
+ local gapy1 = 3;
+ local gapy2 = 3;
+ local areay = gapy2 + OpenMailAttachmentText:GetHeight() + gapy2 + (icony * itemRowCount) + (gapy1 * (itemRowCount - 1)) + gapy2;
+ local indentx = marginxl + gapx2;
+ local indenty = 103 + gapy2;
+ local tabx = (iconx + gapx1);
+ local taby = (icony + gapy1);
+ local scrollHeight = 305 - areay;
+ if (scrollHeight > 256) then
+ scrollHeight = 256;
+ areay = 305 - scrollHeight;
+ end
+
+ -- Resize the scroll frame
+ OpenMailScrollFrame:SetHeight(scrollHeight);
+ OpenMailScrollChildFrame:SetHeight(scrollHeight);
+ OpenMailHorizontalBarLeft:SetPoint("TOPLEFT", "OpenMailFrame", "BOTTOMLEFT", 15, 114 + areay);
+ OpenScrollBarBackgroundTop:SetHeight(min(scrollHeight, 256));
+ OpenScrollBarBackgroundTop:SetTexCoord(0, 0.484375, 0, min(scrollHeight, 256) / 256);
+ OpenStationeryBackgroundLeft:SetHeight(scrollHeight);
+ OpenStationeryBackgroundLeft:SetTexCoord(0, 1.0, 0, min(scrollHeight, 256) / 256);
+ OpenStationeryBackgroundRight:SetHeight(scrollHeight);
+ OpenStationeryBackgroundRight:SetTexCoord(0, 1.0, 0, min(scrollHeight, 256) / 256);
+
+ -- Set attachment text
+ if ( itemButtonCount > 0 ) then
+ OpenMailAttachmentText:SetText(TAKE_ATTACHMENTS);
+ OpenMailAttachmentText:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ OpenMailAttachmentText:SetPoint("TOPLEFT", "OpenMailFrame", "BOTTOMLEFT", indentx, indenty + (icony * itemRowCount) + (gapy1 * (itemRowCount - 1)) + gapy2 + OpenMailAttachmentText:GetHeight());
+ else
+ OpenMailAttachmentText:SetText(NO_ATTACHMENTS);
+ OpenMailAttachmentText:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ OpenMailAttachmentText:SetPoint("TOPLEFT", "OpenMailFrame", "BOTTOMLEFT", marginxl + (areax - OpenMailAttachmentText:GetWidth()) / 2, indenty + (areay - OpenMailAttachmentText:GetHeight()) / 2 + OpenMailAttachmentText:GetHeight());
+ end
+ -- Set letter
+ if ( isTakeable and not textCreated ) then
+ OpenMailLetterButton:Show();
+ else
+ OpenMailLetterButton:Hide();
+ end
+ -- Set Money
+ if ( money == 0 ) then
+ OpenMailMoneyButton:Hide();
+ OpenMailFrame.money = nil;
+ else
+ OpenMailMoneyButton:Show();
+ OpenMailFrame.money = money;
+ end
+ -- Set Items
+ if ( itemRowCount > 0 and OpenMailFrame.activeAttachmentButtons ) then
+ local firstAttachName;
+ local rowIndex = 1;
+ local cursorx = OpenMailFrame.activeAttachmentRowPositions[1].cursorxstart;
+ local cursorxend = OpenMailFrame.activeAttachmentRowPositions[1].cursorxend;
+ local cursory = itemRowCount - 1;
+ for i, attachmentButton in pairs(OpenMailFrame.activeAttachmentButtons) do
+ attachmentButton:SetPoint("TOPLEFT", "OpenMailFrame", "BOTTOMLEFT", indentx + (tabx * cursorx), indenty + icony + (taby * cursory));
+ if ( attachmentButton ~= OpenMailLetterButton and attachmentButton ~= OpenMailMoneyButton ) then
+ local name, itemTexture, count, quality, canUse = GetInboxItem(InboxFrame.openMailID, attachmentButton:GetID());
+ if ( name and cursory >= 0 ) then
+ if ( not firstAttachName ) then
+ firstAttachName = name;
+ end
+
+ attachmentButton:Enable();
+ attachmentButton:Show();
+ else
+ attachmentButton:Hide();
+ end
+ end
+
+ cursorx = cursorx + 1;
+ if (cursorx > cursorxend) then
+ rowIndex = rowIndex + 1;
+
+ cursory = cursory - 1;
+ if ( rowIndex <= itemRowCount ) then
+ cursorx = OpenMailFrame.activeAttachmentRowPositions[rowIndex].cursorxstart;
+ cursorxend = OpenMailFrame.activeAttachmentRowPositions[rowIndex].cursorxend;
+ end
+ end
+ end
+
+ OpenMailFrame.itemName = firstAttachName;
+ else
+ OpenMailFrame.itemName = nil;
+ end
+
+ -- Set COD
+ if ( CODAmount > 0 ) then
+ OpenMailFrame.cod = CODAmount;
+ else
+ OpenMailFrame.cod = nil;
+ end
+ -- Set button to delete or return to sender
+ if ( InboxItemCanDelete(InboxFrame.openMailID) ) then
+ OpenMailDeleteButton:SetText(DELETE);
+ else
+ OpenMailDeleteButton:SetText(MAIL_RETURN);
+ end
+end
+
+function OpenMail_GetItemCounts(letterIsTakeable, textCreated, money)
+ local itemButtonCount = 0;
+ local itemRowCount = 0;
+ local numRows = 0;
+ if ( letterIsTakeable and not textCreated ) then
+ itemButtonCount = itemButtonCount + 1;
+ itemRowCount = itemRowCount + 1;
+ end
+ if ( money ~= 0 ) then
+ itemButtonCount = itemButtonCount + 1;
+ itemRowCount = itemRowCount + 1;
+ end
+ for i=1, ATTACHMENTS_MAX_RECEIVE do
+ local name, itemTexture, count, quality, canUse = GetInboxItem(InboxFrame.openMailID, i);
+ if ( name ) then
+ itemButtonCount = itemButtonCount + 1;
+ itemRowCount = itemRowCount + 1;
+ end
+
+ if ( itemRowCount >= ATTACHMENTS_PER_ROW_RECEIVE ) then
+ numRows = numRows + 1;
+ itemRowCount = 0;
+ end
+ end
+ if ( itemRowCount > 0 ) then
+ numRows = numRows + 1;
+ end
+ return itemButtonCount, numRows;
+end
+
+function OpenMail_Reply()
+ MailFrameTab_OnClick(nil, 2);
+ SendMailNameEditBox:SetText(OpenMailSender:GetText())
+ local subject = OpenMailSubject:GetText();
+ local prefix = MAIL_REPLY_PREFIX.." ";
+ if ( strsub(subject, 1, strlen(prefix)) ~= prefix ) then
+ subject = prefix..subject;
+ end
+ SendMailSubjectEditBox:SetText(subject)
+ SendMailBodyEditBox:SetFocus();
+
+ -- Set the send mode so the work flow can change accordingly
+ SendMailFrame.sendMode = "reply";
+end
+
+function OpenMail_Delete()
+ if ( InboxItemCanDelete(InboxFrame.openMailID) ) then
+ if ( OpenMailFrame.itemName ) then
+ StaticPopup_Show("DELETE_MAIL", OpenMailFrame.itemName);
+ return;
+ elseif ( OpenMailFrame.money ) then
+ StaticPopup_Show("DELETE_MONEY");
+ return;
+ else
+ DeleteInboxItem(InboxFrame.openMailID);
+ end
+ else
+ ReturnInboxItem(InboxFrame.openMailID);
+ StaticPopup_Hide("COD_CONFIRMATION");
+ end
+ InboxFrame.openMailID = nil;
+ HideUIPanel(OpenMailFrame);
+end
+
+function OpenMail_ReportSpam()
+ local dialog = StaticPopup_Show("CONFIRM_REPORT_SPAM_MAIL", InboxFrame.openMailSender);
+ if ( dialog ) then
+ dialog.data = InboxFrame.openMailID;
+ end
+ OpenMailReportSpamButton:Disable();
+end
+
+function OpenMailAttachment_OnEnter(self, index)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetInboxItem(InboxFrame.openMailID, index);
+
+ if ( OpenMailFrame.cod ) then
+ SetTooltipMoney(GameTooltip, OpenMailFrame.cod);
+ if ( OpenMailFrame.cod > GetMoney() ) then
+ SetMoneyFrameColor("GameTooltipMoneyFrame1", "red");
+ else
+ SetMoneyFrameColor("GameTooltipMoneyFrame1", "white");
+ end
+ end
+ GameTooltip:Show();
+end
+
+function OpenMailAttachment_OnClick(self, index)
+ if ( OpenMailFrame.cod and (OpenMailFrame.cod > GetMoney()) ) then
+ StaticPopup_Show("COD_ALERT");
+ elseif ( OpenMailFrame.cod ) then
+ OpenMailFrame.lastTakeAttachment = index;
+ StaticPopup_Show("COD_CONFIRMATION");
+ OpenMailFrame.updateButtonPositions = false;
+ else
+ TakeInboxItem(InboxFrame.openMailID, index);
+ OpenMailFrame.updateButtonPositions = false;
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+-- SendMail functions
+
+function SendMailMailButton_OnClick(self)
+ self:Disable();
+ local copper = MoneyInputFrame_GetCopper(SendMailMoney);
+ SetSendMailCOD(0);
+ SetSendMailMoney(0);
+ if ( SendMailSendMoneyButton:GetChecked() ) then
+ -- Send Money
+ if ( copper > 0 ) then
+ -- Open confirmation dialog
+ StaticPopup_Show("SEND_MONEY", SendMailNameEditBox:GetText());
+ return;
+ end
+ else
+ -- Send C.O.D.
+ if ( copper > 0 ) then
+ SetSendMailCOD(copper);
+ end
+ end
+ SendMailFrame_SendMail();
+end
+
+function SendMailFrame_SendMail()
+ SendMail(SendMailNameEditBox:GetText(), SendMailSubjectEditBox:GetText(), SendMailBodyEditBox:GetText());
+end
+
+function SendMailFrame_Update()
+ -- Update the item(s) being sent
+ local itemCount = 0;
+ local itemTitle;
+ local gap;
+ local last = 0;
+ for i=1, ATTACHMENTS_MAX_SEND do
+ -- get info about the attachment
+ local itemName, itemTexture, stackCount, quality = GetSendMailItem(i);
+ -- set attachment texture info
+ _G["SendMailAttachment"..i]:SetNormalTexture(itemTexture);
+ -- set the stack count
+ if ( stackCount <= 1 ) then
+ _G["SendMailAttachment"..i.."Count"]:SetText("");
+ else
+ _G["SendMailAttachment"..i.."Count"]:SetText(stackCount);
+ end
+ -- determine what a name for the message in case it doesn't already have one
+ if ( itemName ) then
+ itemCount = itemCount + 1;
+ if ( not itemTitle ) then
+ if ( stackCount <= 1 ) then
+ itemTitle = itemName;
+ else
+ itemTitle = itemName.." ("..stackCount..")";
+ end
+ end
+ if ((last + 1) ~= i) then
+ gap = 1;
+ end
+ last = i;
+ end
+ end
+ -- Enable or disable C.O.D. depending on whether or not there's an item to send
+ if ( itemCount > 0 ) then
+ SendMailCODButton:Enable();
+ SendMailCODButtonText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+
+ if ( SendMailSubjectEditBox:GetText() == "" or SendMailSubjectEditBox:GetText() == SendMailFrame.previousItem ) then
+ SendMailSubjectEditBox:SetText(itemTitle);
+ SendMailFrame.previousItem = itemTitle;
+ end
+ else
+ -- If no itemname see if the subject is the name of the previously held item, if so clear the subject
+ if ( SendMailSubjectEditBox:GetText() == SendMailFrame.previousItem ) then
+ SendMailSubjectEditBox:SetText("");
+ end
+ SendMailFrame.previousItem = "";
+
+ SendMailRadioButton_OnClick(1);
+ SendMailCODButton:Disable();
+ SendMailCODButtonText:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+ -- Update the cost
+ MoneyFrame_Update("SendMailCostMoneyFrame", GetSendMailPrice());
+
+ -- Color the postage text
+ if ( GetSendMailPrice() > GetMoney() ) then
+ SetMoneyFrameColor("SendMailCostMoneyFrame", "red");
+ else
+ SetMoneyFrameColor("SendMailCostMoneyFrame", "white");
+ end
+
+ -- Determine how many rows of attachments to show
+ local itemRowCount = 1;
+ local temp = last;
+ while ((temp > ATTACHMENTS_PER_ROW_SEND) and (itemRowCount < ATTACHMENTS_MAX_ROWS_SEND)) do
+ itemRowCount = itemRowCount + 1;
+ temp = temp - ATTACHMENTS_PER_ROW_SEND;
+ end
+ if (not gap and (temp == ATTACHMENTS_PER_ROW_SEND) and (itemRowCount < ATTACHMENTS_MAX_ROWS_SEND)) then
+ itemRowCount = itemRowCount + 1;
+ end
+ if (SendMailFrame.maxRowsShown and (last > 0) and (itemRowCount < SendMailFrame.maxRowsShown)) then
+ itemRowCount = SendMailFrame.maxRowsShown;
+ else
+ SendMailFrame.maxRowsShown = itemRowCount;
+ end
+
+ -- Compute sizes
+ local cursorx = 0;
+ local cursory = itemRowCount - 1;
+ local marginxl = 25 + 6;
+ local marginxr = 40 + 6;
+ local areax = SendMailFrame:GetWidth() - marginxl - marginxr;
+ local iconx = SendMailAttachment1:GetWidth() + 2;
+ local icony = SendMailAttachment1:GetHeight() + 2;
+ local gapx1 = floor((areax - (iconx * ATTACHMENTS_PER_ROW_SEND)) / (ATTACHMENTS_PER_ROW_SEND - 1));
+ local gapx2 = floor((areax - (iconx * ATTACHMENTS_PER_ROW_SEND) - (gapx1 * (ATTACHMENTS_PER_ROW_SEND - 1))) / 2);
+ local gapy1 = 5;
+ local gapy2 = 6;
+ local areay = (gapy2 * 2) + (gapy1 * (itemRowCount - 1)) + (icony * itemRowCount);
+ local indentx = marginxl + gapx2;
+ local indenty = 156 + gapy2 + icony;
+ local tabx = (iconx + gapx1);
+ local taby = (icony + gapy1);
+ local scrollHeight = 249 - areay;
+
+ -- Resize the scroll frame
+ SendMailScrollFrame:SetHeight(scrollHeight);
+ SendMailScrollChildFrame:SetHeight(scrollHeight);
+ SendMailHorizontalBarLeft2:SetPoint("TOPLEFT", "SendMailFrame", "BOTTOMLEFT", 15, 170 + areay);
+ SendScrollBarBackgroundTop:SetHeight(min(scrollHeight, 256));
+ SendScrollBarBackgroundTop:SetTexCoord(0, 0.484375, 0, min(scrollHeight, 256) / 256);
+ SendStationeryBackgroundLeft:SetHeight(min(scrollHeight, 256));
+ SendStationeryBackgroundLeft:SetTexCoord(0, 1.0, 0, min(scrollHeight, 256) / 256);
+ SendStationeryBackgroundRight:SetHeight(min(scrollHeight, 256));
+ SendStationeryBackgroundRight:SetTexCoord(0, 1.0, 0, min(scrollHeight, 256) / 256);
+
+ -- Set Items
+ for i=1, ATTACHMENTS_MAX_SEND do
+ if (cursory >= 0) then
+ _G["SendMailAttachment"..i]:Enable();
+ _G["SendMailAttachment"..i]:Show();
+ _G["SendMailAttachment"..i]:SetPoint("TOPLEFT", "SendMailFrame", "BOTTOMLEFT", indentx + (tabx * cursorx), indenty + (taby * cursory));
+
+ cursorx = cursorx + 1;
+ if (cursorx >= ATTACHMENTS_PER_ROW_SEND) then
+ cursory = cursory - 1;
+ cursorx = 0;
+ end
+ else
+ _G["SendMailAttachment"..i]:Hide();
+ end
+ end
+ for i=ATTACHMENTS_MAX_SEND+1, ATTACHMENTS_MAX do
+ _G["SendMailAttachment"..i]:Hide();
+ end
+
+ SendMailFrame_CanSend();
+end
+
+function SendMailFrame_Reset()
+ SendMailNameEditBox:SetText("");
+ SendMailNameEditBox:SetFocus();
+ SendMailSubjectEditBox:SetText("");
+ SendMailBodyEditBox:SetText("");
+ StationeryPopupFrame.selectedIndex = nil;
+ SendMailFrame_Update();
+ StationeryPopupButton_OnClick(nil, 1);
+ MoneyInputFrame_ResetMoney(SendMailMoney);
+ SendMailRadioButton_OnClick(1);
+ SendMailFrame.maxRowsShown = 0;
+end
+
+function SendMailFrame_CanSend()
+ local checks = 0;
+ local checksRequired = 3;
+ -- If has stationery
+ if ( StationeryPopupFrame.selectedIndex ~= nil ) then
+ checks = checks + 1;
+ end
+ -- and has a sendee
+ if ( strlen(SendMailNameEditBox:GetText()) > 0 ) then
+ checks = checks + 1;
+ end
+ -- and has a subject
+ if ( strlen(SendMailSubjectEditBox:GetText()) > 0 ) then
+ checks = checks + 1;
+ end
+ -- check c.o.d. amount
+ if ( SendMailCODButton:GetChecked() ) then
+ checksRequired = 4;
+ -- COD must be less than 10000 gold
+ if ( MoneyInputFrame_GetCopper(SendMailMoney) > MAX_COD_AMOUNT*COPPER_PER_GOLD ) then
+ if ( ENABLE_COLORBLIND_MODE ~= "1" ) then
+ SendMailErrorCoin:Show();
+ end
+ SendMailErrorText:Show();
+ else
+ SendMailErrorText:Hide();
+ SendMailErrorCoin:Hide();
+ checks = checks + 1;
+ end
+ end
+
+ if ( checks == checksRequired ) then
+ SendMailMailButton:Enable();
+ else
+ SendMailMailButton:Disable();
+ end
+end
+
+function SendMailRadioButton_OnClick(index)
+ if ( index == 1 ) then
+ SendMailSendMoneyButton:SetChecked(1);
+ SendMailCODButton:SetChecked(nil);
+ SendMailMoneyText:SetText(AMOUNT_TO_SEND);
+ else
+ SendMailSendMoneyButton:SetChecked(nil);
+ SendMailCODButton:SetChecked(1);
+ SendMailMoneyText:SetText(COD_AMOUNT);
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+end
+
+-- Stationery functions
+
+function StationeryPopupFrame_Update()
+ local numStationeries = GetNumStationeries();
+ local index = FauxScrollFrame_GetOffset(StationeryPopupScrollFrame) + 1;
+ local name, texture, cost;
+ local button;
+ for i=1, STATIONERYITEMS_TO_DISPLAY do
+ button = _G["StationeryPopupButton"..i];
+ if ( index <= numStationeries ) then
+ name, texture, cost = GetStationeryInfo(index);
+ _G["StationeryPopupButton"..i.."Name"]:SetText(name);
+ if ( cost ) then
+ MoneyFrame_Update("StationeryPopupButton"..i.."MoneyFrame", cost);
+ -- If player can't afford
+ if ( cost > GetMoney() ) then
+ button:Disable();
+ SetMoneyFrameColor("StationeryPopupButton"..i.."MoneyFrame", "red");
+ else
+ button:Enable();
+ SetMoneyFrameColor("StationeryPopupButton"..i.."MoneyFrame", "white");
+ end
+ else
+ -- Is a stationery in player's inventory or is free
+ MoneyFrame_Update("StationeryPopupButton"..i.."MoneyFrame", 0);
+ end
+ _G["StationeryPopupButton"..i.."Icon"]:SetTexture(texture);
+ button:Show();
+ else
+ _G["StationeryPopupButton"..i.."Name"]:SetText("");
+ MoneyFrame_Update("StationeryPopupButton"..i.."MoneyFrame", 0);
+ _G["StationeryPopupButton"..i.."Icon"]:SetTexture("");
+ button:Hide();
+ end
+
+ if ( index == StationeryPopupFrame.selectedIndex ) then
+ button:SetChecked(1);
+ else
+ button:SetChecked(nil);
+ end
+ button.index = index;
+ index = index + 1;
+ end
+
+ -- Scrollbar stuff
+ FauxScrollFrame_Update(StationeryPopupScrollFrame, numStationeries , STATIONERYITEMS_TO_DISPLAY, STATIONERY_ICON_ROW_HEIGHT );
+end
+
+function StationeryPopupButton_OnClick(self, index)
+ if ( not index ) then
+ index = self.index;
+ end
+ SelectStationery(index);
+ StationeryPopupFrame.selectedIndex = index;
+ SendMailFrame_CanSend()
+ -- Set the stationery texture
+ local texture = GetSelectedStationeryTexture();
+ if ( texture ) then
+ SendStationeryBackgroundLeft:SetTexture(STATIONERY_PATH..texture.."1");
+ SendStationeryBackgroundRight:SetTexture(STATIONERY_PATH..texture.."2");
+ end
+ StationeryPopupFrame_Update();
+end
+
+function SendMailMoneyButton_OnClick()
+ local cursorMoney = GetCursorMoney();
+ if ( cursorMoney > 0 ) then
+ local money = MoneyInputFrame_GetCopper(SendMailMoney);
+ if ( money > 0 ) then
+ cursorMoney = cursorMoney + money;
+ end
+ MoneyInputFrame_SetCopper(SendMailMoney, cursorMoney);
+ DropCursorMoney();
+ end
+end
+
+function SendMailAttachmentButton_OnClick(self, button)
+ ClickSendMailItemButton(self:GetID(), button == "RightButton");
+end
+
+function SendMailAttachmentButton_OnDropAny()
+ ClickSendMailItemButton();
+end
+
+function SendMailAttachment_OnEnter(self)
+ local index = self:GetID();
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( GetSendMailItem(index) ) then
+ GameTooltip:SetSendMailItem(index);
+ else
+ GameTooltip:SetText(ATTACHMENT_TEXT, 1.0, 1.0, 1.0);
+ end
+end
diff --git a/reference/FrameXML/MailFrame.xml b/reference/FrameXML/MailFrame.xml
new file mode 100644
index 0000000..3eb1a47
--- /dev/null
+++ b/reference/FrameXML/MailFrame.xml
@@ -0,0 +1,2064 @@
+
+
+
+
+
+ SendMailRadioButton_OnClick(self:GetID());
+ SendMailFrame_CanSend();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( not self.tooltip ) then
+ return;
+ end
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ local modifiedClick = IsModifiedClick("MAILAUTOLOOTTOGGLE");
+ if ( modifiedClick ) then
+ InboxFrame_OnModifiedClick(self, self.index);
+ else
+ InboxFrame_OnClick(self, self.index);
+ end
+
+
+ InboxFrameItem_OnEnter(self, motion);
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ InboxFrameItem_OnEnter(self);
+ end
+
+
+ GameTooltip:Hide();
+ SetMoneyFrameColor("GameTooltipMoneyFrame1", "white");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+ StationeryPopupButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SendMailAttachmentButton_OnClick(self, button, down);
+
+
+ SendMailAttachmentButton_OnClick(self, button);
+
+
+ SendMailAttachmentButton_OnClick(self);
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:RegisterForDrag("LeftButton");
+
+
+ SendMailAttachment_OnEnter(self, motion);
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ SendMailAttachment_OnEnter(self);
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+ self:RegisterEvent("MAIL_INBOX_UPDATE");
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ --GameTooltip:Hide();
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetInboxItem(InboxFrame.openMailID, self:GetID());
+ GameTooltip:Show();
+ end
+
+
+ if ( IsModifiedClick() ) then
+ HandleModifiedItemClick(GetInboxItemLink(InboxFrame.openMailID, self:GetID()));
+ else
+ OpenMailAttachment_OnClick(self, self:GetID());
+ end
+
+
+ OpenMailAttachment_OnEnter(self, self:GetID());
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ OpenMailAttachment_OnEnter(self, self:GetID());
+ end
+
+
+ GameTooltip:Hide();
+ SetMoneyFrameColor("GameTooltipMoneyFrame1", "white");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(InboxTooMuchMailText:GetWidth() + 32);
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(INBOX_TOO_MUCH_MAIL_TOOLTIP);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:Disable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:Disable();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ScrollingEdit_OnTextChanged(self, self:GetParent():GetParent());
+
+
+ ScrollingEdit_OnCursorChanged(self, x, y-10, w, h);
+
+
+ ScrollingEdit_OnUpdate(self, elapsed, self:GetParent():GetParent());
+
+
+ EditBox_HandleTabbing(self, SEND_MAIL_TAB_LIST);
+
+
+
+
+
+
+
+
+ SendMailBodyEditBox:SetFocus();
+ if ( CursorHasItem() ) then
+ SendMailAttachmentButton_OnDropAny();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.autoCompleteParams = AUTOCOMPLETE_LIST.MAIL;
+ self.addHighlightedText = true;
+
+
+ if ( not AutoCompleteEditBox_OnTabPressed(self) ) then
+ EditBox_HandleTabbing(self, SEND_MAIL_TAB_LIST);
+ end
+
+
+ AutoCompleteEditBox_OnEditFocusLost(self);
+ EditBox_ClearHighlight(self)
+
+
+ if ( not AutoCompleteEditBox_OnEnterPressed(self) ) then
+ SendMailSubjectEditBox:SetFocus();
+ end
+
+
+ if ( not AutoCompleteEditBox_OnEscapePressed(self) ) then
+ EditBox_ClearFocus(self);
+ end
+
+
+ AutoCompleteEditBox_OnTextChanged(self, userInput);
+ SendMailFrame_CanSend(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+ MoneyFrame_Update("SendMailCostMoneyFrame", GetSendMailPrice());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ EditBox_HandleTabbing(self, SEND_MAIL_TAB_LIST);
+
+
+ SendMailBodyEditBox:SetFocus();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MoneyInputFrame_SetOnValueChangedFunc(self, SendMailFrame_CanSend);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(SEND_MONEY);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(COD);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(MailFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(SendMailMoneyFrame:GetFrameLevel() + 3);
+
+
+
+
+
+
+ SendMailErrorText:SetPoint("BOTTOMLEFT", "SendMailMoneyText", "TOPLEFT", 0, 2);
+ SendMailRadioButton_OnClick(self, 1);
+
+
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ SendMailErrorText:SetFormattedText(MAIL_COD_ERROR_COLORBLIND, MAX_COD_AMOUNT, GOLD_AMOUNT_SYMBOL);
+ else
+ SendMailErrorText:SetFormattedText(MAIL_COD_ERROR, MAX_COD_AMOUNT);
+ end
+ StationeryPopupFrame_Update();
+ StationeryPopupButton_OnClick(self, 1);
+ SendMailNameEditBox:SetFocus();
+
+
+ if ( CursorHasItem() ) then
+ SendMailAttachmentButton_OnDropAny();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MailFrameTab_OnClick(self, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MailFrameTab_OnClick(self, 2);
+
+
+
+
+
+
+
+
+ CloseMail();
+ HideUIPanel(OpenMailFrame);
+ StationeryPopupFrame:Hide();
+ SendMailBodyEditBox:SetText("");
+ SendMailNameEditBox:SetText("");
+ SendMailSubjectEditBox:SetText("");
+ PlaySound("igCharacterInfoClose");
+ SetSendMailShowing(false);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, STATIONERY_ICON_ROW_HEIGHT, StationeryPopupFrame_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoClose");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "AUCTION");
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ OpenMailFrame.updateButtonPositions = false;
+ TakeInboxTextItem(InboxFrame.openMailID);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(MAIL_LETTER_TOOLTIP);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("MAIL_INBOX_UPDATE");
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ --GameTooltip:Hide();
+ if ( GameTooltip:IsOwned(self) ) then
+ if ( OpenMailFrame.money ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ SetTooltipMoney(GameTooltip, OpenMailFrame.money);
+ GameTooltip:Show();
+ end
+ end
+
+
+ OpenMailFrame.updateButtonPositions = false;
+ TakeInboxMoney(InboxFrame.openMailID);
+
+
+ if ( OpenMailFrame.money ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ SetTooltipMoney(GameTooltip, OpenMailFrame.money);
+ GameTooltip:Show();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(GetUIPanel("center"));
+ HideUIPanel(GetUIPanel("right"));
+
+
+
+
+
+
diff --git a/reference/FrameXML/MainMenuBar.lua b/reference/FrameXML/MainMenuBar.lua
new file mode 100644
index 0000000..3423241
--- /dev/null
+++ b/reference/FrameXML/MainMenuBar.lua
@@ -0,0 +1,573 @@
+local MAINMENU_SLIDETIME = 0.30;
+local MAINMENU_GONEYPOS = 130; --Distance off screen for MainMenuBar to be completely hidden
+local MAINMENU_XPOS = 0;
+local MAINMENU_VEHICLE_ENDCAPPOS = 548;
+
+function MainMenuExpBar_Update()
+ local currXP = UnitXP("player");
+ local nextXP = UnitXPMax("player");
+ MainMenuExpBar:SetMinMaxValues(min(0, currXP), nextXP);
+ MainMenuExpBar:SetValue(currXP);
+end
+
+local function MainMenuBar_GetAnimPos(self, fraction)
+ return "BOTTOM", UIParent, "BOTTOM", MAINMENU_XPOS, (sin(fraction*90+90)-1) * MAINMENU_GONEYPOS;
+end
+
+local function MainMenuBar_GetRightABPos(self, fraction)
+
+ local finaloffset;
+ if ( SHOW_MULTI_ACTIONBAR_3 and SHOW_MULTI_ACTIONBAR_4 ) then
+ finaloffset = 100;
+ else
+ finaloffset = 62;
+ end
+
+ return "BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", (sin(fraction*90)) * finaloffset, 98;
+end
+
+local function MainMenuBar_GetSeatIndicatorPos(self, fraction)
+
+ local finaloffset;
+ if ( SHOW_MULTI_ACTIONBAR_3 and SHOW_MULTI_ACTIONBAR_4 ) then
+ finaloffset = -100;
+ elseif ( SHOW_MULTI_ACTIONBAR_3 ) then
+ finaloffset = -62;
+ else
+ finaloffset = 0;
+ end
+
+ return "TOPRIGHT", MinimapCluster, "BOTTOMRIGHT", (cos(fraction*90)) * finaloffset, -13;
+end
+
+function MainMenuBar_AnimFinished(self)
+ MainMenuBar.busy = false;
+ if ( GetBonusBarOffset() > 0 ) then
+ ShowBonusActionBar(true);
+ else
+ HideBonusActionBar(true);
+ end
+ MainMenuBar_UpdateArt(self);
+end
+
+function MainMenuBar_UnlockAB(self)
+ MultiBarRight.ignoreFramePositionManager = nil;
+end
+
+function MainMenuBar_UpdateArt(self)
+ if ( MainMenuBar.animComplete and not MainMenuBar.busy) then
+ if ( UnitHasVehicleUI("player") ) then
+ MainMenuBar_ToVehicleArt(self);
+ else
+ if ( MainMenuBar.state ~= "player" ) then
+ MainMenuBar_ToPlayerArt(self)
+ else
+ MainMenuBarVehicleLeaveButton_Update();
+ end
+ end
+ end
+end
+
+local AnimDataTable = {
+ MenuBar_Slide = {
+ totalTime = MAINMENU_SLIDETIME,
+ updateFunc = "SetPoint",
+ getPosFunc = MainMenuBar_GetAnimPos,
+ },
+ ActionBar_Slide = {
+ totalTime = MAINMENU_SLIDETIME,
+ updateFunc = "SetPoint",
+ getPosFunc = MainMenuBar_GetRightABPos,
+ },
+ SeatIndicator_Slide = {
+ totalTime = MAINMENU_SLIDETIME,
+ updateFunc = "SetPoint",
+ getPosFunc = MainMenuBar_GetSeatIndicatorPos,
+ },
+}
+
+function MainMenuBar_ToVehicleArt(self)
+ MainMenuBar.state = "vehicle";
+
+ SetUpAnimation(VehicleMenuBar, AnimDataTable.MenuBar_Slide, nil, true);
+
+ MultiBarLeft:Hide();
+ MultiBarRight:Hide();
+ MultiBarBottomLeft:Hide();
+ MultiBarBottomRight:Hide();
+
+ MainMenuBar:Hide();
+ VehicleMenuBar:SetPoint(MainMenuBar_GetAnimPos(VehicleMenuBar, 1))
+ VehicleMenuBar:Show();
+ PossessBar_Update(true);
+ ShowBonusActionBar(true); --Now, when we are switching to vehicle art we will ALWAYS be using the BonusActionBar
+ UIParent_ManageFramePositions(); --This is called in PossessBar_Update, but it doesn't actually do anything but change an attribute, so it is worth keeping
+
+ VehicleMenuBar_SetSkin(VehicleMenuBar.skin, IsVehicleAimAngleAdjustable());
+end
+
+function MainMenuBar_ToPlayerArt(self)
+ MainMenuBar.state = "player";
+
+ MultiActionBar_Update();
+
+ MultiBarRight:SetPoint(MainMenuBar_GetRightABPos(MultiBarRight, 1));
+
+ SetUpAnimation(MainMenuBar, AnimDataTable.MenuBar_Slide, nil, true);
+ SetUpAnimation(MultiBarRight, AnimDataTable.ActionBar_Slide, MainMenuBar_UnlockAB, true);
+ SetUpAnimation(VehicleSeatIndicator, AnimDataTable.SeatIndicator_Slide, nil, true);
+
+
+
+ VehicleMenuBar:Hide();
+
+
+ MainMenuBar:Show();
+
+ PossessBar_Update(true);
+ if ( GetBonusBarOffset() > 0 ) then
+ ShowBonusActionBar(true);
+ else
+ HideBonusActionBar(true);
+ end
+ --UIParent_ManageFramePositions() --This is called in PossessBar_Update
+ MainMenuBarVehicleLeaveButton_Update();
+
+ VehicleMenuBar_MoveMicroButtons();
+ VehicleMenuBar_ReleaseSkins();
+end
+
+function MainMenuBarVehicleLeaveButton_OnLoad(self)
+ self:RegisterEvent("UPDATE_BONUS_ACTIONBAR");
+ self:RegisterEvent("UPDATE_MULTI_CAST_ACTIONBAR");
+ self:RegisterEvent("VEHICLE_UPDATE");
+end
+
+function MainMenuBarVehicleLeaveButton_OnEvent(self, event, ...)
+ MainMenuBarVehicleLeaveButton_Update();
+end
+
+function MainMenuBarVehicleLeaveButton_Update()
+ if ( CanExitVehicle() ) then
+ MainMenuBarVehicleLeaveButton:ClearAllPoints();
+ if ( IsPossessBarVisible() ) then
+ MainMenuBarVehicleLeaveButton:SetPoint("LEFT", PossessButton2, "RIGHT", 30, 0);
+ elseif ( GetNumShapeshiftForms() > 0 ) then
+ MainMenuBarVehicleLeaveButton:SetPoint("LEFT", "ShapeshiftButton"..GetNumShapeshiftForms(), "RIGHT", 30, 0);
+ elseif ( HasMultiCastActionBar() ) then
+ MainMenuBarVehicleLeaveButton:SetPoint("LEFT", MultiCastActionBarFrame, "RIGHT", 30, 0);
+ else
+ MainMenuBarVehicleLeaveButton:SetPoint("LEFT", PossessBarFrame, "LEFT", 10, 0);
+ end
+ MainMenuBarVehicleLeaveButton:Show();
+ ShowPetActionBar(true);
+ else
+ MainMenuBarVehicleLeaveButton:Hide();
+ ShowPetActionBar(true);
+ end
+
+ UIParent_ManageFramePositions();
+end
+
+function MainMenuBar_OnLoad(self)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("BAG_UPDATE");
+ self:RegisterEvent("ACTIONBAR_PAGE_CHANGED");
+ self:RegisterEvent("KNOWN_CURRENCY_TYPES_UPDATE");
+ self:RegisterEvent("CURRENCY_DISPLAY_UPDATE");
+ self:RegisterEvent("ADDON_LOADED");
+ self:RegisterEvent("UNIT_ENTERING_VEHICLE");
+ self:RegisterEvent("UNIT_ENTERED_VEHICLE");
+ self:RegisterEvent("UNIT_EXITING_VEHICLE");
+ self:RegisterEvent("UNIT_EXITED_VEHICLE");
+
+ MainMenuBar.state = "player";
+ MainMenuBarPageNumber:SetText(GetActionBarPage());
+end
+
+local firstEnteringWorld = true;
+function MainMenuBar_OnEvent(self, event, ...)
+ local arg1, arg2, arg3, arg4, arg5 = ...;
+ if ( event == "ACTIONBAR_PAGE_CHANGED" ) then
+ MainMenuBarPageNumber:SetText(GetActionBarPage());
+ elseif ( event == "KNOWN_CURRENCY_TYPES_UPDATE" or event == "CURRENCY_DISPLAY_UPDATE" ) then
+ local showTokenFrame, showTokenFrameHonor = GetCVarBool("showTokenFrame"), GetCVarBool("showTokenFrameHonor");
+ if ( not showTokenFrame or not showTokenFrameHonor ) then
+ local name, isHeader, isExpanded, isUnused, isWatched, count, icon, extraCurrencyType;
+ local hasPVPTokens, hasNormalTokens;
+ for index=1, GetCurrencyListSize() do
+ name, isHeader, isExpanded, isUnused, isWatched, count, extraCurrencyType, icon = GetCurrencyListInfo(index);
+ if ( (not isHeader) and (extraCurrencyType > 0) and (count>0) ) then
+ hasPVPTokens = true;
+ elseif ( (not isHeader) and (extraCurrencyType <= 0) and (count>0) ) then
+ hasNormalTokens = true;
+ end
+ end
+ if ( (not showTokenFrame) and (hasNormalTokens) ) then
+ SetCVar("showTokenFrame", 1);
+ if ( not CharacterFrame:IsVisible() ) then
+ SetButtonPulse(CharacterMicroButton, 60, 1);
+ end
+ if ( not TokenFrame:IsVisible() ) then
+ SetButtonPulse(CharacterFrameTab5, 60, 1);
+ end
+ end
+ if ( (not showTokenFrameHonor) and (hasPVPTokens) ) then
+ SetCVar("showTokenFrameHonor", 1);
+ if ( not CharacterFrame:IsVisible() ) then
+ SetButtonPulse(CharacterMicroButton, 60, 1);
+ end
+ if ( not TokenFrame:IsVisible() ) then
+ SetButtonPulse(CharacterFrameTab5, 60, 1);
+ end
+ end
+ if ( hasNormalTokens or hasPVPTokens or showTokenFrame or showTokenFrameHonor ) then
+ TokenFrame_LoadUI();
+ TokenFrame_Update();
+ BackpackTokenFrame_Update();
+ else
+ CharacterFrameTab5:Hide();
+ end
+ else
+ TokenFrame_LoadUI();
+ TokenFrame_Update();
+ BackpackTokenFrame_Update();
+ end
+ elseif ( event == "PLAYER_ENTERING_WORLD" ) then
+ MainMenuBar_UpdateKeyRing();
+ if ( not firstEnteringWorld ) then
+ MainMenuBar_ToPlayerArt();
+ end
+ firstEnteringWorld = false;
+ elseif ( event == "BAG_UPDATE" ) then
+ if ( not GetCVarBool("showKeyring") ) then
+ if ( HasKey() ) then
+ -- Show Tutorial and flash keyring
+ SetButtonPulse(KeyRingButton, 60, 1);
+ SetCVar("showKeyring", 1);
+ end
+ MainMenuBar_UpdateKeyRing();
+ end
+ elseif ( (event == "UNIT_ENTERED_VEHICLE") and (arg1=="player") ) then
+ MainMenuBar.animComplete = true;
+ MainMenuBar_UpdateArt(self);
+ elseif ( (event == "UNIT_EXITED_VEHICLE") and (arg1=="player") )then
+ MainMenuBar.animComplete = true;
+ MainMenuBar_UpdateArt(self);
+ elseif ( (event == "UNIT_ENTERING_VEHICLE") and (arg1=="player") ) then
+ MainMenuBar.busy = true;
+ MainMenuBar.animComplete = false;
+ VehicleMenuBar.skin = arg3;
+ if ( arg2 ) then --We are going to show a vehicle UI
+ if ( MainMenuBar.state == "vehicle" ) then
+ MultiBarRight.ignoreFramePositionManager = true;
+ SetUpAnimation(VehicleMenuBar, AnimDataTable.MenuBar_Slide, MainMenuBar_AnimFinished, false);
+ else
+ MainMenuBar.state = "vehicle";
+ MultiBarRight.ignoreFramePositionManager = true;
+ SetUpAnimation(MultiBarRight, AnimDataTable.ActionBar_Slide, nil, false);
+ SetUpAnimation(MainMenuBar, AnimDataTable.MenuBar_Slide, MainMenuBar_AnimFinished, false);
+ SetUpAnimation(VehicleSeatIndicator, AnimDataTable.SeatIndicator_Slide, nil, false);
+ end
+ else
+ if ( MainMenuBar.state == "vehicle" ) then
+ MultiBarRight.ignoreFramePositionManager = true;
+ SetUpAnimation(VehicleMenuBar, AnimDataTable.MenuBar_Slide, MainMenuBar_AnimFinished, false);
+ --MainMenuBar_SetUpAnimation(MultiBarRight, true, MAINMENU_SLIDETIME, MainMenuBar_GetRightABPos, nil, true);
+ else
+ MainMenuBar.busy = false;
+ MainMenuBar.animComplete = true;
+ MainMenuBarVehicleLeaveButton_Update();
+ end
+ end
+ elseif ( (event == "UNIT_EXITING_VEHICLE") and (arg1=="player") ) then
+ if ( MainMenuBar.state ~= "player" ) then
+ MainMenuBar.busy = true;
+ MainMenuBar.animComplete = false;
+ MultiBarRight.ignoreFramePositionManager = true;
+ SetUpAnimation(VehicleMenuBar, AnimDataTable.MenuBar_Slide, MainMenuBar_AnimFinished, false);
+ else
+ if ( GetBonusBarOffset() > 0 ) then
+ ShowBonusActionBar();
+ else
+ HideBonusActionBar();
+ end
+ end
+
+ end
+end
+
+function ExhaustionTick_OnLoad(self)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("PLAYER_XP_UPDATE");
+ self:RegisterEvent("UPDATE_EXHAUSTION");
+ self:RegisterEvent("PLAYER_LEVEL_UP");
+ self:RegisterEvent("PLAYER_UPDATE_RESTING");
+end
+
+function ExhaustionTick_OnEvent(self, event, ...)
+ if ((event == "PLAYER_ENTERING_WORLD") or (event == "PLAYER_XP_UPDATE") or (event == "UPDATE_EXHAUSTION") or (event == "PLAYER_LEVEL_UP")) then
+ local playerCurrXP = UnitXP("player");
+ local playerMaxXP = UnitXPMax("player");
+ --local exhaustionCurrXP, exhaustionMaxXP;
+ --exhaustionCurrXP, exhaustionMaxXP = GetXPExhaustion();
+ local exhaustionThreshold = GetXPExhaustion();
+ local exhaustionStateID, exhaustionStateName, exhaustionStateMultiplier;
+ exhaustionStateID, exhaustionStateName, exhaustionStateMultiplier = GetRestState();
+ if (exhaustionStateID >= 3) then
+ ExhaustionTick:SetPoint("CENTER", "MainMenuExpBar", "RIGHT", 0, 0);
+ end
+
+ if (not exhaustionThreshold) then
+ ExhaustionTick:Hide();
+ ExhaustionLevelFillBar:Hide();
+ else
+ local exhaustionTickSet = max(((playerCurrXP + exhaustionThreshold) / playerMaxXP) * MainMenuExpBar:GetWidth(), 0);
+-- local exhaustionTotalXP = playerCurrXP + (exhaustionMaxXP - exhaustionCurrXP);
+-- local exhaustionTickSet = (exhaustionTotalXP / playerMaxXP) * MainMenuExpBar:GetWidth();
+ ExhaustionTick:ClearAllPoints();
+ if (exhaustionTickSet > MainMenuExpBar:GetWidth() or MainMenuBarMaxLevelBar:IsShown()) then
+ ExhaustionTick:Hide();
+ ExhaustionLevelFillBar:Hide();
+ -- Saving this code in case we want to always leave the exhaustion tick onscreen
+-- ExhaustionTick:SetPoint("CENTER", "MainMenuExpBar", "RIGHT", 0, 0);
+-- ExhaustionLevelFillBar:SetPoint("TOPRIGHT", "MainMenuExpBar", "TOPRIGHT", 0, 0);
+ else
+ ExhaustionTick:Show();
+ ExhaustionTick:SetPoint("CENTER", "MainMenuExpBar", "LEFT", exhaustionTickSet, 0);
+ ExhaustionLevelFillBar:Show();
+ ExhaustionLevelFillBar:SetPoint("TOPRIGHT", "MainMenuExpBar", "TOPLEFT", exhaustionTickSet, 0);
+ end
+ end
+
+ -- Hide exhaustion tick if player is max level or XP is turned off
+ if ( UnitLevel("player") == MAX_PLAYER_LEVEL or IsXPUserDisabled() ) then
+ ExhaustionTick:Hide();
+ end
+ end
+ if ((event == "PLAYER_ENTERING_WORLD") or (event == "UPDATE_EXHAUSTION")) then
+ local exhaustionStateID = GetRestState();
+ if (exhaustionStateID == 1) then
+ MainMenuExpBar:SetStatusBarColor(0.0, 0.39, 0.88, 1.0);
+ ExhaustionLevelFillBar:SetVertexColor(0.0, 0.39, 0.88, 0.15);
+ ExhaustionTickHighlight:SetVertexColor(0.0, 0.39, 0.88);
+ elseif (exhaustionStateID == 2) then
+ MainMenuExpBar:SetStatusBarColor(0.58, 0.0, 0.55, 1.0);
+ ExhaustionLevelFillBar:SetVertexColor(0.58, 0.0, 0.55, 0.15);
+ ExhaustionTickHighlight:SetVertexColor(0.58, 0.0, 0.55);
+ end
+
+ end
+ if ( not MainMenuExpBar:IsShown() ) then
+ ExhaustionTick:Hide();
+ end
+end
+
+function ExhaustionToolTipText()
+ -- If showing newbie tips then only show the explanation
+ --[[if ( SHOW_NEWBIE_TIPS == "1" ) then
+ return;
+ end
+ ]]
+
+ if ( SHOW_NEWBIE_TIPS ~= "1" ) then
+ local x,y;
+ x,y = ExhaustionTick:GetCenter();
+ if ( ExhaustionTick:IsShown() ) then
+ if ( x >= ( GetScreenWidth() / 2 ) ) then
+ GameTooltip:SetOwner(ExhaustionTick, "ANCHOR_LEFT");
+ else
+ GameTooltip:SetOwner(ExhaustionTick, "ANCHOR_RIGHT");
+ end
+ else
+ GameTooltip_SetDefaultAnchor(GameTooltip, UIParent);
+ end
+ end
+
+ local exhaustionStateID, exhaustionStateName, exhaustionStateMultiplier;
+ exhaustionStateID, exhaustionStateName, exhaustionStateMultiplier = GetRestState();
+
+ -- Saving this code in case we want to display xp to next rest state
+ local exhaustionCurrXP, exhaustionMaxXP;
+ local exhaustionThreshold = GetXPExhaustion();
+-- local exhaustionXPDifference;
+-- if (exhaustionMaxXP) then
+-- exhaustionXPDifference = (exhaustionMaxXP - exhaustionCurrXP) * exhaustionStateMultiplier;
+-- else
+-- exhaustionXPDifference = 0;
+-- end
+
+ exhaustionStateMultiplier = exhaustionStateMultiplier * 100;
+ local exhaustionCountdown = nil;
+ if ( GetTimeToWellRested() ) then
+ exhaustionCountdown = GetTimeToWellRested() / 60;
+ end
+
+ local currXP = UnitXP("player");
+ local nextXP = UnitXPMax("player");
+ local percentXP = math.ceil(currXP/nextXP*100);
+
+ local XPText = format( XP_TEXT, currXP, nextXP, percentXP );
+ local tooltipText = XPText..format(EXHAUST_TOOLTIP1, exhaustionStateName, exhaustionStateMultiplier);
+ local append = nil;
+ if ( IsResting() ) then
+ if ( exhaustionThreshold and exhaustionCountdown ) then
+ append = format(EXHAUST_TOOLTIP4, exhaustionCountdown);
+ end
+ elseif ( (exhaustionStateID == 4) or (exhaustionStateID == 5) ) then
+ append = EXHAUST_TOOLTIP2;
+ end
+
+ if ( append ) then
+ tooltipText = tooltipText..append;
+ end
+
+ if ( SHOW_NEWBIE_TIPS ~= "1" ) then
+ GameTooltip:SetText(tooltipText);
+ else
+ if ( GameTooltip.canAddRestStateLine ) then
+ GameTooltip:AddLine("\n"..tooltipText);
+ GameTooltip:Show();
+ GameTooltip.canAddRestStateLine = nil;
+ end
+ end
+
+--[[
+ if ((exhaustionStateID == 1) and (IsResting()) and (not exhaustionThreshold)) then
+ GameTooltip:SetText(format(EXHAUST_TOOLTIP1, exhaustionStateName, exhaustionStateMultiplier));
+ elseif ((exhaustionStateID == 1) and (IsResting())) then
+ GameTooltip:SetText(format(EXHAUST_TOOLTIP1,exhaustionStateName,exhaustionStateMultiplier) .. format(EXHAUST_TOOLTIP4,exhaustionCountdown));
+ elseif ((exhaustionStateID == 2) and (IsResting())) then
+ GameTooltip:SetText(format(EXHAUST_TOOLTIP1,exhaustionStateName,exhaustionStateMultiplier) .. format(EXHAUST_TOOLTIP4,exhaustionCountdown));
+ elseif ((exhaustionStateID == 3) and (IsResting())) then
+ GameTooltip:SetText(format(EXHAUST_TOOLTIP1,exhaustionStateName,exhaustionStateMultiplier) .. format(EXHAUST_TOOLTIP4,exhaustionCountdown));
+ elseif ((exhaustionStateID == 4) and (IsResting())) then
+ GameTooltip:SetText(format(EXHAUST_TOOLTIP1,exhaustionStateName,exhaustionStateMultiplier) .. format(EXHAUST_TOOLTIP4,exhaustionCountdown));
+ elseif ((exhaustionStateID == 5) and (IsResting())) then
+ GameTooltip:SetText(format(EXHAUST_TOOLTIP1,exhaustionStateName,exhaustionStateMultiplier) .. format(EXHAUST_TOOLTIP4,exhaustionCountdown));
+ elseif (exhaustionStateID <= 3) then
+ GameTooltip:SetText(format(EXHAUST_TOOLTIP1,exhaustionStateName,exhaustionStateMultiplier));
+ elseif (exhaustionStateID == 4) then
+ GameTooltip:SetText(format(EXHAUST_TOOLTIP1,exhaustionStateName,exhaustionStateMultiplier) .. EXHAUST_TOOLTIP2);
+ elseif (exhaustionStateID == 5) then
+ GameTooltip:SetText(format(EXHAUST_TOOLTIP1,exhaustionStateName,exhaustionStateMultiplier) .. EXHAUST_TOOLTIP2);
+ end
+]]
+end
+
+function ExhaustionTick_OnUpdate(self, elapsed)
+ if ( self.timer ) then
+ if ( self.timer < 0 ) then
+ ExhaustionToolTipText();
+ self.timer = nil;
+ else
+ self.timer = self.timer - elapsed;
+ end
+ end
+end
+
+--KeyRing Functions
+
+function MainMenuBar_UpdateKeyRing()
+ if ( GetCVarBool("showKeyring") ) then
+ MainMenuBarTexture3:SetTexture("Interface\\MainMenuBar\\UI-MainMenuBar-KeyRing");
+ MainMenuBarTexture3:SetTexCoord(0, 1, 0.1640625, 0.5);
+ MainMenuBarTexture2:SetTexture("Interface\\MainMenuBar\\UI-MainMenuBar-KeyRing");
+ MainMenuBarTexture2:SetTexCoord(0, 1, 0.6640625, 1);
+ KeyRingButton:Show();
+ end
+end
+
+-- latency bar
+
+local NUM_ADDONS_TO_DISPLAY = 3;
+local topAddOns = {}
+for i=1, NUM_ADDONS_TO_DISPLAY do
+ topAddOns[i] = { value = 0, name = "" };
+end
+
+function MainMenuBarPerformanceBarFrame_OnEnter(self)
+ local string = "";
+ local i, j, k = 0, 0, 0;
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+
+ GameTooltip_AddNewbieTip(self, self.tooltipText, 1.0, 1.0, 1.0, self.newbieText);
+
+ -- latency
+ local bandwidthIn, bandwidthOut, latency = GetNetStats();
+ string = format(MAINMENUBAR_LATENCY_LABEL, latency);
+ GameTooltip:AddLine("\n");
+ GameTooltip:AddLine(string, 1.0, 1.0, 1.0);
+ if ( SHOW_NEWBIE_TIPS == "1" ) then
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_LATENCY, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ end
+ GameTooltip:AddLine("\n");
+
+ -- framerate
+ string = format(MAINMENUBAR_FPS_LABEL, GetFramerate());
+ GameTooltip:AddLine(string, 1.0, 1.0, 1.0);
+ if ( SHOW_NEWBIE_TIPS == "1" ) then
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_FRAMERATE, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ end
+
+ -- AddOn mem usage
+ for i=1, NUM_ADDONS_TO_DISPLAY, 1 do
+ topAddOns[i].value = 0;
+ end
+
+ UpdateAddOnMemoryUsage();
+ local totalMem = 0;
+
+ for i=1, GetNumAddOns(), 1 do
+ local mem = GetAddOnMemoryUsage(i);
+ totalMem = totalMem + mem;
+ for j=1, NUM_ADDONS_TO_DISPLAY, 1 do
+ if(mem > topAddOns[j].value) then
+ for k=NUM_ADDONS_TO_DISPLAY, 1, -1 do
+ if(k == j) then
+ topAddOns[k].value = mem;
+ topAddOns[k].name = GetAddOnInfo(i);
+ break;
+ elseif(k ~= 1) then
+ topAddOns[k].value = topAddOns[k-1].value;
+ topAddOns[k].name = topAddOns[k-1].name;
+ end
+ end
+ break;
+ end
+ end
+ end
+
+ if ( totalMem > 0 ) then
+ if ( totalMem > 1000 ) then
+ totalMem = totalMem / 1000;
+ string = format(TOTAL_MEM_MB_ABBR, totalMem);
+ else
+ string = format(TOTAL_MEM_KB_ABBR, totalMem);
+ end
+
+ GameTooltip:AddLine("\n");
+ GameTooltip:AddLine(string, 1.0, 1.0, 1.0);
+ if ( SHOW_NEWBIE_TIPS == "1" ) then
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_MEMORY, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ end
+
+ local size;
+ for i=1, NUM_ADDONS_TO_DISPLAY, 1 do
+ if ( topAddOns[i].value == 0 ) then
+ break;
+ end
+ size = topAddOns[i].value;
+ if ( size > 1000 ) then
+ size = size / 1000;
+ string = format(ADDON_MEM_MB_ABBR, size, topAddOns[i].name);
+ else
+ string = format(ADDON_MEM_KB_ABBR, size, topAddOns[i].name);
+ end
+ GameTooltip:AddLine(string, 1.0, 1.0, 1.0);
+ end
+ end
+
+ GameTooltip:Show();
+end
diff --git a/reference/FrameXML/MainMenuBar.xml b/reference/FrameXML/MainMenuBar.xml
new file mode 100644
index 0000000..fbd74ff
--- /dev/null
+++ b/reference/FrameXML/MainMenuBar.xml
@@ -0,0 +1,389 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MainMenuExpBar.lockShow = 0;
+ SetTextStatusBarText(MainMenuExpBar, MainMenuBarExpText);
+ MainMenuExpBar_Update();
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("PLAYER_XP_UPDATE");
+ self.textLockable = 1;
+ self.cvar = "xpBarText";
+ self.cvarLabel = "XP_BAR_TEXT";
+ self.alwaysPrefix = true;
+
+
+ if ( event == "CVAR_UPDATE" ) then
+ TextStatusBar_OnEvent(self, event, ...);
+ else
+ MainMenuExpBar_Update();
+ end
+
+
+ if ( GetCVar("xpBarText") == "1" ) then
+ TextStatusBar_UpdateTextString(self);
+ end
+
+
+ TextStatusBar_UpdateTextString(self);
+ ShowTextStatusBarText(self);
+ ExhaustionTick.timer = 1;
+ GameTooltip_AddNewbieTip(self, XPBAR_LABEL, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_XPBAR, 1);
+ GameTooltip.canAddRestStateLine = 1;
+
+
+ HideTextStatusBarText(self);
+ GameTooltip:Hide();
+ ExhaustionTick.timer = nil;
+
+
+ ExhaustionTick_OnUpdate(ExhaustionTick, elapsed);
+
+
+ if (not self:IsShown()) then
+ return;
+ end
+ TextStatusBar_OnValueChanged(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, LEAVE_VEHICLE, 1.0, 1.0, 1.0, nil);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaiseFrameLevel(MainMenuBarArtFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/MainMenuBarBagButtons.lua b/reference/FrameXML/MainMenuBarBagButtons.lua
new file mode 100644
index 0000000..5d3081f
--- /dev/null
+++ b/reference/FrameXML/MainMenuBarBagButtons.lua
@@ -0,0 +1,171 @@
+
+function BagSlotButton_UpdateChecked(self)
+ local translatedID = self:GetID() - CharacterBag0Slot:GetID() + 1;
+ local isVisible = 0;
+ local frame;
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ frame = _G["ContainerFrame"..i];
+ if ( (frame:GetID() == translatedID) and frame:IsShown() ) then
+ isVisible = 1;
+ break;
+ end
+ end
+ self:SetChecked(isVisible);
+end
+
+function BagSlotButton_OnClick(self)
+ local id = self:GetID();
+ local translatedID = id - CharacterBag0Slot:GetID() + 1;
+ local hadItem = PutItemInBag(id);
+ if ( not hadItem ) then
+ ToggleBag(translatedID);
+ end
+ BagSlotButton_UpdateChecked(self);
+end
+
+function BagSlotButton_OnModifiedClick(self)
+ if ( IsModifiedClick("OPENALLBAGS") ) then
+ if ( GetInventoryItemTexture("player", self:GetID()) ) then
+ OpenAllBags();
+ end
+ end
+ BagSlotButton_UpdateChecked(self);
+end
+
+function BagSlotButton_OnDrag(self)
+ PickupBagFromSlot(self:GetID());
+ BagSlotButton_UpdateChecked(self);
+end
+
+function BackpackButton_UpdateChecked(self)
+ local isVisible = 0;
+ for i=1, NUM_CONTAINER_FRAMES, 1 do
+ local frame = _G["ContainerFrame"..i];
+ if ( (frame:GetID() == 0) and frame:IsShown() ) then
+ isVisible = 1;
+ break;
+ end
+ end
+ self:SetChecked(isVisible);
+end
+
+function BackpackButton_OnClick(self)
+ if ( not PutItemInBackpack() ) then
+ ToggleBackpack();
+ end
+ BackpackButton_UpdateChecked(self);
+end
+
+function BackpackButton_OnModifiedClick(self)
+ if ( IsModifiedClick("OPENALLBAGS") ) then
+ OpenAllBags();
+ end
+ BackpackButton_UpdateChecked(self);
+end
+
+function ItemAnim_OnLoad(self)
+ self:RegisterEvent("ITEM_PUSH");
+end
+
+function ItemAnim_OnEvent(self, event, ...)
+ if ( event == "ITEM_PUSH" ) then
+ local arg1, arg2 = ...;
+ local id = self:GetParent():GetID();
+ if ( id == arg1 ) then
+ self:ReplaceIconTexture(arg2);
+ self:SetSequence(0);
+ self:SetSequenceTime(0, 0);
+ self:Show();
+ end
+ end
+end
+
+function BagSlotButton_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if ( GameTooltip:SetInventoryItem("player", self:GetID()) ) then
+ local bindingKey = GetBindingKey("TOGGLEBAG"..(4 - (self:GetID() - CharacterBag0Slot:GetID())));
+ if ( bindingKey ) then
+ GameTooltip:AppendText(" "..NORMAL_FONT_COLOR_CODE.."("..bindingKey..")"..FONT_COLOR_CODE_CLOSE);
+ end
+ else
+ GameTooltip:SetText(EQUIP_CONTAINER, 1.0, 1.0, 1.0);
+ end
+end
+
+function ItemAnim_OnAnimFinished(self)
+ self:Hide();
+end
+
+function Disable_BagButtons()
+ MainMenuBarBackpackButton:Disable();
+ SetDesaturation(MainMenuBarBackpackButtonIconTexture, 1);
+ CharacterBag0Slot:Disable();
+ SetDesaturation(CharacterBag0SlotIconTexture, 1);
+ CharacterBag1Slot:Disable();
+ SetDesaturation(CharacterBag1SlotIconTexture, 1);
+ CharacterBag2Slot:Disable();
+ SetDesaturation(CharacterBag2SlotIconTexture, 1);
+ CharacterBag3Slot:Disable();
+ SetDesaturation(CharacterBag3SlotIconTexture, 1);
+end
+
+function Enable_BagButtons()
+ MainMenuBarBackpackButton:Enable();
+ SetDesaturation(MainMenuBarBackpackButtonIconTexture, nil);
+ CharacterBag0Slot:Enable();
+ SetDesaturation(CharacterBag0SlotIconTexture, nil);
+ CharacterBag1Slot:Enable();
+ SetDesaturation(CharacterBag1SlotIconTexture, nil);
+ CharacterBag2Slot:Enable();
+ SetDesaturation(CharacterBag2SlotIconTexture, nil);
+ CharacterBag3Slot:Enable();
+ SetDesaturation(CharacterBag3SlotIconTexture, nil);
+end
+
+function MainMenuBarBackpackButton_OnEvent(self, event, ...)
+ if ( event == "BAG_UPDATE" ) then
+ local bag = ...;
+ if ( bag >= BACKPACK_CONTAINER and bag <= NUM_BAG_SLOTS ) then
+ MainMenuBarBackpackButton_UpdateFreeSlots();
+ end
+ elseif ( event == "PLAYER_ENTERING_WORLD" ) then
+ if ( GetCVar("displayFreeBagSlots") == "1" ) then
+ MainMenuBarBackpackButtonCount:Show();
+ else
+ MainMenuBarBackpackButtonCount:Hide();
+ end
+ MainMenuBarBackpackButton_UpdateFreeSlots();
+ elseif ( event == "CVAR_UPDATE" ) then
+ local cvar, value = ...
+ if ( cvar == "DISPLAY_FREE_BAG_SLOTS" ) then
+ if ( value == "1" ) then
+ MainMenuBarBackpackButtonCount:Show();
+ else
+ MainMenuBarBackpackButtonCount:Hide();
+ end
+ end
+ end
+end
+
+local BACKPACK_FREESLOTS_FORMAT = "(%s)";
+
+function MainMenuBarBackpackButton_UpdateFreeSlots()
+ local totalFree, freeSlots, bagFamily = 0;
+ for i = BACKPACK_CONTAINER, NUM_BAG_SLOTS do
+ freeSlots, bagFamily = GetContainerNumFreeSlots(i);
+ if ( bagFamily == 0 ) then
+ totalFree = totalFree + freeSlots;
+ end
+ end
+
+ if ( totalFree == 3) then
+ TriggerTutorial(59);
+ end
+ if ( totalFree == 0) then
+ TriggerTutorial(58);
+ end
+
+ MainMenuBarBackpackButton.freeSlots = totalFree;
+
+ MainMenuBarBackpackButtonCount:SetText(string.format(BACKPACK_FREESLOTS_FORMAT, totalFree));
+end
diff --git a/reference/FrameXML/MainMenuBarBagButtons.xml b/reference/FrameXML/MainMenuBarBagButtons.xml
new file mode 100644
index 0000000..6700637
--- /dev/null
+++ b/reference/FrameXML/MainMenuBarBagButtons.xml
@@ -0,0 +1,220 @@
+
+
+
+
+
+ ItemAnim_OnLoad(self);
+
+
+ ItemAnim_OnEvent(self, event, ...);
+
+
+ ItemAnim_OnAnimFinished(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollItemSlotButton_OnLoad(self);
+ self:RegisterEvent("BAG_UPDATE");
+ self.isBag = 1;
+ self.UpdateTooltip = BagSlotButton_OnEnter;
+ _G[self:GetName().."NormalTexture"]:SetWidth(50);
+ _G[self:GetName().."NormalTexture"]:SetHeight(50);
+ _G[self:GetName().."Count"]:SetPoint("BOTTOMRIGHT", -2, 2);
+ self.maxDisplayCount = 999;
+
+
+ if ( event == "BAG_UPDATE" ) then
+ PaperDollItemSlotButton_Update(self);
+ else
+ PaperDollItemSlotButton_OnEvent(self, event, ...);
+ end
+
+
+ PaperDollItemSlotButton_OnShow(self);
+
+
+ PaperDollItemSlotButton_OnHide(self);
+
+
+ if ( IsModifiedClick() ) then
+ BagSlotButton_OnModifiedClick(self, button);
+ else
+ BagSlotButton_OnClick(self, button);
+ end
+
+
+ BagSlotButton_OnDrag(self, button);
+
+
+ BagSlotButton_OnClick(self);
+
+
+ BagSlotButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ MainMenuBarBackpackButtonIconTexture:SetTexture("Interface\\Buttons\\Button-Backpack-Up");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("CVAR_UPDATE");
+ self:RegisterEvent("BAG_UPDATE");
+
+
+ if ( IsModifiedClick() ) then
+ BackpackButton_OnModifiedClick(self, button);
+ else
+ BackpackButton_OnClick(self, button);
+ end
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(BACKPACK_TOOLTIP, 1.0, 1.0, 1.0);
+ local keyBinding = GetBindingKey("TOGGLEBACKPACK");
+ if ( keyBinding ) then
+ GameTooltip:AppendText(" "..NORMAL_FONT_COLOR_CODE.."("..keyBinding..")"..FONT_COLOR_CODE_CLOSE);
+ end
+ GameTooltip:AddLine(string.format(NUM_FREE_SLOTS, (self.freeSlots or 0)));
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetID(KEYRING_CONTAINER);
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ if (CursorHasItem()) then
+ PutKeyInKeyRing();
+ else
+ ToggleKeyRing();
+ end
+
+
+ if (CursorHasItem()) then
+ PutKeyInKeyRing();
+ end
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(KEYRING, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/MainMenuBarMicroButtons.lua b/reference/FrameXML/MainMenuBarMicroButtons.lua
new file mode 100644
index 0000000..db36612
--- /dev/null
+++ b/reference/FrameXML/MainMenuBarMicroButtons.lua
@@ -0,0 +1,185 @@
+function LoadMicroButtonTextures(self, name)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:RegisterEvent("UPDATE_BINDINGS");
+ local prefix = "Interface\\Buttons\\UI-MicroButton-";
+ self:SetNormalTexture(prefix..name.."-Up");
+ self:SetPushedTexture(prefix..name.."-Down");
+ self:SetDisabledTexture(prefix..name.."-Disabled");
+ self:SetHighlightTexture("Interface\\Buttons\\UI-MicroButton-Hilight");
+end
+
+function MicroButtonTooltipText(text, action)
+ if ( GetBindingKey(action) ) then
+ return text.." "..NORMAL_FONT_COLOR_CODE.."("..GetBindingText(GetBindingKey(action), "KEY_")..")"..FONT_COLOR_CODE_CLOSE;
+ else
+ return text;
+ end
+
+end
+
+function UpdateMicroButtons()
+ local playerLevel = UnitLevel("player");
+ if ( CharacterFrame:IsShown() ) then
+ CharacterMicroButton:SetButtonState("PUSHED", 1);
+ CharacterMicroButton_SetPushed();
+ else
+ CharacterMicroButton:SetButtonState("NORMAL");
+ CharacterMicroButton_SetNormal();
+ end
+
+ if ( SpellBookFrame:IsShown() ) then
+ SpellbookMicroButton:SetButtonState("PUSHED", 1);
+ else
+ SpellbookMicroButton:SetButtonState("NORMAL");
+ end
+
+ if ( PlayerTalentFrame and PlayerTalentFrame:IsShown() ) then
+ TalentMicroButton:SetButtonState("PUSHED", 1);
+ else
+ if ( playerLevel < TalentMicroButton.minLevel ) then
+ TalentMicroButton:Disable();
+ else
+ TalentMicroButton:Enable();
+ TalentMicroButton:SetButtonState("NORMAL");
+ end
+ end
+
+ if ( QuestLogFrame:IsShown() ) then
+ QuestLogMicroButton:SetButtonState("PUSHED", 1);
+ else
+ QuestLogMicroButton:SetButtonState("NORMAL");
+ end
+
+ if ( ( GameMenuFrame:IsShown() )
+ or ( InterfaceOptionsFrame:IsShown())
+ or ( KeyBindingFrame and KeyBindingFrame:IsShown())
+ or ( MacroFrame and MacroFrame:IsShown()) ) then
+ MainMenuMicroButton:SetButtonState("PUSHED", 1);
+ MainMenuMicroButton_SetPushed();
+ else
+ MainMenuMicroButton:SetButtonState("NORMAL");
+ MainMenuMicroButton_SetNormal();
+ end
+
+ if ( PVPParentFrame:IsShown() and (not PVPFrame_IsJustBG())) then
+ PVPMicroButton:SetButtonState("PUSHED", 1);
+ PVPMicroButton_SetPushed();
+ else
+ if ( playerLevel < PVPMicroButton.minLevel ) then
+ PVPMicroButton:Disable();
+ else
+ PVPMicroButton:Enable();
+ PVPMicroButton:SetButtonState("NORMAL");
+ PVPMicroButton_SetNormal();
+ end
+ end
+
+ if ( FriendsFrame:IsShown() ) then
+ SocialsMicroButton:SetButtonState("PUSHED", 1);
+ else
+ SocialsMicroButton:SetButtonState("NORMAL");
+ end
+
+ if ( LFDParentFrame:IsShown() ) then
+ LFDMicroButton:SetButtonState("PUSHED", 1);
+ else
+ if ( playerLevel < LFDMicroButton.minLevel ) then
+ LFDMicroButton:Disable();
+ else
+ LFDMicroButton:Enable();
+ LFDMicroButton:SetButtonState("NORMAL");
+ end
+ end
+
+ if ( HelpFrame:IsShown() ) then
+ HelpMicroButton:SetButtonState("PUSHED", 1);
+ else
+ HelpMicroButton:SetButtonState("NORMAL");
+ end
+
+ if ( AchievementFrame and AchievementFrame:IsShown() ) then
+ AchievementMicroButton:SetButtonState("PUSHED", 1);
+ else
+ if ( HasCompletedAnyAchievement() and CanShowAchievementUI() ) then
+ AchievementMicroButton:Enable();
+ AchievementMicroButton:SetButtonState("NORMAL");
+ else
+ AchievementMicroButton:Disable();
+ end
+ end
+
+ -- Keyring microbutton
+ if ( IsBagOpen(KEYRING_CONTAINER) ) then
+ KeyRingButton:SetButtonState("PUSHED", 1);
+ else
+ KeyRingButton:SetButtonState("NORMAL");
+ end
+end
+
+function AchievementMicroButton_OnEvent(self, event, ...)
+ if ( event == "UPDATE_BINDINGS" ) then
+ AchievementMicroButton.tooltipText = MicroButtonTooltipText(ACHIEVEMENT_BUTTON, "TOGGLEACHIEVEMENT");
+ else
+ UpdateMicroButtons();
+ end
+end
+
+function CharacterMicroButton_OnLoad(self)
+ self:SetNormalTexture("Interface\\Buttons\\UI-MicroButtonCharacter-Up");
+ self:SetPushedTexture("Interface\\Buttons\\UI-MicroButtonCharacter-Down");
+ self:SetHighlightTexture("Interface\\Buttons\\UI-MicroButton-Hilight");
+ self:RegisterEvent("UNIT_PORTRAIT_UPDATE");
+ self:RegisterEvent("UPDATE_BINDINGS");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self.tooltipText = MicroButtonTooltipText(CHARACTER_BUTTON, "TOGGLECHARACTER0");
+ self.newbieText = NEWBIE_TOOLTIP_CHARACTER;
+end
+
+function CharacterMicroButton_OnEvent(self, event, ...)
+ if ( event == "UNIT_PORTRAIT_UPDATE" ) then
+ local unit = ...;
+ if ( unit == "player" ) then
+ SetPortraitTexture(MicroButtonPortrait, unit);
+ end
+ return;
+ elseif ( event == "PLAYER_ENTERING_WORLD" ) then
+ SetPortraitTexture(MicroButtonPortrait, "player");
+ elseif ( event == "UPDATE_BINDINGS" ) then
+ self.tooltipText = MicroButtonTooltipText(CHARACTER_BUTTON, "TOGGLECHARACTER0");
+ end
+end
+
+function CharacterMicroButton_SetPushed()
+ MicroButtonPortrait:SetTexCoord(0.2666, 0.8666, 0, 0.8333);
+ MicroButtonPortrait:SetAlpha(0.5);
+end
+
+function CharacterMicroButton_SetNormal()
+ MicroButtonPortrait:SetTexCoord(0.2, 0.8, 0.0666, 0.9);
+ MicroButtonPortrait:SetAlpha(1.0);
+end
+
+function MainMenuMicroButton_SetPushed()
+ MainMenuMicroButton:SetButtonState("PUSHED", 1);
+ MainMenuBarPerformanceBar:SetPoint("TOPLEFT", MainMenuMicroButton, "TOPLEFT", 9, -36);
+end
+
+function MainMenuMicroButton_SetNormal()
+ MainMenuMicroButton:SetButtonState("NORMAL");
+ MainMenuBarPerformanceBar:SetPoint("TOPLEFT", MainMenuMicroButton, "TOPLEFT", 10, -34);
+end
+
+--Talent button specific functions
+function TalentMicroButton_OnEvent(self, event, ...)
+ if ( event == "PLAYER_LEVEL_UP" ) then
+ local level = ...;
+ UpdateMicroButtons();
+ if ( not CharacterFrame:IsShown() and level >= SHOW_TALENT_LEVEL) then
+ SetButtonPulse(self, 60, 1);
+ end
+ elseif ( event == "UNIT_LEVEL" or event == "PLAYER_ENTERING_WORLD" ) then
+ UpdateMicroButtons();
+ elseif ( event == "UPDATE_BINDINGS" ) then
+ self.tooltipText = MicroButtonTooltipText(TALENTS_BUTTON, "TOGGLETALENTS");
+ end
+end
diff --git a/reference/FrameXML/MainMenuBarMicroButtons.xml b/reference/FrameXML/MainMenuBarMicroButtons.xml
new file mode 100644
index 0000000..18556d3
--- /dev/null
+++ b/reference/FrameXML/MainMenuBarMicroButtons.xml
@@ -0,0 +1,452 @@
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:IsEnabled() == 1 or self.minLevel ) then
+ GameTooltip_AddNewbieTip(self, self.tooltipText, 1.0, 1.0, 1.0, self.newbieText);
+ GameTooltip:AddLine(" ");
+ if ( self:IsEnabled() == 0 and self.minLevel ) then
+ GameTooltip:AddLine(format(FEATURE_BECOMES_AVAILABLE_AT_LEVEL, self.minLevel), RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b, true);
+ GameTooltip:Show();
+ end
+ end
+
+
+ self:SetAlpha(1);
+
+
+ self:SetAlpha(0.5);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self.down ) then
+ self.down = nil;
+ ToggleCharacter("PaperDollFrame");
+ return;
+ end
+ CharacterMicroButton_SetPushed();
+ self.down = 1;
+
+
+ if ( self.down ) then
+ self.down = nil;
+ if ( self:IsMouseOver() ) then
+ ToggleCharacter("PaperDollFrame");
+ end
+ UpdateMicroButtons();
+ return;
+ end
+ if ( self:GetButtonState() == "NORMAL" ) then
+ CharacterMicroButton_SetPushed();
+ self.down = 1;
+ else
+ CharacterMicroButton_SetNormal();
+ self.down = 1;
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadMicroButtonTextures(self, "Spellbook");
+
+
+ ToggleSpellBook(BOOKTYPE_SPELL);
+
+
+ self.tooltipText = MicroButtonTooltipText(SPELLBOOK_ABILITIES_BUTTON, "TOGGLESPELLBOOK");
+ GameTooltip_AddNewbieTip(self, self.tooltipText, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_SPELLBOOK);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadMicroButtonTextures(self, "Talents");
+ self.tooltipText = MicroButtonTooltipText(TALENTS_BUTTON, "TOGGLETALENTS");
+ self.newbieText = NEWBIE_TOOLTIP_TALENTS;
+ self.minLevel = SHOW_TALENT_LEVEL;
+ self:RegisterEvent("PLAYER_LEVEL_UP");
+ self:RegisterEvent("UPDATE_BINDINGS");
+ self:RegisterEvent("UNIT_LEVEL");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadMicroButtonTextures(self, "Achievement");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("RECEIVED_ACHIEVEMENT_LIST");
+ self:RegisterEvent("ACHIEVEMENT_EARNED");
+ self:RegisterEvent("UPDATE_BINDINGS");
+ self.tooltipText = MicroButtonTooltipText(ACHIEVEMENT_BUTTON, "TOGGLEACHIEVEMENT");
+ self.newbieText = NEWBIE_TOOLTIP_ACHIEVEMENT;
+ self.minLevel = 10; --Just used for display. But we know that it will become available by level 10 due to the level 10 achievement.
+
+
+
+ ToggleAchievementFrame();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadMicroButtonTextures(self, "Quest");
+ self.tooltipText = MicroButtonTooltipText(QUESTLOG_BUTTON, "TOGGLEQUESTLOG");
+ self.newbieText = NEWBIE_TOOLTIP_QUESTLOG;
+
+
+ self.tooltipText = MicroButtonTooltipText(QUESTLOG_BUTTON, "TOGGLEQUESTLOG");
+
+
+ ToggleFrame(QuestLogFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadMicroButtonTextures(self, "Socials");
+ self.tooltipText = MicroButtonTooltipText(SOCIAL_BUTTON, "TOGGLESOCIAL");
+ self.newbieText = NEWBIE_TOOLTIP_SOCIAL;
+
+
+ self.tooltipText = MicroButtonTooltipText(SOCIAL_BUTTON, "TOGGLESOCIAL");
+
+
+ ToggleFriendsFrame();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("UPDATE_BINDINGS");
+
+ self:SetNormalTexture("Interface\\Buttons\\UI-MicroButtonCharacter-Up");
+ self:SetPushedTexture("Interface\\Buttons\\UI-MicroButtonCharacter-Down");
+ self:SetHighlightTexture("Interface\\Buttons\\UI-MicroButton-Hilight");
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ _G[self:GetName().."Texture"]:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..factionGroup);
+ end
+ self.tooltipText = MicroButtonTooltipText(PLAYER_V_PLAYER, "TOGGLECHARACTER4");
+ self.newbieText = NEWBIE_TOOLTIP_PVP;
+ self.minLevel = SHOW_PVP_LEVEL;
+
+
+ self.tooltipText = MicroButtonTooltipText(PLAYER_V_PLAYER, "TOGGLECHARACTER4");
+ self.newbieText = NEWBIE_TOOLTIP_PVP;
+
+
+ if ( self:IsEnabled() ~= 0 ) then
+ if ( self.down ) then
+ self.down = nil;
+ TogglePVPFrame();
+ return;
+ end
+ PVPMicroButton_SetPushed();
+ self.down = 1;
+ end
+
+
+ if ( self:IsEnabled() ~= 0 ) then
+ if ( self.down ) then
+ self.down = nil;
+ if ( self:IsMouseOver() ) then
+ TogglePVPFrame();
+ end
+ UpdateMicroButtons();
+ return;
+ end
+ if ( self:GetButtonState() == "NORMAL" ) then
+ PVPMicroButton_SetPushed();
+ self.down = 1;
+ else
+ PVPMicroButton_SetNormal();
+ self.down = 1;
+ end
+ end
+
+
+ self:SetAlpha(1);
+ SetDesaturation(self.texture, false);
+
+
+ self:SetAlpha(0.5);
+ SetDesaturation(self.texture, true);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadMicroButtonTextures(self, "LFG");
+ SetDesaturation(self:GetDisabledTexture(), true);
+ self.tooltipText = MicroButtonTooltipText(DUNGEONS_BUTTON, "TOGGLELFGPARENT");
+ self.newbieText = NEWBIE_TOOLTIP_LFGPARENT;
+ self.minLevel = SHOW_LFD_LEVEL;
+
+
+ self.tooltipText = MicroButtonTooltipText(DUNGEONS_BUTTON, "TOGGLELFGPARENT");
+ self.newbieText = NEWBIE_TOOLTIP_LFGPARENT;
+
+
+ ToggleLFDParentFrame();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadMicroButtonTextures(self, "MainMenu");
+ self.tooltipText = MicroButtonTooltipText(MAINMENU_BUTTON, "TOGGLEGAMEMENU");
+ self.newbieText = NEWBIE_TOOLTIP_MAINMENU;
+
+ PERFORMANCEBAR_LOW_LATENCY = 300;
+ PERFORMANCEBAR_MEDIUM_LATENCY = 600;
+ PERFORMANCEBAR_UPDATE_INTERVAL = 10;
+ self.hover = nil;
+ self.updateInterval = 0;
+ self:RegisterForClicks("LeftButtonDown", "RightButtonDown", "LeftButtonUp", "RightButtonUp");
+
+
+ if (self.updateInterval > 0) then
+ self.updateInterval = self.updateInterval - elapsed;
+ else
+ self.updateInterval = PERFORMANCEBAR_UPDATE_INTERVAL;
+ local bandwidthIn, bandwidthOut, latency = GetNetStats();
+ if (latency > PERFORMANCEBAR_MEDIUM_LATENCY) then
+ MainMenuBarPerformanceBar:SetVertexColor(1, 0, 0);
+ elseif (latency > PERFORMANCEBAR_LOW_LATENCY) then
+ MainMenuBarPerformanceBar:SetVertexColor(1, 1, 0);
+ else
+ MainMenuBarPerformanceBar:SetVertexColor(0, 1, 0);
+ end
+ if (self.hover) then
+ MainMenuBarPerformanceBarFrame_OnEnter(self);
+ end
+ end
+
+
+ self.tooltipText = MicroButtonTooltipText(MAINMENU_BUTTON, "TOGGLEGAMEMENU");
+
+
+ if ( self.down ) then
+ self.down = nil; -- I'm pretty sure none of this should ever get run.
+ if ( not GameMenuFrame:IsShown() ) then
+ if ( VideoOptionsFrame:IsShown() ) then
+ VideoOptionsFrameCancel:Click();
+ elseif ( AudioOptionsFrame:IsShown() ) then
+ AudioOptionsFrameCancel:Click();
+ elseif ( InterfaceOptionsFrame:IsShown() ) then
+ InterfaceOptionsFrameCancel:Click();
+ end
+ CloseMenus();
+ CloseAllWindows()
+ PlaySound("igMainMenuOpen");
+ ShowUIPanel(GameMenuFrame);
+ else
+ PlaySound("igMainMenuQuit");
+ HideUIPanel(GameMenuFrame);
+ MainMenuMicroButton_SetNormal();
+ end
+ return;
+ end
+ MainMenuMicroButton_SetPushed();
+ self.down = 1;
+
+
+ if ( self.down ) then
+ self.down = nil;
+ if ( self:IsMouseOver() ) then
+ if ( not GameMenuFrame:IsShown() ) then
+ if ( VideoOptionsFrame:IsShown() ) then
+ VideoOptionsFrameCancel:Click();
+ elseif ( AudioOptionsFrame:IsShown() ) then
+ AudioOptionsFrameCancel:Click();
+ elseif ( InterfaceOptionsFrame:IsShown() ) then
+ InterfaceOptionsFrameCancel:Click();
+ end
+ CloseMenus();
+ CloseAllWindows()
+ PlaySound("igMainMenuOpen");
+ ShowUIPanel(GameMenuFrame);
+ else
+ PlaySound("igMainMenuQuit");
+ HideUIPanel(GameMenuFrame);
+ MainMenuMicroButton_SetNormal();
+ end
+ end
+ UpdateMicroButtons();
+ return;
+ end
+ if ( self:GetButtonState() == "NORMAL" ) then
+ MainMenuMicroButton_SetPushed();
+ self.down = 1;
+ else
+ MainMenuMicroButton_SetNormal();
+ self.down = 1;
+ end
+
+
+
+ self.hover = 1;
+ self.updateInterval = 0;
+
+
+ self.hover = nil;
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LoadMicroButtonTextures(self, "Help");
+ self.tooltipText = HELP_BUTTON;
+ self.newbieText = NEWBIE_TOOLTIP_HELP;
+
+
+
+
+
diff --git a/reference/FrameXML/MerchantFrame.lua b/reference/FrameXML/MerchantFrame.lua
new file mode 100644
index 0000000..208785d
--- /dev/null
+++ b/reference/FrameXML/MerchantFrame.lua
@@ -0,0 +1,591 @@
+MERCHANT_ITEMS_PER_PAGE = 10;
+BUYBACK_ITEMS_PER_PAGE = 12;
+MAX_ITEM_COST = 3;
+BACKPACK_WAS_OPEN = nil;
+
+function MerchantFrame_OnLoad(self)
+ self:RegisterEvent("MERCHANT_UPDATE");
+ self:RegisterEvent("MERCHANT_CLOSED");
+ self:RegisterEvent("MERCHANT_SHOW");
+ self:RegisterEvent("GUILDBANK_UPDATE_MONEY");
+ self:RegisterForDrag("LeftButton");
+ self.page = 1;
+ -- Tab Handling code
+ PanelTemplates_SetNumTabs(self, 2);
+ PanelTemplates_SetTab(self, 1);
+end
+
+function MerchantFrame_OnEvent(self, event, ...)
+ if ( event == "MERCHANT_UPDATE" ) then
+ if ( self:IsVisible() ) then
+ MerchantFrame_Update();
+ end
+ elseif ( event == "MERCHANT_CLOSED" ) then
+ HideUIPanel(self);
+ elseif ( event == "MERCHANT_SHOW" ) then
+ ShowUIPanel(self);
+ if ( not self:IsShown() ) then
+ CloseMerchant();
+ return;
+ end
+ self.page = 1;
+ MerchantFrame_Update();
+ elseif ( event == "PLAYER_MONEY" or event == "GUILDBANK_UPDATE_MONEY" or event == "GUILDBANK_UPDATE_WITHDRAWMONEY" ) then
+ MerchantFrame_UpdateCanRepairAll();
+ MerchantFrame_UpdateRepairButtons();
+ end
+end
+
+function MerchantFrame_OnShow()
+ BACKPACK_WAS_OPEN = OpenBackpack();
+
+ -- Update repair all button status
+ MerchantFrame_UpdateCanRepairAll();
+ MerchantFrame_UpdateGuildBankRepair();
+ PanelTemplates_SetTab(MerchantFrame, 1);
+ MerchantFrame_Update();
+
+ PlaySound("igCharacterInfoOpen");
+end
+
+function MerchantFrame_OnHide()
+ CloseMerchant();
+ if ( not BACKPACK_WAS_OPEN ) then
+ CloseBackpack();
+ end
+ ResetCursor();
+
+ StaticPopup_Hide("CONFIRM_PURCHASE_TOKEN_ITEM");
+ StaticPopup_Hide("CONFIRM_REFUND_TOKEN_ITEM");
+ StaticPopup_Hide("CONFIRM_REFUND_MAX_HONOR");
+ StaticPopup_Hide("CONFIRM_REFUND_MAX_ARENA_POINTS");
+ PlaySound("igCharacterInfoClose");
+end
+
+function MerchantFrame_Update()
+ if ( MerchantFrame.selectedTab == 1 ) then
+ MerchantFrame_UpdateMerchantInfo();
+ else
+ MerchantFrame_UpdateBuybackInfo();
+ end
+
+end
+
+function MerchantFrame_UpdateMerchantInfo()
+ MerchantNameText:SetText(UnitName("NPC"));
+ SetPortraitTexture(MerchantFramePortrait, "NPC");
+
+ local numMerchantItems = GetMerchantNumItems();
+
+ MerchantPageText:SetFormattedText(MERCHANT_PAGE_NUMBER, MerchantFrame.page, math.ceil(numMerchantItems / MERCHANT_ITEMS_PER_PAGE));
+
+ local name, texture, price, quantity, numAvailable, isUsable, extendedCost;
+ for i=1, MERCHANT_ITEMS_PER_PAGE, 1 do
+ local index = (((MerchantFrame.page - 1) * MERCHANT_ITEMS_PER_PAGE) + i);
+ local itemButton = _G["MerchantItem"..i.."ItemButton"];
+ local merchantButton = _G["MerchantItem"..i];
+ local merchantMoney = _G["MerchantItem"..i.."MoneyFrame"];
+ local merchantAltCurrency = _G["MerchantItem"..i.."AltCurrencyFrame"];
+ if ( index <= numMerchantItems ) then
+ name, texture, price, quantity, numAvailable, isUsable, extendedCost = GetMerchantItemInfo(index);
+ _G["MerchantItem"..i.."Name"]:SetText(name);
+ SetItemButtonCount(itemButton, quantity);
+ SetItemButtonStock(itemButton, numAvailable);
+ SetItemButtonTexture(itemButton, texture);
+
+ if ( extendedCost and (price <= 0) ) then
+ itemButton.price = nil;
+ itemButton.extendedCost = true;
+ itemButton.link = GetMerchantItemLink(index);
+ itemButton.texture = texture;
+ MerchantFrame_UpdateAltCurrency(index, i);
+ merchantAltCurrency:ClearAllPoints();
+ merchantAltCurrency:SetPoint("BOTTOMLEFT", "MerchantItem"..i.."NameFrame", "BOTTOMLEFT", 0, 31);
+ merchantMoney:Hide();
+ merchantAltCurrency:Show();
+ elseif ( extendedCost and (price > 0) ) then
+ itemButton.price = price;
+ itemButton.extendedCost = true;
+ itemButton.link = GetMerchantItemLink(index);
+ itemButton.texture = texture;
+ MerchantFrame_UpdateAltCurrency(index, i);
+ MoneyFrame_Update(merchantMoney:GetName(), price);
+ merchantAltCurrency:ClearAllPoints();
+ merchantAltCurrency:SetPoint("LEFT", merchantMoney:GetName(), "RIGHT", -14, 0);
+ merchantAltCurrency:Show();
+ merchantMoney:Show();
+ else
+ itemButton.price = price;
+ itemButton.extendedCost = nil;
+ itemButton.link = GetMerchantItemLink(index);
+ itemButton.texture = texture;
+ MoneyFrame_Update(merchantMoney:GetName(), price);
+ merchantAltCurrency:Hide();
+ merchantMoney:Show();
+ end
+
+ itemButton.hasItem = true;
+ itemButton:SetID(index);
+ itemButton:Show();
+ if ( numAvailable == 0 ) then
+ -- If not available and not usable
+ if ( not isUsable ) then
+ SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0, 0);
+ SetItemButtonSlotVertexColor(merchantButton, 0.5, 0, 0);
+ SetItemButtonTextureVertexColor(itemButton, 0.5, 0, 0);
+ SetItemButtonNormalTextureVertexColor(itemButton, 0.5, 0, 0);
+ else
+ SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0.5, 0.5);
+ SetItemButtonSlotVertexColor(merchantButton, 0.5, 0.5, 0.5);
+ SetItemButtonTextureVertexColor(itemButton, 0.5, 0.5, 0.5);
+ SetItemButtonNormalTextureVertexColor(itemButton,0.5, 0.5, 0.5);
+ end
+
+ elseif ( not isUsable ) then
+ SetItemButtonNameFrameVertexColor(merchantButton, 1.0, 0, 0);
+ SetItemButtonSlotVertexColor(merchantButton, 1.0, 0, 0);
+ SetItemButtonTextureVertexColor(itemButton, 0.9, 0, 0);
+ SetItemButtonNormalTextureVertexColor(itemButton, 0.9, 0, 0);
+ else
+ SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0.5, 0.5);
+ SetItemButtonSlotVertexColor(merchantButton, 1.0, 1.0, 1.0);
+ SetItemButtonTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
+ end
+ else
+ itemButton.price = nil;
+ itemButton.hasItem = nil;
+ itemButton:Hide();
+ SetItemButtonNameFrameVertexColor(merchantButton, 0.5, 0.5, 0.5);
+ SetItemButtonSlotVertexColor(merchantButton,0.4, 0.4, 0.4);
+ _G["MerchantItem"..i.."Name"]:SetText("");
+ _G["MerchantItem"..i.."MoneyFrame"]:Hide();
+ _G["MerchantItem"..i.."AltCurrencyFrame"]:Hide();
+ end
+ end
+
+ -- Handle repair items
+ MerchantFrame_UpdateRepairButtons();
+
+ -- Handle vendor buy back item
+ local buybackName, buybackTexture, buybackPrice, buybackQuantity, buybackNumAvailable, buybackIsUsable = GetBuybackItemInfo(GetNumBuybackItems());
+ if ( buybackName ) then
+ MerchantBuyBackItemName:SetText(buybackName);
+ SetItemButtonCount(MerchantBuyBackItemItemButton, buybackQuantity);
+ SetItemButtonStock(MerchantBuyBackItemItemButton, buybackNumAvailable);
+ SetItemButtonTexture(MerchantBuyBackItemItemButton, buybackTexture);
+ MerchantBuyBackItemMoneyFrame:Show();
+ MoneyFrame_Update("MerchantBuyBackItemMoneyFrame", buybackPrice);
+ MerchantBuyBackItem:Show();
+
+ else
+ MerchantBuyBackItemName:SetText("");
+ MerchantBuyBackItemMoneyFrame:Hide();
+ SetItemButtonTexture(MerchantBuyBackItemItemButton, "");
+ SetItemButtonCount(MerchantBuyBackItemItemButton, 0);
+ -- Hide the tooltip upon sale
+ if ( GameTooltip:IsOwned(MerchantBuyBackItemItemButton) ) then
+ GameTooltip:Hide();
+ end
+ end
+
+ -- Handle paging buttons
+ if ( numMerchantItems > MERCHANT_ITEMS_PER_PAGE ) then
+ if ( MerchantFrame.page == 1 ) then
+ MerchantPrevPageButton:Disable();
+ else
+ MerchantPrevPageButton:Enable();
+ end
+ if ( MerchantFrame.page == ceil(numMerchantItems / MERCHANT_ITEMS_PER_PAGE) or numMerchantItems == 0) then
+ MerchantNextPageButton:Disable();
+ else
+ MerchantNextPageButton:Enable();
+ end
+ MerchantPageText:Show();
+ MerchantPrevPageButton:Show();
+ MerchantNextPageButton:Show();
+ else
+ MerchantPageText:Hide();
+ MerchantPrevPageButton:Hide();
+ MerchantNextPageButton:Hide();
+ end
+
+ -- Show all merchant related items
+ MerchantBuyBackItem:Show();
+ MerchantFrameBottomLeftBorder:Show();
+ MerchantFrameBottomRightBorder:Show();
+
+ -- Hide buyback related items
+ MerchantItem11:Hide();
+ MerchantItem12:Hide();
+ BuybackFrameTopLeft:Hide();
+ BuybackFrameTopRight:Hide();
+ BuybackFrameBotLeft:Hide();
+ BuybackFrameBotRight:Hide();
+
+ -- Position merchant items
+ MerchantItem3:SetPoint("TOPLEFT", "MerchantItem1", "BOTTOMLEFT", 0, -8);
+ MerchantItem5:SetPoint("TOPLEFT", "MerchantItem3", "BOTTOMLEFT", 0, -8);
+ MerchantItem7:SetPoint("TOPLEFT", "MerchantItem5", "BOTTOMLEFT", 0, -8);
+ MerchantItem9:SetPoint("TOPLEFT", "MerchantItem7", "BOTTOMLEFT", 0, -8);
+end
+
+function MerchantFrame_UpdateAltCurrency(index, i)
+ local itemTexture, itemValue, button;
+ local honorPoints, arenaPoints, itemCount = GetMerchantItemCostInfo(index);
+ local frameName = "MerchantItem"..i.."AltCurrencyFrame";
+ local frameAnchor = AltCurrencyFrame_PointsUpdate( frameName, honorPoints, arenaPoints );
+
+ -- update Alt Currency Frame with itemValues
+ if ( itemCount > 0 ) then
+ for i=1, MAX_ITEM_COST, 1 do
+ button = _G[frameName.."Item"..i];
+ button.index = index;
+ button.item = i;
+
+ itemTexture, itemValue, button.itemLink = GetMerchantItemCostItem(index, i);
+
+ AltCurrencyFrame_Update(frameName.."Item"..i, itemTexture, itemValue);
+ -- Anchor items based on how many item costs there are.
+
+ if ( i > 1 ) then
+ button:SetPoint("LEFT", frameName.."Item"..i-1, "RIGHT", 4, 0);
+ elseif ( i == 1 and ( arenaPoints and honorPoints == 0 ) ) then
+ button:SetPoint("LEFT", frameAnchor, "LEFT", 0, 0);
+ else
+ button:SetPoint("LEFT", frameAnchor, "RIGHT", 4, 0);
+ end
+ if ( not itemTexture ) then
+ button:Hide();
+ else
+ button:Show();
+ end
+ end
+ else
+ for i=1, MAX_ITEM_COST, 1 do
+ _G[frameName.."Item"..i]:Hide();
+ end
+ end
+end
+
+function MerchantFrame_UpdateBuybackInfo()
+ MerchantNameText:SetText(MERCHANT_BUYBACK);
+ MerchantFramePortrait:SetTexture("Interface\\MerchantFrame\\UI-BuyBack-Icon");
+
+ -- Show Buyback specific items
+ MerchantItem11:Show();
+ MerchantItem12:Show();
+ BuybackFrameTopLeft:Show();
+ BuybackFrameTopRight:Show();
+ BuybackFrameBotLeft:Show();
+ BuybackFrameBotRight:Show();
+
+ -- Position buyback items
+ MerchantItem3:SetPoint("TOPLEFT", "MerchantItem1", "BOTTOMLEFT", 0, -15);
+ MerchantItem5:SetPoint("TOPLEFT", "MerchantItem3", "BOTTOMLEFT", 0, -15);
+ MerchantItem7:SetPoint("TOPLEFT", "MerchantItem5", "BOTTOMLEFT", 0, -15);
+ MerchantItem9:SetPoint("TOPLEFT", "MerchantItem7", "BOTTOMLEFT", 0, -15);
+
+ local numBuybackItems = GetNumBuybackItems();
+ local itemButton, buybackButton;
+ local buybackName, buybackTexture, buybackPrice, buybackQuantity, buybackNumAvailable, buybackIsUsable;
+ for i=1, BUYBACK_ITEMS_PER_PAGE do
+ itemButton = _G["MerchantItem"..i.."ItemButton"];
+ buybackButton = _G["MerchantItem"..i];
+ _G["MerchantItem"..i.."AltCurrencyFrame"]:Hide();
+ if ( i <= numBuybackItems ) then
+ buybackName, buybackTexture, buybackPrice, buybackQuantity, buybackNumAvailable, buybackIsUsable = GetBuybackItemInfo(i);
+ _G["MerchantItem"..i.."Name"]:SetText(buybackName);
+ SetItemButtonCount(itemButton, buybackQuantity);
+ SetItemButtonStock(itemButton, buybackNumAvailable);
+ SetItemButtonTexture(itemButton, buybackTexture);
+ _G["MerchantItem"..i.."MoneyFrame"]:Show();
+ MoneyFrame_Update("MerchantItem"..i.."MoneyFrame", buybackPrice);
+ itemButton:SetID(i);
+ itemButton:Show();
+ if ( not buybackIsUsable ) then
+ SetItemButtonNameFrameVertexColor(buybackButton, 1.0, 0, 0);
+ SetItemButtonSlotVertexColor(buybackButton, 1.0, 0, 0);
+ SetItemButtonTextureVertexColor(itemButton, 0.9, 0, 0);
+ SetItemButtonNormalTextureVertexColor(itemButton, 0.9, 0, 0);
+ else
+ SetItemButtonNameFrameVertexColor(buybackButton, 0.5, 0.5, 0.5);
+ SetItemButtonSlotVertexColor(buybackButton, 1.0, 1.0, 1.0);
+ SetItemButtonTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(itemButton, 1.0, 1.0, 1.0);
+ end
+ else
+ SetItemButtonNameFrameVertexColor(buybackButton, 0.5, 0.5, 0.5);
+ SetItemButtonSlotVertexColor(buybackButton,0.4, 0.4, 0.4);
+ _G["MerchantItem"..i.."Name"]:SetText("");
+ _G["MerchantItem"..i.."MoneyFrame"]:Hide();
+ itemButton:Hide();
+ end
+ end
+
+ -- Hide all merchant related items
+ MerchantRepairAllButton:Hide();
+ MerchantRepairItemButton:Hide();
+ MerchantBuyBackItem:Hide();
+ MerchantPrevPageButton:Hide();
+ MerchantNextPageButton:Hide();
+ MerchantFrameBottomLeftBorder:Hide();
+ MerchantFrameBottomRightBorder:Hide();
+ MerchantRepairText:Hide();
+ MerchantPageText:Hide();
+ MerchantGuildBankRepairButton:Hide();
+end
+
+function MerchantPrevPageButton_OnClick()
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ MerchantFrame.page = MerchantFrame.page - 1;
+ MerchantFrame_Update();
+end
+
+function MerchantNextPageButton_OnClick()
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ MerchantFrame.page = MerchantFrame.page + 1;
+ MerchantFrame_Update();
+end
+
+function MerchantItemBuybackButton_OnLoad(self)
+ self:RegisterEvent("MERCHANT_UPDATE");
+ self:RegisterForClicks("LeftButtonUp","RightButtonUp");
+ self:RegisterForDrag("LeftButton");
+
+ self.SplitStack = function(button, split)
+ if ( split > 0 ) then
+ BuyMerchantItem(button:GetID(), split);
+ end
+ end
+end
+
+function MerchantItemButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp","RightButtonUp");
+ self:RegisterForDrag("LeftButton");
+
+ self.SplitStack = function(button, split)
+ if ( button.extendedCost ) then
+ MerchantFrame_ConfirmExtendedItemCost(button, split)
+ elseif ( split > 0 ) then
+ BuyMerchantItem(button:GetID(), split);
+ end
+ end
+
+ self.UpdateTooltip = MerchantItemButton_OnEnter;
+end
+
+MERCHANT_HIGH_PRICE_COST = 1500000;
+
+function MerchantItemButton_OnClick(self, button)
+ MerchantFrame.extendedCost = nil;
+
+ if ( MerchantFrame.selectedTab == 1 ) then
+ -- Is merchant frame
+ if ( button == "LeftButton" ) then
+ if ( MerchantFrame.refundItem ) then
+ if ( ContainerFrame_GetExtendedPriceString(MerchantFrame.refundItem, MerchantFrame.refundItemEquipped)) then
+ -- a confirmation dialog has been shown
+ return;
+ end
+ end
+
+ PickupMerchantItem(self:GetID());
+ if ( self.extendedCost ) then
+ MerchantFrame.extendedCost = self;
+ end
+ else
+ if ( self.extendedCost ) then
+ MerchantFrame_ConfirmExtendedItemCost(self);
+ elseif ( self.price and self.price >= MERCHANT_HIGH_PRICE_COST ) then
+ MerchantFrame_ConfirmHighCostItem(self);
+ else
+ BuyMerchantItem(self:GetID());
+ end
+ end
+ else
+ -- Is buyback item
+ BuybackItem(self:GetID());
+ end
+end
+
+function MerchantItemButton_OnModifiedClick(self, button)
+ if ( MerchantFrame.selectedTab == 1 ) then
+ -- Is merchant frame
+ if ( HandleModifiedItemClick(GetMerchantItemLink(self:GetID())) ) then
+ return;
+ end
+ if ( IsModifiedClick("SPLITSTACK") ) then
+ local maxStack = GetMerchantItemMaxStack(self:GetID());
+ if ( maxStack > 1 ) then
+ if ( self.price and (self.price > 0) ) then
+ local canAfford = floor(GetMoney() / self.price);
+ if ( canAfford < maxStack ) then
+ maxStack = canAfford;
+ end
+ end
+ OpenStackSplitFrame(maxStack, self, "BOTTOMLEFT", "TOPLEFT");
+ end
+ return;
+ end
+ else
+ HandleModifiedItemClick(GetBuybackItemLink(self:GetID()));
+ end
+end
+
+function MerchantItemButton_OnEnter(button)
+ GameTooltip:SetOwner(button, "ANCHOR_RIGHT");
+ if ( MerchantFrame.selectedTab == 1 ) then
+ GameTooltip:SetMerchantItem(button:GetID());
+ GameTooltip_ShowCompareItem(GameTooltip);
+ MerchantFrame.itemHover = button:GetID();
+ else
+ GameTooltip:SetBuybackItem(button:GetID());
+ if ( IsModifiedClick("DRESSUP") and button.hasItem ) then
+ ShowInspectCursor();
+ else
+ ShowBuybackSellCursor(button:GetID());
+ end
+ end
+end
+
+LIST_DELIMITER = ", "
+
+function MerchantFrame_ConfirmExtendedItemCost(itemButton, quantity)
+ quantity = (quantity or 1);
+ local index = itemButton:GetID();
+ local itemTexture, itemLink, itemsString;
+ local pointsTexture, button;
+ local honorPoints, arenaPoints, itemCount = GetMerchantItemCostInfo(index);
+ if ( (honorPoints == 0) and (arenaPoints == 0) and (itemCount == 0) ) then
+ BuyMerchantItem( itemButton:GetID(), quantity );
+ return;
+ end
+
+ local count = itemButton.count or 1;
+ honorPoints, arenaPoints, itemCount = (honorPoints or 0) * quantity, (arenaPoints or 0) * quantity, (itemCount or 0) * quantity;
+
+ if ( honorPoints and honorPoints ~= 0 ) then
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ pointsTexture = "Interface\\PVPFrame\\PVP-Currency-"..factionGroup;
+ itemsString = " |T" .. pointsTexture .. ":0:0:0:-1|t" .. format(MERCHANT_HONOR_POINTS, honorPoints);
+ end
+ end
+ if ( arenaPoints and arenaPoints ~= 0 ) then
+ if ( itemsString ) then
+ -- adding an extra space here because it looks nicer
+ itemsString = itemsString .. " |TInterface\\PVPFrame\\PVP-ArenaPoints-Icon:0:0:0:-1|t" .. format(MERCHANT_ARENA_POINTS, arenaPoints);
+ else
+ itemsString = " |TInterface\\PVPFrame\\PVP-ArenaPoints-Icon:0:0:0:-1|t" .. format(MERCHANT_ARENA_POINTS, arenaPoints);
+ end
+ end
+
+ local maxQuality = 0;
+ for i=1, MAX_ITEM_COST, 1 do
+ itemTexture, itemCount, itemLink = GetMerchantItemCostItem(index, i);
+ if ( itemLink ) then
+ local _, _, itemQuality = GetItemInfo(itemLink);
+ maxQuality = math.max(itemQuality, maxQuality);
+ if ( itemsString ) then
+ itemsString = itemsString .. LIST_DELIMITER .. format(ITEM_QUANTITY_TEMPLATE, (itemCount or 0) * quantity, itemLink);
+ else
+ itemsString = format(ITEM_QUANTITY_TEMPLATE, (itemCount or 0) * quantity, itemLink);
+ end
+ end
+ end
+
+ if ( honorPoints == 0 and arenaPoints == 0 and maxQuality <= ITEM_QUALITY_UNCOMMON ) then
+ BuyMerchantItem( itemButton:GetID(), quantity );
+ return;
+ end
+
+ MerchantFrame.itemIndex = index;
+ MerchantFrame.count = quantity;
+
+ local itemName, _, itemQuality = GetItemInfo(itemButton.link);
+ local r, g, b = GetItemQualityColor(itemQuality);
+ StaticPopup_Show("CONFIRM_PURCHASE_TOKEN_ITEM", itemsString, "", {["texture"] = itemButton.texture, ["name"] = itemName, ["color"] = {r, g, b, 1}, ["link"] = itemButton.link, ["index"] = index, ["count"] = count * quantity});
+end
+
+function MerchantFrame_ResetRefundItem()
+ MerchantFrame.refundItem = nil;
+ MerchantFrame.refundItemEquipped = nil;
+end
+
+function MerchantFrame_SetRefundItem(item, isEquipped)
+ MerchantFrame.refundItem = item;
+ MerchantFrame.refundItemEquipped = isEquipped;
+end
+
+function MerchantFrame_ConfirmHighCostItem(itemButton, quantity)
+ quantity = (quantity or 1);
+ local index = itemButton:GetID();
+
+ MerchantFrame.itemIndex = index;
+ MerchantFrame.count = quantity;
+ MerchantFrame.price = itemButton.price;
+
+ StaticPopup_Show("CONFIRM_HIGH_COST_ITEM", itemButton.link);
+end
+
+function MerchantFrame_UpdateCanRepairAll()
+ if ( MerchantRepairAllIcon ) then
+ local repairAllCost, canRepair = GetRepairAllCost();
+ if ( canRepair ) then
+ SetDesaturation(MerchantRepairAllIcon, nil);
+ MerchantRepairAllButton:Enable();
+ else
+ SetDesaturation(MerchantRepairAllIcon, 1);
+ MerchantRepairAllButton:Disable();
+ end
+ end
+end
+
+function MerchantFrame_UpdateGuildBankRepair()
+ local repairAllCost, canRepair = GetRepairAllCost();
+ if ( canRepair ) then
+ SetDesaturation(MerchantGuildBankRepairButtonIcon, nil);
+ MerchantGuildBankRepairButton:Enable();
+ else
+ SetDesaturation(MerchantGuildBankRepairButtonIcon, 1);
+ MerchantGuildBankRepairButton:Disable();
+ end
+end
+
+function MerchantFrame_UpdateRepairButtons()
+ if ( CanMerchantRepair() ) then
+ --See if can guildbank repair
+ if ( CanGuildBankRepair() ) then
+ MerchantRepairAllButton:SetWidth(32);
+ MerchantRepairAllButton:SetHeight(32);
+ MerchantRepairItemButton:SetWidth(32);
+ MerchantRepairItemButton:SetHeight(32);
+ MerchantRepairItemButton:SetPoint("RIGHT", MerchantRepairAllButton, "LEFT", -4, 0);
+
+ MerchantRepairAllButton:SetPoint("BOTTOMRIGHT", MerchantFrame, "BOTTOMLEFT", 115, 89);
+ MerchantRepairText:ClearAllPoints();
+ MerchantRepairText:SetPoint("CENTER", MerchantFrame, "BOTTOMLEFT", 97, 129);
+ MerchantGuildBankRepairButton:Show();
+ else
+ MerchantRepairAllButton:SetWidth(36);
+ MerchantRepairAllButton:SetHeight(36);
+ MerchantRepairItemButton:SetWidth(36);
+ MerchantRepairItemButton:SetHeight(36);
+ MerchantRepairItemButton:SetPoint("RIGHT", MerchantRepairAllButton, "LEFT", -2, 0);
+
+ MerchantRepairAllButton:SetPoint("BOTTOMRIGHT", MerchantFrame, "BOTTOMLEFT", 172, 91);
+ MerchantRepairText:ClearAllPoints();
+ MerchantRepairText:SetPoint("BOTTOMLEFT", MerchantFrame, "BOTTOMLEFT", 26, 103);
+ MerchantGuildBankRepairButton:Hide();
+ end
+ MerchantRepairText:Show();
+ MerchantRepairAllButton:Show();
+ MerchantRepairItemButton:Show();
+ else
+ MerchantRepairText:Hide();
+ MerchantRepairAllButton:Hide();
+ MerchantRepairItemButton:Hide();
+ MerchantGuildBankRepairButton:Hide();
+ end
+end
diff --git a/reference/FrameXML/MerchantFrame.xml b/reference/FrameXML/MerchantFrame.xml
new file mode 100644
index 0000000..8efa8a6
--- /dev/null
+++ b/reference/FrameXML/MerchantFrame.xml
@@ -0,0 +1,808 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsModifiedClick() ) then
+ MerchantItemButton_OnModifiedClick(self, button);
+ else
+ MerchantItemButton_OnClick(self, button);
+ end
+
+
+ MerchantItemButton_OnLoad(self);
+
+
+ MerchantItemButton_OnClick(self, "LeftButton");
+
+
+ MerchantItemButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+ MerchantFrame.itemHover = nil;
+
+
+ if ( self.hasStackSplit == 1 ) then
+ StackSplitFrame:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ local repairAllCost, canRepair = GetRepairAllCost();
+ if ( canRepair and (repairAllCost > 0) ) then
+ GameTooltip:SetText(REPAIR_ALL_ITEMS);
+ SetTooltipMoney(GameTooltip, repairAllCost);
+ end
+ GameTooltip:Show();
+
+
+
+ RepairAllItems();
+ PlaySound("ITEM_REPAIR");
+ GameTooltip:Hide();
+
+
+ local _, canRepair = GetRepairAllCost();
+ if ( not canRepair ) then
+ SetDesaturation(MerchantRepairAllIcon, 1);
+ SetDesaturation(MerchantGuildBankRepairButtonIcon, 1);
+ MerchantGuildBankRepairButton:Disable();
+ self:Disable();
+ else
+ SetDesaturation(MerchantRepairAllIcon, nil);
+ SetDesaturation(MerchantGuildBankRepairButtonIcon, nil);
+ self:Enable();
+ MerchantGuildBankRepairButton:Enable();
+ end
+
+
+ self:RegisterEvent("UPDATE_INVENTORY_DURABILITY");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(REPAIR_AN_ITEM);
+
+
+
+ if ( InRepairMode() ) then
+ MerchantFrame:UnregisterEvent("PLAYER_MONEY");
+ HideRepairCursor();
+ else
+ MerchantFrame:RegisterEvent("PLAYER_MONEY");
+ ShowRepairCursor();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ local repairAllCost, canRepair = GetRepairAllCost();
+ if ( canRepair and (repairAllCost > 0) ) then
+ GameTooltip:SetText(REPAIR_ALL_ITEMS);
+ SetTooltipMoney(GameTooltip, repairAllCost);
+ local amount = GetGuildBankWithdrawMoney();
+ local guildBankMoney = GetGuildBankMoney();
+ if ( amount == -1 ) then
+ -- Guild leader shows full guild bank amount
+ amount = guildBankMoney;
+ else
+ amount = min(amount, guildBankMoney);
+ end
+ GameTooltip:AddLine(GUILDBANK_REPAIR, nil, nil, nil, 1);
+ SetTooltipMoney(GameTooltip, amount, "GUILD_REPAIR");
+ GameTooltip:Show();
+ end
+
+
+
+ --FIXME!!! Need actual amount of guild money left to withdraw
+ if(CanGuildBankRepair()) then
+ RepairAllItems(1);
+ PlaySound("ITEM_REPAIR");
+ end
+ GameTooltip:Hide();
+
+
+ local _, canRepair = GetRepairAllCost();
+ if ( not canRepair ) then
+ SetDesaturation(MerchantRepairAllIcon, 1);
+ SetDesaturation(MerchantGuildBankRepairButtonIcon, 1);
+ MerchantGuildBankRepairButton:Disable();
+ MerchantRepairAllButton:Disable();
+ else
+ SetDesaturation(MerchantRepairAllIcon, nil);
+ SetDesaturation(MerchantGuildBankRepairButtonIcon, nil);
+ self:Enable();
+ MerchantRepairAllButton:Enable();
+ end
+
+
+ self:RegisterEvent("UPDATE_INVENTORY_DURABILITY");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( event == "MERCHANT_UPDATE" ) then
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetBuybackItem(GetNumBuybackItems());
+ GameTooltip:Show();
+ end
+ end
+
+
+ BuybackItem(GetNumBuybackItems());
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetBuybackItem(GetNumBuybackItems());
+ ShowMerchantSellCursor(self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText("", 1.0,1.0,1.0 );
+
+
+
+ PanelTemplates_SetTab(MerchantFrame, self:GetID());
+ MerchantFrame_Update();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText("", 1.0,1.0,1.0 );
+
+
+
+ PanelTemplates_SetTab(MerchantFrame, self:GetID());
+ MerchantFrame_Update();
+
+
+
+
+
+
+
+
+
+
+ if ( MerchantFrame.itemHover ) then
+ if ( IsModifiedClick("DRESSUP") ) then
+ ShowInspectCursor();
+ else
+ ShowMerchantSellCursor(MerchantFrame.itemHover);
+ end
+ end
+ if ( MerchantRepairItemButton:IsShown() ) then
+ if ( InRepairMode() ) then
+ MerchantRepairItemButton:LockHighlight();
+ else
+ MerchantRepairItemButton:UnlockHighlight();
+ end
+ end
+
+
+ if ( MerchantFrame.refundItem ) then
+ if ( ContainerFrame_GetExtendedPriceString(MerchantFrame.refundItem, MerchantFrame.refundItemEquipped)) then
+ -- a confirmation dialog has been shown
+ return;
+ end
+ end
+ PickupMerchantItem(0);
+
+
+ MerchantItemButton_OnClick(self, "LeftButton");
+
+
+
+
diff --git a/reference/FrameXML/MinigameFrame.lua b/reference/FrameXML/MinigameFrame.lua
new file mode 100644
index 0000000..4720fef
--- /dev/null
+++ b/reference/FrameXML/MinigameFrame.lua
@@ -0,0 +1,19 @@
+function MinigameFrame_OnEvent(self, event, ...)
+ local gameType = GetMinigameType();
+ if ( not gameType ) then
+ return;
+ end
+ if ( event == "START_MINIGAME" ) then
+ ShowUIPanel(self);
+ _G[gameType.."Frame"]:Show();
+ elseif ( event == "MINIGAME_UPDATE" ) then
+ local updateFunc = _G[gameType.."_Update"];
+ if ( updateFunc ) then
+ updateFunc();
+ end
+ end
+end
+
+function MinigameFrame_Update()
+ GetMinigameState();
+end
\ No newline at end of file
diff --git a/reference/FrameXML/MinigameFrame.xml b/reference/FrameXML/MinigameFrame.xml
new file mode 100644
index 0000000..02bc92c
--- /dev/null
+++ b/reference/FrameXML/MinigameFrame.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("START_MINIGAME");
+ self:RegisterEvent("MINIGAME_UPDATE");
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/Minimap.lua b/reference/FrameXML/Minimap.lua
new file mode 100644
index 0000000..b54deaf
--- /dev/null
+++ b/reference/FrameXML/Minimap.lua
@@ -0,0 +1,537 @@
+MINIMAPPING_TIMER = 5.5;
+MINIMAPPING_FADE_TIMER = 0.5;
+
+MINIMAP_RECORDING_INDICATOR_ON = false;
+
+MINIMAP_EXPANDER_MAXSIZE = 28;
+
+function MinimapPing_OnLoad(self)
+ -- self:SetFrameLevel(self:GetFrameLevel() + 1);
+ self.fadeOut = nil;
+ Minimap:SetPlayerTextureHeight(40);
+ Minimap:SetPlayerTextureWidth(40);
+ self:RegisterEvent("MINIMAP_PING");
+ self:RegisterEvent("MINIMAP_UPDATE_ZOOM");
+end
+
+function ToggleMinimap()
+ if(Minimap:IsShown()) then
+ PlaySound("igMiniMapClose");
+ Minimap:Hide();
+ else
+ PlaySound("igMiniMapOpen");
+ Minimap:Show();
+ end
+ UpdateUIPanelPositions();
+end
+
+function Minimap_Update()
+ MinimapZoneText:SetText(GetMinimapZoneText());
+
+ local pvpType, isSubZonePvP, factionName = GetZonePVPInfo();
+ if ( pvpType == "sanctuary" ) then
+ MinimapZoneText:SetTextColor(0.41, 0.8, 0.94);
+ elseif ( pvpType == "arena" ) then
+ MinimapZoneText:SetTextColor(1.0, 0.1, 0.1);
+ elseif ( pvpType == "friendly" ) then
+ MinimapZoneText:SetTextColor(0.1, 1.0, 0.1);
+ elseif ( pvpType == "hostile" ) then
+ MinimapZoneText:SetTextColor(1.0, 0.1, 0.1);
+ elseif ( pvpType == "contested" ) then
+ MinimapZoneText:SetTextColor(1.0, 0.7, 0.0);
+ else
+ MinimapZoneText:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+
+ Minimap_SetTooltip( pvpType, factionName );
+end
+
+function Minimap_SetTooltip( pvpType, factionName )
+ if ( GameTooltip:IsOwned(MinimapZoneTextButton) ) then
+ GameTooltip:SetOwner(MinimapZoneTextButton, "ANCHOR_LEFT");
+ local zoneName = GetZoneText();
+ local subzoneName = GetSubZoneText();
+ if ( subzoneName == zoneName ) then
+ subzoneName = "";
+ end
+ GameTooltip:AddLine( zoneName, 1.0, 1.0, 1.0 );
+ if ( pvpType == "sanctuary" ) then
+ GameTooltip:AddLine( subzoneName, 0.41, 0.8, 0.94 );
+ GameTooltip:AddLine(SANCTUARY_TERRITORY, 0.41, 0.8, 0.94);
+ elseif ( pvpType == "arena" ) then
+ GameTooltip:AddLine( subzoneName, 1.0, 0.1, 0.1 );
+ GameTooltip:AddLine(FREE_FOR_ALL_TERRITORY, 1.0, 0.1, 0.1);
+ elseif ( pvpType == "friendly" ) then
+ GameTooltip:AddLine( subzoneName, 0.1, 1.0, 0.1 );
+ GameTooltip:AddLine(format(FACTION_CONTROLLED_TERRITORY, factionName), 0.1, 1.0, 0.1);
+ elseif ( pvpType == "hostile" ) then
+ GameTooltip:AddLine( subzoneName, 1.0, 0.1, 0.1 );
+ GameTooltip:AddLine(format(FACTION_CONTROLLED_TERRITORY, factionName), 1.0, 0.1, 0.1);
+ elseif ( pvpType == "contested" ) then
+ GameTooltip:AddLine( subzoneName, 1.0, 0.7, 0.0 );
+ GameTooltip:AddLine(CONTESTED_TERRITORY, 1.0, 0.7, 0.0);
+ elseif ( pvpType == "combat" ) then
+ GameTooltip:AddLine( subzoneName, 1.0, 0.1, 0.1 );
+ GameTooltip:AddLine(COMBAT_ZONE, 1.0, 0.1, 0.1);
+ else
+ GameTooltip:AddLine( subzoneName, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b );
+ end
+ GameTooltip:Show();
+ end
+end
+
+function MinimapPing_OnEvent(self, event, ...)
+ if ( event == "MINIMAP_PING" ) then
+ local arg1, arg2, arg3 = ...;
+ Minimap_SetPing(arg2, arg3, 1);
+ self.timer = MINIMAPPING_TIMER;
+ elseif ( event == "MINIMAP_UPDATE_ZOOM" ) then
+ MinimapZoomIn:Enable();
+ MinimapZoomOut:Enable();
+ local zoom = Minimap:GetZoom();
+ if ( zoom == (Minimap:GetZoomLevels() - 1) ) then
+ MinimapZoomIn:Disable();
+ elseif ( zoom == 0 ) then
+ MinimapZoomOut:Disable();
+ end
+ end
+end
+
+function MinimapPing_OnUpdate(self, elapsed)
+ local timer = self.timer or 0;
+ if ( timer > 0 ) then
+ timer = timer - elapsed;
+ if ( not self.fadeOut and timer <= MINIMAPPING_FADE_TIMER ) then
+ MinimapPing_FadeOut();
+ end
+ local percentage = timer - floor(timer)
+ MinimapPingSpinner:SetRotation(percentage * math.pi/2);
+ -- We want about 7 expansions per ping to match the old animation.
+ percentage = mod(timer, MINIMAPPING_TIMER/7);
+ MinimapPingExpander:SetHeight(MINIMAP_EXPANDER_MAXSIZE * (1 - percentage));
+ MinimapPingExpander:SetWidth(MINIMAP_EXPANDER_MAXSIZE * (1 - percentage));
+
+ self.timer = timer;
+ end
+ if ( self.fadeOut ) then
+ local fadeOutTimer = self.fadeOutTimer - elapsed;
+
+ if ( fadeOutTimer > 0 ) then
+ MinimapPing:SetAlpha(fadeOutTimer/MINIMAPPING_FADE_TIMER);
+ else
+ MinimapPing.fadeOut = nil;
+ MinimapPing:Hide();
+ end
+ self.fadeOutTimer = fadeOutTimer;
+ end
+end
+
+function Minimap_SetPing(x, y, playSound)
+ x = x * Minimap:GetWidth();
+ y = y * Minimap:GetHeight();
+
+ if ( sqrt(x * x + y * y) < (Minimap:GetWidth() / 2) ) then
+ MinimapPing:SetPoint("CENTER", "Minimap", "CENTER", x, y);
+ MinimapPing:SetAlpha(1);
+ MinimapPing:Show();
+ if ( playSound ) then
+ PlaySound("MapPing");
+ end
+ else
+ MinimapPing:Hide();
+ end
+end
+
+function MiniMapBattlefieldFrame_OnUpdate (self, elapsed)
+ if ( GameTooltip:IsOwned(self) ) then
+ BattlefieldFrame_UpdateStatus(1);
+ if ( self.tooltip ) then
+ GameTooltip:SetText(self.tooltip);
+ end
+ end
+end
+
+function MinimapPing_FadeOut()
+ MinimapPing.fadeOut = 1;
+ MinimapPing.fadeOutTimer = MINIMAPPING_FADE_TIMER;
+end
+
+function Minimap_ZoomInClick()
+ MinimapZoomOut:Enable();
+ PlaySound("igMiniMapZoomIn");
+ Minimap:SetZoom(Minimap:GetZoom() + 1);
+ if(Minimap:GetZoom() == (Minimap:GetZoomLevels() - 1)) then
+ MinimapZoomIn:Disable();
+ end
+end
+
+function Minimap_ZoomOutClick()
+ MinimapZoomIn:Enable();
+ PlaySound("igMiniMapZoomOut");
+ Minimap:SetZoom(Minimap:GetZoom() - 1);
+ if(Minimap:GetZoom() == 0) then
+ MinimapZoomOut:Disable();
+ end
+end
+
+function Minimap_OnClick(self)
+ local x, y = GetCursorPosition();
+ x = x / self:GetEffectiveScale();
+ y = y / self:GetEffectiveScale();
+
+ local cx, cy = self:GetCenter();
+ x = x - cx;
+ y = y - cy;
+ if ( sqrt(x * x + y * y) < (self:GetWidth() / 2) ) then
+ Minimap:PingLocation(x, y);
+ end
+end
+
+function Minimap_ZoomIn()
+ MinimapZoomIn:Click();
+end
+
+function Minimap_ZoomOut()
+ MinimapZoomOut:Click();
+end
+
+function EyeTemplate_OnUpdate(self, elapsed)
+ AnimateTexCoords(self.texture, 512, 256, 64, 64, 29, elapsed)
+end
+
+function EyeTemplate_StartAnimating(eye)
+ eye:SetScript("OnUpdate", EyeTemplate_OnUpdate);
+end
+
+function EyeTemplate_StopAnimating(eye)
+ eye:SetScript("OnUpdate", nil);
+ if ( eye.texture.frame ) then
+ eye.texture.frame = 1; --To start the animation over.
+ end
+ eye.texture:SetTexCoord(0, 0.125, 0, .25);
+end
+
+function MiniMapLFG_UpdateIsShown()
+ local mode, submode = GetLFGMode();
+ if ( mode ) then
+ MiniMapLFGFrame:Show();
+ if ( mode == "queued" or mode == "listed" or mode == "rolecheck" ) then
+ EyeTemplate_StartAnimating(MiniMapLFGFrame.eye);
+ else
+ EyeTemplate_StopAnimating(MiniMapLFGFrame.eye);
+ end
+ else
+ MiniMapLFGFrame:Hide();
+ end
+end
+
+function MiniMapLFGFrame_TeleportIn()
+ LFGTeleport(false);
+end
+
+function MiniMapLFGFrame_TeleportOut()
+ LFGTeleport(true);
+end
+
+function MiniMapLFGFrameDropDown_Update()
+ local info = UIDropDownMenu_CreateInfo();
+
+ local mode, submode = GetLFGMode();
+
+ --This one can appear in addition to others, so we won't just check the mode.
+ if ( IsPartyLFG() ) then
+ local addButton = false;
+ if ( IsInLFGDungeon() ) then
+ info.text = TELEPORT_OUT_OF_DUNGEON;
+ info.func = MiniMapLFGFrame_TeleportOut;
+ addButton = true;
+ elseif ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0)) then
+ info.text = TELEPORT_TO_DUNGEON;
+ info.func = MiniMapLFGFrame_TeleportIn;
+ addButton = true;
+ end
+ if ( addButton ) then
+ UIDropDownMenu_AddButton(info);
+ end
+ end
+
+ if ( mode == "proposal" and submode == "unaccepted" ) then
+ info.text = ENTER_DUNGEON;
+ info.func = AcceptProposal;
+ UIDropDownMenu_AddButton(info);
+
+ info.text = LEAVE_QUEUE;
+ info.func = RejectProposal;
+ UIDropDownMenu_AddButton(info);
+ elseif ( mode == "queued" ) then
+ info.text = LEAVE_QUEUE;
+ info.func = LeaveLFG;
+ info.disabled = (submode == "unempowered");
+ UIDropDownMenu_AddButton(info);
+ elseif ( mode == "listed" ) then
+ if ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0)) then
+ info.text = UNLIST_MY_GROUP;
+ else
+ info.text = UNLIST_ME;
+ end
+ info.func = LeaveLFG;
+ info.disabled = (submode == "unempowered");
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function MiniMapLFGFrame_OnClick(self, button)
+ local mode, submode = GetLFGMode();
+ if ( button == "RightButton" or mode == "lfgparty" or mode == "abandonedInDungeon") then
+ --Display dropdown
+ PlaySound("igMainMenuOpen");
+ --Weird hack so that the popup isn't under the queued status window (bug 184001)
+ local yOffset;
+ if ( mode == "queued" ) then
+ MiniMapLFGFrameDropDown.point = "BOTTOMRIGHT";
+ MiniMapLFGFrameDropDown.relativePoint = "TOPLEFT";
+ yOffset = 0;
+ else
+ MiniMapLFGFrameDropDown.point = nil;
+ MiniMapLFGFrameDropDown.relativePoint = nil;
+ yOffset = -5;
+ end
+ ToggleDropDownMenu(1, nil, MiniMapLFGFrameDropDown, "MiniMapLFGFrame", 0, yOffset);
+ elseif ( mode == "proposal" ) then
+ if ( not LFDDungeonReadyPopup:IsShown() ) then
+ PlaySound("igCharacterInfoTab");
+ StaticPopupSpecial_Show(LFDDungeonReadyPopup);
+ end
+ elseif ( mode == "queued" or mode == "rolecheck" ) then
+ ToggleLFDParentFrame();
+ elseif ( mode == "listed" ) then
+ ToggleLFRParentFrame();
+ end
+end
+
+function MiniMapLFGFrame_OnEnter(self)
+ local mode, submode = GetLFGMode();
+ if ( mode == "queued" ) then
+ LFDSearchStatus:Show();
+ elseif ( mode == "proposal" ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(LOOKING_FOR_DUNGEON);
+ GameTooltip:AddLine(DUNGEON_GROUP_FOUND_TOOLTIP, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:AddLine(" ");
+ GameTooltip:AddLine(CLICK_HERE_FOR_MORE_INFO, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+ elseif ( mode == "rolecheck" ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(LOOKING_FOR_DUNGEON);
+ GameTooltip:AddLine(ROLE_CHECK_IN_PROGRESS_TOOLTIP, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+ elseif ( mode == "listed" ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(LOOKING_FOR_RAID);
+ GameTooltip:AddLine(YOU_ARE_LISTED_IN_LFR, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+ elseif ( mode == "lfgparty" ) then
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ GameTooltip:SetText(LOOKING_FOR_DUNGEON);
+ GameTooltip:AddLine(YOU_ARE_IN_DUNGEON_GROUP, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+ end
+end
+
+function MiniMapLFGFrame_OnLeave(self)
+ GameTooltip:Hide();
+ LFDSearchStatus:Hide();
+end
+
+function MinimapButton_OnMouseDown(self, button)
+ if ( self.isDown ) then
+ return;
+ end
+ local button = _G[self:GetName().."Icon"];
+ local point, relativeTo, relativePoint, offsetX, offsetY = button:GetPoint();
+ button:SetPoint(point, relativeTo, relativePoint, offsetX+1, offsetY-1);
+ self.isDown = 1;
+end
+function MinimapButton_OnMouseUp(self)
+ if ( not self.isDown ) then
+ return;
+ end
+ local button = _G[self:GetName().."Icon"];
+ local point, relativeTo, relativePoint, offsetX, offsetY = button:GetPoint();
+ button:SetPoint(point, relativeTo, relativePoint, offsetX-1, offsetY+1);
+ self.isDown = nil;
+end
+
+function Minimap_UpdateRotationSetting()
+ if ( GetCVar("rotateMinimap") == "1" ) then
+ MinimapCompassTexture:Show();
+ MinimapNorthTag:Hide();
+ else
+ MinimapCompassTexture:Hide();
+ MinimapNorthTag:Show();
+ end
+end
+
+function ToggleMiniMapRotation()
+ local rotate = GetCVar("rotateMinimap");
+ if ( rotate == "1" ) then
+ rotate = "0";
+ else
+ rotate = "1";
+ end
+ SetCVar("rotateMinimap", rotate);
+ Minimap_UpdateRotationSetting();
+end
+
+function MinimapMailFrameUpdate()
+ local sender1,sender2,sender3 = GetLatestThreeSenders();
+ local toolText;
+
+ if( sender1 or sender2 or sender3 ) then
+ toolText = HAVE_MAIL_FROM;
+ else
+ toolText = HAVE_MAIL;
+ end
+
+ if( sender1 ) then
+ toolText = toolText.."\n"..sender1;
+ end
+ if( sender2 ) then
+ toolText = toolText.."\n"..sender2;
+ end
+ if( sender3 ) then
+ toolText = toolText.."\n"..sender3;
+ end
+ GameTooltip:SetText(toolText);
+end
+
+function MiniMapTracking_Update()
+ local texture = GetTrackingTexture();
+ if ( MiniMapTrackingIcon:GetTexture() ~= texture ) then
+ MiniMapTrackingIcon:SetTexture(texture);
+ MiniMapTrackingShineFadeIn();
+ end
+end
+
+function MiniMapTrackingDropDown_OnLoad(self)
+ UIDropDownMenu_Initialize(self, MiniMapTrackingDropDown_Initialize, "MENU");
+end
+
+function MiniMapTracking_SetTracking (self, id)
+ SetTracking(id);
+end
+
+function MiniMapTrackingDropDown_Initialize()
+ local name, texture, active, category;
+ local anyActive, checked;
+ local count = GetNumTrackingTypes();
+ local info;
+ for id=1, count do
+ name, texture, active, category = GetTrackingInfo(id);
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = name;
+ info.checked = active;
+ info.func = MiniMapTracking_SetTracking;
+ info.icon = texture;
+ info.arg1 = id;
+ if ( category == "spell" ) then
+ info.tCoordLeft = 0.0625;
+ info.tCoordRight = 0.9;
+ info.tCoordTop = 0.0625;
+ info.tCoordBottom = 0.9;
+ else
+ info.tCoordLeft = 0;
+ info.tCoordRight = 1;
+ info.tCoordTop = 0;
+ info.tCoordBottom = 1;
+ end
+ UIDropDownMenu_AddButton(info);
+ if ( active ) then
+ anyActive = active;
+ end
+ end
+
+ if ( anyActive ) then
+ checked = nil;
+ else
+ checked = 1;
+ end
+
+ info = UIDropDownMenu_CreateInfo();
+ info.text = NONE;
+ info.checked = checked;
+ info.func = MiniMapTracking_SetTracking;
+ info.arg1 = nil;
+ UIDropDownMenu_AddButton(info);
+
+end
+
+function MiniMapTrackingShineFadeIn()
+ -- Fade in the shine and then fade it out with the ComboPointShineFadeOut function
+ local fadeInfo = {};
+ fadeInfo.mode = "IN";
+ fadeInfo.timeToFade = 0.5;
+ fadeInfo.finishedFunc = MiniMapTrackingShineFadeOut;
+ UIFrameFade(MiniMapTrackingButtonShine, fadeInfo);
+end
+
+function MiniMapTrackingShineFadeOut()
+ UIFrameFadeOut(MiniMapTrackingButtonShine, 0.5);
+end
+
+local selectedRaidDifficulty;
+local allowedRaidDifficulty;
+function MiniMapInstanceDifficulty_OnEvent(self)
+ local _, instanceType, difficulty, _, maxPlayers, playerDifficulty, isDynamicInstance = GetInstanceInfo();
+ if ( ( instanceType == "party" or instanceType == "raid" ) and not ( difficulty == 1 and maxPlayers == 5 ) ) then
+ local isHeroic = false;
+ if ( instanceType == "party" and difficulty == 2 ) then
+ isHeroic = true;
+ elseif ( instanceType == "raid" ) then
+ if ( isDynamicInstance ) then
+ selectedRaidDifficulty = difficulty;
+ if ( playerDifficulty == 1 ) then
+ if ( selectedRaidDifficulty <= 2 ) then
+ selectedRaidDifficulty = selectedRaidDifficulty + 2;
+ end
+ isHeroic = true;
+ end
+ -- if modified difficulty is normal then you are allowed to select heroic, and vice-versa
+ if ( selectedRaidDifficulty == 1 ) then
+ allowedRaidDifficulty = 3;
+ elseif ( selectedRaidDifficulty == 2 ) then
+ allowedRaidDifficulty = 4;
+ elseif ( selectedRaidDifficulty == 3 ) then
+ allowedRaidDifficulty = 1;
+ elseif ( selectedRaidDifficulty == 4 ) then
+ allowedRaidDifficulty = 2;
+ end
+ allowedRaidDifficulty = "RAID_DIFFICULTY"..allowedRaidDifficulty;
+ elseif ( difficulty > 2 ) then
+ isHeroic = true;
+ end
+ end
+
+ MiniMapInstanceDifficultyText:SetText(maxPlayers);
+ -- the 1 looks a little off when text is centered
+ local xOffset = 0;
+ if ( maxPlayers >= 10 and maxPlayers <= 19 ) then
+ xOffset = -1;
+ end
+ if ( isHeroic ) then
+ MiniMapInstanceDifficultyTexture:SetTexCoord(0, 0.25, 0.0703125, 0.4140625);
+ MiniMapInstanceDifficultyText:SetPoint("CENTER", xOffset, -9);
+ else
+ MiniMapInstanceDifficultyTexture:SetTexCoord(0, 0.25, 0.5703125, 0.9140625);
+ MiniMapInstanceDifficultyText:SetPoint("CENTER", xOffset, 5);
+ end
+ self:Show();
+ else
+ self:Hide();
+ end
+end
+
+function _GetPlayerDifficultyMenuOptions()
+ return selectedRaidDifficulty, allowedRaidDifficulty;
+end
\ No newline at end of file
diff --git a/reference/FrameXML/Minimap.xml b/reference/FrameXML/Minimap.xml
new file mode 100644
index 0000000..d8bdfa4
--- /dev/null
+++ b/reference/FrameXML/Minimap.xml
@@ -0,0 +1,754 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if (self.isDown) then
+ MinimapButton_OnMouseUp(self);
+ end
+
+
+ MinimapButton_OnMouseDown(self, button);
+
+
+ MinimapButton_OnMouseUp(self, button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ local pvpType, isSubZonePvP, factionName = GetZonePVPInfo();
+ Minimap_SetTooltip( pvpType, factionName );
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("UPDATE_PENDING_MAIL");
+ self:SetFrameLevel(self:GetFrameLevel()+1)
+
+
+ if ( event == "UPDATE_PENDING_MAIL" ) then
+ if ( HasNewMail() ) then
+ self:Show();
+ if( GameTooltip:IsOwned(self) ) then
+ MinimapMailFrameUpdate();
+ end
+ else
+ self:Hide();
+ end
+ end
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMLEFT");
+ if( GameTooltip:IsOwned(self) ) then
+ MinimapMailFrameUpdate();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:SetFrameLevel(self:GetFrameLevel()+1);
+ MiniMapBattlefieldFrame.timeInQueue = 0;
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ if (self.tooltip) then
+ GameTooltip:SetText(self.tooltip);
+ end
+ self:SetScript("OnUpdate", MiniMapBattlefieldFrame_OnUpdate);
+
+
+ GameTooltip:Hide();
+ self:SetScript("OnUpdate", nil);
+
+
+ -- Hide tooltip
+ GameTooltip:Hide();
+ if ( MiniMapBattlefieldFrame.status == "active") then
+ if ( button == "RightButton" ) then
+ ToggleDropDownMenu(1, nil, MiniMapBattlefieldDropDown, "MiniMapBattlefieldFrame", 0, -5);
+ elseif ( IsShiftKeyDown() ) then
+ ToggleBattlefieldMinimap();
+ else
+ ToggleWorldStateScoreFrame();
+ end
+ elseif ( button == "RightButton" ) then
+ ToggleDropDownMenu(1, nil, MiniMapBattlefieldDropDown, "MiniMapBattlefieldFrame", 0, -5);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.tooltipText = MicroButtonTooltipText(WORLDMAP_BUTTON, "TOGGLEWORLDMAP");
+ self.newbieText = NEWBIE_TOOLTIP_WORLDMAP;
+ self:RegisterEvent("UPDATE_BINDINGS");
+
+
+ GameTooltip_AddNewbieTip(self, self.tooltipText, 1.0, 1.0, 1.0, self.newbieText);
+
+
+
+ self.tooltipText = MicroButtonTooltipText(WORLDMAP_BUTTON, "TOGGLEWORLDMAP");
+ self.newbieText = NEWBIE_TOOLTIP_WORLDMAP;
+
+
+ ToggleFrame(WorldMapFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("MINIMAP_UPDATE_TRACKING");
+ MiniMapTracking_Update();
+
+
+
+ ToggleDropDownMenu(1, nil, MiniMapTrackingDropDown, "MiniMapTracking", 0, -5);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+ MiniMapTrackingIcon:SetPoint("TOPLEFT", MiniMapTracking, "TOPLEFT", 8, -8);
+ MiniMapTrackingIconOverlay:Show();
+
+
+ MiniMapTrackingIcon:SetPoint("TOPLEFT", MiniMapTracking, "TOPLEFT", 6, -6);
+ MiniMapTrackingIconOverlay:Hide();
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetTracking();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UIDropDownMenu_Initialize(self, MiniMapLFGFrameDropDown_Update, "MENU");
+
+
+
+
+
+
+ self:RegisterEvent("LFG_UPDATE");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("LFG_ROLE_CHECK_UPDATE");
+ self:RegisterEvent("LFG_PROPOSAL_UPDATE");
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:SetFrameLevel(self:GetFrameLevel()+1)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GetCVar("UberTooltips") == "1" ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, UIParent);
+ GameTooltip:SetText(ZOOM_IN);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GetCVar("UberTooltips") == "1" ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, UIParent);
+ GameTooltip:SetText(ZOOM_OUT);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GetCVar("UberTooltips") == "1" ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, UIParent);
+ MINIMAP_RECORDING_INDICATOR_ON = true;
+ end
+
+
+ GameTooltip:Hide();
+ MINIMAP_RECORDING_INDICATOR_ON = false;
+
+
+ self:RegisterEvent("MOVIE_RECORDING_PROGRESS");
+
+
+ if ( event == "MOVIE_RECORDING_PROGRESS" ) then
+ if( MovieRecording_IsRecording() and GetCVar("MovieRecordingIcon") == "1") then
+ self:Show();
+ else
+ self:Hide();
+ end
+ end
+
+
+ if ( MINIMAP_RECORDING_INDICATOR_ON ) then
+ GameTooltip:SetText(MOVIE_RECORDING_RECORDING..MovieRecording_GetTime());
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("PLAYER_DIFFICULTY_CHANGED");
+ self:RegisterEvent("UPDATE_INSTANCE_INFO");
+
+
+
+
+
+
+
+ Minimap.timer = 0;
+ Minimap_Update();
+ self:RegisterEvent("ZONE_CHANGED");
+ self:RegisterEvent("ZONE_CHANGED_INDOORS");
+ self:RegisterEvent("ZONE_CHANGED_NEW_AREA");
+ Minimap_UpdateRotationSetting();
+ MiniMapInstanceDifficulty:SetFrameLevel(self:GetFrameLevel() + 10);
+
+
+
+
+
diff --git a/reference/FrameXML/MirrorTimer.lua b/reference/FrameXML/MirrorTimer.lua
new file mode 100644
index 0000000..f9b486b
--- /dev/null
+++ b/reference/FrameXML/MirrorTimer.lua
@@ -0,0 +1,117 @@
+
+MIRRORTIMER_NUMTIMERS = 3;
+
+MirrorTimerColors = { };
+MirrorTimerColors["EXHAUSTION"] = {
+ r = 1.00, g = 0.90, b = 0.00
+};
+MirrorTimerColors["BREATH"] = {
+ r = 0.00, g = 0.50, b = 1.00
+};
+MirrorTimerColors["DEATH"] = {
+ r = 1.00, g = 0.70, b = 0.00
+};
+MirrorTimerColors["FEIGNDEATH"] = {
+ r = 1.00, g = 0.70, b = 0.00
+};
+
+function MirrorTimer_Show(timer, value, maxvalue, scale, paused, label)
+
+ -- Pick a free dialog to use
+ local dialog = nil;
+ if ( not dialog ) then
+ -- Find an open dialog of the requested type
+ for index = 1, MIRRORTIMER_NUMTIMERS, 1 do
+ local frame = _G["MirrorTimer"..index];
+ if ( frame:IsShown() and (frame.timer == timer) ) then
+ dialog = frame;
+ break;
+ end
+ end
+ end
+ if ( not dialog ) then
+ -- Find a free dialog
+ for index = 1, STATICPOPUP_NUMDIALOGS, 1 do
+ local frame = _G["MirrorTimer"..index];
+ if ( not frame:IsShown() ) then
+ dialog = frame;
+ break;
+ end
+ end
+ end
+ if ( not dialog ) then
+ return nil;
+ end
+
+ dialog.timer = timer;
+ dialog.value = (value / 1000);
+ dialog.scale = scale;
+ if ( paused > 0 ) then
+ dialog.paused = 1;
+ else
+ dialog.paused = nil;
+ end
+
+ -- Set the text of the dialog
+ local text = _G[dialog:GetName().."Text"];
+ text:SetText(label);
+
+ -- Set the status bar of the dialog
+ local statusbar = _G[dialog:GetName().."StatusBar"];
+ local color = MirrorTimerColors[timer];
+ statusbar:SetMinMaxValues(0, (maxvalue / 1000));
+ statusbar:SetValue(dialog.value);
+ statusbar:SetStatusBarColor(color.r, color.g, color.b);
+
+ dialog:Show();
+
+ return dialog;
+end
+
+
+function MirrorTimerFrame_OnLoad(self)
+ self:RegisterEvent("MIRROR_TIMER_PAUSE");
+ self:RegisterEvent("MIRROR_TIMER_STOP");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self.timer = nil;
+end
+
+function MirrorTimerFrame_OnEvent(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ for index=1, MIRRORTIMER_NUMTIMERS do
+ local timer, value, maxvalue, scale, paused, label = GetMirrorTimerInfo(index);
+ if ( timer == "UNKNOWN") then
+ self:Hide();
+ self.timer = nil;
+ else
+ MirrorTimer_Show(timer, value, maxvalue, scale, paused, label)
+ end
+ end
+ end
+
+ local arg1 = ...;
+ if ( not self:IsShown() or (arg1 ~= self.timer) ) then
+ return;
+ end
+
+ if ( event == "MIRROR_TIMER_PAUSE" ) then
+ if ( arg1 > 0 ) then
+ self.paused = 1;
+ else
+ self.paused = nil;
+ end
+ return;
+ elseif ( event == "MIRROR_TIMER_STOP" ) then
+ self:Hide();
+ self.timer = nil;
+ end
+end
+
+function MirrorTimerFrame_OnUpdate(frame, elapsed)
+ if ( frame.paused ) then
+ return;
+ end
+ local statusbar = _G[frame:GetName().."StatusBar"];
+ frame.value = GetMirrorTimerProgress(frame.timer) / 1000;
+ statusbar:SetValue(frame.value);
+end
diff --git a/reference/FrameXML/MirrorTimer.xml b/reference/FrameXML/MirrorTimer.xml
new file mode 100644
index 0000000..b541ea7
--- /dev/null
+++ b/reference/FrameXML/MirrorTimer.xml
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ LowerFrameLevel(self);
+
+
+
+
+
+
+
+ MirrorTimerFrame_OnLoad(self);
+
+
+ MirrorTimerFrame_OnEvent(self, event, ...);
+
+
+ MirrorTimerFrame_OnUpdate(self, elapsed);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/MoneyFrame.lua b/reference/FrameXML/MoneyFrame.lua
new file mode 100644
index 0000000..08caa8b
--- /dev/null
+++ b/reference/FrameXML/MoneyFrame.lua
@@ -0,0 +1,621 @@
+
+MONEY_ICON_WIDTH = 19;
+MONEY_ICON_WIDTH_SMALL = 13;
+
+MONEY_BUTTON_SPACING = -4;
+MONEY_BUTTON_SPACING_SMALL = -4;
+
+MONEY_TEXT_VADJUST = 0;
+
+COPPER_PER_SILVER = 100;
+SILVER_PER_GOLD = 100;
+COPPER_PER_GOLD = COPPER_PER_SILVER * SILVER_PER_GOLD;
+
+COIN_BUTTON_WIDTH = 32;
+
+MoneyTypeInfo = { };
+MoneyTypeInfo["PLAYER"] = {
+ UpdateFunc = function(self)
+ return (GetMoney() - GetCursorMoney() - GetPlayerTradeMoney());
+ end,
+
+ PickupFunc = function(self, amount)
+ PickupPlayerMoney(amount);
+ end,
+
+ DropFunc = function(self)
+ DropCursorMoney();
+ end,
+
+ collapse = 1,
+ canPickup = 1,
+ showSmallerCoins = "Backpack"
+};
+MoneyTypeInfo["STATIC"] = {
+ UpdateFunc = function(self)
+ return self.staticMoney;
+ end,
+
+ collapse = 1,
+};
+MoneyTypeInfo["AUCTION"] = {
+ UpdateFunc = function(self)
+ return self.staticMoney;
+ end,
+ showSmallerCoins = "Backpack",
+ fixedWidth = 1,
+ collapse = 1,
+ truncateSmallCoins = nil,
+};
+MoneyTypeInfo["PLAYER_TRADE"] = {
+ UpdateFunc = function(self)
+ return GetPlayerTradeMoney();
+ end,
+
+ PickupFunc = function(self, amount)
+ PickupTradeMoney(amount);
+ end,
+
+ DropFunc = function(self)
+ AddTradeMoney();
+ end,
+
+ collapse = 1,
+ canPickup = 1,
+};
+MoneyTypeInfo["TARGET_TRADE"] = {
+ UpdateFunc = function(self)
+ return GetTargetTradeMoney();
+ end,
+
+ collapse = 1,
+};
+MoneyTypeInfo["SEND_MAIL"] = {
+ UpdateFunc = function(self)
+ return GetSendMailMoney();
+ end,
+
+ PickupFunc = function(self, amount)
+ PickupSendMailMoney(amount);
+ end,
+
+ DropFunc = function(self)
+ AddSendMailMoney();
+ end,
+
+ collapse = nil,
+ canPickup = 1,
+ showSmallerCoins = "Backpack",
+};
+MoneyTypeInfo["SEND_MAIL_COD"] = {
+ UpdateFunc = function(self)
+ return GetSendMailCOD();
+ end,
+
+ PickupFunc = function(self, amount)
+ PickupSendMailCOD(amount);
+ end,
+
+ DropFunc = function(self)
+ AddSendMailCOD();
+ end,
+
+ collapse = 1,
+ canPickup = 1,
+};
+MoneyTypeInfo["GUILDBANK"] = {
+ OnloadFunc = function(self)
+ self:RegisterEvent("GUILDBANK_UPDATE_MONEY");
+ end,
+
+ UpdateFunc = function(self)
+ return (GetGuildBankMoney() - GetCursorMoney());
+ end,
+
+ PickupFunc = function(self, amount)
+ PickupGuildBankMoney(amount);
+ end,
+
+ DropFunc = function(self)
+ DropCursorMoney();
+ end,
+
+ collapse = 1,
+ showSmallerCoins = "Backpack",
+};
+
+MoneyTypeInfo["GUILDBANKWITHDRAW"] = {
+ OnloadFunc = function(self)
+ self:RegisterEvent("GUILDBANK_UPDATE_WITHDRAWMONEY");
+ end,
+
+ UpdateFunc = function(self)
+ GuildBankFrame_UpdateWithdrawMoney();
+ return nil;
+ end,
+
+ collapse = 1,
+ showSmallerCoins = "Backpack",
+};
+
+MoneyTypeInfo["GUILD_REPAIR"] = {
+ UpdateFunc = function(self)
+ return self.staticMoney;
+ end,
+
+ collapse = 1,
+ showSmallerCoins = "Backpack",
+};
+
+
+
+function MoneyFrame_OnLoad (self)
+ self:RegisterEvent("PLAYER_MONEY");
+ self:RegisterEvent("PLAYER_TRADE_MONEY");
+ self:RegisterEvent("TRADE_MONEY_CHANGED");
+ self:RegisterEvent("SEND_MAIL_MONEY_CHANGED");
+ self:RegisterEvent("SEND_MAIL_COD_CHANGED");
+ MoneyFrame_SetType(self, "PLAYER");
+end
+
+function SmallMoneyFrame_OnLoad(self, moneyType)
+ --If there's a moneyType we'll use the new way of doing things, otherwise do things the old way
+ if ( moneyType ) then
+ local info = MoneyTypeInfo[moneyType];
+ if ( info and info.OnloadFunc ) then
+ --This way you can just register for the events that you care about
+ --Should write OnloadFunc's for all money frames, but don't have time right now
+ info.OnloadFunc(self);
+ self.small = 1;
+ MoneyFrame_SetType(self, moneyType);
+ end
+ else
+ --The old sucky way of doing things
+ self:RegisterEvent("PLAYER_MONEY");
+ self:RegisterEvent("PLAYER_TRADE_MONEY");
+ self:RegisterEvent("TRADE_MONEY_CHANGED");
+ self:RegisterEvent("SEND_MAIL_MONEY_CHANGED");
+ self:RegisterEvent("SEND_MAIL_COD_CHANGED");
+ self.small = 1;
+ MoneyFrame_SetType(self, "PLAYER");
+ end
+end
+
+function MoneyFrame_OnEvent (self, event, ...)
+ if ( not self.info or not self:IsVisible() ) then
+ return;
+ end
+
+ local moneyType = self.moneyType;
+
+ if ( event == "PLAYER_MONEY" and moneyType == "PLAYER" ) then
+ MoneyFrame_UpdateMoney(self);
+ elseif ( event == "PLAYER_TRADE_MONEY" and (moneyType == "PLAYER" or moneyType == "PLAYER_TRADE") ) then
+ MoneyFrame_UpdateMoney(self);
+ elseif ( event == "TRADE_MONEY_CHANGED" and moneyType == "TARGET_TRADE" ) then
+ MoneyFrame_UpdateMoney(self);
+ elseif ( event == "SEND_MAIL_MONEY_CHANGED" and (moneyType == "PLAYER" or moneyType == "SEND_MAIL") ) then
+ MoneyFrame_UpdateMoney(self);
+ elseif ( event == "SEND_MAIL_COD_CHANGED" and (moneyType == "PLAYER" or moneyType == "SEND_MAIL_COD") ) then
+ MoneyFrame_UpdateMoney(self);
+ elseif ( event == "GUILDBANK_UPDATE_MONEY" and moneyType == "GUILDBANK" ) then
+ MoneyFrame_UpdateMoney(self);
+ elseif ( event == "GUILDBANK_UPDATE_WITHDRAWMONEY" and moneyType == "GUILDBANKWITHDRAW" ) then
+ MoneyFrame_UpdateMoney(self);
+ end
+end
+
+function MoneyFrame_SetType(self, type)
+
+ local info = MoneyTypeInfo[type];
+ if ( not info ) then
+ message("Invalid money type: "..type);
+ return;
+ end
+ self.info = info;
+ self.moneyType = type;
+ local frameName = self:GetName();
+ if ( info.canPickup ) then
+ _G[frameName.."GoldButton"]:EnableMouse(true);
+ _G[frameName.."SilverButton"]:EnableMouse(true);
+ _G[frameName.."CopperButton"]:EnableMouse(true);
+ else
+ _G[frameName.."GoldButton"]:EnableMouse(false);
+ _G[frameName.."SilverButton"]:EnableMouse(false);
+ _G[frameName.."CopperButton"]:EnableMouse(false);
+ end
+
+ MoneyFrame_UpdateMoney(self);
+end
+
+-- Update the money shown in a money frame
+function MoneyFrame_UpdateMoney(moneyFrame)
+ assert(moneyFrame);
+
+ if ( moneyFrame.info ) then
+ local money = moneyFrame.info.UpdateFunc(moneyFrame);
+ if ( money ) then
+ MoneyFrame_Update(moneyFrame:GetName(), money);
+ end
+ if ( moneyFrame.hasPickup == 1 ) then
+ UpdateCoinPickupFrame(money);
+ end
+ else
+ message("Error moneyType not set");
+ end
+end
+
+local function CreateMoneyButtonNormalTexture (button, iconWidth)
+ local texture = button:CreateTexture();
+ texture:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons");
+ texture:SetWidth(iconWidth);
+ texture:SetHeight(iconWidth);
+ texture:SetPoint("RIGHT");
+ button:SetNormalTexture(texture);
+
+ return texture;
+end
+
+function MoneyFrame_Update(frameName, money)
+ local frame;
+ if ( type(frameName) == "table" ) then
+ frame = frameName;
+ frameName = frame:GetName();
+ else
+ frame = _G[frameName];
+ end
+
+ local info = frame.info;
+ if ( not info ) then
+ message("Error moneyType not set");
+ end
+
+ -- Breakdown the money into denominations
+ local gold = floor(money / (COPPER_PER_SILVER * SILVER_PER_GOLD));
+ local silver = floor((money - (gold * COPPER_PER_SILVER * SILVER_PER_GOLD)) / COPPER_PER_SILVER);
+ local copper = mod(money, COPPER_PER_SILVER);
+
+ local goldButton = _G[frameName.."GoldButton"];
+ local silverButton = _G[frameName.."SilverButton"];
+ local copperButton = _G[frameName.."CopperButton"];
+
+ local iconWidth = MONEY_ICON_WIDTH;
+ local spacing = MONEY_BUTTON_SPACING;
+ if ( frame.small ) then
+ iconWidth = MONEY_ICON_WIDTH_SMALL;
+ spacing = MONEY_BUTTON_SPACING_SMALL;
+ end
+
+ -- Set values for each denomination
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ if ( not frame.colorblind or not frame.vadjust or frame.vadjust ~= MONEY_TEXT_VADJUST ) then
+ frame.colorblind = true;
+ frame.vadjust = MONEY_TEXT_VADJUST;
+ goldButton:SetNormalTexture("");
+ silverButton:SetNormalTexture("");
+ copperButton:SetNormalTexture("");
+ _G[frameName.."GoldButtonText"]:SetPoint("RIGHT", 0, MONEY_TEXT_VADJUST);
+ _G[frameName.."SilverButtonText"]:SetPoint("RIGHT", 0, MONEY_TEXT_VADJUST);
+ _G[frameName.."CopperButtonText"]:SetPoint("RIGHT", 0, MONEY_TEXT_VADJUST);
+ end
+ goldButton:SetText(gold .. GOLD_AMOUNT_SYMBOL);
+ goldButton:SetWidth(goldButton:GetTextWidth());
+ goldButton:Show();
+ silverButton:SetText(silver .. SILVER_AMOUNT_SYMBOL);
+ silverButton:SetWidth(silverButton:GetTextWidth());
+ silverButton:Show();
+ copperButton:SetText(copper .. COPPER_AMOUNT_SYMBOL);
+ copperButton:SetWidth(copperButton:GetTextWidth());
+ copperButton:Show();
+ else
+ if ( frame.colorblind or not frame.vadjust or frame.vadjust ~= MONEY_TEXT_VADJUST ) then
+ frame.colorblind = nil;
+ frame.vadjust = MONEY_TEXT_VADJUST;
+ local texture = CreateMoneyButtonNormalTexture(goldButton, iconWidth);
+ texture:SetTexCoord(0, 0.25, 0, 1);
+ texture = CreateMoneyButtonNormalTexture(silverButton, iconWidth);
+ texture:SetTexCoord(0.25, 0.5, 0, 1);
+ texture = CreateMoneyButtonNormalTexture(copperButton, iconWidth);
+ texture:SetTexCoord(0.5, 0.75, 0, 1);
+ _G[frameName.."GoldButtonText"]:SetPoint("RIGHT", -iconWidth, MONEY_TEXT_VADJUST);
+ _G[frameName.."SilverButtonText"]:SetPoint("RIGHT", -iconWidth, MONEY_TEXT_VADJUST);
+ _G[frameName.."CopperButtonText"]:SetPoint("RIGHT", -iconWidth, MONEY_TEXT_VADJUST);
+ end
+ goldButton:SetText(gold);
+ goldButton:SetWidth(goldButton:GetTextWidth() + iconWidth);
+ goldButton:Show();
+ silverButton:SetText(silver);
+ silverButton:SetWidth(silverButton:GetTextWidth() + iconWidth);
+ silverButton:Show();
+ copperButton:SetText(copper);
+ copperButton:SetWidth(copperButton:GetTextWidth() + iconWidth);
+ copperButton:Show();
+ end
+
+ -- Store how much money the frame is displaying
+ frame.staticMoney = money;
+
+ -- If not collapsable don't need to continue
+ if ( not info.collapse ) then
+ return;
+ end
+
+ local width = iconWidth;
+
+ local showLowerDenominations, truncateCopper;
+ if ( gold > 0 ) then
+ width = width + goldButton:GetWidth();
+ if ( info.showSmallerCoins ) then
+ showLowerDenominations = 1;
+ end
+ if ( info.truncateSmallCoins ) then
+ truncateCopper = 1;
+ end
+ else
+ goldButton:Hide();
+ end
+
+ goldButton:ClearAllPoints();
+ if ( silver > 0 or showLowerDenominations ) then
+ -- Exception if showLowerDenominations and fixedWidth
+ if ( showLowerDenominations and info.fixedWidth ) then
+ silverButton:SetWidth(COIN_BUTTON_WIDTH);
+ end
+
+ width = width + silverButton:GetWidth();
+ goldButton:SetPoint("RIGHT", frameName.."SilverButton", "LEFT", spacing, 0);
+ if ( goldButton:IsShown() ) then
+ width = width - spacing;
+ end
+ if ( info.showSmallerCoins ) then
+ showLowerDenominations = 1;
+ end
+ else
+ silverButton:Hide();
+ goldButton:SetPoint("RIGHT", frameName.."SilverButton", "RIGHT", 0, 0);
+ end
+
+ -- Used if we're not showing lower denominations
+ silverButton:ClearAllPoints();
+ if ( (copper > 0 or showLowerDenominations or info.showSmallerCoins == "Backpack") and not truncateCopper) then
+ -- Exception if showLowerDenominations and fixedWidth
+ if ( showLowerDenominations and info.fixedWidth ) then
+ copperButton:SetWidth(COIN_BUTTON_WIDTH);
+ end
+
+ width = width + copperButton:GetWidth();
+ silverButton:SetPoint("RIGHT", frameName.."CopperButton", "LEFT", spacing, 0);
+ if ( silverButton:IsShown() or goldButton:IsShown() ) then
+ width = width - spacing;
+ end
+ else
+ copperButton:Hide();
+ silverButton:SetPoint("RIGHT", frameName.."CopperButton", "RIGHT", 0, 0);
+ end
+
+ -- make sure the copper button is in the right place
+ copperButton:ClearAllPoints();
+ copperButton:SetPoint("RIGHT", frameName, "RIGHT", -13, 0);
+
+ -- attach text now that denominations have been computed
+ local prefixText = _G[frameName.."PrefixText"];
+ if ( prefixText ) then
+ if ( prefixText:GetText() and money > 0 ) then
+ prefixText:Show();
+ copperButton:ClearAllPoints();
+ copperButton:SetPoint("RIGHT", frameName.."PrefixText", "RIGHT", width, 0);
+ width = width + prefixText:GetWidth();
+ else
+ prefixText:Hide();
+ end
+ end
+ local suffixText = _G[frameName.."SuffixText"];
+ if ( suffixText ) then
+ if ( suffixText:GetText() and money > 0 ) then
+ suffixText:Show();
+ suffixText:ClearAllPoints();
+ suffixText:SetPoint("LEFT", frameName.."CopperButton", "RIGHT", 0, 0);
+ width = width + suffixText:GetWidth();
+ else
+ suffixText:Hide();
+ end
+ end
+
+ frame:SetWidth(width);
+end
+
+function RefreshMoneyFrame(frameName, money, small, collapse, showSmallerCoins)
+ --[[
+ local gold = floor(money / (COPPER_PER_SILVER * SILVER_PER_GOLD));
+ local silver = floor((money - (gold * COPPER_PER_SILVER * SILVER_PER_GOLD)) / COPPER_PER_SILVER);
+ local copper = mod(money, COPPER_PER_SILVER);
+
+ local goldButton = _G[frameName.."GoldButton"];
+ local silverButton = _G[frameName.."SilverButton"];
+ local copperButton = _G[frameName.."CopperButton"];
+
+ local iconWidth = MONEY_ICON_WIDTH;
+ local spacing = MONEY_BUTTON_SPACING;
+ if ( small > 0 ) then
+ iconWidth = MONEY_ICON_WIDTH_SMALL;
+ spacing = MONEY_BUTTON_SPACING_SMALL;
+ end
+
+ goldButton:SetText(gold);
+ goldButton:SetWidth(goldButton:GetTextWidth() + iconWidth);
+ goldButton:Show();
+ silverButton:SetText(silver);
+ silverButton:SetWidth(silverButton:GetTextWidth() + iconWidth);
+ silverButton:Show();
+ copperButton:SetText(copper);
+ copperButton:SetWidth(copperButton:GetTextWidth() + iconWidth);
+ copperButton:Show();
+
+ local frame = _G[frameName];
+ frame.staticMoney = money;
+
+ if ( collapse == 0 ) then
+ return;
+ end
+
+ local width = 13;
+ local showLowerDenominations;
+ if ( gold > 0 ) then
+ width = width + goldButton:GetWidth();
+ if ( showSmallerCoins ) then
+ showLowerDenominations = 1;
+ end
+ else
+ goldButton:Hide();
+ end
+
+ if ( silver > 0 or showLowerDenominations ) then
+ width = width + silverButton:GetWidth();
+ goldButton:SetPoint("RIGHT", frameName.."SilverButton", "LEFT", spacing, 0);
+ if ( goldButton:IsShown() ) then
+ width = width - spacing;
+ end
+ if ( showSmallerCoins ) then
+ showLowerDenominations = 1;
+ end
+ else
+ silverButton:Hide();
+ goldButton:SetPoint("RIGHT", frameName.."SilverButton", "RIGHT", 0, 0);
+ end
+
+ -- Used if we're not showing lower denominations
+ if ( copper > 0 or showLowerDenominations or showSmallerCoins == "Backpack") then
+ width = width + copperButton:GetWidth();
+ silverButton:SetPoint("RIGHT", frameName.."CopperButton", "LEFT", spacing, 0);
+ if ( silverButton:IsShown() ) then
+ width = width - spacing;
+ end
+ else
+ copperButton:Hide();
+ silverButton:SetPoint("RIGHT", frameName.."CopperButton", "RIGHT", 0, 0);
+ end
+
+ frame:SetWidth(width);
+
+ ]]
+end
+
+function SetMoneyFrameColor(frameName, color)
+ local moneyFrame = _G[frameName];
+ if ( not moneyFrame ) then
+ return;
+ end
+ local fontObject;
+ if ( moneyFrame.small ) then
+ if ( color == "yellow" ) then
+ fontObject = NumberFontNormalRightYellow;
+ elseif ( color == "red" ) then
+ fontObject = NumberFontNormalRightRed;
+ else
+ fontObject = NumberFontNormalRight;
+ end
+ else
+ if ( color == "yellow" ) then
+ fontObject = NumberFontNormalLargeRightYellow;
+ elseif ( color == "red" ) then
+ fontObject = NumberFontNormalLargeRightRed;
+ else
+ fontObject = NumberFontNormalLargeRight;
+ end
+ end
+
+ local goldButton = _G[frameName.."GoldButton"];
+ local silverButton = _G[frameName.."SilverButton"];
+ local copperButton = _G[frameName.."CopperButton"];
+
+ goldButton:SetNormalFontObject(fontObject);
+ silverButton:SetNormalFontObject(fontObject);
+ copperButton:SetNormalFontObject(fontObject);
+end
+
+function AltCurrencyFrame_Update(frameName, texture, cost)
+ local iconWidth;
+ local button = _G[frameName];
+ local buttonTexture = _G[frameName.."Texture"];
+ button:SetText(cost);
+ buttonTexture:SetTexture(texture);
+ if ( button.pointType == HONOR_POINTS ) then
+ iconWidth = 24;
+ buttonTexture:SetPoint("LEFT", _G[frameName.."Text"], "RIGHT", -1, -6);
+ else
+ iconWidth = MONEY_ICON_WIDTH_SMALL;
+ buttonTexture:SetPoint("LEFT", _G[frameName.."Text"], "RIGHT", 0, 0);
+ end
+ buttonTexture:SetWidth(iconWidth);
+ buttonTexture:SetHeight(iconWidth);
+ button:SetWidth(button:GetTextWidth() + MONEY_ICON_WIDTH_SMALL);
+end
+
+function AltCurrencyFrame_PointsUpdate(frameName, honor, arena)
+ local buttonHonor = _G[frameName.."Honor"];
+ if ( honor and honor > 0 ) then
+ buttonHonor.pointType = HONOR_POINTS;
+ local factionGroup = UnitFactionGroup("player");
+ local honorTexture = "Interface\\TargetingFrame\\UI-PVP-Horde";
+ if ( factionGroup ) then
+ honorTexture = "Interface\\TargetingFrame\\UI-PVP-"..factionGroup;
+ end
+ AltCurrencyFrame_Update( frameName.."Honor", honorTexture, honor );
+ buttonHonor:Show();
+ else
+ buttonHonor:Hide();
+ end
+
+ local buttonArena = _G[frameName.."Arena"];
+ if ( arena and arena > 0 ) then
+ buttonHonor.pointType = ARENA_POINTS;
+ AltCurrencyFrame_Update( frameName.."Arena", "Interface\\PVPFrame\\PVP-ArenaPoints-Icon", arena );
+ if ( honor and honor > 0 ) then
+ buttonArena:SetPoint("LEFT", buttonHonor, "RIGHT", 0, 0);
+ else
+ buttonArena:SetPoint("LEFT", frameName, "LEFT", 13, 0);
+ end
+ buttonArena:Show();
+ return buttonArena;
+ else
+ buttonArena:Hide();
+ end
+ return buttonHonor;
+end
+
+function GetDenominationsFromCopper(money)
+ return GetCoinText(money, " ");
+end
+
+function GetMoneyString(money)
+ local goldString, silverString, copperString;
+ local gold = floor(money / (COPPER_PER_SILVER * SILVER_PER_GOLD));
+ local silver = floor((money - (gold * COPPER_PER_SILVER * SILVER_PER_GOLD)) / COPPER_PER_SILVER);
+ local copper = mod(money, COPPER_PER_SILVER);
+
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ goldString = gold..GOLD_AMOUNT_SYMBOL;
+ silverString = silver..SILVER_AMOUNT_SYMBOL;
+ copperString = copper..COPPER_AMOUNT_SYMBOL;
+ else
+ goldString = format(GOLD_AMOUNT_TEXTURE, gold, 0, 0);
+ silverString = format(SILVER_AMOUNT_TEXTURE, silver, 0, 0);
+ copperString = format(COPPER_AMOUNT_TEXTURE, copper, 0, 0);
+ end
+
+ local moneyString = "";
+ local separator = "";
+ if ( gold > 0 ) then
+ moneyString = goldString;
+ separator = " ";
+ end
+ if ( silver > 0 ) then
+ moneyString = moneyString..separator..silverString;
+ separator = " ";
+ end
+ if ( copper > 0 or moneyString == "" ) then
+ moneyString = moneyString..separator..copperString;
+ end
+
+ return moneyString;
+end
diff --git a/reference/FrameXML/MoneyFrame.xml b/reference/FrameXML/MoneyFrame.xml
new file mode 100644
index 0000000..00e1d34
--- /dev/null
+++ b/reference/FrameXML/MoneyFrame.xml
@@ -0,0 +1,405 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parent = self:GetParent();
+ OpenCoinPickupFrame(1, MoneyTypeInfo[parent.moneyType].UpdateFunc(), parent);
+ parent.hasPickup = 1;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parent = self:GetParent();
+ OpenCoinPickupFrame(COPPER_PER_SILVER, MoneyTypeInfo[parent.moneyType].UpdateFunc(), parent);
+ parent.hasPickup = 1;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parent = self:GetParent();
+ OpenCoinPickupFrame(COPPER_PER_GOLD, MoneyTypeInfo[parent.moneyType].UpdateFunc(), parent);
+ parent.hasPickup = 1;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MoneyFrame_OnLoad(self);
+
+
+ MoneyFrame_OnEvent(self, event, ...);
+
+
+ MoneyFrame_UpdateMoney(self);
+
+
+ if ( self.hasPickup == 1 ) then
+ CoinPickupFrame:Hide();
+ self.hasPickup = 0;
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parent = self:GetParent();
+ OpenCoinPickupFrame(1, MoneyTypeInfo[parent.moneyType].UpdateFunc(), parent);
+ parent.hasPickup = 1;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parent = self:GetParent();
+ OpenCoinPickupFrame(COPPER_PER_SILVER, MoneyTypeInfo[parent.moneyType].UpdateFunc(), parent);
+ parent.hasPickup = 1;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parent = self:GetParent();
+ OpenCoinPickupFrame(COPPER_PER_GOLD, MoneyTypeInfo[parent.moneyType].UpdateFunc(), parent);
+ parent.hasPickup = 1;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+
+
+ MoneyFrame_OnEvent(self, event, ...);
+
+
+ MoneyFrame_UpdateMoney(self);
+
+
+ if ( self.hasPickup == 1 ) then
+ CoinPickupFrame:Hide();
+ self.hasPickup = 0;
+ end
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetMerchantCostItem(self.index, self.item);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(HONOR_POINTS);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(ARENA_POINTS);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/MoneyInputFrame.lua b/reference/FrameXML/MoneyInputFrame.lua
new file mode 100644
index 0000000..7ba17a6
--- /dev/null
+++ b/reference/FrameXML/MoneyInputFrame.lua
@@ -0,0 +1,114 @@
+
+function MoneyInputFrame_ResetMoney(moneyFrame)
+ _G[moneyFrame:GetName().."Gold"]:SetText("");
+ _G[moneyFrame:GetName().."Silver"]:SetText("");
+ _G[moneyFrame:GetName().."Copper"]:SetText("");
+end
+
+function MoneyInputFrame_ClearFocus(moneyFrame)
+ _G[moneyFrame:GetName().."Gold"]:ClearFocus();
+ _G[moneyFrame:GetName().."Silver"]:ClearFocus();
+ _G[moneyFrame:GetName().."Copper"]:ClearFocus();
+end
+
+function MoneyInputFrame_GetCopper(moneyFrame)
+ local totalCopper = 0;
+ local copper = _G[moneyFrame:GetName().."Copper"]:GetText();
+ local silver = _G[moneyFrame:GetName().."Silver"]:GetText();
+ local gold = _G[moneyFrame:GetName().."Gold"]:GetText();
+
+ if ( copper ~= "" ) then
+ totalCopper = totalCopper + copper;
+ end
+ if ( silver ~= "" ) then
+ totalCopper = totalCopper + (silver * COPPER_PER_SILVER);
+ end
+ if ( gold ~= "" ) then
+ totalCopper = totalCopper + (gold * COPPER_PER_GOLD);
+ end
+ return totalCopper;
+end
+
+function MoneyInputFrame_SetTextColor(moneyFrame, r, g, b)
+ _G[moneyFrame:GetName().."Copper"]:SetTextColor(r, g, b);
+ _G[moneyFrame:GetName().."Silver"]:SetTextColor(r, g, b);
+ _G[moneyFrame:GetName().."Gold"]:SetTextColor(r, g, b);
+end
+
+function MoneyInputFrame_SetCopper(moneyFrame, money)
+ local gold = floor(money / (COPPER_PER_GOLD));
+ local silver = floor((money - (gold * COPPER_PER_GOLD)) / COPPER_PER_SILVER);
+ local copper = mod(money, COPPER_PER_SILVER);
+ local editbox = nil;
+
+ moneyFrame.expectChanges = 0;
+ editbox = _G[moneyFrame:GetName().."Copper"];
+ if ( editbox:GetNumber() ~= copper ) then
+ editbox:SetNumber(copper);
+ moneyFrame.expectChanges = moneyFrame.expectChanges + 1;
+ end
+ editbox = _G[moneyFrame:GetName().."Silver"];
+ if ( editbox:GetNumber() ~= silver ) then
+ editbox:SetNumber(silver);
+ moneyFrame.expectChanges = moneyFrame.expectChanges + 1;
+ end
+ editbox = _G[moneyFrame:GetName().."Gold"];
+ if ( editbox:GetNumber() ~= gold ) then
+ editbox:SetNumber(gold);
+ moneyFrame.expectChanges = moneyFrame.expectChanges + 1;
+ end
+end
+
+function MoneyInputFrame_OnTextChanged(self)
+ local moneyFrame = self:GetParent();
+ if ( moneyFrame.expectChanges ) then
+ if ( moneyFrame.expectChanges > 1 ) then
+ moneyFrame.expectChanges = moneyFrame.expectChanges - 1;
+ return;
+ end
+ moneyFrame.expectChanges = nil;
+ end
+ if ( self:GetParent().onValueChangedFunc ) then
+ self:GetParent().onValueChangedFunc();
+ end
+end
+
+function MoneyInputFrame_SetMode(frame, mode)
+ local frameName = frame:GetName();
+ if ( mode == "compact" ) then
+ _G[frameName.."Copper"]:SetPoint("LEFT", frameName.."Silver", "RIGHT", 11, 0);
+ _G[frameName.."Silver"]:SetPoint("LEFT", frameName.."Gold", "RIGHT", 22, 0);
+ _G[frameName.."Gold"]:SetWidth(56);
+ end
+end
+
+-- Used to set the frames before the moneyframe when tabbing through
+function MoneyInputFrame_SetPreviousFocus(moneyFrame, focus)
+ moneyFrame.previousFocus = focus;
+end
+
+function MoneyInputFrame_SetNextFocus(moneyFrame, focus)
+ moneyFrame.nextFocus = focus;
+end
+
+function MoneyInputFrame_SetOnValueChangedFunc(moneyFrame, func)
+ moneyFrame.onValueChangedFunc = func;
+end
+
+function MoneyInputFrame_OnShow(moneyFrame)
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ moneyFrame.copper.texture:Hide();
+ moneyFrame.gold.texture:Hide();
+ moneyFrame.silver.texture:Hide();
+ moneyFrame.copper.label:Show();
+ moneyFrame.gold.label:Show();
+ moneyFrame.silver.label:Show();
+ else
+ moneyFrame.copper.texture:Show();
+ moneyFrame.gold.texture:Show();
+ moneyFrame.silver.texture:Show();
+ moneyFrame.copper.label:Hide();
+ moneyFrame.gold.label:Hide();
+ moneyFrame.silver.label:Hide();
+ end
+end
diff --git a/reference/FrameXML/MoneyInputFrame.xml b/reference/FrameXML/MoneyInputFrame.xml
new file mode 100644
index 0000000..9d12364
--- /dev/null
+++ b/reference/FrameXML/MoneyInputFrame.xml
@@ -0,0 +1,313 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsShiftKeyDown() and self:GetParent().previousFocus ) then
+ self:GetParent().previousFocus:SetFocus();
+ else
+ _G[self:GetParent():GetName().."Silver"]:SetFocus();
+ end
+
+
+ _G[self:GetParent():GetName().."Silver"]:SetFocus();
+
+
+ EditBox_ClearFocus(self);
+
+
+ MoneyInputFrame_OnTextChanged(self);
+
+
+ EditBox_ClearHighlight(self);
+
+
+ EditBox_HighlightText(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsShiftKeyDown() ) then
+ _G[self:GetParent():GetName().."Gold"]:SetFocus();
+ else
+ _G[self:GetParent():GetName().."Copper"]:SetFocus();
+ end
+
+
+ _G[self:GetParent():GetName().."Copper"]:SetFocus();
+
+
+ EditBox_ClearFocus(self);
+
+
+ MoneyInputFrame_OnTextChanged(self);
+
+
+ EditBox_ClearHighlight(self);
+
+
+ EditBox_HighlightText(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( IsShiftKeyDown() ) then
+ _G[self:GetParent():GetName().."Silver"]:SetFocus();
+ else
+ if ( self:GetParent().nextFocus ) then
+ self:GetParent().nextFocus:SetFocus();
+ else
+ self:ClearFocus();
+ end
+ end
+
+
+ if ( self:GetParent().nextFocus ) then
+ self:GetParent().nextFocus:SetFocus();
+ else
+ self:ClearFocus();
+ end
+
+
+ EditBox_ClearFocus(self);
+
+
+ MoneyInputFrame_OnTextChanged(self);
+
+
+ EditBox_ClearHighlight(self);
+
+
+ EditBox_HighlightText(self);
+
+
+
+
+
+
+
+ MoneyInputFrame_OnShow(self);
+
+
+
+
diff --git a/reference/FrameXML/MovieFrame.lua b/reference/FrameXML/MovieFrame.lua
new file mode 100644
index 0000000..8e038ff
--- /dev/null
+++ b/reference/FrameXML/MovieFrame.lua
@@ -0,0 +1,88 @@
+
+MOVIE_CAPTION_FADE_TIME = 1.0;
+
+function MovieFrame_OnLoad(self)
+ self:RegisterEvent("PLAY_MOVIE");
+end
+
+function MovieFrame_OnEvent(self, event, ...)
+ if ( event == "PLAY_MOVIE" ) then
+ local name, volume = ...;
+ if ( name ) then
+ MovieFrame_PlayMovie(self, name, volume);
+ end
+ end
+end
+
+function MovieFrame_PlayMovie(self, name, volume)
+ volume = volume or 150;
+ self:Show();
+ if (not self:StartMovie(name, volume) ) then
+ self:Hide();
+ GameMovieFinished();
+ end
+end
+
+function MovieFrame_OnShow(self)
+ WorldFrame:Hide();
+ self.uiParentShown = UIParent:IsShown();
+ UIParent:Hide();
+ self:EnableSubtitles(GetCVarBool("movieSubtitle"));
+end
+
+function MovieFrame_OnHide(self)
+ MovieFrameSubtitleString:Hide();
+ self:StopMovie();
+ WorldFrame:Show();
+ if ( self.uiParentShown ) then
+ UIParent:Show();
+ SetUIVisibility(true);
+ end
+end
+
+function MovieFrame_OnUpdate(self, elapsed)
+ if ( MovieFrameSubtitleString:IsShown() and self.fadingAlpha ) then
+ self.fadingAlpha = self.fadingAlpha + ((elapsed / self.fadeSpeed) * self.fadeDirection);
+ if ( self.fadingAlpha > 1.0 ) then
+ MovieFrameSubtitleString:SetAlpha(1.0);
+ self.fadingAlpha = nil;
+ elseif ( self.fadingAlpha < 0.0 ) then
+ MovieFrameSubtitleString:Hide();
+ self.fadingAlpha = nil;
+ else
+ MovieFrameSubtitleString:SetAlpha(self.fadingAlpha);
+ end
+ end
+end
+
+function MovieFrame_OnKeyUp(self, key)
+ if ( GetBindingFromClick(key) == "TOGGLEGAMEMENU" ) then
+ self:Hide();
+ elseif ( key == "SPACE" or key == "ENTER" ) then
+ self:StopMovie();
+ end
+end
+
+function MovieFrame_OnMovieFinished(self)
+ GameMovieFinished();
+ if ( self:IsShown() ) then
+ self:Hide();
+ end
+end
+
+function MovieFrame_OnMovieShowSubtitle(self, text)
+ MovieFrameSubtitleString:SetText(text);
+ MovieFrameSubtitleString:Show();
+ self.fadingAlpha = 0.0;
+ self.fadeDirection = 1.0;
+ self.fadeSpeed = MOVIE_CAPTION_FADE_TIME;
+ MovieFrameSubtitleString:SetAlpha(self.fadingAlpha);
+end
+
+function MovieFrame_OnMovieHideSubtitle(self)
+ self.fadingAlpha = 1.0;
+ self.fadeDirection = -1.0;
+ self.fadeSpeed = MOVIE_CAPTION_FADE_TIME / 2;
+ MovieFrameSubtitleString:SetAlpha(self.fadingAlpha);
+end
+
diff --git a/reference/FrameXML/MovieFrame.xml b/reference/FrameXML/MovieFrame.xml
new file mode 100644
index 0000000..fafee56
--- /dev/null
+++ b/reference/FrameXML/MovieFrame.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/MovieRecordingProgress.lua b/reference/FrameXML/MovieRecordingProgress.lua
new file mode 100644
index 0000000..783dd79
--- /dev/null
+++ b/reference/FrameXML/MovieRecordingProgress.lua
@@ -0,0 +1,11 @@
+function MovieRecordingProgress_OnUpdate(self, elapsed)
+ if(not MovieRecording_IsCompressing()) then
+ self:Hide();
+ else
+ local recovering, progress = MovieRecording_GetProgress();
+ MovieProgressBar:SetValue(progress);
+ MovieProgressBarText:SetText(MOVIE_RECORDING_COMPRESSING.." "..floor(progress * 100).."%");
+ end
+end
+
+
diff --git a/reference/FrameXML/MovieRecordingProgress.xml b/reference/FrameXML/MovieRecordingProgress.xml
new file mode 100644
index 0000000..a284833
--- /dev/null
+++ b/reference/FrameXML/MovieRecordingProgress.xml
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MacOptionsCancelFrame:Show();
+
+
+ GameTooltip_AddNewbieTip(self, MOVIE_RECORDING_COMPRESSING_CANCEL_TOOLTIP, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b, MOVIE_RECORDING_COMPRESSING_CANCEL_NEWBIE_TOOLTIP, 1);
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, MovieRecording_GetMovieFullPath());
+
+
+
+ self:RegisterEvent("MOVIE_COMPRESSING_PROGRESS");
+
+
+ self:Show();
+
+
+
+
+
diff --git a/reference/FrameXML/MultiActionBars.lua b/reference/FrameXML/MultiActionBars.lua
new file mode 100644
index 0000000..2df83d9
--- /dev/null
+++ b/reference/FrameXML/MultiActionBars.lua
@@ -0,0 +1,128 @@
+NUM_MULTIBAR_BUTTONS = 12;
+
+function MultiActionBarFrame_OnLoad (self)
+ -- Hack no longer needed here.
+ -- This is where i will load the actionbar states
+end
+
+function MultiActionButtonDown (bar, id)
+ local button = _G[bar.."Button"..id];
+ if ( button:GetButtonState() == "NORMAL" ) then
+ button:SetButtonState("PUSHED");
+ end
+end
+
+function MultiActionButtonUp (bar, id)
+ local button = _G[bar.."Button"..id];
+ if ( button:GetButtonState() == "PUSHED" ) then
+ button:SetButtonState("NORMAL");
+ SecureActionButton_OnClick(button, "LeftButton");
+ ActionButton_UpdateState(button);
+ end
+end
+
+function MultiActionBar_Update ()
+ if ( SHOW_MULTI_ACTIONBAR_1 and MainMenuBar.state=="player" ) then
+ MultiBarBottomLeft:Show();
+ MultiBarBottomLeft.isShowing = 1;
+ VIEWABLE_ACTION_BAR_PAGES[BOTTOMLEFT_ACTIONBAR_PAGE] = nil;
+ else
+ MultiBarBottomLeft:Hide();
+ MultiBarBottomLeft.isShowing = nil;
+ VIEWABLE_ACTION_BAR_PAGES[BOTTOMLEFT_ACTIONBAR_PAGE] = 1;
+ end
+ if ( SHOW_MULTI_ACTIONBAR_2 and MainMenuBar.state=="player") then
+ MultiBarBottomRight:Show();
+ VIEWABLE_ACTION_BAR_PAGES[BOTTOMRIGHT_ACTIONBAR_PAGE] = nil;
+ else
+ MultiBarBottomRight:Hide();
+ VIEWABLE_ACTION_BAR_PAGES[BOTTOMRIGHT_ACTIONBAR_PAGE] = 1;
+ end
+ if ( SHOW_MULTI_ACTIONBAR_3 and MainMenuBar.state=="player") then
+ MultiBarRight:Show();
+ VIEWABLE_ACTION_BAR_PAGES[RIGHT_ACTIONBAR_PAGE] = nil;
+ else
+ MultiBarRight:Hide();
+ VIEWABLE_ACTION_BAR_PAGES[RIGHT_ACTIONBAR_PAGE] = 1;
+ end
+ if ( SHOW_MULTI_ACTIONBAR_3 and SHOW_MULTI_ACTIONBAR_4 and MainMenuBar.state=="player") then
+ MultiBarLeft:Show();
+ VIEWABLE_ACTION_BAR_PAGES[LEFT_ACTIONBAR_PAGE] = nil;
+ else
+ MultiBarLeft:Hide();
+ VIEWABLE_ACTION_BAR_PAGES[LEFT_ACTIONBAR_PAGE] = 1;
+ end
+
+ --Adjust VehicleSeatIndicator position
+ if ( VehicleSeatIndicator ) then
+ if ( SHOW_MULTI_ACTIONBAR_3 and SHOW_MULTI_ACTIONBAR_4 ) then
+ VehicleSeatIndicator:SetPoint("TOPRIGHT", MinimapCluster, "BOTTOMRIGHT", -100, -13);
+ elseif ( SHOW_MULTI_ACTIONBAR_3 ) then
+ VehicleSeatIndicator:SetPoint("TOPRIGHT", MinimapCluster, "BOTTOMRIGHT", -62, -13);
+ else
+ VehicleSeatIndicator:SetPoint("TOPRIGHT", MinimapCluster, "BOTTOMRIGHT", 0, -13);
+ end
+ end
+end
+
+function MultiActionBar_ShowAllGrids ()
+ MultiActionBar_UpdateGrid("MultiBarBottomLeft", true);
+ MultiActionBar_UpdateGrid("MultiBarBottomRight", true);
+ MultiActionBar_UpdateGrid("MultiBarRight", true);
+ MultiActionBar_UpdateGrid("MultiBarLeft", true);
+end
+
+function MultiActionBar_HideAllGrids ()
+ MultiActionBar_UpdateGrid("MultiBarBottomLeft", false);
+ MultiActionBar_UpdateGrid("MultiBarBottomRight", false);
+ MultiActionBar_UpdateGrid("MultiBarRight", false);
+ MultiActionBar_UpdateGrid("MultiBarLeft", false);
+end
+
+function MultiActionBar_UpdateGrid (barName, show)
+ for i=1, NUM_MULTIBAR_BUTTONS do
+ if ( show ) then
+ ActionButton_ShowGrid(_G[barName.."Button"..i]);
+ else
+ ActionButton_HideGrid(_G[barName.."Button"..i]);
+ end
+ end
+end
+
+function MultiActionBar_UpdateGridVisibility ()
+ if ( ALWAYS_SHOW_MULTIBARS == "1" or ALWAYS_SHOW_MULTIBARS == 1 ) then
+ MultiActionBar_ShowAllGrids();
+ else
+ MultiActionBar_HideAllGrids();
+ end
+end
+
+function Multibar_EmptyFunc (show)
+
+end
+
+function MultibarGrid_IsVisible ()
+ STATE_AlwaysShowMultibars = ALWAYS_SHOW_MULTIBARS;
+ return ALWAYS_SHOW_MULTIBARS;
+end
+
+function MultiBar1_IsVisible ()
+ STATE_MultiBar1 = SHOW_MULTI_ACTIONBAR_1;
+ return SHOW_MULTI_ACTIONBAR_1;
+end
+
+function MultiBar2_IsVisible ()
+ STATE_MultiBar2 = SHOW_MULTI_ACTIONBAR_2;
+ return SHOW_MULTI_ACTIONBAR_2;
+end
+
+function MultiBar3_IsVisible ()
+ STATE_MultiBar3 = SHOW_MULTI_ACTIONBAR_3;
+ return SHOW_MULTI_ACTIONBAR_3;
+end
+
+function MultiBar4_IsVisible ()
+ STATE_MultiBar4 = SHOW_MULTI_ACTIONBAR_4;
+ return SHOW_MULTI_ACTIONBAR_4;
+end
+
diff --git a/reference/FrameXML/MultiActionBars.xml b/reference/FrameXML/MultiActionBars.xml
new file mode 100644
index 0000000..2b762c4
--- /dev/null
+++ b/reference/FrameXML/MultiActionBars.xml
@@ -0,0 +1,549 @@
+
+
+
+
+
+ self.buttonType = "MULTIACTIONBAR1BUTTON"
+ ActionButton_OnLoad(self);
+
+
+
+
+
+
+ self.buttonType = "MULTIACTIONBAR2BUTTON"
+ ActionButton_OnLoad(self);
+
+
+
+
+
+
+ self.buttonType = "MULTIACTIONBAR3BUTTON"
+ ActionButton_OnLoad(self);
+
+
+
+
+
+
+ self.buttonType = "MULTIACTIONBAR4BUTTON"
+ ActionButton_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MultiActionBarFrame_OnLoad(self);
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/MultiCastActionBarFrame.lua b/reference/FrameXML/MultiCastActionBarFrame.lua
new file mode 100644
index 0000000..1b78c7b
--- /dev/null
+++ b/reference/FrameXML/MultiCastActionBarFrame.lua
@@ -0,0 +1,1072 @@
+
+-- globals
+MULTICASTACTIONBAR_SLIDETIME = 0.09;
+MULTICASTACTIONBAR_YPOS = 0;
+MULTICASTACTIONBAR_XPOS = 30;
+NUM_MULTI_CAST_PAGES = 3;
+NUM_MULTI_CAST_BUTTONS_PER_PAGE = 4; -- NOTE: must match MAX_TOTEMS!!!
+
+-- locals
+local MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET = 4;
+local MULTI_CAST_FLYOUT_BUTTON_OFFSET = 2;
+local MULTI_CAST_FLYOUT_CLOSE_SEC = 3;
+
+local SLOT_EMPTY_TCOORDS = {
+ [EARTH_TOTEM_SLOT] = {
+ left = 66 / 128,
+ right = 96 / 128,
+ top = 3 / 256,
+ bottom = 33 / 256,
+ },
+ [FIRE_TOTEM_SLOT] = {
+ left = 67 / 128,
+ right = 97 / 128,
+ top = 100 / 256,
+ bottom = 130 / 256,
+ },
+ [WATER_TOTEM_SLOT] = {
+ left = 39 / 128,
+ right = 69 / 128,
+ top = 209 / 256,
+ bottom = 239 / 256,
+ },
+ [AIR_TOTEM_SLOT] = {
+ left = 66 / 128,
+ right = 96 / 128,
+ top = 36 / 256,
+ bottom = 66 / 256,
+ },
+};
+local SLOT_OVERLAY_TCOORDS = {
+ [EARTH_TOTEM_SLOT] = {
+ left = 1 / 128,
+ right = 35 / 128,
+ top = 172 / 256,
+ bottom = 206 / 256,
+ },
+ [FIRE_TOTEM_SLOT] = {
+ left = 36 / 128,
+ right = 70 / 128,
+ top = 172 / 256,
+ bottom = 206 / 256,
+ },
+ [WATER_TOTEM_SLOT] = {
+ left = 1 / 128,
+ right = 35 / 128,
+ top = 207 / 256,
+ bottom = 240 / 256,
+ },
+ [AIR_TOTEM_SLOT] = {
+ left = 36 / 128,
+ right = 70 / 128,
+ top = 137 / 256,
+ bottom = 171 / 256,
+ },
+};
+
+local FLYOUT_UP_BUTTON_TCOORDS = {
+ ["summon"] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 84 / 256,
+ bottom = 102 / 256,
+ },
+ [EARTH_TOTEM_SLOT] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 160 / 256,
+ bottom = 178 / 256,
+ },
+ [FIRE_TOTEM_SLOT] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 122 / 256,
+ bottom = 140 / 256,
+ },
+ [WATER_TOTEM_SLOT] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 199 / 256,
+ bottom = 217 / 256,
+ },
+ [AIR_TOTEM_SLOT] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 237 / 256,
+ bottom = 255 / 256,
+ },
+};
+local FLYOUT_DOWN_BUTTON_TCOORDS = {
+ ["summon"] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 65 / 256,
+ bottom = 83 / 256,
+ },
+ [EARTH_TOTEM_SLOT] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 141 / 256,
+ bottom = 159 / 256,
+ },
+ [FIRE_TOTEM_SLOT] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 103 / 256,
+ bottom = 121 / 256,
+ },
+ [WATER_TOTEM_SLOT] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 180 / 256,
+ bottom = 198 / 256,
+ },
+ [AIR_TOTEM_SLOT] = {
+ left = 99 / 128,
+ right = 127 / 128,
+ top = 218 / 256,
+ bottom = 236 / 256,
+ },
+};
+local FLYOUT_TOP_TCOORDS = {
+ ["summon"] = {
+ left = 33 / 128,
+ right = 65 / 128,
+ top = 1 / 256,
+ bottom = 23 / 256,
+ },
+ [EARTH_TOTEM_SLOT] = {
+ left = 0 / 128,
+ right = 32 / 128,
+ top = 46 / 256,
+ bottom = 68 / 256,
+ },
+ [FIRE_TOTEM_SLOT] = {
+ left = 33 / 128,
+ right = 65 / 128,
+ top = 46 / 256,
+ bottom = 68 / 256,
+ },
+ [WATER_TOTEM_SLOT] = {
+ left = 0 / 128,
+ right = 32 / 128,
+ top = 1 / 256,
+ bottom = 23 / 256,
+ },
+ [AIR_TOTEM_SLOT] = {
+ left = 0 / 128,
+ right = 32 / 128,
+ top = 91 / 256,
+ bottom = 113 / 256,
+ },
+};
+local FLYOUT_MIDDLE_TCOORDS = {
+ ["summon"] = {
+ left = 33 / 128,
+ right = 65 / 128,
+ top = 23 / 256,
+ bottom = 43 / 256,
+ },
+ [EARTH_TOTEM_SLOT] = {
+ left = 0 / 128,
+ right = 32 / 128,
+ top = 68 / 256,
+ bottom = 88 / 256,
+ },
+ [FIRE_TOTEM_SLOT] = {
+ left = 33 / 128,
+ right = 65 / 128,
+ top = 68 / 256,
+ bottom = 88 / 256,
+ },
+ [WATER_TOTEM_SLOT] = {
+ left = 0 / 128,
+ right = 32 / 128,
+ top = 23 / 256,
+ bottom = 43 / 256,
+ },
+ [AIR_TOTEM_SLOT] = {
+ left = 0 / 128,
+ right = 32 / 128,
+ top = 113 / 256,
+ bottom = 133 / 256,
+ },
+};
+
+-- knownMultiCastSummonSpells
+-- index: TOTEM_MULTI_CAST_SUMMON_SPELLS
+-- value: spellId if the spell is known, nil otherwise
+local knownMultiCastSummonSpells = { };
+-- knownMultiCastRecallSpells
+-- index: TOTEM_MULTI_CAST_RECALL_SPELLS
+-- value: spellId if the spell is known, nil otherwise
+local knownMultiCastRecallSpells = { };
+
+local function _ComputeMultiCastSlot(id)
+ return mod(id - 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE) + 1;
+end
+
+--
+-- MultiCastActionBar
+--
+
+function MultiCastActionBarFrame_OnLoad(self)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("UPDATE_MULTI_CAST_ACTIONBAR");
+
+ self.currentPage = 1;
+ MultiCastSummonSpellButton:SetID(self.currentPage);
+
+ self.numActiveSlots = 0;
+end
+
+function MultiCastActionBarFrame_OnEvent(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" or event == "UPDATE_MULTI_CAST_ACTIONBAR" ) then
+ MultiCastActionBarFrame_Update(self);
+ if ( HasMultiCastActionBar() ) then
+ ShowMultiCastActionBar();
+ LockMultiCastActionBar();
+ else
+ UnlockMultiCastActionBar();
+ HideMultiCastActionBar();
+ end
+ end
+end
+
+function MultiCastActionBarFrame_OnUpdate(self, elapsed)
+ local yPos;
+ if ( self.slideTimer and (self.slideTimer < self.timeToSlide) ) then
+ self.completed = false;
+ if ( self.mode == "show" ) then
+ yPos = (self.slideTimer/self.timeToSlide) * MULTICASTACTIONBAR_YPOS;
+ self:SetPoint("BOTTOMLEFT", self:GetParent(), "TOPLEFT", MULTICASTACTIONBAR_XPOS, yPos);
+ self.state = "showing";
+ self:Show();
+ elseif ( self.mode == "hide" ) then
+ yPos = (1 - (self.slideTimer/self.timeToSlide)) * MULTICASTACTIONBAR_YPOS;
+ self:SetPoint("BOTTOMLEFT", self:GetParent(), "TOPLEFT", MULTICASTACTIONBAR_XPOS, yPos);
+ self.state = "hiding";
+ end
+ self.slideTimer = self.slideTimer + elapsed;
+ else
+ self.completed = true;
+ if ( self.mode == "show" ) then
+ self:SetPoint("BOTTOMLEFT", self:GetParent(), "TOPLEFT", MULTICASTACTIONBAR_XPOS, MULTICASTACTIONBAR_YPOS);
+ self.state = "top";
+ --Move the chat frame and edit box up a bit
+ elseif ( self.mode == "hide" ) then
+ self:SetPoint("BOTTOMLEFT", self:GetParent(), "TOPLEFT", MULTICASTACTIONBAR_XPOS, 0);
+ self.state = "bottom";
+ self:Hide();
+ --Move the chat frame and edit box back down to original position
+ end
+ self.mode = "none";
+ end
+end
+
+function ShowMultiCastActionBar(doNotSlide)
+ if ( (not MainMenuBar.busy) and (not UnitHasVehicleUI("player")) ) then --Don't change while we're animating out MainMenuBar for vehicle UI
+ if ( (MultiCastActionBarFrame.mode ~= "show" and MultiCastActionBarFrame.state ~= "top") or (not UIParent:IsShown())) then
+ MultiCastActionBarFrame:Show();
+ if ( MultiCastActionBarFrame.completed ) then
+ MultiCastActionBarFrame.slideTimer = 0;
+ end
+ MultiCastActionBarFrame.timeToSlide = MULTICASTACTIONBAR_SLIDETIME;
+ MultiCastActionBarFrame.mode = "show";
+ end
+ end
+end
+
+function HideMultiCastActionBar()
+ if ( (not MainMenuBar.busy) and (not UnitHasVehicleUI("player")) ) then --Don't change while we're animating out MainMenuBar for vehicle UI
+ if ( (MultiCastActionBarFrame:IsShown()) or (not UIParent:IsShown())) then
+ if ( MultiCastActionBarFrame.completed ) then
+ MultiCastActionBarFrame.slideTimer = 0;
+ end
+ MultiCastActionBarFrame.timeToSlide = MULTICASTACTIONBAR_SLIDETIME;
+ MultiCastActionBarFrame.mode = "hide";
+ end
+ end
+end
+
+function LockMultiCastActionBar()
+ MultiCastActionBarFrame.locked = true;
+end
+
+function UnlockMultiCastActionBar()
+ MultiCastActionBarFrame.locked = false;
+end
+
+function MultiCastActionBarFrame_Update(self)
+ local currentPage = self.currentPage;
+
+ -- update the action buttons and slot buttons
+ local slot;
+ local actionButton, slotButton;
+ local actionIndex;
+ local slotIndex = 1;
+ local inverseSlotIndex;
+ local pageOffset;
+ local actionId;
+ for i = 1, NUM_MULTI_CAST_BUTTONS_PER_PAGE do
+ slot = TOTEM_PRIORITIES[i];
+ if ( GetTotemInfo(slot) and GetMultiCastTotemSpells(slot) ) then
+ -- update the slot button
+ slotButton = _G["MultiCastSlotButton"..slotIndex];
+ MultiCastSlotButton_Update(slotButton, slot);
+ -- update the action buttons using this totem slot on each page
+ for j = 1, NUM_MULTI_CAST_PAGES do
+ pageOffset = (j-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE;
+ actionIndex = pageOffset + slotIndex;
+ actionButton = _G["MultiCastActionButton"..actionIndex];
+ actionButton.slotButton = slotButton;
+ actionId = pageOffset + slot;
+ MultiCastActionButton_Update(actionButton, actionId, actionIndex, slot);
+ -- if this is the current page, store a reference to the action button on the slot button
+ if ( j == currentPage ) then
+ slotButton.actionButton = actionButton;
+ end
+ end
+ slotIndex = slotIndex + 1;
+ else
+ inverseSlotIndex = NUM_MULTI_CAST_BUTTONS_PER_PAGE - i + slotIndex;
+ -- hide the slot button
+ slotButton = _G["MultiCastSlotButton"..inverseSlotIndex];
+ MultiCastSlotButton_Update(slotButton, 0);
+ -- hide the action buttons for this button index on each page
+ for j = 1, NUM_MULTI_CAST_PAGES do
+ pageOffset = (j-1) * NUM_MULTI_CAST_BUTTONS_PER_PAGE;
+ actionIndex = pageOffset + inverseSlotIndex;
+ actionButton = _G["MultiCastActionButton"..actionIndex];
+ actionButton.slotButton = nil;
+ actionId = pageOffset + slot;
+ MultiCastActionButton_Update(actionButton, actionId, actionIndex, 0);
+ end
+ slotButton.actionButton = nil;
+ end
+ end
+
+ self.numActiveSlots = slotIndex - 1;
+ if ( self.numActiveSlots == 0 ) then
+ self:Hide();
+ return;
+ end
+ self:Show();
+
+ -- update the multi cast spells
+ MultiCastSummonSpellButton_Update(MultiCastSummonSpellButton);
+ MultiCastRecallSpellButton_Update(MultiCastRecallSpellButton);
+end
+
+function HasMultiCastActionBar()
+ return MultiCastActionBarFrame.numActiveSlots and MultiCastActionBarFrame.numActiveSlots > 0;
+end
+
+function HasMultiCastActionPage(page)
+ return ( page >= 1 and page <= NUM_MULTI_CAST_PAGES and knownMultiCastSummonSpells[page] );
+end
+
+function ChangeMultiCastActionPage(page)
+ local prevPage = MultiCastActionBarFrame.currentPage;
+ if ( page ~= prevPage and HasMultiCastActionPage(page) ) then
+ MultiCastActionBarFrame.currentPage = page;
+ MultiCastSummonSpellButton:SetID(page);
+ _G["MultiCastActionPage"..prevPage]:Hide();
+ _G["MultiCastActionPage"..page]:Show();
+ MultiCastActionBarFrame_Update(MultiCastActionBarFrame);
+ end
+end
+
+
+--
+-- MultiCastSlotButton
+--
+
+
+function MultiCastSlotButton_OnEvent(self, event, ...)
+ if ( event == "MODIFIER_STATE_CHANGED" ) then
+ if ( IsModifiedClick("SHOWMULTICASTFLYOUT") and self:IsMouseOver() ) then
+ MultiCastSlotButton_OnEnter(self);
+ end
+ end
+end
+
+function MultiCastSlotButton_OnEnter(self)
+ if ( MultiCastFlyoutFrame.parent ~= self ) then
+ MultiCastFlyoutFrameOpenButton_Show(MultiCastFlyoutFrameOpenButton, "slot", self);
+ end
+--[[
+ self:RegisterEvent("MODIFIER_STATE_CHANGED");
+ if ( IsModifiedClick("SHOWMULTICASTFLYOUT") ) then
+ local slot = self:GetID();
+ MultiCastFlyoutFrame_ToggleFlyout(MultiCastFlyoutFrame, "slot", self);
+ end
+--]]
+end
+
+function MultiCastSlotButton_OnLeave(self)
+ GameTooltip:Hide();
+ MultiCastFlyoutFrameOpenButton_Hide(MultiCastFlyoutFrameOpenButton);
+end
+
+function MultiCastSlotButton_Update(self, slot)
+ self:SetID(slot);
+ if ( slot == 0 ) then
+ self:Hide();
+ else
+ -- fixup textures
+ local tcoords = SLOT_OVERLAY_TCOORDS[slot];
+ self.overlay:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ tcoords = SLOT_EMPTY_TCOORDS[slot];
+ self.background:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+
+ self:Show();
+ end
+end
+
+
+--
+-- MultiCastActionButton
+--
+
+function MultiCastActionButton_OnLoad(self)
+ -- fixup textures
+ local name = self:GetName();
+ local normalTexture = _G[name.."NormalTexture"];
+ normalTexture:SetWidth(50);
+ normalTexture:SetHeight(50);
+
+ -- setup action button stuff
+ self.buttonType = "MULTICASTACTIONBUTTON";
+ self.buttonIndex = self:GetID();
+ ActionButton_OnLoad(self);
+end
+
+function MultiCastActionButton_OnEvent(self, event, ...)
+ ActionButton_OnEvent(self, event, ...);
+ if ( event == "MODIFIER_STATE_CHANGED" ) then
+ if ( IsModifiedClick("SHOWMULTICASTFLYOUT") and self:IsMouseOver() ) then
+ MultiCastActionButton_OnEnter(self);
+ end
+ end
+end
+
+function MultiCastActionButton_OnShow(self)
+ if ( not self.slotButton ) then
+ self:Hide();
+ end
+end
+
+function MultiCastActionButton_OnEnter(self)
+ MultiCastSlotButton_OnEnter(self.slotButton);
+ ActionButton_SetTooltip(self);
+end
+
+function MultiCastActionButton_OnLeave(self)
+ GameTooltip:Hide();
+ MultiCastFlyoutFrameOpenButton_Hide(MultiCastFlyoutFrameOpenButton);
+end
+
+function MultiCastActionButton_OnPostClick(self, button, down)
+ ActionButton_UpdateState(self, button, down);
+ MultiCastFlyoutFrame_Hide(MultiCastFlyoutFrame, true);
+end
+
+function MultiCastActionButton_Update(self, id, index, slot)
+ self:SetID(id);
+ self.buttonIndex = index;
+ if ( slot == 0 ) then
+ self:Hide();
+ else
+ ActionButton_UpdateAction(self);
+ ActionButton_Update(self);
+ ActionButton_UpdateHotkeys(self, self.buttonType);
+
+ -- fixup textures
+ local tcoords;
+ tcoords = SLOT_OVERLAY_TCOORDS[slot];
+ self.overlay:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ self:Show();
+ end
+end
+
+function MultiCastActionButtonDown(id)
+ local button = _G["MultiCastActionButton"..id];
+ if ( button:GetButtonState() == "NORMAL" ) then
+ button:SetButtonState("PUSHED");
+ end
+end
+
+function MultiCastActionButtonUp(id)
+ local button = _G["MultiCastActionButton"..id];
+ if ( button:GetButtonState() == "PUSHED" ) then
+ button:SetButtonState("NORMAL");
+ SecureActionButton_OnClick(button, "LeftButton");
+ ActionButton_UpdateState(button);
+ end
+ MultiCastFlyoutFrame_Hide(MultiCastFlyoutFrame, true);
+end
+
+
+--
+-- MultiCastFlyoutButton
+--
+
+function MultiCastFlyoutButton_OnLoad(self)
+ self:RegisterForClicks("AnyUp");
+
+ local parent = self:GetParent();
+ tinsert(parent.buttons, self);
+end
+
+function MultiCastFlyoutButton_OnClick(self)
+ local parent = self:GetParent();
+
+ if ( self.spellId ) then
+ local type = parent.type;
+ if ( type == "page" ) then
+ ChangeMultiCastActionPage(self.page);
+ elseif ( type == "slot" ) then
+ SetMultiCastSpell(ActionButton_CalculateAction(parent.parent.actionButton), self.spellId);
+ end
+ end
+
+ MultiCastFlyoutFrame_Hide(parent, true);
+end
+
+function MultiCastFlyoutButton_OnEnter(self)
+ MultiCastFlyoutButton_SetTooltip(self);
+end
+
+function MultiCastFlyoutButton_OnLeave(self)
+ GameTooltip:Hide();
+end
+
+function MultiCastFlyoutButton_SetTooltip(self)
+ if ( self.spellId ) then
+ if ( self.spellId == 0 ) then
+ if ( GetCVarBool("UberTooltips") ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+ GameTooltip:SetText(MULTI_CAST_TOOLTIP_NO_TOTEM, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ self.UpdateTooltip = nil;
+ else
+ if ( GetCVarBool("UberTooltips") ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+ if ( GameTooltip:SetSpellByID(self.spellId, false, true) ) then
+ self.UpdateTooltip = MultiCastFlyoutButton_SetTooltip;
+ else
+ self.UpdateTooltip = nil;
+ end
+ end
+ end
+end
+
+
+--
+-- MultiCastFlyoutFrame
+--
+
+function MultiCastFlyoutFrame_OnShow(self)
+ MultiCastFlyoutFrameOpenButton_Hide(MultiCastFlyoutFrameOpenButton, true);
+end
+
+function MultiCastFlyoutFrame_OnHide(self)
+ self.type = nil;
+ self.parent = nil;
+end
+
+function MultiCastFlyoutFrame_OnEnter(self)
+end
+
+function MultiCastFlyoutFrame_OnLeave(self)
+--[[
+ if ( not self:IsMouseOver() ) then
+ self.closeCountdownSec = MULTI_CAST_FLYOUT_CLOSE_SEC;
+ end
+--]]
+end
+
+function MultiCastFlyoutFrame_OnUpdate(self, elapsed)
+--[[
+ local closeCountdownSec = self.closeCountdownSec;
+ if ( closeCountdownSec ) then
+ closeCountdownSec = closeCountdownSec - elapsed;
+ if ( closeCountdownSec <= 0 ) then
+ self.closeCountdownSec = nil;
+ self:Hide();
+ else
+ self.closeCountdownSec = closeCountdownSec;
+ end
+ end
+--]]
+end
+
+function MultiCastFlyoutFrame_Hide(self, forceHide)
+ if ( forceHide or not self:IsMouseOver() ) then
+ if ( self.parent ) then
+ if ( self.parent:IsMouseOver() ) then
+ MultiCastFlyoutFrameOpenButton_Show(MultiCastFlyoutFrameOpenButton, self.type, self.parent);
+ else
+ self.parent:UnregisterEvent("MODIFIER_STATE_CHANGED");
+ end
+ end
+ self:Hide();
+ end
+end
+
+function MultiCastFlyoutFrame_ToggleFlyout(self, type, parent)
+ if ( self:IsShown() and self.parent == parent ) then
+ MultiCastFlyoutFrame_Hide(self, true);
+ else
+ local toptcoords;
+ local midtcoords;
+ local closetcoords;
+ if ( type == "slot" ) then
+ local actionId = parent:GetID();
+ local slot = _ComputeMultiCastSlot(actionId);
+ if ( MultiCastFlyoutFrame_LoadSlotSpells(self, slot, GetMultiCastTotemSpells(actionId)) ) then
+ toptcoords = FLYOUT_TOP_TCOORDS[slot];
+ midtcoords = FLYOUT_MIDDLE_TCOORDS[slot];
+ closetcoords = FLYOUT_DOWN_BUTTON_TCOORDS[slot];
+ end
+ elseif ( type == "page" ) then
+ if ( MultiCastFlyoutFrame_LoadPageSpells(self) ) then
+ toptcoords = FLYOUT_TOP_TCOORDS["summon"];
+ midtcoords = FLYOUT_MIDDLE_TCOORDS["summon"];
+ closetcoords = FLYOUT_DOWN_BUTTON_TCOORDS["summon"];
+ end
+ end
+ if ( toptcoords ) then
+ self.type = type;
+ self.parent = parent;
+ self:SetPoint("BOTTOM", parent, "TOP", 0, 0);
+ self:Show();
+
+ self.top:SetTexCoord(toptcoords.left, toptcoords.right, toptcoords.top, toptcoords.bottom);
+ self.middle:SetTexCoord(midtcoords.left, midtcoords.right, midtcoords.top, midtcoords.bottom);
+ MultiCastFlyoutFrameCloseButton.normalTexture:SetTexCoord(closetcoords.left, closetcoords.right, closetcoords.top, closetcoords.bottom);
+ end
+ end
+end
+
+function MultiCastFlyoutFrame_LoadPageSpells(self)
+ local numKnownSpells = 0;
+ for i, spellId in next, TOTEM_MULTI_CAST_SUMMON_SPELLS do
+ if ( knownMultiCastSummonSpells[i] ) then
+ numKnownSpells = numKnownSpells + 1;
+ end
+ end
+ if ( numKnownSpells == 0 ) then
+ return false;
+ end
+
+ self.buttons = self.buttons or {};
+ local buttons = self.buttons;
+ local numButtons = #buttons;
+
+ local name = self:GetName();
+ local totalHeight = 0;
+ local button;
+ local spellId;
+ local name, rank, icon;
+ local buttonIndex = 1;
+ for i, spellId in next, TOTEM_MULTI_CAST_SUMMON_SPELLS do
+ if ( knownMultiCastSummonSpells[i] ) then
+ -- create the button
+ if ( buttonIndex <= numButtons ) then
+ button = buttons[buttonIndex];
+ if ( buttonIndex == 1 ) then
+ totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET;
+ else
+ totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_OFFSET;
+ end
+ else
+ button = CreateFrame("Button", "MultiCastFlyoutButton"..buttonIndex, self, "MultiCastFlyoutButtonTemplate");
+ if ( buttonIndex == 1 ) then
+ -- this is the first button, anchor it to the frame
+ button:SetPoint("BOTTOM", self, "BOTTOM", 0, MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET);
+ totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET;
+ else
+ -- this is not the first button, anchor it to the previous button
+ button:SetPoint("BOTTOM", buttons[buttonIndex - 1], "TOP", 0, MULTI_CAST_FLYOUT_BUTTON_OFFSET);
+ totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_OFFSET;
+ end
+ end
+ totalHeight = totalHeight + button:GetHeight();
+
+ -- setup the button
+ button.page = i;
+ spellId = TOTEM_MULTI_CAST_SUMMON_SPELLS[i];
+ button.spellId = spellId;
+ name, rank, icon = GetSpellInfo(spellId);
+ button.icon:SetTexture(icon);
+ button.icon:SetTexCoord(0.0, 1.0, 0.0, 1.0);
+
+ button:Show();
+
+ buttonIndex = buttonIndex + 1;
+ end
+ end
+ -- hide unused buttons
+ for i = buttonIndex, numButtons do
+ buttons[i]:Hide();
+ end
+
+ self:SetHeight(totalHeight + 2 + MultiCastFlyoutFrameCloseButton:GetHeight());
+
+ return true;
+end
+
+function MultiCastFlyoutFrame_LoadSlotSpells(self, slot, ...)
+ local numSpells = select("#", ...);
+ if ( numSpells == 0 ) then
+ return false;
+ end
+ -- add one to numSpells to represent the "none" slot
+ numSpells = numSpells + 1;
+
+ self.buttons = self.buttons or {};
+ local buttons = self.buttons;
+ local numButtons = #buttons;
+
+ local name = self:GetName();
+ local totalHeight = 0;
+ local button;
+ local spellId;
+ local name, rank, icon;
+ local tcoords;
+ local tcoordLeft, tcoordRight, tcoordTop, tcoordBottom;
+ for i = 1, numSpells do
+ -- create the button
+ if ( i <= numButtons ) then
+ button = buttons[i];
+ if ( i == 1 ) then
+ totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET;
+ else
+ totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_OFFSET;
+ end
+ else
+ button = CreateFrame("Button", "MultiCastFlyoutButton"..i, self, "MultiCastFlyoutButtonTemplate");
+ button:ClearAllPoints();
+ if ( i == 1 ) then
+ -- this is the first button, anchor it to the frame
+ button:SetPoint("BOTTOM", self, "BOTTOM", 0, MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET);
+ totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_INITIAL_OFFSET;
+ else
+ -- this is not the first button, anchor it to the previous button
+ button:SetPoint("BOTTOM", buttons[i - 1], "TOP", 0, MULTI_CAST_FLYOUT_BUTTON_OFFSET);
+ totalHeight = totalHeight + MULTI_CAST_FLYOUT_BUTTON_OFFSET;
+ end
+ end
+ totalHeight = totalHeight + button:GetHeight();
+
+ -- setup the button
+ if ( i == 1 ) then
+ -- the first button clears your slot
+ spellId = 0;
+ icon = "Interface\\Buttons\\UI-TotemBar";
+ tcoords = SLOT_EMPTY_TCOORDS[slot];
+ tcoordLeft, tcoordRight, tcoordTop, tcoordBottom = tcoords.left, tcoords.right, tcoords.top, tcoords.bottom;
+ else
+ spellId = select(i - 1, ...);
+ name, rank, icon = GetSpellInfo(spellId);
+ tcoordLeft, tcoordRight, tcoordTop, tcoordBottom = 0.0, 1.0, 0.0, 1.0;
+ end
+ button.spellId = spellId;
+ button.icon:SetTexture(icon);
+ button.icon:SetTexCoord(tcoordLeft, tcoordRight, tcoordTop, tcoordBottom);
+
+ button:Show();
+ end
+ -- hide unused buttons
+ for i = numSpells + 1, numButtons do
+ buttons[i]:Hide();
+ end
+
+ self:SetHeight(totalHeight + 2 + MultiCastFlyoutFrameCloseButton:GetHeight());
+
+ return true;
+end
+
+
+--
+-- MultiCastFlyoutFrameCloseButton
+--
+
+function MultiCastFlyoutFrameCloseButton_OnClick(self)
+ self:GetParent():Hide();
+end
+
+
+--
+-- MultiCastFlyoutFrameOpenButton
+--
+
+function MultiCastFlyoutFrameOpenButton_OnClick(self)
+ MultiCastFlyoutFrame_ToggleFlyout(MultiCastFlyoutFrame, self.type, self.parent);
+end
+
+function MultiCastFlyoutFrameOpenButton_OnLeave(self)
+ self:Hide();
+end
+
+function MultiCastFlyoutFrameOpenButton_Show(self, type, parent)
+ local tcoords;
+ if ( type == "page" ) then
+ tcoords = FLYOUT_UP_BUTTON_TCOORDS["summon"];
+ elseif ( type == "slot" ) then
+ local slot = _ComputeMultiCastSlot(parent:GetID());
+ tcoords = FLYOUT_UP_BUTTON_TCOORDS[slot];
+ end
+ if ( tcoords ) then
+ self.normalTexture:SetTexCoord(tcoords.left, tcoords.right, tcoords.top, tcoords.bottom);
+ self.type = type;
+ self.parent = parent;
+ self:SetParent(parent);
+ self:SetPoint("BOTTOM", parent, "TOP", 0, 0);
+ self:Show();
+ end
+end
+
+function MultiCastFlyoutFrameOpenButton_Hide(self, force)
+ if ( force or (not self:IsMouseOver() and not self.parent:IsMouseOver()) ) then
+ self.type = nil;
+ self:Hide();
+ end
+end
+
+
+--
+-- MultiCastSpellButton
+--
+
+function MultiCastSpellButton_OnLoad(self)
+ self:RegisterForClicks("AnyUp");
+
+ local name = self:GetName();
+ local normalTexture = _G[name.."NormalTexture"];
+ normalTexture:SetWidth(50);
+ normalTexture:SetHeight(50);
+end
+
+function MultiCastSpellButton_OnEvent(self, event, ...)
+ if ( event == "UPDATE_BINDINGS" ) then
+ ActionButton_UpdateHotkeys(self, self.buttonType);
+ elseif ( event == "ACTIONBAR_UPDATE_COOLDOWN" ) then
+ MultiCastSpellButton_UpdateCooldown(self);
+ elseif ( event == "ACTIONBAR_UPDATE_STATE" ) then
+ MultiCastSpellButton_UpdateState(self);
+ end
+end
+
+function MultiCastSpellButton_OnEnter(self)
+ MultiCastSpellButton_SetTooltip(self);
+end
+
+function MultiCastSpellButton_OnLeave(self)
+ GameTooltip:Hide();
+end
+
+function MultiCastSpellButton_SetTooltip(self)
+ if ( GetCVarBool("UberTooltips") ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+ if ( GameTooltip:SetSpellByID(self.spellId, false, true) ) then
+ self.UpdateTooltip = MultiCastSpellButton_SetTooltip;
+ else
+ self.UpdateTooltip = nil;
+ end
+end
+
+function MultiCastSpellButton_UpdateCooldown(self)
+ local cooldown = _G[self:GetName().."Cooldown"];
+ local start, duration, enable = GetSpellCooldown(self.spellId);
+ CooldownFrame_SetTimer(cooldown, start, duration, enable);
+end
+
+function MultiCastSpellButton_UpdateState(self)
+ if ( IsCurrentSpell(self.spellId) ) then
+ self:SetChecked(1);
+ else
+ self:SetChecked(nil);
+ end
+end
+
+
+--
+-- MultiCastSummonSpellButton
+--
+
+function MultiCastSummonSpellButton_OnLoad(self)
+ self.buttonType = "MULTICASTSUMMONBUTTON";
+ MultiCastSpellButton_OnLoad(self);
+end
+
+function MultiCastSummonSpellButton_OnEvent(self, event, ...)
+ MultiCastSpellButton_OnEvent(self, event, ...);
+--[[
+ if ( event == "MODIFIER_STATE_CHANGED" ) then
+ if ( IsModifiedClick("SHOWMULTICASTFLYOUT") and self:IsMouseOver() ) then
+ MultiCastSummonSpellButton_OnEnter(self);
+ end
+ end
+--]]
+end
+
+function MultiCastSummonSpellButton_OnClick(self)
+ MultiCastSummonSpellButtonUp(self:GetID());
+end
+
+function MultiCastSummonSpellButton_OnEnter(self)
+ MultiCastSpellButton_OnEnter(self);
+
+ if ( MultiCastFlyoutFrame.parent ~= self ) then
+ MultiCastFlyoutFrameOpenButton_Show(MultiCastFlyoutFrameOpenButton, "page", self);
+ end
+--[[
+ self:RegisterEvent("MODIFIER_STATE_CHANGED");
+ if ( IsModifiedClick("SHOWMULTICASTFLYOUT") ) then
+ MultiCastFlyoutFrame_ToggleFlyout(MultiCastFlyoutFrame, "page", self);
+ end
+--]]
+end
+
+function MultiCastSummonSpellButton_OnLeave(self)
+ MultiCastSpellButton_OnLeave(self);
+ MultiCastFlyoutFrameOpenButton_Hide(MultiCastFlyoutFrameOpenButton);
+end
+
+function MultiCastSummonSpellButton_Update(self)
+ -- first update which multi-cast spells we actually know
+ for index, spellId in next, TOTEM_MULTI_CAST_SUMMON_SPELLS do
+ knownMultiCastSummonSpells[index] = (IsSpellKnown(spellId) and spellId) or nil;
+ end
+
+ -- update the spell button
+ local spellId = knownMultiCastSummonSpells[self:GetID()];
+ self.spellId = spellId;
+ if ( HasMultiCastActionBar() and spellId ) then
+ local name, rank, icon, cost, isFunnel, powerType, castTime, minRage, maxRange = GetSpellInfo(spellId);
+ local buttonName = self:GetName();
+ _G[buttonName.."Icon"]:SetTexture(icon);
+
+ if ( not self.eventsRegistered ) then
+ self:RegisterEvent("UPDATE_BINDINGS");
+ self:RegisterEvent("ACTIONBAR_UPDATE_STATE");
+ self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
+ self.eventsRegistered = true;
+ end
+ ActionButton_UpdateHotkeys(self, self.buttonType);
+ MultiCastSpellButton_UpdateCooldown(self);
+
+ if ( GameTooltip:GetOwner() == self ) then
+ MultiCastSpellButton_SetTooltip(self);
+ end
+
+ -- reanchor the first slot button take make room for this button
+ local width = self:GetWidth();
+ local xOffset = width + 8 + 3;
+ local page;
+ for i = 1, NUM_MULTI_CAST_PAGES do
+ page = _G["MultiCastActionPage"..i];
+ page:SetPoint("BOTTOMLEFT", page:GetParent(), "BOTTOMLEFT", xOffset, 3);
+ end
+ MultiCastSlotButton1:SetPoint("BOTTOMLEFT", self:GetParent(), "BOTTOMLEFT", xOffset, 3);
+
+ self:Show();
+ else
+ if ( self.eventsRegistered ) then
+ self:UnregisterEvent("UPDATE_BINDINGS");
+ self:UnregisterEvent("ACTIONBAR_UPDATE_STATE");
+ self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
+ self.eventsRegistered = false;
+ end
+
+ -- reanchor the first slot button take the place of this button
+ local xOffset = 3;
+ local page;
+ for i = 1, NUM_MULTI_CAST_PAGES do
+ page = _G["MultiCastActionPage"..i];
+ page:SetPoint("BOTTOMLEFT", page:GetParent(), "BOTTOMLEFT", xOffset, 3);
+ end
+ MultiCastSlotButton1:SetPoint("BOTTOMLEFT", self:GetParent(), "BOTTOMLEFT", xOffset, 3);
+
+ self:Hide();
+ end
+end
+
+function MultiCastSummonSpellButtonUp(id)
+ CastSpellByID(TOTEM_MULTI_CAST_SUMMON_SPELLS[id]);
+end
+
+
+--
+-- MultiCastRecallSpellButton
+--
+
+function MultiCastRecallSpellButton_OnLoad(self)
+ self.buttonType = "MULTICASTRECALLBUTTON";
+ MultiCastSpellButton_OnLoad(self);
+end
+
+function MultiCastRecallSpellButton_OnClick(self)
+ MultiCastRecallSpellButtonUp(self:GetID());
+end
+
+function MultiCastRecallSpellButton_Update(self)
+ -- first update which multi-cast spells we actually know
+ for index, spellId in next, TOTEM_MULTI_CAST_RECALL_SPELLS do
+ knownMultiCastRecallSpells[index] = (IsSpellKnown(spellId) and spellId) or nil;
+ end
+
+ -- update the spell button
+ local spellId = knownMultiCastRecallSpells[self:GetID()];
+ self.spellId = spellId;
+ if ( HasMultiCastActionBar() and spellId ) then
+ local name, rank, icon, cost, isFunnel, powerType, castTime, minRage, maxRange = GetSpellInfo(spellId);
+ local buttonName = self:GetName();
+ _G[buttonName.."Icon"]:SetTexture(icon);
+
+ if ( not self.eventsRegistered ) then
+ self:RegisterEvent("UPDATE_BINDINGS");
+ self:RegisterEvent("ACTIONBAR_UPDATE_STATE");
+ self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
+ self.eventsRegistered = true;
+ end
+ ActionButton_UpdateHotkeys(self, self.buttonType);
+ MultiCastSpellButton_UpdateCooldown(self);
+
+ if ( GameTooltip:GetOwner() == self ) then
+ MultiCastSpellButton_SetTooltip(self);
+ end
+
+ -- anchor to the last shown slot
+ local activeSlots = MultiCastActionBarFrame.numActiveSlots;
+ if ( activeSlots > 0 ) then
+ self:SetPoint("LEFT", _G["MultiCastSlotButton"..activeSlots], "RIGHT", 8, 0);
+ end
+
+ self:Show();
+ else
+ if ( self.eventsRegistered ) then
+ self:UnregisterEvent("UPDATE_BINDINGS");
+ self:UnregisterEvent("ACTIONBAR_UPDATE_STATE");
+ self:UnregisterEvent("ACTIONBAR_UPDATE_COOLDOWN");
+ self.eventsRegistered = false;
+ end
+
+ self:Hide();
+ end
+end
+
+function MultiCastRecallSpellButtonUp(id)
+ CastSpellByID(TOTEM_MULTI_CAST_RECALL_SPELLS[id]);
+end
diff --git a/reference/FrameXML/MultiCastActionBarFrame.xml b/reference/FrameXML/MultiCastActionBarFrame.xml
new file mode 100644
index 0000000..8bc0358
--- /dev/null
+++ b/reference/FrameXML/MultiCastActionBarFrame.xml
@@ -0,0 +1,491 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MultiCastSlotButton_OnEvent(self, event, ...);
+
+
+ MultiCastSlotButton_OnEnter(self);
+
+
+ MultiCastSlotButton_OnLeave(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MultiCastActionButton_OnLoad(self);
+
+
+ MultiCastActionButton_OnEvent(self, event, ...);
+
+
+ MultiCastActionButton_OnShow(self);
+
+
+ MultiCastActionButton_OnEnter(self);
+
+
+ MultiCastActionButton_OnLeave(self);
+
+
+ MultiCastActionButton_OnPostClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MultiCastFlyoutButton_OnLoad(self);
+
+
+ MultiCastFlyoutButton_OnClick(self);
+
+
+ MultiCastFlyoutButton_OnEnter(self);
+
+
+ MultiCastFlyoutButton_OnLeave(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(MultiCastFlyoutFrame:GetFrameLevel() + 6);
+
+
+ MultiCastSummonSpellButtonFlyoutButton_OnClick(self);
+
+
+ MultiCastSummonSpellButtonFlyoutButton_OnLeave(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/OpacitySliderFrame.xml b/reference/FrameXML/OpacitySliderFrame.xml
new file mode 100644
index 0000000..aa2d91f
--- /dev/null
+++ b/reference/FrameXML/OpacitySliderFrame.xml
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/OptionsFrameTemplates.lua b/reference/FrameXML/OptionsFrameTemplates.lua
new file mode 100644
index 0000000..d09c3b3
--- /dev/null
+++ b/reference/FrameXML/OptionsFrameTemplates.lua
@@ -0,0 +1,406 @@
+-- if you change something here you probably want to change the glue version too
+
+local next = next;
+local function SecureNext(elements, key)
+ -- not totally necessary in all cases in this file (since Interface Options are independent), but
+ -- it's used anyway to keep things consistent, plus it's not a huge performance hindrance
+ return securecall(next, elements, key);
+end
+
+
+-- [[ functions for OptionsFrameTemplates controls ]] --
+
+function OptionsList_OnLoad (self, buttonTemplate)
+ local name = self:GetName();
+
+ --Setup random things!
+ self.scrollFrame = _G[name .. "List"];
+ self:SetBackdropBorderColor(.6, .6, .6, 1);
+ _G[name.."Bottom"]:SetVertexColor(.66, .66, .66);
+
+ --Create buttons for scrolling
+ local buttons = {};
+ local button = CreateFrame("BUTTON", name .. "Button1", self, buttonTemplate or "OptionsListButtonTemplate");
+ button:SetPoint("TOPLEFT", self, 0, -8);
+ self.buttonHeight = button:GetHeight();
+ tinsert(buttons, button);
+
+ local maxButtons = (self:GetHeight() - 8) / self.buttonHeight;
+ for i = 2, maxButtons do
+ button = CreateFrame("BUTTON", name .. "Button" .. i, self, buttonTemplate or "OptionsListButtonTemplate");
+ button:SetPoint("TOPLEFT", buttons[#buttons], "BOTTOMLEFT");
+ tinsert(buttons, button);
+ end
+
+ self.buttonHeight = button:GetHeight();
+ self.buttons = buttons;
+end
+
+function OptionsList_DisplayScrollBar (frame)
+ local list = frame.scrollFrame;
+ list:Show();
+
+ local listWidth = list:GetWidth();
+
+ for _, button in SecureNext, frame.buttons do
+ button:SetWidth(button:GetWidth() - listWidth);
+ end
+end
+
+function OptionsList_HideScrollBar (frame)
+ local list = frame.scrollFrame;
+ list:Hide();
+
+ local listWidth = list:GetWidth();
+
+ for _, button in SecureNext, frame.buttons do
+ button:SetWidth(button:GetWidth() + listWidth);
+ end
+end
+
+function OptionsList_HideButton (button)
+ -- Sparse for now, who knows what will end up here?
+ button:Hide();
+end
+
+function OptionsList_DisplayButton (button, element)
+ -- Do display things
+ button:Show();
+ button.element = element;
+
+ if (element.parent) then
+ button:SetNormalFontObject(GameFontHighlightSmall);
+ button:SetHighlightFontObject(GameFontHighlightSmall);
+ button.text:SetPoint("LEFT", 16, 2);
+ else
+ button:SetNormalFontObject(GameFontNormal);
+ button:SetHighlightFontObject(GameFontHighlight);
+ button.text:SetPoint("LEFT", 8, 2);
+ end
+ button.text:SetText(element.name);
+
+ if (element.hasChildren) then
+ if (element.collapsed) then
+ button.toggle:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-UP");
+ button.toggle:SetPushedTexture("Interface\\Buttons\\UI-PlusButton-DOWN");
+ else
+ button.toggle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-UP");
+ button.toggle:SetPushedTexture("Interface\\Buttons\\UI-MinusButton-DOWN");
+ end
+ button.toggle:Show();
+ else
+ button.toggle:Hide();
+ end
+end
+
+function OptionsList_DisplayPanel (panel)
+ local panelContainer = panel:GetParent();
+ if ( panelContainer.displayedPanel ) then
+ panelContainer.displayedPanel:Hide();
+ end
+ panelContainer.displayedPanel = panel;
+
+ panel:ClearAllPoints();
+ panel:SetPoint("TOPLEFT", panelContainer, "TOPLEFT");
+ panel:SetPoint("BOTTOMRIGHT", panelContainer, "BOTTOMRIGHT");
+ panel:Show();
+end
+
+function OptionsList_ClearSelection (listFrame, buttons)
+ for _, button in SecureNext, buttons do
+ button:UnlockHighlight();
+ end
+
+ listFrame.selection = nil;
+end
+
+function OptionsList_SelectButton (listFrame, button)
+ button:LockHighlight()
+
+ listFrame.selection = button.element;
+end
+
+function OptionsListScroll_Update (frame)
+ local parent = frame:GetParent();
+ parent:update();
+end
+
+function OptionsListButton_OnLoad (self, toggleFunc)
+ self.text = _G[self:GetName() .. "Text"];
+ self.highlight = self:GetHighlightTexture();
+ self.highlight:SetVertexColor(.196, .388, .8);
+ self.text:SetPoint("RIGHT", "$parentToggle", "LEFT", -2, 0);
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+ self.toggleFunc = toggleFunc or OptionsListButton_ToggleSubCategories;
+end
+
+function OptionsListButton_OnClick (self, mouseButton)
+ if ( mouseButton == "RightButton" ) then
+ if ( self.element.hasChildren ) then
+ OptionsListButtonToggle_OnClick(self.toggle);
+ end
+ return;
+ end
+
+ local listFrame = self:GetParent();
+
+ OptionsList_ClearSelection(listFrame, listFrame.buttons);
+ OptionsList_SelectButton(listFrame, self);
+
+ OptionsList_DisplayPanel(self.element);
+end
+
+function OptionsListButton_ToggleSubCategories (self)
+ local element = self.element;
+
+ element.collapsed = not element.collapsed;
+
+ local collapsed = element.collapsed;
+
+ local categoryFrame = self:GetParent();
+ local optionsFrame = categoryFrame:GetParent();
+ local categoryList = optionsFrame.categoryList;
+ for _, category in SecureNext, categoryList do
+ if ( category.parent == element.name ) then
+ if ( collapsed ) then
+ category.hidden = true;
+ else
+ category.hidden = false;
+ end
+ end
+ end
+
+ categoryFrame:update();
+end
+
+function OptionsListButtonToggle_OnClick (self)
+ local button = self:GetParent();
+ button:toggleFunc();
+end
+
+
+-- [[ OptionsFrameTemplate ]] --
+
+-- NOTE: the difference between "category" and "panel" is mostly a terminology difference
+-- let's say we have a set of options called foo
+-- "category" is used when referring to foo as data
+-- "panel" is used when referring to the frame that displays foo
+
+function OptionsFrame_OnLoad(self)
+ local name = self:GetName();
+
+ self.categoryFrame = _G[name.."CategoryFrame"];
+ self.panelContainer = _G[name.."PanelContainer"];
+
+ self.okay = _G[name.."Okay"];
+ self.cancel = _G[name.."Cancel"];
+ self.apply = _G[name.."Apply"];
+ self.default = _G[name.."Default"];
+
+ self.categoryList = { };
+
+ self:SetFrameLevel(UIErrorsFrame:GetFrameLevel() - 1);
+end
+
+function OptionsFrame_OnShow (self)
+ --Refresh the category frames and display the first category if nothing is displayed.
+ self.categoryFrame:update();
+ if ( not self.panelContainer.displayedPanel ) then
+ OptionsListButton_OnClick(self.categoryFrame.buttons[1]);
+ end
+ --Refresh the categories to pick up changes made while the options frame was hidden.
+ OptionsFrame_RefreshCategories(self);
+end
+
+function OptionsFrame_OnHide (self)
+ PlaySound("gsTitleOptionExit");
+
+ if ( self.lastFrame ) then
+ ShowUIPanel(self.lastFrame);
+ self.lastFrame = nil;
+ end
+
+ UpdateMicroButtons();
+end
+
+local function OptionsFrame_RunOkayForCategory (category)
+ pcall(category.okay, category);
+end
+
+local function OptionsFrame_RunCancelForCategory (category)
+ pcall(category.cancel, category);
+end
+
+local function OptionsFrame_RunDefaultForCategory (category)
+ pcall(category.default, category);
+end
+
+local function OptionsFrame_RunRefreshForCategory (category)
+ pcall(category.refresh, category);
+end
+
+function OptionsFrameOkay_OnClick (self, apply)
+ --Iterate through registered panels and run their okay methods in a taint-safe fashion
+ for _, category in SecureNext, self.categoryList do
+ securecall(OptionsFrame_RunOkayForCategory, category);
+ end
+end
+
+function OptionsFrameCancel_OnClick (self)
+ --Iterate through registered panels and run their cancel methods in a taint-safe fashion
+ for _, category in SecureNext, self.categoryList do
+ securecall(OptionsFrame_RunCancelForCategory, category);
+ end
+end
+
+function OptionsFrameDefault_OnClick (self)
+ -- NOTE: defer setting defaults until a popup dialog button is clicked
+end
+
+function OptionsFrame_SetAllToDefaults (self)
+ --Iterate through registered panels and run their default methods in a taint-safe fashion
+ for _, category in SecureNext, self.categoryList do
+ securecall(OptionsFrame_RunDefaultForCategory, category);
+ end
+
+ --Refresh the categories to pick up changes made.
+ OptionsFrame_RefreshCategories(self);
+end
+
+function OptionsFrame_SetCurrentToDefaults (self)
+ local displayedPanel = self.panelContainer.displayedPanel;
+ if ( not displayedPanel or not displayedPanel.default ) then
+ return;
+ end
+
+ displayedPanel.default(displayedPanel);
+ --Run the refresh method to refresh any values that were changed.
+ displayedPanel.refresh(displayedPanel);
+end
+
+function OptionsFrame_RefreshCategories (self)
+ for _, category in SecureNext, self.categoryList do
+ securecall(OptionsFrame_RunRefreshForCategory, category);
+ end
+end
+
+--Table to reuse! Yay reuse!
+local displayedElements = {};
+function OptionsCategoryFrame_Update (self)
+ --Redraw the scroll lists
+ local categoryList = self:GetParent().categoryList;
+
+ local element;
+ for i, element in SecureNext, displayedElements do
+ displayedElements[i] = nil;
+ end
+ for i, element in SecureNext, categoryList do
+ if ( not element.hidden ) then
+ tinsert(displayedElements, element);
+ end
+ end
+
+ local scrollFrame = self.scrollFrame;
+ local buttons = self.buttons;
+ local numButtons = #buttons;
+ local numCategories = #displayedElements;
+ if ( numCategories > numButtons and ( not scrollFrame:IsShown() ) ) then
+ OptionsList_DisplayScrollBar(self);
+ elseif ( numCategories <= numButtons and ( scrollFrame:IsShown() ) ) then
+ OptionsList_HideScrollBar(self);
+ end
+
+ FauxScrollFrame_Update(scrollFrame, numCategories, numButtons, buttons[1]:GetHeight());
+
+ local selection = self.selection;
+ if ( selection ) then
+ -- Store the currently selected element and clear all the buttons, we're redrawing.
+ OptionsList_ClearSelection(self, self.buttons);
+ end
+
+ local offset = FauxScrollFrame_GetOffset(scrollFrame);
+ for i = 1, numButtons do
+ element = displayedElements[i + offset];
+ if ( not element ) then
+ OptionsList_HideButton(buttons[i]);
+ else
+ OptionsList_DisplayButton(buttons[i], element);
+
+ if ( selection and selection == element and not self.selection ) then
+ OptionsList_SelectButton(self, buttons[i]);
+ end
+ end
+ end
+
+ if ( selection ) then
+ -- If there was a selected element before we cleared the button highlights, restore it, 'cause we're done.
+ -- Note: This theoretically might already have been done by OptionsList_SelectButton, but in the event that the selected button hasn't been drawn, this is still necessary.
+ self.selection = selection;
+ end
+end
+
+function OptionsFrame_OpenToCategory (self, panel)
+ local panelName;
+ if ( type(panel) == "string" ) then
+ panelName = panel;
+ panel = nil;
+ end
+ if ( not panelName or panel ) then
+ return;
+ end
+
+ local categoryList = self.categoryList;
+
+ local elementToDisplay;
+ for i, element in SecureNext, categoryList do
+ if ( element == panel or (panelName and element.name and element.name == panelName) ) then
+ elementToDisplay = element;
+ break;
+ end
+ end
+ if ( not elementToDisplay ) then
+ return;
+ end
+
+ local buttons = self.categoryFrame.buttons
+ for i, button in SecureNext, buttons do
+ if ( button.element == elementToDisplay ) then
+ button:Click();
+ elseif ( elementToDisplay.parent and button.element and (button.element.name == elementToDisplay.parent and button.element.collapsed) ) then
+ button.toggle:Click();
+ end
+ end
+
+ if ( not self:IsShown() ) then
+ self:Show();
+ end
+end
+
+function OptionsFrame_AddCategory (self, panel)
+ if ( not issecure() ) then
+ -- disallow any non-blizzard code to enter here...
+ -- we may want to change this in the future if we merge this with Interface Options
+ end
+ local parent = panel.parent;
+ if ( parent ) then
+ for i = 1, #self.categoryList do
+ if ( self.categoryList[i].name == parent ) then
+ if ( self.categoryList[i].hasChildren ) then
+ panel.hidden = self.categoryList[i].collapsed;
+ else
+ panel.hidden = true;
+ self.categoryList[i].hasChildren = true;
+ self.categoryList[i].collapsed = true;
+ end
+ tinsert(self.categoryList, i + 1, panel);
+ self.categoryFrame:update();
+ return;
+ end
+ end
+ end
+
+ tinsert(self.categoryList, panel);
+ self.categoryFrame:update();
+end
+
diff --git a/reference/FrameXML/OptionsFrameTemplates.xml b/reference/FrameXML/OptionsFrameTemplates.xml
new file mode 100644
index 0000000..ddbb65e
--- /dev/null
+++ b/reference/FrameXML/OptionsFrameTemplates.xml
@@ -0,0 +1,445 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 4);
+
+
+ PanelTemplates_TabResize(self, 0);
+ _G[self:GetName().."HighlightTexture"]:SetWidth(self:GetTextWidth() + 30);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(.6, .6, .6, .6);
+ ScrollFrame_OnLoad(self);
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, self:GetParent().buttonHeight, OptionsListScroll_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():SetVerticalScroll(value);
+
+
+
+
+
+
+
+
+
+ OptionsList_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent().toggle = self;
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ OptionsListButtonToggle_OnClick(self);
+
+
+
+
+
+
+
+
+
+ OptionsListButton_OnLoad(self);
+
+
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ OptionsListButton_OnClick(self, button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ --self.labelText = CATEGORY;
+ OptionsList_OnLoad(self);
+ self.update = OptionsCategoryFrame_Update;
+ self.toggleSubCategories = OptionsFrame_ToggleSubCategories;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(.6, .6, .6, 1);
+
+
+
+
+
+
+ OptionsFrame_OnLoad(self);
+
+
+ OptionsFrame_OnShow(self);
+
+
+ OptionsFrame_OnHide(self);
+
+
+
+
diff --git a/reference/FrameXML/OptionsPanelTemplates.lua b/reference/FrameXML/OptionsPanelTemplates.lua
new file mode 100644
index 0000000..79c9b44
--- /dev/null
+++ b/reference/FrameXML/OptionsPanelTemplates.lua
@@ -0,0 +1,456 @@
+
+-- if you change something here you probably want to change the glue version too
+
+CONTROLTYPE_CHECKBOX = 1;
+CONTROLTYPE_DROPDOWN = 2;
+CONTROLTYPE_SLIDER = 3;
+
+
+local ALT_KEY = "altkey";
+local CONTROL_KEY = "controlkey";
+local SHIFT_KEY = "shiftkey";
+local NO_KEY = "none";
+
+local next = next;
+local function SecureNext(elements, key)
+ return securecall(next, elements, key);
+end
+
+local tinsert = tinsert;
+local tonumber = tonumber;
+local tostring = tostring;
+local gsub = gsub;
+
+
+-- [[ Slider functions ]] --
+
+function BlizzardOptionsPanel_Slider_Disable (slider)
+ local name = slider:GetName();
+ getmetatable(slider).__index.Disable(slider);
+ _G[name.."Text"]:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ _G[name.."Low"]:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ _G[name.."High"]:SetVertexColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+end
+
+function BlizzardOptionsPanel_Slider_Enable (slider)
+ local name = slider:GetName();
+ getmetatable(slider).__index.Enable(slider);
+ _G[name.."Text"]:SetVertexColor(NORMAL_FONT_COLOR.r , NORMAL_FONT_COLOR.g , NORMAL_FONT_COLOR.b);
+ _G[name.."Low"]:SetVertexColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ _G[name.."High"]:SetVertexColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+end
+
+function BlizzardOptionsPanel_Slider_Refresh (slider)
+ local value;
+
+ if ( slider.GetCurrentValue ) then
+ value = slider:GetCurrentValue();
+ elseif ( slider.cvar ) then
+ value = BlizzardOptionsPanel_GetCVarSafe(slider.cvar);
+ end
+
+ if ( value ) then
+ if ( slider.SetDisplayValue ) then
+ slider:SetDisplayValue(value);
+ else
+ slider:SetValue(value);
+ end
+ slider.value = value;
+ end
+end
+
+function BlizzardOptionsPanel_Slider_OnValueChanged (self, value)
+ self.value = value;
+ BlizzardOptionsPanel_SetCVarSafe(self.cvar, value);
+end
+
+-- [[ CheckButton functions ]] --
+
+function BlizzardOptionsPanel_CheckButton_Disable(checkBox)
+ checkBox:Disable();
+ local text = _G[checkBox:GetName().."Text"];
+ if ( text ) then
+ text:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+end
+
+function BlizzardOptionsPanel_CheckButton_Enable(checkBox, isWhite)
+ checkBox:Enable();
+ local text = _G[checkBox:GetName().."Text"];
+ if ( not text ) then
+ return;
+ end
+ if ( isWhite ) then
+ text:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ else
+ text:SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+end
+
+function BlizzardOptionsPanel_CheckButton_OnClick (checkButton)
+ BlizzardOptionsPanel_CheckButton_SetNewValue(checkButton);
+
+ local setting = "0";
+ if ( checkButton:GetChecked() ) then
+ if ( not checkButton.invert ) then
+ setting = "1";
+ end
+ elseif ( checkButton.invert ) then
+ setting = "1";
+ end
+
+ if ( checkButton.setFunc ) then
+ checkButton.setFunc(setting);
+ end
+end
+
+function BlizzardOptionsPanel_CheckButton_SetNewValue (checkButton)
+ local setting = "0";
+ if ( checkButton:GetChecked() ) then
+ if ( not checkButton.invert ) then
+ setting = "1";
+ end
+ elseif ( checkButton.invert ) then
+ setting = "1";
+ end
+
+ if ( setting == checkButton.value ) then
+ checkButton.newValue = nil;
+ else
+ checkButton.newValue = setting;
+ end
+
+ if ( checkButton.dependentControls ) then
+ if ( checkButton:GetChecked() ) then
+ for _, control in SecureNext, checkButton.dependentControls do
+ control:Enable();
+ end
+ else
+ for _, control in SecureNext, checkButton.dependentControls do
+ control:Disable();
+ end
+ end
+ end
+end
+
+function BlizzardOptionsPanel_CheckButton_Refresh (checkButton)
+ local value;
+
+ if ( checkButton.cvar ) then
+ value = GetCVar(checkButton.cvar);
+ elseif ( checkButton.GetValue ) then
+ value = tostring(checkButton:GetValue());
+ end
+
+ if ( value ) then
+ if ( not checkButton.invert ) then
+ if ( value == "1" ) then
+ checkButton:SetChecked(true);
+ else
+ checkButton:SetChecked(false);
+ end
+ else
+ if ( value == "0" ) then
+ checkButton:SetChecked(true);
+ else
+ checkButton:SetChecked(false);
+ end
+ end
+
+ if ( checkButton.dependentControls ) then
+ if ( checkButton:GetChecked() ) then
+ for _, depControl in SecureNext, checkButton.dependentControls do
+ depControl:Enable();
+ end
+ else
+ for _, depControl in SecureNext, checkButton.dependentControls do
+ depControl:Disable();
+ end
+ end
+ end
+
+ checkButton.value = value;
+ end
+end
+
+-- [[ DropDown functions ]] --
+
+function BlizzardOptionsPanel_DropDown_Refresh (dropDown)
+ if ( dropDown.RefreshValue ) then
+ dropDown:RefreshValue();
+ end
+end
+
+
+-- [[ BlizzardOptionsPanel functions ]] --
+
+-- HACK: unfortunately, CVars have this funny quirk where they are returned as strings, even if they are numbers,
+-- which makes things complicated for sliders...things get even more complicated when you have a mix of regular
+-- Get/SetCVar calls with the following (typesafe) BlizzardOptionsPanel_Get/SetCVarSafe calls... so to avoid
+-- comparing numbers to strings, we are going to convert anything that needs comparing into a number first!
+
+function BlizzardOptionsPanel_SetCVarSafe (cvar, value, event)
+ local oldValue = GetCVar(cvar);
+ local oldValueNum = tonumber(oldValue);
+ local valueNum = tonumber(value);
+ if ( oldValueNum or valueNum ) then
+ if ( oldValueNum ~= valueNum ) then
+ SetCVar(cvar, value, event);
+ end
+ else
+ if ( oldValue ~= value ) then
+ SetCVar(cvar, value, event);
+ end
+ end
+end
+
+function BlizzardOptionsPanel_GetCVarSafe (cvar)
+ local value = GetCVar(cvar);
+ value = tonumber(value) or value;
+ return value;
+end
+
+function BlizzardOptionsPanel_GetCVarDefaultSafe (cvar)
+ local value = GetCVarDefault(cvar);
+ value = tonumber(value) or value;
+ return value;
+end
+
+function BlizzardOptionsPanel_GetCVarMinSafe (cvar)
+ local value = GetCVarMin(cvar);
+ value = tonumber(value) or value;
+ return value;
+end
+
+function BlizzardOptionsPanel_GetCVarMaxSafe (cvar)
+ local value = GetCVarMax(cvar);
+ value = tonumber(value) or value;
+ return value;
+end
+
+function BlizzardOptionsPanel_OkayControl (control)
+ if ( control.newValue ) then
+ if ( control.value ~= control.newValue ) then
+ control:SetValue(control.newValue);
+ control.value = control.newValue;
+ control.newValue = nil;
+ end
+ elseif ( control.value ) then
+ if ( control:GetValue() ~= control.value ) then
+ control:SetValue(control.value);
+ end
+ end
+end
+
+function BlizzardOptionsPanel_CancelControl (control)
+ if ( control.newValue ) then
+ if ( control.value and control.value ~= control.newValue ) then
+ -- we need to force-set the value here just in case the control was doing dynamic updating
+ control:SetValue(control.value);
+ control.newValue = nil;
+ end
+ elseif ( control.value ) then
+ if ( control:GetValue() ~= control.value ) then
+ control:SetValue(control.value);
+ end
+ end
+end
+
+function BlizzardOptionsPanel_DefaultControl (control)
+ if ( control.defaultValue and control.value ~= control.defaultValue ) then
+ control:SetValue(control.defaultValue);
+ control.value = control.defaultValue;
+ control.newValue = nil;
+ end
+end
+
+function BlizzardOptionsPanel_RefreshControl (control)
+ if ( control.type == CONTROLTYPE_CHECKBOX ) then
+ BlizzardOptionsPanel_CheckButton_Refresh(control);
+ elseif ( control.type == CONTROLTYPE_DROPDOWN ) then
+ BlizzardOptionsPanel_DropDown_Refresh(control);
+ elseif ( control.type == CONTROLTYPE_SLIDER ) then
+ BlizzardOptionsPanel_Slider_Refresh(control);
+ end
+end
+
+function BlizzardOptionsPanel_Okay (self)
+ for _, control in SecureNext, self.controls do
+ securecall(BlizzardOptionsPanel_OkayControl, control);
+ end
+end
+
+function BlizzardOptionsPanel_Cancel (self)
+ for _, control in SecureNext, self.controls do
+ securecall(BlizzardOptionsPanel_CancelControl, control);
+ end
+end
+
+function BlizzardOptionsPanel_Default (self)
+ for _, control in SecureNext, self.controls do
+ securecall(BlizzardOptionsPanel_DefaultControl, control);
+ end
+end
+
+function BlizzardOptionsPanel_Refresh (self)
+ for _, control in SecureNext, self.controls do
+ securecall(BlizzardOptionsPanel_RefreshControl, control);
+ end
+end
+
+function BlizzardOptionsPanel_OnLoad (frame, okay, cancel, default, refresh)
+ frame.okay = okay or BlizzardOptionsPanel_Okay;
+ frame.cancel = cancel or BlizzardOptionsPanel_Cancel;
+ frame.default = default or BlizzardOptionsPanel_Default;
+ frame.refresh = refresh or BlizzardOptionsPanel_Refresh;
+
+ frame:RegisterEvent("PLAYER_ENTERING_WORLD");
+ frame:SetScript("OnEvent", BlizzardOptionsPanel_OnEvent);
+end
+
+function BlizzardOptionsPanel_OnEvent (frame, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ if ( frame.options and frame.controls ) then
+ local entry;
+ local minValue, maxValue;
+ for i, control in SecureNext, frame.controls do
+ entry = frame.options[(control.cvar or control.label)];
+ if ( entry ) then
+ if ( entry.text ) then
+ control.tooltipText = (_G["OPTION_TOOLTIP_" .. gsub(entry.text, "_TEXT$", "")] or entry.tooltip);
+ local text = _G[control:GetName() .. "Text"];
+ if ( text ) then
+ text:SetText(_G[entry.text] or entry.text);
+ end
+ end
+ control.tooltipRequirement = entry.tooltipRequirement;
+
+ control.gameRestart = entry.gameRestart;
+ control.logout = entry.logout;
+
+ control.event = entry.event or entry.text;
+
+ if ( control.cvar ) then
+ if ( control.type == CONTROLTYPE_CHECKBOX ) then
+ control.defaultValue = GetCVarDefault(control.cvar);
+ else
+ control.defaultValue = BlizzardOptionsPanel_GetCVarDefaultSafe(control.cvar);
+ minValue = BlizzardOptionsPanel_GetCVarMinSafe(control.cvar) or entry.minValue;
+ maxValue = BlizzardOptionsPanel_GetCVarMaxSafe(control.cvar) or entry.maxValue;
+ end
+ else
+ control.defaultValue = control.defaultValue or entry.default;
+ minValue = entry.minValue;
+ maxValue = entry.maxValue;
+ end
+
+ if ( control.type == CONTROLTYPE_SLIDER ) then
+ BlizzardOptionsPanel_Slider_Enable(control);
+ control:SetMinMaxValues(minValue, maxValue);
+ control:SetValueStep(entry.valueStep);
+ end
+
+ securecall(BlizzardOptionsPanel_SetupControl, control);
+ end
+ end
+ end
+ frame:UnregisterEvent(event);
+ end
+end
+
+function BlizzardOptionsPanel_RegisterControl (control, parentFrame)
+ if ( ( not parentFrame ) or ( not control ) ) then
+ return;
+ end
+
+ parentFrame.controls = parentFrame.controls or {};
+
+ tinsert(parentFrame.controls, control);
+
+ -- Use the panel's OnEvent handler to wait and setup the control after game data is loaded
+end
+
+function BlizzardOptionsPanel_SetupControl (control)
+ if ( control.type == CONTROLTYPE_CHECKBOX ) then
+ if ( control.cvar ) then
+ local value = GetCVar(control.cvar);
+ control.value = value;
+
+ if ( control.uvar ) then
+ _G[control.uvar] = value;
+ end
+
+ control.GetValue = function(self) return GetCVar(self.cvar); end
+ control.SetValue = function(self, value) self.value = value; BlizzardOptionsPanel_SetCVarSafe(self.cvar, value, self.event); if ( self.uvar ) then _G[self.uvar] = value end end
+ control.Disable = function (self) getmetatable(self).__index.Disable(self) _G[self:GetName().."Text"]:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b) end;
+ control.Enable = function (self)
+ getmetatable(self).__index.Enable(self);
+ local text = _G[self:GetName().."Text"];
+ local fontObject = text:GetFontObject();
+ _G[self:GetName().."Text"]:SetTextColor(fontObject:GetTextColor());
+ end
+ elseif ( control.GetValue ) then
+ if ( control.type == CONTROLTYPE_CHECKBOX ) then
+ local value = control:GetValue();
+ if ( value ) then
+ control.value = tostring(value);
+ else
+ control.value = "0";
+ end
+ if ( control.uvar ) then
+ _G[control.uvar] = value;
+ end
+
+ control.SetValue = function(self, value) self.value = value; if ( self.uvar ) then _G[self.uvar] = value; end end;
+ control.Disable = function (self) getmetatable(self).__index.Disable(self) _G[self:GetName().."Text"]:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b) end;
+ control.Enable = function (self)
+ getmetatable(self).__index.Enable(self);
+ local text = _G[self:GetName().."Text"];
+ local fontObject = text:GetFontObject();
+ _G[self:GetName().."Text"]:SetTextColor(fontObject:GetTextColor());
+ end
+ end
+ end
+ elseif ( control.type == CONTROLTYPE_SLIDER ) then
+ local value;
+ if ( control.GetCurrentValue ) then
+ value = control:GetCurrentValue();
+ elseif ( control.cvar ) then
+ value = BlizzardOptionsPanel_GetCVarSafe(control.cvar);
+ else
+ value = control:GetValue();
+ end
+
+ if ( control.SetDisplayValue ) then
+ control:SetDisplayValue(value);
+ else
+ control:SetValue(value);
+ end
+ -- set the value AFTER the set value function call so the current value matches the new value
+ -- just in case an OnValueChange script changed the new value
+ control.value = value;
+
+ control.Disable = BlizzardOptionsPanel_Slider_Disable;
+ control.Enable = BlizzardOptionsPanel_Slider_Enable;
+ end
+end
+
+function BlizzardOptionsPanel_SetupDependentControl (dependency, control)
+ if ( not dependency ) then
+ return;
+ end
+
+ assert(control);
+
+ dependency.dependentControls = dependency.dependentControls or {};
+ tinsert(dependency.dependentControls, control);
+
+ if ( control.type ~= CONTROLTYPE_DROPDOWN ) then
+ control.Disable = function (self) getmetatable(self).__index.Disable(self) _G[self:GetName().."Text"]:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b) end;
+ control.Enable = function (self) getmetatable(self).__index.Enable(self) _G[self:GetName().."Text"]:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b) end;
+ else
+ control.Disable = function (self) UIDropDownMenu_DisableDropDown(self) end;
+ control.Enable = function (self) UIDropDownMenu_EnableDropDown(self) end;
+ end
+end
+
diff --git a/reference/FrameXML/OptionsPanelTemplates.xml b/reference/FrameXML/OptionsPanelTemplates.xml
new file mode 100644
index 0000000..ce907f0
--- /dev/null
+++ b/reference/FrameXML/OptionsPanelTemplates.xml
@@ -0,0 +1,176 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ BlizzardOptionsPanel_CheckButton_OnClick(self);
+
+
+ if ( self.tooltipText ) then
+ GameTooltip:SetOwner(self, self.tooltipOwnerPoint or "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltipText, nil, nil, nil, nil, 1);
+ end
+ if ( self.tooltipRequirement ) then
+ GameTooltip:AddLine(self.tooltipRequirement, 1.0, 1.0, 1.0, 1.0);
+ GameTooltip:Show();
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self:IsEnabled() ) then
+ if ( self.tooltipText ) then
+ GameTooltip:SetOwner(self, self.tooltipOwnerPoint or "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltipText, nil, nil, nil, nil, 1);
+ end
+ if ( self.tooltipRequirement ) then
+ GameTooltip:AddLine(self.tooltipRequirement, 1.0, 1.0, 1.0, 1.0);
+ GameTooltip:Show();
+ end
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetBackdropBorderColor(0.4, 0.4, 0.4);
+ self:SetBackdropColor(0.5, 0.5, 0.5);
+
+
+
+
diff --git a/reference/FrameXML/PVPBattlegroundFrame.lua b/reference/FrameXML/PVPBattlegroundFrame.lua
new file mode 100644
index 0000000..093c0d5
--- /dev/null
+++ b/reference/FrameXML/PVPBattlegroundFrame.lua
@@ -0,0 +1 @@
+Interface\AddOns\AIO_Client\AIO.lua:651: Unknown AIO block handle: 'MoonWellClient'
\ No newline at end of file
diff --git a/reference/FrameXML/PVPBattlegroundFrame.xml b/reference/FrameXML/PVPBattlegroundFrame.xml
new file mode 100644
index 0000000..3f50102
--- /dev/null
+++ b/reference/FrameXML/PVPBattlegroundFrame.xml
@@ -0,0 +1,366 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_TOPRIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+ _G[self:GetName().."Highlight"]:SetVertexColor(1.0, 0.82, 0);
+ self.highlight = _G[self:GetName().."Highlight"];
+ self.title = _G[self:GetName().."Text"];
+
+
+ PVPBattlegroundButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT", 5, 40);
+ GameTooltip:SetText(self.tooltip);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, 16, PVPBattleground_UpdateBattlegrounds)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(PVPParentFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self)
+ GameTooltip:SetText(BATTLEFIELD_GROUP_JOIN, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_BATTLEFIELD_GROUP_JOIN, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/PVPFrame.lua b/reference/FrameXML/PVPFrame.lua
new file mode 100644
index 0000000..74deb01
--- /dev/null
+++ b/reference/FrameXML/PVPFrame.lua
@@ -0,0 +1,597 @@
+MAX_ARENA_TEAMS = 3;
+MAX_ARENA_TEAM_MEMBERS = 10;
+MAX_ARENA_TEAM_NAME_WIDTH = 310;
+
+function PVPFrame_OnLoad(self)
+ PVPFrameLine1:SetAlpha(0.3);
+ PVPHonorKillsLabel:SetVertexColor(0.6, 0.6, 0.6);
+ PVPHonorHonorLabel:SetVertexColor(0.6, 0.6, 0.6);
+ PVPHonorTodayLabel:SetVertexColor(0.6, 0.6, 0.6);
+ PVPHonorYesterdayLabel:SetVertexColor(0.6, 0.6, 0.6);
+ PVPHonorLifetimeLabel:SetVertexColor(0.6, 0.6, 0.6);
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("ARENA_TEAM_UPDATE");
+ self:RegisterEvent("ARENA_TEAM_ROSTER_UPDATE");
+ self:RegisterEvent("PLAYER_PVP_KILLS_CHANGED");
+ self:RegisterEvent("PLAYER_PVP_RANK_CHANGED");
+ self:RegisterEvent("HONOR_CURRENCY_UPDATE");
+ --self:RegisterEvent("ARENA_SEASON_WORLD_STATE");
+end
+
+function PVPFrame_OnEvent(self, event, ...)
+ local arg1 = ...;
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ -- PVPFrame.season = GetCurrentArenaSeason();
+ PVPFrame_Update();
+ PVPHonor_Update();
+ elseif ( event == "PLAYER_PVP_KILLS_CHANGED" or event == "PLAYER_PVP_RANK_CHANGED") then
+ PVPHonor_Update();
+ elseif ( event == "ARENA_TEAM_UPDATE" ) then
+ PVPFrame_Update();
+ if ( PVPTeamDetails:IsShown() ) then
+ local team = GetArenaTeam(PVPTeamDetails.team);
+ if ( not team ) then
+ PVPTeamDetails:Hide();
+ else
+ PVPTeamDetails_Update(PVPTeamDetails.team); -- team games played/won are shown in the detail frame
+ end
+ end
+ --[[ elseif ( event == "ARENA_SEASON_WORLD_STATE" ) then
+ PVPFrame.season = GetCurrentArenaSeason();
+ PVPFrame_Update(); ]]
+ elseif ( event == "HONOR_CURRENCY_UPDATE" ) then
+ PVPHonor_Update();
+ elseif ( event == "ARENA_TEAM_ROSTER_UPDATE" ) then
+ if ( arg1 ) then
+ if ( PVPTeamDetails:IsShown() ) then
+ ArenaTeamRoster(PVPTeamDetails.team);
+ end
+ elseif ( PVPTeamDetails.team ) then
+ PVPTeamDetails_Update(PVPTeamDetails.team);
+ PVPFrame_Update();
+ end
+ end
+end
+
+function PVPFrame_OnShow()
+ PVPFrame_SetFaction();
+ PVPFrame_Update();
+ PVPMicroButton_SetPushed();
+ UpdateMicroButtons();
+ SetPortraitTexture(PVPFramePortrait, "player");
+ PlaySound("igCharacterInfoOpen");
+end
+
+function PVPFrame_OnHide()
+ PVPTeamDetails:Hide();
+ PVPFrame_SetJustBG(false);
+ PVPMicroButton_SetNormal();
+ UpdateMicroButtons();
+ PlaySound("igCharacterInfoClose");
+end
+
+function PVPFrame_SetFaction()
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ PVPFrameHonorIcon:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..factionGroup);
+ PVPFrameHonorIcon:Show();
+ end
+end
+
+function PVPFrame_Update()
+ for i=1, MAX_ARENA_TEAMS do
+ GetArenaTeam(i);
+ end
+ PVPHonor_Update();
+ PVPTeam_Update();
+
+ if ( GetCurrentArenaSeason() == 0 ) then --We're in an off-season.
+ PVPFrame_SetToOffSeason();
+ elseif ( PVPFrameOffSeason:IsShown() ) then
+ PVPFrame_SetToInSeason();
+ end
+end
+
+function PVPTeam_Update()
+ -- Display Elements
+ local button, buttonName, highlight, data, standard, emblem, border;
+ -- Data Elements
+ local teamName, teamSize, teamRating, teamPlayed, teamWins, teamLoss, seasonTeamPlayed, seasonTeamWins, playerPlayed, seasonPlayerPlayed, playerPlayedPct, teamRank, playerRating;
+ local played, wins, loss;
+ local background = {};
+ local borderColor = {};
+ local emblemColor = {};
+ local ARENA_TEAMS = {};
+ ARENA_TEAMS[1] = {size = 2};
+ ARENA_TEAMS[2] = {size = 3};
+ ARENA_TEAMS[3] = {size = 5};
+
+ -- Sort teams by size
+
+ local count = 0;
+ local buttonIndex = 0;
+ for index, value in pairs(ARENA_TEAMS) do
+ for i=1, MAX_ARENA_TEAMS do
+ teamName, teamSize = GetArenaTeam(i);
+ if ( value.size == teamSize ) then
+ value.index = i;
+ end
+ end
+ end
+
+ -- fill out data
+ for index, value in pairs(ARENA_TEAMS) do
+ buttonIndex = buttonIndex + 1;
+ button = _G["PVPTeam"..buttonIndex];
+ if ( value.index ) then
+ -- Pull Values
+ teamName, teamSize, teamRating, teamPlayed, teamWins, seasonTeamPlayed, seasonTeamWins, playerPlayed, seasonPlayerPlayed, teamRank, playerRating, background.r, background.g, background.b, emblem, emblemColor.r, emblemColor.g, emblemColor.b, border, borderColor.r, borderColor.g, borderColor.b = GetArenaTeam(value.index);
+
+ -- Set button elements to variables
+ buttonName = "PVPTeam"..buttonIndex;
+ data = buttonName.."Data";
+ standard = buttonName.."Standard";
+
+ button:SetID(value.index);
+
+
+ if ( PVPFrame.seasonStats ) then
+ _G[data.."TypeLabel"]:SetText(ARENA_THIS_SEASON);
+ PVPFrameToggleButton:SetText(ARENA_THIS_WEEK_TOGGLE);
+ played = seasonTeamPlayed;
+ wins = seasonTeamWins;
+ playerPlayed = seasonPlayerPlayed;
+ else
+ _G[data.."TypeLabel"]:SetText(ARENA_THIS_WEEK);
+ PVPFrameToggleButton:SetText(ARENA_THIS_SEASON_TOGGLE);
+ played = teamPlayed;
+ wins = teamWins;
+ playerPlayed = playerPlayed;
+ end
+
+ loss = played - wins;
+ if ( played ~= 0 ) then
+ playerPlayedPct = floor( ( playerPlayed / played ) * 100 );
+ else
+ playerPlayedPct = floor( ( playerPlayed / 1 ) * 100 );
+ end
+
+ -- Populate Data
+ _G[data.."Name"]:SetText(teamName);
+ _G[data.."Rating"]:SetText(teamRating);
+ _G[data.."Games"]:SetText(played);
+ _G[data.."Wins"]:SetText(wins);
+ _G[data.."Loss"]:SetText(loss);
+
+ if ( PVPFrame.seasonStats ) then
+ _G[data.."Played"]:SetText(playerRating);
+ _G[data.."Played"]:SetVertexColor(1.0, 1.0, 1.0);
+ _G[data.."PlayedLabel"]:SetText(PVP_YOUR_RATING);
+ else
+ -- played %
+ if ( playerPlayedPct < 10 ) then
+ _G[data.."Played"]:SetVertexColor(1.0, 0, 0);
+ else
+ _G[data.."Played"]:SetVertexColor(1.0, 1.0, 1.0);
+ end
+ -- FIXME: Turn this into a localized format string
+ playerPlayedPct = format("%d", playerPlayedPct);
+ _G[data.."Played"]:SetText(playerPlayed.." ("..playerPlayedPct.."%)");
+ _G[data.."PlayedLabel"]:SetText(PLAYED);
+ end
+
+
+ -- Set TeamSize Banner
+ _G[standard.."Banner"]:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..teamSize);
+ _G[standard.."Banner"]:SetVertexColor(background.r, background.g, background.b);
+ _G[standard.."Border"]:SetVertexColor(borderColor.r, borderColor.g, borderColor.b);
+ _G[standard.."Emblem"]:SetVertexColor(emblemColor.r, emblemColor.g, emblemColor.b);
+ if ( border ~= -1 ) then
+ _G[standard.."Border"]:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..teamSize.."-Border-"..border);
+ end
+ if ( emblem ~= -1 ) then
+ _G[standard.."Emblem"]:SetTexture("Interface\\PVPFrame\\Icons\\PVP-Banner-Emblem-"..emblem);
+ end
+
+ -- Set visual elements
+ _G[data]:Show();
+ button:SetAlpha(1);
+ _G[buttonName.."Highlight"]:SetAlpha(1);
+ _G[buttonName.."Highlight"]:SetBackdropBorderColor(1.0, 0.82, 0);
+ _G[standard]:SetAlpha(1);
+ _G[standard.."Border"]:Show();
+ _G[standard.."Emblem"]:Show();
+ _G[buttonName.."Background"]:SetVertexColor(0, 0, 0);
+ _G[buttonName.."Background"]:SetAlpha(1);
+ _G[buttonName.."TeamType"]:Hide();
+ else
+ -- Set button elements to variables
+ buttonName = "PVPTeam"..buttonIndex;
+ data = buttonName.."Data";
+
+ button:SetID(0);
+
+ -- Set standard type
+ local standardBanner = _G[buttonName.."StandardBanner"];
+ standardBanner:SetTexture("Interface\\PVPFrame\\PVP-Banner-"..value.size);
+ standardBanner:SetVertexColor(1, 1, 1);
+
+ -- Hide or Show items
+ button:SetAlpha(0.4);
+ _G[data]:Hide();
+ _G[buttonName.."Background"]:SetVertexColor(0, 0, 0);
+ _G[buttonName.."Standard"]:SetAlpha(0.1);
+ _G[buttonName.."StandardBorder"]:Hide();
+ _G[buttonName.."StandardEmblem"]:Hide();
+ _G[buttonName.."TeamType"]:SetFormattedText(PVP_TEAMSIZE, value.size, value.size);
+ _G[buttonName.."TeamType"]:Show(); end
+ count = count +1;
+ end
+ if ( count == 3 ) then
+ PVPFrameToggleButton:Hide();
+ else
+ PVPFrameToggleButton:Show();
+ end
+
+end
+
+function PVPTeam_OnEnter(self)
+ if ( GetArenaTeam(self:GetID() ) ) then
+ _G[self:GetName().."Highlight"]:Show();
+ GameTooltip_AddNewbieTip(self, ARENA_TEAM, 1.0, 1.0, 1.0, CLICK_FOR_DETAILS, 1);
+ else
+ GameTooltip_AddNewbieTip(self, ARENA_TEAM, 1.0, 1.0, 1.0, ARENA_TEAM_LEAD_IN, 1);
+ end
+end
+
+function PVPTeam_OnLeave(self)
+ _G[self:GetName().."Highlight"]:Hide();
+ GameTooltip:Hide();
+end
+
+function PVPTeamDetails_OnShow()
+ PlaySound("igSpellBookOpen");
+end
+
+function PVPTeamDetails_OnHide()
+ CloseArenaTeamRoster();
+ PlaySound("igSpellBookClose");
+end
+
+function PVPTeamDetails_Update(id)
+ local numMembers = GetNumArenaTeamMembers(id, 1);
+ local name, rank, level, class, online, played, win, loss, seasonPlayed, seasonWin, seasonLoss, rating;
+ local teamName, teamSize, teamRating, teamPlayed, teamWins, seasonTeamPlayed, seasonTeamWins, playerPlayed, seasonPlayerPlayed, teamRank, personalRating = GetArenaTeam(id);
+ local button;
+ local teamIndex;
+
+ -- Display General Team Stats
+ PVPTeamDetailsName:SetText(teamName);
+ PVPTeamDetailsSize:SetFormattedText(PVP_TEAMSIZE, teamSize, teamSize);
+ PVPTeamDetailsRank:SetText(teamRank);
+ PVPTeamDetailsRating:SetText(teamRating);
+
+ -- Tidy up team name display if it's too long - mostly for CN
+ PVPTeamDetailsName:SetWidth(0);
+ if ( PVPTeamDetailsName:GetWidth() > MAX_ARENA_TEAM_NAME_WIDTH ) then
+ PVPTeamDetailsName:SetWidth(MAX_ARENA_TEAM_NAME_WIDTH);
+ end
+
+ -- Display General Team Data
+ if ( PVPTeamDetails.season ) then
+ PVPTeamDetailsFrameColumnHeader3.sortType = "seasonplayed";
+ PVPTeamDetailsFrameColumnHeader4.sortType = "seasonwon";
+ PVPTeamDetailsGames:SetText(seasonTeamPlayed);
+ PVPTeamDetailsWins:SetText(seasonTeamWins);
+ PVPTeamDetailsLoss:SetText(seasonTeamPlayed - seasonTeamWins);
+ PVPTeamDetailsStatsType:SetText(strupper(ARENA_THIS_SEASON));
+ PVPTeamDetailsToggleButton:SetText(ARENA_THIS_WEEK_TOGGLE);
+ else
+ PVPTeamDetailsFrameColumnHeader3.sortType = "played";
+ PVPTeamDetailsFrameColumnHeader4.sortType = "won";
+ PVPTeamDetailsGames:SetText(teamPlayed);
+ PVPTeamDetailsWins:SetText(teamWins);
+ PVPTeamDetailsLoss:SetText(teamPlayed - teamWins);
+ PVPTeamDetailsStatsType:SetText(strupper(ARENA_THIS_WEEK));
+ PVPTeamDetailsToggleButton:SetText(ARENA_THIS_SEASON_TOGGLE);
+ end
+
+ local nameText, classText, playedText, winLossWin, winLossLoss, ratingText;
+ local nameButton, classButton, playedButton, winLossButton;
+ -- Display Team Member Specific Info
+ local playedValue, winValue, lossValue, playedPct;
+ for i=1, MAX_ARENA_TEAM_MEMBERS, 1 do
+ button = _G["PVPTeamDetailsButton"..i];
+ if ( i > numMembers ) then
+ button:Hide();
+ else
+
+ button.teamIndex = i;
+ -- Get Data
+ name, rank, level, class, online, played, win, seasonPlayed, seasonWin, rating = GetArenaTeamRosterInfo(id, i);
+ loss = played - win;
+ seasonLoss = seasonPlayed - seasonWin;
+ if ( class ) then
+ button.tooltip = LEVEL.." "..level.." "..class;
+ else
+ button.tooltip = LEVEL.." "..level;
+ end
+
+ -- Populate Data into the display, season or this week
+ if ( PVPTeamDetails.season ) then
+ playedValue = seasonPlayed;
+ winValue = seasonWin;
+ lossValue = seasonLoss;
+ teamPlayed = seasonTeamPlayed;
+ else
+ playedValue = played;
+ winValue = win;
+ lossValue = loss;
+ teamPlayed = teamPlayed;
+ end
+
+ if ( teamPlayed ~= 0 ) then
+ playedPct = floor( ( playedValue / teamPlayed ) * 100 );
+ else
+ playedPct = floor( (playedValue / 1 ) * 100 );
+ end
+
+ if ( playedPct < 10 ) then
+ _G["PVPTeamDetailsButton"..i.."PlayedText"]:SetVertexColor(1.0, 0, 0);
+ else
+ _G["PVPTeamDetailsButton"..i.."PlayedText"]:SetVertexColor(1.0, 1.0, 1.0);
+ end
+
+ playedPct = format("%d", playedPct);
+
+ _G["PVPTeamDetailsButton"..i.."Played"].tooltip = playedPct.."%";
+
+ nameText = _G["PVPTeamDetailsButton"..i.."NameText"];
+ classText = _G["PVPTeamDetailsButton"..i.."ClassText"];
+ playedText = _G["PVPTeamDetailsButton"..i.."PlayedText"]
+ winLossWin = _G["PVPTeamDetailsButton"..i.."WinLossWin"];
+ winLossLoss = _G["PVPTeamDetailsButton"..i.."WinLossLoss"];
+ ratingText = _G["PVPTeamDetailsButton"..i.."RatingText"];
+
+ --- Not needed after Arena Season 3 change.
+ nameButton = _G["PVPTeamDetailsButton"..i.."Name"];
+ classButton = _G["PVPTeamDetailsButton"..i.."Class"];
+ playedButton = _G["PVPTeamDetailsButton"..i.."Played"]
+ winLossButton = _G["PVPTeamDetailsButton"..i.."WinLoss"];
+
+ nameText:SetText(name);
+ classText:SetText(class);
+ playedText:SetText(playedValue);
+ winLossWin:SetText(winValue)
+ winLossLoss:SetText(lossValue);
+ ratingText:SetText(rating);
+
+ -- Color Entries based on Online status
+ local r, g, b;
+ if ( online ) then
+ if ( rank > 0 ) then
+ r = 1.0;
+ g = 1.0;
+ b = 1.0;
+ else
+ r = 1.0;
+ g = 0.82;
+ b = 0.0;
+ end
+ else
+ r = 0.5;
+ g = 0.5;
+ b = 0.5;
+ end
+
+ nameText:SetTextColor(r, g, b);
+ classText:SetTextColor(r, g, b);
+ playedText:SetTextColor(r, g, b);
+ winLossWin:SetTextColor(r, g, b);
+ _G["PVPTeamDetailsButton"..i.."WinLoss-"]:SetTextColor(r, g, b);
+ winLossLoss:SetTextColor(r, g, b);
+ ratingText:SetTextColor(r, g, b);
+
+ button:Show();
+
+ -- Highlight the correct who
+ if ( GetArenaTeamRosterSelection(id) == i ) then
+ button:LockHighlight();
+ else
+ button:UnlockHighlight();
+ end
+ end
+
+ end
+
+
+end
+
+function PVPTeamDetailsToggleButton_OnClick()
+ if ( PVPTeamDetails.season ) then
+ PVPTeamDetails.season = nil;
+ else
+ PVPTeamDetails.season = 1;
+ end
+ PVPTeamDetails_Update(PVPTeamDetails.team);
+end
+
+function PVPFrameToggleButton_OnClick()
+ if ( PVPFrame.seasonStats ) then
+ PVPFrame.seasonStats = nil;
+ else
+ PVPFrame.seasonStats = 1;
+ end
+ PVPTeam_Update();
+end
+
+
+function PVPTeamDetailsButton_OnClick(self, button)
+ if ( button == "LeftButton" ) then
+ PVPTeamDetails.previousSelectedTeamMember = PVPTeamDetails.selectedTeamMember;
+ PVPTeamDetails.selectedTeamMember = self.teamIndex;
+ SetArenaTeamRosterSelection(PVPTeamDetails.team, PVPTeamDetails.selectedTeamMember);
+ PVPTeamDetails_Update(PVPTeamDetails.team);
+ else
+ local name, rank, level, class, online = GetArenaTeamRosterInfo(PVPTeamDetails.team, self.teamIndex);
+ PVPFrame_ShowDropdown(name, online);
+ end
+end
+
+function PVPDropDown_Initialize()
+ UnitPopup_ShowMenu(UIDROPDOWNMENU_OPEN_MENU, "TEAM", nil, PVPDropDown.name);
+end
+
+function PVPFrame_ShowDropdown(name, online)
+ HideDropDownMenu(1);
+
+ if ( not IsArenaTeamCaptain(PVPTeamDetails.team) ) then
+ if ( online ) then
+ PVPDropDown.initialize = PVPDropDown_Initialize;
+ PVPDropDown.displayMode = "MENU";
+ PVPDropDown.name = name;
+ PVPDropDown.online = online;
+ ToggleDropDownMenu(1, nil, PVPDropDown, "cursor");
+ end
+ else
+ PVPDropDown.initialize = PVPDropDown_Initialize;
+ PVPDropDown.displayMode = "MENU";
+ PVPDropDown.name = name;
+ PVPDropDown.online = online;
+ ToggleDropDownMenu(1, nil, PVPDropDown, "cursor");
+ end
+end
+
+function PVPStandard_OnLoad(self)
+ self:SetAlpha(0.1);
+end
+
+function PVPTeam_OnClick(self)
+ local id = self:GetID();
+
+ local teamName, teamSize = GetArenaTeam(id);
+ if ( not teamName ) then
+ return;
+ else
+ if ( PVPTeamDetails:IsShown() and id == PVPTeamDetails.team ) then
+ PVPTeamDetails:Hide();
+ else
+ PVPTeamDetails.team = id;
+ ArenaTeamRoster(id);
+ PVPTeamDetails_Update(id);
+ PVPTeamDetails:Show();
+ end
+ end
+end
+
+function PVPTeam_OnMouseDown(self)
+ if ( GetArenaTeam(self:GetID()) and (not self.isDown) ) then
+ self.isDown = true;
+ local point, relativeTo, relativePoint, offsetX, offsetY = self:GetPoint();
+ self:SetPoint(point, relativeTo, relativePoint, offsetX-2, offsetY-2);
+ end
+end
+function PVPTeam_OnMouseUp(self)
+ --Note that this function is also called OnShow. Make sure it always checks if it was previously down.
+ if ( GetArenaTeam(self:GetID()) and (self.isDown) ) then
+ self.isDown = false;
+ local point, relativeTo, relativePoint, offsetX, offsetY = self:GetPoint();
+ self:SetPoint(point, relativeTo, relativePoint, offsetX+2, offsetY+2);
+ end
+end
+
+-- PVP Honor Data
+function PVPHonor_Update()
+ local hk, cp, dk, contribution, rank, highestRank, rankName, rankNumber;
+
+ -- Yesterday's values
+ hk, contribution = GetPVPYesterdayStats();
+ PVPHonorYesterdayKills:SetText(hk);
+ PVPHonorYesterdayHonor:SetText(contribution);
+
+ -- Lifetime values
+ hk, contribution = GetPVPLifetimeStats();
+ PVPHonorLifetimeKills:SetText(hk);
+ PVPFrameHonorPoints:SetText(GetHonorCurrency());
+ PVPFrameArenaPoints:SetText(GetArenaCurrency())
+
+ -- Today's values
+ hk, cp = GetPVPSessionStats();
+ PVPHonorTodayKills:SetText(hk);
+ PVPHonorTodayHonor:SetText(cp);
+ PVPHonorTodayHonor:SetHeight(14);
+end
+
+function PVPMicroButton_SetPushed()
+ PVPMicroButtonTexture:SetPoint("TOP", PVPMicroButton, "TOP", 5, -31);
+ PVPMicroButtonTexture:SetAlpha(0.5);
+end
+
+function PVPMicroButton_SetNormal()
+ PVPMicroButtonTexture:SetPoint("TOP", PVPMicroButton, "TOP", 6, -30);
+ PVPMicroButtonTexture:SetAlpha(1.0);
+end
+
+function PVPFrame_SetToOffSeason()
+ PVPTeam1:Hide();
+ PVPTeam1Standard:Hide();
+ PVPTeam2:Hide();
+ PVPTeam2Standard:Hide();
+ PVPTeam3:Hide();
+ PVPTeam3Standard:Hide();
+
+ PVPFrameBlackFilter:Show();
+
+ PVPFrameOffSeason:Show();
+
+ local previousArenaSeason = GetPreviousArenaSeason();
+ PVPFrameOffSeasonText:SetText(format(ARENA_OFF_SEASON_TEXT, previousArenaSeason, previousArenaSeason+1));
+end
+
+function PVPFrame_SetToInSeason()
+ PVPTeam1:Show();
+ PVPTeam1Standard:Show();
+ PVPTeam2:Show();
+ PVPTeam2Standard:Show();
+ PVPTeam3:Show();
+ PVPTeam3Standard:Show();
+
+ PVPFrameBlackFilter:Hide();
+
+ PVPFrameOffSeason:Hide();
+end
+
+function TogglePVPFrame()
+ if ( PVPFrame_IsJustBG() ) then
+ PVPFrame_SetJustBG(false);
+ else
+ if ( UnitLevel("player") >= SHOW_PVP_LEVEL ) then
+ ToggleFrame(PVPParentFrame);
+ end
+ end
+end
+
+function PVPFrame_IsJustBG()
+ return PVPParentFrame.justBG;
+end
+
+function PVPFrame_SetJustBG(justBG)
+ local pvpParentFrame = PVPParentFrame;
+ if ( justBG ) then
+ pvpParentFrame.justBG = true;
+ pvpParentFrame.savedSelectedTab = PanelTemplates_GetSelectedTab(pvpParentFrame);
+ PVPParentFrameTab2:Click();
+ PVPParentFrameTab1:Hide();
+ PVPParentFrameTab2:Hide();
+ UpdateMicroButtons();
+ else
+ pvpParentFrame.justBG = false;
+ if ( pvpParentFrame.savedSelectedTab ) then
+ _G["PVPParentFrameTab"..pvpParentFrame.savedSelectedTab]:Click();
+ pvpParentFrame.savedSelectedTab = nil;
+ end
+ CloseBattlefield();
+ PVPBattlegroundFrame_UpdateVisible();
+ UpdateMicroButtons();
+ end
+end
diff --git a/reference/FrameXML/PVPFrame.xml b/reference/FrameXML/PVPFrame.xml
new file mode 100644
index 0000000..d682dbf
--- /dev/null
+++ b/reference/FrameXML/PVPFrame.xml
@@ -0,0 +1,1053 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 4);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ GameTooltip:SetText(HONOR_POINTS, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(TOOLTIP_HONOR_POINTS, nil, nil, nil, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ GameTooltip:SetText(ARENA_POINTS, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(TOOLTIP_ARENA_POINTS, nil, nil, nil, 1);
+ GameTooltip:Show();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPFrameToggleButton_OnClick();
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 110);
+ self.sortType = "name";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 80);
+ self.sortType = "class";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 55);
+ self.sortType = "played";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 75);
+ self:GetFontString():SetWidth(75); --Deal with a problem of size in Russian client
+ self.sortType = "won";
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WhoFrameColumn_SetWidth(self, 59);
+ self.sortType = "rating";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("ADD_TEAMMEMBER");
+
+
+ GameTooltip_AddNewbieTip(self, ADDMEMBER, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_ADDTEAMMEMBER, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPTeamDetailsToggleButton_OnClick();
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(PLAYER_V_PLAYER, 1.0,1.0,1.0 );
+
+
+ PVPFrame:Show();
+ PVPBattlegroundFrame:Hide();
+ PanelTemplates_Tab_OnClick(self, PVPParentFrame);
+ PlaySound("igCharacterInfoTab");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(BATTLEFIELDS, 1.0,1.0,1.0 );
+
+
+ PVPFrame:Hide();
+ PVPBattlegroundFrame:Show();
+ PanelTemplates_Tab_OnClick(self, PVPParentFrame);
+ PlaySound("igCharacterInfoTab");
+ PVPBattlegroundFrameGroupJoinButton:SetFrameLevel(self:GetFrameLevel() + 1);
+
+
+
+
+
+
+
+
+
+ PanelTemplates_SetNumTabs(self, 2)
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/PVPFrameTemplates.xml b/reference/FrameXML/PVPFrameTemplates.xml
new file mode 100644
index 0000000..e322382
--- /dev/null
+++ b/reference/FrameXML/PVPFrameTemplates.xml
@@ -0,0 +1,578 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PVPStandard_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetAlpha(0.4);
+
+
+ PVPTeam_OnEnter(self, motion);
+
+
+ PVPTeam_OnLeave(self, motion);
+
+
+ PVPTeam_OnClick(self, button, down);
+
+
+ PVPTeam_OnMouseDown(self, button);
+
+
+ PVPTeam_OnMouseUp(self, button);
+
+
+ PVPTeam_OnMouseUp(self, nil);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:GetParent():LockHighlight();
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self.tooltip ) then
+ GameTooltip:SetText(self.tooltip);
+ end
+
+
+ self:GetParent():UnlockHighlight();
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+
+
+ PVPTeamDetailsButton_OnClick(self, button);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self.sortType ) then
+ SortArenaTeamRoster(self.sortType);
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/PaperDollFrame.lua b/reference/FrameXML/PaperDollFrame.lua
new file mode 100644
index 0000000..7937f4f
--- /dev/null
+++ b/reference/FrameXML/PaperDollFrame.lua
@@ -0,0 +1,2691 @@
+EQUIPPED_FIRST = 1;
+EQUIPPED_LAST = 19;
+
+NUM_RESISTANCE_TYPES = 5;
+NUM_STATS = 5;
+NUM_SHOPPING_TOOLTIPS = 2;
+MAX_SPELL_SCHOOLS = 7;
+
+CR_WEAPON_SKILL = 1;
+CR_DEFENSE_SKILL = 2;
+CR_DODGE = 3;
+CR_PARRY = 4;
+CR_BLOCK = 5;
+CR_HIT_MELEE = 6;
+CR_HIT_RANGED = 7;
+CR_HIT_SPELL = 8;
+CR_CRIT_MELEE = 9;
+CR_CRIT_RANGED = 10;
+CR_CRIT_SPELL = 11;
+CR_HIT_TAKEN_MELEE = 12;
+CR_HIT_TAKEN_RANGED = 13;
+CR_HIT_TAKEN_SPELL = 14;
+CR_CRIT_TAKEN_MELEE = 15;
+CR_CRIT_TAKEN_RANGED = 16;
+CR_CRIT_TAKEN_SPELL = 17;
+CR_HASTE_MELEE = 18;
+CR_HASTE_RANGED = 19;
+CR_HASTE_SPELL = 20;
+CR_WEAPON_SKILL_MAINHAND = 21;
+CR_WEAPON_SKILL_OFFHAND = 22;
+CR_WEAPON_SKILL_RANGED = 23;
+CR_EXPERTISE = 24;
+CR_ARMOR_PENETRATION = 25;
+
+ATTACK_POWER_MAGIC_NUMBER = 14;
+BLOCK_PER_STRENGTH = 0.5;
+HEALTH_PER_STAMINA = 10;
+ARMOR_PER_AGILITY = 2;
+MANA_PER_INTELLECT = 15;
+MANA_REGEN_PER_SPIRIT = 0.2;
+DODGE_PARRY_BLOCK_PERCENT_PER_DEFENSE = 0.04;
+RESILIENCE_CRIT_CHANCE_TO_DAMAGE_REDUCTION_MULTIPLIER = 2.2;
+RESILIENCE_CRIT_CHANCE_TO_CONSTANT_DAMAGE_REDUCTION_MULTIPLIER = 2.0;
+
+--Pet scaling:
+HUNTER_PET_BONUS = {};
+HUNTER_PET_BONUS["PET_BONUS_RAP_TO_AP"] = 0.22;
+HUNTER_PET_BONUS["PET_BONUS_RAP_TO_SPELLDMG"] = 0.1287;
+HUNTER_PET_BONUS["PET_BONUS_STAM"] = 0.3;
+HUNTER_PET_BONUS["PET_BONUS_RES"] = 0.4;
+HUNTER_PET_BONUS["PET_BONUS_ARMOR"] = 0.35;
+HUNTER_PET_BONUS["PET_BONUS_SPELLDMG_TO_SPELLDMG"] = 0.0;
+HUNTER_PET_BONUS["PET_BONUS_SPELLDMG_TO_AP"] = 0.0;
+HUNTER_PET_BONUS["PET_BONUS_INT"] = 0.0;
+
+WARLOCK_PET_BONUS = {};
+WARLOCK_PET_BONUS["PET_BONUS_RAP_TO_AP"] = 0.0;
+WARLOCK_PET_BONUS["PET_BONUS_RAP_TO_SPELLDMG"] = 0.0;
+WARLOCK_PET_BONUS["PET_BONUS_STAM"] = 0.3;
+WARLOCK_PET_BONUS["PET_BONUS_RES"] = 0.4;
+WARLOCK_PET_BONUS["PET_BONUS_ARMOR"] = 0.35;
+WARLOCK_PET_BONUS["PET_BONUS_SPELLDMG_TO_SPELLDMG"] = 0.15;
+WARLOCK_PET_BONUS["PET_BONUS_SPELLDMG_TO_AP"] = 0.57;
+WARLOCK_PET_BONUS["PET_BONUS_INT"] = 0.3;
+
+PLAYERSTAT_DROPDOWN_OPTIONS = {
+ "PLAYERSTAT_BASE_STATS",
+ "PLAYERSTAT_MELEE_COMBAT",
+ "PLAYERSTAT_RANGED_COMBAT",
+ "PLAYERSTAT_SPELL_COMBAT",
+ "PLAYERSTAT_DEFENSES",
+};
+
+PDFITEMFLYOUT_MAXITEMS = 23;
+
+PDFITEMFLYOUT_ONESLOT_LEFT_COORDS = { 0, 0.09765625, 0.5546875, 0.77734375 }
+PDFITEMFLYOUT_ONESLOT_RIGHT_COORDS = { 0.41796875, 0.51171875, 0.5546875, 0.77734375 }
+
+PDFITEMFLYOUT_ONESLOT_LEFTWIDTH = 25;
+PDFITEMFLYOUT_ONESLOT_RIGHTWIDTH = 24;
+
+PDFITEMFLYOUT_ONESLOT_WIDTH = 49;
+PDFITEMFLYOUT_ONESLOT_HEIGHT = 54;
+
+PDFITEMFLYOUT_ONEROW_LEFT_COORDS = { 0, 0.16796875, 0.5546875, 0.77734375 }
+PDFITEMFLYOUT_ONEROW_CENTER_COORDS = { 0.16796875, 0.328125, 0.5546875, 0.77734375 }
+PDFITEMFLYOUT_ONEROW_RIGHT_COORDS = { 0.328125, 0.51171875, 0.5546875, 0.77734375 }
+
+PDFITEMFLYOUT_MULTIROW_TOP_COORDS = { 0, 0.8359375, 0, 0.19140625 }
+PDFITEMFLYOUT_MULTIROW_MIDDLE_COORDS = { 0, 0.8359375, 0.19140625, 0.35546875 }
+PDFITEMFLYOUT_MULTIROW_BOTTOM_COORDS = { 0, 0.8359375, 0.35546875, 0.546875 }
+
+PDFITEMFLYOUT_ONEROW_HEIGHT = 54;
+
+PDFITEMFLYOUT_ONEROW_LEFT_WIDTH = 43;
+PDFITEMFLYOUT_ONEROW_CENTER_WIDTH = 41;
+PDFITEMFLYOUT_ONEROW_RIGHT_WIDTH = 47;
+
+PDFITEMFLYOUT_MULTIROW_WIDTH = 214;
+
+PDFITEMFLYOUT_MULTIROW_TOP_HEIGHT = 49;
+PDFITEMFLYOUT_MULTIROW_MIDDLE_HEIGHT = 42;
+PDFITEMFLYOUT_MULTIROW_BOTTOM_HEIGHT = 49;
+
+PDFITEMFLYOUT_PLACEINBAGS_LOCATION = 0xFFFFFFFF;
+PDFITEMFLYOUT_IGNORESLOT_LOCATION = 0xFFFFFFFE;
+PDFITEMFLYOUT_UNIGNORESLOT_LOCATION = 0xFFFFFFFD;
+PDFITEMFLYOUT_FIRST_SPECIAL_LOCATION = PDFITEMFLYOUT_UNIGNORESLOT_LOCATION
+
+PLAYER_DISPLAYED_TITLES = 6;
+PLAYER_TITLE_HEIGHT = 16;
+
+local VERTICAL_FLYOUTS = { [16] = true, [17] = true, [18] = true }
+
+local itemSlotButtons = {};
+
+function PaperDollFrame_OnLoad (self)
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("CHARACTER_POINTS_CHANGED");
+ self:RegisterEvent("UNIT_MODEL_CHANGED");
+ self:RegisterEvent("UNIT_LEVEL");
+ self:RegisterEvent("UNIT_RESISTANCES");
+ self:RegisterEvent("UNIT_STATS");
+ self:RegisterEvent("UNIT_DAMAGE");
+ self:RegisterEvent("UNIT_RANGEDDAMAGE");
+ self:RegisterEvent("PLAYER_DAMAGE_DONE_MODS");
+ self:RegisterEvent("UNIT_ATTACK_SPEED");
+ self:RegisterEvent("UNIT_ATTACK_POWER");
+ self:RegisterEvent("UNIT_RANGED_ATTACK_POWER");
+ self:RegisterEvent("UNIT_ATTACK");
+ self:RegisterEvent("PLAYER_GUILD_UPDATE");
+ self:RegisterEvent("SKILL_LINES_CHANGED");
+ self:RegisterEvent("VARIABLES_LOADED");
+ self:RegisterEvent("COMBAT_RATING_UPDATE");
+ self:RegisterEvent("KNOWN_TITLES_UPDATE");
+ self:RegisterEvent("UNIT_NAME_UPDATE");
+end
+
+function PaperDoll_IsEquippedSlot (slot)
+ if ( slot ) then
+ slot = tonumber(slot);
+ if ( slot ) then
+ return slot >= EQUIPPED_FIRST and slot <= EQUIPPED_LAST;
+ end
+ end
+ return false;
+end
+
+function CharacterModelFrame_OnMouseUp (self, button)
+ if ( button == "LeftButton" ) then
+ AutoEquipCursorItem();
+ end
+end
+
+function PaperDollFrame_OnEvent (self, event, ...)
+ local unit = ...;
+ if ( event == "PLAYER_ENTERING_WORLD" or
+ event == "UNIT_MODEL_CHANGED" and unit == "player" ) then
+ CharacterModelFrame:SetUnit("player");
+ return;
+ elseif ( event == "VARIABLES_LOADED" ) then
+ -- Set defaults if no settings for the dropdowns
+ if ( GetCVar("playerStatLeftDropdown") == "" or GetCVar("playerStatRightDropdown") == "" ) then
+ local temp, classFileName = UnitClass("player");
+ classFileName = strupper(classFileName);
+ SetCVar("playerStatLeftDropdown", "PLAYERSTAT_BASE_STATS");
+ if ( classFileName == "MAGE" or classFileName == "PRIEST" or classFileName == "WARLOCK" or classFileName == "DRUID" ) then
+ SetCVar("playerStatRightDropdown", "PLAYERSTAT_SPELL_COMBAT");
+ elseif ( classFileName == "HUNTER" ) then
+ SetCVar("playerStatRightDropdown", "PLAYERSTAT_RANGED_COMBAT");
+ else
+ SetCVar("playerStatRightDropdown", "PLAYERSTAT_MELEE_COMBAT");
+ end
+ end
+ PaperDollFrame_UpdateStats(self);
+ elseif ( event == "KNOWN_TITLES_UPDATE" or (event == "UNIT_NAME_UPDATE" and unit == "player")) then
+ PlayerTitleFrame_UpdateTitles();
+ end
+
+ if ( not self:IsVisible() ) then
+ return;
+ end
+
+ if ( unit == "player" ) then
+ if ( event == "UNIT_LEVEL" ) then
+ PaperDollFrame_SetLevel();
+ elseif ( event == "UNIT_DAMAGE" or event == "PLAYER_DAMAGE_DONE_MODS" or event == "UNIT_ATTACK_SPEED" or event == "UNIT_RANGEDDAMAGE" or event == "UNIT_ATTACK" or event == "UNIT_STATS" or event == "UNIT_RANGED_ATTACK_POWER" ) then
+ PaperDollFrame_UpdateStats();
+ elseif ( event == "UNIT_RESISTANCES" ) then
+ PaperDollFrame_SetResistances();
+ PaperDollFrame_UpdateStats();
+ elseif ( event == "UNIT_RANGED_ATTACK_POWER" ) then
+ PaperDollFrame_SetRangedAttack();
+ end
+ end
+
+ if ( event == "COMBAT_RATING_UPDATE" ) then
+ PaperDollFrame_UpdateStats();
+ end
+end
+
+function PaperDollFrame_SetLevel()
+ CharacterLevelText:SetFormattedText(PLAYER_LEVEL, UnitLevel("player"), UnitRace("player"), UnitClass("player"));
+ -- Set it for the honor frame while we at it
+ HonorLevelText:SetFormattedText(PLAYER_LEVEL, UnitLevel("player"), UnitRace("player"), UnitClass("player"));
+end
+
+function PaperDollFrame_SetGuild()
+ local guildName;
+ local title;
+ local rank;
+ guildName, title, rank = GetGuildInfo("player");
+ if ( guildName ) then
+ CharacterGuildText:Show();
+ CharacterGuildText:SetFormattedText(GUILD_TITLE_TEMPLATE, title, guildName);
+ -- Set it for the honor frame while we're at it
+ HonorGuildText:Show();
+ HonorGuildText:SetFormattedText(GUILD_TITLE_TEMPLATE, title, guildName);
+ else
+ CharacterGuildText:Hide();
+
+ HonorGuildText:Hide();
+ end
+end
+
+function PaperDollFrame_SetStat(statFrame, statIndex)
+ local label = _G[statFrame:GetName().."Label"];
+ local text = _G[statFrame:GetName().."StatText"];
+ local stat;
+ local effectiveStat;
+ local posBuff;
+ local negBuff;
+ stat, effectiveStat, posBuff, negBuff = UnitStat("player", statIndex);
+ local statName = _G["SPELL_STAT"..statIndex.."_NAME"];
+ label:SetText(format(STAT_FORMAT, statName));
+
+ -- Set the tooltip text
+ local tooltipText = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, statName).." ";
+
+ if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
+ text:SetText(effectiveStat);
+ statFrame.tooltip = tooltipText..effectiveStat..FONT_COLOR_CODE_CLOSE;
+ else
+ tooltipText = tooltipText..effectiveStat;
+ if ( posBuff > 0 or negBuff < 0 ) then
+ tooltipText = tooltipText.." ("..(stat - posBuff - negBuff)..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( posBuff > 0 ) then
+ tooltipText = tooltipText..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( negBuff < 0 ) then
+ tooltipText = tooltipText..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( posBuff > 0 or negBuff < 0 ) then
+ tooltipText = tooltipText..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE;
+ end
+ statFrame.tooltip = tooltipText;
+
+ -- If there are any negative buffs then show the main number in red even if there are
+ -- positive buffs. Otherwise show in green.
+ if ( negBuff < 0 ) then
+ text:SetText(RED_FONT_COLOR_CODE..effectiveStat..FONT_COLOR_CODE_CLOSE);
+ else
+ text:SetText(GREEN_FONT_COLOR_CODE..effectiveStat..FONT_COLOR_CODE_CLOSE);
+ end
+ end
+ statFrame.tooltip2 = _G["DEFAULT_STAT"..statIndex.."_TOOLTIP"];
+ local _, unitClass = UnitClass("player");
+ unitClass = strupper(unitClass);
+
+ if ( statIndex == 1 ) then
+ local attackPower = GetAttackPowerForStat(statIndex,effectiveStat);
+ statFrame.tooltip2 = format(statFrame.tooltip2, attackPower);
+ if ( unitClass == "WARRIOR" or unitClass == "SHAMAN" or unitClass == "PALADIN" ) then
+ statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format( STAT_BLOCK_TOOLTIP, max(0, effectiveStat*BLOCK_PER_STRENGTH-10) );
+ end
+ elseif ( statIndex == 3 ) then
+ local baseStam = min(20, effectiveStat);
+ local moreStam = effectiveStat - baseStam;
+ statFrame.tooltip2 = format(statFrame.tooltip2, (baseStam + (moreStam*HEALTH_PER_STAMINA))*GetUnitMaxHealthModifier("player"));
+ local petStam = ComputePetBonus("PET_BONUS_STAM", effectiveStat );
+ if( petStam > 0 ) then
+ statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_STAMINA,petStam);
+ end
+ elseif ( statIndex == 2 ) then
+ local attackPower = GetAttackPowerForStat(statIndex,effectiveStat);
+ if ( attackPower > 0 ) then
+ statFrame.tooltip2 = format(STAT_ATTACK_POWER, attackPower) .. format(statFrame.tooltip2, GetCritChanceFromAgility("player"), effectiveStat*ARMOR_PER_AGILITY);
+ else
+ statFrame.tooltip2 = format(statFrame.tooltip2, GetCritChanceFromAgility("player"), effectiveStat*ARMOR_PER_AGILITY);
+ end
+ elseif ( statIndex == 4 ) then
+ local baseInt = min(20, effectiveStat);
+ local moreInt = effectiveStat - baseInt
+ if ( UnitHasMana("player") ) then
+ statFrame.tooltip2 = format(statFrame.tooltip2, baseInt + moreInt*MANA_PER_INTELLECT, GetSpellCritChanceFromIntellect("player"));
+ else
+ statFrame.tooltip2 = nil;
+ end
+ local petInt = ComputePetBonus("PET_BONUS_INT", effectiveStat );
+ if( petInt > 0 ) then
+ if ( not statFrame.tooltip2 ) then
+ statFrame.tooltip2 = "";
+ end
+ statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_INTELLECT,petInt);
+ end
+ elseif ( statIndex == 5 ) then
+ -- All mana regen stats are displayed as mana/5 sec.
+ statFrame.tooltip2 = format(statFrame.tooltip2, GetUnitHealthRegenRateFromSpirit("player"));
+ if ( UnitHasMana("player") ) then
+ local regen = GetUnitManaRegenRateFromSpirit("player");
+ regen = floor( regen * 5.0 );
+ statFrame.tooltip2 = statFrame.tooltip2.."\n"..format(MANA_REGEN_FROM_SPIRIT, regen);
+ end
+ end
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetRating(statFrame, ratingIndex)
+ local label = _G[statFrame:GetName().."Label"];
+ local text = _G[statFrame:GetName().."StatText"];
+ local statName = _G["COMBAT_RATING_NAME"..ratingIndex];
+ label:SetText(format(STAT_FORMAT, statName));
+ local rating = GetCombatRating(ratingIndex);
+ local ratingBonus = GetCombatRatingBonus(ratingIndex);
+ text:SetText(rating);
+
+ -- Set the tooltip text
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, statName).." "..rating..FONT_COLOR_CODE_CLOSE;
+ -- Can probably axe this if else tree if all rating tooltips follow the same format
+ if ( ratingIndex == CR_HIT_MELEE ) then
+ statFrame.tooltip2 = format(CR_HIT_MELEE_TOOLTIP, UnitLevel("player"), ratingBonus, GetCombatRating(CR_ARMOR_PENETRATION), GetArmorPenetration());
+ elseif ( ratingIndex == CR_HIT_RANGED ) then
+ statFrame.tooltip2 = format(CR_HIT_RANGED_TOOLTIP, UnitLevel("player"), ratingBonus, GetCombatRating(CR_ARMOR_PENETRATION), GetArmorPenetration());
+ elseif ( ratingIndex == CR_DODGE ) then
+ statFrame.tooltip2 = format(CR_DODGE_TOOLTIP, ratingBonus);
+ elseif ( ratingIndex == CR_PARRY ) then
+ statFrame.tooltip2 = format(CR_PARRY_TOOLTIP, ratingBonus);
+ elseif ( ratingIndex == CR_BLOCK ) then
+ statFrame.tooltip2 = format(CR_PARRY_TOOLTIP, ratingBonus);
+ elseif ( ratingIndex == CR_HIT_SPELL ) then
+ local spellPenetration = GetSpellPenetration();
+ statFrame.tooltip2 = format(CR_HIT_SPELL_TOOLTIP, UnitLevel("player"), ratingBonus, spellPenetration, spellPenetration);
+ elseif ( ratingIndex == CR_CRIT_SPELL ) then
+ local holySchool = 2;
+ local minCrit = GetSpellCritChance(holySchool);
+ statFrame.spellCrit = {};
+ statFrame.spellCrit[holySchool] = minCrit;
+ local spellCrit;
+ for i=(holySchool+1), MAX_SPELL_SCHOOLS do
+ spellCrit = GetSpellCritChance(i);
+ minCrit = min(minCrit, spellCrit);
+ statFrame.spellCrit[i] = spellCrit;
+ end
+ minCrit = format("%.2f%%", minCrit);
+ statFrame.minCrit = minCrit;
+ elseif ( ratingIndex == CR_EXPERTISE ) then
+ statFrame.tooltip2 = format(CR_EXPERTISE_TOOLTIP, ratingBonus);
+ else
+ statFrame.tooltip2 = HIGHLIGHT_FONT_COLOR_CODE.._G["COMBAT_RATING_NAME"..ratingIndex].." "..rating;
+ end
+
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetResistances()
+ for i=1, NUM_RESISTANCE_TYPES, 1 do
+ local resistance;
+ local positive;
+ local negative;
+ local resistanceLevel
+ local base;
+ local text = _G["MagicResText"..i];
+ local frame = _G["MagicResFrame"..i];
+
+ base, resistance, positive, negative = UnitResistance("player", frame:GetID());
+ local petBonus = ComputePetBonus( "PET_BONUS_RES", resistance );
+
+ local resistanceName = _G["RESISTANCE"..(frame:GetID()).."_NAME"];
+ frame.tooltip = format(PAPERDOLLFRAME_TOOLTIP_FORMAT, resistanceName).." "..resistance;
+
+ -- resistances can now be negative. Show Red if negative, Green if positive, white otherwise
+ if( abs(negative) > positive ) then
+ text:SetText(RED_FONT_COLOR_CODE..resistance..FONT_COLOR_CODE_CLOSE);
+ elseif( abs(negative) == positive ) then
+ text:SetText(resistance);
+ else
+ text:SetText(GREEN_FONT_COLOR_CODE..resistance..FONT_COLOR_CODE_CLOSE);
+ end
+
+ if ( positive ~= 0 or negative ~= 0 ) then
+ -- Otherwise build up the formula
+ frame.tooltip = frame.tooltip.. " ( "..HIGHLIGHT_FONT_COLOR_CODE..base;
+ if( positive > 0 ) then
+ frame.tooltip = frame.tooltip..GREEN_FONT_COLOR_CODE.." +"..positive;
+ end
+ if( negative < 0 ) then
+ frame.tooltip = frame.tooltip.." "..RED_FONT_COLOR_CODE..negative;
+ end
+ frame.tooltip = frame.tooltip..FONT_COLOR_CODE_CLOSE.." )";
+ end
+ local unitLevel = UnitLevel("player");
+ unitLevel = max(unitLevel, 20);
+ local magicResistanceNumber = resistance/unitLevel;
+ if ( magicResistanceNumber > 5 ) then
+ resistanceLevel = RESISTANCE_EXCELLENT;
+ elseif ( magicResistanceNumber > 3.75 ) then
+ resistanceLevel = RESISTANCE_VERYGOOD;
+ elseif ( magicResistanceNumber > 2.5 ) then
+ resistanceLevel = RESISTANCE_GOOD;
+ elseif ( magicResistanceNumber > 1.25 ) then
+ resistanceLevel = RESISTANCE_FAIR;
+ elseif ( magicResistanceNumber > 0 ) then
+ resistanceLevel = RESISTANCE_POOR;
+ else
+ resistanceLevel = RESISTANCE_NONE;
+ end
+ frame.tooltipSubtext = format(RESISTANCE_TOOLTIP_SUBTEXT, _G["RESISTANCE_TYPE"..frame:GetID()], unitLevel, resistanceLevel);
+
+ if( petBonus > 0 ) then
+ frame.tooltipSubtext = frame.tooltipSubtext .. "\n" .. format(PET_BONUS_TOOLTIP_RESISTANCE, petBonus);
+ end
+ end
+end
+
+function PaperDollFrame_SetArmor(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ end
+ local base, effectiveArmor, armor, posBuff, negBuff = UnitArmor(unit);
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, ARMOR));
+ local text = _G[statFrame:GetName().."StatText"];
+
+ PaperDollFormatStat(ARMOR, base, posBuff, negBuff, statFrame, text);
+ local armorReduction = PaperDollFrame_GetArmorReduction(effectiveArmor, UnitLevel(unit));
+ statFrame.tooltip2 = format(DEFAULT_STATARMOR_TOOLTIP, armorReduction);
+
+ if ( unit == "player" ) then
+ local petBonus = ComputePetBonus("PET_BONUS_ARMOR", effectiveArmor );
+ if( petBonus > 0 ) then
+ statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_ARMOR, petBonus);
+ end
+ end
+
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetDefense(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ end
+ local base, modifier = UnitDefense(unit);
+ local posBuff = 0;
+ local negBuff = 0;
+ if ( modifier > 0 ) then
+ posBuff = modifier;
+ elseif ( modifier < 0 ) then
+ negBuff = modifier;
+ end
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, DEFENSE));
+ local text = _G[statFrame:GetName().."StatText"];
+
+ PaperDollFormatStat(DEFENSE, base, posBuff, negBuff, statFrame, text);
+ local defensePercent = GetDodgeBlockParryChanceFromDefense();
+ statFrame.tooltip2 = format(DEFAULT_STATDEFENSE_TOOLTIP, GetCombatRating(CR_DEFENSE_SKILL), GetCombatRatingBonus(CR_DEFENSE_SKILL), defensePercent, defensePercent);
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetDodge(statFrame)
+ local chance = GetDodgeChance();
+ PaperDollFrame_SetLabelAndText(statFrame, STAT_DODGE, chance, 1);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, DODGE_CHANCE).." "..string.format("%.02f", chance).."%"..FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = format(CR_DODGE_TOOLTIP, GetCombatRating(CR_DODGE), GetCombatRatingBonus(CR_DODGE));
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetBlock(statFrame)
+ local chance = GetBlockChance();
+ PaperDollFrame_SetLabelAndText(statFrame, STAT_BLOCK, chance, 1);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, BLOCK_CHANCE).." "..string.format("%.02f", chance).."%"..FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = format(CR_BLOCK_TOOLTIP, GetCombatRating(CR_BLOCK), GetCombatRatingBonus(CR_BLOCK), GetShieldBlock());
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetParry(statFrame)
+ local chance = GetParryChance();
+ PaperDollFrame_SetLabelAndText(statFrame, STAT_PARRY, chance, 1);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, PARRY_CHANCE).." "..string.format("%.02f", chance).."%"..FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = format(CR_PARRY_TOOLTIP, GetCombatRating(CR_PARRY), GetCombatRatingBonus(CR_PARRY));
+ statFrame:Show();
+end
+
+function GetDodgeBlockParryChanceFromDefense()
+ local base, modifier = UnitDefense("player");
+ --local defensePercent = DODGE_PARRY_BLOCK_PERCENT_PER_DEFENSE * modifier;
+ local defensePercent = DODGE_PARRY_BLOCK_PERCENT_PER_DEFENSE * ((base + modifier) - (UnitLevel("player")*5));
+ defensePercent = max(defensePercent, 0);
+ return defensePercent;
+end
+
+function PaperDollFrame_SetResilience(statFrame)
+ local melee = GetCombatRating(CR_CRIT_TAKEN_MELEE);
+ local ranged = GetCombatRating(CR_CRIT_TAKEN_RANGED);
+ local spell = GetCombatRating(CR_CRIT_TAKEN_SPELL);
+
+ local minResilience = min(melee, ranged);
+ minResilience = min(minResilience, spell);
+
+ local lowestRating = CR_CRIT_TAKEN_MELEE;
+ if ( melee == minResilience ) then
+ lowestRating = CR_CRIT_TAKEN_MELEE;
+ elseif ( ranged == minResilience ) then
+ lowestRating = CR_CRIT_TAKEN_RANGED;
+ else
+ lowestRating = CR_CRIT_TAKEN_SPELL;
+ end
+
+ local maxRatingBonus = GetMaxCombatRatingBonus(lowestRating);
+ local lowestRatingBonus = GetCombatRatingBonus(lowestRating);
+
+ PaperDollFrame_SetLabelAndText(statFrame, STAT_RESILIENCE, minResilience);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, STAT_RESILIENCE).." "..minResilience..FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = format(RESILIENCE_TOOLTIP, lowestRatingBonus, min(lowestRatingBonus * RESILIENCE_CRIT_CHANCE_TO_DAMAGE_REDUCTION_MULTIPLIER, maxRatingBonus), lowestRatingBonus * RESILIENCE_CRIT_CHANCE_TO_CONSTANT_DAMAGE_REDUCTION_MULTIPLIER);
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetDamage(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ end
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, DAMAGE));
+ local text = _G[statFrame:GetName().."StatText"];
+ local speed, offhandSpeed = UnitAttackSpeed(unit);
+
+ local minDamage;
+ local maxDamage;
+ local minOffHandDamage;
+ local maxOffHandDamage;
+ local physicalBonusPos;
+ local physicalBonusNeg;
+ local percent;
+ minDamage, maxDamage, minOffHandDamage, maxOffHandDamage, physicalBonusPos, physicalBonusNeg, percent = UnitDamage(unit);
+ local displayMin = max(floor(minDamage),1);
+ local displayMax = max(ceil(maxDamage),1);
+
+ minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg;
+ maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg;
+
+ local baseDamage = (minDamage + maxDamage) * 0.5;
+ local fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent;
+ local totalBonus = (fullDamage - baseDamage);
+ local damagePerSecond = (max(fullDamage,1) / speed);
+ local damageTooltip = max(floor(minDamage),1).." - "..max(ceil(maxDamage),1);
+
+ local colorPos = "|cff20ff20";
+ local colorNeg = "|cffff2020";
+
+ -- epsilon check
+ if ( totalBonus < 0.1 and totalBonus > -0.1 ) then
+ totalBonus = 0.0;
+ end
+
+ if ( totalBonus == 0 ) then
+ if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then
+ text:SetText(displayMin.." - "..displayMax);
+ else
+ text:SetText(displayMin.."-"..displayMax);
+ end
+ else
+
+ local color;
+ if ( totalBonus > 0 ) then
+ color = colorPos;
+ else
+ color = colorNeg;
+ end
+ if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then
+ text:SetText(color..displayMin.." - "..displayMax.."|r");
+ else
+ text:SetText(color..displayMin.."-"..displayMax.."|r");
+ end
+ if ( physicalBonusPos > 0 ) then
+ damageTooltip = damageTooltip..colorPos.." +"..physicalBonusPos.."|r";
+ end
+ if ( physicalBonusNeg < 0 ) then
+ damageTooltip = damageTooltip..colorNeg.." "..physicalBonusNeg.."|r";
+ end
+ if ( percent > 1 ) then
+ damageTooltip = damageTooltip..colorPos.." x"..floor(percent*100+0.5).."%|r";
+ elseif ( percent < 1 ) then
+ damageTooltip = damageTooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r";
+ end
+
+ end
+ statFrame.damage = damageTooltip;
+ statFrame.attackSpeed = speed;
+ statFrame.dps = damagePerSecond;
+
+ -- If there's an offhand speed then add the offhand info to the tooltip
+ if ( offhandSpeed ) then
+ minOffHandDamage = (minOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg;
+ maxOffHandDamage = (maxOffHandDamage / percent) - physicalBonusPos - physicalBonusNeg;
+
+ local offhandBaseDamage = (minOffHandDamage + maxOffHandDamage) * 0.5;
+ local offhandFullDamage = (offhandBaseDamage + physicalBonusPos + physicalBonusNeg) * percent;
+ local offhandDamagePerSecond = (max(offhandFullDamage,1) / offhandSpeed);
+ local offhandDamageTooltip = max(floor(minOffHandDamage),1).." - "..max(ceil(maxOffHandDamage),1);
+ if ( physicalBonusPos > 0 ) then
+ offhandDamageTooltip = offhandDamageTooltip..colorPos.." +"..physicalBonusPos.."|r";
+ end
+ if ( physicalBonusNeg < 0 ) then
+ offhandDamageTooltip = offhandDamageTooltip..colorNeg.." "..physicalBonusNeg.."|r";
+ end
+ if ( percent > 1 ) then
+ offhandDamageTooltip = offhandDamageTooltip..colorPos.." x"..floor(percent*100+0.5).."%|r";
+ elseif ( percent < 1 ) then
+ offhandDamageTooltip = offhandDamageTooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r";
+ end
+ statFrame.offhandDamage = offhandDamageTooltip;
+ statFrame.offhandAttackSpeed = offhandSpeed;
+ statFrame.offhandDps = offhandDamagePerSecond;
+ else
+ statFrame.offhandAttackSpeed = nil;
+ end
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetAttackSpeed(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ end
+ local speed, offhandSpeed = UnitAttackSpeed(unit);
+ speed = format("%.2f", speed);
+ if ( offhandSpeed ) then
+ offhandSpeed = format("%.2f", offhandSpeed);
+ end
+ local text;
+ if ( offhandSpeed ) then
+ text = speed.." / "..offhandSpeed;
+ else
+ text = speed;
+ end
+ PaperDollFrame_SetLabelAndText(statFrame, WEAPON_SPEED, text);
+
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, ATTACK_SPEED).." "..text..FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = format(CR_HASTE_RATING_TOOLTIP, GetCombatRating(CR_HASTE_MELEE), GetCombatRatingBonus(CR_HASTE_MELEE));
+
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetAttackPower(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ end
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, ATTACK_POWER));
+ local text = _G[statFrame:GetName().."StatText"];
+ local base, posBuff, negBuff = UnitAttackPower(unit);
+
+ PaperDollFormatStat(MELEE_ATTACK_POWER, base, posBuff, negBuff, statFrame, text);
+ statFrame.tooltip2 = format(MELEE_ATTACK_POWER_TOOLTIP, max((base+posBuff+negBuff), 0)/ATTACK_POWER_MAGIC_NUMBER);
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetAttackBothHands(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ end
+ local mainHandAttackBase, mainHandAttackMod, offHandAttackBase, offHandAttackMod = UnitAttackBothHands(unit);
+
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, COMBAT_RATING_NAME1));
+ local text = _G[statFrame:GetName().."StatText"];
+
+ if( mainHandAttackMod == 0 ) then
+ text:SetText(mainHandAttackBase);
+ else
+ local color = RED_FONT_COLOR_CODE;
+ if( mainHandAttackMod > 0 ) then
+ color = GREEN_FONT_COLOR_CODE;
+ end
+ text:SetText(color..(mainHandAttackBase + mainHandAttackMod)..FONT_COLOR_CODE_CLOSE);
+ end
+
+ if( mainHandAttackMod == 0 ) then
+ statFrame.weaponSkill = COMBAT_RATING_NAME1.." "..mainHandAttackBase;
+ else
+ local color = RED_FONT_COLOR_CODE;
+ statFrame.weaponSkill = COMBAT_RATING_NAME1.." "..(mainHandAttackBase + mainHandAttackMod).." ("..mainHandAttackBase..color.." "..mainHandAttackMod..")";
+ if( mainHandAttackMod > 0 ) then
+ color = GREEN_FONT_COLOR_CODE;
+ statFrame.weaponSkill = COMBAT_RATING_NAME1.." "..(mainHandAttackBase + mainHandAttackMod).." ("..mainHandAttackBase..color.." +"..mainHandAttackMod..FONT_COLOR_CODE_CLOSE..")";
+ end
+ end
+
+ local total = GetCombatRating(CR_WEAPON_SKILL) + GetCombatRating(CR_WEAPON_SKILL_MAINHAND);
+ statFrame.weaponRating = format(WEAPON_SKILL_RATING, total);
+ if ( total > 0 ) then
+ statFrame.weaponRating = statFrame.weaponRating..format(WEAPON_SKILL_RATING_BONUS, GetCombatRatingBonus(CR_WEAPON_SKILL) + GetCombatRatingBonus(CR_WEAPON_SKILL_MAINHAND));
+ end
+
+ local speed, offhandSpeed = UnitAttackSpeed(unit);
+ if ( offhandSpeed ) then
+ if( offHandAttackMod == 0 ) then
+ statFrame.offhandSkill = COMBAT_RATING_NAME1.." "..offHandAttackBase;
+ else
+ local color = RED_FONT_COLOR_CODE;
+ statFrame.offhandSkill = COMBAT_RATING_NAME1.." "..(offHandAttackBase + offHandAttackMod).." ("..offHandAttackBase..color.." "..offHandAttackMod..")";
+ if( offHandAttackMod > 0 ) then
+ color = GREEN_FONT_COLOR_CODE;
+ statFrame.offhandSkill = COMBAT_RATING_NAME1.." "..(offHandAttackBase + offHandAttackMod).." ("..offHandAttackBase..color.." +"..offHandAttackMod..FONT_COLOR_CODE_CLOSE..")";
+ end
+ end
+
+ total = GetCombatRating(CR_WEAPON_SKILL) + GetCombatRating(CR_WEAPON_SKILL_OFFHAND);
+ statFrame.offhandRating = format(WEAPON_SKILL_RATING, total);
+ if ( total > 0 ) then
+ statFrame.offhandRating = statFrame.offhandRating..format(WEAPON_SKILL_RATING_BONUS, GetCombatRatingBonus(CR_WEAPON_SKILL) + GetCombatRatingBonus(CR_WEAPON_SKILL_OFFHAND));
+ end
+ else
+ statFrame.offhandSkill = nil;
+ end
+
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetRangedAttack(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ elseif ( unit == "pet" ) then
+ return;
+ end
+
+ local hasRelic = UnitHasRelicSlot(unit);
+ local rangedAttackBase, rangedAttackMod = UnitRangedAttack(unit);
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, COMBAT_RATING_NAME1));
+ local text = _G[statFrame:GetName().."StatText"];
+
+ -- If no ranged texture then set stats to n/a
+ local rangedTexture = GetInventoryItemTexture("player", 18);
+ if ( rangedTexture and not hasRelic ) then
+ PaperDollFrame.noRanged = nil;
+ else
+ text:SetText(NOT_APPLICABLE);
+ PaperDollFrame.noRanged = 1;
+ statFrame.tooltip = nil;
+ end
+ if ( not rangedTexture or hasRelic ) then
+ return;
+ end
+
+ if( rangedAttackMod == 0 ) then
+ text:SetText(rangedAttackBase);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, COMBAT_RATING_NAME1).." "..rangedAttackBase..FONT_COLOR_CODE_CLOSE;
+ else
+ local color = RED_FONT_COLOR_CODE;
+ if( rangedAttackMod > 0 ) then
+ color = GREEN_FONT_COLOR_CODE;
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, COMBAT_RATING_NAME1).." "..(rangedAttackBase + rangedAttackMod).." ("..rangedAttackBase..color.." +"..rangedAttackMod..FONT_COLOR_CODE_CLOSE..HIGHLIGHT_FONT_COLOR_CODE..")";
+ else
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, COMBAT_RATING_NAME1).." "..(rangedAttackBase + rangedAttackMod).." ("..rangedAttackBase..color.." "..rangedAttackMod..FONT_COLOR_CODE_CLOSE..HIGHLIGHT_FONT_COLOR_CODE..")";
+ end
+ text:SetText(color..(rangedAttackBase + rangedAttackMod)..FONT_COLOR_CODE_CLOSE);
+ end
+ local total = GetCombatRating(CR_WEAPON_SKILL) + GetCombatRating(CR_WEAPON_SKILL_RANGED);
+ statFrame.tooltip2 = format(WEAPON_SKILL_RATING, total);
+ if ( total > 0 ) then
+ statFrame.tooltip2 = statFrame.tooltip2..format(WEAPON_SKILL_RATING_BONUS, GetCombatRatingBonus(CR_WEAPON_SKILL) + GetCombatRatingBonus(CR_WEAPON_SKILL_RANGED));
+ end
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetRangedDamage(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ elseif ( unit == "pet" ) then
+ return;
+ end
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, DAMAGE));
+ local text = _G[statFrame:GetName().."StatText"];
+
+ -- If no ranged attack then set to n/a
+ local hasRelic = UnitHasRelicSlot(unit);
+ local rangedTexture = GetInventoryItemTexture("player", 18);
+ if ( rangedTexture and not hasRelic ) then
+ PaperDollFrame.noRanged = nil;
+ else
+ text:SetText(NOT_APPLICABLE);
+ PaperDollFrame.noRanged = 1;
+ statFrame.damage = nil;
+ return;
+ end
+
+ local rangedAttackSpeed, minDamage, maxDamage, physicalBonusPos, physicalBonusNeg, percent = UnitRangedDamage(unit);
+
+ -- Round to the third decimal place (i.e. 99.9 percent)
+ percent = math.floor(percent * 10^3 + 0.5) / 10^3
+ local displayMin = max(floor(minDamage),1);
+ local displayMax = max(ceil(maxDamage),1);
+
+ local baseDamage;
+ local fullDamage;
+ local totalBonus;
+ local damagePerSecond;
+ local tooltip;
+
+ if ( HasWandEquipped() ) then
+ baseDamage = (minDamage + maxDamage) * 0.5;
+ fullDamage = baseDamage * percent;
+ totalBonus = 0;
+ if( rangedAttackSpeed == 0 ) then
+ damagePerSecond = 0;
+ else
+ damagePerSecond = (max(fullDamage,1) / rangedAttackSpeed);
+ end
+ tooltip = max(floor(minDamage),1).." - "..max(ceil(maxDamage),1);
+ else
+ minDamage = (minDamage / percent) - physicalBonusPos - physicalBonusNeg;
+ maxDamage = (maxDamage / percent) - physicalBonusPos - physicalBonusNeg;
+
+ baseDamage = (minDamage + maxDamage) * 0.5;
+ fullDamage = (baseDamage + physicalBonusPos + physicalBonusNeg) * percent;
+ totalBonus = (fullDamage - baseDamage);
+ if( rangedAttackSpeed == 0 ) then
+ damagePerSecond = 0;
+ else
+ damagePerSecond = (max(fullDamage,1) / rangedAttackSpeed);
+ end
+ tooltip = max(floor(minDamage),1).." - "..max(ceil(maxDamage),1);
+ end
+
+ if ( totalBonus == 0 ) then
+ if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then
+ text:SetText(displayMin.." - "..displayMax);
+ else
+ text:SetText(displayMin.."-"..displayMax);
+ end
+ else
+ local colorPos = "|cff20ff20";
+ local colorNeg = "|cffff2020";
+ local color;
+ if ( totalBonus > 0 ) then
+ color = colorPos;
+ else
+ color = colorNeg;
+ end
+ if ( ( displayMin < 100 ) and ( displayMax < 100 ) ) then
+ text:SetText(color..displayMin.." - "..displayMax.."|r");
+ else
+ text:SetText(color..displayMin.."-"..displayMax.."|r");
+ end
+ if ( physicalBonusPos > 0 ) then
+ tooltip = tooltip..colorPos.." +"..physicalBonusPos.."|r";
+ end
+ if ( physicalBonusNeg < 0 ) then
+ tooltip = tooltip..colorNeg.." "..physicalBonusNeg.."|r";
+ end
+ if ( percent > 1 ) then
+ tooltip = tooltip..colorPos.." x"..floor(percent*100+0.5).."%|r";
+ elseif ( percent < 1 ) then
+ tooltip = tooltip..colorNeg.." x"..floor(percent*100+0.5).."%|r";
+ end
+ statFrame.tooltip = tooltip.." "..format(DPS_TEMPLATE, damagePerSecond);
+ end
+ statFrame.attackSpeed = rangedAttackSpeed;
+ statFrame.damage = tooltip;
+ statFrame.dps = damagePerSecond;
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetRangedAttackSpeed(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ elseif ( unit == "pet" ) then
+ return;
+ end
+ local text;
+ -- If no ranged attack then set to n/a
+ if ( PaperDollFrame.noRanged ) then
+ text = NOT_APPLICABLE;
+ statFrame.tooltip = nil;
+ else
+ text = UnitRangedDamage(unit);
+ text = format("%.2f", text);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, ATTACK_SPEED).." "..text..FONT_COLOR_CODE_CLOSE;
+ end
+ PaperDollFrame_SetLabelAndText(statFrame, WEAPON_SPEED, text);
+ statFrame.tooltip2 = format(CR_HASTE_RATING_TOOLTIP, GetCombatRating(CR_HASTE_RANGED), GetCombatRatingBonus(CR_HASTE_RANGED));
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetRangedAttackPower(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ end
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, ATTACK_POWER));
+ local text = _G[statFrame:GetName().."StatText"];
+ local base, posBuff, negBuff = UnitRangedAttackPower(unit);
+
+ PaperDollFormatStat(RANGED_ATTACK_POWER, base, posBuff, negBuff, statFrame, text);
+ local totalAP = base+posBuff+negBuff;
+ statFrame.tooltip2 = format(RANGED_ATTACK_POWER_TOOLTIP, max((totalAP), 0)/ATTACK_POWER_MAGIC_NUMBER);
+ local petAPBonus = ComputePetBonus( "PET_BONUS_RAP_TO_AP", totalAP );
+ if( petAPBonus > 0 ) then
+ statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_RANGED_ATTACK_POWER, petAPBonus);
+ end
+
+ local petSpellDmgBonus = ComputePetBonus( "PET_BONUS_RAP_TO_SPELLDMG", totalAP );
+ if( petSpellDmgBonus > 0 ) then
+ statFrame.tooltip2 = statFrame.tooltip2 .. "\n" .. format(PET_BONUS_TOOLTIP_SPELLDAMAGE, petSpellDmgBonus);
+ end
+
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetSpellBonusDamage(statFrame)
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, BONUS_DAMAGE));
+ local text = _G[statFrame:GetName().."StatText"];
+ local holySchool = 2;
+ -- Start at 2 to skip physical damage
+ local minModifier = GetSpellBonusDamage(holySchool);
+ statFrame.bonusDamage = {};
+ statFrame.bonusDamage[holySchool] = minModifier;
+ local bonusDamage;
+ for i=(holySchool+1), MAX_SPELL_SCHOOLS do
+ bonusDamage = GetSpellBonusDamage(i);
+ minModifier = min(minModifier, bonusDamage);
+ statFrame.bonusDamage[i] = bonusDamage;
+ end
+ text:SetText(minModifier);
+ statFrame.minModifier = minModifier;
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetSpellCritChance(statFrame)
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, SPELL_CRIT_CHANCE));
+ local text = _G[statFrame:GetName().."StatText"];
+ local holySchool = 2;
+ -- Start at 2 to skip physical damage
+ local minCrit = GetSpellCritChance(holySchool);
+ statFrame.spellCrit = {};
+ statFrame.spellCrit[holySchool] = minCrit;
+ local spellCrit;
+ for i=(holySchool+1), MAX_SPELL_SCHOOLS do
+ spellCrit = GetSpellCritChance(i);
+ minCrit = min(minCrit, spellCrit);
+ statFrame.spellCrit[i] = spellCrit;
+ end
+ -- Add agility contribution
+ --minCrit = minCrit + GetSpellCritChanceFromIntellect();
+ minCrit = format("%.2f%%", minCrit);
+ text:SetText(minCrit);
+ statFrame.minCrit = minCrit;
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetMeleeCritChance(statFrame)
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, MELEE_CRIT_CHANCE));
+ local text = _G[statFrame:GetName().."StatText"];
+ local critChance = GetCritChance();-- + GetCritChanceFromAgility();
+ critChance = format("%.2f%%", critChance);
+ text:SetText(critChance);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, MELEE_CRIT_CHANCE).." "..critChance..FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = format(CR_CRIT_MELEE_TOOLTIP, GetCombatRating(CR_CRIT_MELEE), GetCombatRatingBonus(CR_CRIT_MELEE));
+end
+
+function PaperDollFrame_SetRangedCritChance(statFrame)
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, RANGED_CRIT_CHANCE));
+ local text = _G[statFrame:GetName().."StatText"];
+ local critChance = GetRangedCritChance();-- + GetCritChanceFromAgility();
+ critChance = format("%.2f%%", critChance);
+ text:SetText(critChance);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, RANGED_CRIT_CHANCE).." "..critChance..FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = format(CR_CRIT_RANGED_TOOLTIP, GetCombatRating(CR_CRIT_RANGED), GetCombatRatingBonus(CR_CRIT_RANGED));
+end
+
+function PaperDollFrame_SetSpellBonusHealing(statFrame)
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, BONUS_HEALING));
+ local text = _G[statFrame:GetName().."StatText"];
+ local bonusHealing = GetSpellBonusHealing();
+ text:SetText(bonusHealing);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. BONUS_HEALING .. FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 =format(BONUS_HEALING_TOOLTIP, bonusHealing);
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetSpellPenetration(statFrame)
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, SPELL_PENETRATION));
+ local text = _G[statFrame:GetName().."StatText"];
+ text:SetText(GetSpellPenetration());
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE ..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, SPELL_PENETRATION).. FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = SPELL_PENETRATION_TOOLTIP;
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetSpellHaste(statFrame)
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, SPELL_HASTE));
+ local text = _G[statFrame:GetName().."StatText"];
+ text:SetText(GetCombatRating(CR_HASTE_SPELL));
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. SPELL_HASTE .. FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = format(SPELL_HASTE_TOOLTIP, GetCombatRatingBonus(CR_HASTE_SPELL));
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetManaRegen(statFrame)
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, MANA_REGEN));
+ local text = _G[statFrame:GetName().."StatText"];
+ if ( not UnitHasMana("player") ) then
+ text:SetText(NOT_APPLICABLE);
+ statFrame.tooltip = nil;
+ return;
+ end
+
+ local base, casting = GetManaRegen();
+ -- All mana regen stats are displayed as mana/5 sec.
+ base = floor( base * 5.0 );
+ casting = floor( casting * 5.0 );
+ text:SetText(base);
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE .. MANA_REGEN .. FONT_COLOR_CODE_CLOSE;
+ statFrame.tooltip2 = format(MANA_REGEN_TOOLTIP, base, casting);
+ statFrame:Show();
+end
+
+function PaperDollFrame_SetExpertise(statFrame, unit)
+ if ( not unit ) then
+ unit = "player";
+ end
+ local expertise, offhandExpertise = GetExpertise();
+ local speed, offhandSpeed = UnitAttackSpeed(unit);
+ local text;
+ if( offhandSpeed ) then
+ text = expertise.." / "..offhandExpertise;
+ else
+ text = expertise;
+ end
+ PaperDollFrame_SetLabelAndText(statFrame, STAT_EXPERTISE, text);
+
+ statFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, _G["COMBAT_RATING_NAME"..CR_EXPERTISE]).." "..text..FONT_COLOR_CODE_CLOSE;
+
+ local expertisePercent, offhandExpertisePercent = GetExpertisePercent();
+ expertisePercent = format("%.2f", expertisePercent);
+ if( offhandSpeed ) then
+ offhandExpertisePercent = format("%.2f", offhandExpertisePercent);
+ text = expertisePercent.."% / "..offhandExpertisePercent.."%";
+ else
+ text = expertisePercent.."%";
+ end
+ statFrame.tooltip2 = format(CR_EXPERTISE_TOOLTIP, text, GetCombatRating(CR_EXPERTISE), GetCombatRatingBonus(CR_EXPERTISE));
+
+ statFrame:Show();
+end
+
+function CharacterSpellBonusDamage_OnEnter (self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, BONUS_DAMAGE).." "..self.minModifier..FONT_COLOR_CODE_CLOSE);
+ for i=2, MAX_SPELL_SCHOOLS do
+ GameTooltip:AddDoubleLine(_G["DAMAGE_SCHOOL"..i], self.bonusDamage[i], NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GameTooltip:AddTexture("Interface\\PaperDollInfoFrame\\SpellSchoolIcon"..i);
+ end
+
+ local petStr, damage;
+ if( self.bonusDamage[6] > self.bonusDamage[3] ) then
+ petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_SHADOW;
+ damage = self.bonusDamage[6];
+ else
+ petStr = PET_BONUS_TOOLTIP_WARLOCK_SPELLDMG_FIRE;
+ damage = self.bonusDamage[3];
+ end
+
+ local petBonusAP = ComputePetBonus("PET_BONUS_SPELLDMG_TO_AP", damage );
+ local petBonusDmg = ComputePetBonus("PET_BONUS_SPELLDMG_TO_SPELLDMG", damage );
+ if( petBonusAP > 0 or petBonusDmg > 0 ) then
+ GameTooltip:AddLine("\n" .. format(petStr, petBonusAP, petBonusDmg), nil, nil, nil, 1 );
+ end
+ GameTooltip:Show();
+end
+
+function CharacterSpellCritChance_OnEnter (self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, COMBAT_RATING_NAME11).." "..GetCombatRating(11)..FONT_COLOR_CODE_CLOSE);
+ local spellCrit;
+ for i=2, MAX_SPELL_SCHOOLS do
+ spellCrit = format("%.2f", self.spellCrit[i]);
+ spellCrit = spellCrit.."%";
+ GameTooltip:AddDoubleLine(_G["DAMAGE_SCHOOL"..i], spellCrit, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GameTooltip:AddTexture("Interface\\PaperDollInfoFrame\\SpellSchoolIcon"..i);
+ end
+ GameTooltip:Show();
+end
+
+function PaperDollFrame_OnShow (self)
+ --PaperDollFrame_SetGuild();
+ PaperDollFrame_SetLevel();
+ PaperDollFrame_SetResistances();
+ PaperDollFrame_UpdateStats();
+ if ( UnitHasRelicSlot("player") ) then
+ CharacterAmmoSlot:Hide();
+ else
+ CharacterAmmoSlot:Show();
+ end
+ if ( not PlayerTitlePickerScrollFrame.titles ) then
+ PlayerTitleFrame_UpdateTitles();
+ end
+end
+
+function PaperDollFrame_OnHide (self)
+ PlayerTitlePickerFrame:Hide();
+ GearManagerDialog:Hide();
+end
+
+function PaperDollFrame_ClearIgnoredSlots ()
+ EquipmentManagerClearIgnoredSlotsForSave();
+ for k, button in next, itemSlotButtons do
+ if ( button.ignored ) then
+ button.ignored = nil;
+ PaperDollItemSlotButton_Update(button);
+ end
+ end
+end
+
+function PaperDollFrame_IgnoreSlotsForSet (setName)
+ local set = GetEquipmentSetItemIDs(setName);
+ for slot, item in ipairs(set) do
+ if ( item == EQUIPMENT_SET_IGNORED_SLOT ) then
+ EquipmentManagerIgnoreSlotForSave(slot);
+ itemSlotButtons[slot].ignored = true;
+ PaperDollItemSlotButton_Update(itemSlotButtons[slot]);
+ end
+ end
+end
+
+function PaperDollItemSlotButton_OnLoad (self)
+ self:RegisterForDrag("LeftButton");
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ local slotName = self:GetName();
+ local id, textureName, checkRelic = GetInventorySlotInfo(strsub(slotName,10));
+ self:SetID(id);
+ local texture = _G[slotName.."IconTexture"];
+ texture:SetTexture(textureName);
+ self.backgroundTextureName = textureName;
+ self.checkRelic = checkRelic;
+ self.UpdateTooltip = PaperDollItemSlotButton_OnEnter;
+ itemSlotButtons[id] = self;
+ self.verticalFlyout = VERTICAL_FLYOUTS[id];
+
+ local popoutButton = self.popoutButton;
+ if ( popoutButton ) then
+ if ( self.verticalFlyout ) then
+ popoutButton:SetHeight(16);
+ popoutButton:SetWidth(38);
+
+ popoutButton:GetNormalTexture():SetTexCoord(0.15625, 0.84375, 0.5, 0);
+ popoutButton:GetHighlightTexture():SetTexCoord(0.15625, 0.84375, 1, 0.5);
+ popoutButton:ClearAllPoints();
+ popoutButton:SetPoint("TOP", self, "BOTTOM", 0, 4);
+ else
+ popoutButton:SetHeight(38);
+ popoutButton:SetWidth(16);
+
+ popoutButton:GetNormalTexture():SetTexCoord(0.15625, 0.5, 0.84375, 0.5, 0.15625, 0, 0.84375, 0);
+ popoutButton:GetHighlightTexture():SetTexCoord(0.15625, 1, 0.84375, 1, 0.15625, 0.5, 0.84375, 0.5);
+ popoutButton:ClearAllPoints();
+ popoutButton:SetPoint("LEFT", self, "RIGHT", -8, 0);
+ end
+ end
+end
+
+function PaperDollItemSlotButton_OnShow (self)
+ self:RegisterEvent("UNIT_INVENTORY_CHANGED");
+ self:RegisterEvent("MERCHANT_UPDATE");
+ self:RegisterEvent("PLAYERBANKSLOTS_CHANGED");
+ self:RegisterEvent("ITEM_LOCK_CHANGED");
+ self:RegisterEvent("CURSOR_UPDATE");
+ self:RegisterEvent("BAG_UPDATE_COOLDOWN");
+ self:RegisterEvent("SHOW_COMPARE_TOOLTIP");
+ self:RegisterEvent("UPDATE_INVENTORY_ALERTS");
+
+ PaperDollItemSlotButton_Update(self);
+end
+
+function PaperDollItemSlotButton_OnHide (self)
+ self:UnregisterEvent("UNIT_INVENTORY_CHANGED");
+ self:UnregisterEvent("MERCHANT_UPDATE");
+ self:UnregisterEvent("PLAYERBANKSLOTS_CHANGED");
+ self:UnregisterEvent("ITEM_LOCK_CHANGED");
+ self:UnregisterEvent("CURSOR_UPDATE");
+ self:UnregisterEvent("BAG_UPDATE_COOLDOWN");
+ self:UnregisterEvent("SHOW_COMPARE_TOOLTIP");
+ self:UnregisterEvent("UPDATE_INVENTORY_ALERTS");
+end
+
+function PaperDollItemSlotButton_OnEvent (self, event, ...)
+ local arg1, arg2 = ...;
+ if ( event == "UNIT_INVENTORY_CHANGED" ) then
+ if ( arg1 == "player" ) then
+ PaperDollItemSlotButton_Update(self);
+ end
+ elseif ( event == "ITEM_LOCK_CHANGED" ) then
+ if ( not arg2 and arg1 == self:GetID() ) then
+ PaperDollItemSlotButton_UpdateLock(self);
+ end
+ elseif ( event == "BAG_UPDATE_COOLDOWN" ) then
+ PaperDollItemSlotButton_Update(self);
+ elseif ( event == "CURSOR_UPDATE" ) then
+ if ( CursorCanGoInSlot(self:GetID()) ) then
+ self:LockHighlight();
+ else
+ self:UnlockHighlight();
+ end
+ elseif ( event == "SHOW_COMPARE_TOOLTIP" ) then
+ if ( (arg1 ~= self:GetID()) or (arg2 > NUM_SHOPPING_TOOLTIPS) ) then
+ return;
+ end
+
+ local tooltip = _G["ShoppingTooltip"..arg2];
+ local anchor = "ANCHOR_RIGHT";
+ if ( arg2 > 1 ) then
+ anchor = "ANCHOR_BOTTOMRIGHT";
+ end
+ tooltip:SetOwner(self, anchor);
+ local hasItem, hasCooldown = tooltip:SetInventoryItem("player", self:GetID());
+ if ( not hasItem ) then
+ tooltip:Hide();
+ end
+ elseif ( event == "UPDATE_INVENTORY_ALERTS" ) then
+ PaperDollItemSlotButton_Update(self);
+ elseif ( event == "MODIFIER_STATE_CHANGED" ) then
+ if ( IsModifiedClick("SHOWITEMFLYOUT") and self:IsMouseOver() ) then
+ PaperDollItemSlotButton_OnEnter(self);
+ end
+ end
+end
+
+function PaperDollItemSlotButton_OnClick (self, button)
+ MerchantFrame_ResetRefundItem();
+ if ( button == "LeftButton" ) then
+ local type = GetCursorInfo();
+ if ( type == "merchant" and MerchantFrame.extendedCost ) then
+ MerchantFrame_ConfirmExtendedItemCost(MerchantFrame.extendedCost);
+ else
+ PickupInventoryItem(self:GetID());
+ if ( CursorHasItem() ) then
+ MerchantFrame_SetRefundItem(self, 1);
+ end
+ end
+ else
+ UseInventoryItem(self:GetID());
+ end
+end
+
+function PaperDollItemSlotButton_OnModifiedClick (self, button)
+ if ( HandleModifiedItemClick(GetInventoryItemLink("player", self:GetID())) ) then
+ return;
+ end
+ if ( IsModifiedClick("SOCKETITEM") ) then
+ SocketInventoryItem(self:GetID());
+ end
+end
+
+function PaperDollItemSlotButton_Update (self)
+ local textureName = GetInventoryItemTexture("player", self:GetID());
+ local cooldown = _G[self:GetName().."Cooldown"];
+ if ( textureName ) then
+ SetItemButtonTexture(self, textureName);
+ SetItemButtonCount(self, GetInventoryItemCount("player", self:GetID()));
+ if ( GetInventoryItemBroken("player", self:GetID()) ) then
+ SetItemButtonTextureVertexColor(self, 0.9, 0, 0);
+ SetItemButtonNormalTextureVertexColor(self, 0.9, 0, 0);
+ else
+ SetItemButtonTextureVertexColor(self, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(self, 1.0, 1.0, 1.0);
+ end
+ if ( cooldown ) then
+ local start, duration, enable = GetInventoryItemCooldown("player", self:GetID());
+ CooldownFrame_SetTimer(cooldown, start, duration, enable);
+ end
+ self.hasItem = 1;
+ else
+ local textureName = self.backgroundTextureName;
+ if ( self.checkRelic and UnitHasRelicSlot("player") ) then
+ textureName = "Interface\\Paperdoll\\UI-PaperDoll-Slot-Relic.blp";
+ end
+ SetItemButtonTexture(self, textureName);
+ SetItemButtonCount(self, 0);
+ SetItemButtonTextureVertexColor(self, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(self, 1.0, 1.0, 1.0);
+ if ( cooldown ) then
+ cooldown:Hide();
+ end
+ self.hasItem = nil;
+ end
+
+ if ( not GearManagerDialog:IsShown() ) then
+ self.ignored = nil;
+ end
+
+ if ( self.ignored and self.ignoreTexture ) then
+ self.ignoreTexture:Show();
+ elseif ( self.ignoreTexture ) then
+ self.ignoreTexture:Hide();
+ end
+
+ PaperDollItemSlotButton_UpdateLock(self);
+
+ -- Update repair all button status
+ MerchantFrame_UpdateGuildBankRepair();
+ MerchantFrame_UpdateCanRepairAll();
+end
+
+function PaperDollItemSlotButton_UpdateLock (self)
+ if ( IsInventoryItemLocked(self:GetID()) ) then
+ --this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot");
+ SetItemButtonDesaturated(self, 1, 0.5, 0.5, 0.5);
+ else
+ --this:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");
+ SetItemButtonDesaturated(self, nil);
+ end
+end
+
+function PaperDollItemSlotButton_UpdateFlyout (self)
+ if ( self:GetID() ~= INVSLOT_AMMO ) then
+ if ( (IsModifiedClick("SHOWITEMFLYOUT") and not (PaperDollFrameItemFlyout:IsVisible() and PaperDollFrameItemFlyout.button == self)) or
+ self.popoutButton.flyoutLocked) then
+ PaperDollFrameItemFlyout_Show(self);
+ elseif ( (PaperDollFrameItemFlyout:IsVisible() and PaperDollFrameItemFlyout.button == self) and
+ not self.popoutButton.flyoutLocked and not IsModifiedClick("SHOWITEMFLYOUT") ) then
+ PaperDollFrameItemFlyout_Hide();
+ end
+ end
+end
+
+function PaperDollItemSlotButton_OnEnter (self)
+ self:RegisterEvent("MODIFIER_STATE_CHANGED");
+ PaperDollItemSlotButton_UpdateFlyout(self);
+ if ( PaperDollFrameItemFlyout:IsShown() ) then
+ GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6);
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ end
+ local hasItem, hasCooldown, repairCost = GameTooltip:SetInventoryItem("player", self:GetID());
+ if ( not hasItem ) then
+ local text = _G[strupper(strsub(self:GetName(), 10))];
+ if ( self.checkRelic and UnitHasRelicSlot("player") ) then
+ text = RELICSLOT;
+ end
+ GameTooltip:SetText(text);
+ end
+ if ( InRepairMode() and repairCost and (repairCost > 0) ) then
+ GameTooltip:AddLine(REPAIR_COST, "", 1, 1, 1);
+ SetTooltipMoney(GameTooltip, repairCost);
+ GameTooltip:Show();
+ else
+ CursorUpdate(self);
+ end
+end
+
+function PaperDollItemSlotButton_OnLeave (self)
+ self:UnregisterEvent("MODIFIER_STATE_CHANGED");
+ GameTooltip:Hide();
+ ResetCursor();
+end
+
+function PaperDollStatTooltip (self, unit)
+ if ( not self.tooltip ) then
+ return;
+ end
+ if ( not unit ) then
+ unit = "player";
+ end
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip);
+ if ( self.tooltip2 ) then
+ GameTooltip:AddLine(self.tooltip2, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ end
+ GameTooltip:Show();
+end
+
+function FormatPaperDollTooltipStat(name, base, posBuff, negBuff)
+ local effective = max(0,base + posBuff + negBuff);
+ local text = HIGHLIGHT_FONT_COLOR_CODE..name.." "..effective;
+ if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
+ text = text..FONT_COLOR_CODE_CLOSE;
+ else
+ if ( posBuff > 0 or negBuff < 0 ) then
+ text = text.." ("..base..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( posBuff > 0 ) then
+ text = text..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( negBuff < 0 ) then
+ text = text..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( posBuff > 0 or negBuff < 0 ) then
+ text = text..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE;
+ end
+ end
+ return text;
+end
+
+function ColorPaperDollStat(base, posBuff, negBuff)
+ local stat;
+ local effective = max(0,base + posBuff + negBuff);
+ if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
+ stat = effective;
+ else
+
+ -- if there is a negative buff then show the main number in red, even if there are
+ -- positive buffs. Otherwise show the number in green
+ if ( negBuff < 0 ) then
+ stat = RED_FONT_COLOR_CODE..effective..FONT_COLOR_CODE_CLOSE;
+ else
+ stat = GREEN_FONT_COLOR_CODE..effective..FONT_COLOR_CODE_CLOSE;
+ end
+ end
+ return stat;
+end
+
+function PaperDollFormatStat(name, base, posBuff, negBuff, frame, textString)
+ local effective = max(0,base + posBuff + negBuff);
+ local text = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT,name).." "..effective;
+ if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
+ text = text..FONT_COLOR_CODE_CLOSE;
+ textString:SetText(effective);
+ else
+ if ( posBuff > 0 or negBuff < 0 ) then
+ text = text.." ("..base..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( posBuff > 0 ) then
+ text = text..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( negBuff < 0 ) then
+ text = text..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( posBuff > 0 or negBuff < 0 ) then
+ text = text..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE;
+ end
+
+ -- if there is a negative buff then show the main number in red, even if there are
+ -- positive buffs. Otherwise show the number in green
+ if ( negBuff < 0 ) then
+ textString:SetText(RED_FONT_COLOR_CODE..effective..FONT_COLOR_CODE_CLOSE);
+ else
+ textString:SetText(GREEN_FONT_COLOR_CODE..effective..FONT_COLOR_CODE_CLOSE);
+ end
+ end
+ frame.tooltip = text;
+end
+
+function CharacterAttackFrame_OnEnter (self)
+ -- Main hand weapon
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(self.weaponSkill);
+ GameTooltip:AddLine(self.weaponRating);
+ -- Check for offhand weapon
+ if ( self.offhandSkill ) then
+ GameTooltip:AddLine("\n");
+ GameTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(self.offhandSkill);
+ GameTooltip:AddLine(self.offhandRating);
+ end
+ GameTooltip:Show();
+end
+
+function CharacterDamageFrame_OnEnter (self)
+ -- Main hand weapon
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self == PetDamageFrame ) then
+ GameTooltip:SetText(INVTYPE_WEAPONMAINHAND_PET, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ else
+ GameTooltip:SetText(INVTYPE_WEAPONMAINHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ end
+ GameTooltip:AddDoubleLine(format(STAT_FORMAT, ATTACK_SPEED_SECONDS), format("%.2f", self.attackSpeed), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE), self.damage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE_PER_SECOND), format("%.1f", self.dps), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ -- Check for offhand weapon
+ if ( self.offhandAttackSpeed ) then
+ GameTooltip:AddLine("\n");
+ GameTooltip:AddLine(INVTYPE_WEAPONOFFHAND, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddDoubleLine(format(STAT_FORMAT, ATTACK_SPEED_SECONDS), format("%.2f", self.offhandAttackSpeed), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE), self.offhandDamage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE_PER_SECOND), format("%.1f", self.offhandDps), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ end
+ GameTooltip:Show();
+end
+
+function CharacterRangedDamageFrame_OnEnter (self)
+ if ( not self.damage ) then
+ return;
+ end
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(INVTYPE_RANGED, HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddDoubleLine(format(STAT_FORMAT, ATTACK_SPEED_SECONDS), format("%.2f", self.attackSpeed), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE), self.damage, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GameTooltip:AddDoubleLine(format(STAT_FORMAT, DAMAGE_PER_SECOND), format("%.1f", self.dps), NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b);
+ GameTooltip:Show();
+end
+
+function PaperDollFrame_GetArmorReduction(armor, attackerLevel)
+ local levelModifier = attackerLevel;
+ if ( levelModifier > 59 ) then
+ levelModifier = levelModifier + (4.5 * (levelModifier-59));
+ end
+ local temp = 0.1*armor/(8.5*levelModifier + 40);
+ temp = temp/(1+temp);
+
+ if ( temp > 0.75 ) then
+ return 75;
+ end
+
+ if ( temp < 0 ) then
+ return 0;
+ end
+
+ return temp*100;
+end
+
+-- Paperdoll stat selection functions
+function PlayerStatFrameLeftDropDown_OnLoad (self)
+ RaiseFrameLevel(self);
+ UIDropDownMenu_Initialize(self, PlayerStatFrameLeftDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, GetCVar("playerStatLeftDropdown"));
+ UIDropDownMenu_SetWidth(self, 99);
+ UIDropDownMenu_JustifyText(self, "LEFT");
+end
+
+function PlayerStatFrameLeftDropDown_OnShow (self)
+ UIDropDownMenu_Initialize(self, PlayerStatFrameLeftDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, GetCVar("playerStatLeftDropdown"));
+end
+
+function PlayerStatFrameLeftDropDown_Initialize (self)
+ -- Setup buttons
+ local info = UIDropDownMenu_CreateInfo();
+ local checked;
+ for i=1, getn(PLAYERSTAT_DROPDOWN_OPTIONS) do
+ if ( PLAYERSTAT_DROPDOWN_OPTIONS[i] == GetCVar("playerStatLeftDropdown") ) then
+ checked = 1;
+ else
+ checked = nil;
+ end
+ info.text = _G[PLAYERSTAT_DROPDOWN_OPTIONS[i]];
+ info.func = PlayerStatFrameLeftDropDown_OnClick;
+ info.value = PLAYERSTAT_DROPDOWN_OPTIONS[i];
+ info.checked = checked;
+ info.owner = UIDROPDOWNMENU_OPEN_MENU;
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function PlayerStatFrameLeftDropDown_OnClick (self)
+ UIDropDownMenu_SetSelectedValue(self.owner, self.value);
+ SetCVar("playerStatLeftDropdown", self.value);
+ UpdatePaperdollStats("PlayerStatFrameLeft", self.value);
+end
+
+function PlayerStatFrameRightDropDown_OnLoad (self)
+ UIDropDownMenu_Initialize(self, PlayerStatFrameRightDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, GetCVar("playerStatRightDropdown"));
+ UIDropDownMenu_SetWidth(self, 99);
+ UIDropDownMenu_JustifyText(self, "LEFT");
+end
+
+function PlayerStatFrameRightDropDown_OnShow (self)
+ UIDropDownMenu_Initialize(self, PlayerStatFrameRightDropDown_Initialize);
+ UIDropDownMenu_SetSelectedValue(self, GetCVar("playerStatRightDropdown"));
+end
+
+function PlayerStatFrameRightDropDown_Initialize (self)
+ -- Setup buttons
+ local info = UIDropDownMenu_CreateInfo();
+ local checked;
+ for i=1, getn(PLAYERSTAT_DROPDOWN_OPTIONS) do
+ if ( PLAYERSTAT_DROPDOWN_OPTIONS[i] == GetCVar("playerStatRightDropdown") ) then
+ checked = 1;
+ else
+ checked = nil;
+ end
+ info.text = _G[PLAYERSTAT_DROPDOWN_OPTIONS[i]];
+ info.func = PlayerStatFrameRightDropDown_OnClick;
+ info.value = PLAYERSTAT_DROPDOWN_OPTIONS[i];
+ info.checked = checked;
+ info.owner = UIDROPDOWNMENU_OPEN_MENU;
+ UIDropDownMenu_AddButton(info);
+ end
+end
+
+function PlayerStatFrameRightDropDown_OnClick (self)
+ UIDropDownMenu_SetSelectedValue(self.owner, self.value);
+ SetCVar("playerStatRightDropdown", self.value);
+ UpdatePaperdollStats("PlayerStatFrameRight", self.value);
+end
+
+function PaperDollFrame_UpdateStats()
+ UpdatePaperdollStats("PlayerStatFrameLeft", GetCVar("playerStatLeftDropdown"));
+ UpdatePaperdollStats("PlayerStatFrameRight", GetCVar("playerStatRightDropdown"));
+end
+
+function PaperDollFrame_SetLabelAndText(statFrame, label, text, isPercentage)
+ _G[statFrame:GetName().."Label"]:SetText(format(STAT_FORMAT, label));
+ if ( isPercentage ) then
+ text = format("%.2f%%", text);
+ end
+ _G[statFrame:GetName().."StatText"]:SetText(text);
+end
+
+function UpdatePaperdollStats(prefix, index)
+ local stat1 = _G[prefix..1];
+ local stat2 = _G[prefix..2];
+ local stat3 = _G[prefix..3];
+ local stat4 = _G[prefix..4];
+ local stat5 = _G[prefix..5];
+ local stat6 = _G[prefix..6];
+
+ -- reset any OnEnter scripts that may have been changed
+ stat1:SetScript("OnEnter", PaperDollStatTooltip);
+ stat2:SetScript("OnEnter", PaperDollStatTooltip);
+ stat4:SetScript("OnEnter", PaperDollStatTooltip);
+
+ stat6:Show();
+
+ if ( index == "PLAYERSTAT_BASE_STATS" ) then
+ PaperDollFrame_SetStat(stat1, 1);
+ PaperDollFrame_SetStat(stat2, 2);
+ PaperDollFrame_SetStat(stat3, 3);
+ PaperDollFrame_SetStat(stat4, 4);
+ PaperDollFrame_SetStat(stat5, 5);
+ PaperDollFrame_SetArmor(stat6);
+ elseif ( index == "PLAYERSTAT_MELEE_COMBAT" ) then
+ PaperDollFrame_SetDamage(stat1);
+ stat1:SetScript("OnEnter", CharacterDamageFrame_OnEnter);
+ PaperDollFrame_SetAttackSpeed(stat2);
+ PaperDollFrame_SetAttackPower(stat3);
+ PaperDollFrame_SetRating(stat4, CR_HIT_MELEE);
+ PaperDollFrame_SetMeleeCritChance(stat5);
+ PaperDollFrame_SetExpertise(stat6);
+ elseif ( index == "PLAYERSTAT_RANGED_COMBAT" ) then
+ PaperDollFrame_SetRangedDamage(stat1);
+ stat1:SetScript("OnEnter", CharacterRangedDamageFrame_OnEnter);
+ PaperDollFrame_SetRangedAttackSpeed(stat2);
+ PaperDollFrame_SetRangedAttackPower(stat3);
+ PaperDollFrame_SetRating(stat4, CR_HIT_RANGED);
+ PaperDollFrame_SetRangedCritChance(stat5);
+ stat6:Hide();
+ elseif ( index == "PLAYERSTAT_SPELL_COMBAT" ) then
+ PaperDollFrame_SetSpellBonusDamage(stat1);
+ stat1:SetScript("OnEnter", CharacterSpellBonusDamage_OnEnter);
+ PaperDollFrame_SetSpellBonusHealing(stat2);
+ PaperDollFrame_SetRating(stat3, CR_HIT_SPELL);
+ PaperDollFrame_SetSpellCritChance(stat4);
+ stat4:SetScript("OnEnter", CharacterSpellCritChance_OnEnter);
+ PaperDollFrame_SetSpellHaste(stat5);
+ PaperDollFrame_SetManaRegen(stat6);
+ elseif ( index == "PLAYERSTAT_DEFENSES" ) then
+ PaperDollFrame_SetArmor(stat1);
+ PaperDollFrame_SetDefense(stat2);
+ PaperDollFrame_SetDodge(stat3);
+ PaperDollFrame_SetParry(stat4);
+ PaperDollFrame_SetBlock(stat5);
+ PaperDollFrame_SetResilience(stat6);
+ end
+end
+
+function ComputePetBonus(stat, value)
+ local temp, unitClass = UnitClass("player");
+ unitClass = strupper(unitClass);
+ if( unitClass == "WARLOCK" ) then
+ if( WARLOCK_PET_BONUS[stat] ) then
+ return value * WARLOCK_PET_BONUS[stat];
+ else
+ return 0;
+ end
+ elseif( unitClass == "HUNTER" ) then
+ if( HUNTER_PET_BONUS[stat] ) then
+ return value * HUNTER_PET_BONUS[stat];
+ else
+ return 0;
+ end
+ end
+
+ return 0;
+end
+
+PDFITEMFLYOUT_ITEMS_PER_ROW = 5;
+
+PDFITEMFLYOUT_BORDERWIDTH = 3;
+
+PDFITEMFLYOUT_WIDTH = 43;
+PDFITEMFLYOUT_HEIGHT = 43;
+PDFITEM_WIDTH = 37;
+PDFITEM_HEIGHT = 37;
+PDFITEM_XOFFSET = 4;
+PDFITEM_YOFFSET = -5;
+
+local itemTable = {}; -- Used for items and locations
+local itemDisplayTable = {} -- Used for ordering items by location
+
+function PaperDollFrameItemFlyout_CreateButton ()
+ local buttons = PaperDollFrameItemFlyout.buttons;
+ local buttonAnchor = PaperDollFrameItemFlyoutButtons;
+ local numButtons = #buttons;
+
+ local button = CreateFrame("BUTTON", "PaperDollFrameItemFlyoutButtons" .. numButtons + 1, buttonAnchor, "PaperDollFrameItemFlyoutButtonTemplate");
+
+ local pos = numButtons/PDFITEMFLYOUT_ITEMS_PER_ROW;
+ if ( math.floor(pos) == pos ) then
+ -- This is the first button in a row.
+ button:SetPoint("TOPLEFT", buttonAnchor, "TOPLEFT", PDFITEMFLYOUT_BORDERWIDTH, -PDFITEMFLYOUT_BORDERWIDTH - (PDFITEM_HEIGHT - PDFITEM_YOFFSET)* pos);
+ else
+ button:SetPoint("TOPLEFT", buttons[numButtons], "TOPRIGHT", PDFITEM_XOFFSET, 0);
+ end
+
+ tinsert(buttons, button);
+ return button
+end
+
+function PaperDollFrameItemFlyout_Hide ()
+ PaperDollFrameItemFlyout:Hide();
+end
+
+function PaperDollFrameItemFlyout_OnUpdate (self, elapsed)
+ if ( not IsModifiedClick("SHOWITEMFLYOUT") ) then
+ local button = self.button;
+
+ if ( button and button.popoutButton.flyoutLocked ) then
+ PaperDollItemSlotButton_UpdateFlyout(button);
+ elseif ( button and button:IsMouseOver() ) then
+ PaperDollItemSlotButton_OnEnter(button);
+ else
+ PaperDollFrameItemFlyout_Hide();
+ end
+ end
+end
+
+function PaperDollFrameItemFlyout_OnShow (self)
+ self:RegisterEvent("BAG_UPDATE");
+ self:RegisterEvent("UNIT_INVENTORY_CHANGED");
+end
+
+function PaperDollFrameItemFlyout_OnHide (self)
+ if ( self.button ) then
+ local popoutButton = self.button.popoutButton;
+ popoutButton.flyoutLocked = false;
+ PaperDollFrameItemPopoutButton_SetReversed(popoutButton, false);
+ end
+ self.button = nil;
+ self:UnregisterEvent("BAG_UPDATE");
+ self:UnregisterEvent("UNIT_INVENTORY_CHANGED");
+end
+
+function PaperDollFrameItemFlyout_OnEvent (self, event, ...)
+ if ( event == "BAG_UPDATE" ) then
+ -- This spams a lot, four times when we equip an item, but we need to use it. PaperDollFrameItemFlyout_Show needs to stay fast for this reason.
+ PaperDollFrameItemFlyout_Show(self.button);
+ elseif ( event == "UNIT_INVENTORY_CHANGED" ) then
+ local arg1 = ...;
+ if ( arg1 == "player" ) then
+ PaperDollFrameItemFlyout_Show(self.button);
+ end
+ end
+end
+
+local function _createFlyoutBG (buttonAnchor)
+ local numBGs = buttonAnchor["numBGs"];
+ numBGs = numBGs + 1;
+ local texture = buttonAnchor:CreateTexture(nil, nil, "PaperDollFrameFlyoutTexture");
+ buttonAnchor["bg" .. numBGs] = texture;
+ buttonAnchor["numBGs"] = numBGs;
+ return texture;
+end
+
+function PaperDollFrameItemFlyout_Show (paperDollItemSlot)
+ local id = paperDollItemSlot:GetID();
+
+ local flyout = PaperDollFrameItemFlyout;
+ local buttons = flyout.buttons;
+ local buttonAnchor = flyout.buttonFrame;
+
+ if ( flyout.button and flyout.button ~= paperDollItemSlot ) then
+ local popoutButton = flyout.button.popoutButton;
+ if ( popoutButton.flyoutLocked ) then
+ popoutButton.flyoutLocked = false;
+ PaperDollFrameItemPopoutButton_SetReversed(popoutButton, false);
+ end
+ end
+
+ for k in next, itemDisplayTable do
+ itemDisplayTable[k] = nil;
+ end
+
+ for k in next, itemTable do
+ itemTable[k] = nil;
+ end
+
+ GetInventoryItemsForSlot(id, itemTable);
+
+ for location, itemID in next, itemTable do
+ if ( location - id == ITEM_INVENTORY_LOCATION_PLAYER ) then -- Remove the currently equipped item from the list
+ itemTable[location] = nil;
+ else
+ tinsert(itemDisplayTable, location);
+ end
+ end
+
+ table.sort(itemDisplayTable); -- Sort by location. This ends up as: inventory, backpack, bags, bank, and bank bags.
+
+ local numItems = #itemDisplayTable;
+
+ for i = PDFITEMFLYOUT_MAXITEMS + 1, numItems do
+ itemDisplayTable[i] = nil;
+ end
+
+ numItems = min(numItems, PDFITEMFLYOUT_MAXITEMS);
+
+ if ( GearManagerDialog:IsShown() ) then
+ if ( not paperDollItemSlot.ignored ) then
+ tinsert(itemDisplayTable, 1, PDFITEMFLYOUT_IGNORESLOT_LOCATION);
+ else
+ tinsert(itemDisplayTable, 1, PDFITEMFLYOUT_UNIGNORESLOT_LOCATION);
+ end
+ numItems = numItems + 1;
+ end
+
+ if ( paperDollItemSlot.hasItem ) then
+ tinsert(itemDisplayTable, 1, PDFITEMFLYOUT_PLACEINBAGS_LOCATION);
+ numItems = numItems + 1;
+ end
+
+ while #buttons < numItems do -- Create any buttons we need.
+ PaperDollFrameItemFlyout_CreateButton();
+ end
+
+ if ( numItems == 0 ) then
+ flyout:Hide();
+ return;
+ end
+
+ for i, button in ipairs(buttons) do
+ if ( i <= numItems ) then
+ button.id = id;
+ button.location = itemDisplayTable[i];
+ button:Show();
+
+ PaperDollFrameItemFlyout_DisplayButton(button, paperDollItemSlot);
+ else
+ button:Hide();
+ end
+ end
+
+ flyout:ClearAllPoints();
+ flyout:SetFrameLevel(paperDollItemSlot:GetFrameLevel() - 1);
+ flyout.button = paperDollItemSlot;
+ flyout:SetPoint("TOPLEFT", paperDollItemSlot, "TOPLEFT", -PDFITEMFLYOUT_BORDERWIDTH, PDFITEMFLYOUT_BORDERWIDTH);
+ local horizontalItems = min(numItems, PDFITEMFLYOUT_ITEMS_PER_ROW);
+ if ( paperDollItemSlot.verticalFlyout ) then
+ buttonAnchor:SetPoint("TOPLEFT", paperDollItemSlot.popoutButton, "BOTTOMLEFT", 0, -PDFITEMFLYOUT_BORDERWIDTH);
+ else
+ buttonAnchor:SetPoint("TOPLEFT", paperDollItemSlot.popoutButton, "TOPRIGHT", 0, 0);
+ end
+ buttonAnchor:SetWidth((horizontalItems * PDFITEM_WIDTH) + ((horizontalItems - 1) * PDFITEM_XOFFSET) + PDFITEMFLYOUT_BORDERWIDTH);
+ buttonAnchor:SetHeight(PDFITEMFLYOUT_HEIGHT + (math.floor((numItems - 1)/PDFITEMFLYOUT_ITEMS_PER_ROW) * (PDFITEM_HEIGHT - PDFITEM_YOFFSET)));
+
+
+ if ( flyout.numItems ~= numItems ) then
+ local texturesUsed = 0;
+ if ( numItems == 1 ) then
+ local bgTex, lastBGTex;
+ bgTex = buttonAnchor.bg1;
+ bgTex:ClearAllPoints();
+ bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONESLOT_LEFT_COORDS));
+ bgTex:SetWidth(PDFITEMFLYOUT_ONESLOT_LEFTWIDTH);
+ bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT);
+ bgTex:SetPoint("TOPLEFT", -5, 4);
+ bgTex:Show();
+ texturesUsed = texturesUsed + 1;
+ lastBGTex = bgTex;
+
+ bgTex = buttonAnchor.bg2 or _createFlyoutBG(buttonAnchor);
+ bgTex:ClearAllPoints();
+ bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONESLOT_RIGHT_COORDS));
+ bgTex:SetWidth(PDFITEMFLYOUT_ONESLOT_RIGHTWIDTH);
+ bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT);
+ bgTex:SetPoint("TOPLEFT", lastBGTex, "TOPRIGHT");
+ bgTex:Show();
+ texturesUsed = texturesUsed + 1;
+ lastBGTex = bgTex;
+ elseif ( numItems <= PDFITEMFLYOUT_ITEMS_PER_ROW ) then
+ local bgTex, lastBGTex;
+ bgTex = buttonAnchor.bg1;
+ bgTex:ClearAllPoints();
+ bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONEROW_LEFT_COORDS));
+ bgTex:SetWidth(PDFITEMFLYOUT_ONEROW_LEFT_WIDTH);
+ bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT);
+ bgTex:SetPoint("TOPLEFT", -5, 4);
+ bgTex:Show();
+ texturesUsed = texturesUsed + 1;
+ lastBGTex = bgTex;
+ for i = texturesUsed + 1, numItems - 1 do
+ bgTex = buttonAnchor["bg"..i] or _createFlyoutBG(buttonAnchor);
+ bgTex:ClearAllPoints();
+ bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONEROW_CENTER_COORDS));
+ bgTex:SetWidth(PDFITEMFLYOUT_ONEROW_CENTER_WIDTH);
+ bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT);
+ bgTex:SetPoint("TOPLEFT", lastBGTex, "TOPRIGHT");
+ bgTex:Show();
+ texturesUsed = texturesUsed + 1;
+ lastBGTex = bgTex;
+ end
+
+ bgTex = buttonAnchor["bg"..numItems] or _createFlyoutBG(buttonAnchor);
+ bgTex:ClearAllPoints();
+ bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_ONEROW_RIGHT_COORDS));
+ bgTex:SetWidth(PDFITEMFLYOUT_ONEROW_RIGHT_WIDTH);
+ bgTex:SetHeight(PDFITEMFLYOUT_ONEROW_HEIGHT);
+ bgTex:SetPoint("TOPLEFT", lastBGTex, "TOPRIGHT");
+ bgTex:Show();
+ texturesUsed = texturesUsed + 1;
+ elseif ( numItems > PDFITEMFLYOUT_ITEMS_PER_ROW ) then
+ local numRows = math.ceil(numItems/PDFITEMFLYOUT_ITEMS_PER_ROW);
+ local bgTex, lastBGTex;
+ bgTex = buttonAnchor.bg1;
+ bgTex:ClearAllPoints();
+ bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_MULTIROW_TOP_COORDS));
+ bgTex:SetWidth(PDFITEMFLYOUT_MULTIROW_WIDTH);
+ bgTex:SetHeight(PDFITEMFLYOUT_MULTIROW_TOP_HEIGHT);
+ bgTex:SetPoint("TOPLEFT", -5, 4);
+ bgTex:Show();
+ texturesUsed = texturesUsed + 1;
+ lastBGTex = bgTex;
+ for i = 2, numRows - 1 do -- Middle rows
+ bgTex = buttonAnchor["bg"..i] or _createFlyoutBG(buttonAnchor);
+ bgTex:ClearAllPoints();
+ bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_MULTIROW_MIDDLE_COORDS));
+ bgTex:SetWidth(PDFITEMFLYOUT_MULTIROW_WIDTH);
+ bgTex:SetHeight(PDFITEMFLYOUT_MULTIROW_MIDDLE_HEIGHT);
+ bgTex:SetPoint("TOPLEFT", lastBGTex, "BOTTOMLEFT");
+ bgTex:Show();
+ texturesUsed = texturesUsed + 1;
+ lastBGTex = bgTex;
+ end
+
+ bgTex = buttonAnchor["bg"..numRows] or _createFlyoutBG(buttonAnchor);
+ bgTex:ClearAllPoints();
+ bgTex:SetTexCoord(unpack(PDFITEMFLYOUT_MULTIROW_BOTTOM_COORDS));
+ bgTex:SetWidth(PDFITEMFLYOUT_MULTIROW_WIDTH);
+ bgTex:SetHeight(PDFITEMFLYOUT_MULTIROW_BOTTOM_HEIGHT);
+ bgTex:SetPoint("TOPLEFT", lastBGTex, "BOTTOMLEFT");
+ bgTex:Show();
+ texturesUsed = texturesUsed + 1;
+ lastBGTex = bgTex;
+ end
+
+ for i = texturesUsed + 1, buttonAnchor["numBGs"] do
+ buttonAnchor["bg" .. i]:Hide();
+ end
+ flyout.numItems = numItems;
+ end
+
+ flyout:Show();
+end
+
+function PaperDollFrameItemFlyout_DisplayButton (button, paperDollItemSlot)
+ local location = button.location;
+ if ( not location ) then
+ return;
+ end
+ if ( location >= PDFITEMFLYOUT_FIRST_SPECIAL_LOCATION ) then
+ PaperDollFrameItemFlyout_DisplaySpecialButton(button, paperDollItemSlot);
+ return;
+ end
+
+ local id, name, textureName, count, durability, maxDurability, invType, locked, start, duration, enable, setTooltip = EquipmentManager_GetItemInfoByLocation(location);
+
+ local broken = ( maxDurability and durability == 0 );
+ if ( textureName ) then
+ SetItemButtonTexture(button, textureName);
+ SetItemButtonCount(button, count);
+ if ( broken ) then
+ SetItemButtonTextureVertexColor(button, 0.9, 0, 0);
+ SetItemButtonNormalTextureVertexColor(button, 0.9, 0, 0);
+ else
+ SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0);
+ end
+
+ CooldownFrame_SetTimer(button.cooldown, start, duration, enable);
+
+ button.UpdateTooltip = function () GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6); setTooltip(); end;
+ if ( button:IsMouseOver() ) then
+ button.UpdateTooltip();
+ end
+ else
+ textureName = paperDollItemSlot.backgroundTextureName;
+ if ( paperDollItemSlot.checkRelic and UnitHasRelicSlot("player") ) then
+ textureName = "Interface\\Paperdoll\\UI-PaperDoll-Slot-Relic.blp";
+ end
+ SetItemButtonTexture(button, textureName);
+ SetItemButtonCount(button, 0);
+ SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0);
+ button.cooldown:Hide();
+ button.UpdateTooltip = nil;
+ end
+end
+
+function PaperDollFrameItemFlyout_DisplaySpecialButton (button, paperDollItemSlot)
+ local location = button.location;
+ if ( location == PDFITEMFLYOUT_IGNORESLOT_LOCATION ) then
+ SetItemButtonTexture(button, "Interface\\PaperDollInfoFrame\\UI-GearManager-LeaveItem-Opaque");
+ SetItemButtonCount(button, nil);
+ button.UpdateTooltip =
+ function ()
+ GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6);
+ GameTooltip:SetText(EQUIPMENT_MANAGER_IGNORE_SLOT, 1.0, 1.0, 1.0);
+ if ( SHOW_NEWBIE_TIPS == "1" ) then
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_EQUIPMENT_MANAGER_IGNORE_SLOT, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ end
+ GameTooltip:Show();
+ end;
+ SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0);
+ elseif ( location == PDFITEMFLYOUT_UNIGNORESLOT_LOCATION ) then
+ SetItemButtonTexture(button, "Interface\\PaperDollInfoFrame\\UI-GearManager-Undo");
+ SetItemButtonCount(button, nil);
+ button.UpdateTooltip =
+ function ()
+ GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6);
+ GameTooltip:SetText(EQUIPMENT_MANAGER_UNIGNORE_SLOT, 1.0, 1.0, 1.0);
+ if ( SHOW_NEWBIE_TIPS == "1" ) then
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_EQUIPMENT_MANAGER_UNIGNORE_SLOT, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ end
+ GameTooltip:Show();
+ end;
+ SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0);
+ elseif ( location == PDFITEMFLYOUT_PLACEINBAGS_LOCATION ) then
+ SetItemButtonTexture(button, "Interface\\PaperDollInfoFrame\\UI-GearManager-ItemIntoBag");
+ SetItemButtonCount(button, nil);
+ button.UpdateTooltip =
+ function ()
+ GameTooltip:SetOwner(PaperDollFrameItemFlyoutButtons, "ANCHOR_RIGHT", 6, -PaperDollFrameItemFlyoutButtons:GetHeight() - 6);
+ GameTooltip:SetText(EQUIPMENT_MANAGER_PLACE_IN_BAGS, 1.0, 1.0, 1.0);
+ if ( SHOW_NEWBIE_TIPS == "1" ) then
+ GameTooltip:AddLine(NEWBIE_TOOLTIP_EQUIPMENT_MANAGER_PLACE_IN_BAGS, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ end
+ GameTooltip:Show();
+ end;
+ SetItemButtonTextureVertexColor(button, 1.0, 1.0, 1.0);
+ SetItemButtonNormalTextureVertexColor(button, 1.0, 1.0, 1.0);
+ end
+ if ( button:IsMouseOver() and button.UpdateTooltip ) then
+ button.UpdateTooltip();
+ end
+end
+
+function PaperDollFrameItemFlyoutButton_OnEnter (self)
+ if ( self.UpdateTooltip ) then
+ self.UpdateTooltip(); -- This shows the tooltip, and gets called repeatedly thereafter by GameTooltip.
+ end
+end
+
+function PaperDollFrameItemFlyoutButton_OnClick (self)
+ if ( self.location == PDFITEMFLYOUT_IGNORESLOT_LOCATION ) then
+ local slot = PaperDollFrameItemFlyout.button;
+ EquipmentManagerIgnoreSlotForSave(slot:GetID());
+ slot.ignored = true;
+ PaperDollItemSlotButton_Update(slot);
+ PaperDollFrameItemFlyout_Show(slot);
+ elseif ( self.location == PDFITEMFLYOUT_UNIGNORESLOT_LOCATION ) then
+ local slot = PaperDollFrameItemFlyout.button;
+ EquipmentManagerUnignoreSlotForSave(slot:GetID());
+ slot.ignored = nil;
+ PaperDollItemSlotButton_Update(slot);
+ PaperDollFrameItemFlyout_Show(slot);
+ elseif ( self.location == PDFITEMFLYOUT_PLACEINBAGS_LOCATION ) then
+ if ( UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[PaperDollFrameItemFlyout.button:GetID()] ) then
+ UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
+ return;
+ end
+ local action = EquipmentManager_UnequipItemInSlot(PaperDollFrameItemFlyout.button:GetID());
+ EquipmentManager_RunAction(action);
+ elseif ( self.location ) then
+ if ( UnitAffectingCombat("player") and not INVSLOTS_EQUIPABLE_IN_COMBAT[PaperDollFrameItemFlyout.button:GetID()] ) then
+ UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
+ return;
+ end
+ local action = EquipmentManager_EquipItemByLocation(self.location, self.id);
+ EquipmentManager_RunAction(action);
+ end
+ if ( PaperDollFrameItemFlyout.button.popoutButton.flyoutLocked ) then
+ PaperDollFrameItemFlyout_Hide();
+ end
+end
+
+local popoutButtons = {}
+
+function PaperDollFrameItemPopoutButton_OnLoad(self)
+ tinsert(popoutButtons, self);
+end
+
+function PaperDollFrameItemPopoutButton_HideAll()
+ if ( PaperDollFrameItemFlyout.button and PaperDollFrameItemFlyout.button.popoutButton.flyoutLocked ) then
+ PaperDollFrameItemFlyout_Hide();
+ end
+ for _, button in pairs(popoutButtons) do
+ if ( button.flyoutLocked ) then
+ button.flyoutLocked = false;
+ PaperDollFrameItemFlyout_Hide();
+ PaperDollFrameItemPopoutButton_SetReversed(button, false);
+ end
+
+ button:Hide();
+ end
+end
+
+function PaperDollFrameItemPopoutButton_ShowAll()
+ for _, button in pairs(popoutButtons) do
+ button:Show();
+ end
+end
+
+function PaperDollFrameItemPopoutButton_OnClick(self)
+ if ( self.flyoutLocked ) then
+ self.flyoutLocked = false;
+ PaperDollFrameItemFlyout_Hide();
+ PaperDollFrameItemPopoutButton_SetReversed(self, false);
+ else
+ self.flyoutLocked = true;
+ PaperDollFrameItemFlyout_Show(self:GetParent());
+ PaperDollFrameItemPopoutButton_SetReversed(self, true);
+ end
+end
+
+function PaperDollFrameItemPopoutButton_SetReversed(self, isReversed)
+ if ( self:GetParent().verticalFlyout ) then
+ if ( isReversed ) then
+ self:GetNormalTexture():SetTexCoord(0.15625, 0.84375, 0, 0.5);
+ self:GetHighlightTexture():SetTexCoord(0.15625, 0.84375, 0.5, 1);
+ else
+ self:GetNormalTexture():SetTexCoord(0.15625, 0.84375, 0.5, 0);
+ self:GetHighlightTexture():SetTexCoord(0.15625, 0.84375, 1, 0.5);
+ end
+ else
+ if ( isReversed ) then
+ self:GetNormalTexture():SetTexCoord(0.15625, 0, 0.84375, 0, 0.15625, 0.5, 0.84375, 0.5);
+ self:GetHighlightTexture():SetTexCoord(0.15625, 0.5, 0.84375, 0.5, 0.15625, 1, 0.84375, 1);
+ else
+ self:GetNormalTexture():SetTexCoord(0.15625, 0.5, 0.84375, 0.5, 0.15625, 0, 0.84375, 0);
+ self:GetHighlightTexture():SetTexCoord(0.15625, 1, 0.84375, 1, 0.15625, 0.5, 0.84375, 0.5);
+ end
+ end
+end
+NUM_GEARSETS_PER_ROW = 5;
+
+function GearManagerDialog_OnLoad (self)
+ self.title:SetText(EQUIPMENT_MANAGER);
+ self.buttons = {};
+ local name = self:GetName();
+ local button;
+ for i = 1, MAX_EQUIPMENT_SETS_PER_PLAYER do
+ button = CreateFrame("CheckButton", "GearSetButton" .. i, self, "GearSetButtonTemplate");
+ if ( i == 1 ) then
+ button:SetPoint("TOPLEFT", self, "TOPLEFT", 16, -32);
+ elseif ( mod(i, NUM_GEARSETS_PER_ROW) == 1 ) then
+ button:SetPoint("TOP", "GearSetButton"..(i-NUM_GEARSETS_PER_ROW), "BOTTOM", 0, -10);
+ else
+ button:SetPoint("LEFT", "GearSetButton"..(i-1), "RIGHT", 13, 0);
+ end
+ button.icon = _G["GearSetButton" .. i .. "Icon"];
+ button.text = _G["GearSetButton" .. i .. "Name"];
+ tinsert(self.buttons, button);
+ end
+ self:RegisterEvent("VARIABLES_LOADED");
+ self:RegisterEvent("EQUIPMENT_SWAP_FINISHED");
+end
+
+function GearManagerDialog_OnShow (self)
+ CharacterFrame:SetAttribute("UIPanelLayout-defined", nil);
+ GearManagerToggleButton:SetButtonState("PUSHED", 1);
+ GearManagerDialog_Update();
+ self:RegisterEvent("EQUIPMENT_SETS_CHANGED");
+ EquipmentManagerClearIgnoredSlotsForSave();
+ PlaySound("igBackPackOpen");
+
+ PaperDollFrameItemPopoutButton_ShowAll();
+
+ UpdateUIPanelPositions(CharacterFrame);
+ GearManagerDialog:Raise();
+end
+
+function GearManagerDialog_OnHide (self)
+ CharacterFrame:SetAttribute("UIPanelLayout-defined", nil);
+ GearManagerDialogPopup:Hide();
+
+ GearManagerToggleButton:SetButtonState("NORMAL");
+ self:UnregisterEvent("EQUIPMENT_SETS_CHANGED");
+ PlaySound("igBackPackClose");
+ PaperDollFrame_ClearIgnoredSlots();
+
+ PaperDollFrameItemPopoutButton_HideAll();
+
+ UpdateUIPanelPositions();
+end
+
+function GearManagerDialog_OnEvent (self, event, ...)
+ if ( event == "EQUIPMENT_SETS_CHANGED" ) then
+ GearManagerDialog_Update();
+ elseif ( event == "VARIABLES_LOADED" ) then
+ if ( GetCVarBool("equipmentManager") ) then
+ GearManagerToggleButton:Show();
+ end
+ elseif ( event == "EQUIPMENT_SWAP_FINISHED" ) then
+ local completed, setName = ...;
+ if ( completed ) then
+ self.selectedSetName = setName;
+ GearManagerDialog_Update();
+ if ( self:IsShown() ) then
+ PaperDollFrame_ClearIgnoredSlots();
+ PaperDollFrame_IgnoreSlotsForSet(setName);
+ end
+ end
+ end
+end
+
+function GearManagerDialog_Update ()
+ local numSets = GetNumEquipmentSets();
+
+ local dialog = GearManagerDialog;
+ local buttons = dialog.buttons;
+
+ local selectedName = dialog.selectedSetName;
+ local name, texture, button;
+ dialog.selectedSet = nil;
+ for i = 1, numSets do
+ name, texture = GetEquipmentSetInfo(i);
+ button = buttons[i];
+ button:Enable();
+ button.name = name;
+ button.text:SetText(name);
+ if (texture) then
+ button.icon:SetTexture(texture);
+ else
+ button.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark");
+ end
+ if (selectedName and button.name == selectedName) then
+ button:SetChecked(true);
+ dialog.selectedSet = button;
+ else
+ button:SetChecked(false);
+ end
+ end
+ if ( dialog.selectedSet ) then
+ GearManagerDialogDeleteSet:Enable();
+ GearManagerDialogEquipSet:Enable();
+ else
+ GearManagerDialogDeleteSet:Disable();
+ GearManagerDialogEquipSet:Disable();
+ end
+
+ for i = numSets + 1, MAX_EQUIPMENT_SETS_PER_PLAYER do
+ button = buttons[i];
+ button:Disable();
+ button:SetChecked(false);
+ button.name = nil;
+ button.text:SetText("");
+ button.icon:SetTexture("");
+ end
+ if(GearManagerDialogPopup:IsShown()) then
+ RecalculateGearManagerDialogPopup(); --Scroll so that the texture appears and Save is enabled
+ end
+end
+
+function GearManagerDialogDeleteSet_OnClick (self)
+ local selectedSet = GearManagerDialog.selectedSet;
+ if ( selectedSet ) then
+ local dialog = StaticPopup_Show("CONFIRM_DELETE_EQUIPMENT_SET", selectedSet.name);
+ if ( dialog ) then
+ dialog.data = selectedSet.name;
+ else
+ UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
+ end
+ end
+end
+
+function GearManagerDialogSaveSet_OnClick (self)
+ local popup = GearManagerDialogPopup;
+ local wasShown = popup:IsShown();
+ popup:Show();
+ if ( wasShown ) then --If the dialog was already shown, the OnShow script will not run and the icon will not be updated (Bug 169523)
+ GearManagerDialogPopup_Update();
+ end
+end
+
+function GearManagerDialogEquipSet_OnClick (self)
+ local selectedSet = GearManagerDialog.selectedSet;
+ if ( selectedSet ) then
+ local name = selectedSet.name;
+ if ( name and name ~= "" ) then
+ PlaySound("igCharacterInfoTab"); -- inappropriately named, but a good sound.
+ EquipmentManager_EquipSet(name);
+ end
+ end
+end
+
+function GearSetButton_OnClick (self)
+ --[[
+ Select the new gear set
+ ]]
+ if ( self.name and self.name ~= "" ) then
+ PlaySound("igMainMenuOptionCheckBoxOn"); -- inappropriately named, but a good sound.
+ local dialog = GearManagerDialog;
+ dialog.selectedSetName = self.name;
+ GearManagerDialog_Update(); --change selection, enable one equip button, disable rest.
+ else
+ self:SetChecked(false);
+ end
+end
+
+function GearSetButton_OnEnter (self)
+ if ( self.name and self.name ~= "" ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ GameTooltip:SetEquipmentSet(self.name);
+ end
+end
+
+NUM_GEARSET_ICONS_SHOWN = 15;
+NUM_GEARSET_ICONS_PER_ROW = 5;
+NUM_GEARSET_ICON_ROWS = 3;
+GEARSET_ICON_ROW_HEIGHT = 36;
+
+function GearManagerDialogPopup_OnLoad (self)
+ self.buttons = {};
+
+ local rows = 0;
+
+ local button = CreateFrame("CheckButton", "GearManagerDialogPopupButton1", GearManagerDialogPopup, "GearSetPopupButtonTemplate");
+ button:SetPoint("TOPLEFT", 24, -85);
+ button:SetID(1);
+ tinsert(self.buttons, button);
+
+ local lastPos;
+ for i = 2, NUM_GEARSET_ICONS_SHOWN do
+ button = CreateFrame("CheckButton", "GearManagerDialogPopupButton" .. i, GearManagerDialogPopup, "GearSetPopupButtonTemplate");
+ button:SetID(i);
+
+ lastPos = (i - 1) / NUM_GEARSET_ICONS_PER_ROW;
+ if ( lastPos == math.floor(lastPos) ) then
+ button:SetPoint("TOPLEFT", self.buttons[i-NUM_GEARSET_ICONS_PER_ROW], "BOTTOMLEFT", 0, -8);
+ else
+ button:SetPoint("TOPLEFT", self.buttons[i-1], "TOPRIGHT", 10, 0);
+ end
+ tinsert(self.buttons, button);
+ end
+
+ self.SetSelection = function(self, fTexture, Value)
+ if(fTexture) then
+ self.selectedTexture = Value;
+ self.selectedIcon = nil;
+ else
+ self.selectedTexture = nil;
+ self.selectedIcon = Value;
+ end
+ end
+end
+
+local _equippedItems = {};
+local _numItems;
+local _specialIcon;
+local _TotalItems;
+
+function GearManagerDialogPopup_OnShow (self)
+ PlaySound("igCharacterInfoOpen");
+ RecalculateGearManagerDialogPopup();
+ GearManagerDialogSaveSet:Disable();
+end
+
+function GearManagerDialogPopup_OnHide (self)
+ local popup = GearManagerDialogPopup;
+ popup.name = nil;
+ popup:SetSelection(true, nil);
+ GearManagerDialogPopupEditBox:SetText("");
+ GearManagerDialogSaveSet:Enable();
+end
+
+function RecalculateGearManagerDialogPopup()
+ local popup = GearManagerDialogPopup;
+ local selectedSet = GearManagerDialog.selectedSet;
+ if ( selectedSet ) then
+ popup:SetSelection(true, selectedSet.icon:GetTexture());
+ local editBox = GearManagerDialogPopupEditBox;
+ editBox:SetText(selectedSet.name);
+ editBox:HighlightText(0);
+ end
+ --[[
+ Scroll and ensure that any selected equipment shows up in the list.
+ When we first press "save", we want to make sure any selected equipment set shows up in the list, so that
+ the user can just make his changes and press Okay to overwrite.
+ To do this, we need to find the current set (by icon) and move the offset of the GearManagerDialogPopup
+ to display it. Issue ID: 171220
+ ]]
+ RefreshEquipmentSetIconInfo();
+ _TotalItems = GetNumMacroIcons() + _numItems;
+ _specialIcon = nil;
+ local texture;
+ if(popup.selectedTexture) then
+ local index = 1;
+ local foundIndex = nil;
+ for index=1, _TotalItems do
+ texture, _ = GetEquipmentSetIconInfo(index);
+ if ( texture == popup.selectedTexture ) then
+ foundIndex = index;
+ break;
+ end
+ end
+ if (foundIndex == nil) then
+ _specialIcon = popup.selectedTexture;
+ _TotalItems = _TotalItems + 1;
+ foundIndex = _TotalItems;
+ else
+ _specialIcon = nil;
+ end
+ -- now make it so we always display at least NUM_GEARSET_ICON_ROWS of data
+ local offsetnumIcons = floor((_TotalItems-1)/NUM_GEARSET_ICONS_PER_ROW);
+ local offset = floor((foundIndex-1) / NUM_GEARSET_ICONS_PER_ROW);
+ offset = offset + min((NUM_GEARSET_ICON_ROWS-1), offsetnumIcons-offset) - (NUM_GEARSET_ICON_ROWS-1);
+ if(foundIndex<=NUM_GEARSET_ICONS_SHOWN) then
+ offset = 0; --Equipment all shows at the same place.
+ end
+ FauxScrollFrame_OnVerticalScroll(GearManagerDialogPopupScrollFrame, offset*GEARSET_ICON_ROW_HEIGHT, GEARSET_ICON_ROW_HEIGHT, nil);
+ end
+ GearManagerDialogPopup_Update();
+end
+
+--[[
+RefreshEquipmentSetIconInfo() counts how many uniquely textured inventory items the player has equipped.
+]]
+function RefreshEquipmentSetIconInfo ()
+ _numItems = 0;
+ for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
+ _equippedItems[i] = GetInventoryItemTexture("player", i);
+ if(_equippedItems[i]) then
+ _numItems = _numItems + 1;
+ --[[
+ Currently checks all for duplicates, even though only rings, trinkets, and weapons may be duplicated.
+ This version is clean and maintainable.
+ ]]
+ for j=INVSLOT_FIRST_EQUIPPED, (i-1) do
+ if(_equippedItems[i] == _equippedItems[j]) then
+ _equippedItems[i] = nil;
+ _numItems = _numItems - 1;
+ break;
+ end
+ end
+ end
+ end
+end
+
+
+--[[
+GetEquipmentSetIconInfo(index) determines the texture and real index of a regular index
+ Input: index = index into a list of equipped items follows by the macro items. Only tricky part is the equipped items list keeps changing.
+ Output: the associated texture for the item, and a index relative to the join point between the lists, i.e. negative for the equipped items
+ and positive from the equipped items for the macro items//
+]]
+function GetEquipmentSetIconInfo(index)
+ for i = INVSLOT_FIRST_EQUIPPED, INVSLOT_LAST_EQUIPPED do
+ if (_equippedItems[i]) then
+ index = index - 1;
+ if ( index == 0 ) then
+ return _equippedItems[i], -i;
+ end
+ end
+ end
+ if(index>GetNumMacroIcons()) then
+ return _specialIcon, index;
+ end
+ return GetMacroIconInfo(index), index;
+end
+
+function GearManagerDialogPopup_Update ()
+ RefreshEquipmentSetIconInfo();
+
+ local popup = GearManagerDialogPopup;
+ local buttons = popup.buttons;
+ local offset = FauxScrollFrame_GetOffset(GearManagerDialogPopupScrollFrame) or 0;
+ local button;
+ -- Icon list
+ local texture, index, button, realIndex;
+ for i=1, NUM_GEARSET_ICONS_SHOWN do
+ local button = buttons[i];
+ index = (offset * NUM_GEARSET_ICONS_PER_ROW) + i;
+ if ( index <= _TotalItems ) then
+ texture, _ = GetEquipmentSetIconInfo(index);
+ -- button.name:SetText(index); --dcw
+ button.icon:SetTexture(texture);
+ button:Show();
+ if ( index == popup.selectedIcon ) then
+ button:SetChecked(1);
+ elseif ( texture == popup.selectedTexture ) then
+ button:SetChecked(1);
+ popup:SetSelection(false, index);
+ else
+ button:SetChecked(nil);
+ end
+ else
+ button.icon:SetTexture("");
+ button:Hide();
+ end
+
+ end
+
+ -- Scrollbar stuff
+ FauxScrollFrame_Update(GearManagerDialogPopupScrollFrame, ceil(_TotalItems / NUM_GEARSET_ICONS_PER_ROW) , NUM_GEARSET_ICON_ROWS, GEARSET_ICON_ROW_HEIGHT );
+end
+
+function GearManagerDialogPopupOkay_Update ()
+ local popup = GearManagerDialogPopup;
+ local button = GearManagerDialogPopupOkay;
+
+ if ( popup.selectedIcon and popup.name ) then
+ button:Enable();
+ else
+ button:Disable();
+ end
+end
+
+function GearManagerDialogPopupOkay_OnClick (self, button, pushed)
+ local popup = GearManagerDialogPopup;
+
+ local _, iconIndex = GetEquipmentSetIconInfo(popup.selectedIcon);
+
+ if ( GetEquipmentSetInfoByName(popup.name) ) then
+ local dialog = StaticPopup_Show("CONFIRM_OVERWRITE_EQUIPMENT_SET", popup.name);
+ if ( dialog ) then
+ dialog.data = popup.name;
+ dialog.selectedIcon = iconIndex;
+ else
+ UIErrorsFrame:AddMessage(ERR_CLIENT_LOCKED_OUT, 1.0, 0.1, 0.1, 1.0);
+ end
+ return;
+ elseif ( GetNumEquipmentSets() >= MAX_EQUIPMENT_SETS_PER_PLAYER ) then
+ UIErrorsFrame:AddMessage(EQUIPMENT_SETS_TOO_MANY, 1.0, 0.1, 0.1, 1.0);
+ return
+ end
+
+ SaveEquipmentSet(popup.name, iconIndex);
+ GearManagerDialogPopup:Hide();
+end
+
+function GearManagerDialogPopupCancel_OnClick ()
+ GearManagerDialogPopup:Hide();
+end
+
+function GearSetPopupButton_OnClick (self, button)
+ local popup = GearManagerDialogPopup;
+ local offset = FauxScrollFrame_GetOffset(GearManagerDialogPopupScrollFrame) or 0;
+ popup.selectedIcon = (offset * NUM_GEARSET_ICONS_PER_ROW) + self:GetID();
+ popup.selectedTexture = nil;
+ GearManagerDialogPopup_Update();
+ GearManagerDialogPopupOkay_Update();
+end
+
+function PlayerTitlePickerScrollFrame_OnLoad(self)
+ PlayerTitlePickerFrame:SetFrameLevel(self:GetParent():GetFrameLevel() + 2);
+ PlayerTitlePickerScrollFrame:SetHeight(PLAYER_DISPLAYED_TITLES * PLAYER_TITLE_HEIGHT);
+ HybridScrollFrame_OnLoad(self);
+ self.update = PlayerTitlePickerScrollFrame_Update;
+ HybridScrollFrame_CreateButtons(self, "PlayerTitleButtonTemplate");
+end
+
+function PlayerTitlePickerScrollFrame_Update()
+ local buttons = PlayerTitlePickerScrollFrame.buttons;
+ local playerTitles = PlayerTitleFrame.titles;
+ local numButtons = #buttons;
+ local scrollOffset = HybridScrollFrame_GetOffset(PlayerTitlePickerScrollFrame);
+ local playerTitle;
+ for i = 1, numButtons do
+ playerTitle = playerTitles[i + scrollOffset];
+ if ( playerTitle ) then
+ buttons[i].text:SetText(playerTitle.name);
+ buttons[i].titleId = playerTitle.id;
+ if ( PlayerTitleFrame.selected == playerTitle.id ) then
+ buttons[i].check:Show();
+ else
+ buttons[i].check:Hide();
+ end
+ end
+ end
+end
+
+local function PlayerTitleSort(a, b) return a.name < b.name; end
+
+function PlayerTitleFrame_UpdateTitles()
+ local playerTitles = { };
+ local currentTitle = GetCurrentTitle();
+ local titleCount = 1;
+ local buttons = PlayerTitlePickerScrollFrame.buttons;
+ local fontstringText = buttons[1].text;
+ local fontstringWidth;
+ local maxWidth = 0;
+ PlayerTitleFrame.selected = -1;
+ playerTitles[1] = { };
+ -- reserving space for None so it doesn't get sorted out of the top position
+ playerTitles[1].name = " ";
+ playerTitles[1].id = -1;
+ for i = 1, GetNumTitles() do
+ if ( IsTitleKnown(i) ~= 0 ) then
+ titleCount = titleCount + 1;
+ playerTitles[titleCount] = playerTitles[titleCount] or { };
+ playerTitles[titleCount].name = strtrim(GetTitleName(i));
+ playerTitles[titleCount].id = i;
+ if ( i == currentTitle ) then
+ PlayerTitleFrame.selected = i;
+ end
+ fontstringText:SetText(playerTitles[titleCount].name);
+ fontstringWidth = fontstringText:GetWidth();
+ if ( fontstringWidth > maxWidth ) then
+ maxWidth = fontstringWidth;
+ end
+ end
+ end
+ if ( titleCount < 2 ) then
+ PlayerTitleFrame:Hide();
+ PlayerTitlePickerFrame:Hide();
+ else
+ PlayerTitleFrame:Show()
+ if ( currentTitle == 0 ) then
+ PlayerTitleFrameText:SetText(PAPERDOLL_SELECT_TITLE);
+ elseif ( currentTitle == -1 ) then
+ PlayerTitleFrameText:SetText(NONE);
+ else
+ PlayerTitleFrameText:SetText(GetTitleName(currentTitle));
+ end
+ table.sort(playerTitles, PlayerTitleSort);
+ playerTitles[1].name = NONE;
+ PlayerTitleFrame.titles = playerTitles;
+
+ maxWidth = maxWidth + 10;
+ for i = 1, #buttons do
+ buttons[i]:SetWidth(maxWidth);
+ end
+ PlayerTitlePickerScrollFrame:SetWidth(maxWidth + 34);
+ PlayerTitlePickerScrollFrameScrollChild:SetWidth(maxWidth + 34);
+ if ( titleCount <= PLAYER_DISPLAYED_TITLES ) then
+ PlayerTitlePickerFrame:SetWidth(maxWidth + 56);
+ PlayerTitlePickerFrame:SetHeight(titleCount * PLAYER_TITLE_HEIGHT + 26);
+ -- adding 1 due to possible rounding errors in HybridScrollFrame
+ PlayerTitlePickerScrollFrame:SetHeight(titleCount * PLAYER_TITLE_HEIGHT + 1);
+ else
+ PlayerTitlePickerFrame:SetWidth(maxWidth + 76);
+ PlayerTitlePickerFrame:SetHeight(PLAYER_TITLE_HEIGHT * PLAYER_DISPLAYED_TITLES + 26);
+ -- adding 1 due to possible rounding errors in HybridScrollFrame
+ PlayerTitlePickerScrollFrame:SetHeight(PLAYER_TITLE_HEIGHT * PLAYER_DISPLAYED_TITLES + 1);
+ end
+ HybridScrollFrame_CreateButtons(PlayerTitlePickerScrollFrame, "PlayerTitleButtonTemplate");
+ HybridScrollFrame_Update(PlayerTitlePickerScrollFrame, titleCount * PLAYER_TITLE_HEIGHT, PlayerTitlePickerScrollFrame:GetHeight());
+ PlayerTitlePickerScrollFrame_Update();
+ end
+end
+
+function PlayerTitlePickerFrame_Toggle()
+ if ( PlayerTitlePickerFrame:IsShown() ) then
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ PlayerTitlePickerFrame:Hide();
+ else
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ PlayerTitlePickerFrame:Show();
+ PlayerTitlePickerScrollFrame_Update();
+ end
+end
+
+function PlayerTitleButton_OnClick(self)
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ PlayerTitleFrame.selected = self.titleId;
+ SetCurrentTitle(self.titleId);
+ PlayerTitleFrameText:SetText(self.text:GetText());
+ PlayerTitlePickerFrame:Hide();
+end
+
+function SetTitleByName(name)
+ name = strlower(name);
+ for i = 1, GetNumTitles() do
+ if ( IsTitleKnown(i) ~= 0 ) then
+ local title = strlower(strtrim(GetTitleName(i)));
+ if(title:find(name) == 1) then
+ SetCurrentTitle(i);
+ return true;
+ end
+ end
+ end
+ return false;
+end
+
diff --git a/reference/FrameXML/PaperDollFrame.xml b/reference/FrameXML/PaperDollFrame.xml
new file mode 100644
index 0000000..e69b0d5
--- /dev/null
+++ b/reference/FrameXML/PaperDollFrame.xml
@@ -0,0 +1,1490 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollFrameItemPopoutButton_OnLoad(self);
+
+
+ PaperDollFrameItemPopoutButton_OnClick(self);
+
+
+
+
+
+
+
+
+ PaperDollItemSlotButton_OnLoad(self);
+
+
+ PaperDollItemSlotButton_OnEvent(self, event, ...);
+
+
+ PaperDollItemSlotButton_OnShow(self);
+
+
+ PaperDollItemSlotButton_OnHide(self);
+
+
+ if ( IsModifiedClick() ) then
+ PaperDollItemSlotButton_OnModifiedClick(self, button);
+ else
+ PaperDollItemSlotButton_OnClick(self, button);
+ end
+
+
+ PaperDollItemSlotButton_OnClick(self, "LeftButton");
+
+
+ PaperDollItemSlotButton_OnClick(self, "LeftButton");
+
+
+ PaperDollItemSlotButton_OnEnter(self, motion);
+
+
+ PaperDollItemSlotButton_OnLeave(self, motion);
+
+
+
+
+
+
+
+
+
+ PaperDollFrameItemFlyoutButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ PaperDollFrameItemFlyoutButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlayerTitleButton_OnClick(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForDrag("LeftButton");
+
+
+ GearSetButton_OnClick(self, button, down);
+
+
+ GearSetButton_OnEnter(self);
+
+
+ GameTooltip:Hide();
+
+
+ if ( self.name and self.name ~= "" ) then
+ PickupEquipmentSetByName(self.name);
+ end
+
+
+
+
+
+
+
+ local name = self:GetName();
+ self.icon = _G[name .. "Icon"];
+ self.name = _G[name .. "Name"];
+
+
+ GearSetPopupButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip(self, "player");
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+ if ( self.tooltip ) then
+ GameTooltip:SetOwner(self,"ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip, 1.0,1.0,1.0);
+ GameTooltip:AddLine(self.tooltipSubtext, NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b, 1);
+ GameTooltip:Show();
+ end
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlayerTitlePickerFrame_Toggle();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Model_OnLoad(self);
+ self:RegisterEvent("DISPLAY_SIZE_CHANGED");
+
+
+ self:RefreshUnit();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateLeft(self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateRight(self:GetParent());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.maxDisplayCount = 999;
+ PaperDollItemSlotButton_OnLoad(self);
+
+
+ if ( event == "MERCHANT_UPDATE" ) then
+ -- update ammo amount shown in frame after selling ammo to a vendor
+ PaperDollItemSlotButton_Update(self);
+ elseif ( event == "PLAYERBANKSLOTS_CHANGED" ) then
+ -- update ammo amount shown in frame after moving ammo to the bank
+ PaperDollItemSlotButton_Update(self);
+ else
+ PaperDollItemSlotButton_OnEvent(self, event, ...);
+ end
+
+
+ PaperDollItemSlotButton_OnShow(self);
+ self:RegisterEvent("MERCHANT_UPDATE");
+ self:RegisterEvent("PLAYERBANKSLOTS_CHANGED");
+
+
+ PaperDollItemSlotButton_OnHide(self);
+ self:UnregisterEvent("MERCHANT_UPDATE");
+ self:UnregisterEvent("PLAYERBANKSLOTS_CHANGED");
+
+
+
+ PaperDollItemSlotButton_OnClick(self, "LeftButton", 1);
+
+
+ PaperDollItemSlotButton_OnClick(self, "LeftButton", 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, EQUIPMENT_MANAGER, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_EQUIPMENT_MANAGER);
+
+
+
+ self.icon = _G[self:GetName() .. "Icon"];
+
+
+ if ( GearManagerDialog:IsShown() ) then
+ GearManagerDialog:Hide();
+ else
+ GearManagerDialog:Show();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.numBGs = 1;
+
+
+
+
+
+
+ self.buttons = {};
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, GEARSET_ICON_ROW_HEIGHT, GearManagerDialogPopup_Update);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local text = self:GetText();
+ if ( text ~= "" ) then
+ GearManagerDialogPopup.name = text;
+ else
+ GearManagerDialogPopup.name = nil;
+ end
+
+ GearManagerDialogPopupOkay_Update();
+
+
+
+ if ( GearManagerDialogPopupOkay:IsEnabled() ~= 0 ) then
+ GearManagerDialogPopupOkay:Click();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GearManagerDialogPopupCancel_OnClick(self, button, pushed);
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+
+
+
+
+
+ GearManagerDialogPopupOkay_OnClick(self, button, pushed);
+ PlaySound("gsTitleOptionOK");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/PartyFrame.xml b/reference/FrameXML/PartyFrame.xml
new file mode 100644
index 0000000..a691453
--- /dev/null
+++ b/reference/FrameXML/PartyFrame.xml
@@ -0,0 +1,328 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("VARIABLES_LOADED");
+
+
+ self:SetFrameLevel(1);
+
+
+ if ( event == "VARIABLES_LOADED" ) then
+ UpdatePartyMemberBackground();
+ OpacityFrameSlider:SetValue(tonumber(GetCVar("partyBackgroundOpacity")));
+ PartyMemberBackground_SetOpacity();
+ end
+
+
+ if ( button == "RightButton" ) then
+ PartyMemberBackground_ToggleOpacity();
+ end
+
+
+
+
+
diff --git a/reference/FrameXML/PartyFrameTemplates.xml b/reference/FrameXML/PartyFrameTemplates.xml
new file mode 100644
index 0000000..cade303
--- /dev/null
+++ b/reference/FrameXML/PartyFrameTemplates.xml
@@ -0,0 +1,617 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetUnitBuff("party"..self:GetParent():GetID(), self:GetID());
+ end
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetUnitBuff("party"..self:GetParent():GetID(), self:GetID());
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetUnitDebuff("party"..self:GetParent():GetID(), self:GetID());
+ end
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetUnitDebuff("party"..self:GetParent():GetID(), self:GetID());
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:SetUnitDebuff("partypet"..self:GetParent():GetID(), self:GetID());
+ end
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetUnitDebuff("partypet"..self:GetParent():GetParent():GetID(), self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UnitFrameHealthBar_OnValueChanged(self, value);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local id = self:GetParent():GetID();
+ local prefix = "PartyMemberFrame"..id.."PetFrame";
+ local unit = "partypet"..id;
+ UnitFrame_Initialize(self, unit, _G[prefix.."Name"], _G[prefix.."Portrait"],
+ _G[prefix.."HealthBar"], _G[prefix.."HealthBarText"],
+ nil, nil, _G[prefix.."Flash"]);
+ SetTextStatusBarTextZeroText(_G[prefix.."HealthBar"], DEAD);
+ _G[prefix.."Name"]:Hide();
+ SecureUnitButton_OnLoad(self, unit);
+
+
+ UnitFrame_Update(self);
+
+
+ UnitFrame_OnEvent(self, event, ...);
+
+
+ UnitFrame_OnEnter(self, motion);
+
+
+ UnitFrame_OnLeave(self, motion);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PartyFrameDropDown_OnLoad(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ self.textLockable = 1;
+ self.cvar = "partyStatusText";
+ self.cvarLabel = "STATUS_TEXT_PARTY";
+
+
+ self:GetParent():Click(button);
+
+
+ PartyMemberHealthCheck(self, value);
+ UnitFrameHealthBar_OnValueChanged(self, value);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ self.textLockable = 1;
+ self.cvar = "partyStatusText";
+ self.cvarLabel = "STATUS_TEXT_PARTY";
+
+
+ self:GetParent():Click(button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaiseFrameLevelByTwo(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ VoiceChat_OnUpdate(self, elapsed);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaiseFrameLevelByTwo(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local id = self:GetID();
+ self.debuffCountdown = 0;
+ self.numDebuffs = 0;
+ self.noTextPrefix = true;
+ local prefix = "PartyMemberFrame"..id;
+ UnitFrame_Initialize(self, "party"..id, _G[prefix.."Name"], _G[prefix.."Portrait"],
+ _G[prefix.."HealthBar"], _G[prefix.."HealthBarText"],
+ _G[prefix.."ManaBar"], _G[prefix.."ManaBarText"],
+ _G[prefix.."Flash"]);
+ SetTextStatusBarTextZeroText(_G[prefix.."HealthBar"], DEAD);
+ PartyMemberFrame_OnLoad(self);
+
+
+ self:SetFrameLevel(2);
+
+
+ PartyMemberFrame_OnEvent(self, event, ...);
+
+
+ UnitFrame_OnEnter(self);
+ PartyMemberBuffTooltip:SetPoint("TOPLEFT", self, "TOPLEFT", 47, -30);
+ PartyMemberBuffTooltip_Update(self);
+
+
+ UnitFrame_OnLeave(self);
+ PartyMemberBuffTooltip:Hide();
+
+
+ PartyMemberFrame_OnUpdate(self, elapsed);
+
+
+
+
diff --git a/reference/FrameXML/PartyMemberFrame.lua b/reference/FrameXML/PartyMemberFrame.lua
new file mode 100644
index 0000000..7c3a95c
--- /dev/null
+++ b/reference/FrameXML/PartyMemberFrame.lua
@@ -0,0 +1,626 @@
+MAX_PARTY_MEMBERS = 4;
+MAX_PARTY_BUFFS = 4;
+MAX_PARTY_DEBUFFS = 4;
+MAX_PARTY_TOOLTIP_BUFFS = 16;
+MAX_PARTY_TOOLTIP_DEBUFFS = 8;
+
+function HidePartyFrame()
+ for i=1, MAX_PARTY_MEMBERS, 1 do
+ _G["PartyMemberFrame"..i]:Hide();
+ end
+end
+
+function ShowPartyFrame()
+ for i=1, MAX_PARTY_MEMBERS, 1 do
+ if ( GetPartyMember(i) ) then
+ _G["PartyMemberFrame"..i]:Show();
+ end
+ end
+end
+
+function PartyMemberFrame_UpdateArt(self)
+ local unit = "party"..self:GetID();
+ if ( UnitHasVehicleUI(unit) and UnitIsConnected(unit) ) then
+ local vehicleType = UnitVehicleSkin(unit);
+ PartyMemberFrame_ToVehicleArt(self, vehicleType);
+ else
+ PartyMemberFrame_ToPlayerArt(self);
+ end
+end
+
+function PartyMemberFrame_ToPlayerArt(self)
+ self.state = "player";
+ local prefix = self:GetName();
+ _G[prefix.."VehicleTexture"]:Hide();
+ _G[prefix.."Texture"]:Show();
+ _G[prefix.."Portrait"]:SetPoint("TOPLEFT", 7, -6);
+ _G[prefix.."LeaderIcon"]:SetPoint("TOPLEFT", 0, 0);
+ _G[prefix.."MasterIcon"]:SetPoint("TOPLEFT", 32, 0);
+ _G[prefix.."PVPIcon"]:SetPoint("TOPLEFT", -9, -15);
+ _G[prefix.."Disconnect"]:SetPoint("LEFT", -7, -1);
+
+ self.overrideName = nil;
+
+ UnitFrame_SetUnit(self, "party"..self:GetID(), _G[prefix.."HealthBar"], _G[prefix.."ManaBar"]);
+ UnitFrame_SetUnit(_G[prefix.."PetFrame"], "partypet"..self:GetID(), _G[prefix.."PetFrameHealthBar"], nil);
+ PartyMemberFrame_UpdateMember(self);
+
+ UnitFrame_Update(self)
+end
+
+function PartyMemberFrame_ToVehicleArt(self, vehicleType)
+ self.state = "vehicle";
+ local prefix = self:GetName();
+ _G[prefix.."Texture"]:Hide();
+ if ( vehicleType == "Natural" ) then
+ _G[prefix.."VehicleTexture"]:SetTexture("Interface\\Vehicles\\UI-Vehicles-PartyFrame-Organic");
+ else
+ _G[prefix.."VehicleTexture"]:SetTexture("Interface\\Vehicles\\UI-Vehicles-PartyFrame");
+ end
+ _G[prefix.."VehicleTexture"]:Show();
+ _G[prefix.."Portrait"]:SetPoint("TOPLEFT", 4, -9);
+ _G[prefix.."LeaderIcon"]:SetPoint("TOPLEFT", -3, 0);
+ _G[prefix.."MasterIcon"]:SetPoint("TOPLEFT", 29, 0);
+ _G[prefix.."PVPIcon"]:SetPoint("TOPLEFT", -12, -15);
+ _G[prefix.."Disconnect"]:SetPoint("LEFT", -10, -1);
+
+ self.overrideName = "party"..self:GetID();
+
+ UnitFrame_SetUnit(self, "partypet"..self:GetID(), _G[prefix.."HealthBar"], _G[prefix.."ManaBar"]);
+ UnitFrame_SetUnit(_G[prefix.."PetFrame"], "party"..self:GetID(), _G[prefix.."PetFrameHealthBar"], nil);
+ PartyMemberFrame_UpdateMember(self);
+
+ UnitFrame_Update(self)
+end
+
+function PartyMemberFrame_OnLoad (self)
+ self.statusCounter = 0;
+ self.statusSign = -1;
+ self.unitHPPercent = 1;
+ PartyMemberFrame_UpdateMember(self);
+ PartyMemberFrame_UpdateLeader(self);
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("PARTY_LEADER_CHANGED");
+ self:RegisterEvent("PARTY_LOOT_METHOD_CHANGED");
+ self:RegisterEvent("MUTELIST_UPDATE");
+ self:RegisterEvent("IGNORELIST_UPDATE");
+ self:RegisterEvent("UNIT_FACTION");
+ self:RegisterEvent("UNIT_AURA");
+ self:RegisterEvent("UNIT_PET");
+ self:RegisterEvent("VOICE_START");
+ self:RegisterEvent("VOICE_STOP");
+ self:RegisterEvent("VARIABLES_LOADED");
+ self:RegisterEvent("VOICE_STATUS_UPDATE");
+ self:RegisterEvent("READY_CHECK");
+ self:RegisterEvent("READY_CHECK_CONFIRM");
+ self:RegisterEvent("READY_CHECK_FINISHED");
+ self:RegisterEvent("UNIT_ENTERED_VEHICLE");
+ self:RegisterEvent("UNIT_EXITED_VEHICLE");
+ self:RegisterEvent("UNIT_HEALTH");
+
+ local showmenu = function()
+ ToggleDropDownMenu(1, nil, _G["PartyMemberFrame"..self:GetID().."DropDown"], self:GetName(), 47, 15);
+ end
+ SecureUnitButton_OnLoad(self, "party"..self:GetID(), showmenu);
+
+ PartyMemberFrame_UpdateArt(self);
+end
+
+function PartyMemberFrame_UpdateMember (self)
+ if ( HIDE_PARTY_INTERFACE == "1" and GetNumRaidMembers() > 0 ) then
+ self:Hide();
+ return;
+ end
+ local id = self:GetID();
+ if ( GetPartyMember(id) ) then
+ self:Show();
+
+ UnitFrame_Update(self);
+
+ local masterIcon = _G[self:GetName().."MasterIcon"];
+ local lootMethod;
+ local lootMaster;
+ lootMethod, lootMaster = GetLootMethod();
+ if ( id == lootMaster ) then
+ masterIcon:Show();
+ else
+ masterIcon:Hide();
+ end
+ else
+ self:Hide();
+ end
+ PartyMemberFrame_UpdatePet(self);
+ PartyMemberFrame_UpdatePvPStatus(self);
+ RefreshDebuffs(self, "party"..id);
+ PartyMemberFrame_UpdateVoiceStatus(self);
+ PartyMemberFrame_UpdateReadyCheck(self);
+ PartyMemberFrame_UpdateOnlineStatus(self);
+ UpdatePartyMemberBackground();
+end
+
+function PartyMemberFrame_UpdatePet (self, id)
+ if ( not id ) then
+ id = self:GetID();
+ end
+
+ local frameName = "PartyMemberFrame"..id;
+ local petFrame = _G["PartyMemberFrame"..id.."PetFrame"];
+
+ if ( UnitIsConnected("party"..id) and UnitExists("partypet"..id) and SHOW_PARTY_PETS == "1" ) then
+ petFrame:Show();
+ petFrame:SetPoint("TOPLEFT", frameName, "TOPLEFT", 23, -43);
+ else
+ petFrame:Hide();
+ petFrame:SetPoint("TOPLEFT", frameName, "TOPLEFT", 23, -27);
+ end
+
+ PartyMemberFrame_RefreshPetDebuffs(self, id);
+ UpdatePartyMemberBackground();
+end
+
+function PartyMemberFrame_UpdateMemberHealth (self, elapsed)
+ if ( (self.unitHPPercent > 0) and (self.unitHPPercent <= 0.2) ) then
+ local alpha = 255;
+ local counter = self.statusCounter + elapsed;
+ local sign = self.statusSign;
+
+ if ( counter > 0.5 ) then
+ sign = -sign;
+ self.statusSign = sign;
+ end
+ counter = mod(counter, 0.5);
+ self.statusCounter = counter;
+
+ if ( sign == 1 ) then
+ alpha = (127 + (counter * 256)) / 255;
+ else
+ alpha = (255 - (counter * 256)) / 255;
+ end
+ _G[self:GetName().."Portrait"]:SetAlpha(alpha);
+ end
+end
+
+function PartyMemberFrame_UpdateLeader (self)
+ local id = self:GetID();
+ local leaderIcon = _G["PartyMemberFrame"..id.."LeaderIcon"];
+ local guideIcon = _G["PartyMemberFrame"..id.."GuideIcon"];
+
+ if( GetPartyLeaderIndex() == id ) then
+ if ( HasLFGRestrictions() ) then
+ guideIcon:Show();
+ leaderIcon:Hide();
+ else
+ leaderIcon:Show();
+ guideIcon:Hide();
+ end
+ else
+ guideIcon:Hide();
+ leaderIcon:Hide();
+ end
+end
+
+function PartyMemberFrame_UpdatePvPStatus (self)
+ local id = self:GetID();
+ local unit = "party"..id;
+ local icon = _G["PartyMemberFrame"..id.."PVPIcon"];
+ local factionGroup = UnitFactionGroup(unit);
+ if ( UnitIsPVPFreeForAll(unit) ) then
+ icon:SetTexture("Interface\\TargetingFrame\\UI-PVP-FFA");
+ icon:Show();
+ elseif ( factionGroup and UnitIsPVP(unit) ) then
+ icon:SetTexture("Interface\\GroupFrame\\UI-Group-PVP-"..factionGroup);
+ icon:Show();
+ else
+ icon:Hide();
+ end
+end
+
+function PartyMemberFrame_UpdateAssignedRoles (self)
+ local id = self:GetID();
+ local unit = "party"..id;
+ local icon = _G["PartyMemberFrame"..id.."RoleIcon"];
+ local isTank, isHealer, isDamage = UnitGroupRolesAssigned(unit);
+
+ if ( isTank ) then
+ icon:SetTexCoord(0, 19/64, 22/64, 41/64);
+ icon:Show();
+ elseif ( isHealer ) then
+ icon:SetTexCoord(20/64, 39/64, 1/64, 20/64);
+ icon:Show();
+ elseif ( isDamage ) then
+ icon:SetTexCoord(20/64, 39/64, 22/64, 41/64);
+ icon:Show();
+ else
+ icon:Hide();
+ end
+end
+
+function PartyMemberFrame_UpdateVoiceStatus (self)
+ local id = self:GetID();
+ if ( not UnitName("party"..id) ) then
+ --No need to update if the frame doesn't have a unit.
+ return;
+ end
+
+ local mode;
+ local inInstance, instanceType = IsInInstance();
+
+ if ( (instanceType == "pvp") or (instanceType == "arena") ) then
+ mode = "Battleground";
+ elseif ( GetNumRaidMembers() > 0 ) then
+ mode = "raid";
+ else
+ mode = "party";
+ end
+ local status = GetVoiceStatus("party"..id, mode);
+ local statusIcon = _G["PartyMemberFrame"..id.."Speaker"];
+ local muted = GetMuteStatus("party"..id, mode);
+ local mutedIcon = _G["PartyMemberFrame"..id.."SpeakerMuted"];
+
+ _G["PartyMemberFrame"..id.."SpeakerOn"]:SetVertexColor(0.7, 0.7, 0.7);
+ if ( status ) then
+ statusIcon:Show();
+ else
+ statusIcon:Hide();
+ end
+ if ( muted ) then
+ mutedIcon:Show();
+ else
+ mutedIcon:Hide();
+ end
+ -- Update the talking speaker thingie if they are talking or not.
+ local speaker = _G["PartyMemberFrame"..id.."SpeakerFrame"];
+ local state = UnitIsTalking(UnitName("party"..id));
+ if ( state ) then
+ VoiceChat_Animate(speaker, 1);
+ speaker:Show();
+ else
+ VoiceChat_Animate(speaker, nil);
+ speaker:Hide();
+ end
+end
+
+function PartyMemberFrame_UpdateReadyCheck (self)
+ local id = self:GetID();
+ local partyID = "party"..id;
+
+ local readyCheckFrame = _G["PartyMemberFrame"..id.."ReadyCheck"];
+ local readyCheckStatus = GetReadyCheckStatus(partyID);
+ if ( UnitName(partyID) and UnitIsConnected(partyID) and readyCheckStatus ) then
+ if ( readyCheckStatus == "ready" ) then
+ ReadyCheck_Confirm(readyCheckFrame, 1);
+ elseif ( readyCheckStatus == "notready" ) then
+ ReadyCheck_Confirm(readyCheckFrame, 0);
+ else -- "waiting"
+ ReadyCheck_Start(readyCheckFrame);
+ end
+ else
+ readyCheckFrame:Hide();
+ end
+end
+
+function PartyMemberFrame_OnEvent(self, event, ...)
+ UnitFrame_OnEvent(self, event, ...);
+
+ local arg1, arg2, arg3 = ...;
+ local selfID = self:GetID();
+
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ if ( GetPartyMember(self:GetID()) ) then
+ PartyMemberFrame_UpdateMember(self);
+ PartyMemberFrame_UpdateOnlineStatus(self);
+ return;
+ end
+ end
+
+ if ( event == "PARTY_MEMBERS_CHANGED" ) then
+ PartyMemberFrame_UpdateMember(self);
+ PartyMemberFrame_UpdateArt(self);
+ PartyMemberFrame_UpdateAssignedRoles(self);
+ return;
+ end
+
+ if ( event == "PARTY_LEADER_CHANGED" ) then
+ PartyMemberFrame_UpdateLeader(self);
+ return;
+ end
+
+ if ( event == "PARTY_LOOT_METHOD_CHANGED" ) then
+ local lootMethod;
+ local lootMaster;
+ lootMethod, lootMaster = GetLootMethod();
+ if ( selfID == lootMaster ) then
+ _G[self:GetName().."MasterIcon"]:Show();
+ else
+ _G[self:GetName().."MasterIcon"]:Hide();
+ end
+ return;
+ end
+
+ if ( event == "MUTELIST_UPDATE" or event == "IGNORELIST_UPDATE" ) then
+ PartyMemberFrame_UpdateVoiceStatus(self);
+ end
+
+ local unit = "party"..self:GetID();
+ local unitPet = "partypet"..self:GetID();
+
+ if ( event == "UNIT_FACTION" ) then
+ if ( arg1 == unit ) then
+ PartyMemberFrame_UpdatePvPStatus(self);
+ end
+ return;
+ end
+
+ if ( event =="UNIT_AURA" ) then
+ if ( arg1 == unit ) then
+ RefreshDebuffs(self, unit);
+ if ( PartyMemberBuffTooltip:IsShown() and
+ selfID == PartyMemberBuffTooltip:GetID() ) then
+ PartyMemberBuffTooltip_Update(self);
+ end
+ else
+ if ( arg1 == unitPet ) then
+ PartyMemberFrame_RefreshPetDebuffs(self);
+ end
+ end
+ return;
+ end
+
+ if ( event =="UNIT_PET" ) then
+ if ( arg1 == unit ) then
+ PartyMemberFrame_UpdatePet(self);
+ end
+ if ( UnitHasVehicleUI("party"..selfID) and UnitIsConnected("party"..selfID)) then
+ PartyMemberFrame_ToVehicleArt(self, UnitVehicleSkin("party"..selfID));
+ end
+ return;
+ end
+
+ if ( event == "READY_CHECK" or
+ event == "READY_CHECK_CONFIRM" ) then
+ PartyMemberFrame_UpdateReadyCheck(self);
+ return;
+ elseif ( event == "READY_CHECK_FINISHED" ) then
+ if (GetPartyMember(self:GetID())) then
+ ReadyCheck_Finish(_G["PartyMemberFrame"..self:GetID().."ReadyCheck"]);
+ end
+ return;
+ end
+
+ local speaker = _G[self:GetName().."SpeakerFrame"];
+ if ( event == "VOICE_START") then
+ if ( arg1 == unit ) then
+ speaker.timer = nil;
+ UIFrameFadeIn(speaker, 0.2, speaker:GetAlpha(), 1);
+ VoiceChat_Animate(speaker, 1);
+ end
+ elseif ( event == "VOICE_STOP" ) then
+ if ( arg1 == unit ) then
+ speaker.timer = VOICECHAT_DELAY;
+ VoiceChat_Animate(speaker, nil);
+ end
+ elseif ( event == "VARIABLES_LOADED" ) then
+ PartyMemberFrame_UpdatePet(self);
+ PartyMemberFrame_UpdateVoiceStatus(self);
+ elseif ( event == "VOICE_STATUS_UPDATE" ) then
+ PartyMemberFrame_UpdateVoiceStatus(self);
+ elseif ( event == "UNIT_ENTERED_VEHICLE" ) then
+ if ( arg1 == "party"..selfID ) then
+ if ( arg2 and UnitIsConnected("party"..selfID) ) then
+ PartyMemberFrame_ToVehicleArt(self, arg3);
+ else
+ PartyMemberFrame_ToPlayerArt(self);
+ end
+ end
+ elseif ( event == "UNIT_EXITED_VEHICLE" ) then
+ if ( arg1 == "party"..selfID ) then
+ PartyMemberFrame_ToPlayerArt(self);
+ end
+ elseif ( event == "UNIT_HEALTH" ) and ( arg1 == "party"..selfID ) then
+ PartyMemberFrame_UpdateOnlineStatus(self);
+ end
+end
+
+function PartyMemberFrame_OnUpdate (self, elapsed)
+ PartyMemberFrame_UpdateMemberHealth(self, elapsed);
+ local partyStatus = _G[self:GetName().."Status"];
+ if ( self.hasDispellable ) then
+ partyStatus:Show();
+ partyStatus:SetAlpha(BuffFrame.BuffAlphaValue);
+ if ( self.debuffCountdown and self.debuffCountdown > 0 ) then
+ self.debuffCountdown = self.debuffCountdown - elapsed;
+ else
+ partyStatus:Hide();
+ end
+ else
+ partyStatus:Hide();
+ end
+end
+
+function PartyMemberFrame_RefreshPetDebuffs (self, id)
+ if ( not id ) then
+ id = self:GetID();
+ end
+ RefreshDebuffs(_G["PartyMemberFrame"..id.."PetFrame"], "partypet"..id)
+end
+
+function PartyMemberBuffTooltip_Update (self)
+ local name, rank, icon;
+ local numBuffs = 0;
+ local numDebuffs = 0;
+ local index = 1;
+
+ PartyMemberBuffTooltip:SetID(self:GetID());
+
+ for i=1, MAX_PARTY_TOOLTIP_BUFFS do
+ name, rank, icon = UnitBuff(self.unit, i);
+ if ( icon ) then
+ _G["PartyMemberBuffTooltipBuff"..index.."Icon"]:SetTexture(icon);
+ _G["PartyMemberBuffTooltipBuff"..index]:Show();
+ index = index + 1;
+ numBuffs = numBuffs + 1;
+ end
+ end
+ for i=index, MAX_PARTY_TOOLTIP_BUFFS do
+ _G["PartyMemberBuffTooltipBuff"..i]:Hide();
+ end
+
+ if ( numBuffs == 0 ) then
+ PartyMemberBuffTooltipDebuff1:SetPoint("TOP", "PartyMemberBuffTooltipBuff1", "TOP", 0, 0);
+ elseif ( numBuffs <= 8 ) then
+ PartyMemberBuffTooltipDebuff1:SetPoint("TOP", "PartyMemberBuffTooltipBuff1", "BOTTOM", 0, -2);
+ else
+ PartyMemberBuffTooltipDebuff1:SetPoint("TOP", "PartyMemberBuffTooltipBuff9", "BOTTOM", 0, -2);
+ end
+
+ index = 1;
+
+ local debuffButton, debuffStack, debuffType, color, countdown;
+ for i=1, MAX_PARTY_TOOLTIP_DEBUFFS do
+ local debuffBorder = _G["PartyMemberBuffTooltipDebuff"..index.."Border"]
+ local partyDebuff = _G["PartyMemberBuffTooltipDebuff"..index.."Icon"];
+ name, rank, icon, debuffStack, debuffType = UnitDebuff(self.unit, i);
+ if ( icon ) then
+ partyDebuff:SetTexture(icon);
+ if ( debuffType ) then
+ color = DebuffTypeColor[debuffType];
+ else
+ color = DebuffTypeColor["none"];
+ end
+ debuffBorder:SetVertexColor(color.r, color.g, color.b);
+ _G["PartyMemberBuffTooltipDebuff"..index]:Show();
+ numDebuffs = numDebuffs + 1;
+ index = index + 1;
+ end
+ end
+ for i=index, MAX_PARTY_TOOLTIP_DEBUFFS do
+ _G["PartyMemberBuffTooltipDebuff"..i]:Hide();
+ end
+
+ -- Size the tooltip
+ local rows = ceil(numBuffs / 8) + ceil(numDebuffs / 8);
+ local columns = min(8, max(numBuffs, numDebuffs));
+ if ( (rows > 0) and (columns > 0) ) then
+ PartyMemberBuffTooltip:SetWidth( (columns * 17) + 15 );
+ PartyMemberBuffTooltip:SetHeight( (rows * 17) + 15 );
+ PartyMemberBuffTooltip:Show();
+ else
+ PartyMemberBuffTooltip:Hide();
+ end
+end
+
+function PartyMemberHealthCheck (self, value)
+ local prefix = self:GetParent():GetName();
+ local unitHPMin, unitHPMax, unitCurrHP;
+ unitHPMin, unitHPMax = self:GetMinMaxValues();
+ local parentName = self:GetParent():GetName();
+
+ unitCurrHP = self:GetValue();
+ if ( unitHPMax > 0 ) then
+ self:GetParent().unitHPPercent = unitCurrHP / unitHPMax;
+ else
+ self:GetParent().unitHPPercent = 0;
+ end
+ if ( UnitIsDead("party"..self:GetParent():GetID()) ) then
+ _G[prefix.."Portrait"]:SetVertexColor(0.35, 0.35, 0.35, 1.0);
+ elseif ( UnitIsGhost("party"..self:GetParent():GetID()) ) then
+ _G[prefix.."Portrait"]:SetVertexColor(0.2, 0.2, 0.75, 1.0);
+ elseif ( (self:GetParent().unitHPPercent > 0) and (self:GetParent().unitHPPercent <= 0.2) ) then
+ _G[prefix.."Portrait"]:SetVertexColor(1.0, 0.0, 0.0);
+ else
+ _G[prefix.."Portrait"]:SetVertexColor(1.0, 1.0, 1.0, 1.0);
+ end
+end
+
+function PartyFrameDropDown_OnLoad (self)
+ UIDropDownMenu_Initialize(self, PartyFrameDropDown_Initialize, "MENU");
+end
+
+function PartyFrameDropDown_Initialize (self)
+ local dropdown = UIDROPDOWNMENU_OPEN_MENU or self;
+ UnitPopup_ShowMenu(dropdown, "PARTY", "party"..dropdown:GetParent():GetID());
+end
+
+function UpdatePartyMemberBackground ()
+ if ( not PartyMemberBackground ) then
+ return;
+ end
+ if ( SHOW_PARTY_BACKGROUND == "1" and GetNumPartyMembers() > 0 and not(HIDE_PARTY_INTERFACE == "1" and (GetNumRaidMembers() > 0)) ) then
+ if ( _G["PartyMemberFrame"..GetNumPartyMembers().."PetFrame"]:IsShown() ) then
+ PartyMemberBackground:SetPoint("BOTTOMLEFT", "PartyMemberFrame"..GetNumPartyMembers(), "BOTTOMLEFT", -5, -21);
+ else
+ PartyMemberBackground:SetPoint("BOTTOMLEFT", "PartyMemberFrame"..GetNumPartyMembers(), "BOTTOMLEFT", -5, -5);
+ end
+ PartyMemberBackground:Show();
+ else
+ PartyMemberBackground:Hide();
+ end
+end
+
+function PartyMemberBackground_ToggleOpacity (self)
+ if ( not self ) then
+ self = PartyMemberBackground;
+ end
+ if ( OpacityFrame:IsShown() ) then
+ OpacityFrame:Hide();
+ return;
+ end
+ OpacityFrame:ClearAllPoints();
+ if ( self == ArenaEnemyBackground ) then
+ OpacityFrame:SetPoint("TOPRIGHT", self, "TOPLEFT", 0, -7);
+ else
+ OpacityFrame:SetPoint("TOPLEFT", self, "TOPRIGHT", 0, 7);
+ end
+ OpacityFrame.opacityFunc = PartyMemberBackground_SetOpacity;
+ OpacityFrame.saveOpacityFunc = PartyMemberBackground_SaveOpacity;
+ OpacityFrame:Show();
+end
+
+function PartyMemberBackground_SetOpacity ()
+ local alpha = 1.0 - OpacityFrameSlider:GetValue();
+ PartyMemberBackground:SetAlpha(alpha);
+ if ( ArenaEnemyBackground_SetOpacity ) then
+ ArenaEnemyBackground_SetOpacity();
+ end
+end
+
+function PartyMemberBackground_SaveOpacity ()
+ PARTYBACKGROUND_OPACITY = OpacityFrameSlider:GetValue();
+ SetCVar("partyBackgroundOpacity", PARTYBACKGROUND_OPACITY);
+end
+
+function PartyMemberFrame_UpdateStatusBarText ()
+ local lockText = nil;
+ if ( SHOW_PARTY_TEXT == "1" ) then
+ lockText = 1;
+ end
+ for i=1, MAX_PARTY_MEMBERS do
+ _G["PartyMemberFrame"..i.."HealthBar"].forceShow = lockText;
+ _G["PartyMemberFrame"..i.."ManaBar"].forceShow = lockText;
+ if ( lockText ) then
+ _G["PartyMemberFrame"..i.."HealthBarText"]:Show();
+ _G["PartyMemberFrame"..i.."ManaBarText"]:Show();
+ end
+ end
+end
+
+function PartyMemberFrame_UpdateOnlineStatus(self)
+ if ( not UnitIsConnected("party"..self:GetID()) ) then
+ -- Handle disconnected state
+ local selfName = self:GetName();
+ local healthBar = _G[selfName.."HealthBar"];
+ local unitHPMin, unitHPMax = healthBar:GetMinMaxValues();
+
+ healthBar:SetValue(unitHPMax);
+ healthBar:SetStatusBarColor(0.5, 0.5, 0.5);
+ SetDesaturation(_G[selfName.."Portrait"], 1);
+ _G[selfName.."Disconnect"]:Show();
+ _G[selfName.."PetFrame"]:Hide();
+ return;
+ else
+ local selfName = self:GetName();
+ SetDesaturation(_G[selfName.."Portrait"], nil);
+ _G[selfName.."Disconnect"]:Hide();
+ end
+end
diff --git a/reference/FrameXML/PetActionBarFrame.lua b/reference/FrameXML/PetActionBarFrame.lua
new file mode 100644
index 0000000..89738f1
--- /dev/null
+++ b/reference/FrameXML/PetActionBarFrame.lua
@@ -0,0 +1,399 @@
+PETACTIONBAR_SLIDETIME = 0.09;
+PETACTIONBAR_YPOS = 98;
+PETACTIONBAR_XPOS = 36;
+NUM_PET_ACTION_SLOTS = 10;
+
+PET_DEFENSIVE_TEXTURE = "Interface\\Icons\\Ability_Defend";
+PET_AGGRESSIVE_TEXTURE = "Interface\\Icons\\Ability_Racial_BloodRage";
+PET_PASSIVE_TEXTURE = "Interface\\Icons\\Ability_Seal";
+PET_ATTACK_TEXTURE = "Interface\\Icons\\Ability_GhoulFrenzy";
+PET_FOLLOW_TEXTURE = "Interface\\Icons\\Ability_Tracking";
+PET_WAIT_TEXTURE = "Interface\\Icons\\Spell_Nature_TimeStop";
+PET_DISMISS_TEXTURE = "Interface\\Icons\\Spell_Shadow_Teleport";
+
+function PetActionBar_OnLoad (self)
+ self:RegisterEvent("PLAYER_CONTROL_LOST");
+ self:RegisterEvent("PLAYER_CONTROL_GAINED");
+ self:RegisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED");
+ self:RegisterEvent("UNIT_PET");
+ self:RegisterEvent("UNIT_FLAGS");
+ self:RegisterEvent("UNIT_AURA");
+ self:RegisterEvent("PET_BAR_UPDATE");
+ self:RegisterEvent("PET_BAR_UPDATE_COOLDOWN");
+ self:RegisterEvent("PET_BAR_SHOWGRID");
+ self:RegisterEvent("PET_BAR_HIDEGRID");
+ self:RegisterEvent("PET_BAR_HIDE");
+ self:RegisterEvent("PET_BAR_UPDATE_USABLE");
+ self.showgrid = 0;
+ PetActionBar_Update(self);
+ if ( PetHasActionBar() ) then
+ ShowPetActionBar();
+ LockPetActionBar();
+ end
+end
+
+function PetActionBar_OnEvent (self, event, ...)
+ local arg1 = ...;
+
+ if ( event == "PET_BAR_UPDATE" or (event == "UNIT_PET" and arg1 == "player") ) then
+ PetActionBar_Update(self);
+ if ( PetHasActionBar() and UnitIsVisible("pet") ) then
+ ShowPetActionBar();
+ LockPetActionBar();
+ else
+ UnlockPetActionBar();
+ HidePetActionBar();
+ end
+ elseif ( event == "PLAYER_CONTROL_LOST" or event == "PLAYER_CONTROL_GAINED" or event == "PLAYER_FARSIGHT_FOCUS_CHANGED" or event == "PET_BAR_UPDATE_USABLE" ) then
+ PetActionBar_Update(self);
+ elseif ( (event == "UNIT_FLAGS") or (event == "UNIT_AURA") ) then
+ if ( arg1 == "pet" ) then
+ PetActionBar_Update(self);
+ end
+ elseif ( event =="PET_BAR_UPDATE_COOLDOWN" ) then
+ PetActionBar_UpdateCooldowns();
+ elseif ( event =="PET_BAR_SHOWGRID" ) then
+ PetActionBar_ShowGrid();
+ elseif ( event =="PET_BAR_HIDEGRID" ) then
+ PetActionBar_HideGrid();
+ elseif ( event =="PET_BAR_HIDE" ) then
+ HidePetActionBar();
+ end
+end
+
+function PetActionBarFrame_IsAboveShapeshift(ignoreShowing)
+ return ( ((ShapeshiftBarFrame and GetNumShapeshiftForms() > 0) or (MultiCastActionBarFrame and HasMultiCastActionBar()) or
+ (MainMenuBarVehicleLeaveButton and MainMenuBarVehicleLeaveButton:IsShown())) and
+ (not MultiBarBottomLeft:IsShown() and MultiBarBottomRight:IsShown()) and
+ (ignoreShowing or (PetActionBarFrame and PetActionBarFrame:IsShown())))
+end
+
+function PetActionBarFrame_OnUpdate(self, elapsed)
+ local yPos;
+ if ( self.slideTimer and (self.slideTimer < self.timeToSlide) ) then
+ self.completed = nil;
+ if ( self.mode == "show" ) then
+ yPos = (self.slideTimer/self.timeToSlide) * PETACTIONBAR_YPOS;
+ self:SetPoint("TOPLEFT", self:GetParent(), "BOTTOMLEFT", PETACTIONBAR_XPOS, yPos);
+ self.state = "showing";
+ self:Show();
+ elseif ( self.mode == "hide" ) then
+ yPos = (1 - (self.slideTimer/self.timeToSlide)) * PETACTIONBAR_YPOS;
+ self:SetPoint("TOPLEFT", self:GetParent(), "BOTTOMLEFT", PETACTIONBAR_XPOS, yPos);
+ self.state = "hiding";
+ end
+ self.slideTimer = self.slideTimer + elapsed;
+ else
+ self.completed = 1;
+ if ( self.mode == "show" ) then
+ self:SetPoint("TOPLEFT", self:GetParent(), "BOTTOMLEFT", PETACTIONBAR_XPOS, PETACTIONBAR_YPOS);
+ self.state = "top";
+ --Move the chat frame and edit box up a bit
+ elseif ( self.mode == "hide" ) then
+ self:SetPoint("TOPLEFT", self:GetParent(), "BOTTOMLEFT", PETACTIONBAR_XPOS, 0);
+ self.state = "bottom";
+ self:Hide();
+ --Move the chat frame and edit box back down to original position
+ end
+ self.mode = "none";
+ end
+end
+
+function PetActionBar_Update (self)
+ local petActionButton, petActionIcon, petAutoCastableTexture, petAutoCastShine;
+ for i=1, NUM_PET_ACTION_SLOTS, 1 do
+ local buttonName = "PetActionButton" .. i;
+ petActionButton = _G[buttonName];
+ petActionIcon = _G[buttonName.."Icon"];
+ petAutoCastableTexture = _G[buttonName.."AutoCastable"];
+ petAutoCastShine = _G[buttonName.."Shine"];
+ local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(i);
+ if ( not isToken ) then
+ petActionIcon:SetTexture(texture);
+ petActionButton.tooltipName = name;
+ else
+ petActionIcon:SetTexture(_G[texture]);
+ petActionButton.tooltipName = _G[name];
+ end
+ petActionButton.isToken = isToken;
+ petActionButton.tooltipSubtext = subtext;
+ if ( isActive ) then
+ if ( IsPetAttackAction(i) ) then
+ PetActionButton_StartFlash(petActionButton);
+ -- the checked texture looks a little confusing at full alpha (looks like you have an extra ability selected)
+ petActionButton:GetCheckedTexture():SetAlpha(0.5);
+ else
+ petActionButton:GetCheckedTexture():SetAlpha(1.0);
+ end
+ petActionButton:SetChecked(1);
+ else
+ if ( IsPetAttackAction(i) ) then
+ PetActionButton_StopFlash(petActionButton);
+ end
+ petActionButton:SetChecked(0);
+ end
+ if ( autoCastAllowed ) then
+ petAutoCastableTexture:Show();
+ else
+ petAutoCastableTexture:Hide();
+ end
+ if ( autoCastEnabled ) then
+ AutoCastShine_AutoCastStart(petAutoCastShine);
+ else
+ AutoCastShine_AutoCastStop(petAutoCastShine);
+ end
+ if ( name ) then
+ petActionButton:Show();
+ else
+ if ( PetActionBarFrame.showgrid == 0 ) then
+ petActionButton:Hide();
+ end
+ end
+ if ( texture ) then
+ if ( GetPetActionSlotUsable(i) ) then
+ SetDesaturation(petActionIcon, nil);
+ else
+ SetDesaturation(petActionIcon, 1);
+ end
+ petActionIcon:Show();
+ petActionButton:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2");
+ else
+ petActionIcon:Hide();
+ petActionButton:SetNormalTexture("Interface\\Buttons\\UI-Quickslot");
+ end
+ end
+ PetActionBar_UpdateCooldowns();
+ if ( not PetHasActionBar() ) then
+ --ControlReleased();
+ HidePetActionBar();
+ end
+end
+
+function PetActionBar_UpdateCooldowns()
+ local cooldown;
+ for i=1, NUM_PET_ACTION_SLOTS, 1 do
+ cooldown = _G["PetActionButton"..i.."Cooldown"];
+ local start, duration, enable = GetPetActionCooldown(i);
+ CooldownFrame_SetTimer(cooldown, start, duration, enable);
+ end
+end
+
+function PetActionBar_UpdatePositionValues()
+ if ( PetActionBarFrame_IsAboveShapeshift(true) ) then
+ PETACTIONBAR_XPOS = 36;
+ elseif ( MainMenuBarVehicleLeaveButton and MainMenuBarVehicleLeaveButton:IsShown() ) then
+ PETACTIONBAR_XPOS = MainMenuBarVehicleLeaveButton:GetRight() + 20;
+ elseif ( ShapeshiftBarFrame and GetNumShapeshiftForms() > 0 ) then
+ PETACTIONBAR_XPOS = _G["ShapeshiftButton"..GetNumShapeshiftForms()]:GetRight() + 20;
+ elseif ( MultiCastActionBarFrame and HasMultiCastActionBar() ) then
+ PETACTIONBAR_XPOS = MultiCastActionBarFrame:GetRight() + 20;
+ else
+ PETACTIONBAR_XPOS = 36;
+ end
+end
+
+function ShowPetActionBar(doNotSlide)
+ if ( PetHasActionBar() and PetActionBarFrame.showgrid == 0 and (PetActionBarFrame.mode ~= "show") and (not PetActionBarFrame.locked or doNotSlide) and not PetActionBarFrame.ctrlPressed ) then
+ PetActionBar_UpdatePositionValues();
+ if ( MainMenuBar.busy or UnitHasVehicleUI("player") or doNotSlide ) then
+ PetActionBarFrame:SetPoint("TOPLEFT", PetActionBarFrame:GetParent(), "BOTTOMLEFT", PETACTIONBAR_XPOS, PETACTIONBAR_YPOS);
+ PetActionBarFrame.state = "top";
+ PetActionBarFrame:Show();
+ else
+ PetActionBarFrame:Show();
+ if ( PetActionBarFrame.completed ) then
+ PetActionBarFrame.slideTimer = 0;
+ end
+ PetActionBarFrame.timeToSlide = PETACTIONBAR_SLIDETIME;
+ PetActionBarFrame.mode = "show";
+ end
+ UIParent_ManageFramePositions();
+ end
+end
+
+function HidePetActionBar()
+ if ( PetActionBarFrame.showgrid == 0 and PetActionBarFrame:IsShown() and not PetActionBarFrame.locked and not PetActionBarFrame.ctrlPressed ) then
+ if ( MainMenuBar.busy or UnitHasVehicleUI("player") ) then
+ PetActionBarFrame:SetPoint("TOPLEFT", PetActionBarFrame:GetParent(), "BOTTOMLEFT", PETACTIONBAR_XPOS, 0);
+ PetActionBarFrame.state = "bottom";
+ PetActionBarFrame:Hide();
+ else
+ if ( PetActionBarFrame.completed ) then
+ PetActionBarFrame.slideTimer = 0;
+ end
+ PetActionBarFrame.timeToSlide = PETACTIONBAR_SLIDETIME;
+ PetActionBarFrame.mode = "hide";
+ end
+ end
+end
+
+function PetActionBar_ShowGrid()
+ ShowPetActionBar();
+ PetActionBarFrame.showgrid = PetActionBarFrame.showgrid + 1;
+ for i=1, NUM_PET_ACTION_SLOTS do
+ _G["PetActionButton"..i]:Show();
+ end
+end
+
+function PetActionBar_HideGrid()
+ if ( PetActionBarFrame.showgrid > 0 ) then
+ PetActionBarFrame.showgrid = PetActionBarFrame.showgrid - 1;
+ end
+ if ( PetActionBarFrame.showgrid == 0 ) then
+ HidePetActionBar();
+ local name;
+ for i=1, NUM_PET_ACTION_SLOTS, 1 do
+ name = GetPetActionInfo(i);
+ if ( not name ) then
+ _G["PetActionButton"..i]:Hide();
+ end
+ end
+ end
+end
+
+function PetActionButtonDown(id)
+ local button = _G["PetActionButton"..id];
+ if ( button:GetButtonState() == "NORMAL" ) then
+ button:SetButtonState("PUSHED");
+ end
+end
+
+function PetActionButtonUp (id)
+ local button = _G["PetActionButton"..id];
+ if ( button:GetButtonState() == "PUSHED" ) then
+ button:SetButtonState("NORMAL");
+ CastPetAction(id);
+ end
+end
+
+function PetActionButton_OnLoad (self)
+ self:RegisterForDrag("LeftButton", "RightButton");
+ self:RegisterForClicks("AnyUp");
+ self:RegisterEvent("UPDATE_BINDINGS");
+ _G[self:GetName().."Cooldown"]:ClearAllPoints();
+ _G[self:GetName().."Cooldown"]:SetWidth(33);
+ _G[self:GetName().."Cooldown"]:SetHeight(33);
+ _G[self:GetName().."Cooldown"]:SetPoint("CENTER", self, "CENTER", -2, -1);
+ PetActionButton_SetHotkeys(self);
+end
+
+function PetActionButton_OnEvent (self, event, ...)
+ if ( event == "UPDATE_BINDINGS" ) then
+ PetActionButton_SetHotkeys(self);
+ return;
+ end
+end
+
+function PetActionButton_OnClick (self, button)
+ if ( button == "LeftButton" ) then
+ CastPetAction(self:GetID());
+ else
+ TogglePetAutocast(self:GetID());
+ end
+end
+
+function PetActionButton_OnModifiedClick (self, button)
+ if ( IsModifiedClick("PICKUPACTION") ) then
+ PickupPetAction(self:GetID());
+ return;
+ end
+end
+
+function PetActionButton_OnDragStart (self)
+ if ( LOCK_ACTIONBAR ~= "1" ) then
+ self:SetChecked(0);
+ PickupPetAction(self:GetID());
+ PetActionBar_Update();
+ end
+end
+
+function PetActionButton_OnReceiveDrag (self)
+ if ( LOCK_ACTIONBAR ~= "1" ) then
+ self:SetChecked(0);
+ PickupPetAction(self:GetID());
+ PetActionBar_Update();
+ end
+end
+
+function PetActionButton_OnEnter (self)
+ if ( not self.tooltipName ) then
+ return;
+ end
+ local uber = GetCVar("UberTooltips");
+ if ( self.isToken or (uber == "0") ) then
+ if ( uber == "0" ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ else
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ end
+ GameTooltip:SetText(self.tooltipName..NORMAL_FONT_COLOR_CODE.." ("..GetBindingText(GetBindingKey("BONUSACTIONBUTTON"..self:GetID()), "KEY_")..")"..FONT_COLOR_CODE_CLOSE, 1.0, 1.0, 1.0);
+ if ( self.tooltipSubtext ) then
+ GameTooltip:AddLine(self.tooltipSubtext, "", 0.5, 0.5, 0.5);
+ end
+ GameTooltip:Show();
+ else
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ GameTooltip:SetPetAction(self:GetID());
+ end
+end
+
+function PetActionButton_OnLeave ()
+ GameTooltip:Hide();
+end
+
+function PetActionButton_OnUpdate (self, elapsed)
+ if ( PetActionButton_IsFlashing(self) ) then
+ local flashtime = self.flashtime;
+ flashtime = flashtime - elapsed;
+
+ if ( flashtime <= 0 ) then
+ local overtime = -flashtime;
+ if ( overtime >= ATTACK_BUTTON_FLASH_TIME ) then
+ overtime = 0;
+ end
+ flashtime = ATTACK_BUTTON_FLASH_TIME - overtime;
+
+ local flashTexture = _G[self:GetName().."Flash"];
+ if ( flashTexture:IsShown() ) then
+ flashTexture:Hide();
+ else
+ flashTexture:Show();
+ end
+ end
+
+ self.flashtime = flashtime;
+ end
+end
+
+function PetActionButton_StartFlash (self)
+ self.flashing = true;
+ self.flashtime = 0;
+end
+
+function PetActionButton_StopFlash (self)
+ self.flashing = false;
+ _G[self:GetName().."Flash"]:Hide();
+end
+
+function PetActionButton_IsFlashing (self)
+ return self.flashing;
+end
+
+function PetActionButton_SetHotkeys (self)
+ local binding = GetBindingText(GetBindingKey("BONUSACTIONBUTTON"..self:GetID()), 1);
+ local bindingSuffix = gsub(binding, ".*%-", "");
+ local hotkey = _G[self:GetName().."HotKey"];
+ if ( bindingSuffix == self:GetID() ) then
+ hotkey:SetText(self:GetID());
+ else
+ hotkey:SetText("");
+ end
+end
+
+function LockPetActionBar()
+ PetActionBarFrame.locked = 1;
+end
+
+function UnlockPetActionBar()
+ PetActionBarFrame.locked = nil;
+end
diff --git a/reference/FrameXML/PetActionBarFrame.xml b/reference/FrameXML/PetActionBarFrame.xml
new file mode 100644
index 0000000..42e826a
--- /dev/null
+++ b/reference/FrameXML/PetActionBarFrame.xml
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PetActionButton_OnLoad(self);
+
+
+ PetActionButton_OnEvent(self, event, ...);
+
+
+ self:SetChecked(0);
+
+
+ if ( IsModifiedClick() ) then
+ PetActionButton_OnModifiedClick(self, button);
+ else
+ PetActionButton_OnClick(self, button);
+ end
+
+
+ PetActionButton_OnDragStart(self, button);
+
+
+ PetActionButton_OnReceiveDrag(self);
+
+
+ PetActionButton_OnEnter(self, motion);
+
+
+ PetActionButton_OnLeave(self, motion);
+
+
+ PetActionButton_OnUpdate(self, elapsed);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/PetFrame.lua b/reference/FrameXML/PetFrame.lua
new file mode 100644
index 0000000..842f699
--- /dev/null
+++ b/reference/FrameXML/PetFrame.lua
@@ -0,0 +1,204 @@
+--PET_WARNING_TIME = 55;
+--PET_FLASH_ON_TIME = 0.5;
+--PET_FLASH_OFF_TIME = 0.5;
+
+function PetFrame_OnLoad (self)
+ self.noTextPrefix = true;
+ UnitFrame_Initialize(self, "pet", PetName, PetPortrait,
+ PetFrameHealthBar, PetFrameHealthBarText,
+ PetFrameManaBar, PetFrameManaBarText,
+ PetFrameFlash);
+
+ self.attackModeCounter = 0;
+ self.attackModeSign = -1;
+ --self.flashState = 1;
+ --self.flashTimer = 0;
+ CombatFeedback_Initialize(self, PetHitIndicator, 30);
+ PetFrame_Update(self);
+ self:RegisterEvent("UNIT_PET");
+ self:RegisterEvent("UNIT_COMBAT");
+ self:RegisterEvent("UNIT_AURA");
+ self:RegisterEvent("PET_ATTACK_START");
+ self:RegisterEvent("PET_ATTACK_STOP");
+ self:RegisterEvent("UNIT_HAPPINESS");
+ self:RegisterEvent("PET_UI_UPDATE");
+ self:RegisterEvent("PET_RENAMEABLE");
+ local showmenu = function()
+ ToggleDropDownMenu(1, nil, PetFrameDropDown, "PetFrame", 44, 8);
+ end
+ SecureUnitButton_OnLoad(self, "pet", showmenu);
+
+ local _, class = UnitClass("player");
+ if ( class == "DEATHKNIGHT" or class == "DRUID" ) then --Death Knights need the Pet frame moved down for their Runes and Druids need it moved down for the secondary power bar.
+ self:SetPoint("TOPLEFT", PlayerFrame, "TOPLEFT", 60, -75);
+ elseif ( class == "SHAMAN" ) then
+ self:SetPoint("TOPLEFT", PlayerFrame, "TOPLEFT", 60, -100);
+ end
+end
+
+function PetFrame_Update (self, override)
+ if ( (not PlayerFrame.animating) or (override) ) then
+ if ( UnitIsVisible(self.unit) ) then
+ if ( self:IsShown() ) then
+ UnitFrame_Update(self);
+ else
+ self:Show();
+ end
+ --self.flashState = 1;
+ --self.flashTimer = PET_FLASH_ON_TIME;
+ if ( UnitPowerMax(self.unit) == 0 ) then
+ PetFrameTexture:SetTexture("Interface\\TargetingFrame\\UI-SmallTargetingFrame-NoMana");
+ PetFrameManaBarText:Hide();
+ else
+ PetFrameTexture:SetTexture("Interface\\TargetingFrame\\UI-SmallTargetingFrame");
+ end
+ PetAttackModeTexture:Hide();
+
+ PetFrame_SetHappiness(self);
+ RefreshDebuffs(self, self.unit);
+ else
+ self:Hide();
+ end
+ end
+end
+
+function PetFrame_OnEvent (self, event, ...)
+ UnitFrame_OnEvent(self, event, ...);
+
+ local arg1, arg2, arg3, arg4, arg5 = ...;
+ if ( (event == "UNIT_PET" and arg1 == "player" ) or event == "PET_UI_UPDATE" ) then
+ local unit
+ if ( UnitInVehicle("player") and UnitHasVehicleUI("player") ) then
+ unit = "player";
+ else
+ unit = "pet";
+ end
+ UnitFrame_SetUnit(self, unit, PetFrameHealthBar, PetFrameManaBar);
+ PetFrame_Update(self);
+ elseif ( event == "UNIT_COMBAT" ) then
+ if ( arg1 == self.unit ) then
+ CombatFeedback_OnCombatEvent(self, arg2, arg3, arg4, arg5);
+ end
+ elseif ( event == "UNIT_AURA" ) then
+ if ( arg1 == self.unit ) then
+ RefreshDebuffs(self, self.unit);
+ end
+ elseif ( event == "PET_ATTACK_START" ) then
+ PetAttackModeTexture:SetVertexColor(1.0, 1.0, 1.0, 1.0);
+ PetAttackModeTexture:Show();
+ elseif ( event == "PET_ATTACK_STOP" ) then
+ PetAttackModeTexture:Hide();
+ elseif ( event == "UNIT_HAPPINESS" ) then
+ PetFrame_SetHappiness(self);
+ elseif ( event == "PET_RENAMEABLE" ) then
+ StaticPopup_Show("RENAME_PET");
+ end
+end
+
+function PetFrame_OnUpdate (self, elapsed)
+ if ( PetAttackModeTexture:IsShown() ) then
+ local alpha = 255;
+ local counter = self.attackModeCounter + elapsed;
+ local sign = self.attackModeSign;
+
+ if ( counter > 0.5 ) then
+ sign = -sign;
+ self.attackModeSign = sign;
+ end
+ counter = mod(counter, 0.5);
+ self.attackModeCounter = counter;
+
+ if ( sign == 1 ) then
+ alpha = (55 + (counter * 400)) / 255;
+ else
+ alpha = (255 - (counter * 400)) / 255;
+ end
+ PetAttackModeTexture:SetVertexColor(1.0, 1.0, 1.0, alpha);
+ end
+ CombatFeedback_OnUpdate(self, elapsed);
+ -- Expiration flash stuff
+ --local petTimeRemaining = nil;
+ --if ( GetPetTimeRemaining() ) then
+ --- if ( self.flashState == 1 ) then
+ -- self:SetAlpha(this.flashTimer/PET_FLASH_ON_TIME);
+ -- else
+ -- self:SetAlpha((PET_FLASH_OFF_TIME - this.flashTimer)/PET_FLASH_OFF_TIME);
+ -- end
+ -- petTimeRemaining = GetPetTimeRemaining() / 1000;
+ --end
+ --if ( petTimeRemaining and (petTimeRemaining < PET_WARNING_TIME) ) then
+ -- PetFrame.flashTimer = PetFrame.flashTimer - elapsed;
+ -- if ( PetFrame.flashTimer <= 0 ) then
+ -- if ( PetFrame.flashState == 1 ) then
+ -- PetFrame.flashState = 0;
+ -- PetFrame.flashTimer = PET_FLASH_OFF_TIME;
+ -- else
+ -- PetFrame.flashState = 1;
+ -- PetFrame.flashTimer = PET_FLASH_ON_TIME;
+ -- end
+ -- end
+ --end
+
+end
+
+function PetFrame_SetHappiness ()
+ local happiness, damagePercentage = GetPetHappiness();
+ local hasPetUI, isHunterPet = HasPetUI();
+ if ( not happiness or not isHunterPet ) then
+ PetFrameHappiness:Hide();
+ return;
+ end
+ PetFrameHappiness:Show();
+ if ( happiness == 1 ) then
+ PetFrameHappinessTexture:SetTexCoord(0.375, 0.5625, 0, 0.359375);
+ elseif ( happiness == 2 ) then
+ PetFrameHappinessTexture:SetTexCoord(0.1875, 0.375, 0, 0.359375);
+ elseif ( happiness == 3 ) then
+ PetFrameHappinessTexture:SetTexCoord(0, 0.1875, 0, 0.359375);
+ end
+ PetFrameHappiness.tooltip = _G["PET_HAPPINESS"..happiness];
+ PetFrameHappiness.tooltipDamage = format(PET_DAMAGE_PERCENTAGE, damagePercentage);
+end
+
+function PetFrameDropDown_OnLoad (self)
+ UIDropDownMenu_Initialize(self, PetFrameDropDown_Initialize, "MENU");
+end
+
+function PetFrameDropDown_Initialize ()
+ if ( UnitExists(PetFrame.unit) ) then
+ if ( PetFrame.unit == "player" ) then
+ UnitPopup_ShowMenu(PetFrameDropDown, "SELF", "player");
+ else
+ if ( UnitIsUnit("pet", "vehicle") ) then
+ UnitPopup_ShowMenu(PetFrameDropDown, "VEHICLE", "vehicle");
+ else
+ UnitPopup_ShowMenu(PetFrameDropDown, "PET", "pet");
+ end
+ end
+ end
+end
+
+function PetCastingBarFrame_OnLoad (self)
+ CastingBarFrame_OnLoad(self, "pet", false, false);
+
+ self:RegisterEvent("UNIT_PET");
+
+ self.showCastbar = UnitIsPossessed("pet");
+end
+
+function PetCastingBarFrame_OnEvent (self, event, ...)
+ local arg1 = ...;
+ if ( event == "UNIT_PET" ) then
+ if ( arg1 == "player" ) then
+ self.showCastbar = UnitIsPossessed("pet");
+
+ if ( not self.showCastbar ) then
+ self:Hide();
+ elseif ( self.casting or self.channeling ) then
+ self:Show();
+ end
+ end
+ return;
+ end
+ CastingBarFrame_OnEvent(self, event, ...);
+end
diff --git a/reference/FrameXML/PetFrame.xml b/reference/FrameXML/PetFrame.xml
new file mode 100644
index 0000000..e59549f
--- /dev/null
+++ b/reference/FrameXML/PetFrame.xml
@@ -0,0 +1,313 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ self.textLockable = 1;
+ self.cvar = "petStatusText";
+ self.cvarLabel = "STATUS_TEXT_PET";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ self.textLockable = 1;
+ self.cvar = "petStatusText";
+ self.cvarLabel = "STATUS_TEXT_PET";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetUnitDebuff(PetFrame.unit, self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetUnitDebuff(PetFrame.unit, self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetUnitDebuff(PetFrame.unit, self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetUnitDebuff(PetFrame.unit, self:GetID());
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( self.tooltip ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip);
+ if ( self.tooltipDamage ) then
+ GameTooltip:AddLine(self.tooltipDamage, "", 1, 1, 1);
+ end
+ GameTooltip:Show();
+ end
+
+
+
+
+
+
+
+
+
+ UnitFrame_Update(self);
+ PetFrame_Update(self);
+ TotemFrame_Update(self);
+
+
+
+
+ UnitFrame_OnEnter(self);
+ PartyMemberBuffTooltip:SetPoint("TOPLEFT", self, "TOPLEFT", 60, -35);
+ PartyMemberBuffTooltip_Update(self);
+
+
+ UnitFrame_OnLeave(self);
+ PartyMemberBuffTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/PetPaperDollFrame.lua b/reference/FrameXML/PetPaperDollFrame.lua
new file mode 100644
index 0000000..000973d
--- /dev/null
+++ b/reference/FrameXML/PetPaperDollFrame.lua
@@ -0,0 +1,632 @@
+NUM_PET_RESISTANCE_TYPES = 5;
+NUM_PET_STATS = 5;
+NUM_COMPANIONS_PER_PAGE = 12;
+
+function PetPaperDollFrame_OnLoad (self)
+ self:RegisterEvent("PET_UI_UPDATE");
+ self:RegisterEvent("PET_BAR_UPDATE");
+ self:RegisterEvent("PET_UI_CLOSE");
+ self:RegisterEvent("UNIT_NAME_UPDATE");
+ self:RegisterEvent("UNIT_PET");
+ self:RegisterEvent("UNIT_PET_EXPERIENCE");
+ self:RegisterEvent("UNIT_MODEL_CHANGED");
+ self:RegisterEvent("UNIT_LEVEL");
+ self:RegisterEvent("UNIT_RESISTANCES");
+ self:RegisterEvent("UNIT_STATS");
+ self:RegisterEvent("UNIT_DAMAGE");
+ self:RegisterEvent("UNIT_RANGEDDAMAGE");
+ self:RegisterEvent("UNIT_ATTACK_SPEED");
+ self:RegisterEvent("UNIT_ATTACK_POWER");
+ self:RegisterEvent("UNIT_RANGED_ATTACK_POWER");
+ self:RegisterEvent("UNIT_DEFENSE");
+ self:RegisterEvent("UNIT_ATTACK");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("COMPANION_LEARNED");
+ self:RegisterEvent("COMPANION_UNLEARNED");
+ self:RegisterEvent("COMPANION_UPDATE");
+ self:RegisterEvent("SPELL_UPDATE_COOLDOWN");
+ self:RegisterEvent("UNIT_ENTERED_VEHICLE");
+ self:RegisterEvent("UNIT_EXITED_VEHICLE");
+ self:RegisterEvent("PET_SPELL_POWER_UPDATE");
+
+ PetPaperDollFrameCompanionFrame.mode = "CRITTER";
+ PetPaperDollFrameCompanionFrame.idMount = GetCompanionInfo("MOUNT", 1);
+ PetPaperDollFrameCompanionFrame.pageMount = 0;
+ PetPaperDollFrameCompanionFrame.idCritter = GetCompanionInfo("CRITTER", 1);
+ PetPaperDollFrameCompanionFrame.pageCritter = 0;
+
+ PetDamageFrameLabel:SetText(format(STAT_FORMAT, DAMAGE));
+ PetAttackPowerFrameLabel:SetText(format(STAT_FORMAT, ATTACK_POWER));
+ PetArmorFrameLabel:SetText(format(STAT_FORMAT, ARMOR));
+ SetTextStatusBarTextPrefix(PetPaperDollFrameExpBar, XP);
+ PetSpellDamageFrameLabel:SetText(format(STAT_FORMAT, SPELL_BONUS));
+end
+
+local tabPoints={
+ [1]={ point="TOPLEFT", relativeTo="PetPaperDollFrameCompanionFrame", relativePoint="TOPLEFT", xoffset=70, yoffset=-39},
+ [2]={ point="LEFT", relativePoint="RIGHT", xoffset=0, yoffset=0},
+ [3]={ point="LEFT", relativePoint="RIGHT", xoffset=0, yoffset=0},
+}
+
+function PetPaperDollFrame_UpdateIsAvailable()
+ if ( (not HasPetUI()) and (GetNumCompanions("CRITTER") == 0) and (GetNumCompanions("MOUNT") == 0) ) then
+ PetPaperDollFrame.hidden = true;
+ CharacterFrameTab2:Hide();
+ CharacterFrameTab3:SetPoint("LEFT", "CharacterFrameTab2", "LEFT", 0, 0);
+ if ( PetPaperDollFrame:IsVisible() ) then --We have the pet frame selected, but nothing to show on it
+ ToggleCharacter("PaperDollFrame");
+ end
+ else
+ PetPaperDollFrame.hidden = false;
+ CharacterFrameTab2:Show();
+ CharacterFrameTab3:SetPoint("LEFT", "CharacterFrameTab2", "RIGHT", -16, 0);
+ end
+end
+
+function PetPaperDollFrame_UpdateTabs()
+ if ( not PetPaperDollFrame:IsVisible() ) then
+ -- There's no need to run this when the frame isn't shown (i.e. we're zoning), it causes problems with the subtabs (bug 145137)
+ PetPaperDollFrame_UpdateIsAvailable(); --But we still need to update the tabs on the CharacterFrame (bug 150500)
+ return;
+ end
+
+ local currVal, currRef = 1, tabPoints[1];
+
+ --PetPaperDollFrameTab1:ClearAllPoints() --Never moved, just hidden
+ PetPaperDollFrameTab2:ClearAllPoints()
+ PetPaperDollFrameTab3:ClearAllPoints()
+ if ( HasPetUI() ) then
+ PetPaperDollFrameTab1:Show();
+ PetPaperDollFrameTab1:SetPoint(currRef.point, currRef.relativeTo, currRef.relativePoint, currRef.xoffset, currRef.yoffset)
+ currVal = currVal + 1;
+ currRef = tabPoints[currVal];
+ currRef.relativeTo = PetPaperDollFrameTab1;
+ else
+ PetPaperDollFrameTab1:Hide();
+ end
+
+ if ( GetNumCompanions("CRITTER") > 0 ) then
+ PetPaperDollFrameTab2:Show();
+ PetPaperDollFrameTab2:SetPoint(currRef.point, currRef.relativeTo, currRef.relativePoint, currRef.xoffset, currRef.yoffset);
+ currVal = currVal + 1;
+ currRef = tabPoints[currVal];
+ currRef.relativeTo = PetPaperDollFrameTab2;
+ else
+ PetPaperDollFrameTab2:Hide();
+ end
+
+ if ( GetNumCompanions("MOUNT") > 0 ) then
+ PetPaperDollFrameTab3:Show();
+ PetPaperDollFrameTab3:SetPoint(currRef.point, currRef.relativeTo, currRef.relativePoint, currRef.xoffset, currRef.yoffset);
+ currVal = currVal + 1;
+ else
+ PetPaperDollFrameTab3:Hide();
+ end
+
+ PetPaperDollFrame_UpdateIsAvailable();
+
+ local selectedTab = PanelTemplates_GetSelectedTab(PetPaperDollFrame);
+ if ( (not PetPaperDollFrame.selectedTab) or (not PetPaperDollFrame_BeenViewed) or (not _G["PetPaperDollFrameTab"..selectedTab]:IsShown()) ) then
+ if ( PetPaperDollFrameTab1:IsShown() ) then
+ PetPaperDollFrame_SetTab(1);
+ elseif ( PetPaperDollFrameTab2:IsShown() ) then
+ PetPaperDollFrame_SetTab(2);
+ elseif ( PetPaperDollFrameTab3:IsShown() ) then
+ PetPaperDollFrame_SetTab(3);
+ else
+ if ( PetPaperDollFrame:IsVisible() ) then
+ ToggleCharacter("PaperDollFrame");
+ end
+ end
+ end
+
+ if ( currVal == 2 ) then --Only 1 tab shown, so no reason to make it visible.
+ PetPaperDollFrameTab1:Hide();
+ PetPaperDollFrameTab2:Hide();
+ PetPaperDollFrameTab3:Hide();
+ end
+end
+
+function PetPaperDollFrame_OnEvent (self, event, ...)
+ local arg1 = ...;
+ if ( event == "PET_UI_UPDATE" or event == "PET_UI_CLOSE" or event == "PET_BAR_UPDATE" or (event == "UNIT_PET" and arg1 == "player") or
+ (event == "UNIT_NAME_UPDATE" and arg1 == "pet") ) then
+ PetPaperDollFrame_UpdateTabs();
+ PetPaperDollFrame_Update();
+ elseif ( event == "UNIT_PET_EXPERIENCE" ) then
+ PetExpBar_Update();
+ elseif ( event == "COMPANION_LEARNED" ) then
+ if ( not CharacterFrame:IsVisible() ) then
+ SetButtonPulse(CharacterMicroButton, 60, 1);
+ end
+ if ( not PetPaperDollFrame:IsVisible() ) then
+ SetButtonPulse(CharacterFrameTab2, 60, 1);
+ end
+ PetPaperDollFrame_UpdateTabs();
+ --PetPaperDollFrame_UpdateCompanions(); --This is called in SetCompanionPage
+ PetPaperDollFrame_SetCompanionPage((PetPaperDollFrameCompanionFrame.mode=="MOUNT") and PetPaperDollFrameCompanionFrame.pageMount or PetPaperDollFrameCompanionFrame.pageCritter);
+ elseif ( event == "COMPANION_UNLEARNED" ) then
+ local page;
+ local numCompanions = GetNumCompanions(PetPaperDollFrameCompanionFrame.mode);
+ if ( PetPaperDollFrameCompanionFrame.mode=="MOUNT" ) then
+ page = PetPaperDollFrameCompanionFrame.pageMount;
+ if ( numCompanions > 0 ) then
+ PetPaperDollFrameCompanionFrame.idMount = GetCompanionInfo("MOUNT", 1);
+ PetPaperDollFrame_UpdateCompanionPreview();
+ else
+ PetPaperDollFrameCompanionFrame.idMount = nil;
+ end
+ else
+ page = PetPaperDollFrameCompanionFrame.pageCritter;
+ if ( numCompanions > 0 ) then
+ PetPaperDollFrameCompanionFrame.idCritter = GetCompanionInfo("CRITTER", 1);
+ PetPaperDollFrame_UpdateCompanionPreview()
+ else
+ PetPaperDollFrameCompanionFrame.idCritter = nil;
+ end
+ end
+ page = min(ceil(numCompanions/NUM_COMPANIONS_PER_PAGE) - 1, page);
+ page = max(page, 0);
+ PetPaperDollFrame_SetCompanionPage(page); -- The pages are 0 based to make the mathematical calculations slightly faster.
+ PetPaperDollFrame_UpdateTabs();
+ elseif ( event == "COMPANION_UPDATE" ) then
+ if ( not PetPaperDollFrameCompanionFrame.idMount ) then
+ PetPaperDollFrameCompanionFrame.idMount = GetCompanionInfo("MOUNT", 1);
+ end
+ if ( not PetPaperDollFrameCompanionFrame.idCritter ) then
+ PetPaperDollFrameCompanionFrame.idCritter = GetCompanionInfo("CRITTER", 1);
+ end
+ PetPaperDollFrame_UpdateCompanions();
+ elseif ( event == "SPELL_UPDATE_COOLDOWN" ) then
+ if ( self:IsVisible() ) then
+ PetPaperDollFrame_UpdateCompanionCooldowns();
+ end
+ elseif( event == "PET_SPELL_POWER_UPDATE" ) then
+ PetPaperDollFrame_SetSpellBonusDamage();
+ elseif ( (event == "UNIT_ENTERED_VEHICLE" or event == "UNIT_EXITED_VEHICLE") and (arg1 == "player")) then
+ PetPaperDollFrame_UpdateCompanions();
+ elseif ( arg1 == "pet" ) then
+ PetPaperDollFrame_Update();
+ end
+end
+
+function PetPaperDollFrame_SetTab(id)
+ if ( (id == 1) and HasPetUI() ) then --Pet Tab
+ PetPaperDollFrame.selectedTab=1;
+ PetPaperDollFramePetFrame:Show();
+ PetPaperDollFrameCompanionFrame:Hide();
+ PetNameText:SetText(UnitName("pet"));
+ elseif ( (id == 2) and (GetNumCompanions("CRITTER") > 0) ) then --Critter Tab
+ PetPaperDollFrame.selectedTab=2;
+ PetPaperDollFrameCompanionFrame.mode="CRITTER";
+ PetPaperDollFramePetFrame:Hide();
+ PetPaperDollFrameCompanionFrame:Show();
+ PetPaperDollFrame_SetCompanionPage(PetPaperDollFrameCompanionFrame.pageCritter);
+ for i=1,NUM_COMPANIONS_PER_PAGE do
+ _G["CompanionButton"..i]:SetDisabledTexture([[Interface\PetPaperDollFrame\UI-PetFrame-Slots-Companions]])
+ end
+ PetPaperDollFrame_UpdateCompanions();
+ PetPaperDollFrame_UpdateCompanionPreview();
+ PetNameText:SetText(COMPANIONS);
+ elseif ( (id == 3) and (GetNumCompanions("MOUNT") > 0) ) then --Mount Tab
+ PetPaperDollFrame.selectedTab=3;
+ PetPaperDollFrameCompanionFrame.mode="MOUNT";
+ PetPaperDollFramePetFrame:Hide();
+ PetPaperDollFrameCompanionFrame:Show();
+ PetPaperDollFrame_SetCompanionPage(PetPaperDollFrameCompanionFrame.pageMount);
+ for i=1,NUM_COMPANIONS_PER_PAGE do
+ _G["CompanionButton"..i]:SetDisabledTexture([[Interface\PetPaperDollFrame\UI-PetFrame-Slots-Mounts]]);
+ end
+ PetPaperDollFrame_UpdateCompanions();
+ PetPaperDollFrame_UpdateCompanionPreview();
+ PetNameText:SetText(MOUNTS);
+ end
+
+ for i=1,3 do
+ if ( i == id ) then
+ PanelTemplates_SelectTab(_G["PetPaperDollFrameTab"..i]);
+ else
+ PanelTemplates_DeselectTab(_G["PetPaperDollFrameTab"..i]);
+ end
+ end
+end
+
+function PetPaperDollFrame_FindCompanionIndex(creatureID, mode)
+ if ( not mode ) then
+ mode = PetPaperDollFrameCompanionFrame.mode;
+ end
+ if (not creatureID ) then
+ creatureID = (PetPaperDollFrameCompanionFrame.mode=="MOUNT") and PetPaperDollFrameCompanionFrame.idMount or PetPaperDollFrameCompanionFrame.idCritter;
+ end
+ for i=1,GetNumCompanions(mode) do
+ if ( GetCompanionInfo(mode, i) == creatureID ) then
+ return i;
+ end
+ end
+ return 0
+end
+
+function CompanionSummonButton_OnClick()
+ local selected = PetPaperDollFrame_FindCompanionIndex();
+ local creatureID, creatureName, spellID, icon, active = GetCompanionInfo(PetPaperDollFrameCompanionFrame.mode, selected);
+ if ( active ) then
+ DismissCompanion(PetPaperDollFrameCompanionFrame.mode);
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ CallCompanion(PetPaperDollFrameCompanionFrame.mode, selected);
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+end
+
+function CompanionButton_OnLoad(self)
+ self:RegisterForDrag("LeftButton");
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+end
+
+function CompanionButton_OnDrag(self)
+ local offset;
+
+ if ( PetPaperDollFrameCompanionFrame.mode=="CRITTER" ) then
+ offset = (PetPaperDollFrameCompanionFrame.pageCritter or 0)*NUM_COMPANIONS_PER_PAGE;
+ elseif ( PetPaperDollFrameCompanionFrame.mode=="MOUNT" ) then
+ offset = (PetPaperDollFrameCompanionFrame.pageMount or 0)*NUM_COMPANIONS_PER_PAGE;
+ end
+ local dragged = self:GetID() + offset;
+ PickupCompanion( PetPaperDollFrameCompanionFrame.mode, dragged );
+end
+
+function CompanionButton_OnClick(self, button)
+ local selected, selectedID;
+ if ( PetPaperDollFrameCompanionFrame.mode == "CRITTER" ) then
+ selected = PetPaperDollFrame_FindCompanionIndex(PetPaperDollFrameCompanionFrame.idCritter);
+ selectedID = PetPaperDollFrameCompanionFrame.idCritter;
+ elseif ( PetPaperDollFrameCompanionFrame.mode == "MOUNT" ) then
+ selected = PetPaperDollFrame_FindCompanionIndex(PetPaperDollFrameCompanionFrame.idMount);
+ selectedID = PetPaperDollFrameCompanionFrame.idMount;
+ end
+
+ if ( button ~= "LeftButton" or ( selectedID == self.creatureID) ) then
+ local offset;
+ if ( PetPaperDollFrameCompanionFrame.mode == "CRITTER" ) then
+ offset = (PetPaperDollFrameCompanionFrame.pageCritter or 0) * NUM_COMPANIONS_PER_PAGE;
+ elseif ( PetPaperDollFrameCompanionFrame.mode == "MOUNT" ) then
+ offset = (PetPaperDollFrameCompanionFrame.pageMount or 0) * NUM_COMPANIONS_PER_PAGE;
+ end
+ local index = self:GetID() + offset;
+ if ( self.active ) then
+ DismissCompanion(PetPaperDollFrameCompanionFrame.mode);
+ else
+ CallCompanion(PetPaperDollFrameCompanionFrame.mode, index);
+ end
+ else
+ if ( PetPaperDollFrameCompanionFrame.mode == "CRITTER" ) then
+ PetPaperDollFrameCompanionFrame.idCritter = self.creatureID;
+ PetPaperDollFrame_UpdateCompanionPreview();
+ elseif ( PetPaperDollFrameCompanionFrame.mode == "MOUNT" ) then
+ PetPaperDollFrameCompanionFrame.idMount = self.creatureID;
+ PetPaperDollFrame_UpdateCompanionPreview();
+ end
+ end
+
+ PetPaperDollFrame_UpdateCompanions();
+end
+
+function CompanionButton_OnModifiedClick(self)
+ local id = self.spellID;
+ if ( IsModifiedClick("CHATLINK") ) then
+ if ( MacroFrame and MacroFrame:IsShown() ) then
+ local spellName = GetSpellInfo(id);
+ ChatEdit_InsertLink(spellName);
+ else
+ local spellLink = GetSpellLink(id)
+ ChatEdit_InsertLink(spellLink);
+ end
+ elseif ( IsModifiedClick("PICKUPACTION") ) then
+ CompanionButton_OnDrag(self);
+ end
+ PetPaperDollFrame_UpdateCompanions(); --Set up the highlights again
+end
+function CompanionButton_OnEnter(self)
+ if ( GetCVar("UberTooltips") == "1" ) then
+ GameTooltip_SetDefaultAnchor(GameTooltip, self);
+ else
+ GameTooltip:SetOwner(self, "ANCHOR_LEFT");
+ end
+
+ if ( GameTooltip:SetHyperlink("spell:"..self.spellID) ) then
+ self.UpdateTooltip = CompanionButton_OnEnter;
+ else
+ self.UpdateTooltip = nil;
+ end
+
+ GameTooltip:Show()
+end
+
+function PetPaperDollFrame_SetCompanionPage(num)
+ if ( PetPaperDollFrameCompanionFrame.mode == "CRITTER" ) then
+ PetPaperDollFrameCompanionFrame.pageCritter = num;
+ elseif ( PetPaperDollFrameCompanionFrame.mode == "MOUNT" ) then
+ PetPaperDollFrameCompanionFrame.pageMount = num;
+ end
+
+ num = num + 1; --For easier usage
+ local maxpage = ceil(GetNumCompanions(PetPaperDollFrameCompanionFrame.mode)/NUM_COMPANIONS_PER_PAGE);
+ CompanionPageNumber:SetFormattedText(MERCHANT_PAGE_NUMBER,num, maxpage);
+ if ( num <= 1 ) then
+ CompanionPrevPageButton:Disable();
+ else
+ CompanionPrevPageButton:Enable();
+ end
+ if ( num >= maxpage ) then
+ CompanionNextPageButton:Disable();
+ else
+ CompanionNextPageButton:Enable();
+ end
+ PetPaperDollFrame_UpdateCompanions();
+ PetPaperDollFrame_UpdateCompanionCooldowns();
+end
+
+function PetPaperDollFrame_UpdateCompanions()
+ local button, iconTexture, id;
+ local creatureID, creatureName, spellID, icon, active;
+ local offset, selected;
+
+ if ( PetPaperDollFrameCompanionFrame.mode == "CRITTER" ) then
+ offset = (PetPaperDollFrameCompanionFrame.pageCritter or 0)*NUM_COMPANIONS_PER_PAGE;
+ selected = PetPaperDollFrame_FindCompanionIndex(PetPaperDollFrameCompanionFrame.idCritter);
+ elseif ( PetPaperDollFrameCompanionFrame.mode == "MOUNT" ) then
+ offset = (PetPaperDollFrameCompanionFrame.pageMount or 0)*NUM_COMPANIONS_PER_PAGE;
+ selected = PetPaperDollFrame_FindCompanionIndex(PetPaperDollFrameCompanionFrame.idMount);
+ end
+
+ for i = 1, NUM_COMPANIONS_PER_PAGE do
+ button = _G["CompanionButton"..i];
+ id = i + (offset or 0);
+ creatureID, creatureName, spellID, icon, active = GetCompanionInfo(PetPaperDollFrameCompanionFrame.mode, id);
+ button.creatureID = creatureID;
+ button.spellID = spellID;
+ button.active = active;
+ if ( creatureID ) then
+ button:SetNormalTexture(icon);
+ button:Enable();
+ else
+ button:Disable();
+ end
+ if ( (id == selected) and creatureID ) then
+ button:SetChecked(true);
+ else
+ button:SetChecked(false);
+ end
+
+ if ( active ) then
+ _G["CompanionButton"..i.."ActiveTexture"]:Show();
+ else
+ _G["CompanionButton"..i.."ActiveTexture"]:Hide();
+ end
+ end
+
+ if ( selected > 0 ) then
+ creatureID, creatureName, spellID, icon, active = GetCompanionInfo(PetPaperDollFrameCompanionFrame.mode, selected);
+ if ( active and creatureID ) then
+ CompanionSummonButton:SetText(PetPaperDollFrameCompanionFrame.mode == "MOUNT" and BINDING_NAME_DISMOUNT or PET_DISMISS);
+ else
+ CompanionSummonButton:SetText(PetPaperDollFrameCompanionFrame.mode == "MOUNT" and MOUNT or SUMMON);
+ end
+ end
+end
+
+function PetPaperDollFrame_UpdateCompanionCooldowns()
+ local offset;
+ if ( PetPaperDollFrameCompanionFrame.mode == "CRITTER" ) then
+ offset = (PetPaperDollFrameCompanionFrame.pageCritter or 0)*NUM_COMPANIONS_PER_PAGE;
+ elseif ( PetPaperDollFrameCompanionFrame.mode == "MOUNT" ) then
+ offset = (PetPaperDollFrameCompanionFrame.pageMount or 0)*NUM_COMPANIONS_PER_PAGE;
+ end
+ for i = 1, NUM_COMPANIONS_PER_PAGE do
+ local button = _G["CompanionButton"..i];
+ local cooldown = _G[button:GetName().."Cooldown"];
+ if ( button.creatureID ) then
+ local start, duration, enable = GetCompanionCooldown(PetPaperDollFrameCompanionFrame.mode, offset + button:GetID());
+ if ( start and duration and enable ) then
+ CooldownFrame_SetTimer(cooldown, start, duration, enable);
+ end
+ else
+ cooldown:Hide();
+ end
+ end
+end
+
+function PetPaperDollFrame_UpdateCompanionPreview()
+ local selected = PetPaperDollFrame_FindCompanionIndex();
+
+ if (selected > 0) then
+ local creatureID, creatureName = GetCompanionInfo(PetPaperDollFrameCompanionFrame.mode, selected);
+ CompanionModelFrame:SetCreature(creatureID);
+ CompanionSelectedName:SetText(creatureName);
+ end
+end
+
+PetPaperDollFrame_BeenViewed = false;
+function PetPaperDollFrame_OnShow(self)
+ if ( self:IsVisible() ) then
+ PetPaperDollFrame_BeenViewed = true;
+ end
+ SetButtonPulse(CharacterFrameTab2, 0, 1); --Stop the button pulse
+ CharacterNameText:Hide();
+ PetNameText:Show();
+ PetPaperDollFrame_Update();
+ PetPaperDollFrame_UpdateTabs();
+end
+
+function PetPaperDollFrame_OnHide()
+ CharacterNameText:Show();
+ PetNameText:Hide();
+end
+
+function PetPaperDollFrame_Update()
+ local hasPetUI, canGainXP = HasPetUI();
+ if ( not hasPetUI ) then
+ return;
+ end
+ PetModelFrame:SetUnit("pet");
+ if ( UnitCreatureFamily("pet") ) then
+ PetLevelText:SetFormattedText(UNIT_TYPE_LEVEL_TEMPLATE,UnitLevel("pet"),UnitCreatureFamily("pet"));
+ end
+ if ( PetPaperDollFramePetFrame:IsShown() ) then
+ PetNameText:SetText(UnitName("pet"));
+ end
+ PetExpBar_Update();
+ PetPaperDollFrame_SetResistances();
+ PetPaperDollFrame_SetStats();
+ PaperDollFrame_SetDamage(PetDamageFrame, "Pet");
+ PaperDollFrame_SetArmor(PetArmorFrame, "Pet");
+ PaperDollFrame_SetAttackPower(PetAttackPowerFrame, "Pet");
+ PetPaperDollFrame_SetSpellBonusDamage();
+
+ if ( canGainXP ) then
+ PetPaperDollPetInfo:Show();
+ else
+ PetPaperDollPetInfo:Hide();
+ end
+end
+
+function PetPaperDollFrame_SetResistances()
+ local resistance;
+ local positive;
+ local negative;
+ local base;
+ local index;
+ local text;
+ local frame;
+ for i=1, NUM_PET_RESISTANCE_TYPES, 1 do
+ index = i + 1;
+ if ( i == NUM_PET_RESISTANCE_TYPES ) then
+ index = 1;
+ end
+ text = _G["PetMagicResText"..i];
+ frame = _G["PetMagicResFrame"..i];
+
+ base, resistance, positive, negative = UnitResistance("pet", frame:GetID());
+
+ frame.tooltip = _G["RESISTANCE"..frame:GetID().."_NAME"];
+
+ -- resistances can now be negative. Show Red if negative, Green if positive, white otherwise
+ if( resistance < 0 ) then
+ text:SetText(RED_FONT_COLOR_CODE..resistance..FONT_COLOR_CODE_CLOSE);
+ elseif( resistance == 0 ) then
+ text:SetText(resistance);
+ else
+ text:SetText(GREEN_FONT_COLOR_CODE..resistance..FONT_COLOR_CODE_CLOSE);
+ end
+
+ if ( positive ~= 0 or negative ~= 0 ) then
+ -- Otherwise build up the formula
+ frame.tooltip = frame.tooltip.. " ( "..HIGHLIGHT_FONT_COLOR_CODE..base;
+ if( positive > 0 ) then
+ frame.tooltip = frame.tooltip..GREEN_FONT_COLOR_CODE.." +"..positive;
+ end
+ if( negative < 0 ) then
+ frame.tooltip = frame.tooltip.." "..RED_FONT_COLOR_CODE..negative;
+ end
+ frame.tooltip = frame.tooltip..FONT_COLOR_CODE_CLOSE.." )";
+ end
+ end
+end
+
+function PetPaperDollFrame_SetStats()
+ for i=1, NUM_PET_STATS, 1 do
+ local label = _G["PetStatFrame"..i.."Label"];
+ local text = _G["PetStatFrame"..i.."StatText"];
+ local frame = _G["PetStatFrame"..i];
+ local stat;
+ local effectiveStat;
+ local posBuff;
+ local negBuff;
+ label:SetText(format(STAT_FORMAT, _G["SPELL_STAT"..i.."_NAME"]));
+ stat, effectiveStat, posBuff, negBuff = UnitStat("pet", i);
+ -- Set the tooltip text
+ local tooltipText = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, _G["SPELL_STAT"..i.."_NAME"]).." ";
+
+ if ( ( posBuff == 0 ) and ( negBuff == 0 ) ) then
+ text:SetText(effectiveStat);
+ frame.tooltip = tooltipText..effectiveStat..FONT_COLOR_CODE_CLOSE;
+ else
+ tooltipText = tooltipText..effectiveStat;
+ if ( posBuff > 0 or negBuff < 0 ) then
+ tooltipText = tooltipText.." ("..(stat - posBuff - negBuff)..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( posBuff > 0 ) then
+ tooltipText = tooltipText..FONT_COLOR_CODE_CLOSE..GREEN_FONT_COLOR_CODE.."+"..posBuff..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( negBuff < 0 ) then
+ tooltipText = tooltipText..RED_FONT_COLOR_CODE.." "..negBuff..FONT_COLOR_CODE_CLOSE;
+ end
+ if ( posBuff > 0 or negBuff < 0 ) then
+ tooltipText = tooltipText..HIGHLIGHT_FONT_COLOR_CODE..")"..FONT_COLOR_CODE_CLOSE;
+ end
+ frame.tooltip = tooltipText;
+
+ -- If there are any negative buffs then show the main number in red even if there are
+ -- positive buffs. Otherwise show in green.
+ if ( negBuff < 0 ) then
+ text:SetText(RED_FONT_COLOR_CODE..effectiveStat..FONT_COLOR_CODE_CLOSE);
+ else
+ text:SetText(GREEN_FONT_COLOR_CODE..effectiveStat..FONT_COLOR_CODE_CLOSE);
+ end
+ end
+
+ -- Second tooltip line
+ frame.tooltip2 = _G["DEFAULT_STAT"..i.."_TOOLTIP"];
+ if ( i == 1 ) then
+ local attackPower = effectiveStat-20;
+ frame.tooltip2 = format(frame.tooltip2, attackPower);
+ elseif ( i == 2 ) then
+ local newLineIndex = strfind(frame.tooltip2, "|n")+1;
+ frame.tooltip2 = strsub(frame.tooltip2, 1, newLineIndex);
+ frame.tooltip2 = format(frame.tooltip2, GetCritChanceFromAgility("pet"));
+ elseif ( i == 3 ) then
+ local expectedHealthGain = (((stat - posBuff - negBuff)-20)*10+20)*GetUnitHealthModifier("pet");
+ local realHealthGain = ((effectiveStat-20)*10+20)*GetUnitHealthModifier("pet");
+ local healthGain = (realHealthGain - expectedHealthGain)*GetUnitMaxHealthModifier("pet");
+ frame.tooltip2 = format(frame.tooltip2, healthGain);
+ elseif ( i == 4 ) then
+ if ( UnitHasMana("pet") ) then
+ local manaGain = ((effectiveStat-20)*15+20)*GetUnitPowerModifier("pet");
+ frame.tooltip2 = format(frame.tooltip2, manaGain, GetSpellCritChanceFromIntellect("pet"));
+ else
+ local newLineIndex = strfind(frame.tooltip2, "|n")+2;
+ frame.tooltip2 = strsub(frame.tooltip2, newLineIndex);
+ frame.tooltip2 = format(frame.tooltip2, GetSpellCritChanceFromIntellect("pet"));
+ end
+ elseif ( i == 5 ) then
+ frame.tooltip2 = format(frame.tooltip2, GetUnitHealthRegenRateFromSpirit("pet"));
+ if ( UnitHasMana("pet") ) then
+ frame.tooltip2 = frame.tooltip2.."\n"..format(MANA_REGEN_FROM_SPIRIT, GetUnitManaRegenRateFromSpirit("pet"));
+ end
+ end
+ end
+end
+
+function PetPaperDollFrame_SetSpellBonusDamage()
+ local spellDamageBonus = GetPetSpellBonusDamage();
+ local spellDamageBonusText = format("%d",spellDamageBonus);
+
+ PetSpellDamageFrameLabel:SetText(format(STAT_FORMAT, SPELL_BONUS));
+ if ( spellDamageBonus > 0 ) then
+ spellDamageBonusText = GREEN_FONT_COLOR_CODE.."+"..spellDamageBonusText..FONT_COLOR_CODE_CLOSE;
+ elseif( spellDamageBonus < 0 ) then
+ spellDamageBonusText = RED_FONT_COLOR_CODE..spellDamageBonusText..FONT_COLOR_CODE_CLOSE;
+ end
+
+ PetSpellDamageFrameStatText:SetText(spellDamageBonusText);
+ PetSpellDamageFrame.tooltip = HIGHLIGHT_FONT_COLOR_CODE..format(PAPERDOLLFRAME_TOOLTIP_FORMAT, SPELL_BONUS)..FONT_COLOR_CODE_CLOSE.." "..spellDamageBonusText;
+ PetSpellDamageFrame.tooltip2 = DEFAULT_STATSPELLBONUS_TOOLTIP;
+
+ PetSpellDamageFrame:Show();
+end
+
+function PetExpBar_Update()
+ local currXP, nextXP = GetPetExperience();
+ PetPaperDollFrameExpBar:SetMinMaxValues(min(0, currXP), nextXP);
+ PetPaperDollFrameExpBar:SetValue(currXP);
+end
diff --git a/reference/FrameXML/PetPaperDollFrame.xml b/reference/FrameXML/PetPaperDollFrame.xml
new file mode 100644
index 0000000..32e9a5d
--- /dev/null
+++ b/reference/FrameXML/PetPaperDollFrame.xml
@@ -0,0 +1,990 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CompanionButton_OnLoad(self);
+
+
+ if ( IsModifiedClick() ) then
+ CompanionButton_OnModifiedClick(self, button);
+ else
+ CompanionButton_OnClick(self, button);
+ end
+ PlaySound("igMainMenuOptionCheckBoxOn");
+
+
+ CompanionButton_OnDrag(self, button);
+
+
+ CompanionButton_OnDrag(self);
+
+
+ CompanionButton_OnEnter(self, motion);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ SetTextStatusBarText(self, PetPaperDollFrameExpBarText);
+
+
+ TextStatusBar_UpdateTextString(self);
+ ShowTextStatusBarText(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Model_OnLoad(self);
+ self:RegisterEvent("DISPLAY_SIZE_CHANGED");
+
+
+ self:RefreshUnit();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateLeft(PetModelFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateRight(PetModelFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(format(PET_DIET_TEMPLATE, BuildListString(GetPetFoodTypes())));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(CharacterFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip(self, "pet");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip(self, "pet");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip(self, "pet");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip(self, "pet");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip(self, "pet");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip(self, "pet");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CharacterDamageFrame_OnEnter(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip(self, "pet");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PaperDollStatTooltip(self, "pet");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Model_OnLoad(self);
+ self:RegisterEvent("DISPLAY_SIZE_CHANGED");
+
+
+ self:RefreshUnit();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateLeft(CompanionModelFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateRight(CompanionModelFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PetPaperDollFrame_SetCompanionPage((PetPaperDollFrameCompanionFrame.mode=="MOUNT" and PetPaperDollFrameCompanionFrame.pageMount or PetPaperDollFrameCompanionFrame.pageCritter) - 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PetPaperDollFrame_SetCompanionPage(((PetPaperDollFrameCompanionFrame.mode=="MOUNT" and PetPaperDollFrameCompanionFrame.pageMount or PetPaperDollFrameCompanionFrame.pageCritter) or 0)+ 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PanelTemplates_TabResize(self, 0);
+ _G[self:GetName().."HighlightTexture"]:SetWidth(self:GetTextWidth() + 31);
+ self:SetFrameLevel(PetPaperDollFrameCompanionFrame:GetFrameLevel()+1);
+
+
+ if ( PetPaperDollFrame.selectedTab ~= 1 ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+ PetPaperDollFrame_SetTab(1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PanelTemplates_TabResize(self, 0);
+ _G[self:GetName().."HighlightTexture"]:SetWidth(self:GetTextWidth() + 31);
+ self:SetFrameLevel(PetPaperDollFrameCompanionFrame:GetFrameLevel()+1);
+
+
+ if ( PetPaperDollFrame.selectedTab ~= 2 ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+ PetPaperDollFrame_SetTab(2);
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PanelTemplates_TabResize(self, 0);
+ _G[self:GetName().."HighlightTexture"]:SetWidth(self:GetTextWidth() + 31);
+ self:SetFrameLevel(PetPaperDollFrameCompanionFrame:GetFrameLevel()+1);
+
+
+ if ( PetPaperDollFrame.selectedTab ~= 3 ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ end
+ PetPaperDollFrame_SetTab(3);
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/PetPopup.lua b/reference/FrameXML/PetPopup.lua
new file mode 100644
index 0000000..c8bcc83
--- /dev/null
+++ b/reference/FrameXML/PetPopup.lua
@@ -0,0 +1,8 @@
+
+function PetPopup_Confirm()
+ StaticPopup_Show("PETRENAMECONFIRM");
+end
+
+function PetPopup_Cancel()
+ PetRenamePopup:Hide();
+end
diff --git a/reference/FrameXML/PetPopup.xml b/reference/FrameXML/PetPopup.xml
new file mode 100644
index 0000000..f1f7f4a
--- /dev/null
+++ b/reference/FrameXML/PetPopup.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/PetStable.lua b/reference/FrameXML/PetStable.lua
new file mode 100644
index 0000000..2722a1e
--- /dev/null
+++ b/reference/FrameXML/PetStable.lua
@@ -0,0 +1,239 @@
+NUM_PET_STABLE_SLOTS = 4;
+
+function PetStable_OnLoad(self)
+ self:RegisterEvent("PET_STABLE_SHOW");
+ self:RegisterEvent("PET_STABLE_UPDATE");
+ self:RegisterEvent("PET_STABLE_UPDATE_PAPERDOLL");
+ self:RegisterEvent("PET_STABLE_CLOSED");
+ self:RegisterEvent("UNIT_PET");
+ self:RegisterEvent("UNIT_NAME_UPDATE");
+end
+
+function PetStable_OnEvent(self, event, ...)
+ local arg1 = ...;
+ if ( event == "PET_STABLE_SHOW" ) then
+ ShowUIPanel(self);
+ if ( not self:IsShown() ) then
+ ClosePetStables();
+ return;
+ end
+
+ PetStable_Update();
+ elseif ( event == "PET_STABLE_UPDATE" or
+ (event == "UNIT_PET" and arg1 == "player") or
+ (event == "UNIT_NAME_UPDATE" and arg1 == "pet") ) then
+ PetStable_Update();
+ elseif ( event == "PET_STABLE_UPDATE_PAPERDOLL" ) then
+ -- So warlock pets don't show
+ if ( UnitExists("pet") and not HasPetUI() ) then
+ PetStable_NoPetsAllowed();
+ return;
+ end
+ SetPetStablePaperdoll(PetStableModel);
+ elseif ( event == "PET_STABLE_CLOSED" ) then
+ HideUIPanel(self);
+ StaticPopup_Hide("CONFIRM_BUY_STABLE_SLOT");
+ end
+end
+
+function PetStable_Update()
+ -- Set stablemaster portrait
+ SetPortraitTexture(PetStableFramePortrait, "player");
+
+ -- So warlock pets don't show
+ local hasPetUI, isHunterPet = HasPetUI();
+ if ( UnitExists("pet") and hasPetUI and not isHunterPet ) then
+ PetStable_NoPetsAllowed();
+ PetStableCurrentPet:Disable();
+ return;
+ else
+ PetStableCurrentPet:Enable();
+ end
+
+ -- If no selected pet try to set one
+ local selectedPet = GetSelectedStablePet();
+ if ( selectedPet == -1 ) then
+ if ( GetPetIcon() ) then
+ selectedPet = 0;
+ ClickStablePet(0);
+ else
+ for i=0, NUM_PET_STABLE_SLOTS do
+ if ( GetStablePetInfo(i) ) then
+ selectedPet = i;
+ ClickStablePet(i);
+ break;
+ end
+ end
+ end
+ end
+
+ -- Set slot cost
+ MoneyFrame_Update("PetStableCostMoneyFrame", GetNextStableSlotCost());
+
+ -- Set slot statuseses
+ local numSlots = GetNumStableSlots();
+ local numPets = GetNumStablePets();
+
+ local button, buttonName;
+ local background;
+ local icon, name, level, family, talent;
+ for i=1, NUM_PET_STABLE_SLOTS do
+ buttonName = "PetStableStabledPet"..i;
+ button = _G[buttonName];
+ background = _G[buttonName.."Background"];
+ icon, name, level, family, talent = GetStablePetInfo(i);
+ SetItemButtonTexture(button, icon);
+ if ( i <= GetNumStableSlots() ) then
+ background:SetVertexColor(1.0,1.0,1.0);
+ button:Enable();
+ if ( icon ) then
+ button.tooltip = name;
+ button.tooltipSubtext = format(STABLE_PET_INFO_TOOLTIP_TEXT, level, family, talent);
+ else
+ button.tooltip = EMPTY_STABLE_SLOT;
+ button.tooltipSubtext = "";
+ end
+ if ( i == selectedPet ) then
+ if ( icon ) then
+ button:SetChecked(1);
+ PetStableLevelText:SetFormattedText(STABLE_PET_INFO_TEXT, name, level, family, talent);
+ SetPetStablePaperdoll(PetStableModel);
+ PetStablePetInfo.tooltip = format(PET_DIET_TEMPLATE, BuildListString(GetStablePetFoodTypes(i)));
+ if ( not PetStableModel:IsShown() ) then
+ PetStableModel:Show();
+ end
+ else
+ button:SetChecked(nil);
+ PetStableLevelText:SetText("");
+ PetStableModel:Hide();
+ end
+
+ else
+ button:SetChecked(nil);
+ end
+ if ( GameTooltip:IsOwned(button) ) then
+ GameTooltip:SetOwner(button, "ANCHOR_RIGHT");
+ GameTooltip:SetText(button.tooltip);
+ GameTooltip:AddLine(button.tooltipSubtext, 1.0, 1.0, 1.0);
+ GameTooltip:Show();
+ end
+ else
+ background:SetVertexColor(1.0, 0.1, 0.1);
+ button:Disable();
+ end
+ end
+
+ -- Current pet slot
+ if ( selectedPet == 0 ) then
+ if ( UnitExists("pet") and hasPetUI ) then
+ PetStableCurrentPet:SetChecked(1);
+ name = UnitName("pet") or "";
+ level = UnitLevel("pet");
+ family = UnitCreatureFamily("pet") or "";
+ talent = GetPetTalentTree() or "";
+ PetStableLevelText:SetFormattedText(STABLE_PET_INFO_TEXT, name, level, family, talent);
+ SetPetStablePaperdoll(PetStableModel);
+ if ( not PetStableModel:IsShown() ) then
+ PetStableModel:Show();
+ end
+ if ( GetPetFoodTypes() ) then
+ PetStablePetInfo.tooltip = format(PET_DIET_TEMPLATE, BuildListString(GetPetFoodTypes()));
+ end
+ elseif ( GetStablePetInfo(0) ) then
+ -- If pet doesn't exist it might be dismissed, so check stable slot 0 for current pet info
+ PetStableCurrentPet:SetChecked(1);
+ icon, name, level, family, talent = GetStablePetInfo(0);
+ PetStableLevelText:SetFormattedText(STABLE_PET_INFO_TEXT, name, level, family, talent);
+ SetPetStablePaperdoll(PetStableModel);
+ if ( not PetStableModel:IsShown() ) then
+ PetStableModel:Show();
+ end
+ if ( GetStablePetFoodTypes(0) ) then
+ PetStablePetInfo.tooltip = format(PET_DIET_TEMPLATE, BuildListString(GetStablePetFoodTypes(0)));
+ end
+ else
+ PetStableCurrentPet:SetChecked(nil);
+ PetStableLevelText:SetText("");
+ PetStableModel:Hide();
+ end
+ else
+ PetStableCurrentPet:SetChecked(nil);
+ end
+
+ -- Set tooltip and icon info
+ if ( GetPetIcon() and UnitCreatureFamily("pet") ) then
+ SetItemButtonTexture(PetStableCurrentPet, GetPetIcon());
+ name = UnitName("pet") or "";
+ level = UnitLevel("pet");
+ family = UnitCreatureFamily("pet") or "";
+ talent = GetPetTalentTree() or "";
+ PetStableCurrentPet.tooltip = name;
+ PetStableCurrentPet.tooltipSubtext = format(STABLE_PET_INFO_TOOLTIP_TEXT, level, family, talent);
+ elseif ( GetStablePetInfo(0) ) then
+ icon, name, level, family, talent = GetStablePetInfo(0);
+ SetItemButtonTexture(PetStableCurrentPet, icon);
+ PetStableCurrentPet.tooltip = name;
+ PetStableCurrentPet.tooltipSubtext = format(STABLE_PET_INFO_TOOLTIP_TEXT, level, family, talent);
+ else
+ SetItemButtonTexture(PetStableCurrentPet, "");
+ PetStableCurrentPet.tooltip = EMPTY_STABLE_SLOT;
+ PetStableCurrentPet.tooltipSubtext = "";
+ PetStableCurrentPet:SetChecked(nil);
+ end
+ if ( GameTooltip:IsOwned(PetStableCurrentPet) ) then
+ GameTooltip:SetOwner(PetStableCurrentPet, "ANCHOR_RIGHT");
+ GameTooltip:SetText(PetStableCurrentPet.tooltip);
+ GameTooltip:AddLine(PetStableCurrentPet.tooltipSubtext, 1.0, 1.0, 1.0);
+ GameTooltip:Show();
+ end
+
+ -- If no selected pet clear everything out
+ if ( selectedPet == -1 ) then
+ -- no pet
+ PetStableModel:Hide();
+ PetStableLevelText:SetText("");
+ end
+
+ -- Enable, disable, or hide purchase button
+ PetStablePurchaseButton:Show();
+ if ( GetNumStableSlots() == NUM_PET_STABLE_SLOTS or (not IsAtStableMaster())) then
+ PetStablePurchaseButton:Hide();
+ PetStableCostLabel:Hide();
+ PetStableCostMoneyFrame:Hide();
+ PetStableSlotText:Hide();
+ elseif ( GetMoney() >= GetNextStableSlotCost() ) then
+ PetStablePurchaseButton:Show();
+ PetStablePurchaseButton:Enable();
+ PetStableCostLabel:Show();
+ PetStableCostMoneyFrame:Show();
+ PetStableSlotText:Show();
+ SetMoneyFrameColor("PetStableCostMoneyFrame", "white");
+ else
+ PetStablePurchaseButton:Show();
+ PetStablePurchaseButton:Disable();
+ PetStableCostLabel:Show();
+ PetStableCostMoneyFrame:Show();
+ PetStableSlotText:Show();
+ SetMoneyFrameColor("PetStableCostMoneyFrame", "red");
+ end
+end
+
+function PetStable_NoPetsAllowed()
+ local button;
+ for i=1, NUM_PET_STABLE_SLOTS do
+ button = _G["PetStableStabledPet"..i];
+ button.tooltip = EMPTY_STABLE_SLOT;
+ button:SetChecked(nil);
+ end
+
+ PetStableCurrentPet:SetChecked(nil);
+ PetStableLevelText:SetText("");
+ PetStableModel:Hide();
+ SetItemButtonTexture(PetStableCurrentPet, "");
+ PetStableCurrentPet.tooltip = EMPTY_STABLE_SLOT;
+ PetStableCurrentPet:SetChecked(nil);
+ PetStablePurchaseButton:Hide();
+ PetStableCostLabel:Hide();
+ PetStableCostMoneyFrame:Hide();
+ PetStableSlotText:Hide();
+end
diff --git a/reference/FrameXML/PetStable.xml b/reference/FrameXML/PetStable.xml
new file mode 100644
index 0000000..2f848e4
--- /dev/null
+++ b/reference/FrameXML/PetStable.xml
@@ -0,0 +1,405 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForDrag("LeftButton");
+
+
+ if (self.tooltip) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip);
+ GameTooltip:AddLine(self.tooltipSubtext, "", 1.0, 1.0, 1.0);
+ GameTooltip:Show();
+ end
+
+
+ GameTooltip:Hide();
+
+
+ if ( ClickStablePet(self:GetID()) ) then
+ PetStable_Update();
+ end
+
+
+ PickupStablePet(self:GetID());
+
+
+ if ( ClickStablePet(self:GetID()) ) then
+ PetStable_Update();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Model_OnLoad(self);
+ self:RegisterEvent("DISPLAY_SIZE_CHANGED");
+
+
+ self:RefreshUnit();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateLeft(PetStableModel);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterForClicks("LeftButtonDown", "LeftButtonUp");
+
+
+ Model_RotateRight(PetStableModel);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ StaticPopup_Show("CONFIRM_BUY_STABLE_SLOT");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("igCharacterInfoOpen");
+
+
+ ClosePetStables();
+ PlaySound("igCharacterInfoClose");
+
+
+
+
+
diff --git a/reference/FrameXML/PetitionFrame.lua b/reference/FrameXML/PetitionFrame.lua
new file mode 100644
index 0000000..dca35a6
--- /dev/null
+++ b/reference/FrameXML/PetitionFrame.lua
@@ -0,0 +1,73 @@
+
+function PetitionFrame_Update(self)
+ if ( CanSignPetition() ) then
+ PetitionFrameSignButton:Enable();
+ else
+ PetitionFrameSignButton:Disable();
+ end
+ local petitionType, title, bodyText, maxSignatures, originatorName, isOriginator, minSignatures = GetPetitionInfo();
+ if ( isOriginator ) then
+ PetitionFrameRequestButton:Show();
+ PetitionFrameSignButton:Hide();
+ if ( petitionType == "guild" ) then
+ PetitionFrameInstructions:SetText(GUILD_PETITION_LEADER_INSTRUCTIONS);
+ elseif ( petitionType == "arena" ) then
+ PetitionFrameInstructions:SetText(ARENA_PETITION_LEADER_INSTRUCTIONS);
+ end
+ PetitionFrameRenameButton:Show();
+ else
+ PetitionFrameRequestButton:Hide();
+ PetitionFrameSignButton:Show();
+ if ( petitionType == "guild" ) then
+ PetitionFrameInstructions:SetText(GUILD_PETITION_MEMBER_INSTRUCTIONS);
+ elseif ( petitionType == "arena" ) then
+ PetitionFrameInstructions:SetText(ARENA_PETITION_MEMBER_INSTRUCTIONS);
+ end
+ PetitionFrameRenameButton:Hide();
+ end
+ if ( petitionType == "guild" ) then
+ PetitionFrameNpcNameText:SetFormattedText(GUILD_CHARTER_TEMPLATE, title);
+ PetitionFrameCharterTitle:SetText(GUILD_NAME);
+ PetitionFrameCharterName:SetText(title);
+ PetitionFrameMasterTitle:SetText(GUILD_RANK0_DESC);
+ PetitionFrameMasterName:SetText(originatorName);
+ PetitionFrameRenameButton:SetText(RENAME_GUILD);
+ elseif ( petitionType == "arena" ) then
+ PetitionFrameNpcNameText:SetFormattedText(ARENA_CHARTER_TEMPLATE, title);
+ PetitionFrameCharterTitle:SetText(ARENA_TEAM);
+ PetitionFrameCharterName:SetText(title..", "..format(PVP_TEAMSIZE, minSignatures + 1, minSignatures + 1));
+ PetitionFrameMasterTitle:SetText(ARENA_TEAM_CAPTAIN);
+ PetitionFrameMasterName:SetText(originatorName);
+ PetitionFrameRenameButton:SetText(RENAME_ARENA_TEAM);
+ else
+ PetitionFrameNpcNameText:SetText("Petition");
+ end
+ local memberText;
+ local numNames = GetNumPetitionNames();
+ if ( self.minSignatures ) then
+ for i=1, self.minSignatures, 1 do
+ memberText = _G["PetitionFrameMemberName"..i];
+ memberText:Hide();
+ end
+ end
+ for i=1, minSignatures do
+ memberText = _G["PetitionFrameMemberName"..i];
+ if ( i <= numNames ) then
+ memberText:SetText(GetPetitionNameInfo(i));
+ else
+ memberText:SetText(NOT_YET_SIGNED);
+ end
+ if ( i == minSignatures ) then
+ PetitionFrameInstructions:SetPoint( "TOPLEFT", memberText:GetName(), "BOTTOMLEFT", 0, -10);
+ end
+ memberText:Show();
+ end
+ self.minSignatures = minSignatures;
+ self.petitionType = petitionType;
+ if ( numNames >= maxSignatures ) then
+ PetitionFrameRequestButton:Disable();
+ else
+ PetitionFrameRequestButton:Enable();
+ end
+end
+
diff --git a/reference/FrameXML/PetitionFrame.xml b/reference/FrameXML/PetitionFrame.xml
new file mode 100644
index 0000000..623f1fa
--- /dev/null
+++ b/reference/FrameXML/PetitionFrame.xml
@@ -0,0 +1,393 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( PetitionFrame.petitionType == "guild" ) then
+ StaticPopup_Show("RENAME_GUILD");
+ elseif ( PetitionFrame.petitionType == "arena" ) then
+ StaticPopup_Show("RENAME_ARENA_TEAM");
+ end
+
+
+
+
+
+
+ self:RegisterEvent("PETITION_SHOW");
+ self:RegisterEvent("PETITION_CLOSED");
+
+
+ if (event == "PETITION_SHOW") then
+ ShowUIPanel(PetitionFrame);
+ if ( not PetitionFrame:IsShown() ) then
+ ClosePetition();
+ return;
+ end
+
+ PetitionFrame_Update(self);
+ elseif (event == "PETITION_CLOSED") then
+ HideUIPanel(PetitionFrame);
+ end
+
+
+ PlaySound("igQuestListOpen");
+
+
+ PlaySound("igQuestListClose");
+ ClosePetition();
+
+
+
+
diff --git a/reference/FrameXML/PlayerFrame.lua b/reference/FrameXML/PlayerFrame.lua
new file mode 100644
index 0000000..e44062c
--- /dev/null
+++ b/reference/FrameXML/PlayerFrame.lua
@@ -0,0 +1,688 @@
+REQUIRED_REST_HOURS = 5;
+
+function PlayerFrame_OnLoad(self)
+ UnitFrame_Initialize(self, "player", PlayerName, PlayerPortrait,
+ PlayerFrameHealthBar, PlayerFrameHealthBarText,
+ PlayerFrameManaBar, PlayerFrameManaBarText,
+ PlayerFrameFlash);
+
+ self.statusCounter = 0;
+ self.statusSign = -1;
+ CombatFeedback_Initialize(self, PlayerHitIndicator, 30);
+ PlayerFrame_Update();
+ self:RegisterEvent("UNIT_LEVEL");
+ self:RegisterEvent("UNIT_COMBAT");
+ self:RegisterEvent("UNIT_FACTION");
+ self:RegisterEvent("UNIT_MAXMANA");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("PLAYER_ENTER_COMBAT");
+ self:RegisterEvent("PLAYER_LEAVE_COMBAT");
+ self:RegisterEvent("PLAYER_REGEN_DISABLED");
+ self:RegisterEvent("PLAYER_REGEN_ENABLED");
+ self:RegisterEvent("PLAYER_UPDATE_RESTING");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("PARTY_LEADER_CHANGED");
+ self:RegisterEvent("PARTY_LOOT_METHOD_CHANGED");
+ self:RegisterEvent("VOICE_START");
+ self:RegisterEvent("VOICE_STOP");
+ self:RegisterEvent("RAID_ROSTER_UPDATE");
+ self:RegisterEvent("READY_CHECK");
+ self:RegisterEvent("READY_CHECK_CONFIRM");
+ self:RegisterEvent("READY_CHECK_FINISHED");
+ self:RegisterEvent("UNIT_ENTERED_VEHICLE");
+ self:RegisterEvent("UNIT_ENTERING_VEHICLE");
+ self:RegisterEvent("UNIT_EXITING_VEHICLE");
+ self:RegisterEvent("UNIT_EXITED_VEHICLE");
+ self:RegisterEvent("PLAYER_FLAGS_CHANGED");
+ self:RegisterEvent("PLAYER_ROLES_ASSIGNED");
+
+ -- Chinese playtime stuff
+ self:RegisterEvent("PLAYTIME_CHANGED");
+
+ PlayerAttackBackground:SetVertexColor(0.8, 0.1, 0.1);
+ PlayerAttackBackground:SetAlpha(0.4);
+
+ local showmenu = function()
+ ToggleDropDownMenu(1, nil, PlayerFrameDropDown, "PlayerFrame", 106, 27);
+ end
+ SecureUnitButton_OnLoad(self, "player", showmenu);
+end
+
+function PlayerFrame_Update ()
+ if ( UnitExists("player") ) then
+ PlayerLevelText:SetText(UnitLevel(PlayerFrame.unit));
+ PlayerFrame_UpdatePartyLeader();
+ PlayerFrame_UpdatePvPStatus();
+ PlayerFrame_UpdateStatus();
+ PlayerFrame_UpdatePlaytime();
+ PlayerFrame_UpdateLayout();
+ end
+end
+
+function PlayerFrame_UpdatePartyLeader()
+ if ( IsPartyLeader() ) then
+ if ( HasLFGRestrictions() ) then
+ PlayerGuideIcon:Show();
+ PlayerLeaderIcon:Hide();
+ else
+ PlayerLeaderIcon:Show()
+ PlayerGuideIcon:Hide();
+ end
+ else
+ PlayerLeaderIcon:Hide();
+ PlayerGuideIcon:Hide();
+ end
+
+ local lootMethod;
+ local lootMaster;
+ lootMethod, lootMaster = GetLootMethod();
+ if ( lootMaster == 0 and ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0)) ) then
+ PlayerMasterIcon:Show();
+ else
+ PlayerMasterIcon:Hide();
+ end
+end
+
+function PlayerFrame_UpdatePvPStatus()
+ local factionGroup, factionName = UnitFactionGroup("player");
+ if ( UnitIsPVPFreeForAll("player") ) then
+ if ( not PlayerPVPIcon:IsShown() ) then
+ PlaySound("igPVPUpdate");
+ end
+ PlayerPVPIcon:SetTexture("Interface\\TargetingFrame\\UI-PVP-FFA");
+ PlayerPVPIcon:Show();
+
+ -- Setup newbie tooltip
+ PlayerPVPIconHitArea.tooltipTitle = PVPFFA;
+ PlayerPVPIconHitArea.tooltipText = NEWBIE_TOOLTIP_PVPFFA;
+ PlayerPVPIconHitArea:Show();
+
+ PlayerPVPTimerText:Hide();
+ PlayerPVPTimerText.timeLeft = nil;
+ elseif ( factionGroup and UnitIsPVP("player") ) then
+ if ( not PlayerPVPIcon:IsShown() ) then
+ PlaySound("igPVPUpdate");
+ end
+ -- MoonWell: traitors display the opposite faction icon
+ local displayFaction = factionGroup;
+ if ( MoonWell_IsTraitor ) then
+ displayFaction = (factionGroup == "Alliance") and "Horde" or "Alliance";
+ end
+ PlayerPVPIcon:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..displayFaction);
+ PlayerPVPIcon:Show();
+
+ -- Setup newbie tooltip
+ PlayerPVPIconHitArea.tooltipTitle = factionName;
+ PlayerPVPIconHitArea.tooltipText = _G["NEWBIE_TOOLTIP_"..strupper(factionGroup)];
+ PlayerPVPIconHitArea:Show();
+ else
+ PlayerPVPIcon:Hide();
+ PlayerPVPIconHitArea:Hide();
+ PlayerPVPTimerText:Hide();
+ PlayerPVPTimerText.timeLeft = nil;
+ end
+end
+
+function PlayerFrame_OnEvent(self, event, ...)
+ UnitFrame_OnEvent(self, event, ...);
+
+ local arg1, arg2, arg3, arg4, arg5 = ...;
+ if ( event == "UNIT_LEVEL" ) then
+ if ( arg1 == "player" ) then
+ PlayerLevelText:SetText(UnitLevel(self.unit));
+ end
+ elseif ( event == "UNIT_COMBAT" ) then
+ if ( arg1 == self.unit ) then
+ CombatFeedback_OnCombatEvent(self, arg2, arg3, arg4, arg5);
+ end
+ elseif ( event == "UNIT_FACTION" ) then
+ if ( arg1 == "player" ) then
+ PlayerFrame_UpdatePvPStatus();
+ end
+ elseif ( event == "PLAYER_ENTERING_WORLD" ) then
+ PlayerFrame_ToPlayerArt(self);
+-- if ( UnitHasVehicleUI("player") ) then
+-- UnitFrame_SetUnit(self, "vehicle", PlayerFrameHealthBar, PlayerFrameManaBar);
+-- else
+-- UnitFrame_SetUnit(self, "player", PlayerFrameHealthBar, PlayerFrameManaBar);
+-- end
+ self.inCombat = nil;
+ self.onHateList = nil;
+ PlayerFrame_Update();
+ PlayerFrame_UpdateStatus();
+ PlayerFrame_UpdateRolesAssigned();
+ PlayerSpeakerFrame:Show();
+ PlayerFrame_UpdateVoiceStatus(UnitIsTalking(UnitName("player")));
+
+ if ( IsPVPTimerRunning() ) then
+ PlayerPVPTimerText:Show();
+ PlayerPVPTimerText.timeLeft = GetPVPTimer();
+ else
+ PlayerPVPTimerText:Hide();
+ PlayerPVPTimerText.timeLeft = nil;
+ end
+ elseif ( event == "PLAYER_ENTER_COMBAT" ) then
+ self.inCombat = 1;
+ PlayerFrame_UpdateStatus();
+ elseif ( event == "PLAYER_LEAVE_COMBAT" ) then
+ self.inCombat = nil;
+ PlayerFrame_UpdateStatus();
+ elseif ( event == "PLAYER_REGEN_DISABLED" ) then
+ self.onHateList = 1;
+ PlayerFrame_UpdateStatus();
+
+ if ( GetCVarBool("screenEdgeFlash") ) then
+ CombatFeedback_StartFullscreenStatus();
+ end
+ elseif ( event == "PLAYER_REGEN_ENABLED" ) then
+ self.onHateList = nil;
+ PlayerFrame_UpdateStatus();
+
+ CombatFeedback_StopFullscreenStatus();
+ elseif ( event == "PLAYER_UPDATE_RESTING" ) then
+ PlayerFrame_UpdateStatus();
+ elseif ( event == "PARTY_MEMBERS_CHANGED" or event == "PARTY_LEADER_CHANGED" or event == "RAID_ROSTER_UPDATE" ) then
+ PlayerFrame_UpdateGroupIndicator();
+ PlayerFrame_UpdatePartyLeader();
+ PlayerFrame_UpdateReadyCheck();
+ elseif ( event == "PARTY_LOOT_METHOD_CHANGED" ) then
+ local lootMethod;
+ local lootMaster;
+ lootMethod, lootMaster = GetLootMethod();
+ if ( lootMaster == 0 and ((GetNumPartyMembers() > 0) or (GetNumRaidMembers() > 0)) ) then
+ PlayerMasterIcon:Show();
+ else
+ PlayerMasterIcon:Hide();
+ end
+ elseif ( event == "VOICE_START") then
+ if ( arg1 == "player" ) then
+ PlayerFrame_UpdateVoiceStatus(true);
+ end
+ elseif ( event == "VOICE_STOP" ) then
+ if ( arg1 == "player" ) then
+ PlayerFrame_UpdateVoiceStatus(false);
+ end
+ elseif ( event == "PLAYTIME_CHANGED" ) then
+ PlayerFrame_UpdatePlaytime();
+ elseif ( event == "READY_CHECK" or event == "READY_CHECK_CONFIRM" ) then
+ PlayerFrame_UpdateReadyCheck();
+ elseif ( event == "READY_CHECK_FINISHED" ) then
+ ReadyCheck_Finish(PlayerFrameReadyCheck);
+ elseif ( event == "UNIT_RUNIC_POWER" and arg1 == "player" ) then
+ PlayerFrame_SetRunicPower(UnitPower("player"));
+ elseif ( event == "UNIT_ENTERING_VEHICLE" ) then
+ if ( arg1 == "player" ) then
+ if ( arg2 ) then
+ PlayerFrame_AnimateOut(self);
+ else
+ if ( PlayerFrame.state == "vehicle" ) then
+ PlayerFrame_AnimateOut(self);
+ end
+ end
+ end
+ elseif ( event == "UNIT_ENTERED_VEHICLE" ) then
+ if ( arg1 == "player" ) then
+ self.inSeat = true;
+ PlayerFrame_UpdateArt(self);
+ end
+ elseif ( event == "UNIT_EXITING_VEHICLE" ) then
+ if ( arg1 == "player" ) then
+ if ( self.state == "vehicle" ) then
+ PlayerFrame_AnimateOut(self);
+ end
+ end
+ elseif ( event == "UNIT_EXITED_VEHICLE" ) then
+ if ( arg1 == "player" ) then
+ self.inSeat = true;
+ PlayerFrame_UpdateArt(self);
+ end
+ elseif ( event == "PLAYER_FLAGS_CHANGED" ) then
+ if ( IsPVPTimerRunning() ) then
+ PlayerPVPTimerText:Show();
+ PlayerPVPTimerText.timeLeft = GetPVPTimer();
+ else
+ PlayerPVPTimerText:Hide();
+ PlayerPVPTimerText.timeLeft = nil;
+ end
+ elseif ( event == "PLAYER_ROLES_ASSIGNED" ) then
+ PlayerFrame_UpdateRolesAssigned();
+ end
+end
+
+function PlayerFrame_UpdateRolesAssigned()
+ local frame = PlayerFrame;
+ local icon = _G[frame:GetName().."RoleIcon"];
+ local isTank, isHealer, isDamage = UnitGroupRolesAssigned("player");
+
+ if ( isTank ) then
+ icon:SetTexCoord(0, 19/64, 22/64, 41/64);
+ icon:Show();
+ elseif ( isHealer ) then
+ icon:SetTexCoord(20/64, 39/64, 1/64, 20/64);
+ icon:Show();
+ elseif ( isDamage ) then
+ icon:SetTexCoord(20/64, 39/64, 22/64, 41/64);
+ icon:Show();
+ else
+ icon:Hide();
+ end
+end
+
+local function PlayerFrame_AnimPos(self, fraction)
+ return "TOPLEFT", UIParent, "TOPLEFT", -19, fraction*140-4;
+end
+
+local PlayerFrameAnimTable = {
+ totalTime = 0.3,
+ updateFunc = "SetPoint",
+ getPosFunc = PlayerFrame_AnimPos,
+ }
+function PlayerFrame_AnimateOut(self)
+ self.inSeat = false;
+ self.animFinished = false;
+ self.inSequence = true;
+ SetUpAnimation(PlayerFrame, PlayerFrameAnimTable, PlayerFrame_AnimFinished, false)
+end
+
+function PlayerFrame_AnimFinished(self)
+ self.animFinished = true;
+ PlayerFrame_UpdateArt(self);
+end
+
+function PlayerFrame_UpdateArt(self)
+ if ( self.animFinished and self.inSeat and self.inSequence) then
+ SetUpAnimation(PlayerFrame, PlayerFrameAnimTable, PlayerFrame_SequenceFinished, true)
+ if ( UnitHasVehicleUI("player") ) then
+ PlayerFrame_ToVehicleArt(self, UnitVehicleSkin("player"));
+ else
+ PlayerFrame_ToPlayerArt(self);
+ end
+ end
+end
+
+function PlayerFrame_SequenceFinished(self)
+ self.inSequence = false;
+ PetFrame_Update(PetFrame);
+end
+
+function PlayerFrame_ToVehicleArt(self, vehicleType)
+ --Swap frame
+
+ PlayerFrame.state = "vehicle";
+
+ UnitFrame_SetUnit(self, "vehicle", PlayerFrameHealthBar, PlayerFrameManaBar);
+ UnitFrame_SetUnit(PetFrame, "player", PetFrameHealthBar, PetFrameManaBar);
+ PetFrame_Update(PetFrame);
+ PlayerFrame_Update();
+ BuffFrame_Update();
+ ComboFrame_Update();
+
+ PlayerFrameTexture:Hide();
+ if ( vehicleType == "Natural" ) then
+ PlayerFrameVehicleTexture:SetTexture("Interface\\Vehicles\\UI-Vehicle-Frame-Organic");
+ PlayerFrameHealthBar:SetWidth(103);
+ PlayerFrameHealthBar:SetPoint("TOPLEFT",116,-41);
+ PlayerFrameManaBar:SetWidth(103);
+ PlayerFrameManaBar:SetPoint("TOPLEFT",116,-52);
+ else
+ PlayerFrameVehicleTexture:SetTexture("Interface\\Vehicles\\UI-Vehicle-Frame");
+ PlayerFrameHealthBar:SetWidth(100);
+ PlayerFrameHealthBar:SetPoint("TOPLEFT",119,-41);
+ PlayerFrameManaBar:SetWidth(100);
+ PlayerFrameManaBar:SetPoint("TOPLEFT",119,-52);
+ end
+ PlayerFrameVehicleTexture:Show();
+
+ PlayerName:SetPoint("CENTER",50,23);
+ PlayerLeaderIcon:SetPoint("TOPLEFT",40,-12);
+ PlayerMasterIcon:SetPoint("TOPLEFT",86,0);
+ PlayerFrameGroupIndicator:SetPoint("BOTTOMLEFT", PlayerFrame, "TOPLEFT", 97, -13);
+
+ PlayerFrameBackground:SetWidth(114);
+ PlayerLevelText:Hide();
+end
+
+function PlayerFrame_ToPlayerArt(self)
+ --Unswap frame
+
+ PlayerFrame.state = "player";
+
+ UnitFrame_SetUnit(self, "player", PlayerFrameHealthBar, PlayerFrameManaBar);
+ UnitFrame_SetUnit(PetFrame, "pet", PetFrameHealthBar, PetFrameManaBar);
+ PetFrame_Update(PetFrame);
+ PlayerFrame_Update();
+ BuffFrame_Update();
+ ComboFrame_Update();
+
+ PlayerFrameTexture:Show();
+ PlayerFrameVehicleTexture:Hide();
+ PlayerName:SetPoint("CENTER",50,19);
+ PlayerLeaderIcon:SetPoint("TOPLEFT",40,-12);
+ PlayerMasterIcon:SetPoint("TOPLEFT",80,-10);
+ PlayerFrameGroupIndicator:SetPoint("BOTTOMLEFT", PlayerFrame, "TOPLEFT", 97, -20);
+ PlayerFrameHealthBar:SetWidth(119);
+ PlayerFrameHealthBar:SetPoint("TOPLEFT",106,-41);
+ PlayerFrameManaBar:SetWidth(119);
+ PlayerFrameManaBar:SetPoint("TOPLEFT",106,-52);
+ PlayerFrameBackground:SetWidth(119);
+ PlayerLevelText:Show();
+end
+
+function PlayerFrame_UpdateVoiceStatus (status)
+ if ( status ) then
+ UIFrameFadeIn(PlayerSpeakerFrame, 0.2, PlayerSpeakerFrame:GetAlpha(), 1);
+ VoiceChat_Animate(PlayerSpeakerFrame, 1);
+ else
+ UIFrameFadeOut(PlayerSpeakerFrame, 0.2, PlayerSpeakerFrame:GetAlpha(), 0);
+ VoiceChat_Animate(PlayerSpeakerFrame, nil);
+ end
+end
+
+function PlayerFrame_UpdateReadyCheck ()
+ local readyCheckStatus = GetReadyCheckStatus("player");
+ if ( readyCheckStatus ) then
+ if ( readyCheckStatus == "ready" ) then
+ ReadyCheck_Confirm(PlayerFrameReadyCheck, 1);
+ elseif ( readyCheckStatus == "notready" ) then
+ ReadyCheck_Confirm(PlayerFrameReadyCheck, 0);
+ else -- "waiting"
+ ReadyCheck_Start(PlayerFrameReadyCheck);
+ end
+ else
+ PlayerFrameReadyCheck:Hide();
+ end
+end
+
+function PlayerFrame_OnUpdate (self, elapsed)
+ if ( PlayerStatusTexture:IsShown() ) then
+ local alpha = 255;
+ local counter = self.statusCounter + elapsed;
+ local sign = self.statusSign;
+
+ if ( counter > 0.5 ) then
+ sign = -sign;
+ self.statusSign = sign;
+ end
+ counter = mod(counter, 0.5);
+ self.statusCounter = counter;
+
+ if ( sign == 1 ) then
+ alpha = (55 + (counter * 400)) / 255;
+ else
+ alpha = (255 - (counter * 400)) / 255;
+ end
+ PlayerStatusTexture:SetAlpha(alpha);
+ PlayerStatusGlow:SetAlpha(alpha);
+ end
+
+ if ( PlayerPVPTimerText.timeLeft ) then
+ PlayerPVPTimerText.timeLeft = PlayerPVPTimerText.timeLeft - elapsed*1000;
+ local timeLeft = PlayerPVPTimerText.timeLeft;
+ if ( timeLeft < 0 ) then
+ PlayerPVPTimerText:Hide()
+ end
+ PlayerPVPTimerText:SetFormattedText(SecondsToTimeAbbrev(floor(timeLeft/1000)));
+ else
+ PlayerPVPTimerText:Hide();
+ end
+ CombatFeedback_OnUpdate(self, elapsed);
+end
+
+function PlayerFrame_OnReceiveDrag ()
+ if ( CursorHasItem() ) then
+ AutoEquipCursorItem();
+ end
+end
+
+function PlayerFrame_UpdateStatus()
+ if ( UnitHasVehicleUI("player") ) then
+ PlayerStatusTexture:Hide()
+ PlayerRestIcon:Hide()
+ PlayerAttackIcon:Hide()
+ PlayerRestGlow:Hide()
+ PlayerAttackGlow:Hide()
+ PlayerStatusGlow:Hide()
+ PlayerAttackBackground:Hide()
+ elseif ( IsResting() ) then
+ PlayerStatusTexture:SetVertexColor(1.0, 0.88, 0.25, 1.0);
+ PlayerStatusTexture:Show();
+ PlayerRestIcon:Show();
+ PlayerAttackIcon:Hide();
+ PlayerRestGlow:Show();
+ PlayerAttackGlow:Hide();
+ PlayerStatusGlow:Show();
+ PlayerAttackBackground:Hide();
+ elseif ( PlayerFrame.inCombat ) then
+ PlayerStatusTexture:SetVertexColor(1.0, 0.0, 0.0, 1.0);
+ PlayerStatusTexture:Show();
+ PlayerAttackIcon:Show();
+ PlayerRestIcon:Hide();
+ PlayerAttackGlow:Show();
+ PlayerRestGlow:Hide();
+ PlayerStatusGlow:Show();
+ PlayerAttackBackground:Show();
+ elseif ( PlayerFrame.onHateList ) then
+ PlayerAttackIcon:Show();
+ PlayerRestIcon:Hide();
+ PlayerStatusGlow:Hide();
+ PlayerAttackBackground:Hide();
+ else
+ PlayerStatusTexture:Hide();
+ PlayerRestIcon:Hide();
+ PlayerAttackIcon:Hide();
+ PlayerStatusGlow:Hide();
+ PlayerAttackBackground:Hide();
+ end
+end
+
+function PlayerFrame_UpdateGroupIndicator()
+ PlayerFrameGroupIndicator:Hide();
+ local name, rank, subgroup;
+ if ( GetNumRaidMembers() == 0 ) then
+ PlayerFrameGroupIndicator:Hide();
+ return;
+ end
+ local numRaidMembers = GetNumRaidMembers();
+ for i=1, MAX_RAID_MEMBERS do
+ if ( i <= numRaidMembers ) then
+ name, rank, subgroup = GetRaidRosterInfo(i);
+ -- Set the player's group number indicator
+ if ( name == UnitName("player") ) then
+ PlayerFrameGroupIndicatorText:SetText(GROUP.." "..subgroup);
+ PlayerFrameGroupIndicator:SetWidth(PlayerFrameGroupIndicatorText:GetWidth()+40);
+ PlayerFrameGroupIndicator:Show();
+ end
+ end
+ end
+end
+
+function PlayerFrameDropDown_OnLoad (self)
+ UIDropDownMenu_Initialize(self, PlayerFrameDropDown_Initialize, "MENU");
+end
+
+function PlayerFrameDropDown_Initialize ()
+ if ( PlayerFrame.unit == "vehicle" ) then
+ UnitPopup_ShowMenu(PlayerFrameDropDown, "VEHICLE", "vehicle");
+ else
+ UnitPopup_ShowMenu(PlayerFrameDropDown, "SELF", "player");
+ end
+end
+
+function PlayerFrame_UpdatePlaytime()
+ if ( PartialPlayTime() ) then
+ PlayerPlayTimeIcon:SetTexture("Interface\\CharacterFrame\\UI-Player-PlayTimeTired");
+ PlayerPlayTime.tooltip = format(PLAYTIME_TIRED, REQUIRED_REST_HOURS - floor(GetBillingTimeRested()/60));
+ PlayerPlayTime:Show();
+ elseif ( NoPlayTime() ) then
+ PlayerPlayTimeIcon:SetTexture("Interface\\CharacterFrame\\UI-Player-PlayTimeUnhealthy");
+ PlayerPlayTime.tooltip = format(PLAYTIME_UNHEALTHY, REQUIRED_REST_HOURS - floor(GetBillingTimeRested()/60));
+ PlayerPlayTime:Show();
+ else
+ PlayerPlayTime:Hide();
+ end
+end
+
+function PlayerFrame_SetupDeathKnniggetLayout ()
+ PlayerFrame:SetHitRectInsets(0,0,0,35);
+
+ --[[ PlayerFrame:SetPoint("TOPLEFT", -11, -8);
+ PlayerFrame:RegisterEvent("UNIT_RUNIC_POWER");
+ PlayerPortrait:SetDrawLayer("BACKGROUND");
+ PlayerFrameTexture:ClearAllPoints();
+ PlayerFrameTexture:SetTexture("Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight");
+ PlayerFrameTexture:SetPoint("TOPLEFT", 15, 15);
+ PlayerFrameTexture:SetTexCoord(0, 1, 0, 1)
+ PlayerFrameTexture:SetHeight(128);
+ PlayerFrameTexture:SetWidth(256)
+
+ PlayerFrame:CreateTexture("PlayerFrameBackgroundTexture", "BACKGROUND");
+ PlayerFrameBackgroundTexture:SetTexture("Interface\\PlayerFrame\\UI-PlayerFrame-DeathKnight-Background");
+ PlayerFrameBackgroundTexture:SetPoint("TOPLEFT", 15, 15);
+ PlayerFrameBackgroundTexture:SetWidth(256);
+ PlayerFrameBackgroundTexture:SetHeight(128);
+ PlayerFrameBackgroundTexture:SetDrawLayer("BORDER");
+ PlayerFrameBackground:SetDrawLayer("ARTWORK");
+ PlayerFrameBackground:SetHeight(4);
+ PlayerFrameBackground:SetWidth(4);
+ PlayerFrameBackground:SetPoint("TOPLEFT", 108, -24);
+
+ PlayerName:SetPoint("CENTER", 50, 18);
+ PlayerFrameHealthBar:SetPoint("TOPLEFT", PlayerFrame, "TOPLEFT", 113, -41);
+ PlayerFrameHealthBar:SetWidth(112);
+ PlayerFrameHealthBarText:SetPoint("CENTER", 53, 3);
+
+ -- Death Knight Specific Border Frame
+ PlayerFrame:CreateTexture("PlayerFrameRunicPowerOverlay", "OVERLAY");
+ PlayerFrameRunicPowerOverlay:SetPoint("TOPLEFT", 15, 15);
+ PlayerFrameRunicPowerOverlay:SetWidth(256);
+ PlayerFrameRunicPowerOverlay:SetHeight(128);
+ PlayerFrameRunicPowerOverlay:SetTexture("Interface\\PlayerFrame\\UI-PlayerFrame-DeathKnight-GoldBorder");
+
+ -- Death Knight Runic Power Glow
+ local frame = CreateFrame("Frame");
+ frame:SetPoint("TOPLEFT", PlayerFrame);
+ frame:SetPoint("BOTTOMRIGHT", PlayerFrame);
+
+ frame:CreateTexture("PlayerFrameRunicPowerGlow", "BORDER");
+ PlayerFrameRunicPowerGlow:SetPoint("TOPLEFT", 15, 15);
+ PlayerFrameRunicPowerGlow:SetPoint("BOTTOMRIGHT", PlayerFrameBackgroundTexture);
+ PlayerFrameRunicPowerGlow:SetAlpha(0.050);
+ PlayerFrameRunicPowerGlow:SetWidth(256);
+ PlayerFrameRunicPowerGlow:SetHeight(128);
+ PlayerFrameRunicPowerGlow:Hide();
+ PlayerFrameRunicPowerGlow:SetTexture("Interface\\PlayerFrame\\UI-PlayerFrame-DeathKnight-Sword-Glow");
+
+ --Hoorah for hacks!
+ PlayerFrameManaBar:UnregisterAllEvents();
+ PlayerFrameManaBar:Hide();
+ PlayerFrameManaBar:ClearAllPoints();
+ PlayerFrameManaBar:SetPoint("TOPLEFT", UIParent, "BOTTOMRIGHT");
+ PlayerFrameManaBarText:SetParent(PlayerFrameManaBar);
+
+ local runicPowerBar = PlayerFrame:CreateTexture("$parentRunicPowerBar", "ARTWORK");
+ -- Mmmm, runic Power Bars, my favorite kind. Tastes like Death Knnigget.
+ runicPowerBar:SetTexture("Interface\\PlayerFrame\\UI-PlayerFrame-DeathKnight-RunicPower");
+ runicPowerBar:SetPoint("BOTTOMLEFT", "$parent", "BOTTOMLEFT", 70, 24);
+ runicPowerBar:SetWidth(64);
+ runicPowerBar:SetHeight(63);
+
+ PlayerFrame_SetRunicPower(UnitPower("player"));--]]
+end
+
+CustomClassLayouts = {
+ ["DEATHKNIGHT"] = PlayerFrame_SetupDeathKnniggetLayout,
+}
+
+local layoutUpdated = false;
+
+function PlayerFrame_UpdateLayout ()
+ if ( layoutUpdated ) then
+ return;
+ end
+ layoutUpdated = true;
+
+ local _, class = UnitClass("player");
+
+ if ( CustomClassLayouts[class] ) then
+ CustomClassLayouts[class]();
+ end
+end
+
+local RUNICPOWERBARHEIGHT = 63;
+local RUNICPOWERBARWIDTH = 64;
+
+local RUNICGLOW_FADEALPHA = .050
+local RUNICGLOW_MINALPHA = .40
+local RUNICGLOW_MAXALPHA = .80
+local RUNICGLOW_THROBINTERVAL = .8;
+
+RUNICGLOW_FINISHTHROBANDHIDE = false;
+local RUNICGLOW_THROBSTART = 0;
+
+function PlayerFrame_SetRunicPower (runicPower)
+ PlayerFrameRunicPowerBar:SetHeight(RUNICPOWERBARHEIGHT * (runicPower / 100));
+ PlayerFrameRunicPowerBar:SetTexCoord(0, 1, (1 - (runicPower / 100)), 1);
+
+ if ( runicPower >= 90 ) then
+ -- Oh, God help us for these function and variable names.
+ RUNICGLOW_FINISHTHROBANDHIDE = false;
+ if ( not PlayerFrameRunicPowerGlow:IsShown() ) then
+ PlayerFrameRunicPowerGlow:Show();
+ end
+ PlayerFrameRunicPowerGlow:GetParent():SetScript("OnUpdate", DeathKnniggetThrobFunction);
+ elseif ( PlayerFrameRunicPowerGlow:GetParent():GetScript("OnUpdate") ) then
+ RUNICGLOW_FINISHTHROBANDHIDE = true;
+ else
+ PlayerFrameRunicPowerGlow:Hide();
+ end
+end
+
+local firstFadeIn = true;
+function DeathKnniggetThrobFunction (self, elapsed)
+ if ( RUNICGLOW_THROBSTART == 0 ) then
+ RUNICGLOW_THROBSTART = GetTime();
+ elseif ( not RUNICGLOW_FINISHTHROBANDHIDE ) then
+ local interval = RUNICGLOW_THROBINTERVAL - math.abs( .9 - (UnitPower("player") / 100));
+ local animTime = GetTime() - RUNICGLOW_THROBSTART;
+ if ( animTime >= interval ) then
+ -- Fading out
+ PlayerFrameRunicPowerGlow:SetAlpha(math.max(RUNICGLOW_MINALPHA, math.min(RUNICGLOW_MAXALPHA, RUNICGLOW_MAXALPHA * interval/animTime)));
+ if ( animTime >= interval * 2 ) then
+ self.timeSinceThrob = 0;
+ RUNICGLOW_THROBSTART = GetTime();
+ end
+ firstFadeIn = false;
+ else
+ -- Fading in
+ if ( firstFadeIn ) then
+ PlayerFrameRunicPowerGlow:SetAlpha(math.max(RUNICGLOW_FADEALPHA, math.min(RUNICGLOW_MAXALPHA, RUNICGLOW_MAXALPHA * animTime/interval)));
+ else
+ PlayerFrameRunicPowerGlow:SetAlpha(math.max(RUNICGLOW_MINALPHA, math.min(RUNICGLOW_MAXALPHA, RUNICGLOW_MAXALPHA * animTime/interval)));
+ end
+ end
+ elseif ( RUNICGLOW_FINISHTHROBANDHIDE ) then
+ local currentAlpha = PlayerFrameRunicPowerGlow:GetAlpha();
+ local animTime = GetTime() - RUNICGLOW_THROBSTART;
+ local interval = RUNICGLOW_THROBINTERVAL;
+ firstFadeIn = true;
+
+ if ( animTime >= interval ) then
+ -- Already fading out, just keep fading out.
+ local alpha = math.min(PlayerFrameRunicPowerGlow:GetAlpha(), RUNICGLOW_MAXALPHA * (interval/(animTime*(animTime/2))));
+
+ PlayerFrameRunicPowerGlow:SetAlpha(alpha);
+ if ( alpha <= RUNICGLOW_FADEALPHA ) then
+ self.timeSinceThrob = 0;
+ RUNICGLOW_THROBSTART = 0;
+ PlayerFrameRunicPowerGlow:Hide();
+ self:SetScript("OnUpdate", nil);
+ RUNICGLOW_FINISHTHROBANDHIDE = false;
+ return;
+ end
+ else
+ -- Was fading in, start fading out
+ animTime = interval;
+ end
+ end
+end
+
diff --git a/reference/FrameXML/PlayerFrame.xml b/reference/FrameXML/PlayerFrame.xml
new file mode 100644
index 0000000..41e68fc
--- /dev/null
+++ b/reference/FrameXML/PlayerFrame.xml
@@ -0,0 +1,512 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, self.tooltipTitle, 1.0, 1.0, 1.0, self.tooltipText, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetFrameLevel(self:GetFrameLevel() + 3);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltip, nil, nil, nil, nil, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ self.textLockable = 1;
+ self.cvar = "playerStatusText";
+ self.cvarLabel = "STATUS_TEXT_PLAYER";
+
+
+ self:GetParent():Click(button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TextStatusBar_Initialize(self);
+ self.textLockable = 1;
+ self.cvar = "playerStatusText";
+ self.cvarLabel = "STATUS_TEXT_PLAYER";
+
+
+ self:GetParent():Click(button);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlayerFrameGroupIndicatorLeft:SetAlpha(0.3);
+ PlayerFrameGroupIndicatorRight:SetAlpha(0.3);
+ PlayerFrameGroupIndicatorMiddle:SetAlpha(0.3);
+ PlayerFrameGroupIndicatorText:SetAlpha(0.7);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/QuestFrame.lua b/reference/FrameXML/QuestFrame.lua
new file mode 100644
index 0000000..a5802c3
--- /dev/null
+++ b/reference/FrameXML/QuestFrame.lua
@@ -0,0 +1,391 @@
+MAX_NUM_QUESTS = 32;
+MAX_NUM_ITEMS = 10;
+MAX_REQUIRED_ITEMS = 6;
+QUEST_DESCRIPTION_GRADIENT_LENGTH = 30;
+QUEST_DESCRIPTION_GRADIENT_CPS = 70;
+QUESTINFO_FADE_IN = 0.5;
+
+function QuestFrame_OnLoad(self)
+ self:RegisterEvent("QUEST_GREETING");
+ self:RegisterEvent("QUEST_DETAIL");
+ self:RegisterEvent("QUEST_PROGRESS");
+ self:RegisterEvent("QUEST_COMPLETE");
+ self:RegisterEvent("QUEST_FINISHED");
+ self:RegisterEvent("QUEST_ITEM_UPDATE");
+end
+
+function QuestFrame_OnEvent(self, event, ...)
+ if ( event == "QUEST_FINISHED" ) then
+ HideUIPanel(QuestFrame);
+ return;
+ end
+ if ( (event == "QUEST_ITEM_UPDATE") and not QuestFrame:IsShown() ) then
+ return;
+ end
+
+ QuestFrame_SetPortrait();
+ ShowUIPanel(QuestFrame);
+ if ( not QuestFrame:IsShown() ) then
+ CloseQuest();
+ return;
+ end
+ if ( event == "QUEST_GREETING" ) then
+ QuestFrameGreetingPanel:Hide();
+ QuestFrameGreetingPanel:Show();
+ elseif ( event == "QUEST_DETAIL" ) then
+ HideUIPanel(QuestLogDetailFrame);
+ QuestFrameDetailPanel:Hide();
+ QuestFrameDetailPanel:Show();
+ elseif ( event == "QUEST_PROGRESS" ) then
+ HideUIPanel(QuestLogDetailFrame);
+ QuestFrameProgressPanel:Hide();
+ QuestFrameProgressPanel:Show();
+ elseif ( event == "QUEST_COMPLETE" ) then
+ HideUIPanel(QuestLogDetailFrame);
+ QuestFrameCompleteQuestButton:Enable();
+ QuestFrameRewardPanel:Hide();
+ QuestFrameRewardPanel:Show();
+ elseif ( event == "QUEST_ITEM_UPDATE" ) then
+ if ( QuestFrameDetailPanel:IsShown() ) then
+ QuestInfo_ShowRewards();
+ QuestDetailScrollFrameScrollBar:SetValue(0);
+ elseif ( QuestFrameProgressPanel:IsShown() ) then
+ QuestFrameProgressItems_Update()
+ QuestProgressScrollFrameScrollBar:SetValue(0);
+ elseif ( QuestFrameRewardPanel:IsShown() ) then
+ QuestInfo_ShowRewards();
+ QuestRewardScrollFrameScrollBar:SetValue(0);
+ end
+ end
+end
+
+function QuestFrame_SetPortrait()
+ QuestFrameNpcNameText:SetText(UnitName("questnpc"));
+ if ( UnitExists("questnpc") ) then
+ SetPortraitTexture(QuestFramePortrait, "questnpc");
+ else
+ QuestFramePortrait:SetTexture("Interface\\QuestFrame\\UI-QuestLog-BookIcon");
+ end
+
+end
+
+function QuestFrameRewardPanel_OnShow()
+ QuestFrameDetailPanel:Hide();
+ QuestFrameGreetingPanel:Hide();
+ QuestFrameProgressPanel:Hide();
+ local material = QuestFrame_GetMaterial();
+ QuestFrame_SetMaterial(QuestFrameRewardPanel, material);
+ QuestInfo_Display(QUEST_TEMPLATE_REWARD, QuestRewardScrollChildFrame, QuestFrameCompleteQuestButton, QuestFrameCancelButton, material);
+ QuestRewardScrollFrameScrollBar:SetValue(0);
+ if ( QUEST_FADING_DISABLE == "0" ) then
+ QuestRewardScrollChildFrame:SetAlpha(0);
+ UIFrameFadeIn(QuestRewardScrollChildFrame, QUESTINFO_FADE_IN);
+ end
+end
+
+function QuestRewardCancelButton_OnClick()
+ DeclineQuest();
+ PlaySound("igQuestCancel");
+end
+
+function QuestRewardCompleteButton_OnClick()
+ if ( QuestInfoFrame.itemChoice == 0 and GetNumQuestChoices() > 0 ) then
+ QuestChooseRewardError();
+ else
+ local money = GetQuestMoneyToGet();
+ if ( money and money > 0 ) then
+ QuestFrame.dialog = StaticPopup_Show("CONFIRM_COMPLETE_EXPENSIVE_QUEST");
+ if ( QuestFrame.dialog ) then
+ MoneyFrame_Update(QuestFrame.dialog:GetName().."MoneyFrame", money);
+ end
+ else
+ GetQuestReward(QuestInfoFrame.itemChoice);
+ end
+ end
+end
+
+function QuestProgressCompleteButton_OnClick()
+ CompleteQuest();
+ --PlaySound("igQuestListComplete");
+end
+
+function QuestGoodbyeButton_OnClick()
+ DeclineQuest();
+ PlaySound("igQuestCancel");
+end
+
+function QuestRewardItem_OnClick(self)
+ if ( self.type == "choice" ) then
+ QuestRewardItemHighlight:SetPoint("TOPLEFT", self, "TOPLEFT", -8, 7);
+ QuestRewardItemHighlight:Show();
+ QuestFrameRewardPanel.itemChoice = self:GetID();
+ end
+end
+
+function QuestFrameProgressPanel_OnShow()
+ QuestFrameRewardPanel:Hide();
+ QuestFrameDetailPanel:Hide();
+ QuestFrameGreetingPanel:Hide();
+ local material = QuestFrame_GetMaterial();
+ QuestFrame_SetMaterial(QuestFrameProgressPanel, material);
+ QuestProgressTitleText:SetText(GetTitleText());
+ QuestFrame_SetTitleTextColor(QuestProgressTitleText, material);
+ QuestProgressText:SetText(GetProgressText());
+ QuestFrame_SetTextColor(QuestProgressText, material);
+ if ( IsQuestCompletable() ) then
+ QuestFrameCompleteButton:Enable();
+ else
+ QuestFrameCompleteButton:Disable();
+ end
+ QuestFrameProgressItems_Update();
+ if ( QUEST_FADING_DISABLE == "0" ) then
+ QuestProgressScrollChildFrame:SetAlpha(0);
+ UIFrameFadeIn(QuestProgressScrollChildFrame, QUESTINFO_FADE_IN);
+ end
+end
+
+function QuestFrameProgressItems_Update()
+ local numRequiredItems = GetNumQuestItems();
+ local questItemName = "QuestProgressItem";
+ if ( numRequiredItems > 0 or GetQuestMoneyToGet() > 0 ) then
+ QuestProgressRequiredItemsText:Show();
+
+ -- If there's money required then anchor and display it
+ if ( GetQuestMoneyToGet() > 0 ) then
+ MoneyFrame_Update("QuestProgressRequiredMoneyFrame", GetQuestMoneyToGet());
+
+ if ( GetQuestMoneyToGet() > GetMoney() ) then
+ -- Not enough money
+ QuestProgressRequiredMoneyText:SetTextColor(0, 0, 0);
+ SetMoneyFrameColor("QuestProgressRequiredMoneyFrame", "red");
+ else
+ QuestProgressRequiredMoneyText:SetTextColor(0.2, 0.2, 0.2);
+ SetMoneyFrameColor("QuestProgressRequiredMoneyFrame", "white");
+ end
+ QuestProgressRequiredMoneyText:Show();
+ QuestProgressRequiredMoneyFrame:Show();
+
+ -- Reanchor required item
+ _G[questItemName..1]:SetPoint("TOPLEFT", "QuestProgressRequiredMoneyText", "BOTTOMLEFT", 0, -10);
+ else
+ QuestProgressRequiredMoneyText:Hide();
+ QuestProgressRequiredMoneyFrame:Hide();
+
+ _G[questItemName..1]:SetPoint("TOPLEFT", "QuestProgressRequiredItemsText", "BOTTOMLEFT", -3, -5);
+ end
+
+
+
+ for i=1, numRequiredItems, 1 do
+ local requiredItem = _G[questItemName..i];
+ requiredItem.type = "required";
+ local name, texture, numItems = GetQuestItemInfo(requiredItem.type, i);
+ SetItemButtonCount(requiredItem, numItems);
+ SetItemButtonTexture(requiredItem, texture);
+ requiredItem:Show();
+ _G[questItemName..i.."Name"]:SetText(name);
+
+ end
+ else
+ QuestProgressRequiredMoneyText:Hide();
+ QuestProgressRequiredMoneyFrame:Hide();
+ QuestProgressRequiredItemsText:Hide();
+ end
+ for i=numRequiredItems + 1, MAX_REQUIRED_ITEMS, 1 do
+ _G[questItemName..i]:Hide();
+ end
+ QuestProgressScrollFrameScrollBar:SetValue(0);
+end
+
+function QuestFrameGreetingPanel_OnShow()
+ QuestFrameRewardPanel:Hide();
+ QuestFrameProgressPanel:Hide();
+ QuestFrameDetailPanel:Hide();
+ if ( QUEST_FADING_DISABLE == "0" ) then
+ QuestGreetingScrollChildFrame:SetAlpha(0);
+ UIFrameFadeIn(QuestGreetingScrollChildFrame, QUESTINFO_FADE_IN);
+ end
+ local material = QuestFrame_GetMaterial();
+ QuestFrame_SetMaterial(QuestFrameGreetingPanel, material);
+ GreetingText:SetText(GetGreetingText());
+ QuestFrame_SetTextColor(GreetingText, material);
+ QuestFrame_SetTitleTextColor(CurrentQuestsText, material);
+ QuestFrame_SetTitleTextColor(AvailableQuestsText, material);
+ local numActiveQuests = GetNumActiveQuests();
+ local numAvailableQuests = GetNumAvailableQuests();
+ if ( numActiveQuests == 0 ) then
+ CurrentQuestsText:Hide();
+ QuestGreetingFrameHorizontalBreak:Hide();
+ else
+ CurrentQuestsText:SetPoint("TOPLEFT", "GreetingText", "BOTTOMLEFT", 0, -10);
+ CurrentQuestsText:Show();
+ QuestTitleButton1:SetPoint("TOPLEFT", "CurrentQuestsText", "BOTTOMLEFT", -10, -5);
+ for i=1, numActiveQuests, 1 do
+ local questTitleButton = _G["QuestTitleButton"..i];
+ local questTitleButtonIcon = _G[questTitleButton:GetName() .. "QuestIcon"];
+ local title, isComplete = GetActiveTitle(i);
+ if ( IsActiveQuestTrivial(i) ) then
+ questTitleButton:SetFormattedText(TRIVIAL_QUEST_DISPLAY, title);
+ questTitleButtonIcon:SetVertexColor(0.75,0.75,0.75);
+ else
+ questTitleButton:SetFormattedText(NORMAL_QUEST_DISPLAY, title);
+ questTitleButtonIcon:SetVertexColor(1,1,1);
+ end
+ if ( isComplete ) then
+ questTitleButtonIcon:SetTexture("Interface\\GossipFrame\\ActiveQuestIcon");
+ else
+ questTitleButtonIcon:SetTexture("Interface\\GossipFrame\\IncompleteQuestIcon");
+ end
+ questTitleButton:SetHeight(questTitleButton:GetTextHeight() + 2);
+ questTitleButton:SetID(i);
+ questTitleButton.isActive = 1;
+ questTitleButton:Show();
+ if ( i > 1 ) then
+ questTitleButton:SetPoint("TOPLEFT", "QuestTitleButton"..(i-1),"BOTTOMLEFT", 0, -2)
+ end
+ end
+ end
+ if ( numAvailableQuests == 0 ) then
+ AvailableQuestsText:Hide();
+ QuestGreetingFrameHorizontalBreak:Hide();
+ else
+ if ( numActiveQuests > 0 ) then
+ QuestGreetingFrameHorizontalBreak:SetPoint("TOPLEFT", "QuestTitleButton"..numActiveQuests, "BOTTOMLEFT",22,-10);
+ QuestGreetingFrameHorizontalBreak:Show();
+ AvailableQuestsText:SetPoint("TOPLEFT", "QuestGreetingFrameHorizontalBreak", "BOTTOMLEFT", -12, -10);
+ else
+ AvailableQuestsText:SetPoint("TOPLEFT", "GreetingText", "BOTTOMLEFT", 0, -10);
+ end
+ AvailableQuestsText:Show();
+ _G["QuestTitleButton"..(numActiveQuests + 1)]:SetPoint("TOPLEFT", "AvailableQuestsText", "BOTTOMLEFT", -10, -5);
+ for i=(numActiveQuests + 1), (numActiveQuests + numAvailableQuests), 1 do
+ local questTitleButton = _G["QuestTitleButton"..i];
+ local questTitleButtonIcon = _G[questTitleButton:GetName() .. "QuestIcon"];
+ local isTrivial, isDaily, isRepeatable = GetAvailableQuestInfo(i - numActiveQuests);
+ if ( isDaily ) then
+ questTitleButtonIcon:SetTexture("Interface\\GossipFrame\\DailyQuestIcon");
+ elseif ( isRepeatable ) then
+ questTitleButtonIcon:SetTexture("Interface\\GossipFrame\\DailyActiveQuestIcon");
+ else
+ questTitleButtonIcon:SetTexture("Interface\\GossipFrame\\AvailableQuestIcon");
+ end
+ if ( isTrivial ) then
+ questTitleButton:SetFormattedText(TRIVIAL_QUEST_DISPLAY, GetAvailableTitle(i - numActiveQuests));
+ questTitleButtonIcon:SetVertexColor(0.5,0.5,0.5);
+ else
+ questTitleButton:SetFormattedText(NORMAL_QUEST_DISPLAY, GetAvailableTitle(i - numActiveQuests));
+ questTitleButtonIcon:SetVertexColor(1,1,1);
+ end
+ questTitleButton:SetHeight(questTitleButton:GetTextHeight() + 2);
+ questTitleButton:SetID(i - numActiveQuests);
+ questTitleButton.isActive = 0;
+ questTitleButton:Show();
+ if ( i > numActiveQuests + 1 ) then
+ questTitleButton:SetPoint("TOPLEFT", "QuestTitleButton"..(i-1),"BOTTOMLEFT", 0, -2)
+ end
+ end
+ end
+ for i=(numActiveQuests + numAvailableQuests + 1), MAX_NUM_QUESTS, 1 do
+ _G["QuestTitleButton"..i]:Hide();
+ end
+end
+
+function QuestFrame_OnShow()
+ PlaySound("igQuestListOpen");
+end
+
+function QuestFrame_OnHide()
+ QuestFrameGreetingPanel:Hide();
+ QuestFrameDetailPanel:Hide();
+ QuestFrameRewardPanel:Hide();
+ QuestFrameProgressPanel:Hide();
+ if ( QuestFrame.dialog ) then
+ QuestFrame.dialog:Hide();
+ QuestFrame.dialog = nil;
+ end
+ if ( QuestFrame.autoQuest ) then
+ QuestFrameDetailPanelBotRight:SetTexture("Interface\\QuestFrame\\UI-QuestGreeting-BotRight");
+ QuestFrameDeclineButton:Show();
+ QuestFrame.autoQuest = nil;
+ end
+ CloseQuest();
+ PlaySound("igQuestListClose");
+end
+
+function QuestTitleButton_OnClick(self)
+ if ( self.isActive == 1 ) then
+ SelectActiveQuest(self:GetID());
+ else
+ SelectAvailableQuest(self:GetID());
+ end
+ PlaySound("igQuestListSelect");
+end
+
+function QuestFrameDetailPanel_OnShow()
+ QuestFrameRewardPanel:Hide();
+ QuestFrameProgressPanel:Hide();
+ QuestFrameGreetingPanel:Hide();
+ if ( QuestGetAutoAccept() ) then
+ QuestFrameDetailPanelBotRight:SetTexture("Interface\\QuestFrame\\UI-QuestGreeting-BotRight-blank");
+ QuestFrameDeclineButton:Hide();
+ QuestFrame.autoQuest = true;
+ end
+ local material = QuestFrame_GetMaterial();
+ QuestFrame_SetMaterial(QuestFrameDetailPanel, material);
+ QuestInfo_Display(QUEST_TEMPLATE_DETAIL1, QuestDetailScrollChildFrame, QuestFrameAcceptButton, nil, material);
+ QuestInfo_Display(QUEST_TEMPLATE_DETAIL2, QuestInfoFadingFrame, QuestFrameAcceptButton, nil, material);
+ QuestDetailScrollFrameScrollBar:SetValue(0);
+end
+
+function QuestDetailAcceptButton_OnClick()
+ if ( QuestFlagsPVP() ) then
+ QuestFrame.dialog = StaticPopup_Show("CONFIRM_ACCEPT_PVP_QUEST");
+ else
+ if ( QuestFrame.autoQuest ) then
+ HideUIPanel(QuestFrame);
+ else
+ AcceptQuest();
+ end
+ end
+end
+
+function QuestDetailDeclineButton_OnClick()
+ DeclineQuest();
+ PlaySound("igQuestCancel");
+end
+
+function QuestFrame_SetMaterial(frame, material)
+ if ( material == "Parchment" ) then
+ _G[frame:GetName().."MaterialTopLeft"]:Hide();
+ _G[frame:GetName().."MaterialTopRight"]:Hide();
+ _G[frame:GetName().."MaterialBotLeft"]:Hide();
+ _G[frame:GetName().."MaterialBotRight"]:Hide();
+ else
+ _G[frame:GetName().."MaterialTopLeft"]:Show();
+ _G[frame:GetName().."MaterialTopRight"]:Show();
+ _G[frame:GetName().."MaterialBotLeft"]:Show();
+ _G[frame:GetName().."MaterialBotRight"]:Show();
+ _G[frame:GetName().."MaterialTopLeft"]:SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-TopLeft");
+ _G[frame:GetName().."MaterialTopRight"]:SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-TopRight");
+ _G[frame:GetName().."MaterialBotLeft"]:SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-BotLeft");
+ _G[frame:GetName().."MaterialBotRight"]:SetTexture("Interface\\ItemTextFrame\\ItemText-"..material.."-BotRight");
+ end
+end
+
+function QuestFrame_GetMaterial()
+ local material = GetQuestBackgroundMaterial();
+ if ( not material ) then
+ material = "Parchment";
+ end
+ return material;
+end
+
+function QuestFrame_SetTitleTextColor(fontString, material)
+ local temp, materialTitleTextColor = GetMaterialTextColors(material);
+ fontString:SetTextColor(materialTitleTextColor[1], materialTitleTextColor[2], materialTitleTextColor[3]);
+end
+
+function QuestFrame_SetTextColor(fontString, material)
+ local materialTextColor = GetMaterialTextColors(material);
+ fontString:SetTextColor(materialTextColor[1], materialTextColor[2], materialTextColor[3]);
+end
\ No newline at end of file
diff --git a/reference/FrameXML/QuestFrame.xml b/reference/FrameXML/QuestFrame.xml
new file mode 100644
index 0000000..e80ab6a
--- /dev/null
+++ b/reference/FrameXML/QuestFrame.xml
@@ -0,0 +1,642 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(QuestFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/QuestFrameTemplates.xml b/reference/FrameXML/QuestFrameTemplates.xml
new file mode 100644
index 0000000..bd6af6d
--- /dev/null
+++ b/reference/FrameXML/QuestFrameTemplates.xml
@@ -0,0 +1,379 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.hasItem = 1;
+
+
+ if ( self:GetAlpha() > 0 ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self.rewardType == "item" ) then
+ GameTooltip:SetQuestItem(self.type, self:GetID());
+ GameTooltip_ShowCompareItem(GameTooltip);
+ elseif ( self.rewardType == "spell" ) then
+ GameTooltip:SetQuestRewardSpell();
+ end
+ end
+ CursorUpdate(self);
+
+
+ GameTooltip:Hide();
+ ResetCursor();
+
+
+ CursorOnUpdate(self, elapsed);
+
+
+ if ( self.rewardType == "spell" ) then
+ if ( IsModifiedClick("CHATLINK") ) then
+ ChatEdit_InsertLink(GetQuestSpellLink());
+ end
+ else
+ HandleModifiedItemClick(GetQuestItemLink(self.type, self:GetID()));
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ QuestTitleButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local factionGroup = UnitFactionGroup("player");
+ if ( factionGroup ) then
+ self.icon:SetTexture("Interface\\TargetingFrame\\UI-PVP-"..factionGroup);
+ self.icon:Show();
+ else
+ self.icon:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/QuestInfo.lua b/reference/FrameXML/QuestInfo.lua
new file mode 100644
index 0000000..8fe25c7
--- /dev/null
+++ b/reference/FrameXML/QuestInfo.lua
@@ -0,0 +1,565 @@
+MAX_REPUTATIONS = 10;
+
+function QuestInfoFadingFrame_OnUpdate(self, elapsed)
+ if ( self.fading ) then
+ self.fadingProgress = self.fadingProgress + (elapsed * QUEST_DESCRIPTION_GRADIENT_CPS);
+ PlaySound("WriteQuest");
+ if ( not QuestInfoDescriptionText:SetAlphaGradient(self.fadingProgress, QUEST_DESCRIPTION_GRADIENT_LENGTH) ) then
+ self.fading = nil;
+ if ( QUEST_FADING_DISABLE == "0" ) then
+ UIFrameFadeIn(self, QUESTINFO_FADE_IN );
+ else
+ self:SetAlpha(1);
+ end
+ QuestInfoFrame.acceptButton:Enable();
+ end
+ end
+end
+
+function QuestInfoTimerFrame_OnUpdate(self, elapsed)
+ if ( self.timeLeft ) then
+ self.timeLeft = max(self.timeLeft - elapsed, 0);
+ QuestInfoTimerText:SetText(TIME_REMAINING.." "..SecondsToTime(self.timeLeft));
+ end
+end
+
+function QuestInfoItem_OnClick(self)
+ if ( self.type == "choice" ) then
+ QuestInfoItemHighlight:SetPoint("TOPLEFT", self, "TOPLEFT", -8, 7);
+ QuestInfoItemHighlight:Show();
+ QuestInfoFrame.itemChoice = self:GetID();
+ end
+end
+
+function QuestInfo_Display(template, parentFrame, acceptButton, cancelButton, material)
+ local lastFrame = nil;
+ local shownFrame = nil;
+ local elementsTable = template.elements;
+
+ QuestInfoFrame.questLog = template.questLog;
+ QuestInfoFrame.chooseItems = template.chooseItems;
+ QuestInfoFrame.tooltip = template.tooltip;
+ QuestInfoFrame.acceptButton = acceptButton;
+ QuestInfoFrame.cancelButton = cancelButton;
+
+ if ( QuestInfoFrame.material ~= material ) then
+ QuestInfoFrame.material = material;
+ local textColor, titleTextColor = GetMaterialTextColors(material);
+ -- headers
+ QuestInfoTitleHeader:SetTextColor(titleTextColor[1], titleTextColor[2], titleTextColor[3]);
+ QuestInfoDescriptionHeader:SetTextColor(titleTextColor[1], titleTextColor[2], titleTextColor[3]);
+ QuestInfoObjectivesHeader:SetTextColor(titleTextColor[1], titleTextColor[2], titleTextColor[3]);
+ QuestInfoRewardsHeader:SetTextColor(titleTextColor[1], titleTextColor[2], titleTextColor[3]);
+ -- other text
+ QuestInfoDescriptionText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ QuestInfoObjectivesText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ QuestInfoGroupSize:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ QuestInfoRewardText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ -- reward frame text
+ QuestInfoItemChooseText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ QuestInfoItemReceiveText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ QuestInfoSpellLearnText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ QuestInfoHonorFrameReceiveText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ QuestInfoArenaPointsFrameReceiveText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ QuestInfoTalentFrameReceiveText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ QuestInfoXPFrameReceiveText:SetTextColor(textColor[1], textColor[2], textColor[3]);
+ end
+
+ for i = 1, #elementsTable, 3 do
+ shownFrame, bottomShownFrame = elementsTable[i]();
+ if ( shownFrame ) then
+ shownFrame:SetParent(parentFrame);
+ if ( lastFrame ) then
+ shownFrame:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", elementsTable[i+1], elementsTable[i+2]);
+ else
+ shownFrame:SetPoint("TOPLEFT", parentFrame, "TOPLEFT", elementsTable[i+1], elementsTable[i+2]);
+ end
+ lastFrame = bottomShownFrame or shownFrame;
+ end
+ end
+end
+
+function QuestInfo_ShowTitle()
+ local questTitle;
+ if ( QuestInfoFrame.questLog ) then
+ questTitle = GetQuestLogTitle(GetQuestLogSelection());
+ if ( not questTitle ) then
+ questTitle = "";
+ end
+ if ( IsCurrentQuestFailed() ) then
+ questTitle = questTitle.." - ("..FAILED..")";
+ end
+ else
+ questTitle = GetTitleText();
+ end
+ QuestInfoTitleHeader:SetText(questTitle);
+ return QuestInfoTitleHeader;
+end
+
+function QuestInfo_ShowDescriptionText()
+ local questDescription;
+ if ( QuestInfoFrame.questLog ) then
+ questDescription = GetQuestLogQuestText();
+ else
+ questDescription = GetQuestText();
+ end
+ QuestInfoDescriptionText:SetText(questDescription);
+ QuestInfoDescriptionText:SetAlphaGradient(0, 0);
+ return QuestInfoDescriptionText;
+end
+
+function QuestInfo_ShowObjectives()
+ local numObjectives = GetNumQuestLeaderBoards();
+ local objective;
+ local text, type, finished;
+ for i = 1, numObjectives do
+ objective = _G["QuestInfoObjective"..i];
+ text, type, finished = GetQuestLogLeaderBoard(i);
+ if ( not text or strlen(text) == 0 ) then
+ text = type;
+ end
+ if ( finished ) then
+ objective:SetTextColor(0.2, 0.2, 0.2);
+ text = text.." ("..COMPLETE..")";
+ else
+ objective:SetTextColor(0, 0, 0);
+ end
+ objective:SetText(text);
+ objective:Show();
+ end
+ for i = numObjectives + 1, MAX_OBJECTIVES do
+ _G["QuestInfoObjective"..i]:Hide();
+ end
+ if ( objective ) then
+ QuestInfoObjectivesFrame:Show();
+ return QuestInfoObjectivesFrame, objective;
+ else
+ QuestInfoObjectivesFrame:Hide();
+ return nil;
+ end
+end
+
+function QuestInfo_DoReputations(anchor)
+ local numReputations = GetNumQuestLogRewardFactions();
+ local factionName, amount, factionId, isHeader;
+ local index = 0;
+ for i = 1, numReputations do
+ factionId, amount = GetQuestLogRewardFactionInfo(i);
+ factionName, _, _, _, _, _, _, _, isHeader, _, hasRep = GetFactionInfoByID(factionId);
+ if ( factionName and ( not isHeader or hasRep ) ) then
+ index = index + 1;
+ amount = floor(amount / 100);
+ if ( amount < 0 ) then
+ amount = "|cffff4400"..amount.."|r";
+ end
+ _G["QuestInfoReputation"..index.."Faction"]:SetText(format(REWARD_REPUTATION, factionName));
+ _G["QuestInfoReputation"..index.."Amount"]:SetText(amount);
+ _G["QuestInfoReputation"..index]:Show();
+ end
+ end
+ if ( index > 0 ) then
+ for i = index + 1, MAX_REPUTATIONS do
+ _G["QuestInfoReputation"..i]:Hide();
+ end
+ QuestInfoReputationsFrame:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -5);
+ QuestInfoReputationsFrame:SetHeight(index * 17 + QuestInfoReputationText:GetHeight() + 4);
+ QuestInfoReputationsFrame:Show();
+ return QuestInfoReputationsFrame;
+ else
+ QuestInfoReputationsFrame:Hide();
+ return anchor;
+ end
+end
+
+function QuestInfo_ShowTimer()
+ local timeLeft = GetQuestLogTimeLeft();
+ QuestInfoTimerFrame.timeLeft = timeLeft;
+ if ( timeLeft ) then
+ QuestInfoTimerText:SetText(TIME_REMAINING.." "..SecondsToTime(timeLeft));
+ QuestInfoTimerFrame:SetHeight(QuestInfoTimerFrame:GetTop() - QuestInfoTimerText:GetTop() + QuestInfoTimerText:GetHeight());
+ QuestInfoTimerFrame:Show();
+ return QuestInfoTimerFrame;
+ else
+ QuestInfoTimerFrame:Hide();
+ return nil;
+ end
+end
+
+function QuestInfo_ShowRequiredMoney()
+ local requiredMoney = GetQuestLogRequiredMoney();
+ if ( requiredMoney > 0 ) then
+ MoneyFrame_Update("QuestInfoRequiredMoneyDisplay", requiredMoney);
+ if ( requiredMoney > GetMoney() ) then
+ -- Not enough money
+ QuestInfoRequiredMoneyText:SetTextColor(0, 0, 0);
+ SetMoneyFrameColor("QuestInfoRequiredMoneyDisplay", "red");
+ else
+ QuestInfoRequiredMoneyText:SetTextColor(0.2, 0.2, 0.2);
+ SetMoneyFrameColor("QuestInfoRequiredMoneyDisplay", "white");
+ end
+ QuestInfoRequiredMoneyFrame:Show();
+ return QuestInfoRequiredMoneyFrame;
+ else
+ QuestInfoRequiredMoneyFrame:Hide();
+ return nil;
+ end
+end
+
+function QuestInfo_ShowGroupSize()
+ local groupNum;
+ if ( QuestInfoFrame.questLog ) then
+ groupNum = GetQuestLogGroupNum();
+ else
+ groupNum = GetSuggestedGroupNum();
+ end
+ if ( groupNum > 0 ) then
+ local suggestedGroupString = format(QUEST_SUGGESTED_GROUP_NUM, groupNum);
+ QuestInfoGroupSize:SetText(suggestedGroupString);
+ QuestInfoGroupSize:Show();
+ return QuestInfoGroupSize;
+ else
+ QuestInfoGroupSize:Hide();
+ return nil;
+ end
+end
+
+function QuestInfo_ShowDescriptionHeader()
+ return QuestInfoDescriptionHeader;
+end
+
+function QuestInfo_ShowObjectivesHeader()
+ return QuestInfoObjectivesHeader;
+end
+
+function QuestInfo_ShowObjectivesText()
+ local questObjectives;
+ if ( QuestInfoFrame.questLog ) then
+ _, questObjectives = GetQuestLogQuestText();
+ else
+ questObjectives = GetObjectiveText();
+ end
+ QuestInfoObjectivesText:SetText(questObjectives);
+ return QuestInfoObjectivesText;
+end
+
+function QuestInfo_ShowSpacer()
+ return QuestInfoSpacerFrame;
+end
+
+function QuestInfo_ShowAnchor()
+ return QuestInfoAnchor;
+end
+
+function QuestInfo_ShowRewardText()
+ QuestInfoRewardText:SetText(GetRewardText());
+ return QuestInfoRewardText;
+end
+
+function QuestInfo_ShowRewards()
+ local numQuestRewards;
+ local numQuestChoices;
+ local numQuestSpellRewards = 0;
+ local money;
+ local honor;
+ local arenaPoints;
+ local talents;
+ local xp;
+ local playerTitle;
+
+ if ( QuestInfoFrame.questLog ) then
+ numQuestRewards = GetNumQuestLogRewards();
+ numQuestChoices = GetNumQuestLogChoices();
+ if ( GetQuestLogRewardSpell() ) then
+ numQuestSpellRewards = 1;
+ end
+ money = GetQuestLogRewardMoney();
+ honor = GetQuestLogRewardHonor();
+ arenaPoints = GetQuestLogRewardArenaPoints();
+ talents = GetQuestLogRewardTalents();
+ xp = GetQuestLogRewardXP();
+ playerTitle = GetQuestLogRewardTitle();
+ ProcessQuestLogRewardFactions();
+ else
+ numQuestRewards = GetNumQuestRewards();
+ numQuestChoices = GetNumQuestChoices();
+ if ( GetRewardSpell() ) then
+ numQuestSpellRewards = 1;
+ end
+ money = GetRewardMoney();
+ honor = GetRewardHonor();
+ arenaPoints = GetRewardArenaPoints();
+ talents = GetRewardTalents();
+ xp = GetRewardXP();
+ playerTitle = GetRewardTitle();
+ end
+
+ local totalRewards = numQuestRewards + numQuestChoices + numQuestSpellRewards;
+ if ( totalRewards == 0 and money == 0 and honor == 0 and arenaPoints == 0 and talents == 0 and xp == 0 and not playerTitle ) then
+ QuestInfoRewardsFrame:Hide();
+ return nil;
+ end
+
+ -- Hide unused rewards
+ for i = totalRewards + 1, MAX_NUM_ITEMS, 1 do
+ _G["QuestInfoItem"..i]:Hide();
+ end
+ -- Hide non-icon rewards (for now)
+ QuestInfoMoneyFrame:Hide();
+ QuestInfoHonorFrame:Hide();
+ QuestInfoArenaPointsFrame:Hide();
+ QuestInfoTalentFrame:Hide();
+ QuestInfoXPFrame:Hide();
+ QuestInfoPlayerTitleFrame:Hide();
+
+ local questItem, name, texture, isTradeskillSpell, isSpellLearned, quality, isUsable, numItems;
+ local rewardsCount = 0;
+ local lastFrame = QuestInfoRewardsHeader;
+ local questItemReceiveText = QuestInfoItemReceiveText;
+ questItemReceiveText:SetText(REWARD_ITEMS_ONLY);
+
+ -- Setup choosable rewards
+ if ( numQuestChoices > 0 ) then
+ local itemChooseText = QuestInfoItemChooseText;
+ questItemReceiveText:SetText(REWARD_ITEMS);
+ itemChooseText:Show();
+
+ local index;
+ local baseIndex = rewardsCount;
+ for i = 1, numQuestChoices, 1 do
+ index = i + baseIndex;
+ questItem = _G["QuestInfoItem"..index];
+ questItem.type = "choice";
+ numItems = 1;
+ if ( QuestInfoFrame.questLog ) then
+ name, texture, numItems, quality, isUsable = GetQuestLogChoiceInfo(i);
+ else
+ name, texture, numItems, quality, isUsable = GetQuestItemInfo(questItem.type, i);
+ end
+ questItem:SetID(i)
+ questItem:Show();
+ -- For the tooltip
+ questItem.rewardType = "item"
+ _G["QuestInfoItem"..index.."Name"]:SetText(name);
+ SetItemButtonCount(questItem, numItems);
+ SetItemButtonTexture(questItem, texture);
+ if ( isUsable ) then
+ SetItemButtonTextureVertexColor(questItem, 1.0, 1.0, 1.0);
+ SetItemButtonNameFrameVertexColor(questItem, 1.0, 1.0, 1.0);
+ else
+ SetItemButtonTextureVertexColor(questItem, 0.9, 0, 0);
+ SetItemButtonNameFrameVertexColor(questItem, 0.9, 0, 0);
+ end
+ if ( i > 1 ) then
+ if ( mod(i,2) == 1 ) then
+ questItem:SetPoint("TOPLEFT", "QuestInfoItem"..(index - 2), "BOTTOMLEFT", 0, -2);
+ lastFrame = questItem;
+ else
+ questItem:SetPoint("TOPLEFT", "QuestInfoItem"..(index - 1), "TOPRIGHT", 1, 0);
+ end
+ else
+ questItem:SetPoint("TOPLEFT", itemChooseText, "BOTTOMLEFT", -3, -5);
+ lastFrame = questItem;
+ end
+ rewardsCount = rewardsCount + 1;
+ end
+ if ( QuestInfoFrame.chooseItems ) then
+ itemChooseText:SetText(REWARD_CHOOSE);
+ else
+ itemChooseText:SetText(REWARD_CHOICES);
+ end
+ else
+ QuestInfoItemChooseText:Hide();
+ end
+
+ -- Setup spell rewards
+ if ( numQuestSpellRewards > 0 ) then
+ questItemReceiveText:SetText(REWARD_ITEMS);
+ local learnSpellText = QuestInfoSpellLearnText;
+ learnSpellText:Show();
+ learnSpellText:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", 3, -5);
+
+ if ( QuestInfoFrame.questLog ) then
+ texture, name, isTradeskillSpell, isSpellLearned = GetQuestLogRewardSpell();
+ else
+ texture, name, isTradeskillSpell, isSpellLearned = GetRewardSpell();
+ end
+
+ if ( isTradeskillSpell ) then
+ learnSpellText:SetText(REWARD_TRADESKILL_SPELL);
+ elseif ( not isSpellLearned ) then
+ learnSpellText:SetText(REWARD_AURA);
+ else
+ learnSpellText:SetText(REWARD_SPELL);
+ end
+
+ rewardsCount = rewardsCount + 1;
+ questItem = _G["QuestInfoItem"..rewardsCount];
+ questItem:Show();
+ -- For the tooltip
+ questItem.rewardType = "spell";
+ SetItemButtonCount(questItem, 0);
+ SetItemButtonTexture(questItem, texture);
+ _G["QuestInfoItem"..rewardsCount.."Name"]:SetText(name);
+ questItem:SetPoint("TOPLEFT", learnSpellText, "BOTTOMLEFT", -3, -5);
+ lastFrame = questItem;
+ else
+ QuestInfoSpellLearnText:Hide();
+ end
+
+ -- Setup mandatory rewards
+ if ( numQuestRewards > 0 or money > 0 or honor > 0 or arenaPoints > 0 or talents > 0 or xp > 0 or playerTitle ) then
+ questItemReceiveText:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", 3, -5);
+ questItemReceiveText:Show();
+ lastFrame = questItemReceiveText;
+ -- Money rewards
+ if ( money > 0 ) then
+ MoneyFrame_Update("QuestInfoMoneyFrame", money);
+ QuestInfoMoneyFrame:Show();
+ end
+ -- XP rewards
+ lastFrame = QuestInfo_ToggleRewardElement("QuestInfoXPFrame", xp, "Points", lastFrame);
+ -- Honor rewards
+ lastFrame = QuestInfo_ToggleRewardElement("QuestInfoHonorFrame", honor, "Points", lastFrame);
+ -- Arena point rewards
+ lastFrame = QuestInfo_ToggleRewardElement("QuestInfoArenaPointsFrame", arenaPoints, "Points", lastFrame);
+ -- Talent rewards
+ lastFrame = QuestInfo_ToggleRewardElement("QuestInfoTalentFrame", talents, "Points", lastFrame);
+ -- Title reward
+ lastFrame = QuestInfo_ToggleRewardElement("QuestInfoPlayerTitleFrame", playerTitle, "Title", lastFrame);
+ -- Item rewards
+ local index;
+ local baseIndex = rewardsCount;
+ for i = 1, numQuestRewards, 1 do
+ index = i + baseIndex;
+ questItem = _G["QuestInfoItem"..index];
+ questItem.type = "reward";
+ numItems = 1;
+ if ( QuestInfoFrame.questLog ) then
+ name, texture, numItems, quality, isUsable = GetQuestLogRewardInfo(i);
+ else
+ name, texture, numItems, quality, isUsable = GetQuestItemInfo(questItem.type, i);
+ end
+ questItem:SetID(i)
+ questItem:Show();
+ -- For the tooltip
+ questItem.rewardType = "item";
+ _G["QuestInfoItem"..index.."Name"]:SetText(name);
+ SetItemButtonCount(questItem, numItems);
+ SetItemButtonTexture(questItem, texture);
+ if ( isUsable ) then
+ SetItemButtonTextureVertexColor(questItem, 1.0, 1.0, 1.0);
+ SetItemButtonNameFrameVertexColor(questItem, 1.0, 1.0, 1.0);
+ else
+ SetItemButtonTextureVertexColor(questItem, 0.9, 0, 0);
+ SetItemButtonNameFrameVertexColor(questItem, 0.9, 0, 0);
+ end
+
+ if ( i > 1 ) then
+ if ( mod(i,2) == 1 ) then
+ questItem:SetPoint("TOPLEFT", "QuestInfoItem"..(index - 2), "BOTTOMLEFT", 0, -2);
+ lastFrame = questItem;
+ else
+ questItem:SetPoint("TOPLEFT", "QuestInfoItem"..(index - 1), "TOPRIGHT", 1, 0);
+ end
+ else
+ questItem:SetPoint("TOPLEFT", lastFrame, "BOTTOMLEFT", -3, -5);
+ lastFrame = questItem;
+ end
+ rewardsCount = rewardsCount + 1;
+ end
+ else
+ questItemReceiveText:Hide();
+ end
+
+ -- deselect item
+ QuestInfoFrame.itemChoice = 0;
+ QuestInfoItemHighlight:Hide();
+
+ QuestInfoRewardsFrame:Show();
+ return QuestInfoRewardsFrame, lastFrame;
+end
+
+function QuestInfo_ShowFadingFrame()
+ QuestInfoFadingFrame:SetAlpha(0);
+ QuestInfoFrame.acceptButton:Disable();
+ QuestInfoFadingFrame.fading = 1;
+ QuestInfoFadingFrame.fadingProgress = 0;
+ QuestInfoDescriptionText:SetAlphaGradient(0, QUEST_DESCRIPTION_GRADIENT_LENGTH);
+ if ( QUEST_FADING_DISABLE == "1" ) then
+ QuestInfoFadingFrame.fadingProgress = 1024;
+ end
+ return QuestInfoFadingFrame;
+end
+
+function QuestInfo_ToggleRewardElement(frameName, value, stringName, anchor)
+ local frame = _G[frameName];
+ if ( value and value ~= 0 ) then
+ frame:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -5);
+ if ( stringName ) then
+ _G[frameName..stringName]:SetText(value);
+ end
+ frame:Show();
+ return frame;
+ else
+ return anchor;
+ end
+end
+
+QUEST_TEMPLATE_DETAIL1 = { questLog = nil, chooseItems = nil, tooltip = nil,
+ elements = {
+ QuestInfo_ShowTitle, 5, -10,
+ QuestInfo_ShowDescriptionText, 0, -5,
+ QuestInfo_ShowFadingFrame, 0, -5
+ }
+}
+
+QUEST_TEMPLATE_DETAIL2 = { questLog = nil, chooseItems = nil, tooltip = "GameTooltip",
+ elements = {
+ QuestInfo_ShowObjectivesHeader, 0, -10,
+ QuestInfo_ShowObjectivesText, 0, -5,
+ QuestInfo_ShowGroupSize, 0, -10,
+ QuestInfo_ShowRewards, 0, -15,
+ QuestInfo_ShowSpacer, 0, -15
+ }
+}
+
+QUEST_TEMPLATE_LOG = { questLog = true, chooseItems = nil, tooltip = "GameTooltip",
+ elements = {
+ QuestInfo_ShowTitle, 5, -5,
+ QuestInfo_ShowObjectivesText, 0, -5,
+ QuestInfo_ShowTimer, 0, -10,
+ QuestInfo_ShowObjectives, 0, -10,
+ QuestInfo_ShowRequiredMoney, 0, 0,
+ QuestInfo_ShowGroupSize, 0, -10,
+ QuestInfo_ShowDescriptionHeader, 0, -10,
+ QuestInfo_ShowDescriptionText, 0, -5,
+ QuestInfo_ShowRewards, 0, -10,
+ QuestInfo_ShowSpacer, 0, -10
+ }
+}
+
+QUEST_TEMPLATE_REWARD = { questLog = nil, chooseItems = true, tooltip = "GameTooltip",
+ elements = {
+ QuestInfo_ShowTitle, 5, -10,
+ QuestInfo_ShowRewardText, 0, -5,
+ QuestInfo_ShowRewards, 0, -10,
+ QuestInfo_ShowSpacer, 0, -10
+ }
+}
+
+QUEST_TEMPLATE_MAP1 = { questLog = true, chooseItems = nil, fadingText = nil, tooltip = nil,
+ elements = {
+ QuestInfo_ShowTitle, 30, -10,
+ QuestInfo_ShowObjectivesText, 0, -5,
+ QuestInfo_ShowDescriptionHeader, 0, -10,
+ QuestInfo_ShowDescriptionText, 0, -5,
+ QuestInfo_ShowSpacer, 0, -10
+ }
+}
+
+QUEST_TEMPLATE_MAP2 = { questLog = true, chooseItems = nil, fadingText = nil, tooltip = "WorldMapTooltip",
+ elements = {
+ QuestInfo_ShowRewards, 30, -10,
+ QuestInfo_ShowAnchor, 5, 0,
+ }
+}
\ No newline at end of file
diff --git a/reference/FrameXML/QuestInfo.xml b/reference/FrameXML/QuestInfo.xml
new file mode 100644
index 0000000..6129224
--- /dev/null
+++ b/reference/FrameXML/QuestInfo.xml
@@ -0,0 +1,509 @@
+
+
+
+
+
+
+ local tooltip = _G[QuestInfoFrame.tooltip];
+ if ( tooltip ) then
+ tooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self.rewardType == "item" ) then
+ if ( QuestInfoFrame.questLog ) then
+ tooltip:SetQuestLogItem(self.type, self:GetID());
+ else
+ tooltip:SetQuestItem(self.type, self:GetID());
+ end
+ GameTooltip_ShowCompareItem(tooltip);
+ elseif ( self.rewardType == "spell" ) then
+ if ( QuestInfoFrame.questLog ) then
+ tooltip:SetQuestLogRewardSpell();
+ else
+ tooltip:SetQuestRewardSpell();
+ end
+ end
+ end
+
+
+ if ( IsModifiedClick() ) then
+ if ( self.rewardType == "spell" ) then
+ if ( IsModifiedClick("CHATLINK") ) then
+ if ( QuestInfoFrame.questLog ) then
+ ChatEdit_InsertLink(GetQuestLogSpellLink());
+ else
+ ChatEdit_InsertLink(GetQuestSpellLink());
+ end
+ end
+ else
+ if ( QuestInfoFrame.questLog ) then
+ HandleModifiedItemClick(GetQuestLogItemLink(self.type, self:GetID()));
+ else
+ HandleModifiedItemClick(GetQuestItemLink(self.type, self:GetID()));
+ end
+ end
+ else
+ if ( QuestInfoFrame.chooseItems ) then
+ QuestInfoItem_OnClick(self);
+ end
+ end
+
+
+ if ( QuestInfoFrame.tooltip ) then
+ _G[QuestInfoFrame.tooltip]:Hide();
+ ResetCursor();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SmallMoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.material = "Parchment";
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MoneyFrame_OnLoad(self);
+ MoneyFrame_SetType(self, "STATIC");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/QuestLogFrame.lua b/reference/FrameXML/QuestLogFrame.lua
new file mode 100644
index 0000000..0bbdf48
--- /dev/null
+++ b/reference/FrameXML/QuestLogFrame.lua
@@ -0,0 +1,891 @@
+-- global constants
+MAX_QUESTS = 25;
+MAX_OBJECTIVES = 10;
+MAX_QUESTLOG_QUESTS = 25;
+MAX_WATCHABLE_QUESTS = 25;
+MAX_QUEST_WATCH_TIME = 300;
+
+QuestDifficultyColors["impossible"].font = QuestDifficulty_Impossible;
+QuestDifficultyColors["verydifficult"].font = QuestDifficulty_VeryDifficult;
+QuestDifficultyColors["difficult"].font = QuestDifficulty_Difficult;
+QuestDifficultyColors["standard"].font = QuestDifficulty_Standard;
+QuestDifficultyColors["trivial"].font = QuestDifficulty_Trivial;
+QuestDifficultyColors["header"].font = QuestDifficulty_Header;
+
+-- local constants
+local QUEST_TIMER_UPDATE_DELAY = 0.1;
+local GROUP_UPDATE_INTERVAL_SEC = 3;
+
+-- update optimizations
+local max = max;
+
+--
+-- local helper functions
+--
+
+local function _QuestLog_HighlightQuest(questLogTitle)
+ local prevParent = QuestLogHighlightFrame:GetParent();
+ if ( prevParent and prevParent ~= questLogTitle ) then
+ -- set prev quest's colors back to normal
+ local prevName = prevParent:GetName();
+ prevParent:UnlockHighlight();
+ prevParent.tag:SetTextColor(prevParent.r, prevParent.g, prevParent.b);
+ prevParent.groupMates:SetTextColor(prevParent.r, prevParent.g, prevParent.b);
+ end
+ if ( questLogTitle ) then
+ local name = questLogTitle:GetName();
+ -- highlight the quest's colors
+ questLogTitle.tag:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ questLogTitle.groupMates:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ questLogTitle:LockHighlight();
+ -- reposition highlight frames
+ QuestLogHighlightFrame:SetParent(questLogTitle);
+ QuestLogHighlightFrame:SetPoint("TOPLEFT", questLogTitle, "TOPLEFT", 0, 0);
+ QuestLogHighlightFrame:SetPoint("BOTTOMRIGHT", questLogTitle, "BOTTOMRIGHT", 0, 0);
+ QuestLogSkillHighlight:SetVertexColor(questLogTitle.r, questLogTitle.g, questLogTitle.b);
+ QuestLogHighlightFrame:Show();
+ else
+ QuestLogHighlightFrame:Hide();
+ end
+end
+
+-- this function returns the amount needed to adjust the scroll bar in order to get the given quest index to appear in the
+-- QuestLogScrollFrame's viewable area
+local function _QuestLog_GetQuestScrollOffset(questIndex)
+ local scrollBarOffset = 0;
+ local buttons = QuestLogScrollFrame.buttons;
+ local testButton = buttons[1];
+ local testIndex = testButton:GetID();
+ local buttonHeight = testButton:GetHeight();
+ if ( questIndex <= testIndex ) then
+ if ( questIndex < testIndex ) then
+ -- selected quest comes before the first visible quest
+
+ -- instead of just offsetting by the delta of the indexes, we offset by 1 more to get the line BEFORE the selected
+ -- line to be at the top...if we don't do this, then the selected line would be at the top of the frame, which
+ -- isn't bad, but it feels better if we have the previous element at the top
+ scrollBarOffset = (testIndex - questIndex + 1) * buttonHeight;
+ end
+ -- make sure the visible area is aligned to the top of a button by adding the difference between the button's
+ -- top and the scroll area's top
+ scrollBarOffset = scrollBarOffset - (QuestLogScrollFrame:GetTop() - testButton:GetTop());
+ else
+ local numButtons = #buttons;
+ testButton = buttons[numButtons];
+ testIndex = max(testButton:GetID(), numButtons); --If the buttons aren't initalized, this will default to the last button. The index of the last button should never be greater than it's ID otherwise
+ if ( questIndex >= (testIndex - 1) ) then
+ if ( questIndex > testIndex ) then
+ -- selected quest comes after the last visible quest
+ -- instead of just offsetting by the delta of the indexes, we offset by 1 more to get the line AFTER the selected
+ -- line to be at the bottom...if we don't do this, then the selected line would be at the bottom of the frame, which
+ -- isn't bad, but it feels better if we have the next element at the bottom
+ scrollBarOffset = (testIndex - questIndex - 1) * buttonHeight;
+ end
+ -- make sure the visible area is aligned to the bottom of a button by adding the difference between the button's
+ -- bottom and the scroll area's bottom
+ if ( questIndex == (testIndex - 1) ) then
+ testButton = buttons[numButtons - 1];
+ end
+ local testBottom = testButton:GetBottom();
+ local scrollBottom = QuestLogScrollFrame:GetBottom();
+ if ( scrollBottom > testBottom ) then
+ -- don't add the offset unless the test button is actually lower than the scroll frame...it feels jumpy if you do
+ scrollBarOffset = scrollBarOffset + (testBottom - scrollBottom);
+ end
+ end
+ end
+ return scrollBarOffset;
+end
+
+local function _QuestLog_ToggleQuestWatch(questIndex)
+ if ( IsQuestWatched(questIndex) ) then
+ RemoveQuestWatch(questIndex);
+ WatchFrame_Update();
+ else
+ if ( GetNumQuestWatches() >= MAX_WATCHABLE_QUESTS ) then -- Check this first though it's less likely, otherwise they could make the frame bigger and be disappointed
+ UIErrorsFrame:AddMessage(format(QUEST_WATCH_TOO_MANY, MAX_WATCHABLE_QUESTS), 1.0, 0.1, 0.1, 1.0);
+ return;
+ end
+ AddQuestWatch(questIndex);
+ WatchFrame_Update();
+ end
+end
+
+--
+-- QuestLogTitleButton
+--
+
+function QuestLogTitleButton_OnLoad(self)
+ self:RegisterForClicks("LeftButtonUp", "RightButtonUp");
+ self:RegisterEvent("UNIT_QUEST_LOG_CHANGED");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("PARTY_MEMBER_ENABLE");
+ self:RegisterEvent("PARTY_MEMBER_DISABLE");
+
+ -- anchor the check to the normal text now since we can't do it with the way it's currently setup in XML
+ local name = self:GetName();
+ self.check:SetPoint("LEFT", name.."NormalText", "RIGHT", 2, 0);
+end
+
+function QuestLogTitleButton_OnEvent(self, event, ...)
+ if ( GameTooltip:IsOwned(self) ) then
+ GameTooltip:Hide();
+ QuestLog_UpdatePartyInfoTooltip(self);
+ end
+end
+
+function QuestLogTitleButton_OnClick(self, button)
+ local questName = self:GetText();
+ local questIndex = self:GetID();
+ if ( IsModifiedClick() ) then
+ -- If header then return
+ if ( self.isHeader ) then
+ return;
+ end
+ -- Otherwise try to track it or put it into chat
+ if ( IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow() ) then
+ local questLink = GetQuestLink(questIndex);
+ if ( questLink ) then
+ ChatEdit_InsertLink(questLink);
+ end
+ QuestLog_SetSelection(questIndex);
+ elseif ( IsModifiedClick("QUESTWATCHTOGGLE") ) then
+ _QuestLog_ToggleQuestWatch(questIndex);
+ QuestLog_SetSelection(questIndex);
+ QuestLog_Update();
+ end
+ else
+ QuestLog_SetSelection(questIndex);
+ end
+end
+
+function QuestLogTitleButton_OnEnter(self)
+ -- Set highlight
+ local name = self:GetName();
+ self.tag:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ self.groupMates:SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+
+ -- Set group info tooltip
+ QuestLog_UpdatePartyInfoTooltip(self);
+end
+
+function QuestLogTitleButton_OnLeave(self)
+ if ( self:GetID() ~= QuestLogFrame.selectedIndex ) then
+ local name = self:GetName();
+ self.tag:SetTextColor(self.r, self.g, self.b);
+ self.groupMates:SetTextColor(self.r, self.g, self.b);
+ end
+ GameTooltip:Hide();
+end
+
+-- HACK ALERT --
+-- QuestLogTitleButton_Resize contains a couple of big hacks to compensate for some weaknesses in the UI system
+function QuestLogTitleButton_Resize(questLogTitle)
+ -- the purpose of this function is to resize the contents of the questLogTitle button to fit inside its width
+
+ -- first reset the width of the button's font string (called normal text)
+ local questNormalText = questLogTitle.normalText;
+ -- HACK: in order to reset the width of the font string to be exactly the width of the quest title text,
+ -- we have to explicitly set the font string's width to 0 and then call SetText on the button
+ questNormalText:SetWidth(0);
+ questLogTitle:SetText(questLogTitle:GetText());
+
+ local questTitleTag = questLogTitle.tag;
+ local questCheck = questLogTitle.check;
+
+ -- find the right edge of the text
+ -- HACK: Unfortunately we can't just call questTitleTag:GetLeft() or questLogTitle:GetRight() to find right edges.
+ -- The reason why is because SetWidth may be called on the questLogTitle button before we enter this function. The
+ -- results of a SetWidth are not calculated until the next update tick; so in order to get the most up-to-date
+ -- right edge, we call GetLeft() + GetWidth() instead of just GetRight()
+ local rightEdge;
+ if ( questTitleTag:IsShown() ) then
+ -- adjust the normal text to not overrun the title tag
+ if ( questCheck:IsShown() ) then
+ --rightEdge = questTitleTag:GetLeft() - questCheck:GetWidth() - 2;
+ rightEdge = questLogTitle:GetLeft() + questLogTitle:GetWidth() - questTitleTag:GetWidth() - 4 - questCheck:GetWidth() - 2;
+ else
+ --rightEdge = questTitleTag:GetLeft();
+ rightEdge = questLogTitle:GetLeft() + questLogTitle:GetWidth() - questTitleTag:GetWidth() - 4;
+ end
+ else
+ -- adjust the normal text to not overrun the button
+ if ( questCheck:IsShown() ) then
+ --rightEdge = questLogTitle:GetRight() - questCheck:GetWidth() - 2;
+ rightEdge = questLogTitle:GetLeft() + questLogTitle:GetWidth() - questCheck:GetWidth() - 2;
+ else
+ --rightEdge = questLogTitle:GetRight();
+ rightEdge = questLogTitle:GetLeft() + questLogTitle:GetWidth();
+ end
+ end
+ -- subtract from the text width the number of pixels that overrun the right edge
+ local questNormalTextWidth = questNormalText:GetWidth() - max(questNormalText:GetRight() - rightEdge, 0);
+ questNormalText:SetWidth(questNormalTextWidth);
+end
+
+
+function QuestLogScrollFrame_OnLoad(self)
+ HybridScrollFrame_OnLoad(self);
+ self.update = QuestLog_Update;
+ HybridScrollFrame_CreateButtons(self, "QuestLogTitleButtonTemplate");
+end
+
+
+--
+-- QuestLogFrame
+--
+
+function QuestLog_OnLoad(self)
+ self:RegisterEvent("QUEST_LOG_UPDATE");
+ self:RegisterEvent("QUEST_ACCEPTED");
+ self:RegisterEvent("QUEST_WATCH_UPDATE");
+ self:RegisterEvent("UPDATE_FACTION");
+ self:RegisterEvent("UNIT_QUEST_LOG_CHANGED");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("PARTY_MEMBER_ENABLE");
+ self:RegisterEvent("PARTY_MEMBER_DISABLE");
+ self:RegisterEvent("DISPLAY_SIZE_CHANGED");
+
+ QuestLog_SetSelection(0);
+end
+
+function QuestLog_OnEvent(self, event, ...)
+ local arg1 = ...;
+ if ( event == "QUEST_LOG_UPDATE" or event == "UPDATE_FACTION" or (event == "UNIT_QUEST_LOG_CHANGED" and arg1 == "player") ) then
+ QuestLog_Update();
+ if ( QuestLogDetailScrollFrame:IsVisible() ) then
+ QuestLog_UpdateQuestDetails(false);
+ QuestLog_UpdateMap();
+ end
+ elseif ( event == "QUEST_ACCEPTED" ) then
+ if ( AUTO_QUEST_WATCH == "1" and GetNumQuestWatches() < MAX_WATCHABLE_QUESTS ) then
+ AddQuestWatch(arg1);
+ QuestLog_Update();
+ end
+ elseif ( event == "QUEST_WATCH_UPDATE" ) then
+ if ( AUTO_QUEST_PROGRESS == "1" and
+ GetNumQuestLeaderBoards(arg1) > 0 and
+ GetNumQuestWatches() < MAX_WATCHABLE_QUESTS ) then
+ AddQuestWatch(arg1,MAX_QUEST_WATCH_TIME);
+ QuestLog_Update();
+ end
+ elseif ( event == "PARTY_MEMBERS_CHANGED" or event == "PARTY_MEMBER_ENABLE" or event == "PARTY_MEMBER_DISABLE" ) then
+ QuestLog_Update();
+ if ( event == "PARTY_MEMBERS_CHANGED" ) then
+ QuestLogControlPanel_UpdateState();
+ end
+ elseif ( event == "DISPLAY_SIZE_CHANGED" and self:IsShown() ) then
+ for _, questTitleButton in pairs(QuestLogScrollFrame.buttons) do
+ QuestLogTitleButton_Resize(questTitleButton);
+ end
+ end
+end
+
+function QuestLog_OnShow(self)
+ if ( QuestLogDetailFrame:IsShown() ) then
+ HideUIPanel(QuestLogDetailFrame);
+ end
+ UpdateMicroButtons();
+ PlaySound("igQuestLogOpen");
+ QuestLogControlPanel_UpdatePosition();
+ QuestLogShowMapPOI_UpdatePosition();
+ QuestLog_SetSelection(GetQuestLogSelection());
+ QuestLog_Update();
+
+ QuestLogDetailFrame_AttachToQuestLog();
+end
+
+function QuestLog_OnHide(self)
+ UpdateMicroButtons();
+ PlaySound("igQuestLogClose");
+ QuestLogShowMapPOI_UpdatePosition();
+ QuestLogControlPanel_UpdatePosition();
+
+ QuestLogDetailFrame_DetachFromQuestLog();
+end
+
+function QuestLog_OnUpdate(self, elapsed)
+ if ( self.groupUpdateTimer ) then
+ -- this updates the quest log periodically so we can accurately update the number of group members sharing
+ -- quests with the player
+ self.groupUpdateTimer = self.groupUpdateTimer + elapsed;
+ if ( self.groupUpdateTimer > GROUP_UPDATE_INTERVAL_SEC ) then
+ QuestLog_Update();
+ self.groupUpdateTimer = 0;
+ end
+ end
+end
+
+function QuestLog_UpdateMapButton()
+ if ( WatchFrame.showObjectives and GetNumQuestLogEntries() ~= 0 ) then
+ QuestLogFrameShowMapButton:Show();
+ else
+ QuestLogFrameShowMapButton:Hide();
+ end
+end
+
+function QuestLog_Update()
+ if ( not QuestLogFrame:IsShown() ) then
+ return;
+ end
+
+ local numEntries, numQuests = GetNumQuestLogEntries();
+ if ( numEntries == 0 ) then
+ HideUIPanel(QuestLogDetailFrame);
+ QuestLogDetailFrame.timeLeft = nil;
+ EmptyQuestLogFrame:Show();
+ QuestLog_SetSelection(0);
+ else
+ EmptyQuestLogFrame:Hide();
+ end
+
+ QuestLog_UpdateMapButton();
+
+ -- Update Quest Count
+ QuestLog_UpdateQuestCount(numQuests);
+
+ -- If no selection then set it to the first available quest
+ local questLogSelection = GetQuestLogSelection();
+ local haveSelection = questLogSelection ~= 0;
+ if ( numQuests > 0 and not haveSelection ) then
+ if ( QuestLogFrame.selectedIndex ) then
+ QuestLog_SetNearestValidSelection();
+ else
+ QuestLog_SetFirstValidSelection();
+ end
+ questLogSelection = GetQuestLogSelection();
+ end
+ QuestLogFrame.selectedIndex = questLogSelection;
+
+ --The counts may have changed with SetNearestValidSelection expanding quest headers.
+ --Bug ID 170644
+ numEntries, numQuests = GetNumQuestLogEntries();
+
+ -- hide the details if we don't have a selected quest
+ if ( not haveSelection ) then
+ HideUIPanel(QuestLogDetailFrame);
+ end
+
+ -- update the group timer
+ local haveGroup = GetNumPartyMembers() > 0 or GetNumRaidMembers() > 1;
+ if ( haveGroup ) then
+ QuestLogFrame.groupUpdateTimer = 0;
+ else
+ QuestLogFrame.groupUpdateTimer = nil;
+ end
+
+ -- hide the highlight frame initially, it may be shown when we loop through the quest listing if a quest is selected
+ QuestLogHighlightFrame:Hide();
+
+ -- Update the quest listing
+ local buttons = QuestLogScrollFrame.buttons;
+ local numButtons = #buttons;
+ local scrollOffset = HybridScrollFrame_GetOffset(QuestLogScrollFrame);
+ local buttonHeight = buttons[1]:GetHeight();
+ local displayedHeight = 0;
+
+ local numPartyMembers = GetNumPartyMembers();
+ local questIndex, questLogTitle, questTitleTag, questNumGroupMates, questNormalText, questCheck;
+ local title, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily, questID, displayQuestID;
+ local color;
+ local partyMembersOnQuest, tempWidth, textWidth;
+ for i=1, numButtons do
+ questLogTitle = buttons[i];
+ questIndex = i + scrollOffset;
+ questLogTitle:SetID(questIndex);
+ questTitleTag = questLogTitle.tag;
+ questNumGroupMates = questLogTitle.groupMates;
+ questCheck = questLogTitle.check;
+ questNormalText = questLogTitle.normalText;
+ if ( questIndex <= numEntries ) then
+ title, level, questTag, suggestedGroup, isHeader, isCollapsed, isComplete, isDaily, questID, displayQuestID = GetQuestLogTitle(questIndex);
+
+ if ( isHeader ) then
+ -- set the title
+ if ( title ) then
+ questLogTitle:SetText(title);
+ else
+ questLogTitle:SetText("");
+ end
+
+ -- set the normal texture based on the header's collapsed state
+ if ( isCollapsed ) then
+ questLogTitle:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
+ else
+ questLogTitle:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
+ end
+ questLogTitle:SetHighlightTexture("Interface\\Buttons\\UI-PlusButton-Hilight");
+
+ questNumGroupMates:Hide();
+ questTitleTag:Hide();
+ questCheck:Hide();
+ else
+ -- set the title
+ if ( ENABLE_COLORBLIND_MODE == "1" ) then
+ title = "["..level.."] " .. title;
+ end
+ if (questID and displayQuestID) then
+ questLogTitle:SetText(" "..questID.." - "..title);
+ else
+ questLogTitle:SetText(" "..title);
+ end
+
+ -- this isn't a header, hide the header textures
+ questLogTitle:SetNormalTexture("");
+ questLogTitle:SetHighlightTexture("");
+
+ -- If not a header see if any nearby group mates are on this quest
+ partyMembersOnQuest = 0;
+ for j=1, numPartyMembers do
+ if ( IsUnitOnQuest(questIndex, "party"..j) ) then
+ partyMembersOnQuest = partyMembersOnQuest + 1;
+ end
+ end
+ if ( partyMembersOnQuest > 0 ) then
+ questNumGroupMates:SetText("["..partyMembersOnQuest.."]");
+ questNumGroupMates:Show();
+ else
+ questNumGroupMates:Hide();
+ end
+
+ -- figure out which tag to show, if any
+ if ( isComplete and isComplete < 0 ) then
+ questTag = FAILED;
+ elseif ( isComplete and isComplete > 0 ) then
+ questTag = COMPLETE;
+ elseif ( isDaily ) then
+ if ( questTag ) then
+ questTag = format(DAILY_QUEST_TAG_TEMPLATE, questTag);
+ else
+ questTag = DAILY;
+ end
+ end
+ if ( questTag ) then
+ questTitleTag:SetText("("..questTag..")");
+ questTitleTag:Show();
+ else
+ questTitleTag:Hide();
+ end
+
+ -- show the quest check if the quest is being watched
+ if ( IsQuestWatched(questIndex) ) then
+ questCheck:Show();
+ else
+ questCheck:Hide();
+ end
+ end
+
+ -- Save if its a header or not
+ questLogTitle.isHeader = isHeader;
+
+ -- resize the title button so everything fits where it's supposed to
+ QuestLogTitleButton_Resize(questLogTitle);
+
+ -- Color the quest title and highlight according to the difficulty level
+ if ( isHeader ) then
+ color = QuestDifficultyColors["header"];
+ else
+ color = GetQuestDifficultyColor(level);
+ end
+ questTitleTag:SetTextColor(color.r, color.g, color.b);
+ questLogTitle:SetNormalFontObject(color.font);
+ questNumGroupMates:SetTextColor(color.r, color.g, color.b);
+ questLogTitle.r = color.r;
+ questLogTitle.g = color.g;
+ questLogTitle.b = color.b;
+ questLogTitle:Show();
+
+ -- Place the highlight and lock the highlight state
+ if ( questLogSelection == questIndex ) then
+ _QuestLog_HighlightQuest(questLogTitle);
+ else
+ questLogTitle:UnlockHighlight();
+ end
+ else
+ questLogTitle:Hide();
+ end
+ displayedHeight = displayedHeight + buttonHeight;
+ end
+ HybridScrollFrame_Update(QuestLogScrollFrame, numEntries * buttonHeight, displayedHeight);
+
+ -- update the control panel
+ QuestLogControlPanel_UpdateState();
+end
+
+function QuestLog_UpdateQuestCount(numQuests)
+ QuestLogQuestCount:SetFormattedText(QUEST_LOG_COUNT_TEMPLATE, numQuests, MAX_QUESTLOG_QUESTS);
+ local textHeight = 12;
+ local hPadding = 15;
+ local vPadding = 8;
+ local dailyQuestsComplete = GetDailyQuestsCompleted();
+ local parent = QuestLogCount:GetParent();
+ local width = QuestLogQuestCount:GetWidth();
+
+ if ( dailyQuestsComplete > 0 ) then
+ QuestLogDailyQuestCount:SetFormattedText(QUEST_LOG_DAILY_COUNT_TEMPLATE, dailyQuestsComplete, GetMaxDailyQuests());
+ QuestLogDailyQuestCount:Show();
+ QuestLogDailyQuestCountMouseOverFrame:Show();
+ if ( QuestLogDailyQuestCount:GetWidth() > width ) then
+ width = QuestLogDailyQuestCount:GetWidth();
+ end
+ QuestLogCount:SetHeight(textHeight*2+vPadding);
+ QuestLogCount:SetPoint("TOPLEFT", parent, "TOPLEFT", 80, -38);
+ else
+ QuestLogDailyQuestCount:Hide();
+ QuestLogDailyQuestCountMouseOverFrame:Hide();
+ QuestLogCount:SetHeight(textHeight+vPadding);
+ QuestLogCount:SetPoint("TOPLEFT", parent, "TOPLEFT", 80, -41);
+ end
+ QuestLogCount:SetWidth(width+hPadding);
+end
+
+function QuestLog_UpdateQuestDetails(resetScrollBar)
+ QuestInfo_Display(QUEST_TEMPLATE_LOG, QuestLogDetailScrollChildFrame)
+ if ( resetScrollBar ) then
+ QuestLogDetailScrollFrameScrollBar:SetValue(0);
+ end
+ QuestLogDetailScrollFrame:Show();
+end
+
+function QuestLog_UpdateMap()
+ -- Fill in map tiles
+ local mapFileName, textureHeight = GetMapInfo();
+ if ( not mapFileName ) then
+ return;
+ end
+ local texName;
+ local dungeonLevel = GetCurrentMapDungeonLevel();
+ local completeMapFileName;
+ if ( dungeonLevel > 0 ) then
+ completeMapFileName = mapFileName..dungeonLevel.."_";
+ else
+ completeMapFileName = mapFileName;
+ end
+ local mapFrameWidth = QuestLogMapFrame:GetRight() - QuestLogMapFrame:GetLeft();
+ local mapFrameHeight = QuestLogMapFrame:GetTop() - QuestLogMapFrame:GetBottom();
+ local tileWidth = mapFrameWidth / NUM_WORLDMAP_DETAIL_TILE_COLS;
+ -- there are a few unused pixels on the bottom of the bottom row's map tiles, so fudge the map height
+ -- to account for these extra pixels
+ local tileHeight = (mapFrameHeight) / NUM_WORLDMAP_DETAIL_TILE_ROWS;
+ local tile;
+ for i=1, NUM_WORLDMAP_DETAIL_TILES do
+ tile = _G["QuestLogMapFrame"..i];
+ tile:SetTexture("Interface\\WorldMap\\"..mapFileName.."\\"..completeMapFileName..i);
+--[[
+ tile:SetWidth(tileWidth);
+--]]
+ tile:SetHeight(tileHeight);
+ end
+end
+
+function QuestLog_UpdatePartyInfoTooltip(questLogTitle)
+ local numPartyMembers = GetNumPartyMembers();
+ if ( numPartyMembers == 0 or questLogTitle.isHeader ) then
+ return;
+ end
+
+ GameTooltip_SetDefaultAnchor(GameTooltip, questLogTitle);
+
+ local questIndex = questLogTitle:GetID();
+ local title = GetQuestLogTitle(questIndex);
+ GameTooltip:SetText(title);
+
+ local partyMemberOnQuest = false;
+ for i=1, numPartyMembers do
+ if ( IsUnitOnQuest(questIndex, "party"..i) ) then
+ if ( not partyMemberOnQuest ) then
+ GameTooltip:AddLine(HIGHLIGHT_FONT_COLOR_CODE..PARTY_QUEST_STATUS_ON..FONT_COLOR_CODE_CLOSE);
+ partyMemberOnQuest = true;
+ end
+ GameTooltip:AddLine(LIGHTYELLOW_FONT_COLOR_CODE..UnitName("party"..i)..FONT_COLOR_CODE_CLOSE);
+ end
+ end
+ if ( not partyMemberOnQuest ) then
+ --GameTooltip:AddLine(HIGHLIGHT_FONT_COLOR_CODE..PARTY_QUEST_STATUS_NONE..FONT_COLOR_CODE_CLOSE);
+ GameTooltip:Hide();
+ else
+ GameTooltip:Show();
+ end
+end
+
+function QuestLog_SetSelection(questIndex)
+ SelectQuestLogEntry(questIndex);
+ StaticPopup_Hide("ABANDON_QUEST");
+ StaticPopup_Hide("ABANDON_QUEST_WITH_ITEMS");
+ SetAbandonQuest();
+
+ QuestLogControlPanel_UpdateState();
+
+ if ( questIndex == 0 ) then
+ QuestLogFrame.selectedIndex = nil;
+ HideUIPanel(QuestLogDetailFrame);
+ QuestLogDetailScrollFrame:Hide();
+ return;
+ end
+
+ local title, level, questTag, suggestedGroup, isHeader, isCollapsed = GetQuestLogTitle(questIndex);
+ if ( isHeader ) then
+ if ( isCollapsed ) then
+ ExpandQuestHeader(questIndex);
+ else
+ CollapseQuestHeader(questIndex);
+ end
+ return;
+ end
+
+ QuestLogFrame.selectedIndex = questIndex;
+
+ local scrollBarOffset = _QuestLog_GetQuestScrollOffset(questIndex);
+ if ( scrollBarOffset ~= 0 ) then
+ -- adjust the scroll bar to show the quest, if necessary
+ -- NOTE: this must be done BEFORE you highlight the quest (otherwise, the button you need to highlight may not be visible)
+ QuestLogScrollFrameScrollBar:SetValue(QuestLogScrollFrameScrollBar:GetValue() - scrollBarOffset);
+ end
+ -- find and highlight the selected quest
+ local buttons = QuestLogScrollFrame.buttons;
+ local numButtons = #buttons;
+ local min = 1;
+ local max = #buttons;
+ local mid;
+ local titleButton, id;
+ while ( min <= max ) do
+ mid = bit.rshift(min + max, 1);
+ titleButton = buttons[mid];
+ id = titleButton:GetID();
+ if ( id == questIndex ) then
+ _QuestLog_HighlightQuest(titleButton);
+ break;
+ end
+ if ( id > questIndex ) then
+ max = mid - 1;
+ else
+ min = mid + 1;
+ end
+ end
+
+ -- update the quest
+ QuestLog_UpdateQuestDetails(true);
+ QuestLog_UpdateMap();
+ if ( not QuestLogFrame:IsShown() ) then
+ ShowUIPanel(QuestLogDetailFrame);
+ end
+end
+
+function QuestLog_UnsetSelection()
+ QuestLog_SetSelection(0);
+ QuestLog_Update();
+end
+
+function QuestLog_GetFirstSelectableQuest()
+ local numEntries = GetNumQuestLogEntries();
+ local title, level, questTag, suggestedGroup, isHeader, isCollapsed;
+ for i=1, numEntries do
+ title, level, questTag, suggestedGroup, isHeader, isCollapsed = GetQuestLogTitle(i);
+ if ( title and not isHeader ) then
+ return i;
+ end
+ end
+ return 0;
+end
+
+function QuestLog_SetFirstValidSelection()
+ local selectableQuest = QuestLog_GetFirstSelectableQuest();
+ QuestLog_SetSelection(selectableQuest);
+ QuestLogDetailScrollFrameScrollBar:SetValue(0);
+end
+
+-- this function assumes that QuestLogFrame.selectedIndex points to an invalid quest
+-- the most likely cause of this case is that the selected quest was abandoned
+function QuestLog_SetNearestValidSelection()
+ local numEntries = GetNumQuestLogEntries();
+ if ( numEntries == 0 ) then
+ QuestLog_SetSelection(0);
+ return;
+ end
+
+ local questIndex = QuestLogFrame.selectedIndex;
+ if ( questIndex > numEntries ) then
+ -- if the index is now past the end of the list, treat it as if it were at the end of the list
+ questIndex = numEntries;
+ end
+
+ local title, level, questTag, suggestedGroup, isHeader, isCollapsed;
+
+ -- 1. try to select the quest that is currently under the selected index
+ title, level, questTag, suggestedGroup, isHeader, isCollapsed = GetQuestLogTitle(questIndex);
+ if ( title and not isHeader ) then
+ QuestLog_SetSelection(questIndex);
+ QuestLogDetailScrollFrameScrollBar:SetValue(0);
+ return;
+ end
+
+ -- 2. try to select the previous quest
+ title, level, questTag, suggestedGroup, isHeader, isCollapsed = GetQuestLogTitle(questIndex - 1);
+ if ( title ) then
+ if ( not isHeader ) then
+ -- the previous quest is not a header, select it
+ QuestLog_SetSelection(questIndex - 1);
+ QuestLogDetailScrollFrameScrollBar:SetValue(0);
+ return;
+ else
+ -- the previous quest is a header
+ -- at this point, we will just expand the header if it is collapsed, then we will select the first quest under the header
+ if ( isCollapsed ) then
+ ExpandQuestHeader(questIndex - 1);
+ end
+ QuestLog_SetSelection(questIndex);
+ QuestLogDetailScrollFrameScrollBar:SetValue(0);
+ return;
+ end
+ end
+
+ -- 3, Found nothing, so deselect
+ QuestLog_SetSelection(0);
+end
+
+function QuestLog_OpenToQuest(questIndex, keepOpen)
+ local selectedIndex = GetQuestLogSelection();
+--[[
+ if ( selectedIndex ~= 0 and questIndex == selectedIndex and QuestLogFrame:IsShown() and
+ _QuestLog_GetQuestScrollOffset(questIndex) == 0 ) then
+ -- if the current quest is selected and is visible, then treat this as a toggle
+ HideUIPanel(QuestLogFrame);
+ return;
+ end
+
+ local numEntries, numQuests = GetNumQuestLogEntries();
+ if ( questIndex < 1 or questIndex > numEntries ) then
+ return;
+ end
+
+ ExpandQuestHeader(0);
+ ShowUIPanel(QuestLogFrame);
+ QuestLog_SetSelection(questIndex);
+--]]
+
+ if ( not keepOpen and selectedIndex ~= 0 and questIndex == selectedIndex and QuestLogDetailFrame:IsShown() ) then
+ -- if the current quest is selected and is visible, then treat this as a toggle
+ HideUIPanel(QuestLogDetailFrame);
+ return;
+ end
+
+ local numEntries, numQuests = GetNumQuestLogEntries();
+ if ( questIndex < 1 or questIndex > numEntries ) then
+ return;
+ end
+ HideUIPanel(QuestFrame);
+ QuestLog_SetSelection(questIndex);
+end
+
+--
+-- QuestLogFrameTrackButton
+--
+
+function QuestLogFrameTrackButton_OnClick(self)
+ _QuestLog_ToggleQuestWatch(GetQuestLogSelection());
+ QuestLog_Update();
+end
+
+
+--
+-- QuestLogDetailFrame
+--
+
+function QuestLogDetailFrame_OnShow(self)
+ PlaySound("igQuestLogOpen");
+ QuestLogControlPanel_UpdatePosition();
+ QuestLogShowMapPOI_UpdatePosition();
+ QuestLog_UpdateQuestDetails();
+end
+
+function QuestLogDetailFrame_OnHide(self)
+ -- this function effectively deselects the selected quest
+ PlaySound("igQuestLogClose");
+ QuestLogControlPanel_UpdatePosition();
+ QuestLogShowMapPOI_UpdatePosition();
+end
+
+function QuestLogDetailFrame_AttachToQuestLog()
+ QuestLogDetailScrollFrame:SetParent(QuestLogFrame);
+ QuestLogDetailScrollFrame:ClearAllPoints();
+ QuestLogDetailScrollFrame:SetPoint("TOPRIGHT", QuestLogFrame, "TOPRIGHT", -32, -77);
+ QuestLogDetailScrollFrame:SetHeight(333);
+ QuestLogDetailScrollFrameScrollBar:SetPoint("TOPLEFT", QuestLogDetailScrollFrame, "TOPRIGHT", 6, -13);
+ QuestLogDetailScrollFrameScrollBackgroundBottomRight:Hide();
+ QuestLogDetailScrollFrameScrollBackgroundTopLeft:Hide();
+end
+
+function QuestLogDetailFrame_DetachFromQuestLog()
+ QuestLogDetailScrollFrame:SetParent(QuestLogDetailFrame);
+ QuestLogDetailScrollFrame:ClearAllPoints();
+ QuestLogDetailScrollFrame:SetPoint("TOPLEFT", QuestLogDetailFrame, "TOPLEFT", 19, -76);
+ QuestLogDetailScrollFrame:SetHeight(334);
+ QuestLogDetailScrollFrameScrollBar:SetPoint("TOPLEFT", QuestLogDetailScrollFrame, "TOPRIGHT", 6, -16);
+ QuestLogDetailScrollFrameScrollBackgroundBottomRight:Show();
+ QuestLogDetailScrollFrameScrollBackgroundTopLeft:Show();
+end
+
+function QuestLogDetailFrame_OnLoad(self)
+ QuestLogDetailFrame_DetachFromQuestLog();
+end
+
+--
+-- QuestLogControlPanel
+--
+
+function QuestLogControlPanel_UpdatePosition()
+ local parent;
+ if ( QuestLogFrame:IsShown() ) then
+ parent = QuestLogFrame;
+ QuestLogControlPanel:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", 18, 11);
+ QuestLogControlPanel:SetWidth(307);
+ elseif ( QuestLogDetailFrame:IsShown() ) then
+ parent = QuestLogDetailFrame;
+ QuestLogControlPanel:SetPoint("BOTTOMLEFT", parent, "BOTTOMLEFT", 18, 5);
+ QuestLogControlPanel:SetWidth(327);
+ end
+ if ( parent ) then
+ QuestLogControlPanel:SetParent(parent);
+ QuestLogControlPanel:Show();
+ else
+ QuestLogControlPanel:Hide();
+ end
+end
+
+function QuestLogControlPanel_UpdateState()
+ local questLogSelection = GetQuestLogSelection();
+
+ if ( questLogSelection == 0 ) then
+ QuestLogFrameAbandonButton:Disable();
+ QuestLogFrameTrackButton:Disable();
+ QuestLogFramePushQuestButton:Disable();
+ else
+ if ( GetAbandonQuestName() ) then
+ QuestLogFrameAbandonButton:Enable();
+ else
+ QuestLogFrameAbandonButton:Disable();
+ end
+
+ QuestLogFrameTrackButton:Enable();
+
+ if ( GetQuestLogPushable() and ( GetNumPartyMembers() > 0 or GetNumRaidMembers() > 1 ) ) then
+ QuestLogFramePushQuestButton:Enable();
+ else
+ QuestLogFramePushQuestButton:Disable();
+ end
+ end
+end
+
+function QuestLogShowMapPOI_UpdatePosition()
+ local parent;
+ if ( QuestLogFrame:IsShown() ) then
+ parent = QuestLogFrame;
+ elseif ( QuestLogDetailFrame:IsShown() ) then
+ parent = QuestLogDetailFrame;
+ end
+
+ if ( parent ) then
+ QuestLogFrameShowMapButton:SetParent(parent);
+ QuestLogFrameShowMapButton:SetPoint("TOPRIGHT", -25, -38);
+ end
+end
\ No newline at end of file
diff --git a/reference/FrameXML/QuestLogFrame.xml b/reference/FrameXML/QuestLogFrame.xml
new file mode 100644
index 0000000..9cdfd24
--- /dev/null
+++ b/reference/FrameXML/QuestLogFrame.xml
@@ -0,0 +1,947 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ QuestLogTitleButton_OnLoad(self);
+
+
+ QuestLogTitleButton_OnEvent(self, event, ...);
+
+
+ QuestLogTitleButton_OnClick(self, button, down);
+
+
+ QuestLogTitleButton_OnEnter(self);
+
+
+ QuestLogTitleButton_OnLeave(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ if ( self.rewardType == "item" ) then
+ GameTooltip:SetQuestLogItem(self.type, self:GetID());
+ GameTooltip_ShowCompareItem(GameTooltip);
+ elseif ( self.rewardType == "spell" ) then
+ GameTooltip:SetQuestLogRewardSpell();
+ end
+
+
+ if ( self.rewardType == "spell" ) then
+ if ( IsModifiedClick("CHATLINK") ) then
+ ChatEdit_InsertLink(GetQuestLogSpellLink());
+ end
+ else
+ HandleModifiedItemClick(GetQuestLogItemLink(self.type, self:GetID()));
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SetAbandonQuest();
+ local items = GetAbandonQuestItems();
+ if ( items ) then
+ StaticPopup_Hide("ABANDON_QUEST");
+ StaticPopup_Show("ABANDON_QUEST_WITH_ITEMS", GetAbandonQuestName(), items);
+ else
+ StaticPopup_Hide("ABANDON_QUEST_WITH_ITEMS");
+ StaticPopup_Show("ABANDON_QUEST", GetAbandonQuestName());
+ end
+
+
+ GameTooltip_AddNewbieTip(self, ABANDON_QUEST, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_ABANDONQUEST, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, TRACK_QUEST, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_TRACKQUEST, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ QuestLogPushQuest();
+ PlaySound("igQuestLogOpen");
+
+
+ GameTooltip_AddNewbieTip(self, SHARE_QUEST, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_SHAREQUEST, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ HideUIPanel(QuestLogFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetWidth(self.text:GetWidth() + self.texture:GetWidth());
+
+
+ local questID = select(9, GetQuestLogTitle(QuestLogFrame.selectedIndex))
+ WorldMap_OpenToQuest(questID, self:GetParent());
+
+
+ QuestLogFrameShowMapButtonHighlight:Show();
+
+
+ QuestLogFrameShowMapButtonHighlight:Hide();
+
+
+ self.texture:SetTexCoord(0.125, 0.875, 0.5, 1.0);
+
+
+ self.texture:SetTexCoord(0.125, 0.875, 0.0, 0.5);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(format(QUEST_LOG_DAILY_TOOLTIP, GetMaxDailyQuests(), SecondsToTime(GetQuestResetTime(), nil, 1)));
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local name = self:GetName();
+ _G[name.."BG"]:Hide();
+ _G[name.."Top"]:Hide();
+ _G[name.."Bottom"]:Hide();
+ _G[name.."Middle"]:Hide();
+ self.doNotHide = true;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:SetParent(nil);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/QuestPOI.lua b/reference/FrameXML/QuestPOI.lua
new file mode 100644
index 0000000..673234f
--- /dev/null
+++ b/reference/FrameXML/QuestPOI.lua
@@ -0,0 +1,241 @@
+local QUEST_POI_BUTTONS_MAX = { }; -- max of a button created
+local QUEST_POI_BUTTONS_SELECTED = { }; -- selected button
+QUEST_POI_SWAP_BUTTONS = { }; -- buttons that need to swap in (for QUEST_POI_COMPLETE_SWAP type)
+QUEST_POI_ICONS_PER_ROW = 8;
+QUEST_POI_ICON_SIZE = 0.125;
+
+-- POI types
+local QUEST_POI_MAX_TYPES = 4;
+QUEST_POI_NUMERIC = 1; -- number within a circle
+QUEST_POI_COMPLETE_IN = 2; -- completed quest icon within a normal circle
+QUEST_POI_COMPLETE_OUT = 3; -- completed quest icon within a darker circle (quest outside current zone)
+QUEST_POI_COMPLETE_SWAP = 4; -- completed quest icon without a circle that needs to be swapped on selection (for map)
+
+-- POI text colors (offsets into texture)
+local QUEST_POI_COLOR_BLACK = 0;
+local QUEST_POI_COLOR_YELLOW = 0.5;
+
+function QuestPOI_DisplayButton(parentName, buttonType, buttonIndex, questId)
+ local buttonName = "poi"..parentName..buttonType.."_"..buttonIndex;
+ local poiButton = _G[buttonName];
+ local swapButton;
+
+ if ( not poiButton ) then
+ if ( buttonType == QUEST_POI_COMPLETE_SWAP ) then
+ poiButton = CreateFrame("Button", buttonName, _G[parentName], "QuestPOICompletedTemplate");
+ if ( not QUEST_POI_SWAP_BUTTONS[parentName] ) then
+ swapButton = true;
+ end
+ else
+ poiButton = CreateFrame("Button", buttonName, _G[parentName], "QuestPOITemplate");
+ end
+ -- frame-specific stuff
+ if ( parentName == "WatchFrameLines" ) then
+ poiButton:SetScale(0.9);
+ poiButton:SetScript("OnClick", WatchFrameQuestPOI_OnClick);
+ elseif ( parentName == "WorldMapPOIFrame" ) then
+ poiButton:SetScript("OnEnter", WorldMapQuestPOI_OnEnter);
+ poiButton:SetScript("OnLeave", WorldMapQuestPOI_OnLeave);
+ poiButton:SetScript("OnClick", WorldMapQuestPOI_OnClick);
+ if ( swapButton ) then
+ swapButton = CreateFrame("Button", "poi"..parentName.."_Swap", _G[parentName], "QuestPOITemplate");
+ QUEST_POI_SWAP_BUTTONS[parentName] = swapButton;
+ swapButton.type = buttonType;
+ swapButton:SetScript("OnEnter", WorldMapQuestPOI_OnEnter);
+ swapButton:SetScript("OnLeave", WorldMapQuestPOI_OnLeave);
+ swapButton:SetScript("OnClick", WorldMapQuestPOI_OnClick);
+ swapButton:SetFrameLevel(poiButton:GetFrameLevel() + 2);
+ swapButton.selectionGlow:Show();
+ swapButton.normalTexture:SetTexCoord(0.500, 0.625, 0.375, 0.5);
+ swapButton.pushedTexture:SetTexCoord(0.375, 0.500, 0.375, 0.5);
+ swapButton.highlightTexture:SetTexCoord(0.625, 0.750, 0.375, 0.5);
+ swapButton.turnin:Show();
+ swapButton.number:Hide();
+ end
+ end
+ -- *
+ poiButton.index = buttonIndex;
+ poiButton.type = buttonType;
+ poiButton.parentName = parentName;
+ QUEST_POI_BUTTONS_MAX[parentName..buttonType] = buttonIndex;
+ if ( buttonType == QUEST_POI_COMPLETE_IN ) then
+ poiButton.turnin:Show();
+ poiButton.number:Hide();
+ elseif ( buttonType == QUEST_POI_COMPLETE_OUT ) then
+ poiButton.turnin:Show();
+ poiButton.number:Hide();
+ poiButton.normalTexture:SetTexCoord(0.500, 0.625, 0.875, 1.0);
+ poiButton.pushedTexture:SetTexCoord(0.375, 0.500, 0.875, 1.0);
+ poiButton.highlightTexture:SetTexCoord(0.625, 0.750, 0.375, 0.5);
+ elseif ( buttonType == QUEST_POI_NUMERIC ) then
+ buttonIndex = buttonIndex - 1;
+ local yOffset = 0.5 + floor(buttonIndex / QUEST_POI_ICONS_PER_ROW) * QUEST_POI_ICON_SIZE;
+ local xOffset = mod(buttonIndex, QUEST_POI_ICONS_PER_ROW) * QUEST_POI_ICON_SIZE;
+ poiButton.number:SetTexCoord(xOffset, xOffset + QUEST_POI_ICON_SIZE, yOffset, yOffset + QUEST_POI_ICON_SIZE);
+ end
+ end
+ poiButton.questId = questId;
+ if ( poiButton.isSelected ) then
+ QuestPOI_DeselectButton(poiButton);
+ end
+ poiButton:Show();
+ return poiButton;
+end
+
+local function QuestPOI_FindButtonByQuestId(parentName, questId)
+ local poiButton;
+ local numButtons;
+
+ for i = 1, QUEST_POI_MAX_TYPES do
+ numButtons = QUEST_POI_BUTTONS_MAX[parentName..i];
+ if ( numButtons ) then
+ for j = 1, numButtons do
+ poiButton = _G["poi"..parentName..i.."_"..j];
+ if ( poiButton.questId == questId ) then
+ return poiButton;
+ end
+ end
+ end
+ end
+end
+
+function QuestPOI_SelectButtonByIndex(parentName, buttonType, buttonIndex)
+ QuestPOI_SelectButton(_G["poi"..parentName..buttonType.."_"..buttonIndex]);
+end
+
+function QuestPOI_SelectButtonByQuestId(parentName, questId, deselectOnFail)
+ local poiButton = QuestPOI_FindButtonByQuestId(parentName, questId);
+ if ( poiButton ) then
+ QuestPOI_SelectButton(poiButton);
+ elseif ( deselectOnFail ) then
+ poiButton = QUEST_POI_BUTTONS_SELECTED[parentName];
+ if ( poiButton ) then
+ QuestPOI_DeselectButton(poiButton);
+ end
+ end
+end
+
+function QuestPOI_SelectButton(poiButton)
+ if ( poiButton ) then
+ local parentName = poiButton.parentName;
+ if ( QUEST_POI_BUTTONS_SELECTED[parentName] ) then
+ -- return if already selected
+ if ( QUEST_POI_BUTTONS_SELECTED[parentName] == poiButton ) then
+ return;
+ else
+ QuestPOI_DeselectButton(QUEST_POI_BUTTONS_SELECTED[parentName]);
+ end
+ end
+ -- select
+ QUEST_POI_BUTTONS_SELECTED[parentName] = poiButton;
+ poiButton.isSelected = true;
+ if ( poiButton.type == QUEST_POI_NUMERIC ) then
+ poiButton.selectionGlow:Show();
+ poiButton.normalTexture:SetTexCoord(0.500, 0.625, 0.375, 0.5);
+ poiButton.pushedTexture:SetTexCoord(0.375, 0.500, 0.375, 0.5);
+ poiButton.highlightTexture:SetTexCoord(0.625, 0.750, 0.375, 0.5);
+ QuestPOI_SetTextColor(poiButton, QUEST_POI_COLOR_BLACK);
+ elseif ( poiButton.type == QUEST_POI_COMPLETE_IN ) then
+ poiButton.selectionGlow:Show();
+ poiButton.normalTexture:SetTexCoord(0.500, 0.625, 0.375, 0.5);
+ poiButton.pushedTexture:SetTexCoord(0.375, 0.500, 0.375, 0.5);
+ poiButton.highlightTexture:SetTexCoord(0.625, 0.750, 0.375, 0.5);
+ elseif ( poiButton.type == QUEST_POI_COMPLETE_OUT ) then
+ -- has no selected mode, should switch to QUEST_POI_COMPLETE_IN type upon being selected
+ elseif ( poiButton.type == QUEST_POI_COMPLETE_SWAP ) then
+ local swapButton = QUEST_POI_SWAP_BUTTONS[parentName];
+ swapButton:ClearAllPoints();
+ swapButton:SetPoint("CENTER", poiButton);
+ swapButton.quest = poiButton.quest;
+ swapButton:Show();
+ poiButton:Hide();
+ end
+ end
+end
+
+function QuestPOI_DeselectButtonByParent(parentName)
+ QuestPOI_DeselectButton(QUEST_POI_BUTTONS_SELECTED[parentName]);
+end
+
+function QuestPOI_DeselectButton(poiButton)
+ if ( poiButton and poiButton.isSelected ) then
+ if ( poiButton.type == QUEST_POI_NUMERIC ) then
+ poiButton.selectionGlow:Hide();
+ poiButton.normalTexture:SetTexCoord(0.875, 1, 0.875, 1);
+ poiButton.pushedTexture:SetTexCoord(0.750, 0.875, 0.875, 1);
+ poiButton.highlightTexture:SetTexCoord(0.625, 0.750, 0.875, 1);
+ QuestPOI_SetTextColor(poiButton, QUEST_POI_COLOR_YELLOW);
+ elseif ( poiButton.type == QUEST_POI_COMPLETE_IN ) then
+ poiButton.selectionGlow:Hide();
+ poiButton.normalTexture:SetTexCoord(0.875, 1, 0.875, 1);
+ poiButton.pushedTexture:SetTexCoord(0.750, 0.875, 0.875, 1);
+ poiButton.highlightTexture:SetTexCoord(0.625, 0.750, 0.875, 1);
+ elseif ( poiButton.type == QUEST_POI_COMPLETE_OUT ) then
+ -- has no selected mode
+ elseif ( poiButton.type == QUEST_POI_COMPLETE_SWAP ) then
+ poiButton:Show();
+ QUEST_POI_SWAP_BUTTONS[poiButton.parentName]:Hide();
+ end
+ QUEST_POI_BUTTONS_SELECTED[poiButton.parentName] = nil;
+ poiButton.isSelected = false;
+ end
+end
+
+function QuestPOI_SetTextColor(poiButton, yOffset)
+ local index = poiButton.index - 1
+ yOffset = yOffset + floor(index / QUEST_POI_ICONS_PER_ROW) * QUEST_POI_ICON_SIZE;
+ local xOffset = mod(index, QUEST_POI_ICONS_PER_ROW) * QUEST_POI_ICON_SIZE;
+ poiButton.number:SetTexCoord(xOffset, xOffset + QUEST_POI_ICON_SIZE, yOffset, yOffset + QUEST_POI_ICON_SIZE);
+end
+
+function QuestPOI_HideButtons(parentName, buttonType, buttonIndex)
+ local numButtons;
+
+ numButtons = QUEST_POI_BUTTONS_MAX[parentName..buttonType];
+ if ( numButtons ) then
+ local poiButton;
+ local buttonName = "poi"..parentName..buttonType.."_";
+ for i = buttonIndex, numButtons do
+ poiButton = _G[buttonName..i];
+ if ( poiButton.isSelected and poiButton.type == QUEST_POI_COMPLETE_SWAP ) then
+ QuestPOI_DeselectButton(poiButton);
+ end
+ poiButton:Hide();
+ end
+ end
+end
+
+function QuestPOI_HideAllButtons(parentName)
+ local numButtons;
+
+ for i = 1, QUEST_POI_MAX_TYPES do
+ numButtons = QUEST_POI_BUTTONS_MAX[parentName..i];
+ if ( numButtons ) then
+ local poiButton;
+ local buttonName = "poi"..parentName..i.."_";
+ for j = 1, numButtons do
+ poiButton = _G[buttonName..j];
+ if ( poiButton.isSelected and poiButton.type == QUEST_POI_COMPLETE_SWAP ) then
+ QuestPOI_DeselectButton(poiButton);
+ end
+ poiButton:Hide();
+ end
+ end
+ end
+end
+
+function QuestPOIButton_OnMouseDown(self)
+ if ( self.isComplete ) then
+ self.turnin:SetPoint("CENTER", 0, -1);
+ else
+ self.number:SetPoint("CENTER", 1, -1);
+ end
+end
+
+function QuestPOIButton_OnMouseUp(self)
+ if ( self.isComplete ) then
+ self.turnin:SetPoint("CENTER", -1, 0);
+ else
+ self.number:SetPoint("CENTER", 0, 0);
+ end
+end
\ No newline at end of file
diff --git a/reference/FrameXML/QuestPOI.xml b/reference/FrameXML/QuestPOI.xml
new file mode 100644
index 0000000..2c82996
--- /dev/null
+++ b/reference/FrameXML/QuestPOI.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.normalTexture:SetDrawLayer("BORDER");
+ self.pushedTexture:SetDrawLayer("BORDER");
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.highlightTexture:SetPoint("CENTER", 1, -1);
+
+
+ self.highlightTexture:SetPoint("CENTER", 0, 0);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/QuestTimerFrame.lua b/reference/FrameXML/QuestTimerFrame.lua
new file mode 100644
index 0000000..4fc2f27
--- /dev/null
+++ b/reference/FrameXML/QuestTimerFrame.lua
@@ -0,0 +1,58 @@
+function QuestTimerFrame_OnLoad(self)
+ self:RegisterEvent("QUEST_LOG_UPDATE");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self.numTimers = 0;
+ self.updating = nil;
+end
+
+function QuestTimerFrame_OnEvent(self, event, ...)
+ -- if ( event == "QUEST_LOG_UPDATE" or event == "PLAYER_ENTERING_WORLD" ) then
+ -- if ( not self.updating ) then
+ -- QuestTimerFrame_Update(self, GetQuestTimers());
+ -- end
+ -- end
+end
+
+function QuestTimerFrame_Update(self, ...)
+ QuestTimerFrame:Hide();
+ if ( true ) then
+ return;
+ end
+
+ self.updating = 1;
+ self.numTimers = select("#", ...);
+ for i=1, self.numTimers, 1 do
+ _G["QuestTimer"..i.."Text"]:SetText(SecondsToTime(select(i, ...)));
+ _G["QuestTimer"..i]:Show();
+ end
+ for i=self.numTimers + 1, MAX_QUESTS, 1 do
+ _G["QuestTimer"..i]:Hide();
+ end
+ if ( self.numTimers > 0 ) then
+ self:SetHeight(45 + (16 * self.numTimers));
+ self:Show();
+ else
+ self:Hide();
+ end
+ self.updating = nil;
+end
+
+function QuestTimerFrame_OnUpdate(self, elapsed)
+ if ( self.numTimers > 0 ) then
+ QuestTimerFrame_Update(self, GetQuestTimers());
+ end
+end
+
+function QuestTimerButton_OnClick(self, button)
+ ShowUIPanel(QuestLogFrame);
+ QuestLog_SetSelection(GetQuestIndexForTimer(self:GetID()));
+ QuestLog_Update();
+end
+
+function QuestTimerFrame_OnShow()
+ UIParent_ManageFramePositions();
+end
+
+function QuestTimerFrame_OnHide()
+ UIParent_ManageFramePositions();
+end
diff --git a/reference/FrameXML/QuestTimerFrame.xml b/reference/FrameXML/QuestTimerFrame.xml
new file mode 100644
index 0000000..7121e6f
--- /dev/null
+++ b/reference/FrameXML/QuestTimerFrame.xml
@@ -0,0 +1,313 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip:SetOwner(self);
+ GameTooltip:SetText(GetQuestLogTitle(GetQuestIndexForTimer(self:GetID())), 1.0, 1.0, 1.0);
+ GameTooltip:Show();
+
+
+ GameTooltip:Hide();
+
+
+ QuestTimerButton_OnClick(self, button, down);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/RaidFrame.lua b/reference/FrameXML/RaidFrame.lua
new file mode 100644
index 0000000..39bbf03
--- /dev/null
+++ b/reference/FrameXML/RaidFrame.lua
@@ -0,0 +1,230 @@
+
+MAX_RAID_MEMBERS = 40;
+NUM_RAID_GROUPS = 8;
+MEMBERS_PER_RAID_GROUP = 5;
+MAX_RAID_INFOS = 20;
+
+function RaidFrame_OnLoad(self)
+ self:RegisterEvent("PLAYER_LOGIN");
+ self:RegisterEvent("RAID_ROSTER_UPDATE");
+ self:RegisterEvent("UPDATE_INSTANCE_INFO");
+ self:RegisterEvent("PARTY_MEMBERS_CHANGED");
+ self:RegisterEvent("PARTY_LEADER_CHANGED");
+ self:RegisterEvent("VOICE_STATUS_UPDATE");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+ self:RegisterEvent("READY_CHECK");
+ self:RegisterEvent("READY_CHECK_CONFIRM");
+ self:RegisterEvent("READY_CHECK_FINISHED");
+ self:RegisterEvent("PARTY_LFG_RESTRICTED");
+
+ -- Update party frame visibility
+ RaidOptionsFrame_UpdatePartyFrames();
+ RaidFrame_Update();
+
+ RaidFrame.hasRaidInfo = nil;
+end
+
+function RaidFrame_OnEvent(self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ RequestRaidInfo();
+ elseif ( event == "PLAYER_LOGIN" ) then
+ if ( GetNumRaidMembers() > 0 ) then
+ RaidFrame_LoadUI();
+ RaidFrame_Update();
+ end
+ elseif ( event == "RAID_ROSTER_UPDATE" ) then
+ RaidFrame_LoadUI();
+ RaidFrame_Update();
+ RaidPullout_RenewFrames();
+ elseif ( event == "READY_CHECK" or
+ event == "READY_CHECK_CONFIRM" ) then
+ if ( RaidFrame:IsShown() and RaidGroupFrame_Update ) then
+ RaidGroupFrame_Update();
+ end
+ elseif ( event == "READY_CHECK_FINISHED" ) then
+ if ( RaidFrame:IsShown() and RaidGroupFrame_ReadyCheckFinished ) then
+ RaidGroupFrame_ReadyCheckFinished();
+ end
+ elseif ( event == "UPDATE_INSTANCE_INFO" ) then
+ if ( not RaidFrame.hasRaidInfo ) then
+ -- Set flag
+ RaidFrame.hasRaidInfo = 1;
+ return;
+ end
+ if ( GetNumSavedInstances() > 0 ) then
+ RaidFrameRaidInfoButton:Enable();
+ else
+ RaidFrameRaidInfoButton:Disable();
+ end
+ RaidInfoFrame_Update(true);
+ elseif ( event == "PARTY_MEMBERS_CHANGED" or event == "PARTY_LEADER_CHANGED" or
+ event == "VOICE_STATUS_UPDATE" or event == "PARTY_LFG_RESTRICTED" ) then
+ RaidFrame_Update();
+ end
+end
+
+function RaidFrame_Update()
+ -- If not in a raid hide all the UI and just display raid explanation text
+ if ( GetNumRaidMembers() == 0 ) then
+ RaidFrameConvertToRaidButton:Show();
+ if ( GetPartyMember(1) and IsPartyLeader() and UnitLevel("player") >= 10 and not HasLFGRestrictions() ) then
+ RaidFrameConvertToRaidButton:Enable();
+ else
+ RaidFrameConvertToRaidButton:Disable();
+ end
+ RaidFrameNotInRaid:Show();
+ else
+ RaidFrameConvertToRaidButton:Hide();
+ RaidFrameNotInRaid:Hide();
+ end
+
+ if ( RaidGroupFrame_Update ) then
+ RaidGroupFrame_Update();
+ end
+end
+
+-- Function for raid options
+function RaidOptionsFrame_UpdatePartyFrames()
+ if ( HIDE_PARTY_INTERFACE == "1" and GetNumRaidMembers() > 0) then
+ HidePartyFrame();
+ else
+ HidePartyFrame();
+ ShowPartyFrame();
+ end
+ UpdatePartyMemberBackground();
+end
+
+-- Populates Raid Info Data
+function RaidInfoFrame_Update(scrollToSelected)
+ RaidInfoFrame_UpdateSelectedIndex();
+
+ local scrollFrame = RaidInfoScrollFrame;
+ local savedInstances = GetNumSavedInstances();
+ local instanceName, instanceID, instanceReset, instanceDifficulty, locked, extended, instanceIDMostSig, isRaid, maxPlayers, difficultyName;
+ local frameName, frameNameText, frameID, frameReset, width;
+ local offset = HybridScrollFrame_GetOffset(scrollFrame);
+ local buttons = scrollFrame.buttons;
+ local numButtons = #buttons;
+ local buttonHeight = buttons[1]:GetHeight();
+
+ if ( scrollToSelected == true and RaidInfoFrame.selectedIndex ) then --Using == true in case the HybridScrollFrame .update is changed to pass in the parent.
+ local button = buttons[RaidInfoFrame.selectedIndex - offset]
+ if ( not button or (button:GetTop() > scrollFrame:GetTop()) or (button:GetBottom() < scrollFrame:GetBottom()) ) then
+ local scrollFrame = RaidInfoScrollFrame;
+ local buttonHeight = scrollFrame.buttons[1]:GetHeight();
+ local scrollValue = min(((RaidInfoFrame.selectedIndex - 1) * buttonHeight), scrollFrame.range)
+ if ( scrollValue ~= scrollFrame.scrollBar:GetValue() ) then
+ scrollFrame.scrollBar:SetValue(scrollValue);
+ end
+ end
+ end
+
+ offset = HybridScrollFrame_GetOffset(scrollFrame); --May have changed in the previous section to move selected parts into view.
+
+ local mouseIsOverScrollFrame = scrollFrame:IsVisible() and scrollFrame:IsMouseOver();
+
+ for i=1, numButtons do
+ local frame = buttons[i];
+ local index = i + offset;
+
+ if ( index <= savedInstances) then
+ instanceName, instanceID, instanceReset, instanceDifficulty, locked, extended, instanceIDMostSig, isRaid, maxPlayers, difficultyName = GetSavedInstanceInfo(index);
+
+ frame.instanceID = instanceID;
+ frame.longInstanceID = string.format("%x%x", instanceIDMostSig, instanceID);
+ frame:SetID(index);
+
+ if ( RaidInfoFrame.selectedRaidID == frame.longInstanceID ) then
+ frame:LockHighlight();
+ else
+ frame:UnlockHighlight();
+ end
+
+ frame.difficulty:SetText(difficultyName);
+
+ if ( extended or locked ) then
+ frame.reset:SetText(SecondsToTime(instanceReset, true, nil, 3));
+ frame.name:SetText(instanceName);
+ else
+ frame.reset:SetFormattedText("|cff808080%s|r", RAID_INSTANCE_EXPIRES_EXPIRED);
+ frame.name:SetFormattedText("|cff808080%s|r", instanceName);
+ end
+
+ if ( extended ) then
+ frame.extended:Show();
+ else
+ frame.extended:Hide();
+ end
+
+ frame:Show();
+
+ if ( mouseIsOverScrollFrame and frame:IsMouseOver() ) then
+ RaidInfoInstance_OnEnter(frame);
+ end
+ else
+ frame:Hide();
+ end
+ end
+ HybridScrollFrame_Update(scrollFrame, savedInstances * buttonHeight, scrollFrame:GetHeight());
+end
+
+function RaidInfoScrollFrame_OnLoad(self)
+ HybridScrollFrame_OnLoad(self);
+ self.update = RaidInfoFrame_Update;
+ HybridScrollFrame_CreateButtons(self, "RaidInfoInstanceTemplate");
+end
+
+--Makes the button look likes it's being pressed
+function RaidInfoInstance_OnMouseDown(self)
+ self.name:SetPoint("TOPLEFT", 7, -12);
+ self.reset:SetPoint("TOPRIGHT", 2, -13);
+end
+
+function RaidInfoInstance_OnMouseUp(self)
+ self.name:SetPoint("TOPLEFT", 5, -10);
+ self.reset:SetPoint("TOPRIGHT", 0, -11);
+end
+
+function RaidInfoInstance_OnClick(self)
+ RaidInfoFrame.selectedRaidID = self.longInstanceID;
+ RaidInfoFrame_Update();
+end
+
+function RaidInfoInstance_OnEnter(self)
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.name:GetText());
+ GameTooltip:AddLine(self.difficulty:GetText(), HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:AddLine(format(INSTANCE_ID, self.instanceID), HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b);
+ GameTooltip:Show();
+end
+
+function RaidInfoFrame_UpdateSelectedIndex()
+ local savedInstances = GetNumSavedInstances();
+ for index=1, savedInstances do
+ local instanceName, instanceID, instanceReset, instanceDifficulty, locked, extended, instanceIDMostSig = GetSavedInstanceInfo(index);
+ if ( format("%x%x", instanceIDMostSig, instanceID) == RaidInfoFrame.selectedRaidID ) then
+ RaidInfoFrame.selectedIndex = index;
+ RaidInfoExtendButton:Enable();
+ if ( extended ) then
+ RaidInfoExtendButton.doExtend = false;
+ RaidInfoExtendButton:SetText(UNEXTEND_RAID_LOCK);
+ else
+ RaidInfoExtendButton.doExtend = true;
+ if ( locked ) then
+ RaidInfoExtendButton:SetText(EXTEND_RAID_LOCK);
+ else
+ RaidInfoExtendButton:SetText(REACTIVATE_RAID_LOCK);
+ end
+ end
+ return;
+ end
+ end
+ RaidInfoFrame.selectedIndex = nil;
+ RaidInfoExtendButton:Disable();
+end
+
+function RaidInfoExtendButton_OnClick(self)
+ SetSavedInstanceExtend(RaidInfoFrame.selectedIndex, self.doExtend);
+ RequestRaidInfo();
+ RaidInfoFrame_Update();
+end
diff --git a/reference/FrameXML/RaidFrame.xml b/reference/FrameXML/RaidFrame.xml
new file mode 100644
index 0000000..1dcad7b
--- /dev/null
+++ b/reference/FrameXML/RaidFrame.xml
@@ -0,0 +1,477 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaidInfoInstance_OnMouseDown(self);
+
+
+ RaidInfoInstance_OnMouseUp(self);
+
+
+ RaidInfoInstance_OnClick(self);
+
+
+ RaidInfoInstance_OnEnter(self);
+
+
+ GameTooltip:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ShowUIPanel(LFRParentFrame);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if ( RaidInfoFrame:IsShown() ) then
+ RaidInfoFrame:Hide();
+ else
+ RaidInfoFrame:Show();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.text:SetText(INSTANCE);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self.text:SetText(LOCK_EXPIRE);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ local parent = self:GetParent();
+ parent:SetWidth(295);
+ RaidInfoInstanceLabel:SetWidth(143);
+ for _, frame in pairs(parent.buttons) do
+ frame:SetWidth(275);
+ frame.name:SetWidth(120);
+ end
+
+
+ local parent = self:GetParent();
+ parent:SetWidth(310);
+ RaidInfoInstanceLabel:SetWidth(173);
+ for _, frame in pairs(parent.buttons) do
+ frame:SetWidth(305);
+ frame.name:SetWidth(150);
+ end
+
+
+
+
+
+
+
+ RaidInfoFrame_Update()
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaidInfoFrame:Hide();
+
+
+
+
+
+
+
+
+
+ if (GetNumRaidMembers() > 0 ) then
+ RaidInfoFrame:SetPoint("TOPLEFT", "RaidFrame", "TOPRIGHT", -13, -28);
+ else
+ RaidInfoFrame:SetPoint("TOPLEFT", "RaidFrame", "TOPRIGHT", -33, -28);
+ end
+ PlaySound("UChatScrollButton");
+
+
+ PlaySound("UChatScrollButton");
+
+
+
+
+
+
+
+ RaidFrame_Update();
+ RequestRaidInfo();
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/RaidWarning.lua b/reference/FrameXML/RaidWarning.lua
new file mode 100644
index 0000000..67fa133
--- /dev/null
+++ b/reference/FrameXML/RaidWarning.lua
@@ -0,0 +1,139 @@
+
+function RaidNotice_FadeInit( slotFrame )
+ FadingFrame_OnLoad(slotFrame);
+ FadingFrame_SetFadeInTime(slotFrame, 0.2);
+ FadingFrame_SetHoldTime(slotFrame, 10.0);
+ FadingFrame_SetFadeOutTime(slotFrame, 3.0);
+end
+
+function RaidNotice_AddMessage( noticeFrame, textString, colorInfo )
+ if ( not noticeFrame or not noticeFrame.slot1 or not noticeFrame.slot2 or not textString ) then
+ return;
+ end
+
+ noticeFrame:Show();
+ if ( not noticeFrame.slot1:IsShown() ) then
+ noticeFrame.slot1_text = textString;
+ RaidNotice_SetSlot( noticeFrame.slot1, noticeFrame.slot1_text, colorInfo, noticeFrame.timings["RAID_NOTICE_MIN_HEIGHT"] );
+ noticeFrame.slot1.scrollTime = 0;
+ else
+ if ( noticeFrame.slot2:IsShown() ) then
+ noticeFrame.slot1_text = noticeFrame.slot2_text;
+ RaidNotice_SetSlot( noticeFrame.slot1, noticeFrame.slot1_text, colorInfo, noticeFrame.timings["RAID_NOTICE_MIN_HEIGHT"] );
+ noticeFrame.slot1.scrollTime = noticeFrame.slot2.scrollTime;
+ end
+
+ noticeFrame.slot2_text = textString;
+ RaidNotice_SetSlot( noticeFrame.slot2, noticeFrame.slot2_text, colorInfo, noticeFrame.timings["RAID_NOTICE_MIN_HEIGHT"] );
+ noticeFrame.slot2.scrollTime = 0;
+ end
+end
+
+function RaidNotice_SetSlot( slotFrame, textString, colorInfo, minHeight )
+ slotFrame:SetText( textString );
+ slotFrame:SetTextColor( colorInfo.r, colorInfo.g, colorInfo.b, 1.0 )
+ slotFrame:SetTextHeight(minHeight);
+ FadingFrame_Show( slotFrame );
+end
+
+local RaidNotice_unused = false;
+function RaidNotice_OnUpdate( noticeFrame, elapsedTime )
+ if ( not noticeFrame or not noticeFrame.slot1 or not noticeFrame.slot2 ) then
+ return;
+ end
+
+ RaidNotice_unused = true;
+ if ( noticeFrame.slot1:IsShown() ) then
+ RaidNotice_UpdateSlot( noticeFrame.slot1, noticeFrame.timings, elapsedTime );
+ RaidNotice_unused = false;
+ end
+
+ if ( noticeFrame.slot2:IsShown() ) then
+ RaidNotice_UpdateSlot( noticeFrame.slot2, noticeFrame.timings, elapsedTime );
+ RaidNotice_unused = false;
+ end
+
+ if ( RaidNotice_unused ) then
+ noticeFrame:Hide();
+ end
+end
+
+function RaidNotice_UpdateSlot( slotFrame, timings, elapsedTime )
+ if ( slotFrame.scrollTime ) then
+ slotFrame.scrollTime = slotFrame.scrollTime + elapsedTime;
+ if ( slotFrame.scrollTime <= timings["RAID_NOTICE_SCALE_UP_TIME"] ) then
+ slotFrame:SetTextHeight(floor(timings["RAID_NOTICE_MIN_HEIGHT"]+((timings["RAID_NOTICE_MAX_HEIGHT"]-timings["RAID_NOTICE_MIN_HEIGHT"])*slotFrame.scrollTime/timings["RAID_NOTICE_SCALE_UP_TIME"])));
+ elseif ( slotFrame.scrollTime <= timings["RAID_NOTICE_SCALE_DOWN_TIME"] ) then
+ slotFrame:SetTextHeight(floor(timings["RAID_NOTICE_MAX_HEIGHT"] - ((timings["RAID_NOTICE_MAX_HEIGHT"]-timings["RAID_NOTICE_MIN_HEIGHT"])*(slotFrame.scrollTime - timings["RAID_NOTICE_SCALE_UP_TIME"])/(timings["RAID_NOTICE_SCALE_DOWN_TIME"] - timings["RAID_NOTICE_SCALE_UP_TIME"]))));
+ else
+ slotFrame:SetTextHeight(timings["RAID_NOTICE_MIN_HEIGHT"]);
+ slotFrame.scrollTime = nil;
+ end
+ end
+ FadingFrame_OnUpdate(slotFrame);
+end
+
+
+
+
+
+----------- RAID WARNING
+function RaidWarningFrame_OnLoad(self)
+ self:RegisterEvent("CHAT_MSG_RAID_WARNING");
+ self.slot1 = RaidWarningFrameSlot1;
+ self.slot2 = RaidWarningFrameSlot2;
+ RaidNotice_FadeInit( self.slot1 );
+ RaidNotice_FadeInit( self.slot2 );
+ self.timings = { };
+ self.timings["RAID_NOTICE_MIN_HEIGHT"] = 20.0;
+ self.timings["RAID_NOTICE_MAX_HEIGHT"] = 30.0;
+ self.timings["RAID_NOTICE_SCALE_UP_TIME"] = 0.2;
+ self.timings["RAID_NOTICE_SCALE_DOWN_TIME"] = 0.4;
+end
+
+function RaidWarningFrame_OnEvent(self, event, message)
+ if ( event == "CHAT_MSG_RAID_WARNING" ) then
+
+ --Task 21207: Add the ability to link raid icons to other players
+ local term;
+ for tag in string.gmatch(message, "%b{}") do
+ term = strlower(string.gsub(tag, "[{}]", ""));
+ if ( ICON_TAG_LIST[term] and ICON_LIST[ICON_TAG_LIST[term]] ) then
+ -- Using 0 as the height to make the texture match the font height
+ message = string.gsub(message, tag, ICON_LIST[ICON_TAG_LIST[term]] .. "0|t");
+ end
+ end
+
+ RaidNotice_AddMessage( self, message, ChatTypeInfo["RAID_WARNING"] );
+ PlaySound("RaidWarning");
+ end
+end
+
+
+----------- BOSS EMOTE
+function RaidBossEmoteFrame_OnLoad(self)
+ self.slot1 = RaidBossEmoteFrameSlot1;
+ self.slot2 = RaidBossEmoteFrameSlot2;
+ RaidNotice_FadeInit(self.slot1);
+ RaidNotice_FadeInit(self.slot2);
+ self.timings = { };
+ self.timings["RAID_NOTICE_MIN_HEIGHT"] = 20.0;
+ self.timings["RAID_NOTICE_MAX_HEIGHT"] = 30.0;
+ self.timings["RAID_NOTICE_SCALE_UP_TIME"] = 0.2;
+ self.timings["RAID_NOTICE_SCALE_DOWN_TIME"] = 0.4;
+
+ self:RegisterEvent("CHAT_MSG_RAID_BOSS_EMOTE");
+ self:RegisterEvent("CHAT_MSG_RAID_BOSS_WHISPER");
+end
+
+function RaidBossEmoteFrame_OnEvent(self, event, ...)
+ local arg1, arg2 = ...;
+ if ( strsub(event,10,18) == "RAID_BOSS" ) then
+ local mtype = strsub(event,10);
+ local body = format(_G["CHAT_"..mtype.."_GET"]..arg1, arg2, arg2); --No need for pflag, monsters can't be afk, dnd, or GMs.
+ local info = ChatTypeInfo[mtype];
+ RaidNotice_AddMessage( RaidBossEmoteFrame, body, info );
+-- RaidNotice_AddMessage( RaidBossEmoteFrame, "This is a TEST of the MESSAGE!", ChatTypeInfo["RAID_BOSS_EMOTE"] );
+ PlaySound("RaidBossEmoteWarning");
+ end
+end
\ No newline at end of file
diff --git a/reference/FrameXML/RaidWarning.xml b/reference/FrameXML/RaidWarning.xml
new file mode 100644
index 0000000..71a3891
--- /dev/null
+++ b/reference/FrameXML/RaidWarning.xml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/RatingMenuFrame.xml b/reference/FrameXML/RatingMenuFrame.xml
new file mode 100644
index 0000000..2103dca
--- /dev/null
+++ b/reference/FrameXML/RatingMenuFrame.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PlaySound("gsTitleOptionExit");
+ HideUIPanel(RatingMenuFrame);
+
+
+
+
+
+
+ ShowUIPanel(GameMenuFrame);
+ UpdateMicroButtons();
+
+
+ if ( GetBindingFromClick(key) == "TOGGLEGAMEMENU" ) then
+ PlaySound("gsTitleOptionExit");
+ HideUIPanel(RatingMenuFrame);
+ MacOptionsFrame_Cancel();
+ elseif ( GetBindingFromClick(key) == "SCREENSHOT" ) then
+ RunBinding("SCREENSHOT");
+ end
+
+
+
+
diff --git a/reference/FrameXML/ReadyCheck.lua b/reference/FrameXML/ReadyCheck.lua
new file mode 100644
index 0000000..c4ac1a7
--- /dev/null
+++ b/reference/FrameXML/ReadyCheck.lua
@@ -0,0 +1,113 @@
+READY_CHECK_WAITING_TEXTURE = "Interface\\RaidFrame\\ReadyCheck-Waiting";
+READY_CHECK_READY_TEXTURE = "Interface\\RaidFrame\\ReadyCheck-Ready";
+READY_CHECK_NOT_READY_TEXTURE = "Interface\\RaidFrame\\ReadyCheck-NotReady";
+READY_CHECK_AFK_TEXTURE = "Interface\\RaidFrame\\ReadyCheck-NotReady";
+
+
+--
+-- ReadyCheckFrame
+--
+
+function ShowReadyCheck(initiator, timeLeft)
+ ReadyCheckFrame.initiator = initiator;
+ if ( initiator ) then
+ ReadyCheckFrame:Show();
+ if ( UnitIsUnit("player", initiator) ) then
+ ReadyCheckListenerFrame:Hide();
+ else
+ SetPortraitTexture(ReadyCheckPortrait, initiator);
+ ReadyCheckFrameText:SetFormattedText(READY_CHECK_MESSAGE, initiator);
+ ReadyCheckListenerFrame:Show();
+ end
+ end
+end
+
+function ReadyCheckFrame_OnLoad(self)
+ self:RegisterEvent("READY_CHECK");
+ self:RegisterEvent("READY_CHECK_FINISHED");
+end
+
+function ReadyCheckFrame_OnEvent(self, event, ...)
+ if ( event == "READY_CHECK" ) then
+ ShowReadyCheck(...);
+ elseif ( event == "READY_CHECK_FINISHED" ) then
+ local preempted = ...;
+ if ( not preempted and self.initiator and not UnitIsUnit("player", self.initiator) ) then
+ local info = ChatTypeInfo["SYSTEM"];
+ DEFAULT_CHAT_FRAME:AddMessage(READY_CHECK_YOU_WERE_AFK, info.r, info.g, info.b, info.id);
+ end
+ self:Hide();
+ end
+end
+
+function ReadyCheckFrame_OnHide(self)
+ self.initiator = nil;
+end
+
+
+--
+-- ReadyCheck unit frame functions
+--
+
+function ReadyCheck_Start(readyCheckFrame)
+ readyCheckFrame:SetScript("OnUpdate", nil);
+
+ _G[readyCheckFrame:GetName().."Texture"]:SetTexture(READY_CHECK_WAITING_TEXTURE);
+ readyCheckFrame.state = "waiting";
+ readyCheckFrame:SetAlpha(1);
+ readyCheckFrame:Show();
+end
+
+function ReadyCheck_Confirm(readyCheckFrame, ready)
+ readyCheckFrame:SetScript("OnUpdate", nil);
+
+ if ( ready == 1 ) then
+ _G[readyCheckFrame:GetName().."Texture"]:SetTexture(READY_CHECK_READY_TEXTURE);
+ readyCheckFrame.state = "ready";
+ else
+ _G[readyCheckFrame:GetName().."Texture"]:SetTexture(READY_CHECK_NOT_READY_TEXTURE);
+ readyCheckFrame.state = "notready";
+ end
+ readyCheckFrame:SetAlpha(1);
+ readyCheckFrame:Show();
+end
+
+function ReadyCheck_Finish(readyCheckFrame, fadeTime, onFinishFunc, onFinishFuncArg)
+ if ( readyCheckFrame.state == "waiting" ) then
+ _G[readyCheckFrame:GetName().."Texture"]:SetTexture(READY_CHECK_AFK_TEXTURE);
+ readyCheckFrame.state = "afk";
+ end
+
+ readyCheckFrame:SetScript("OnUpdate", ReadyCheck_OnUpdate);
+ readyCheckFrame.finishedTimer = 10;
+ if ( fadeTime ) then
+ readyCheckFrame.fadeTimer = fadeTime;
+ else
+ readyCheckFrame.fadeTimer = 1.5;
+ end
+ readyCheckFrame.onFinishFunc = onFinishFunc;
+ readyCheckFrame.onFinishFuncArg = onFinishFuncArg;
+end
+
+function ReadyCheck_OnUpdate(readyCheckFrame, elapsed)
+ if ( readyCheckFrame.finishedTimer ) then
+ readyCheckFrame.finishedTimer = readyCheckFrame.finishedTimer - elapsed;
+ if ( readyCheckFrame.finishedTimer <= 0 ) then
+ readyCheckFrame.finishedTimer = nil;
+ end
+ elseif ( readyCheckFrame.fadeTimer ) then
+ readyCheckFrame.fadeTimer = readyCheckFrame.fadeTimer - elapsed;
+ readyCheckFrame:SetAlpha(readyCheckFrame.fadeTimer / 1.5);
+ if ( readyCheckFrame.fadeTimer <= 0 ) then
+ readyCheckFrame.fadeTimer = nil;
+ readyCheckFrame:Hide();
+ readyCheckFrame:SetScript("OnUpdate", nil);
+ readyCheckFrame.state = nil;
+ if ( readyCheckFrame.onFinishFunc ) then
+ readyCheckFrame.onFinishFunc(readyCheckFrame.onFinishFuncArg);
+ readyCheckFrame.onFinishFunc = nil;
+ readyCheckFrame.onFinishFuncArg = nil;
+ end
+ end
+ end
+end
diff --git a/reference/FrameXML/ReadyCheck.xml b/reference/FrameXML/ReadyCheck.xml
new file mode 100644
index 0000000..44d4316
--- /dev/null
+++ b/reference/FrameXML/ReadyCheck.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ConfirmReadyCheck(1);
+ ReadyCheckFrame:Hide();
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ConfirmReadyCheck();
+ ReadyCheckFrame:Hide();
+
+
+
+
+
+
+ PlaySound("ReadyCheck");
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/ReputationFrame.lua b/reference/FrameXML/ReputationFrame.lua
new file mode 100644
index 0000000..14e0f20
--- /dev/null
+++ b/reference/FrameXML/ReputationFrame.lua
@@ -0,0 +1,439 @@
+
+NUM_FACTIONS_DISPLAYED = 15;
+REPUTATIONFRAME_FACTIONHEIGHT = 26;
+FACTION_BAR_COLORS = {
+ [1] = {r = 0.8, g = 0.3, b = 0.22},
+ [2] = {r = 0.8, g = 0.3, b = 0.22},
+ [3] = {r = 0.75, g = 0.27, b = 0},
+ [4] = {r = 0.9, g = 0.7, b = 0},
+ [5] = {r = 0, g = 0.6, b = 0.1},
+ [6] = {r = 0, g = 0.6, b = 0.1},
+ [7] = {r = 0, g = 0.6, b = 0.1},
+ [8] = {r = 0, g = 0.6, b = 0.1},
+};
+-- Hard coded =(, will need to add entries for each expansion
+MAX_PLAYER_LEVEL_TABLE = {};
+MAX_PLAYER_LEVEL_TABLE[0] = 60;
+MAX_PLAYER_LEVEL_TABLE[1] = 70;
+MAX_PLAYER_LEVEL_TABLE[2] = 80;
+MAX_PLAYER_LEVEL = 0;
+REPUTATIONFRAME_ROWSPACING = 23;
+
+function ReputationFrame_OnLoad(self)
+ self:RegisterEvent("UPDATE_FACTION");
+ -- Initialize max player level
+ MAX_PLAYER_LEVEL = MAX_PLAYER_LEVEL_TABLE[GetAccountExpansionLevel()];
+ --[[for i=1, NUM_FACTIONS_DISPLAYED, 1 do
+ _G["ReputationBar"..i.."FactionStanding"]:SetPoint("CENTER",_G["ReputationBar"..i.."ReputationBar"]);
+ end
+ --]]
+end
+
+function ReputationFrame_OnShow()
+ ReputationFrame_Update();
+end
+
+function ReputationFrame_OnEvent(self, event, ...)
+ if ( event == "UPDATE_FACTION" ) then
+ if ( self:IsVisible() ) then
+ ReputationFrame_Update();
+ end
+ end
+end
+
+function ReputationFrame_SetRowType(factionRow, rowType, hasRep) --rowType is a binary table of type isHeader, isChild
+ local factionRowName = factionRow:GetName()
+ local factionBar = _G[factionRowName.."ReputationBar"];
+ local factionTitle = _G[factionRowName.."FactionName"];
+ local factionButton = _G[factionRowName.."ExpandOrCollapseButton"];
+ local factionStanding = _G[factionRowName.."ReputationBarFactionStanding"];
+ local factionBackground = _G[factionRowName.."Background"];
+ local factionLeftTexture = _G[factionRowName.."ReputationBarLeftTexture"];
+ local factionRightTexture = _G[factionRowName.."ReputationBarRightTexture"];
+ factionLeftTexture:SetWidth(62);
+ factionRightTexture:SetWidth(42);
+ factionBar:SetPoint("RIGHT", factionRow, "RIGHT", 0, 0);
+ if ( rowType == 0 ) then --Not header, not child
+ factionRow:SetPoint("LEFT", ReputationFrame, "LEFT", 44, 0);
+ factionButton:Hide();
+ factionTitle:SetPoint("LEFT", factionRow, "LEFT", 10, 0);
+ factionTitle:SetFontObject(GameFontHighlightSmall);
+ factionTitle:SetWidth(160);
+ factionBackground:Show();
+ factionLeftTexture:SetHeight(21);
+ factionRightTexture:SetHeight(21);
+ factionLeftTexture:SetTexCoord(0.7578125, 1.0, 0.0, 0.328125);
+ factionRightTexture:SetTexCoord(0.0, 0.1640625, 0.34375, 0.671875);
+ factionBar:SetWidth(101)
+ elseif ( rowType == 1 ) then --Child, not header
+ factionRow:SetPoint("LEFT", ReputationFrame, "LEFT", 62, 0);
+ factionButton:Hide()
+ factionTitle:SetPoint("LEFT", factionRow, "LEFT", 10, 0);
+ factionTitle:SetFontObject(GameFontHighlightSmall);
+ factionTitle:SetWidth(150);
+ factionBackground:Show();
+ factionLeftTexture:SetHeight(21);
+ factionRightTexture:SetHeight(21);
+ factionLeftTexture:SetTexCoord(0.7578125, 1.0, 0.0, 0.328125);
+ factionRightTexture:SetTexCoord(0.0, 0.1640625, 0.34375, 0.671875);
+ factionBar:SetWidth(101)
+ elseif ( rowType == 2 ) then --Header, not child
+ factionRow:SetPoint("LEFT", ReputationFrame, "LEFT", 20, 0);
+ factionButton:SetPoint("LEFT", factionRow, "LEFT", 3, 0);
+ factionButton:Show();
+ factionTitle:SetPoint("LEFT",factionButton,"RIGHT",10,0);
+ factionTitle:SetFontObject(GameFontNormalLeft);
+ factionTitle:SetWidth(145);
+ factionBackground:Hide()
+ factionLeftTexture:SetHeight(15);
+ factionLeftTexture:SetWidth(60);
+ factionRightTexture:SetHeight(15);
+ factionRightTexture:SetWidth(39);
+ factionLeftTexture:SetTexCoord(0.765625, 1.0, 0.046875, 0.28125);
+ factionRightTexture:SetTexCoord(0.0, 0.15234375, 0.390625, 0.625);
+ factionBar:SetWidth(99);
+ elseif ( rowType == 3 ) then --Header and child
+ factionRow:SetPoint("LEFT", ReputationFrame, "LEFT", 39, 0);
+ factionButton:SetPoint("LEFT", factionRow, "LEFT", 3, 0);
+ factionButton:Show();
+ factionTitle:SetPoint("LEFT" ,factionButton, "RIGHT", 10, 0);
+ factionTitle:SetFontObject(GameFontNormalLeft);
+ factionTitle:SetWidth(135);
+ factionBackground:Hide()
+ factionLeftTexture:SetHeight(15);
+ factionLeftTexture:SetWidth(60);
+ factionRightTexture:SetHeight(15);
+ factionRightTexture:SetWidth(39);
+ factionLeftTexture:SetTexCoord(0.765625, 1.0, 0.046875, 0.28125);
+ factionRightTexture:SetTexCoord(0.0, 0.15234375, 0.390625, 0.625);
+ factionBar:SetWidth(99);
+ end
+
+ if ( (hasRep) or (rowType == 0) or (rowType == 1)) then
+ factionStanding:Show();
+ factionBar:Show();
+ factionBar:GetParent().hasRep = true;
+ else
+ factionStanding:Hide();
+ factionBar:Hide();
+ factionBar:GetParent().hasRep = false;
+ end
+end
+
+function ReputationFrame_Update()
+ local numFactions = GetNumFactions();
+ local factionIndex, factionRow, factionTitle, factionStanding, factionBar, factionButton, factionLeftLine, factionBottomLine, factionBackground, color, tooltipStanding;
+ local name, description, standingID, barMin, barMax, barValue, atWarWith, canToggleAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild;
+ local atWarIndicator, rightBarTexture;
+
+ local previousBigTexture = ReputationFrameTopTreeTexture; --In case we have a line going off the panel to the top
+ previousBigTexture:Hide();
+ local previousBigTexture2 = ReputationFrameTopTreeTexture2;
+ previousBigTexture2:Hide();
+
+ -- Update scroll frame
+ if ( not FauxScrollFrame_Update(ReputationListScrollFrame, numFactions, NUM_FACTIONS_DISPLAYED, REPUTATIONFRAME_FACTIONHEIGHT ) ) then
+ ReputationListScrollFrameScrollBar:SetValue(0);
+ end
+ local factionOffset = FauxScrollFrame_GetOffset(ReputationListScrollFrame);
+
+ local gender = UnitSex("player");
+
+ local i;
+
+ local offScreenFudgeFactor = 5;
+ local previousBigTextureRows = 0;
+ local previousBigTextureRows2 = 0;
+ for i=1, NUM_FACTIONS_DISPLAYED, 1 do
+ factionIndex = factionOffset + i;
+ factionRow = _G["ReputationBar"..i];
+ factionBar = _G["ReputationBar"..i.."ReputationBar"];
+ factionTitle = _G["ReputationBar"..i.."FactionName"];
+ factionButton = _G["ReputationBar"..i.."ExpandOrCollapseButton"];
+ factionLeftLine = _G["ReputationBar"..i.."LeftLine"];
+ factionBottomLine = _G["ReputationBar"..i.."BottomLine"];
+ factionStanding = _G["ReputationBar"..i.."ReputationBarFactionStanding"];
+ factionBackground = _G["ReputationBar"..i.."Background"];
+ if ( factionIndex <= numFactions ) then
+ name, description, standingID, barMin, barMax, barValue, atWarWith, canToggleAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild = GetFactionInfo(factionIndex);
+ factionTitle:SetText(name);
+ if ( isCollapsed ) then
+ factionButton:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up");
+ else
+ factionButton:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up");
+ end
+ factionRow.index = factionIndex;
+ factionRow.isCollapsed = isCollapsed;
+ local factionStandingtext = GetText("FACTION_STANDING_LABEL"..standingID, gender);
+ factionStanding:SetText(factionStandingtext);
+
+ --Normalize Values
+ barMax = barMax - barMin;
+ barValue = barValue - barMin;
+ barMin = 0;
+
+ factionRow.standingText = factionStandingtext;
+ factionRow.tooltip = HIGHLIGHT_FONT_COLOR_CODE.." "..barValue.." / "..barMax..FONT_COLOR_CODE_CLOSE;
+ factionBar:SetMinMaxValues(0, barMax);
+ factionBar:SetValue(barValue);
+ local color = FACTION_BAR_COLORS[standingID];
+ factionBar:SetStatusBarColor(color.r, color.g, color.b);
+
+ if ( isHeader and not isChild ) then
+ factionLeftLine:SetTexCoord(0, 0.25, 0, 2);
+ factionBottomLine:Hide();
+ factionLeftLine:Hide();
+ if ( previousBigTextureRows == 0 ) then
+ previousBigTexture:Hide();
+ end
+ previousBigTexture = factionBottomLine;
+ previousBigTextureRows = 0;
+ elseif ( isHeader and isChild ) then
+ ReputationBar_DrawHorizontalLine(factionLeftLine, 11, factionButton);
+ if ( previousBigTexture2 and previousBigTextureRows2 == 0 ) then
+ previousBigTexture2:Hide();
+ end
+ factionBottomLine:Hide();
+ previousBigTexture2 = factionBottomLine;
+ previousBigTextureRows2 = 0;
+ previousBigTextureRows = previousBigTextureRows+1;
+ ReputationBar_DrawVerticalLine(previousBigTexture, previousBigTextureRows);
+
+ elseif ( isChild ) then
+ ReputationBar_DrawHorizontalLine(factionLeftLine, 11, factionBackground);
+ factionBottomLine:Hide();
+ previousBigTextureRows = previousBigTextureRows+1;
+ previousBigTextureRows2 = previousBigTextureRows2+1;
+ ReputationBar_DrawVerticalLine(previousBigTexture2, previousBigTextureRows2);
+ else
+ -- is immediately under a main category
+ ReputationBar_DrawHorizontalLine(factionLeftLine, 13, factionBackground);
+ factionBottomLine:Hide();
+ previousBigTextureRows = previousBigTextureRows+1;
+ ReputationBar_DrawVerticalLine(previousBigTexture, previousBigTextureRows);
+ end
+
+ ReputationFrame_SetRowType(factionRow, ((isChild and 1 or 0) + (isHeader and 2 or 0)), hasRep);
+
+ factionRow:Show();
+
+ -- Update details if this is the selected faction
+ if ( atWarWith ) then
+ _G["ReputationBar"..i.."ReputationBarAtWarHighlight1"]:Show();
+ _G["ReputationBar"..i.."ReputationBarAtWarHighlight2"]:Show();
+ else
+ _G["ReputationBar"..i.."ReputationBarAtWarHighlight1"]:Hide();
+ _G["ReputationBar"..i.."ReputationBarAtWarHighlight2"]:Hide();
+ end
+ if ( factionIndex == GetSelectedFaction() ) then
+ if ( ReputationDetailFrame:IsShown() ) then
+ ReputationDetailFactionName:SetText(name);
+ ReputationDetailFactionDescription:SetText(description);
+ if ( atWarWith ) then
+ ReputationDetailAtWarCheckBox:SetChecked(1);
+ else
+ ReputationDetailAtWarCheckBox:SetChecked(nil);
+ end
+ if ( canToggleAtWar and (not isHeader)) then
+ ReputationDetailAtWarCheckBox:Enable();
+ ReputationDetailAtWarCheckBoxText:SetTextColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+ else
+ ReputationDetailAtWarCheckBox:Disable();
+ ReputationDetailAtWarCheckBoxText:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+ if ( not isHeader ) then
+ ReputationDetailInactiveCheckBox:Enable();
+ ReputationDetailInactiveCheckBoxText:SetTextColor(ReputationDetailInactiveCheckBoxText:GetFontObject():GetTextColor());
+ else
+ ReputationDetailInactiveCheckBox:Disable();
+ ReputationDetailInactiveCheckBoxText:SetTextColor(GRAY_FONT_COLOR.r, GRAY_FONT_COLOR.g, GRAY_FONT_COLOR.b);
+ end
+ if ( IsFactionInactive(factionIndex) ) then
+ ReputationDetailInactiveCheckBox:SetChecked(1);
+ else
+ ReputationDetailInactiveCheckBox:SetChecked(nil);
+ end
+ if ( isWatched ) then
+ ReputationDetailMainScreenCheckBox:SetChecked(1);
+ else
+ ReputationDetailMainScreenCheckBox:SetChecked(nil);
+ end
+ _G["ReputationBar"..i.."ReputationBarHighlight1"]:Show();
+ _G["ReputationBar"..i.."ReputationBarHighlight2"]:Show();
+ end
+ else
+ _G["ReputationBar"..i.."ReputationBarHighlight1"]:Hide();
+ _G["ReputationBar"..i.."ReputationBarHighlight2"]:Hide();
+ end
+ else
+ factionRow:Hide();
+ end
+ end
+ if ( GetSelectedFaction() == 0 ) then
+ ReputationDetailFrame:Hide();
+ end
+
+ local i = NUM_
+ for i = (NUM_FACTIONS_DISPLAYED + factionOffset + 1), numFactions, 1 do
+ local name, description, standingID, barMin, barMax, barValue, atWarWith, canToggleAtWar, isHeader, isCollapsed, hasRep, isWatched, isChild = GetFactionInfo(i);
+ if not name then break; end
+
+ if ( isHeader and not isChild ) then
+ break;
+ elseif ( (isHeader and isChild) or not(isHeader or isChild) ) then
+ ReputationBar_DrawVerticalLine(previousBigTexture, previousBigTextureRows+1);
+ break;
+ elseif ( isChild ) then
+ ReputationBar_DrawVerticalLine(previousBigTexture2, previousBigTextureRows2+1);
+ break;
+ end
+ end
+end
+
+function ReputationBar_DrawVerticalLine(texture, rows)
+ -- Need to add this fudge factor because the lines are anchored to the top of the screen in this case, not another button
+ local fudgeFactor = 0;
+ if ( texture == ReputationFrameTopTreeTexture or texture == ReputationFrameTopTreeTexture2) then
+ fudgeFactor = 5;
+ end
+ texture:SetHeight(rows*REPUTATIONFRAME_ROWSPACING-fudgeFactor);
+ texture:SetTexCoord(0, 0.25, 0, texture:GetHeight()/2);
+ texture:Show();
+end
+
+function ReputationBar_DrawHorizontalLine(texture, width, anchorTo)
+ texture:SetPoint("RIGHT", anchorTo, "LEFT", 3, 0);
+ texture:SetWidth(width);
+ texture:SetTexCoord(0, width/2, 0, 0.25);
+ texture:Show();
+end
+
+function ReputationBar_OnClick(self)
+ if ( ReputationDetailFrame:IsShown() and (GetSelectedFaction() == self.index) ) then
+ ReputationDetailFrame:Hide();
+ else
+ if ( self.hasRep ) then
+ SetSelectedFaction(self.index);
+ ReputationDetailFrame:Show();
+ ReputationFrame_Update();
+ end
+ end
+end
+
+function ReputationWatchBar_Update(newLevel)
+ local name, reaction, min, max, value = GetWatchedFactionInfo();
+ local visibilityChanged = nil;
+ if ( not newLevel ) then
+ newLevel = UnitLevel("player");
+ end
+ if ( name ) then
+ -- See if it was already shown or not
+ if ( not ReputationWatchBar:IsShown() ) then
+ visibilityChanged = 1;
+ end
+
+ -- Normalize values
+ max = max - min;
+ value = value - min;
+ min = 0;
+ ReputationWatchStatusBar:SetMinMaxValues(min, max);
+ ReputationWatchStatusBar:SetValue(value);
+ ReputationWatchStatusBarText:SetText(name.." "..value.." / "..max);
+ local color = FACTION_BAR_COLORS[reaction];
+ ReputationWatchStatusBar:SetStatusBarColor(color.r, color.g, color.b);
+ ReputationWatchBar:Show();
+
+ -- If the player is max level then replace the xp bar with the watched reputation, otherwise stack the reputation watch bar on top of the xp bar
+ ReputationWatchStatusBar:SetFrameLevel(MainMenuBarArtFrame:GetFrameLevel()-1);
+ if ( newLevel < MAX_PLAYER_LEVEL and not IsXPUserDisabled() ) then
+ -- Reconfigure reputation bar
+ ReputationWatchStatusBar:SetHeight(8);
+ ReputationWatchBar:ClearAllPoints();
+ ReputationWatchBar:SetPoint("BOTTOM", MainMenuBar, "TOP", 0, -3);
+ ReputationWatchStatusBarText:SetPoint("CENTER", ReputationWatchBarOverlayFrame, "CENTER", 0, 3);
+ ReputationWatchBarTexture0:Show();
+ ReputationWatchBarTexture1:Show();
+ ReputationWatchBarTexture2:Show();
+ ReputationWatchBarTexture3:Show();
+
+ ReputationXPBarTexture0:Hide();
+ ReputationXPBarTexture1:Hide();
+ ReputationXPBarTexture2:Hide();
+ ReputationXPBarTexture3:Hide();
+
+ -- Show the XP bar
+ MainMenuExpBar:Show();
+ MainMenuExpBar.pauseUpdates = nil;
+ -- Hide max level bar
+ MainMenuBarMaxLevelBar:Hide();
+ else
+ -- Replace xp bar
+ ReputationWatchStatusBar:SetHeight(13);
+ ReputationWatchBar:ClearAllPoints();
+ ReputationWatchBar:SetPoint("TOP", MainMenuBar, "TOP", 0, 0);
+ ReputationWatchStatusBarText:SetPoint("CENTER", ReputationWatchBarOverlayFrame, "CENTER", 0, 1);
+ ReputationWatchBarTexture0:Hide();
+ ReputationWatchBarTexture1:Hide();
+ ReputationWatchBarTexture2:Hide();
+ ReputationWatchBarTexture3:Hide();
+
+ ReputationXPBarTexture0:Show();
+ ReputationXPBarTexture1:Show();
+ ReputationXPBarTexture2:Show();
+ ReputationXPBarTexture3:Show();
+
+ ExhaustionTick:Hide();
+
+ -- Hide the XP bar
+ MainMenuExpBar:Hide();
+ MainMenuExpBar.pauseUpdates = true;
+ -- Hide max level bar
+ MainMenuBarMaxLevelBar:Hide();
+ end
+
+ else
+ if ( ReputationWatchBar:IsShown() ) then
+ visibilityChanged = 1;
+ end
+ ReputationWatchBar:Hide();
+ if ( newLevel < MAX_PLAYER_LEVEL and not IsXPUserDisabled() ) then
+ MainMenuExpBar:Show();
+ MainMenuExpBar.pauseUpdates = nil;
+ MainMenuBarMaxLevelBar:Hide();
+ else
+ MainMenuExpBar:Hide();
+ MainMenuExpBar.pauseUpdates = true;
+ MainMenuBarMaxLevelBar:Show();
+ ExhaustionTick:Hide();
+ end
+ end
+
+ -- update the xp bar
+ TextStatusBar_UpdateTextString(MainMenuExpBar);
+ MainMenuExpBar_Update();
+
+ if ( visibilityChanged ) then
+ UIParent_ManageFramePositions();
+ updateContainerFrameAnchors();
+ end
+end
+
+function ShowWatchedReputationBarText(lock)
+ if ( lock ) then
+ ReputationWatchBar.cvarLocked = lock;
+ end
+ if ( ReputationWatchBar:IsShown() ) then
+ ReputationWatchStatusBarText:Show();
+ ReputationWatchBar.textLocked = 1;
+ else
+ HideWatchedReputationBarText();
+ end
+end
+
+function HideWatchedReputationBarText(unlock)
+ if ( unlock or not ReputationWatchBar.cvarLocked ) then
+ ReputationWatchBar.cvarLocked = nil;
+ ReputationWatchStatusBarText:Hide();
+ ReputationWatchBar.textLocked = nil;
+ end
+end
diff --git a/reference/FrameXML/ReputationFrame.xml b/reference/FrameXML/ReputationFrame.xml
new file mode 100644
index 0000000..723d91e
--- /dev/null
+++ b/reference/FrameXML/ReputationFrame.xml
@@ -0,0 +1,951 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ if (self:GetParent().isCollapsed) then
+ ExpandFactionHeader(self:GetParent().index);
+ else
+ CollapseFactionHeader(self:GetParent().index);
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."ReputationBarHighlight1"]:SetPoint("TOPLEFT",self,"TOPLEFT",-2, 4);
+ _G[self:GetName().."ReputationBarHighlight1"]:SetPoint("BOTTOMRIGHT",self,"BOTTOMRIGHT",-10, -4);
+ _G[self:GetName().."ReputationBarAtWarHighlight1"]:SetPoint("TOPLEFT",self,"TOPLEFT",3,-2);
+ _G[self:GetName().."ReputationBarAtWarHighlight2"]:SetPoint("TOPRIGHT",self,"TOPRIGHT",-1,-2);
+ _G[self:GetName().."ReputationBarAtWarHighlight1"]:SetAlpha(0.2);
+ _G[self:GetName().."ReputationBarAtWarHighlight2"]:SetAlpha(0.2);
+ _G[self:GetName().."Background"]:SetPoint("TOPRIGHT", self:GetName().."ReputationBarLeftTexture", "TOPLEFT", 0, 0);
+ _G[self:GetName().."LeftLine"]:SetWidth(0);
+ _G[self:GetName().."BottomLine"]:SetHeight(0);
+ _G[self:GetName().."BottomLine"]:SetPoint("TOP", self:GetName().."ExpandOrCollapseButton", "CENTER", 5, 0);
+
+
+ ReputationBar_OnClick(self, button, down);
+
+
+ if (self.tooltip) then
+ _G[self:GetName().."ReputationBarFactionStanding"]:SetText(self.tooltip);
+ end
+ _G[self:GetName().."ReputationBarHighlight1"]:Show();
+ _G[self:GetName().."ReputationBarHighlight2"]:Show();
+
+
+ _G[self:GetName().."ReputationBarFactionStanding"]:SetText(self.standingText);
+ if ((GetSelectedFaction() ~= self.index) or (not ReputationDetailFrame:IsShown())) then
+ _G[self:GetName().."ReputationBarHighlight1"]:Hide();
+ _G[self:GetName().."ReputationBarHighlight2"]:Hide();
+ end
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ FauxScrollFrame_OnVerticalScroll(self, offset, REPUTATIONFRAME_FACTIONHEIGHT, ReputationFrame_Update);
+
+
+ ReputationBar1:SetPoint("TOPRIGHT", ReputationFrame, "TOPRIGHT", -70, -83);
+
+
+ ReputationBar1:SetPoint("TOPRIGHT", ReputationFrame, "TOPRIGHT", -46, -83);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, FACTION, 1.0, 1.0, 1.0, REPUTATION_FACTION_DESCRIPTION, 1);
+
+
+
+
+
+
+
+
+
+
+
+ GameTooltip_AddNewbieTip(self, STANDING, 1.0, 1.0, 1.0, REPUTATION_STANDING_DESCRIPTION, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(AT_WAR);
+ _G[self:GetName().."Text"]:SetVertexColor(RED_FONT_COLOR.r, RED_FONT_COLOR.g, RED_FONT_COLOR.b);
+
+
+ FactionToggleAtWar(GetSelectedFaction());
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ end
+ ReputationFrame_Update();
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(REPUTATION_AT_WAR_DESCRIPTION, nil, nil, nil, nil, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(MOVE_TO_INACTIVE);
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ SetFactionInactive(GetSelectedFaction());
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ SetFactionActive(GetSelectedFaction());
+ end
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(REPUTATION_MOVE_TO_INACTIVE, nil, nil, nil, nil, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ _G[self:GetName().."Text"]:SetText(SHOW_FACTION_ON_MAINSCREEN);
+
+
+ if ( self:GetChecked() ) then
+ PlaySound("igMainMenuOptionCheckBoxOn");
+ SetWatchedFactionIndex(GetSelectedFaction());
+ else
+ PlaySound("igMainMenuOptionCheckBoxOff");
+ SetWatchedFactionIndex(0);
+ end
+ ReputationWatchBar_Update();
+
+
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(REPUTATION_SHOW_AS_XP, nil, nil, nil, nil, 1);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ self:RegisterEvent("UPDATE_FACTION");
+ self:RegisterEvent("PLAYER_LEVEL_UP");
+ self:RegisterEvent("ENABLE_XP_GAIN");
+ self:RegisterEvent("DISABLE_XP_GAIN");
+ self:RegisterEvent("CVAR_UPDATE");
+
+
+ local arg1, arg2 = ...;
+ if( event == "UPDATE_FACTION" ) then
+ if ( self:IsShown() ) then
+ ReputationFrame_Update();
+ end
+ ReputationWatchBar_Update();
+ elseif( event == "PLAYER_LEVEL_UP" or event == "ENABLE_XP_GAIN" or event == "DISABLE_XP_GAIN" ) then
+ ReputationWatchBar_Update(arg1);
+ elseif( event == "CVAR_UPDATE" and arg1 == "XP_BAR_TEXT" ) then
+ if( arg2 == "1" ) then
+ ShowWatchedReputationBarText("lock");
+ else
+ HideWatchedReputationBarText("unlock");
+ end
+ end
+
+
+ if ( GetCVar("xpBarText") == "1" ) then
+ ShowWatchedReputationBarText("lock");
+ end
+ UIParent_ManageFramePositions();
+
+
+
+ ReputationWatchStatusBarText:Show();
+
+
+ if(not ReputationWatchBar.textLocked) then
+ ReputationWatchStatusBarText:Hide();
+ end
+
+
+
+
\ No newline at end of file
diff --git a/reference/FrameXML/RestrictedEnvironment.lua b/reference/FrameXML/RestrictedEnvironment.lua
new file mode 100644
index 0000000..94f9aa4
--- /dev/null
+++ b/reference/FrameXML/RestrictedEnvironment.lua
@@ -0,0 +1,237 @@
+-- RestrictedEnvironment.lua (Part of the new Secure Headers implementation)
+--
+-- This file defines the environment available to restricted code. The
+-- 'base' API functions (everything that's safe to use from the core
+-- WoW lua API), and functions which provide the same degree of game state
+-- as macro conditionals.
+--
+-- Nevin Flanagan (alestane@comcast.net)
+-- Daniel Stephens (iriel@vigilance-committee.org)
+---------------------------------------------------------------------------
+
+---------------------------------------------------------------------------
+-- Somewhat extensible print infrastructure for debugging, modelled around
+-- error handler code.
+--
+-- setprinthandler(func) -- Sets the active print handler
+-- func = getprinthandler() -- Gets the current print handler
+-- print(...) -- Passes its arguments to the current print handler
+--
+-- The default print handler simply strjoin's its arguments with a " "
+-- delimiter and adds it to DEFAULT_CHAT_FRAME
+
+local select = select;
+local tostring = tostring;
+local type = type;
+
+local LOCAL_ToStringAllTemp = {};
+function tostringall(...)
+ local n = select('#', ...);
+ -- Simple versions for common argument counts
+ if (n == 1) then
+ return tostring(...);
+ elseif (n == 2) then
+ local a, b = ...;
+ return tostring(a), tostring(b);
+ elseif (n == 3) then
+ local a, b, c = ...;
+ return tostring(a), tostring(b), tostring(c);
+ elseif (n == 0) then
+ return;
+ end
+
+ local needfix;
+ for i = 1, n do
+ local v = select(i, ...);
+ if (type(v) ~= "string") then
+ needfix = i;
+ break;
+ end
+ end
+ if (not needfix) then return ...; end
+
+ wipe(LOCAL_ToStringAllTemp);
+ for i = 1, needfix - 1 do
+ LOCAL_ToStringAllTemp[i] = select(i, ...);
+ end
+ for i = needfix, n do
+ LOCAL_ToStringAllTemp[i] = tostring(select(i, ...));
+ end
+ return unpack(LOCAL_ToStringAllTemp);
+end
+
+local LOCAL_PrintHandler =
+ function(...)
+ DEFAULT_CHAT_FRAME:AddMessage(strjoin(" ", tostringall(...)));
+ end
+
+function setprinthandler(func)
+ if (type(func) ~= "function") then
+ error("Invalid print handler");
+ else
+ LOCAL_PrintHandler = func;
+ end
+end
+
+function getprinthandler() return LOCAL_PrintHandler; end
+
+local geterrorhandler = geterrorhandler;
+local forceinsecure = forceinsecure;
+local pcall = pcall;
+local securecall = securecall;
+
+local function print_inner(...)
+ forceinsecure();
+ local ok, err = pcall(LOCAL_PrintHandler, ...);
+ if (not ok) then
+ local func = geterrorhandler();
+ func(err);
+ end
+end
+
+function print(...)
+ securecall(pcall, print_inner, ...);
+end
+
+-- The bare minimum functions that should exist in order to be
+-- useful without being ridiculously restrictive.
+
+RESTRICTED_FUNCTIONS_SCOPE = {
+ math = math;
+ string = string;
+ -- table is provided elsewhere, as direct tables are not allowed
+
+ select = select;
+ tonumber = tonumber;
+ tostring = tostring;
+
+ print = print;
+
+ -- String methods
+ format = format;
+ gmatch = gmatch;
+ gsub = gsub; -- Restricted table aware rtgsub is added later
+ strbyte = strbyte;
+ strchar = strchar;
+ strconcat = strconcat;
+ strfind = strfind;
+ strjoin = strjoin;
+ strlen = strlen;
+ strlower = strlower;
+ strmatch = strmatch;
+ strrep = strrep;
+ strrev = strrev;
+ strsplit = strsplit;
+ strsub = strsub;
+ strtrim = strtrim;
+ strupper = strupper;
+
+ -- Math functions
+ abs = abs;
+ acos = acos;
+ asin = asin;
+ atan = atan;
+ atan2 = atan2;
+ ceil = ceil;
+ cos = cos;
+ deg = deg;
+ exp = exp;
+ floor = floor;
+ frexp = frexp;
+ ldexp = ldexp;
+ log = log;
+ log10 = log10;
+ max = max;
+ min = min;
+ mod = mod;
+ rad = rad;
+ random = random;
+ sin = sin;
+ tan = tan;
+};
+
+-- Initialize directly available functions so they can be copied into the
+-- table
+local DIRECT_MACRO_CONDITIONAL_NAMES = {
+ "SecureCmdOptionParse",
+ "GetShapeshiftForm", "IsStealthed",
+ "UnitExists", "UnitIsDead", "UnitIsGhost",
+ "UnitPlayerOrPetInParty", "UnitPlayerOrPetInRaid",
+ "IsRightAltKeyDown", "IsLeftAltKeyDown", "IsAltKeyDown",
+ "IsRightControlKeyDown", "IsLeftControlKeyDown", "IsControlKeyDown",
+ "IsLeftShiftKeyDown", "IsRightShiftKeyDown", "IsShiftKeyDown",
+ "IsModifierKeyDown", "IsModifiedClick",
+ "GetMouseButtonClicked", "GetActionBarPage", "GetBonusBarOffset",
+ "IsMounted", "IsSwimming", "IsFlying", "IsFlyableArea",
+ "IsIndoors", "IsOutdoors",
+};
+
+local OTHER_SAFE_FUNCTION_NAMES = {
+ "GetBindingKey", "HasAction",
+ "IsHarmfulSpell", "IsHarmfulItem", "IsHelpfulSpell", "IsHelpfulItem",
+ "GetMultiCastTotemSpells"
+};
+
+-- Copy the direct functions into the table
+for _, name in ipairs( DIRECT_MACRO_CONDITIONAL_NAMES ) do
+ RESTRICTED_FUNCTIONS_SCOPE[name] = _G[name];
+end
+
+-- Copy the other safe functions into the table
+for _, name in ipairs( OTHER_SAFE_FUNCTION_NAMES ) do
+ RESTRICTED_FUNCTIONS_SCOPE[name] = _G[name];
+end
+
+-- Now create the remainder (ENV is just an alias for brevity)
+local ENV = RESTRICTED_FUNCTIONS_SCOPE;
+
+function ENV.PlayerCanAttack( unit )
+ return UnitCanAttack( "player", unit )
+end
+
+function ENV.PlayerCanAssist( unit )
+ return UnitCanAssist( "player", unit )
+end
+
+function ENV.PlayerIsChanneling()
+ return (UnitChannelInfo( "player" ) ~= nil)
+end
+
+function ENV.PlayerPetSummary()
+ return UnitCreatureFamily( "pet" ), (UnitName( "pet" ))
+end
+
+function ENV.PlayerInCombat()
+ return UnitAffectingCombat( "player" ) or UnitAffectingCombat( "pet" )
+end
+
+function ENV.PlayerInGroup()
+ return ( GetNumRaidMembers() > 0 and "raid" )
+ or ( GetNumPartyMembers() > 0 and "party" )
+end
+
+function ENV.UnitHasVehicleUI(unit)
+ unit = tostring(unit);
+ return UnitHasVehicleUI(unit) and
+ (UnitCanAssist("player", unit:gsub("(%D+)(%d*)", "%1pet%2")) and true) or
+ (UnitCanAssist("player", unit) and false);
+end
+
+function ENV.RegisterStateDriver(frameHandle, ...)
+ return RegisterStateDriver(GetFrameHandleFrame(frameHandle), ...)
+end
+
+local safeActionTypes = {["spell"] = true, ["companion"] = true, ["item"] = true, ["macro"] = true}
+local function scrubActionInfo(actionType, ...)
+ if ( safeActionTypes[actionType]) then
+ return actionType, ...
+ else
+ return actionType
+ end
+end
+
+function ENV.GetActionInfo(...)
+ return scrubActionInfo(GetActionInfo(...));
+end
+
+ENV = nil;
diff --git a/reference/FrameXML/RestrictedExecution.lua b/reference/FrameXML/RestrictedExecution.lua
new file mode 100644
index 0000000..027198f
--- /dev/null
+++ b/reference/FrameXML/RestrictedExecution.lua
@@ -0,0 +1,827 @@
+-- RestrictedExecution.lua (Part of the new Secure Headers implementation)
+--
+-- This contains the necessary (and sufficient) code to support
+-- 'restricted execution' for code provided via attributes, intended
+-- for use in the secure header implementations. It provides a fairly
+-- isolated execution environment and is constructed to maintain local
+-- control over the important elements of the execution environment.
+--
+-- Daniel Stephens (iriel@vigilance-committee.org)
+-- Nevin Flanagan (alestane@comcast.net)
+---------------------------------------------------------------------------
+
+-- Localizes for functions that are frequently called or need to be
+-- assuredly un-replaceable or unhookable.
+local type = type;
+local error = error;
+local scrub = scrub;
+local issecure = issecure;
+local rawset = rawset;
+local setfenv = setfenv;
+local loadstring = loadstring;
+local setmetatable = setmetatable;
+local getmetatable = getmetatable;
+local pcall = pcall;
+local tostring = tostring;
+local next = next;
+local unpack = unpack;
+local newproxy = newproxy;
+local select = select;
+local wipe = wipe;
+local tonumber = tonumber;
+
+local t_insert = table.insert;
+local t_maxn = table.maxn;
+local t_concat = table.concat;
+local t_sort = table.sort;
+local t_remove = table.remove;
+
+local s_gsub = string.gsub;
+
+local IsFrameHandle = IsFrameHandle;
+
+---------------------------------------------------------------------------
+-- RESTRICTED CLOSURES
+
+local function SelfScrub(self)
+ if (self ~= nil and IsFrameHandle(self)) then
+ return self;
+ end
+ return nil;
+end
+
+-- closure, err = BuildRestrictedClosure(body, env, signature)
+--
+-- body -- The function body (defaults to "")
+-- env -- The execution environment (defaults to {})
+-- signature -- The function signature (defaults to "self,...")
+--
+-- Returns the constructed closure, or nil and an error
+local function BuildRestrictedClosure(body, env, signature)
+ body = tostring(body) or "";
+ signature = tostring(signature) or "self,...";
+ if (type(env) ~= "table") then
+ env = {};
+ end
+
+ if (body:match("function")) then
+ -- NOTE - This is overzealous but it keeps it simple
+ return nil, "The function keyword is not permitted";
+ end
+
+ if (body:match("[{}]")) then
+ -- NOTE - This is overzealous but it keeps it simple
+ return nil, "Direct table creation is not permitted";
+ end
+
+ if (signature:match("function")) then
+ -- NOTE - This is overzealous but it keeps it simple
+ return nil, "The function keyword is not permitted";
+ end
+
+ if (not signature:match("^[a-zA-Z_0-9, ]*[.]*$")) then
+ -- NOTE - This is overzealous but it keeps it simple
+ return nil, "Signature contains invalid characters (" .. signature .. ")";
+ end
+
+ -- Include a \n before end to stop shenanigans with comments
+ local def, err =
+ loadstring("return function (" .. signature .. ") " .. body .. "\nend", body);
+ if (def == nil) then
+ return nil, err;
+ end
+
+ -- Use a completely empty environment here to be absolutely
+ -- sure to avoid tampering during function definition.
+ setfenv(def, {});
+ def = def();
+ -- Double check that the definition did infact return a function
+ if (type(def) ~= "function") then
+ return nil, "Invalid body";
+ end
+ -- Set the desired environment on the resulting closure.
+ setfenv(def, env);
+
+ -- And then return a 'safe' wrapped invocation for the closure.
+ return function(self, ...) return def(SelfScrub(self), scrub(...)) end;
+end
+
+-- factory = CreateClosureFactory(env, signature)
+--
+-- env -- The desired environment table for the closures
+-- signature -- The function signature for the closures
+--
+-- Returns a 'factory table' which is keyed by function bodies, and
+-- has restricted closure values. It's weak-keyed and uses an __index
+-- metamethod that automatically creates necessary closures on demand.
+local function CreateClosureFactory(env, signature)
+ local function metaIndex(t, k)
+ if (type(k) == "string") then
+ local closure, err = BuildRestrictedClosure(k, env, signature);
+ if (not closure) then
+ -- Put the error into a closure to avoid constantly
+ -- re-parsing it
+ err = tostring(err or "Closure creation failed");
+ closure = function() error(err) end;
+ end
+ if (issecure()) then
+ t[k] = closure;
+ end
+ return closure;
+ end
+ error("Invalid closure body type (" .. type(k) .. ")");
+ return nil;
+ end
+
+ local ret = {};
+ setmetatable(ret, { __index = metaIndex, __mode = "k" });
+ return ret;
+end
+
+---------------------------------------------------------------------------
+-- RESTRICTED TABLES
+--
+-- Provides fully proxied tables with restrictions on their contents.
+--
+
+-- Mapping table from restricted table 'proxy' to the 'real' storage
+local LOCAL_Restricted_Tables = {};
+setmetatable(LOCAL_Restricted_Tables, { __mode="k" });
+
+-- Metatable common to all restricted tables (This introduces one
+-- level of indirection in every use as a means to share the same
+-- metatable between all instances)
+local LOCAL_Restricted_Table_Meta = {
+ __index = function(t, k)
+ local real = LOCAL_Restricted_Tables[t];
+ return real[k];
+ end,
+
+ __newindex = function(t, k, v)
+ local real = LOCAL_Restricted_Tables[t];
+ if (not issecure()) then
+ error("Cannot insecurely modify restricted table");
+ return;
+ end
+ local tv = type(v);
+ if ((tv ~= "string") and (tv ~= "number")
+ and (tv ~= "boolean") and (tv ~= "nil")
+ and ((tv ~= "userdata")
+ or not (LOCAL_Restricted_Tables[v]
+ or IsFrameHandle(v)))) then
+ error("Invalid value type '" .. tv .. "'");
+ return;
+ end
+ local tk = type(k);
+ if ((tk ~= "string") and (tk ~= "number")
+ and (tk ~= "boolean")
+ and ((tk ~= "userdata")
+ or not (IsFrameHandle(k)))) then
+ error("Invalid key type '" .. tk .. "'");
+ return;
+ end
+ real[k] = v;
+ end,
+
+ __len = function(t)
+ local real = LOCAL_Restricted_Tables[t];
+ return #real;
+ end,
+
+ __metatable = false, -- False means read-write proxy
+}
+
+local LOCAL_Readonly_Restricted_Tables = {};
+setmetatable(LOCAL_Readonly_Restricted_Tables, { __mode="k" });
+
+local function CheckReadonlyValue(ret)
+ if (type(ret) == "userdata") then
+ if (LOCAL_Restricted_Tables[ret]) then
+ if (getmetatable(ret)) then
+ return ret;
+ end
+ return LOCAL_Readonly_Restricted_Tables[ret];
+ end
+ end
+ return ret;
+end
+
+-- Metatable common to all read-only restricted tables (This also introduces
+-- indirection so that a single metatable is viable)
+local LOCAL_Readonly_Restricted_Table_Meta = {
+ __index = function(t, k)
+ local real = LOCAL_Restricted_Tables[t];
+ return CheckReadonlyValue(real[k]);
+ end,
+
+ __newindex = function(t, k, v)
+ error("Table is read-only");
+ end,
+
+ __len = function(t)
+ local real = LOCAL_Restricted_Tables[t];
+ return #real;
+ end,
+
+ __metatable = true, -- True means read-only proxy
+}
+
+
+local LOCAL_Restricted_Prototype = newproxy(true);
+local LOCAL_Readonly_Restricted_Prototype = newproxy(true);
+do
+ local meta = getmetatable(LOCAL_Restricted_Prototype);
+ for k, v in pairs(LOCAL_Restricted_Table_Meta) do
+ meta[k] = v;
+ end
+
+ meta = getmetatable(LOCAL_Readonly_Restricted_Prototype);
+ for k, v in pairs(LOCAL_Readonly_Restricted_Table_Meta) do
+ meta[k] = v;
+ end
+end
+
+local function RestrictedTable_Readonly_index(t, k)
+ local real = LOCAL_Restricted_Tables[k];
+ if (not real) then return; end
+ if (not issecure()) then
+ error("Cannot create restricted tables from insecure code");
+ return;
+ end
+
+ local ret = newproxy(LOCAL_Readonly_Restricted_Prototype);
+ LOCAL_Restricted_Tables[ret] = real;
+ t[k] = ret;
+ return ret;
+end
+
+getmetatable(LOCAL_Readonly_Restricted_Tables).__index
+ = RestrictedTable_Readonly_index;
+
+-- table = RestrictedTable_create(...)
+--
+-- Create a new, restricted table, populating it from ... if
+-- necessary, similar to the way the normal table constructor
+-- works.
+local function RestrictedTable_create(...)
+ local ret = newproxy(LOCAL_Restricted_Prototype);
+ if (not issecure()) then
+ error("Cannot create restricted tables from insecure code");
+ return;
+ end
+ LOCAL_Restricted_Tables[ret] = {};
+
+ -- Use this loop to ensure that the contents of the new
+ -- table are all allowed
+ for i = 1, select('#', ...) do
+ ret[i] = select(i, ...);
+ end
+
+ return ret;
+end
+
+-- table = GetReadonlyRestrictedTable(otherTable)
+--
+-- Given a restricted table, return a read-only proxy to the same
+-- table (which will be itself, if it's already read-only)
+function GetReadonlyRestrictedTable(ref)
+ if (LOCAL_Restricted_Tables[ref]) then
+ if (getmetatable(ref)) then
+ return ref;
+ end
+ return LOCAL_Readonly_Restricted_Tables[ref];
+ end
+ error("Invalid restricted table");
+end
+
+-- key = RestrictedTable_next(table [,key])
+--
+-- An implementation of the next function, which is
+-- aware of restricted and normal tables and behaves consistently
+-- for both.
+local function RestrictedTable_next(T, k)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ if (getmetatable(T)) then
+ local idx, val = next(PT, k);
+ if (val ~= nil) then
+ return idx, CheckReadonlyValue(val);
+ else
+ return idx, val;
+ end
+ else
+ return next(PT, k);
+ end
+ end
+ return next(T, k);
+end
+
+-- iterfunc, table, key = RestrictedTable_pairs(table)
+--
+-- An implementation of the pairs function, which is aware
+-- of and iterates over both restricted and normal tables.
+local function RestrictedTable_pairs(T)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ -- v
+ return RestrictedTable_next, T, nil;
+ end
+ return pairs(T);
+end
+
+-- key, value = RestrictedTable_ipairsaux(table, prevkey)
+--
+-- Iterator function for internal use by restricted table ipairs
+local function RestrictedTable_ipairsaux(T, i)
+ i = i + 1;
+ local v = T[i];
+ if (v) then
+ return i, v;
+ end
+end
+
+-- iterfunc, table, key = RestrictedTable_ipairs(table)
+--
+-- An implementation of the ipairs function, which is aware
+-- of and iterates over both restricted and normal tables.
+local function RestrictedTable_ipairs(T)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ return RestrictedTable_ipairsaux, T, 0;
+ end
+ return ipairs(T);
+end
+
+-- Recursive helper to ensure all values from a list are properly converted
+-- to read-only proxies
+local RestrictedTable_unpack_ro;
+function RestrictedTable_unpack_ro(...)
+ local n = select('#', ...);
+ if (n == 0) then
+ return;
+ end
+ return CheckReadonlyValue(...), RestrictedTable_unpack_ro(select(2, ...));
+end
+
+-- ... = RestrictedTable_unpack(table)
+--
+-- An implementation of unpack which unpacks both restricted
+-- and normal tables.
+local function RestrictedTable_unpack(T)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ if (getmetatable(T)) then
+ return RestrictedTable_unpack_ro(unpack(PT));
+ end
+ return unpack(PT)
+ end
+ return unpack(T);
+end
+
+-- table = RestrictedTable_wipe(table)
+--
+-- A restricted aware implementation of wipe()
+local function RestrictedTable_wipe(T)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ if (getmetatable(T)) then
+ error("Cannot wipe a read-only table");
+ return;
+ end
+ if (not issecure()) then
+ error("Cannot insecurely modify restricted table");
+ return;
+ end
+ wipe(PT);
+ return T;
+ end
+ return wipe(T);
+end
+
+-- RestrictedTable_maxn(table)
+--
+-- A restricted aware implementation of table.maxn()
+local function RestrictedTable_maxn(T)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ return t_maxn(PT);
+ end
+ return t_maxn(T);
+end
+
+-- RestrictedTable_concat(table)
+--
+-- A restricted aware implementation of table.concat()
+local function RestrictedTable_concat(T)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ return t_concat(PT);
+ end
+ return t_concat(T);
+end
+
+-- RestrictedTable_sort(table, func)
+--
+-- A restricted aware implementation of table.sort()
+local function RestrictedTable_sort(T, func)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ if (getmetatable(T)) then
+ error("Cannot sort a read-only table");
+ return;
+ end
+ if (not issecure()) then
+ error("Cannot insecurely modify restricted table");
+ return;
+ end
+ t_sort(PT, func);
+ return;
+ end
+ t_sort(T, func);
+end
+
+-- RestrictedTable_insert(table [,pos], val)
+--
+-- A restricted aware implementation of table.insert()
+local function RestrictedTable_insert(T, ...)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ if (getmetatable(T)) then
+ error("Cannot insert into a read-only table");
+ return;
+ end
+ local pos, val;
+ if (select('#', ...) == 1) then
+ local val = ...;
+ T[#PT + 1] = val;
+ return;
+ end
+ pos, val = ...;
+ pos = tonumber(pos);
+ t_insert(PT, pos, nil);
+ -- Leverage protections present on regular indexing
+ T[pos] = val;
+ return;
+ end
+ return t_insert(T, ...);
+end
+
+-- val = RestrictedTable_remove(table, pos)
+--
+-- A restricted aware implementation of table.remove()
+local function RestrictedTable_remove(T, pos)
+ local PT = LOCAL_Restricted_Tables[T];
+ if (PT) then
+ if (getmetatable(T)) then
+ error("Cannot remove from a read-only table");
+ return;
+ end
+ if (not issecure()) then
+ error("Cannot insecurely modify restricted table");
+ return;
+ end
+ return CheckReadonlyValue(t_remove(PT, pos));
+ end
+ return t_remove(T, pos);
+end
+
+-- objtype = RestrictedTable_type(obj)
+--
+-- A version of type which returns 'table' for restricted tables
+local function RestrictedTable_type(obj)
+ local t = type(obj);
+ if (t == "userdata") then
+ if (LOCAL_Restricted_Tables[obj]) then
+ t = "table";
+ end
+ end
+ return t;
+end
+
+-- ns = RestrictedTable_rtgsub(s, pattern, repl, n)
+--
+-- A version of string.gsub which is able to be passed restricted tables
+local function RestrictedTable_rtgsub(s, pattern, repl, n)
+ local t = type(repl);
+ if (t == "userdata") then
+ local PT = LOCAL_Restricted_Tables[repl];
+ return s_gsub(s, pattern, PT, n);
+ end
+ return s_gsub(s, pattern, repl, n);
+end
+
+-- Export these functions so that addon code can use them if desired
+-- and so that the handlers can create these tables
+rtable = {
+ next = RestrictedTable_next;
+ pairs = RestrictedTable_pairs;
+ ipairs = RestrictedTable_ipairs;
+ unpack = RestrictedTable_unpack;
+ newtable = RestrictedTable_create;
+
+ maxn = RestrictedTable_maxn;
+ insert = RestrictedTable_insert;
+ remove = RestrictedTable_remove;
+ sort = RestrictedTable_sort;
+ concat = RestrictedTable_concat;
+ wipe = RestrictedTable_wipe;
+
+ type = RestrictedTable_type;
+ rtgsub = RestrictedTable_rtgsub;
+};
+
+-- Add this version of gsub to the string metatable
+string.rtgsub = RestrictedTable_rtgsub;
+
+local LOCAL_Table_Namespace = {
+ table = {
+ maxn = RestrictedTable_maxn;
+ insert = RestrictedTable_insert;
+ remove = RestrictedTable_remove;
+ sort = RestrictedTable_sort;
+ concat = RestrictedTable_concat;
+ wipe = RestrictedTable_wipe;
+ new = RestrictedTable_create;
+ }
+};
+
+---------------------------------------------------------------------------
+-- RESTRICTED ENVIRONMENT
+--
+-- environment, manageFunc = CreateRestrictedEnvironment(baseEnvironment)
+--
+-- baseEnvironment -- The base environment table (containing functions)
+--
+-- environment -- The new restricted environment table
+-- manageFunc -- Management function to set/clear working and proxy
+-- environments.
+--
+-- The management function takes two parameters
+-- manageFunc(set, workingTable, controlHandle)
+--
+-- set is a boolean; If it's true then the working table is set to the
+-- specified value (pushing any previous environment onto a stack). If
+-- it's false then the working table is unset (and restored from stack).
+--
+-- The working table should be a restricted table, or an immutable object.
+--
+-- The controlHandle is an optional object which is made available to
+-- the restricted code with the name 'control'.
+--
+-- The management function monitors calls to get and set in order to prevent
+-- re-entrancy (i.e. calls to get and set must be balanced, and one cannot
+-- switch working tables in the middle).
+local function CreateRestrictedEnvironment(base)
+ if (type(base) ~= "table") then base = {}; end
+
+ local working, control, depth = nil, nil, 0;
+ local workingStack, controlStack = {}, {};
+
+ local result = {};
+ local meta_index;
+
+ local function meta_index(t, k)
+ local v = base[k] or working[k];
+ if (v == nil) then
+ if (k == "control") then return control; end
+ end
+ return v;
+ end;
+
+ local function meta_newindex(t, k, v)
+ working[k] = v;
+ end
+
+ local meta = {
+ __index = meta_index,
+ __newindex = meta_newindex,
+ __metatable = false;
+ __environment = false;
+ }
+
+ setmetatable(result, meta);
+
+ local function manage(set, newWorking, newControl)
+ if (set) then
+ if (depth == 0) then
+ depth = 1;
+ else
+ workingStack[depth] = working;
+ controlStack[depth] = control;
+
+ depth = depth + 1;
+ end
+ working = newWorking;
+ control = newControl;
+ else
+ if (depth == 0) then
+ error("Attempted to release unused environment");
+ return;
+ end
+
+ if (working ~= newWorking) then
+ error("Working environment mismatch at release");
+ return;
+ end
+
+ if (control ~= newControl) then
+ error("Control handle mismatch at release");
+ return;
+ end
+
+ depth = depth - 1;
+ if (depth == 0) then
+ working = nil;
+ control = nil;
+ else
+ working = workingStack[depth];
+ control = controlStack[depth];
+ workingStack[depth] = nil;
+ controlStack[depth] = nil;
+ end
+ end
+ end
+
+ return result, manage;
+end
+
+---------------------------------------------------------------------------
+-- AVAILABLE FUNCTIONS
+--
+-- The current implementation has a single set of functions (aka a single
+-- base environment), this initializes that environment by creating a master
+-- base environment table, and then creating a restricted environment
+-- around that. If the RESTRICTED_FUNCTIONS_SCOPE table exists when
+-- this file is executed then its contents are added to the environment.
+--
+-- It is expected that any functions that are to be placed into this
+-- environment have been carefully written to not return arbtirary tables,
+-- functions, or userdata back to the caller.
+--
+-- One can use function(...) return scrub(realFunction(...)) end to wrap
+-- those functions one doesn't trust.
+
+-- A metatable to prevent tampering with the environment tables.
+local LOCAL_No_Secure_Update_Meta = {
+ __newindex = function() end;
+ __metatable = false;
+};
+
+local LOCAL_Restricted_Global_Functions = {
+ newtable = RestrictedTable_create;
+ pairs = RestrictedTable_pairs;
+ ipairs = RestrictedTable_ipairs;
+ next = RestrictedTable_next;
+ unpack = RestrictedTable_unpack;
+
+ -- Table methods
+ wipe = RestrictedTable_wipe;
+ tinsert = RestrictedTable_insert;
+ tremove = RestrictedTable_remove;
+
+ -- Synthetic restricted-table-aware 'type'
+ type = RestrictedTable_type;
+
+ -- Restricted table aware gsub
+ rtgsub = RestrictedTable_rtgsub;
+};
+
+-- A helper function to recursively copy and protect scopes
+local PopulateGlobalFunctions
+function PopulateGlobalFunctions(src, dest)
+ for k, v in pairs(src) do
+ if (type(k) == "string") then
+ local tv = type(v);
+ if ((tv == "function") or (tv == "number") or (tv == "string") or (tv == "boolean")) then
+ dest[k] = v;
+ elseif (tv == "table") then
+ local subdest = {};
+ PopulateGlobalFunctions(v, subdest);
+ setmetatable(subdest, LOCAL_No_Secure_Update_Meta);
+ local dproxy = newproxy(true);
+ local dproxy_meta = getmetatable(dproxy);
+ dproxy_meta.__index = subdest;
+ dproxy_meta.__metatable = false;
+ dest[k] = dproxy;
+ end
+ end
+ end
+end
+
+-- Import any functions initialized by other/earier files
+if (RESTRICTED_FUNCTIONS_SCOPE) then
+ PopulateGlobalFunctions(RESTRICTED_FUNCTIONS_SCOPE,
+ LOCAL_Restricted_Global_Functions);
+ RESTRICTED_FUNCTIONS_SCOPE = nil;
+end
+
+PopulateGlobalFunctions(LOCAL_Table_Namespace,
+ LOCAL_Restricted_Global_Functions);
+
+-- Create the environment
+local LOCAL_Function_Environment, LOCAL_Function_Environment_Manager =
+ CreateRestrictedEnvironment(LOCAL_Restricted_Global_Functions);
+
+-- Protect from injection via the string metatable index
+-- Assume for now that 'string' is relatively clean
+local strmeta = getmetatable("x");
+local newmetaindex = {};
+for k, v in pairs(string) do newmetaindex[k] = v; end
+setmetatable(newmetaindex, {
+ __index = function(t,k)
+ if (not issecure()) then
+ return string[k];
+ end
+ end;
+ __metatable = false;
+ });
+strmeta.__index = newmetaindex;
+strmeta.__metatable = string;
+strmeta = nil;
+newmetaindex = nil;
+
+---------------------------------------------------------------------------
+-- CLOSURE FACTORIES
+--
+-- An automatically populating table keyed by function signature with
+-- values that are closure factories for those signatures.
+
+local LOCAL_Closure_Factories = { };
+
+local function ClosureFactories_index(t, signature)
+ if (type(signature) ~= "string") then
+ return;
+ end
+
+ local factory = CreateClosureFactory(LOCAL_Function_Environment, signature);
+
+ if (not issecure()) then
+ error("Cannot declare closure factories from insecure code");
+ return;
+ end
+
+ t[signature] = factory;
+ return factory;
+end
+
+setmetatable(LOCAL_Closure_Factories, { __index = ClosureFactories_index });
+
+---------------------------------------------------------------------------
+-- FUNCTION CALL
+
+-- A helper method to release the restricted environment environment before
+-- returning from the function call.
+local function ReleaseAndReturn(workingEnv, ctrlHandle, pcallFlag, ...)
+ -- Tampering at this point will irrevocably taint the protected
+ -- environment, for now that's a handy protective measure.
+ LOCAL_Function_Environment_Manager(false, workingEnv, ctrlHandle);
+ if (pcallFlag) then
+ return ...;
+ end
+ error("Call failed: " .. tostring( (...) ) );
+end
+
+-- ? = CallRestrictedClosure(signature, workingEnv, onupdate, body, ...)
+--
+-- Invoke a managed closure, looking its definition up from a factory
+-- and managing its environment during execution.
+--
+-- signature -- function signature
+-- workingEnv -- the working environment, must be a restricted table
+-- ctrlHandle -- a control handle
+-- body -- function body
+-- ... -- any arguments to pass to the executing closure
+--
+-- Returns whatever the restricted closure returns
+function CallRestrictedClosure(signature, workingEnv, ctrlHandle, body, ...)
+ if (not LOCAL_Restricted_Tables[workingEnv]) then
+ error("Invalid working environment");
+ return;
+ end
+
+ signature = tostring(signature);
+ local factory = LOCAL_Closure_Factories[signature];
+ if (not factory) then
+ error("Invalid signature '" .. signature .. "'");
+ return;
+ end
+
+ local closure = factory[body];
+ if (not closure) then
+ -- Expect factory to have thrown an error
+ return;
+ end
+
+ if (not issecure()) then
+ error("Cannot call restricted closure from insecure code");
+ return;
+ end
+
+ if (type(ctrlHandle) ~= "userdata") then
+ ctrlHandle = nil;
+ end
+
+ LOCAL_Function_Environment_Manager(true, workingEnv, ctrlHandle);
+ return ReleaseAndReturn(workingEnv, ctrlHandle, pcall( closure, ... ) );
+end
+
diff --git a/reference/FrameXML/RestrictedFrames.lua b/reference/FrameXML/RestrictedFrames.lua
new file mode 100644
index 0000000..7fb98ab
--- /dev/null
+++ b/reference/FrameXML/RestrictedFrames.lua
@@ -0,0 +1,658 @@
+-- RestrictedFrames.lua (Part of the new Secure Headers implementation)
+--
+-- Handle objects to access frames during restricted execution in order to
+-- allow safe manipulation of frame properties. These handles can be passed
+-- around safely without allowing their destinations or functions to be
+-- tampered with.
+--
+-- Daniel Stephens (iriel@vigilance-committee.org)
+-- Nevin Flanagan (alestane@comcast.net)
+--
+-- The design consists of several components...
+--
+-- HANDLES: These are lightweight userdata objects with a shared metatable
+-- that stand in for frames. They're persistent once created (i.e.
+-- a given frame always has the same handle). Internally these map
+-- to a 'copied' frame object. Only explcitly protected frames can
+-- be assigned handles.
+--
+-- METHODS: The handler methods are contained in a table which is then set
+-- as the __index on the handlers. These are in two groups, there
+-- are 'read' methods that may be blocked in some situations, and
+-- there are 'write' methods which simply require that an execution
+-- is active.
+--
+-- Various methods (SetPoint/SetParent) take frame handles as relative
+-- frame arguments also. You can safely obtain frame handles (out of combat)
+-- by setting the '_frame-' attribute on a header frame to the frame
+-- you want a handle to, and it'll set the 'frameref-' attribute to be
+-- the handle to that frame (or nil if it's invalid or unprotected).
+-- This handle can then be retrieved using a GetAttribute call.
+---------------------------------------------------------------------------
+
+local issecure = issecure;
+local select = select;
+local type = type;
+local unpack = unpack;
+local wipe = wipe;
+local pairs = pairs;
+local newproxy = newproxy;
+local error = error;
+local tostring = tostring;
+local tonumber = tonumber;
+local string = string;
+local rawget = rawget;
+local securecall = securecall;
+local GetCursorPosition = GetCursorPosition;
+local InCombatLockdown = InCombatLockdown;
+
+---------------------------------------------------------------------------
+-- Frame Handles -- Userdata handles referencing explicitly protected frames
+--
+-- LOCAL_FrameHandle_Protected_Frames -- handle keys, frame surrogate values
+-- (explicitly protected)
+-- LOCAL_FrameHandle_Other_Frames -- handle keys, frame surrogate values
+-- (possibly protected)
+-- LOCAL_FrameHandle_Lookup -- frame keys, handle values
+--
+-- The lookup table auto-populates via an __index metamethod
+
+local LOCAL_FrameHandle_Protected_Frames = {};
+local LOCAL_FrameHandle_Other_Frames = {};
+local LOCAL_FrameHandle_Lookup = {};
+setmetatable(LOCAL_FrameHandle_Protected_Frames, { __mode = "k" });
+setmetatable(LOCAL_FrameHandle_Other_Frames, { __mode = "k" });
+
+-- Setup metatable for prototype object
+local LOCAL_FrameHandle_Prototype = newproxy(true);
+-- HANDLE is the frame handle method namespace (populated below)
+local HANDLE = {};
+do
+ local meta = getmetatable(LOCAL_FrameHandle_Prototype);
+ meta.__index = HANDLE;
+ meta.__metatable = false;
+end
+
+function IsFrameHandle(handle, protected)
+ local surrogate = LOCAL_FrameHandle_Protected_Frames[handle];
+ if ((surrogate == nil) and not protected) then
+ surrogate = LOCAL_FrameHandle_Other_Frames[handle];
+ end
+ return (surrogate ~= nil);
+end
+
+function GetFrameHandleFrame(handle, protected)
+ local surrogate = LOCAL_FrameHandle_Protected_Frames[handle];
+ if ((surrogate == nil) and (not protected or not InCombatLockdown())) then
+ surrogate = LOCAL_FrameHandle_Other_Frames[handle];
+ end
+ if (surrogate ~= nil) then
+ return surrogate[1];
+ end
+end
+
+local function FrameHandleLookup_index(t, frame)
+ -- Create a 'surrogate' frame object
+ local surrogate = { [0] = frame[0], [1] = frame };
+ setmetatable(surrogate, getmetatable(frame));
+ -- Test whether the frame is explcitly protected
+ local _, protected = surrogate:IsProtected();
+ if (not issecure()) then
+ return;
+ end
+ local handle = newproxy(LOCAL_FrameHandle_Prototype);
+ LOCAL_FrameHandle_Lookup[frame] = handle;
+ if (protected) then
+ LOCAL_FrameHandle_Protected_Frames[handle] = surrogate;
+ else
+ LOCAL_FrameHandle_Other_Frames[handle] = surrogate;
+ end
+ return handle;
+end
+setmetatable(LOCAL_FrameHandle_Lookup, { __index = FrameHandleLookup_index; });
+
+-- Gets the handle for a frame (if available)
+function GetFrameHandle(frame, protected)
+ local handle = LOCAL_FrameHandle_Lookup[frame];
+ if (protected and (frame ~= nil)) then
+ if (not LOCAL_FrameHandle_Protected_Frames[handle]) then
+ return nil;
+ end
+ end
+ return handle;
+end
+
+---------------------------------------------------------------------------
+-- Action implementation support function
+--
+-- GetHandleFrame -- Get the frame for a handle
+
+local function GetUnprotectedHandleFrame(handle)
+ local frame = LOCAL_FrameHandle_Protected_Frames[handle];
+ if (not frame) then
+ frame = LOCAL_FrameHandle_Other_Frames[handle];
+ if (not frame) then
+ error("Invalid frame handle");
+ return;
+ end
+ end
+ return frame;
+end
+
+local function GetHandleFrame(handle)
+ local frame = LOCAL_FrameHandle_Protected_Frames[handle];
+ if (not frame) then
+ frame = LOCAL_FrameHandle_Other_Frames[handle];
+ if (frame) then
+ if (frame:IsProtected() or not InCombatLockdown()) then
+ return frame;
+ end
+ end
+ error("Invalid frame handle");
+ return;
+ end
+ return frame;
+end
+
+---------------------------------------------------------------------------
+-- "GETTER" methods
+
+function HANDLE:GetName() return GetUnprotectedHandleFrame(self):GetName() end
+
+function HANDLE:GetID() return GetHandleFrame(self):GetID() end
+function HANDLE:IsShown() return GetHandleFrame(self):IsShown() end
+function HANDLE:IsVisible() return GetHandleFrame(self):IsVisible() end
+function HANDLE:GetWidth() return GetHandleFrame(self):GetWidth() end
+function HANDLE:GetHeight() return GetHandleFrame(self):GetHeight() end
+function HANDLE:GetRect() return GetHandleFrame(self):GetRect() end
+function HANDLE:GetScale() return GetHandleFrame(self):GetScale() end
+function HANDLE:GetEffectiveScale()
+ return GetHandleFrame(self):GetEffectiveScale()
+end
+
+-- Cannot expose GetAlpha since alpha is not protected
+
+function HANDLE:GetFrameLevel()
+ return GetHandleFrame(self):GetFrameLevel() end
+function HANDLE:GetObjectType()
+ return GetUnprotectedHandleFrame(self):GetObjectType()
+end
+function HANDLE:IsObjectType(ot)
+ return GetUnprotectedHandleFrame(self):IsObjectType(tostring(ot))
+end
+function HANDLE:IsProtected()
+ return GetUnprotectedHandleFrame(self):IsProtected();
+end
+
+
+function HANDLE:GetAttribute(name)
+ if (type(name) ~= "string" or name:match("^_")) then
+ return;
+ end
+ local val = GetHandleFrame(self):GetAttribute(name)
+ local tv = type(val);
+ if (tv == "string" or tv == "number" or tv == "boolean" or val == nil) then
+ return val;
+ end
+ if (tv == "userdata" and
+ (LOCAL_FrameHandle_Protected_Frames[val]
+ or LOCAL_FrameHandle_Other_Frames[val])) then
+ return val;
+ end
+ return nil;
+end
+
+function HANDLE:GetFrameRef(label)
+ if (type(label) ~= "string") then
+ return;
+ end
+ local val = GetHandleFrame(self):GetAttribute("frameref-" .. label);
+ local tv = type(val);
+ if (tv == "userdata" and
+ (LOCAL_FrameHandle_Protected_Frames[val]
+ or LOCAL_FrameHandle_Other_Frames[val])) then
+ return val;
+ end
+ return nil;
+end
+
+function HANDLE:GetEffectiveAttribute(name, button, prefix, suffix)
+ if (type(name) ~= "string" or name:match("^_")) then
+ return;
+ end
+ if (button ~= nil) then button = tostring(button) end
+ if (prefix ~= nil) then
+ prefix = tostring(prefix)
+ if (prefix:match("^_")) then
+ prefix = nil;
+ end
+ end
+ if (suffix ~= nil) then suffix = tostring(suffix) end
+ local val = SecureButton_GetModifiedAttribute(GetHandleFrame(self),
+ name, button, prefix,
+ suffix);
+ local tv = type(val);
+ if (tv == "string" or tv == "number" or tv == "boolean" or val == nil) then
+ return val;
+ end
+ if (tv == "userdata" and
+ (LOCAL_FrameHandle_Protected_Frames[val]
+ or LOCAL_FrameHandle_Other_Frames[val])) then
+ return val;
+ end
+ return nil;
+end
+
+
+local function FrameHandleMapper(nolockdown, frame, nextFrame, ...)
+ if (not frame) then
+ return;
+ end
+ -- Do an explicit protection check to avoid errors from
+ -- the frame handle lookup
+ local p = nolockdown;
+ if (not p) then
+ p = frame:IsProtected();
+ end
+ if (p) then
+ frame = LOCAL_FrameHandle_Lookup[frame];
+ if (frame) then
+ if (nextFrame) then
+ return frame, FrameHandleMapper(nolockdown, nextFrame, ...);
+ else
+ return frame;
+ end
+ end
+ end
+ if (nextFrame) then
+ return FrameHandleMapper(nolockdown, nextFrame, ...);
+ end
+end
+
+local function FrameHandleInserter(result, ...)
+ local nolockdown = not InCombatLockdown();
+ local idx = #result;
+ for i = 1, select('#', ...) do
+ local frame = select(i, ...);
+ -- Do an explicit protection check to avoid errors from
+ -- the frame handle lookup
+ local p = nolockdown;
+ if (not p) then
+ p = frame:IsProtected();
+ end
+ if (p) then
+ frame = LOCAL_FrameHandle_Lookup[frame];
+ if (frame) then
+ idx = idx + 1;
+ result[idx] = frame;
+ end
+ end
+ end
+
+ return result;
+end
+
+function HANDLE:GetChildren()
+ return FrameHandleMapper(not InCombatLockdown(),
+ GetHandleFrame(self):GetChildren());
+end
+
+function HANDLE:GetChildList(tbl)
+ return FrameHandleInserter(tbl, GetHandleFrame(self):GetChildren());
+end
+
+function HANDLE:GetParent()
+ return FrameHandleMapper(not InCombatLockdown(),
+ GetHandleFrame(self):GetParent());
+end
+
+-- NOTE: Cannot allow the frame to figure out if it has mouse focus
+-- because an insecure frame could be appearing on top of it.
+
+function HANDLE:GetMousePosition()
+ local frame = GetHandleFrame(self);
+ local x, y = GetCursorPosition()
+ local l, b, w, h = frame:GetRect()
+ if (not w or not h or w == 0 or h == 0) then return nil; end
+ local e = frame:GetEffectiveScale();
+ x, y = x / e, y /e;
+ x = x - l
+ y = y - b
+ if x < 0 or x > w or y < 0 or y > h then
+ return nil
+ else
+ return x / w, y / h
+ end
+end
+
+-- Used only for recursive check, since it's more expensive
+--
+-- Only check protected and visible children
+local function RF_CheckUnderMouse(x, y, ...)
+ for i = 1, select('#', ...) do
+ local frame = select(i, ...);
+ if (frame and frame:IsProtected() and frame:IsVisible()) then
+ local l, b, w, h = frame:GetRect()
+ if (w and h) then
+ local e = frame:GetEffectiveScale();
+ local fx = x / e - l;
+ if ((fx >= 0) and (fx <= w)) then
+ local fy = y / e - b;
+ if ((fy >= 0) and (fy <= h)) then return true; end
+ end
+ end
+ if (RF_CheckUnderMouse(x, y, frame:GetChildren())) then
+ return true;
+ end
+ end
+ end
+end
+
+function HANDLE:IsUnderMouse(recursive)
+ local frame = GetHandleFrame(self);
+ local x, y = GetCursorPosition();
+ local l, b, w, h = frame:GetRect()
+ if (w and h) then
+ local e = frame:GetEffectiveScale();
+ local fx = x / e - l;
+ if ((fx >= 0) and (fx <= w)) then
+ local fy = y / e - b;
+ if ((fy >= 0) and (fy <= h)) then return true; end
+ end
+ end
+ if (not recursive) then
+ return;
+ end
+ return RF_CheckUnderMouse(x, y, frame:GetChildren());
+end
+
+function HANDLE:GetNumPoints()
+ return GetHandleFrame(self):GetNumPoints();
+end
+
+function HANDLE:GetPoint(i)
+ local point, frame, relative, dx, dy = GetHandleFrame(self):GetPoint(i);
+ local handle;
+ if (frame) then
+ handle = FrameHandleMapper(not InCombatLockdown(), frame);
+ end
+ if (handle or not frame) then
+ return point, handle, relative, dx, dy;
+ end
+end
+
+---------------------------------------------------------------------------
+-- "SETTER" methods and actions
+
+function HANDLE:Show(skipAttr)
+ local frame = GetHandleFrame(self);
+ frame:Show();
+ if (not skipAttr) then
+ frame:SetAttribute("statehidden", nil);
+ end
+end
+
+function HANDLE:Hide(skipAttr)
+ local frame = GetHandleFrame(self);
+ frame:Hide();
+ if (not skipAttr) then
+ frame:SetAttribute("statehidden", true);
+ end
+end
+
+function HANDLE:SetID(id)
+ GetHandleFrame(self):SetID(tonumber(id) or 0);
+end
+
+function HANDLE:SetWidth(width)
+ GetHandleFrame(self):SetWidth(tonumber(width));
+end
+
+function HANDLE:SetHeight(height)
+ GetHandleFrame(self):SetHeight(tonumber(height));
+end
+
+function HANDLE:SetScale(scale)
+ GetHandleFrame(self):SetScale(tonumber(scale));
+end
+
+function HANDLE:SetAlpha(alpha)
+ GetHandleFrame(self):SetAlpha(tonumber(alpha));
+end
+
+local _set_points = {
+ TOP=true; BOTTOM=true; LEFT=true; RIGHT=true; CENTER=true;
+ TOPLEFT=true; BOTTOMLEFT=true; TOPRIGHT=true; BOTTOMRIGHT=true;
+};
+
+function HANDLE:ClearAllPoints()
+ GetHandleFrame(self):ClearAllPoints();
+end
+
+function HANDLE:SetPoint(point, relframe, relpoint, xofs, yofs)
+ if (type(relpoint) == "number") then
+ relpoint, xofs, yofs = nil, relpoint, xofs;
+ end
+ if (relpoint == nil) then
+ relpoint = point;
+ end
+ if ((xofs == nil) and (yofs == nil)) then
+ xofs, yofs = 0, 0;
+ else
+ xofs, yofs = tonumber(xofs), tonumber(yofs);
+ end
+ if (not _set_points[point]) then
+ error("Invalid point '" .. tostring(point) .. "'");
+ return;
+ end
+ if (not _set_points[relpoint]) then
+ error("Invalid relative point '" .. tostring(relpoint) .. "'");
+ return;
+ end
+ if (not (xofs and yofs)) then
+ error("Invalid offset");
+ return
+ end
+
+ local frame = GetHandleFrame(self);
+
+ local realrelframe = nil;
+ if (type(relframe) == "userdata") then
+ realrelframe = LOCAL_FrameHandle_Protected_Frames[relframe];
+ if (not realrelframe) then
+ error("Invalid relative frame handle");
+ return;
+ end
+ elseif ((relframe == nil) or (relframe == "$screen")) then
+ realrelframe = nil;
+ elseif (relframe == "$cursor") then
+ local cx, cy = GetCursorPosition();
+ local eff = frame:GetEffectiveScale();
+ xofs = xofs + (cx / eff);
+ yofs = yofs + (cy / eff);
+ relpoint = "BOTTOMLEFT";
+ realrelframe = nil;
+ elseif (relframe == "$parent") then
+ realrelframe = frame:GetParent();
+ else
+ error("Invalid relative frame id '" .. tostring(relframe) .. "'");
+ return;
+ end
+
+ frame:SetPoint(point, realrelframe, relpoint, xofs, yofs);
+end
+
+function HANDLE:SetAllPoints(relframe)
+ local frame = GetHandleFrame(self);
+
+ local realrelframe = nil;
+ if (type(relframe) == "userdata") then
+ realrelframe = LOCAL_FrameHandle_Protected_Frames[relframe];
+ if (not realrelframe) then
+ error("Invalid relative frame handle");
+ return;
+ end
+ elseif ((relframe == nil) or (relframe == "$screen")) then
+ realrelframe = nil;
+ elseif (relframe == "$parent") then
+ realrelframe = frame:GetParent();
+ else
+ error("Invalid relative frame id '" .. tostring(relframe) .. "'");
+ return;
+ end
+
+ frame:SetAllPoints(realrelframe);
+end
+
+function HANDLE:SetAttribute(name, value)
+ if (type(name) ~= "string" or name:match("^_")) then
+ error("Invalid attribute name");
+ return;
+ end
+ local tv = type(value);
+ if (tv ~= "string" and tv ~= "nil" and tv ~= "number"
+ and tv ~= "boolean") then
+ if (not (tv == "userdata" and
+ (LOCAL_FrameHandle_Protected_Frames[value]
+ or LOCAL_FrameHandle_Other_Frames[value]))) then
+ error("Invalid attribute value");
+ return;
+ end
+ end
+ GetHandleFrame(self):SetAttribute(name, value);
+end
+
+function HANDLE:ClearBindings()
+ ClearOverrideBindings(GetHandleFrame(self));
+end
+
+function HANDLE:ClearBinding(key)
+ SetOverrideBinding(GetHandleFrame(self), true, key, nil);
+end
+
+function HANDLE:SetBindingClick(priority, key, name, button)
+ local tn = type(name);
+ if (tn == "userdata") then
+ if (LOCAL_FrameHandle_Protected_Frames[name]
+ or LOCAL_FrameHandle_Other_Frames[name]) then
+ name = name:GetName();
+ tn = type(name);
+ end
+ end
+ if (tn ~= "string" or name:match(":")) then
+ error("Invalid click target name");
+ return;
+ end
+ if ((button ~= nil) and type(button) ~= "string") then
+ error("Invalid button name");
+ return;
+ end
+ SetOverrideBindingClick(GetHandleFrame(self), priority, key, name, button);
+end
+
+function HANDLE:SetBinding(priority, key, action)
+ if (action ~= nil and type(action) ~= "string") then
+ error("Invalid binding action");
+ return;
+ end
+ SetOverrideBinding(GetHandleFrame(self), priority, key, action);
+end
+
+function HANDLE:SetBindingSpell(priority, key, spell)
+ if (type(spell) ~= "string") then
+ error("Invalid binding spell");
+ return;
+ end
+ SetOverrideBindingSpell(GetHandleFrame(self), priority, key, spell);
+end
+
+function HANDLE:SetBindingMacro(priority, key, macro)
+ if (type(macro) == "number") then
+ macro = tostring(macro);
+ elseif (type(macro) ~= "string") then
+ error("Invalid binding macro");
+ return;
+ end
+ SetOverrideBindingMacro(GetHandleFrame(self), priority, key, macro);
+end
+
+function HANDLE:SetBindingItem(priority, key, item)
+ if (type(item) ~= "string") then
+ error("Invalid binding item");
+ return;
+ end
+ SetOverrideBindingItem(GetHandleFrame(self), priority, key, item);
+end
+
+function HANDLE:Raise()
+ GetHandleFrame(self):Raise();
+end
+
+function HANDLE:Lower()
+ GetHandleFrame(self):Lower();
+end
+
+function HANDLE:SetFrameLevel(level)
+ GetHandleFrame(self):SetFrameLevel(tonumber(level));
+end
+
+function HANDLE:SetParent(handle)
+ local parent = nil;
+ if (handle ~= nil) then
+ if (type(handle) ~= "userdata") then
+ error("Invalid frame handle for SetParent");
+ return;
+ end
+ parent = LOCAL_FrameHandle_Protected_Frames[handle];
+ if (not parent) then
+ error("Invalid frame handle for SetParent");
+ return;
+ end
+ end
+
+ GetHandleFrame(self):SetParent(parent);
+end
+
+function HANDLE:RegisterAutoHide(duration)
+ RegisterAutoHide(GetHandleFrame(self), tonumber(duration));
+end
+
+function HANDLE:UnregisterAutoHide()
+ UnregisterAutoHide(GetHandleFrame(self));
+end
+
+function HANDLE:AddToAutoHide(handle)
+ if (type(handle) ~= "userdata") then
+ error("Invalid frame handle for AddToAutoHide");
+ return;
+ end
+
+ local child = LOCAL_FrameHandle_Protected_Frames[handle];
+ if (not child) then
+ error("Invalid frame handle for AddToAutoHide");
+ return;
+ end
+
+ AddToAutoHide(GetHandleFrame(self), child);
+end
+
+---------------------------------------------------------------------------
+-- Type specific methods
+
+function HANDLE:Disable()
+ local frame = GetHandleFrame(self);
+ if (not frame:IsObjectType("Button")) then
+ error("Frame is not a Button");
+ return;
+ end
+ frame:Disable();
+end
+
+function HANDLE:Enable()
+ local frame = GetHandleFrame(self);
+ if (not frame:IsObjectType("Button")) then
+ error("Frame is not a Button");
+ return;
+ end
+ frame:Enable();
+end
diff --git a/reference/FrameXML/RuneFrame.lua b/reference/FrameXML/RuneFrame.lua
new file mode 100644
index 0000000..9550727
--- /dev/null
+++ b/reference/FrameXML/RuneFrame.lua
@@ -0,0 +1,180 @@
+--Readability == win
+local FirstTime = true;
+local RUNETYPE_BLOOD = 1;
+local RUNETYPE_UNHOLY = 2;
+local RUNETYPE_FROST = 3;
+local RUNETYPE_DEATH = 4;
+
+local iconTextures = {};
+iconTextures[RUNETYPE_BLOOD] = "Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight-Blood";
+iconTextures[RUNETYPE_UNHOLY] = "Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight-Unholy";
+iconTextures[RUNETYPE_FROST] = "Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight-Frost";
+iconTextures[RUNETYPE_DEATH] = "Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight-Death";
+
+local runeTextures = {
+ [RUNETYPE_BLOOD] = "Interface\\PlayerFrame\\UI-PlayerFrame-DeathKnight-Blood-Off.tga",
+ [RUNETYPE_UNHOLY] = "Interface\\PlayerFrame\\UI-PlayerFrame-DeathKnight-Death-Off.tga",
+ [RUNETYPE_FROST] = "Interface\\PlayerFrame\\UI-PlayerFrame-DeathKnight-Frost-Off.tga",
+ [RUNETYPE_DEATH] = "Interface\\PlayerFrame\\UI-PlayerFrame-Deathknight-Chromatic-Off.tga",
+}
+
+local runeColors = {
+ [RUNETYPE_BLOOD] = {1, 0, 0},
+ [RUNETYPE_UNHOLY] = {0, 0.5, 0},
+ [RUNETYPE_FROST] = {0, 1, 1},
+ [RUNETYPE_DEATH] = {0.8, 0.1, 1},
+}
+runeMapping = {
+ [1] = "BLOOD",
+ [2] = "UNHOLY",
+ [3] = "FROST",
+ [4] = "DEATH",
+}
+
+function RuneButton_OnLoad (self)
+ RuneFrame_AddRune(RuneFrame, self);
+
+ self.rune = _G[self:GetName().."Rune"];
+ self.fill = _G[self:GetName().."Fill"];
+ self.shine = _G[self:GetName().."ShineTexture"];
+ RuneButton_Update(self);
+end
+
+function RuneButton_OnUpdate (self, elapsed)
+ -- Constants that aren't used elsewhere and are actually constant are happiest inside their functions ;)
+ --local RUNE_HEIGHT = 18;
+ --local MIN_RUNE_ALPHA = .4
+
+ local cooldown = _G[self:GetName().."Cooldown"];
+ local start, duration, runeReady = GetRuneCooldown(self:GetID());
+
+ local displayCooldown = (runeReady and 0) or 1;
+
+ CooldownFrame_SetTimer(cooldown, start, duration, displayCooldown);
+
+ -- if ( not enable ) then
+ -- self.fill:SetHeight(RUNE_HEIGHT * ((GetTime() - start)/duration));
+ -- self.fill:SetTexCoord(0, 1, (1 - ((GetTime() - start)/duration)), 1);
+ -- self.fill:SetAlpha(math.max(MIN_RUNE_ALPHA, (GetTime() - start)/duration));
+ -- else
+
+ if ( runeReady ) then
+ -- self.fill:SetHeight(RUNE_HEIGHT);
+ -- self.fill:SetTexCoord(0, 1, 0, 1);
+ -- self.fill:SetAlpha(1);
+ self:SetScript("OnUpdate", nil);
+ end
+end
+
+function RuneButton_Update (self, rune, dontFlash)
+ rune = rune or self:GetID();
+ local runeType = GetRuneType(rune);
+
+ if ( (not dontFlash) and (runeType) and (runeType ~= self.rune.runeType)) then
+ self.shine:SetVertexColor(unpack(runeColors[runeType]));
+ RuneButton_ShineFadeIn(self.shine)
+ end
+
+ if (runeType) then
+ self.rune:SetTexture(iconTextures[runeType]);
+ -- self.fill:SetTexture(iconTextures[runeType]);
+ self.rune:Show();
+ -- self.fill:Show();
+ self.rune.runeType = runeType;
+ self.tooltipText = _G["COMBAT_TEXT_RUNE_"..runeMapping[runeType]];
+ else
+ self.rune:Hide();
+ -- self.fill:Hide();
+ self.tooltipText = nil;
+ end
+
+end
+
+function RuneButton_OnEnter(self)
+ if ( self.tooltipText ) then
+ GameTooltip:SetOwner(self, "ANCHOR_RIGHT");
+ GameTooltip:SetText(self.tooltipText);
+ GameTooltip:Show();
+ end
+end
+
+function RuneButton_OnLeave(self)
+ GameTooltip:Hide();
+end
+
+function RuneFrame_OnLoad (self)
+ -- Disable rune frame if not a death knight.
+ local _, class = UnitClass("player");
+
+ if ( class ~= "DEATHKNIGHT" ) then
+ self:Hide();
+ end
+
+ self:RegisterEvent("RUNE_POWER_UPDATE");
+ self:RegisterEvent("RUNE_TYPE_UPDATE");
+ self:RegisterEvent("PLAYER_ENTERING_WORLD");
+
+ self:SetScript("OnEvent", RuneFrame_OnEvent);
+
+ self.runes = {};
+end
+
+function RuneFrame_OnEvent (self, event, ...)
+ if ( event == "PLAYER_ENTERING_WORLD" ) then
+ if ( FirstTime ) then
+ RuneFrame_FixRunes(self);
+ FirstTime = false;
+ end
+ for rune in next, self.runes do
+ RuneButton_Update(self.runes[rune], rune, true);
+ end
+ elseif ( event == "RUNE_POWER_UPDATE" ) then
+ local rune, usable = ...;
+ if ( not usable and rune and self.runes[rune] ) then
+ self.runes[rune]:SetScript("OnUpdate", RuneButton_OnUpdate);
+ elseif ( usable and rune and self.runes[rune] ) then
+ self.runes[rune].shine:SetVertexColor(1, 1, 1);
+ RuneButton_ShineFadeIn(self.runes[rune].shine)
+ end
+ elseif ( event == "RUNE_TYPE_UPDATE" ) then
+ local rune = ...;
+ if ( rune ) then
+ RuneButton_Update(self.runes[rune], rune);
+ end
+ end
+end
+
+function RuneFrame_AddRune (runeFrame, rune)
+ tinsert(runeFrame.runes, rune);
+end
+
+function RuneFrame_FixRunes (runeFrame) --We want to swap where frost and unholy appear'
+ local temp;
+
+ temp = runeFrame.runes[3];
+ runeFrame.runes[3] = runeFrame.runes[5];
+ runeFrame.runes[5] = temp;
+
+ temp = runeFrame.runes[4];
+ runeFrame.runes[4] = runeFrame.runes[6];
+ runeFrame.runes[6] = temp;
+end
+
+function RuneButton_ShineFadeIn(self)
+ if self.shining then
+ return
+ end
+ local fadeInfo={
+ mode = "IN",
+ timeToFade = 0.5,
+ finishedFunc = RuneButton_ShineFadeOut,
+ finishedArg1 = self,
+ }
+ self.shining=true;
+ UIFrameFade(self, fadeInfo);
+end
+
+function RuneButton_ShineFadeOut(self)
+ self.shining=false;
+ UIFrameFadeOut(self, 0.5);
+end
\ No newline at end of file
diff --git a/reference/FrameXML/RuneFrame.xml b/reference/FrameXML/RuneFrame.xml
new file mode 100644
index 0000000..ad2b41a
--- /dev/null
+++ b/reference/FrameXML/RuneFrame.xml
@@ -0,0 +1,161 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RaiseFrameLevel(self);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ RuneButton_OnLoad(self);
+
+
+ RuneButton_OnEnter(self, motion);
+
+
+ RuneButton_OnLeave(self, motion);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/FrameXML/SecureHandlerTemplates.xml b/reference/FrameXML/SecureHandlerTemplates.xml
new file mode 100644
index 0000000..b2f2349
--- /dev/null
+++ b/reference/FrameXML/SecureHandlerTemplates.xml
@@ -0,0 +1,124 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SecureHandler_OnClick(self, "_onclick", button, down);
+
+
+
+
+
+
+
+ SecureHandler_OnClick(self, "_ondoubleclick", button);
+
+
+
+
+
+
+
+ SecureHandler_OnDragEvent(self, "_ondragstart", button);
+
+
+ SecureHandler_OnDragEvent(self, "_onreceivedrag");
+
+
+
+
+
+
+
+ SecureHandler_OnSimpleEvent(self, "_onshow");
+
+
+ SecureHandler_OnSimpleEvent(self, "_onhide");
+
+
+
+
+
+
+
+ SecureHandler_OnMouseUpDown(self, "_onmouseup", button);
+
+
+ SecureHandler_OnMouseUpDown(self, "_onmousedown", button);
+
+
+
+
+
+
+
+ SecureHandler_OnLoad(self);
+ self:EnableMouseWheel();
+
+
+ SecureHandler_OnMouseWheel(self, "_onmousewheel", delta);
+
+
+
+
+
+
+
+ if ( motion ) then
+ self:SetAttribute("_entered", true);
+ SecureHandler_OnSimpleEvent(self, "_onenter");
+ end
+
+
+ if ( motion and self:GetAttribute("_entered") ) then
+ self:SetAttribute("_entered", nil);
+ SecureHandler_OnSimpleEvent(self, "_onleave");
+ end
+
+
+
+
diff --git a/reference/FrameXML/SecureHandlers.lua b/reference/FrameXML/SecureHandlers.lua
new file mode 100644
index 0000000..ea68cae
--- /dev/null
+++ b/reference/FrameXML/SecureHandlers.lua
@@ -0,0 +1,910 @@
+-- SecureHandlers.lua (Part of the new Secure Headers implementation)
+--
+-- Lua code to support the various handlers and templates which can execute
+-- code in a secure, but restricted, environment.
+--
+-- Daniel Stephens (iriel@vigilance-committee.org)
+-- Nevin Flanagan (alestane@comcast.net)
+---------------------------------------------------------------------------
+
+-- Local references to things so that they can't be subverted
+local forceinsecure = forceinsecure;
+local geterrorhandler = geterrorhandler;
+local issecure = issecure;
+local newproxy = newproxy;
+local pairs = pairs;
+local pcall = pcall;
+local rawget = rawget;
+local scrub = scrub;
+local securecall = securecall;
+local select = select;
+local tostring = tostring;
+local type = type;
+local wipe = wipe;
+
+local GetCursorInfo = GetCursorInfo;
+local GetTime = GetTime;
+local InCombatLockdown = InCombatLockdown;
+
+local CallRestrictedClosure = CallRestrictedClosure;
+local GetFrameHandle = GetFrameHandle;
+local IsFrameHandle = IsFrameHandle;
+local RestrictedTable_create = rtable.newtable;
+
+-- SoftError(message)
+-- Report an error message without stopping execution
+local function SoftError_inner(message)
+ local func = geterrorhandler();
+ func(message);
+end
+
+local function SoftError(message)
+ securecall(pcall, SoftError_inner, message);
+end
+
+---------------------------------------------------------------------------
+-- Working environments and control handles
+
+local LOCAL_Managed_Control_Frames = {};
+setmetatable(LOCAL_Managed_Control_Frames, { __mode = "v"; });
+
+local LOCAL_CTRL = {};
+local LOCAL_Managed_Control_Proto = newproxy(true);
+do
+ local mt = getmetatable(LOCAL_Managed_Control_Proto);
+ mt.__index = LOCAL_CTRL;
+ mt.__metatable = false;
+end
+
+local LOCAL_Managed_Controls = {};
+setmetatable(LOCAL_Managed_Controls, { __mode = "k"; });
+
+local function ManagedEnvironmentsIndex(t, k)
+ if (not issecure() or type(k) ~= "table") then
+ error("Invalid access of managed environments table");
+ return;
+ end;
+
+ local ownerHandle = GetFrameHandle(k, true);
+ if (not ownerHandle) then
+ error("Invalid access of managed environments table (bad frame)");
+ return;
+ end
+ local _, explicitProtected = ownerHandle:IsProtected();
+ if (not explicitProtected) then
+ error("Invalid access of managed environments table (not protected)");
+ return;
+ end
+
+ local e = RestrictedTable_create();
+ e._G = e;
+ e.owner = ownerHandle;
+ local control = newproxy(LOCAL_Managed_Control_Proto);
+ t[k] = e;
+ LOCAL_Managed_Controls[e] = control;
+ LOCAL_Managed_Control_Frames[control] = k;
+ return e;
+end
+
+local LOCAL_Managed_Environments = {};
+setmetatable(LOCAL_Managed_Environments,
+ {
+ __index = ManagedEnvironmentsIndex,
+ __mode = "k",
+ });
+
+function GetManagedEnvironment(envKey)
+ return rawget(LOCAL_Managed_Environments, envKey);
+end
+
+---------------------------------------------------------------------------
+-- Standard invocation for header executions and child executions
+
+local function SecureHandler_Self_Execute(self, signature, body, ...)
+ if (type(body) ~= "string") then return; end
+
+ local selfHandle = GetFrameHandle(self, true);
+ if (not selfHandle) then
+ error("Invalid 'self' frame handle");
+ return;
+ end
+
+ local environment = LOCAL_Managed_Environments[self];
+ local controlHandle = LOCAL_Managed_Controls[environment];
+
+ return CallRestrictedClosure(signature, environment, controlHandle,
+ body, selfHandle, ...);
+end
+
+local function SecureHandler_Other_Execute(header, self, signature, body, ...)
+ if (type(body) ~= "string") then return; end
+
+ local selfHandle = GetFrameHandle(self, true);
+ if (not selfHandle) then return; end
+
+ local environment = LOCAL_Managed_Environments[header];
+ local controlHandle = LOCAL_Managed_Controls[environment];
+ return CallRestrictedClosure(signature, environment, controlHandle,
+ body, selfHandle, ...);
+end
+
+---------------------------------------------------------------------------
+-- Script handlers for various header templates
+
+function SecureHandler_OnSimpleEvent(self, snippetAttr)
+ local body = self:GetAttribute(snippetAttr);
+ if (body) then
+ SecureHandler_Self_Execute(self, "self", body);
+ end
+end
+
+function SecureHandler_OnClick(self, snippetAttr, button, down)
+ local body = self:GetAttribute(snippetAttr);
+ if (body) then
+ SecureHandler_Self_Execute(self, "self,button,down",
+ body, button, down);
+ end
+end
+
+function SecureHandler_OnMouseUpDown(self, snippetAttr, button)
+ local body = self:GetAttribute(snippetAttr);
+ if (body) then
+ SecureHandler_Self_Execute(self, "self,button", body, button);
+ end
+end
+
+function SecureHandler_OnMouseWheel(self, snippetAttr, delta)
+ local body = self:GetAttribute(snippetAttr);
+ if (body) then
+ SecureHandler_Self_Execute(self, "self,delta", body, delta);
+ end
+end
+
+function SecureHandler_StateOnAttributeChanged(self, name, value)
+ local stateid = name:match("^state%-(.+)");
+ if (stateid) then
+ local body = self:GetAttribute("_onstate-" .. stateid);
+ if (body) then
+ SecureHandler_Self_Execute(self, "self,stateid,newstate",
+ body, stateid, value);
+ end
+ end
+end
+
+function SecureHandler_AttributeOnAttributeChanged(self, name, value)
+ if (name:match("^_")) then
+ return;
+ end;
+
+ local body = self:GetAttribute("_onattributechanged");
+ if (body) then
+ SecureHandler_Self_Execute(self, "self,name,value",
+ body, name, value);
+ end
+end
+
+local function PickupAny(kind, target, detail, ...)
+ if (kind == "clear") then
+ ClearCursor();
+ kind, target, detail = target, detail, ...;
+ end
+
+ if kind == 'action' then
+ PickupAction(target);
+ elseif kind == 'bag' then
+ PickupBagFromSlot(target)
+ elseif kind == 'bagslot' then
+ PickupContainerItem(target, detail)
+ elseif kind == 'inventory' then
+ PickupInventoryItem(target)
+ elseif kind == 'item' then
+ PickupItem(target)
+ elseif kind == 'macro' then
+ PickupMacro(target)
+ elseif kind == 'merchant' then
+ PickupMerchantItem(target)
+ elseif kind == 'petaction' then
+ PickupPetAction(target)
+ elseif kind == 'money' then
+ PickupPlayerMoney(target)
+ elseif kind == 'spell' then
+ PickupSpell(target, detail)
+ elseif kind == 'companion' then
+ PickupCompanion(target, detail)
+ elseif kind == 'equipmentset' then
+ PickupEquipmentSet(target);
+ end
+end
+
+function SecureHandler_OnDragEvent(self, snippetAttr, button)
+ local body = self:GetAttribute(snippetAttr);
+ if (body) then
+ PickupAny( SecureHandler_Self_Execute(self,
+ "self,button,kind,value,...",
+ body, button, GetCursorInfo()) );
+ end
+end
+
+---------------------------------------------------------------------------
+-- "Wrap" handlers for alternate dispatch on various conditions
+-- such as OnClick, used for child handlers
+--
+-- All wrappers use ... to make sure the original handler gets all of
+-- its arguments even if WoW is updated and this file is missed.
+
+-- 'Marker object' used to trigger unwrap of wrap closure
+local MAGIC_UNWRAP = newproxy();
+
+local LOCAL_Wrapped_Handlers = {};
+setmetatable(LOCAL_Wrapped_Handlers, { __mode = "k"; });
+
+-- Create a closure to hold the data for a specific wrap
+local function CreateWrapClosure(handler, header, preBody, postBody)
+ local wrap;
+ if (postBody) then
+ wrap = function(self, ...)
+ if (self == MAGIC_UNWRAP) then
+ return header, preBody, postBody;
+ end
+ return handler(self, header, preBody, postBody, wrap, ...);
+ end
+ else
+ wrap = function(self, ...)
+ if (self == MAGIC_UNWRAP) then
+ return header, preBody, nil;
+ end
+ return handler(self, header, preBody, nil, wrap, ...);
+ end
+ end
+ return wrap;
+end
+
+-- Save a hander against a specific wrap (securecall'ed for protection)
+local function SaveWrapHandler(frame, script, wrap)
+ LOCAL_Wrapped_Handlers[wrap] = frame:GetScript(script) or false;
+end
+
+-- Restore a hander from a specific wrap (securecall'ed for protection)
+local function RestoreWrapHandler(frame, script, wrap)
+ local old = LOCAL_Wrapped_Handlers[wrap];
+ if (old == nil) then return; end
+ if (old == false) then old = nil; end
+ frame:SetScript(script, old);
+ return true;
+end
+
+-- Create a new handler wrapper and configure it
+--
+-- frame - the frame that has the script
+-- script - the script name (such as OnClick)
+-- header - the secure header that owns the 'wrap'
+-- handler - the handler function that will process the event
+-- preBody - the snippet to execute before the wrapped handler
+-- postBody (optional) - the snippet to execute after the wrapped handler
+--
+-- The resulting closure is called as (self, ...)
+--
+-- The handler is invoked with (self, header, preBody, postBody, wrap, ...)
+-- where 'wrap' is the wrap closure itself (also the key to the wrapped
+-- handlers table)
+local function CreateWrapper(frame, script, header, handler, preBody, postBody)
+ local wrap = CreateWrapClosure(handler, header, preBody, postBody);
+ securecall(SaveWrapHandler, frame, script, wrap);
+ return wrap;
+end
+
+-- Reverse the wrap process, restoring the wrapped handler (does nothing
+-- if the current handler is not wrapped)
+local function RemoveWrapper(frame, script)
+ local wrap = frame:GetScript(script);
+
+ if (not issecure()) then
+ -- not valid
+ return;
+ end
+
+ if (not securecall(RestoreWrapHandler, frame, script, wrap)) then
+ -- not valid
+ return;
+ end
+
+ -- Extract header, preBody, postBody
+ return wrap(MAGIC_UNWRAP);
+end
+
+-- Invoke the wrapped handler for a wrapper, passing in all arguments
+local function SafeCallWrappedHandler(frame, wrap, ...)
+ local handler = LOCAL_Wrapped_Handlers[wrap];
+ if (type(handler) == "function") then
+ local ok, err = pcall(handler, frame, ...);
+ if (not ok) then
+ SoftError(err);
+ end
+ end
+end
+
+-- Check that a given frame is eligible for wrapped execution
+local function IsWrapEligible(frame)
+ return (not InCombatLockdown()) or frame:IsProtected();
+end
+
+-- Wrapper handler for clicks
+local function Wrapped_Click(self, header, preBody, postBody, wrap,
+ button, down, ...)
+ local message, newbutton;
+
+ if ( IsWrapEligible(self) ) then
+ newbutton, message =
+ SecureHandler_Other_Execute(header, self,
+ "self,button,down", preBody,
+ button, down);
+ if (newbutton == false) then
+ return;
+ end
+ if (newbutton) then
+ button = tostring(newbutton);
+ end
+ end
+
+ securecall(SafeCallWrappedHandler, self, wrap, button, down, ...);
+
+ if (postBody and message ~= nil) then
+ SecureHandler_Other_Execute(header, self,
+ "self,message,button,down",
+ postBody,
+ message, button, down);
+ end;
+end
+
+local function Wrapped_OnEnter(self, header, preBody, postBody, wrap,
+ motion, ...)
+ local allow, message;
+ if ( motion ) then
+ self:SetAttribute("_wrapentered", true);
+ if ( IsWrapEligible(self) ) then
+ allow, message =
+ SecureHandler_Other_Execute(header, self, "self",
+ preBody);
+ end
+
+ if (allow == false) then
+ return;
+ end
+ end
+
+ securecall(SafeCallWrappedHandler, self, wrap, motion, ...);
+
+ if (postBody and message ~= nil) then
+ SecureHandler_Other_Execute(header, self, "self,message",
+ postBody, message);
+ end
+end
+
+local function Wrapped_OnLeave(self, header, preBody, postBody, wrap,
+ motion, ...)
+ local allow, message;
+ if ( motion and self:GetAttribute("_wrapentered")) then
+ self:SetAttribute("_wrapentered", nil);
+ if ( IsWrapEligible(self) ) then
+ allow, message =
+ SecureHandler_Other_Execute(header, self, "self",
+ preBody);
+ if (allow == false) then
+ return;
+ end
+ end
+ end
+
+ securecall(SafeCallWrappedHandler, self, wrap, motion, ...);
+
+ if (postBody and message ~= nil) then
+ SecureHandler_Other_Execute(header, self, "self,message",
+ postBody, message);
+ end
+end
+
+local function CreateSimpleWrapper(beforeSignature, afterSignature)
+ return function(self, header, preBody, postBody, wrap,
+ ...)
+ local allow, message;
+ if ( IsWrapEligible(self) ) then
+ allow, message =
+ SecureHandler_Other_Execute(header,
+ self, beforeSignature,
+ preBody, ...);
+ if (allow == false) then
+ return;
+ end
+ end
+
+ securecall(SafeCallWrappedHandler, self, wrap, ...);
+
+ if ( postBody and message ~= nil ) then
+ SecureHandler_Other_Execute(header,
+ self, afterSignature,
+ postBody, message, ...);
+ end
+ end;
+end
+
+local Wrapped_ShowHide = CreateSimpleWrapper("self", "self,message");
+
+local Wrapped_MouseWheel = CreateSimpleWrapper("self,offset",
+ "self,message,offset");
+
+local function Wrapped_Drag(self, header, preBody, postBody, wrap, ...)
+ local message;
+ if ( IsWrapEligible(self) ) then
+ local selfHandle = GetFrameHandle(self, true);
+ if (selfHandle) then
+ local environment = LOCAL_Managed_Environments[header];
+ local controlHandle = LOCAL_Managed_Controls[environment];
+ local button = ...;
+ local type, target, x1, x2, x3 =
+ CallRestrictedClosure("self,button,kind,value,...",
+ environment,
+ controlHandle, preBody,
+ selfHandle, button,
+ GetCursorInfo());
+ if (type == false) then
+ return;
+ elseif (type == "message") then
+ message = target;
+ elseif (type) then
+ PickupAny(type, target, x1, x2, x3);
+ return;
+ end
+ end
+ end
+
+ securecall(SafeCallWrappedHandler, self, wrap, ...);
+
+ if ( postBody and message ~= nil ) then
+ SecureHandler_Other_Execute(header, self,
+ "self,message,button",
+ postBody, message, ...);
+ end
+end
+
+local function Wrapped_Attribute(self, header, preBody, postBody, wrap,
+ name, value, ...)
+ local allow, message;
+ if ( (not name:match("^_")) and IsWrapEligible(self) ) then
+ allow, message =
+ SecureHandler_Other_Execute(header, self,
+ "self,name,value", preBody,
+ name, value);
+ if (allow == false) then
+ return;
+ end
+ end
+
+ securecall(SafeCallWrappedHandler, self, wrap, name, value, ...);
+
+ if ( postBody and message ~= nil ) then
+ SecureHandler_Other_Execute(header, self,
+ "self,message,name,value",
+ postBody, message, name, value);
+ end
+end
+
+local LOCAL_Wrap_Handlers = {
+ OnClick = Wrapped_Click;
+ OnDoubleClick = Wrapped_Click;
+ PreClick = Wrapped_Click;
+ PostClick = Wrapped_Click;
+
+ OnEnter = Wrapped_OnEnter;
+ OnLeave = Wrapped_OnLeave;
+
+ OnShow = Wrapped_ShowHide;
+ OnHide = Wrapped_ShowHide;
+
+ OnDragStart = Wrapped_Drag;
+ OnReceiveDrag = Wrapped_Drag;
+
+ OnMouseWheel = Wrapped_MouseWheel;
+
+ OnAttributeChanged = Wrapped_Attribute;
+};
+
+---------------------------------------------------------------------------
+-- External API helpers, all are driven off a single control frame
+-- using OnAttributeChanged.
+
+-- Quick sanity check that a frame looks like a frame
+local function IsValidFrame(frame)
+ return (type(frame) == "table") and (type(frame[0]) == "userdata");
+end
+
+-- 'Action' handler for most of the API methods, invoked somewhat indirectly
+-- via attribute sets so as to allow secure execution (doesn't work from
+-- combat for user code (or indeed for any code))
+local function API_OnAttributeChanged(self, name, value)
+ if (value == nil) then
+ return;
+ end
+
+ if (InCombatLockdown()) then
+ -- This shouldn't ever happen because API frame is protected,
+ -- but just in case someone does something silly...
+ error("Cannot use SecureHandlers API during combat");
+ return;
+ end
+
+
+ -- _execute runs code in the context of a header
+ if (name == "_execute") then
+ local frame = self:GetAttribute("_apiframe");
+ self:SetAttribute("_execute", nil);
+ if (type(value) ~= "string") then
+ error("Invalid execute body");
+ return;
+ end
+ -- Most validation is performed by SecureHandler_Self_Execute
+ SecureHandler_Self_Execute(frame, "self", value);
+ return;
+ end
+
+ -- _wrap wraps a script handler in a secure wrapper
+ if (name == "_wrap") then
+ local frame = self:GetAttribute("_apiframe");
+ local header = self:GetAttribute("_apiheader");
+ local preBody = self:GetAttribute("_apiprebody");
+ local postBody = self:GetAttribute("_apipostbody");
+ self:SetAttribute("_wrap", nil);
+ if (type(value) ~= "string") then
+ error("Invalid wrap script id");
+ end
+ if (not IsValidFrame(frame)) then
+ error("Invalid wrap frame");
+ end
+ if (not IsValidFrame(header)) then
+ error("Invalid header frame");
+ end
+ if (type(preBody) ~= "string") then
+ error("Invalid pre-handler body");
+ end
+ if (postBody ~= nil and type(postBody) ~= "string") then
+ error("Invalid post-handler body");
+ end
+ if (not select(2, header:IsProtected())) then
+ error("Header frame must be explicitly protected");
+ end
+ local script = value;
+ if (not frame:HasScript(script)) then
+ error("Frame does not support script '" .. script .. "'");
+ end
+ if (not issecure()) then
+ error("Wrap frame cannot be used");
+ end
+ local handler = LOCAL_Wrap_Handlers[value];
+ if (not handler) then
+ error("Unsupported script type '" .. value .. "'");
+ end
+ local wrapper = CreateWrapper(frame, value, header,
+ handler, preBody, postBody);
+ frame:SetScript(script, wrapper);
+ return;
+ end
+
+ -- _unwrap restores a previously wrapped handler
+ if (name == "_unwrap") then
+ local frame = self:GetAttribute("_apiframe");
+ local data = self:GetAttribute("_apidata");
+ if (data) then
+ self:SetAttribute("_apidata", nil);
+ end
+ self:SetAttribute("_unwrap", nil);
+ if (type(value) ~= "string") then
+ error("Invalid unwrap script id");
+ end
+ if (not IsValidFrame(frame)) then
+ error("Invalid unwrap frame");
+ end
+ local script = value;
+ if (not frame:HasScript(script)) then
+ error("Frame does not support script '" .. script .. "'");
+ end
+ local header, preBody, postBody = RemoveWrapper(frame, script);
+ if (type(data) == "table") then
+ forceinsecure();
+ wipe(data);
+ data[1] = frame;
+ data[2] = script;
+ data[3] = header;
+ data[4] = preBody;
+ data[5] = postBody;
+ end
+ return;
+ end
+
+ -- _frame-