diff --git a/Wow.exe b/Wow.exe index 46870af..fb862d7 100644 Binary files a/Wow.exe and b/Wow.exe differ diff --git a/make_modes_in_exe.py b/make_modes_in_exe.py new file mode 100644 index 0000000..fdbf1a6 --- /dev/null +++ b/make_modes_in_exe.py @@ -0,0 +1,339 @@ +""" +Wow.exe binary patcher for MoonWell custom features. + +Patches: + 1. Script_CreateCharacter: reads lua_tonumber(L, 2) as outfitId, + stores to global, passes to CMSG_CHAR_CREATE packet instead of 0. + 2. GetCharacterInfo: adds 11th return value — charFlags as a Lua number, + read from struct_offset +0x170 (same field as ghost flag 0x2000). + Lua checks bit 0x40000000 (CHARACTER_FLAG_UNK31) for traitor status. + +Usage: + python make_modes_in_exe.py + +A backup (Wow.exe.bak) is created before patching. +""" + +import struct +import sys +import shutil +from pathlib import Path + + +# --------------------------------------------------------------------------- +# PE helpers +# --------------------------------------------------------------------------- + +def _u16(data, off): + return struct.unpack_from("= size consecutive CC bytes after search_from_va.""" + text = next((s for s in sections if s[0] == ".text"), None) + if not text is None: + _, va0, vs, ro, rs = text + else: + raise ValueError("No .text section") + + rva_start = max(search_from_va - image_base, va0) + off_start = ro + (rva_start - va0) + off_end = ro + min(vs, rs) + + i = off_start + while i <= off_end - size: + if data[i] != 0xcc: + i += 1 + continue + j = i + while j < off_end and data[j] == 0xcc: + j += 1 + if j - i >= size: + return offset_to_va(i, sections, image_base) + i = j + raise ValueError(f"No {size}-byte code cave found from VA 0x{search_from_va:08x}") + + +# --------------------------------------------------------------------------- +# Patch 1 & 2: outfitId in CMSG_CHAR_CREATE (fixed addresses) +# --------------------------------------------------------------------------- + +_FIXED_PATCHES = [ + ( + 0x004e0c60, + bytes.fromhex( + "558bec568b75086a0156e8f1d23600" + "83c40885c0740d6a006a0156e860d4" + "360083c40c6a006a0156e853d43600" + "50e8edf6ffff83c41033c05e5dc3cc" + "cccccccc" + ), + bytes.fromhex( + "558bec568b75086a0256e8c1d33600" + "db1c245883c404a221 42ac006a006a" + "0156e85bd4360050e8f5f6ffff83c4" + "1033c05e5dc38855f08a1521 42ac00" + "8855f4c3" + ).replace(b" ", b""), # spaces stripped for readability + "Script_CreateCharacter: read outfitId from Lua arg 2 -> global", + ), + ( + 0x004e042f, + bytes.fromhex("8855f0c645f400"), + bytes.fromhex("e85f08000090 90").replace(b" ", b""), + "Packet builder: CALL helper -> load face + outfitId from global", + ), +] + +# --------------------------------------------------------------------------- +# Patch 3: GetCharacterInfo — add 11th return value (charFlags as number) +# --------------------------------------------------------------------------- +# +# Assembly context (FUN_004e3170 epilogue, valid branch): +# +# 004e31cd 56 PUSH ESI ← saves caller's ESI +# 004e31ce 8b f0 MOV ESI, EAX ← ESI = char struct ptr +# ... [function body — ESI used throughout for char struct] ... +# 004e32e5 8b 8e 70010000 MOV ECX, [ESI+0x170] ← charFlags (ghost flag check) +# ... +# 004e332d 83 c4 2c ADD ESP, 0x2c ← clean accumulated args ← PATCH HERE +# 004e3330 5e POP ESI ← restores caller's ESI (ESI valid until here) +# 004e3331 b8 0a 00 00 00 MOV EAX, 0xa (dead after patch) +# 004e3336 5f POP EDI ← JMP back target +# 004e3337 8b e5 MOV ESP, EBP +# 004e3339 5d POP EBP +# 004e333a c3 RET +# +# KEY: ESI = char struct ptr up to and including ADD ESP,0x2c (004e332d). +# After POP ESI (004e3330) it is caller's ESI — NOT char struct. +# Previous approach: CALL cave at 004e3331 (after POP ESI) -> ESI already wrong. +# Fix: JMP cave at 004e332d (before POP ESI) -> ESI still valid in cave. +# +# New approach: patch 5 bytes at 004e332d with JMP cave. +# Old bytes: 83 c4 2c (ADD ESP,0x2c) + 5e (POP ESI) + b8 (MOV EAX first byte) +# New bytes: e9 XX XX XX XX JMP cave +# The 4 dead bytes at 004e3332-004e3335 are unreachable. +# +# Cave (30 bytes, found automatically via CC scan over entire .text): +# 83 ec 08 SUB ESP, 8 ; make room for double +# db 86 70 01 00 00 FILD [ESI+0x170] ; load charFlags into FPU (ESI valid here!) +# dd 1c 24 FSTP [ESP] ; store as double +# 57 PUSH EDI ; lua_State* L +# e8 XX XX XX XX CALL FUN_0084e2a0 ; lua_pushnumber(L, charFlags) +# 83 c4 38 ADD ESP, 0x38 ; merged: own 0xc + stolen 0x2c +# 5e POP ESI ; stolen: restore caller's ESI +# 6a 0b PUSH 0xb ; \ EAX = 11 in 3 bytes +# 58 POP EAX ; / (vs MOV EAX,0xb = 5 bytes) +# e9 XX XX XX XX JMP 004e3336 ; continue epilogue (POP EDI ...) +# +# Lua code reads info[11] and checks bit 0x40000000 (CHARACTER_FLAG_UNK31 = traitor). +# charFlags confirmed at [ESI+0x170]: same field used for ghost flag (AND ECX,0x2000). + +_CHARINFO_PATCH_VA = 0x004e332d # ADD ESP,0x2c (5 bytes including POP ESI + MOV EAX[0]) +_CHARINFO_JMPBACK_VA = 0x004e3336 # POP EDI — resume epilogue after cave +_CHARINFO_CAVE_SIZE = 30 +_CHARINFO_CAVE_SEARCH_FROM = 0x00401000 # search entire .text for first 35-byte CC block +_LUA_PUSHNUMBER_VA = 0x0084e2a0 # lua_pushnumber + + +def _build_charinfo_patches(data, sections, image_base): + """ + Build the dynamic GetCharacterInfo patches. + Returns list of (va, old_bytes, new_bytes, description), [] if already applied, + or None on unrecoverable error. + """ + patch_off = va_to_offset(_CHARINFO_PATCH_VA, sections, image_base) + current = bytes(data[patch_off:patch_off + 5]) + + # Already patched with new JMP approach? + if current[0:1] == b"\xe9": + return [] + + # Verify first 4 bytes look like the epilogue (ADD ESP,0x2c + POP ESI). + # Accept both unpatched (b8 at [4]) and old-CALL-patched (e8 at [4]) states. + if current[0:4] != bytes.fromhex("83c42c5e"): + print(f"[WARN] 0x{_CHARINFO_PATCH_VA:08x}: unexpected bytes {current.hex(' ')}") + print(" Expected ADD ESP,0x2c + POP ESI at this address.") + print(" Restore Wow.exe.bak and re-run.") + return None + + old_b = current # exact 5 bytes currently in file (b8 or e8 at index 4) + + # Find a 35-byte code cave in .text + cave_va = find_cave(data, sections, image_base, + _CHARINFO_CAVE_SIZE, _CHARINFO_CAVE_SEARCH_FROM) + + # Cave layout offsets (30 bytes total): + # 0 SUB ESP,8 (3) + # 3 FILD [ESI+0x170] (6) + # 9 FSTP [ESP] (3) + # 12 PUSH EDI (1) + # 13 CALL lua_pushnumber (5) — next instr at 18 + # 18 ADD ESP, 0x38 (3) merged: own 0xc + stolen 0x2c + # 21 POP ESI (1) stolen + # 22 PUSH 0xb (2) \ shorter than MOV EAX,0xb (5 bytes) + # 24 POP EAX (1) / + # 25 JMP 004e3336 (5) — next instr at cave_va+30 + call_rel = _LUA_PUSHNUMBER_VA - (cave_va + 18) + jmp_back_rel = _CHARINFO_JMPBACK_VA - (cave_va + 30) + + cave_bytes = ( + bytes.fromhex("83ec08") # SUB ESP, 8 (3) + + bytes.fromhex("db8670010000") # FILD [ESI+0x170] (6) + + bytes.fromhex("dd1c24") # FSTP [ESP] (3) + + bytes.fromhex("57") # PUSH EDI (1) + + b"\xe8" + struct.pack(" EAX=11 (1) + + b"\xe9" + struct.pack("") + sys.exit(1) + + exe_path = Path(sys.argv[1]) + if not exe_path.exists(): + print(f"Error: file not found: {exe_path}") + sys.exit(1) + + data = bytearray(exe_path.read_bytes()) + image_base, sections = parse_pe_sections(data) + + print(f"Image base: 0x{image_base:08x}") + print(f"Sections: {len(sections)}") + for n, va, vs, ro, rs in sections: + print(f" {n:8s} VA=0x{va:08x} VSize=0x{vs:08x} Raw=0x{ro:08x} RSize=0x{rs:08x}") + print() + + charinfo_patches = _build_charinfo_patches(data, sections, image_base) + if charinfo_patches is None: + sys.exit(1) + all_patches = list(_FIXED_PATCHES) + charinfo_patches + + # Verify all first + ok = True + for va, old_b, new_b, desc in all_patches: + off = va_to_offset(va, sections, image_base) + cur = bytes(data[off:off + len(old_b)]) + if cur == new_b: + print(f"[SKIP] 0x{va:08x}: already patched — {desc}") + elif cur == old_b: + print(f"[ OK ] 0x{va:08x}: verified — {desc}") + else: + print(f"[FAIL] 0x{va:08x}: {desc}") + print(f" Expected: {old_b.hex(' ')}") + print(f" Found: {cur.hex(' ')}") + ok = False + + if not ok: + print("\nByte mismatch — aborting. Is this the correct Wow.exe (3.3.5a build 12340)?") + sys.exit(1) + + # Backup + bak = exe_path.with_suffix(".exe.bak") + if not bak.exists(): + shutil.copy2(exe_path, bak) + print(f"\nBackup: {bak}") + else: + print(f"\nBackup already exists: {bak}") + + # Apply + applied = 0 + for va, old_b, new_b, desc in all_patches: + off = va_to_offset(va, sections, image_base) + cur = bytes(data[off:off + len(old_b)]) + if cur == new_b: + continue + data[off:off + len(old_b)] = new_b + applied += 1 + print(f"[PATCH] 0x{va:08x}: {desc}") + + if applied == 0: + print("\nNothing to patch.") + else: + exe_path.write_bytes(data) + print(f"\n{applied} patch(es) written to {exe_path}") + + print("Done!") + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/patch-ruRU-4/Interface/GlueXML/AccountLogin.lua b/patch-ruRU-4/Interface/GlueXML/AccountLogin.lua deleted file mode 100644 index 95963b1..0000000 --- a/patch-ruRU-4/Interface/GlueXML/AccountLogin.lua +++ /dev/null @@ -1,742 +0,0 @@ -FADE_IN_TIME = 2; -DEFAULT_TOOLTIP_COLOR = {0.8, 0.8, 0.8, 0.09, 0.09, 0.09}; -MAX_PIN_LENGTH = 10; - -function AccountLogin_OnLoad(self) - TOSFrame.noticeType = "EULA"; - - self:RegisterEvent("SHOW_SERVER_ALERT"); - self:RegisterEvent("SHOW_SURVEY_NOTIFICATION"); - self:RegisterEvent("CLIENT_ACCOUNT_MISMATCH"); - self:RegisterEvent("CLIENT_TRIAL"); - self:RegisterEvent("SCANDLL_ERROR"); - self:RegisterEvent("SCANDLL_FINISHED"); - - local versionType, buildType, version, internalVersion, date = GetBuildInfo(); - AccountLoginVersion:SetFormattedText(VERSION_TEMPLATE, versionType, version, internalVersion, buildType, date); - - -- Color edit box backdrops - local backdropColor = DEFAULT_TOOLTIP_COLOR; - AccountLoginAccountEdit:SetBackdropBorderColor(backdropColor[1], backdropColor[2], backdropColor[3]); - AccountLoginAccountEdit:SetBackdropColor(backdropColor[4], backdropColor[5], backdropColor[6]); - AccountLoginPasswordEdit:SetBackdropBorderColor(backdropColor[1], backdropColor[2], backdropColor[3]); - AccountLoginPasswordEdit:SetBackdropColor(backdropColor[4], backdropColor[5], backdropColor[6]); - AccountLoginTokenEdit:SetBackdropBorderColor(backdropColor[1], backdropColor[2], backdropColor[3]); - AccountLoginTokenEdit:SetBackdropColor(backdropColor[4], backdropColor[5], backdropColor[6]); - TokenEnterDialogBackgroundEdit:SetBackdropBorderColor(backdropColor[1], backdropColor[2], backdropColor[3]); - TokenEnterDialogBackgroundEdit:SetBackdropColor(backdropColor[4], backdropColor[5], backdropColor[6]); - - self:SetCamera(0); - self:SetSequence(0); - - if (IsStreamingTrial()) then - AccountLoginCinematicsButton:Disable(); - AccountLogin:SetModel("Interface\\Glues\\Models\\UI_MainMenu\\UI_MainMenu.m2"); - else - AccountLogin:SetModel("Interface\\Glues\\Models\\UI_RS_NightElf\\UI_RS_NightElf.m2"); - end -end - -function AccountLogin_OnShow(self) - self:SetSequence(0); - PlayGlueMusic(CurrentGlueMusic); - PlayGlueAmbience(GlueAmbienceTracks["DARKPORTAL"], 4.0); - - -- Try to show the EULA or the TOS - AccountLogin_ShowUserAgreements(); - - local serverName = GetServerName(); - if(serverName) then - AccountLoginRealmName:SetText(serverName); - else - AccountLoginRealmName:Hide() - end - - local accountName = GetSavedAccountName(); - - AccountLoginAccountEdit:SetText(accountName); - AccountLoginPasswordEdit:SetText(""); - AccountLoginTokenEdit:SetText(""); - if ( accountName and accountName ~= "" and GetUsesToken() ) then - AccountLoginTokenEdit:Show() - else - AccountLoginTokenEdit:Hide() - end - - AccountLogin_SetupAccountListDDL(); - - if ( accountName == "" ) then - AccountLogin_FocusAccountName(); - else - AccountLogin_FocusPassword(); - end - - if( IsTrialAccount() ) then - AccountLoginUpgradeAccountButton:Show(); - else - AccountLoginUpgradeAccountButton:Hide(); - end - - ACCOUNT_MSG_NUM_AVAILABLE = 0; - ACCOUNT_MSG_PRIORITY = 0; - ACCOUNT_MSG_HEADERS_LOADED = false; - ACCOUNT_MSG_BODY_LOADED = false; - ACCOUNT_MSG_CURRENT_INDEX = nil; -end - -function AccountLogin_OnHide(self) - --Stop the sounds from the login screen (like the dragon roaring etc) - StopAllSFX( 1.0 ); - if ( not AccountLoginSaveAccountName:GetChecked() ) then - SetSavedAccountList(""); - end -end - -function AccountLogin_FocusPassword() - AccountLoginPasswordEdit:SetFocus(); -end - -function AccountLogin_FocusAccountName() - AccountLoginAccountEdit:SetFocus(); -end - -function AccountLogin_OnKeyDown(key) - if ( key == "ESCAPE" ) then - if ( ConnectionHelpFrame:IsShown() ) then - ConnectionHelpFrame:Hide(); - AccountLoginUI:Show(); - elseif ( SurveyNotificationFrame:IsShown() ) then - -- do nothing - else - AccountLogin_Exit(); - end - elseif ( key == "ENTER" ) then - if ( not TOSAccepted() ) then - return; - elseif ( TOSFrame:IsShown() or ConnectionHelpFrame:IsShown() ) then - return; - elseif ( SurveyNotificationFrame:IsShown() ) then - AccountLogin_SurveyNotificationDone(1); - end - AccountLogin_Login(); - elseif ( key == "PRINTSCREEN" ) then - Screenshot(); - end -end - -function AccountLogin_OnEvent(event, arg1, arg2, arg3) - if ( event == "SHOW_SERVER_ALERT" ) then - ServerAlertText:SetText(arg1); - ServerAlertFrame:Show(); - elseif ( event == "SHOW_SURVEY_NOTIFICATION" ) then - AccountLogin_ShowSurveyNotification(); - elseif ( event == "CLIENT_ACCOUNT_MISMATCH" ) then - local accountExpansionLevel = arg1; - local installationExpansionLevel = arg2; - if ( accountExpansionLevel == 1 ) then - GlueDialog_Show("CLIENT_ACCOUNT_MISMATCH", CLIENT_ACCOUNT_MISMATCH_BC); - else - GlueDialog_Show("CLIENT_ACCOUNT_MISMATCH", CLIENT_ACCOUNT_MISMATCH_LK); - end - elseif ( event == "CLIENT_TRIAL" ) then - GlueDialog_Show("CLIENT_TRIAL"); - elseif ( event == "SCANDLL_ERROR" ) then - GlueDialog:Hide(); - ScanDLLContinueAnyway(); - AccountLoginUI:Show(); - elseif ( event == "SCANDLL_FINISHED" ) then - if ( arg1 == "OK" ) then - GlueDialog:Hide(); - AccountLoginUI:Show(); - else - AccountLogin.hackURL = _G["SCANDLL_URL_"..arg1]; - AccountLogin.hackName = arg2; - AccountLogin.hackType = arg1; - local formatString = _G["SCANDLL_MESSAGE_"..arg1]; - if ( arg3 == 1 ) then - formatString = _G["SCANDLL_MESSAGE_HACKNOCONTINUE"]; - end - local msg = format(formatString, AccountLogin.hackName, AccountLogin.hackURL); - if ( arg3 == 1 ) then - GlueDialog_Show("SCANDLL_HACKFOUND_NOCONTINUE", msg); - else - GlueDialog_Show("SCANDLL_HACKFOUND", msg); - end - PlaySoundFile("Sound\\Creature\\MobileAlertBot\\MobileAlertBotIntruderAlert01.wav"); - end - end -end - -function AccountLogin_Login() - PlaySound("gsLogin"); - DefaultServerLogin(AccountLoginAccountEdit:GetText(), AccountLoginPasswordEdit:GetText()); - AccountLoginPasswordEdit:SetText(""); - - if ( AccountLoginSaveAccountName:GetChecked() ) then - SetSavedAccountName(AccountLoginAccountEdit:GetText()); - else - SetSavedAccountName(""); - SetUsesToken(false); - end -end - -function AccountLogin_TOS() - if ( not GlueDialog:IsShown() ) then - PlaySound("gsLoginNewAccount"); - AccountLoginUI:Hide(); - TOSFrame:Show(); - TOSScrollFrameScrollBar:SetValue(0); - TOSScrollFrame:Show(); - TOSFrameTitle:SetText(TOS_FRAME_TITLE); - TOSText:Show(); - end -end - -function AccountLogin_ManageAccount() - PlaySound("gsLoginNewAccount"); - LaunchURL(AUTH_NO_TIME_URL); -end - -function AccountLogin_LaunchCommunitySite() - PlaySound("gsLoginNewAccount"); - LaunchURL(COMMUNITY_URL); -end - -function CharacterSelect_UpgradeAccount() - PlaySound("gsLoginNewAccount"); - LaunchURL(AUTH_NO_TIME_URL); -end - -function AccountLogin_Credits() - CreditsFrame.creditsType = 3; - PlaySound("gsTitleCredits"); - SetGlueScreen("credits"); -end - -function AccountLogin_Cinematics() - if ( not GlueDialog:IsShown() ) then - PlaySound("gsLoginNewAccount"); - if ( CinematicsFrame.numMovies > 1 ) then - CinematicsFrame:Show(); - else - MovieFrame.version = 1; - SetGlueScreen("movie"); - end - end -end - -function AccountLogin_Options() - PlaySound("gsTitleOptions"); -end - -function AccountLogin_Exit() --- PlaySound("gsTitleQuit"); - QuitGame(); -end - -function AccountLogin_ShowSurveyNotification() - GlueDialog:Hide(); - AccountLoginUI:Hide(); - SurveyNotificationAccept:Enable(); - SurveyNotificationDecline:Enable(); - SurveyNotificationFrame:Show(); -end - -function AccountLogin_SurveyNotificationDone(accepted) - SurveyNotificationFrame:Hide(); - SurveyNotificationAccept:Disable(); - SurveyNotificationDecline:Disable(); - SurveyNotificationDone(accepted); - AccountLoginUI:Show(); -end - -function AccountLogin_ShowUserAgreements() - TOSScrollFrame:Hide(); - EULAScrollFrame:Hide(); - TerminationScrollFrame:Hide(); - ScanningScrollFrame:Hide(); - ContestScrollFrame:Hide(); - TOSText:Hide(); - EULAText:Hide(); - TerminationText:Hide(); - ScanningText:Hide(); - if ( not EULAAccepted() ) then - if ( ShowEULANotice() ) then - TOSNotice:SetText(EULA_NOTICE); - TOSNotice:Show(); - end - AccountLoginUI:Hide(); - TOSFrame.noticeType = "EULA"; - TOSFrameTitle:SetText(EULA_FRAME_TITLE); - TOSFrameHeader:SetWidth(TOSFrameTitle:GetWidth()); - EULAScrollFrame:Show(); - EULAText:Show(); - TOSFrame:Show(); - elseif ( not TOSAccepted() ) then - if ( ShowTOSNotice() ) then - TOSNotice:SetText(TOS_NOTICE); - TOSNotice:Show(); - end - AccountLoginUI:Hide(); - TOSFrame.noticeType = "TOS"; - TOSFrameTitle:SetText(TOS_FRAME_TITLE); - TOSFrameHeader:SetWidth(TOSFrameTitle:GetWidth()); - TOSScrollFrame:Show(); - TOSText:Show(); - TOSFrame:Show(); - elseif ( not TerminationWithoutNoticeAccepted() and SHOW_TERMINATION_WITHOUT_NOTICE_AGREEMENT ) then - if ( ShowTerminationWithoutNoticeNotice() ) then - TOSNotice:SetText(TERMINATION_WITHOUT_NOTICE_NOTICE); - TOSNotice:Show(); - end - AccountLoginUI:Hide(); - TOSFrame.noticeType = "TERMINATION"; - TOSFrameTitle:SetText(TERMINATION_WITHOUT_NOTICE_FRAME_TITLE); - TOSFrameHeader:SetWidth(TOSFrameTitle:GetWidth()); - TerminationScrollFrame:Show(); - TerminationText:Show(); - TOSFrame:Show(); - elseif ( not ScanningAccepted() and SHOW_SCANNING_AGREEMENT ) then - if ( ShowScanningNotice() ) then - TOSNotice:SetText(SCANNING_NOTICE); - TOSNotice:Show(); - end - AccountLoginUI:Hide(); - TOSFrame.noticeType = "SCAN"; - TOSFrameTitle:SetText(SCAN_FRAME_TITLE); - TOSFrameHeader:SetWidth(TOSFrameTitle:GetWidth()); - ScanningScrollFrame:Show(); - ScanningText:Show(); - TOSFrame:Show(); - elseif ( not ContestAccepted() and SHOW_CONTEST_AGREEMENT ) then - if ( ShowContestNotice() ) then - TOSNotice:SetText(CONTEST_NOTICE); - TOSNotice:Show(); - end - AccountLoginUI:Hide(); - TOSFrame.noticeType = "CONTEST"; - TOSFrameTitle:SetText(CONTEST_FRAME_TITLE); - TOSFrameHeader:SetWidth(TOSFrameTitle:GetWidth()); - ContestScrollFrame:Show(); - ContestText:Show(); - TOSFrame:Show(); - elseif ( not IsScanDLLFinished() ) then - AccountLoginUI:Hide(); - TOSFrame:Hide(); - local dllURL = ""; - if ( IsWindowsClient() ) then dllURL = SCANDLL_URL_WIN32_SCAN_DLL; end - ScanDLLStart(SCANDLL_URL_LAUNCHER_TXT, dllURL); - else - AccountLoginUI:Show(); - TOSFrame:Hide(); - end -end - -function AccountLogin_UpdateAcceptButton(scrollFrame, isAcceptedFunc, noticeType) - local scrollbar = _G[scrollFrame:GetName().."ScrollBar"]; - local min, max = scrollbar:GetMinMaxValues(); - - -- HACK: scrollbars do not handle max properly - -- DO NOT CHANGE - without speaking to Mikros/Barris/Thompson - if (scrollbar:GetValue() >= max - 20) then - TOSAccept:Enable(); - else - if ( not isAcceptedFunc() and TOSFrame.noticeType == noticeType ) then - TOSAccept:Disable(); - end - end -end - -function ChangedOptionsDialog_OnShow(self) - if ( not ShowChangedOptionWarnings() ) then - self:Hide(); - return; - end - - local options = ChangedOptionsDialog_BuildWarningsString(GetChangedOptionWarnings()); - if ( options == "" ) then - self:Hide(); - return; - end - - -- set text - ChangedOptionsDialogText:SetText(options); - - -- resize the background to fit the text - local textHeight = ChangedOptionsDialogText:GetHeight(); - local titleHeight = ChangedOptionsDialogTitle:GetHeight(); - local buttonHeight = ChangedOptionsDialogOkayButton:GetHeight(); - ChangedOptionsDialogBackground:SetHeight(26 + titleHeight + 16 + textHeight + 8 + buttonHeight + 16); - self:Raise(); -end - -function ChangedOptionsDialog_OnKeyDown(self,key) - if ( key == "PRINTSCREEN" ) then - Screenshot(); - return; - end - - if ( key == "ESCAPE" or key == "ENTER" ) then - ChangedOptionsDialogOkayButton:Click(); - end -end - -function ChangedOptionsDialog_BuildWarningsString(...) - local options = ""; - for i=1, select("#", ...) do - if ( i == 1 ) then - options = select(1, ...); - else - options = options.."\n\n"..select(i, ...); - end - end - return options; -end - --- Virtual keypad functions -function VirtualKeypadFrame_OnEvent(event, ...) - if ( event == "PLAYER_ENTER_PIN" ) then - for i=1, 10 do - _G["VirtualKeypadButton"..i]:SetText(select(i,...)); - end - end - -- Randomize location to prevent hacking (yeah right) - local xPadding = 5; - local yPadding = 10; - local xPos = random(xPadding, GlueParent:GetWidth()-VirtualKeypadFrame:GetWidth()-xPadding); - local yPos = random(yPadding, GlueParent:GetHeight()-VirtualKeypadFrame:GetHeight()-yPadding); - VirtualKeypadFrame:SetPoint("TOPLEFT", GlueParent, "TOPLEFT", xPos, -yPos); - - VirtualKeypadFrame:Show(); - VirtualKeypad_UpdateButtons(); -end - -function VirtualKeypadButton_OnClick(self) - local text = VirtualKeypadText:GetText(); - if ( not text ) then - text = ""; - end - VirtualKeypadText:SetText(text.."*"); - VirtualKeypadFrame.PIN = VirtualKeypadFrame.PIN..self:GetID(); - VirtualKeypad_UpdateButtons(); -end - -function VirtualKeypadOkayButton_OnClick() - local PIN = VirtualKeypadFrame.PIN; - local numNumbers = strlen(PIN); - local pinNumber = {}; - for i=1, MAX_PIN_LENGTH do - if ( i <= numNumbers ) then - pinNumber[i] = strsub(PIN,i,i); - else - pinNumber[i] = nil; - end - end - PINEntered(pinNumber[1] , pinNumber[2], pinNumber[3], pinNumber[4], pinNumber[5], pinNumber[6], pinNumber[7], pinNumber[8], pinNumber[9], pinNumber[10]); - VirtualKeypadFrame:Hide(); -end - -function VirtualKeypad_UpdateButtons() - local numNumbers = strlen(VirtualKeypadFrame.PIN); - if ( numNumbers >= 4 and numNumbers <= MAX_PIN_LENGTH ) then - VirtualKeypadOkayButton:Enable(); - else - VirtualKeypadOkayButton:Disable(); - end - if ( numNumbers == 0 ) then - VirtualKeypadBackButton:Disable(); - else - VirtualKeypadBackButton:Enable(); - end - if ( numNumbers >= MAX_PIN_LENGTH ) then - for i=1, MAX_PIN_LENGTH do - _G["VirtualKeypadButton"..i]:Disable(); - end - else - for i=1, MAX_PIN_LENGTH do - _G["VirtualKeypadButton"..i]:Enable(); - end - end -end - -TOKEN_SEED = - "idobdfillpkiimdgkclhnlibgnepalcbpccdkhloipdoeebccnoeedefgmljndai".. - "epicgamehpoifjbggbcihfanenmhkemffilglaebddmbakkhblpencadlaiepoga".. - "ecpjojaijcefflabhilmmpgjiecbhamoceponkbjiogaodhnagencenlaeljhbna".. - "ciglpffdnfgaaidccjjgbgiihhnbbjcbanhfdjadljkhmfknfnmpjblnelbfnnjf".. - "dpakjehajomgjahhljnmnhnpadfkbopppiicnkkkhblkbibgajfmemhhimpjgcoe".. - "mbkpilkleedkmpnckkcdbhnoanhpjeneinehgknalgglcbdcjdcppbjhgkahamgk".. - "gijkofghdhopbkjjghmndfdpiadcdigefikbgccfhgkkbmkollbhlkbdobhaofbh".. - "adbiepfnpiibfkcpflpkjpfmmhbopkcbcblaadaoodnoodgfhjpedmpballngmoo".. - "bbmkgghdgmhdngbfpmikijmdjgddkeahhidkofihemfmolbcojpiapfkogbdenfc".. - "cmahmfhlclfkeijbndcllbnffbjbbkfgdboiffhpkfgjckliookjlonenifdbenn".. - "epeicoloceldnilhlkameoeceiobfnpeccaihhgjdgagjhmeljacpfljlhgnlhkj".. - "dbihegomcbifklmmhmbaodnaehnbkikcjkloebkhmkhejakcdklndeiinidlgdhc".. - "ddfbafimcpddekndmbcfemcpfihngpkoccjniboomialmgejaalnfogjofbfgbdk".. - "poibhankhndpgeldkkdjgbknnahfdbcjhkmaciajeadkfmjcgaipjcilhhlagjcp".. - "lnbeodabfpofdabnhckmnbjnofopfhglgiociaehalfcclkmjmobmjdbillmompm".. - "jfgppnfgfancjglolkhoejogfjljnknoeiniiiimcifhlpiefmkkmhonbnppdndl".. - "hmgpgcniinbaanciifdggklbgoanaihndbjpnannabbmfjkdjfkhimpccelcpjed".. - "kgmpmpfnbmleiejkgbbknnnhambkmomlbjbhpkegehdfacdnbdfcmfagadbcaemg".. - "ddhpjoacekfnakamgafmkodcplnhbhblcllikeglfnedlmkcoiegldlhikoncmca".. - "bloiejelafbjjgmhapobofongodoojelpnkgfjdgpfckjglfbgaipbdpmbpjlcje".. - "jcpgagffnmappkacgacmokedaicjklinmemijkojchoojjandkcdmjigjeldpepl".. - "ihpenljefeechdndbdjkcipajcajghnhjackcjnoofebnmhimajekangghkfgcjm".. - "hndedmcpmdilipgljglplhppcogaidkfaeibkedaihckjodddfblfonfnnljgcbi".. - "hmnojjolaljebgiegnmjcficnkjchoakajkdhnchbljhonghjffebdobdcahpdjp".. - "bmhpmnamkgpfjfbfgghjnabakoilmlbkhjoiegldbcdlijakkmehoemokdeafgjl".. - "khmdjmbkdckdlidapcigbomjikehjddpblijhdgooegdfeinhaiponemlnffcnif".. - "bkbnihminfmkfhbdneaaegofpacckahbgnmobgehalklcfkncogkanff"; - --- TOKEN SYSTEM -function TokenEntryOkayButton_OnLoad(self) - self:RegisterEvent("PLAYER_ENTER_TOKEN"); -end - -function TokenEntryOkayButton_OnEvent(self, event) - if (event == "PLAYER_ENTER_TOKEN") then - if ( AccountLoginSaveAccountName:GetChecked() ) then - if ( GetUsesToken() ) then - if ( AccountLoginTokenEdit:GetText() ~= "" ) then - TokenEntered(AccountLoginTokenEdit:GetText()); - return; - end - else - SetUsesToken(true); - end - end - self:Show(); - end -end - -function TokenEntryOkayButton_OnShow() - TokenEnterDialogBackgroundEdit:SetText(""); - TokenEnterDialogBackgroundEdit:SetFocus(); -end - -function TokenEntryOkayButton_OnKeyDown(self, key) - if ( key == "ENTER" ) then - TokenEntry_Okay(self); - elseif ( key == "ESCAPE" ) then - TokenEntry_Cancel(self); - end -end - -function TokenEntry_Okay(self) - TokenEntered(TokenEnterDialogBackgroundEdit:GetText()); - TokenEnterDialog:Hide(); -end - -function TokenEntry_Cancel(self) - TokenEnterDialog:Hide(); - CancelLogin(); -end - --- WOW Account selection -function WoWAccountSelect_OnLoad(self) - self:RegisterEvent("GAME_ACCOUNTS_UPDATED"); - self:RegisterEvent("OPEN_STATUS_DIALOG"); - WoWAccountSelectDialogBackgroundContainerScrollFrame.offset = 0 - CURRENT_SELECTED_WOW_ACCOUNT = 1; -end - -function WoWAccountSelect_OnShow (self) - AccountLoginAccountEdit:SetFocus(); - AccountLoginAccountEdit:ClearFocus(); - CURRENT_SELECTED_WOW_ACCOUNT = 1; - WoWAccountSelect_Update(); -end - -function WoWAccountSelectButton_OnClick(self) - CURRENT_SELECTED_WOW_ACCOUNT = self:GetID(); - WoWAccountSelect_Update(); -end - -function WoWAccountSelectButton_OnDoubleClick(self) - WoWAccountSelect_SelectAccount(self:GetID()); -end - -function WoWAccountSelect_OnEvent(self, event) - if ( event == "GAME_ACCOUNTS_UPDATED" ) then - local str, selectedIndex, selectedName = "" - for i = 1, GetNumGameAccounts() do - local name = GetGameAccountInfo(i); - if ( name == GlueDropDownMenu_GetText(AccountLoginDropDown) ) then - selectedName = name; - selectedIndex = i; - end - str = str .. name .. "|"; - end - - if ( str == strreplace(GetSavedAccountList(), "!", "") and selectedIndex ) then - WoWAccountSelect_SelectAccount(selectedIndex); - return; - else - self:Show(); - end - else - self:Hide(); - end -end - -function WoWAccountSelect_SelectAccount(index) - if ( AccountLoginSaveAccountName:GetChecked() ) then - WowAccountSelect_UpdateSavedAccountNames(index); - else - SetSavedAccountList(""); - end - WoWAccountSelectDialog:Hide(); - SetGameAccount(index); -end - -function WowAccountSelect_UpdateSavedAccountNames(selectedIndex) - local count = GetNumGameAccounts(); - - local str = "" - for i = 1, count do - local name = GetGameAccountInfo(i); - if ( i == selectedIndex ) then - str = str .. "!" .. name .. "|"; - else - str = str .. name .. "|"; - end - end - SetSavedAccountList(str); -end - -ACCOUNTNAME_BUTTON_HEIGHT = 20; - -function WoWAccountSelect_OnVerticalScroll (self, offset) - local scrollbar = _G[self:GetName().."ScrollBar"]; - scrollbar:SetValue(offset); - WoWAccountSelectDialogBackgroundContainerScrollFrame.offset = floor((offset / ACCOUNTNAME_BUTTON_HEIGHT) + 0.5); - WoWAccountSelect_Update(); -end - -MAX_ACCOUNTS_DISPLAYED = 8; -function WoWAccountSelect_Update() - local count = GetNumGameAccounts(); - - local offset = WoWAccountSelectDialogBackgroundContainerScrollFrame.offset; - for index=1, MAX_ACCOUNTS_DISPLAYED do - local button = _G["WoWAccountSelectDialogBackgroundContainerButton" .. index]; - local name, regionID = GetGameAccountInfo(index + offset); - button:SetButtonState("NORMAL"); - button.BG_Highlight:Hide(); - if ( name ) then - button:SetID(index + offset); - button:SetText(name); - button.regionID = regionID; - button:Show(); - if ( index == CURRENT_SELECTED_WOW_ACCOUNT) then - button.BG_Highlight:Show(); - end - else - button:Hide(); - end - end - - GlueScrollFrame_Update(WoWAccountSelectDialogBackgroundContainerScrollFrame, count, MAX_ACCOUNTS_DISPLAYED, ACCOUNTNAME_BUTTON_HEIGHT); -end - -function WoWAccountSelect_AccountButton_OnClick(self, button) - CURRENT_SELECTED_WOW_ACCOUNT = self:GetID(); - WoWAccountSelect_Accept(); -end - -function WoWAccountSelect_OnKeyDown(self, key) - if ( key == "ESCAPE" ) then - WoWAccountSelect_OnCancel(self); - elseif ( key == "UP" ) then - CURRENT_SELECTED_WOW_ACCOUNT = max(1, CURRENT_SELECTED_WOW_ACCOUNT - 1); - WoWAccountSelect_Update() - elseif ( key == "DOWN" ) then - CURRENT_SELECTED_WOW_ACCOUNT = min(GetNumGameAccounts(), CURRENT_SELECTED_WOW_ACCOUNT + 1); - WoWAccountSelect_Update() - elseif ( key == "ENTER" ) then - WoWAccountSelect_SelectAccount(CURRENT_SELECTED_WOW_ACCOUNT); - elseif ( key == "PRINTSCREEN" ) then - Screenshot(); - end -end - -function WoWAccountSelect_OnCancel (self) - self:Hide(); - GlueDialog:Hide(); - CancelLogin(); -end - -function WoWAccountSelect_Accept() - WoWAccountSelect_SelectAccount(CURRENT_SELECTED_WOW_ACCOUNT); -end - -function AccountLoginDropDown_OnClick(self) - GlueDropDownMenu_SetSelectedValue(AccountLoginDropDown, self.value); -end - -function AccountLoginDropDown_Initialize() - local selectedValue = GlueDropDownMenu_GetSelectedValue(AccountLoginDropDown); - local info; - - for i = 1, #AccountList do - AccountList[i].checked = (AccountList[i].text == selectedValue); - GlueDropDownMenu_AddButton(AccountList[i]); - end -end - -AccountList = {}; -function AccountLogin_SetupAccountListDDL() - if ( GetSavedAccountName() ~= "" and GetSavedAccountList() ~= "" ) then - AccountLoginPasswordEdit:SetPoint("BOTTOM", 0, 255); - AccountLoginLoginButton:SetPoint("BOTTOM", 0, 150); - AccountLoginDropDown:Show(); - else - AccountLoginPasswordEdit:SetPoint("BOTTOM", 0, 275); - AccountLoginLoginButton:SetPoint("BOTTOM", 0, 170); - AccountLoginDropDown:Hide(); - return; - end - - AccountList = {}; - local i = 1; - for str in string.gmatch(GetSavedAccountList(), "([%w!]+)|?") do - local selected = false; - if ( strsub(str, 1, 1) == "!" ) then - selected = true; - str = strsub(str, 2, #str); - GlueDropDownMenu_SetSelectedName(AccountLoginDropDown, str); - GlueDropDownMenu_SetText(str, AccountLoginDropDown); - end - AccountList[i] = { ["text"] = str, ["value"] = str, ["selected"] = selected, func = AccountLoginDropDown_OnClick }; - i = i + 1; - end -end - -function CinematicsFrame_OnLoad(self) - local numMovies = GetClientExpansionLevel(); - CinematicsFrame.numMovies = numMovies; - if ( numMovies < 2 ) then - return; - end - - for i = 1, numMovies do - _G["CinematicsButton"..i]:Show(); - end - CinematicsBackground:SetHeight(numMovies * 40 + 70); -end - -function CinematicsFrame_OnKeyDown(key) - if ( key == "PRINTSCREEN" ) then - Screenshot(); - else - PlaySound("igMainMenuOptionCheckBoxOff"); - CinematicsFrame:Hide(); - end -end - -function Cinematics_PlayMovie(self) - CinematicsFrame:Hide(); - PlaySound("gsTitleOptionOK"); - MovieFrame.version = self:GetID(); - SetGlueScreen("movie"); -end \ No newline at end of file diff --git a/patch-ruRU-4/Interface/GlueXML/AccountLogin.xml b/patch-ruRU-4/Interface/GlueXML/AccountLogin.xml deleted file mode 100644 index 9a63648..0000000 --- a/patch-ruRU-4/Interface/GlueXML/AccountLogin.xml +++ /dev/null @@ -1,2822 +0,0 @@ - - + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + 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 @@ + +