diff --git a/Altoholic-Addon/Altoholic/Altoholic.lua b/Altoholic-Addon/Altoholic/Altoholic.lua new file mode 100644 index 0000000..f90ec4b --- /dev/null +++ b/Altoholic-Addon/Altoholic/Altoholic.lua @@ -0,0 +1,791 @@ +--[[ *** Altoholic *** +Written by : Thaoky, EU-Marécages de Zangar +--]] + +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local DS + +local WHITE = "|cFFFFFFFF" +local RED = "|cFFFF0000" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" +local ORANGE = "|cFFFF7F00" +local TEAL = "|cFF00FF9A" +local GOLD = "|cFFFFD700" + +local THIS_ACCOUNT = "Default" + +Altoholic.ClassInfo = { + ["MAGE"] = "|cFF69CCF0", + ["WARRIOR"] = "|cFFC79C6E", + ["HUNTER"] = "|cFFABD473", + ["ROGUE"] = "|cFFFFF569", + ["WARLOCK"] = "|cFF9482CA", + ["DRUID"] = "|cFFFF7D0A", + ["SHAMAN"] = "|cFF2459FF", + ["PALADIN"] = "|cFFF58CBA", + ["PRIEST"] = WHITE, + ["DEATHKNIGHT"] = "|cFFC41F3B" +} + +local function InitLocalization() + -- this function's purpose is to initialize the text attribute of widgets created in XML. + -- in versions prior to 3.1.003, they were initialized through global constants named XML_ALTO_??? + -- the strings stayed in memory for no reason, and could not be included in the automated localization offered by curse, hence the change of approach. + + AltoholicMinimapButton.tooltip = format("%s\n%s\n%s", addonName, WHITE..L["Left-click to |cFF00FF00open"], WHITE..L["Right-click to |cFF00FF00drag"] ) + + AltoAccountSharing_InfoButton.tooltip = format("%s|r\n%s\n%s\n\n%s", + WHITE..L["Account Name"], + L["Enter an account name that will be\nused for |cFF00FF00display|r purposes only."], + L["This name can be anything you like,\nit does |cFF00FF00NOT|r have to be the real account name."], + L["This field |cFF00FF00cannot|r be left empty."]) + + AltoholicTabSummary_Options.tooltip = format("%s:|r %s", WHITE..GAMEOPTIONS_MENU, addonName) + AltoholicTabSummary_OptionsDataStore.tooltip = format("%s:|r %s", WHITE..GAMEOPTIONS_MENU, "DataStore") + + AltoholicFrameTab1:SetText(L["Summary"]) + AltoholicFrameTab2:SetText(L["Characters"]) + AltoholicTabSummaryMenuItem1:SetText(L["Account Summary"]) + AltoholicTabSummaryMenuItem2:SetText(L["Bag Usage"]) + AltoholicTabSummaryMenuItem4:SetText(L["Activity"]) + AltoholicTabSummaryMenuItem5:SetText(L["Guild Members"]) + AltoholicTabSummaryMenuItem6:SetText(L["Guild Skills"]) + AltoholicTabSummaryMenuItem7:SetText(L["Guild Bank Tabs"]) + AltoholicTabSummaryMenuItem8:SetText(L["Calendar"]) + AltoholicTabSummary_RequestSharing:SetText(L["Account Sharing"]) + + AltoholicTabCharactersText1:SetText(L["Realm"]) + AltoholicTabCharactersText2:SetText(L["Character"]) + + AltoholicTabSearch_Sort1:SetText(L["Item / Location"]) + AltoholicTabSearch_Sort2:SetText(L["Character"]) + AltoholicTabSearch_Sort3:SetText(L["Realm"]) + AltoholicTabSearchSlot:SetText(L["Equipment Slot"]) + AltoholicTabSearchLocation:SetText(L["Location"]) + + AltoholicFramePetsText1:SetText(L["View"]) + AltoholicFrameReputationsText1:SetText(L["View"]) + AltoholicFrameCurrenciesText1:SetText(L["View"]) + + AltoholicTabGuildBank_HideInTooltipText:SetText(L["Hide this guild in the tooltip"]) + + AltoAccountSharingName:SetText(L["Account Name"]) + AltoAccountSharingText1:SetText(L["Send account sharing request to:"]) + AltoAccountSharingText2:SetText(ORANGE.."Available Content") + AltoAccountSharingText3:SetText(ORANGE.."Size") + AltoAccountSharingText4:SetText(ORANGE.."Date") + AltoAccountSharing_UseNameText:SetText(L["Character"]) + + AltoholicFrameTotals:SetText(L["Totals"]) + AltoholicFrameSearchLabel:SetText(L["Search Containers"]) + AltoholicFrame_ResetButton:SetText(L["Reset"]) + + -- nil strings to save memory, since they are not used later on. + L["Summary"] = nil + L["Characters"] = nil + L["Account Summary"] = nil + L["Bag Usage"] = nil + L["Activity"] = nil + L["Guild Skills"] = nil + L["Guild Bank Tabs"] = nil + + L["View"] = nil + L["Hide this guild in the tooltip"] = nil + L["Search Containers"] = nil + L["Equipment Slot"] = nil + L["Location"] = nil + L["Reset"] = nil + L["Send account sharing request to:"] = nil + L["Left-click to |cFF00FF00open"] = nil + L["Right-click to |cFF00FF00drag"] = nil + L["Enter an account name that will be\nused for |cFF00FF00display|r purposes only."] = nil + L["This name can be anything you like,\nit does |cFF00FF00NOT|r have to be the real account name."] = nil + L["This field |cFF00FF00cannot|r be left empty."] = nil + + if GetLocale() == "deDE" then + -- This is a global string from wow, for some reason the original is causing problem. DO NOT copy this line in localization files + ITEM_MOD_SPELL_POWER = "Erh\195\182ht die Zaubermacht um %d."; + end +end + +local function BuildUnsafeItemList() + -- This method will clean the unsafe item list currently in the DB. + -- In the previous game session, the list has been populated with items id's that were originally unsafe and for which a query was sent to the server. + -- In this session, a getiteminfo on these id's will keep returning a nil if the item is really unsafe, so this method will get rid of the id's that are now valid. + local TmpUnsafe = {} -- create a temporary table with confirmed unsafe id's + local unsafeItems = Altoholic.db.global.unsafeItems + + for _, itemID in pairs(unsafeItems) do + local itemName = GetItemInfo(itemID) + if not itemName then -- if the item is really unsafe .. save it + table.insert(TmpUnsafe, itemID) + end + end + + wipe(unsafeItems) -- clear the DB table + + for _, itemID in pairs(TmpUnsafe) do + table.insert(unsafeItems, itemID) -- save the confirmed unsafe ids back in the db + end +end + +-- *** DB functions *** +local currentAlt +local currentRealm +local currentAccount + +function addon:GetCharacterTable(name, realm, account) + -- Usage: + -- local c = addon:GetCharacterTable(char, realm, account) + -- all 3 parameters default to current player, realm or account + -- use this for features that have to work regardless of an alt's location (any realm, any account) + local key = format("%s.%s.%s", account or currentAccount, realm or currentRealm, name or currentAlt) + return addon.db.global.Characters[key] +end + +function addon:GetCharacterTableByLine(line) + -- shortcut to get the right character table based on the line number in the info table. + return addon:GetCharacterTable( addon.Characters:GetInfo(line) ) +end + +function addon:GetCurrentCharacter() + return currentAlt, currentRealm, currentAccount +end + +function addon:SetCurrentCharacter(name, realm, account) + currentAlt = name + if realm then + addon:SetCurrentRealm(realm) + end + if account then + addon:SetCurrentAccount(account) + end +end + +function addon:GetCurrentRealm() + return currentRealm, currentAccount +end + +function addon:SetCurrentRealm(name) + currentRealm = name +end + +function addon:GetCurrentAccount() + return currentAccount +end + +function addon:SetCurrentAccount(name) + currentAccount = name +end + +function addon:GetGuild(name, realm, account) + name = name or GetGuildInfo("player") + if not name then return end + + realm = realm or GetRealmName() + account = account or THIS_ACCOUNT + + local key = format("%s.%s.%s", account, realm, name) + return addon.db.global.Guilds[key] +end + +function Altoholic:GetGuildMembers(guild) + assert(type(guild) == "table") + return guild.members +end + +function Altoholic:SetLastAccountSharingInfo(name, realm, account) + local sharing = Altoholic.db.global.Sharing.Domains[format("%s.%s", account, realm)] + sharing.lastSharingTimestamp = time() + sharing.lastUpdatedWith = name +end + +function Altoholic:GetLastAccountSharingInfo(realm, account) + local sharing = Altoholic.db.global.Sharing.Domains[format("%s.%s", account, realm)] + + if sharing then + return date("%m/%d/%Y %H:%M", sharing.lastSharingTimestamp), sharing.lastUpdatedWith + end +end + + +-- *** Scanning functions *** +local function ScanFriends() + local c = addon.ThisCharacter + wipe(c.Friends) + + for i = 1, GetNumFriends() do + local name = GetFriendInfo(i); + table.insert(c.Friends, name) + end +end + +local function ScanSavedInstances() + local c = addon.ThisCharacter + + wipe(c.SavedInstance) + + for i=1, GetNumSavedInstances() do + local instanceName, instanceID, instanceReset, difficulty, _, extended, _, isRaid, maxPlayers, difficultyName = GetSavedInstanceInfo(i) + + if instanceReset > 0 then -- in 3.2, instances with reset = 0 are also listed (to support raid extensions) + extended = extended and 0 or 1 + isRaid = isRaid and 0 or 1 + + if difficulty > 1 then + instanceName = format("%s %s", instanceName, difficultyName) + end + + local key = instanceName.. "|" .. instanceID + c.SavedInstance[key] = format("%s|%s|%s|%s", instanceReset, time(), extended, isRaid ) + end + end +end + + +-- *** Event Handlers *** +local function OnPlayerAlive() + ScanFriends() +end + +local function OnPlayerLogout() + local t = {} + for i = 1, 10 do + t[i] = strchar(64 + random(26)) + end + + local y = (tonumber(date("%Y")) - 2000) + 64 + local m = tonumber(date("%m")) + 64 + local d = date("%d") + local h = tonumber(date("%H")) + 64 + local M = date("%M") + local S = date("%S") + local x = t[1]..S..t[3]..t[4]..strchar(m)..t[7]..M..t[2]..t[6]..t[8]..d..t[9]..strchar(h)..t[5]..t[1]..strchar(y)..t[4] + + addon.Options:Set("Lola", x) +end + +local function OnRaidInstanceWelcome() + RequestRaidInfo() +end + +local function OnChatMsgSystem(event, arg) + if arg then + if tostring(arg1) == INSTANCE_SAVED then + RequestRaidInfo() + end + end +end + +local trackedItems = { + [39878] = 590400, -- Mysterious Egg, 6 days 20 hours + [44717] = 590400, -- Disgusting Jar, 6 days 20 hours +} + +local lootMsg = gsub(LOOT_ITEM_SELF, "%%s", "(.+)") + +local function OnChatMsgLoot(event, arg) + local _, _, link = strfind(arg, lootMsg) + if not link then return end + + local id = addon:GetIDFromLink(link) + id = tonumber(id) + if not id then return end + + for itemID, duration in pairs(trackedItems) do + if itemID == id then + local name = GetItemInfo(itemID) + if name then + local c = addon.ThisCharacter + table.insert(c.Timers, name .."|" .. time() .. "|" .. duration) + addon.Calendar.Events:BuildList() + addon.Tabs.Summary:Refresh() + end + end + end +end + + + +function addon:OnEnable() + DS = DataStore + + InitLocalization() + addon.Options:Init() + addon.Tasks:Init() + addon.Profiler:Init() + addon:InitTooltip() + + addon:RegisterEvent("PLAYER_ALIVE", OnPlayerAlive) + addon:RegisterEvent("PLAYER_LOGOUT", OnPlayerLogout) + addon:RegisterEvent("UPDATE_INSTANCE_INFO", ScanSavedInstances) + addon:RegisterEvent("RAID_INSTANCE_WELCOME", OnRaidInstanceWelcome) + + addon:RegisterEvent("AUCTION_HOUSE_SHOW", addon.AuctionHouse.OnShow) + addon:RegisterEvent("PLAYER_TALENT_UPDATE", addon.Talents.OnUpdate); + + AltoholicFrameName:SetText("Altoholic |cFFFFFFFF".. addon.Version .. " by |cFF69CCF0Thaoky") + + local realm = GetRealmName() + local player = UnitName("player") + local key = format("%s.%s.%s", THIS_ACCOUNT, realm, player) + addon.ThisCharacter = addon.db.global.Characters[key] + + addon:SetCurrentCharacter(player, realm, THIS_ACCOUNT) + + addon.Tabs.Summary:Init() + addon.Containers:Init() + addon.Search:Init() + addon.Currencies:Init() + + -- do not move this one into the frame's OnLoad + UIDropDownMenu_Initialize(AltoholicFrameEquipmentRightClickMenu, Equipment_RightClickMenu_OnLoad, "MENU"); + + _G["AltoholicFrameClassesItem10"]:SetPoint("BOTTOMRIGHT", "AltoholicFrameClasses", "BOTTOMRIGHT", -15, 0); + for j=9, 1, -1 do + _G["AltoholicFrameClassesItem" .. j]:SetPoint("BOTTOMRIGHT", "AltoholicFrameClassesItem" .. (j + 1), "BOTTOMLEFT", -5, 0); + end + + addon.Options:RestoreToUI() + + if Altoholic.Options:Get("ShowMinimap") == 1 then + addon:MoveMinimapIcon() + AltoholicMinimapButton:Show(); + else + AltoholicMinimapButton:Hide(); + end + + addon:RegisterEvent("BAG_UPDATE", addon.Containers.OnBagUpdate) + addon:RegisterEvent("FRIENDLIST_UPDATE", ScanFriends); + addon:RegisterEvent("CHAT_MSG_SYSTEM", OnChatMsgSystem); + addon:RegisterEvent("CHAT_MSG_LOOT", OnChatMsgLoot) + addon:RegisterEvent("UNIT_PET", addon.Pets.OnChange); + + if IsInGuild() then + addon:RegisterEvent("GUILD_ROSTER_UPDATE", addon.Guild.Members.OnRosterUpdate); + end + + BuildUnsafeItemList() + + -- create an empty frame to manage the timer via its Onupdate + addon.TimerFrame = CreateFrame("Frame", "AltoholicTimerFrame", UIParent) + local f = addon.TimerFrame + + f:SetWidth(1) + f:SetHeight(1) + f:SetPoint("TOPLEFT", UIParent, "TOPLEFT", 1, 1) + f:SetScript("OnUpdate", function(addon, elapsed) Altoholic.Tasks:OnUpdate(elapsed) end) + f:Show() +end + +function addon:OnDisable() +end + +function addon:ToggleUI() + if (AltoholicFrame:IsVisible()) then + AltoholicFrame:Hide(); + else + AltoholicFrame:Show(); + end +end + +function addon:OnShow() + SetPortraitTexture(AltoholicFramePortrait, "player"); + + addon.Characters:BuildList() + addon.Characters:BuildView() + + if not addon.Tabs.current then + addon.Tabs.current = 1 + addon.Tabs.Summary:MenuItem_OnClick(1) + elseif addon.Tabs.current == 1 then + addon.Tabs.Summary:Refresh() + end +end + + +-- *** Utility functions *** +function Altoholic:ScrollFrameUpdate(desc) + assert(type(desc) == "table") -- desc is the table that contains a standardized description of the scrollframe + + local frame = desc.Frame + local entry = frame.."Entry" + + -- hide all lines and set their id to 0, the update function is responsible for showing and setting id's of valid lines + for i = 1, desc.NumLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + end + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ) + -- call the update handler + desc:Update(offset, entry, desc) + + local last = (desc:GetSize() < desc.NumLines) and desc.NumLines or desc:GetSize() + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], last, desc.NumLines, desc.LineHeight); +end + +function Altoholic:ClearScrollFrame(name, entry, lines, height) + for i=1, lines do -- Hides all entries of the scrollframe, and updates it accordingly + _G[ entry..i ]:Hide() + end + FauxScrollFrame_Update( name, lines, lines, height); +end + +function addon:Item_OnEnter(frame) + if not frame.id then return end + + GameTooltip:SetOwner(frame, "ANCHOR_LEFT"); + frame.link = frame.link or select(2, GetItemInfo(frame.id) ) + + if frame.link then + GameTooltip:SetHyperlink(frame.link); + else + -- GameTooltip:AddLine(L["Unknown link, please relog this character"],1,1,1); + GameTooltip:SetHyperlink("item:"..frame.id..":0:0:0:0:0:0:0") -- this line queries the server for an unknown id + GameTooltip:ClearLines(); -- don't leave residual info in the tooltip after the server query + end + GameTooltip:Show(); +end + +function addon:Item_OnClick(frame, button) + if not frame.id then return end + + if not frame.link then + frame.link = select(2, GetItemInfo(frame.id) ) + end + if not frame.link then return end -- still not valid ? exit + + if ( button == "LeftButton" ) and ( IsControlKeyDown() ) then + DressUpItemLink(frame.link); + elseif ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then + local chat = ChatEdit_GetLastActiveWindow() + + if chat:IsShown() then + chat:Insert(frame.link); + else + AltoholicFrame_SearchEditBox:SetText(GetItemInfo(frame.link)) + end + end +end + +function addon:SetItemButtonTexture(button, texture, width, height) + -- wrapper for SetItemButtonTexture from ItemButtonTemplate.lua + width = width or 36 + height = height or 36 + + local itemTexture = _G[button.."IconTexture"] + + itemTexture:SetWidth(width); + itemTexture:SetHeight(height); + itemTexture:SetAllPoints(_G[button]); + + SetItemButtonTexture(_G[button], texture) +end + +function addon:TextureToFontstring(name, width, height) + return format("|T%s:%s:%s|t", name, width, height) +end + +function addon:GetSpellIcon(spellID) + return select(3, GetSpellInfo(spellID)) +end + +function addon:GetIDFromLink(link) + if link then + return tonumber(link:match("item:(%d+)")) + end +end + +function addon:GetSpellIDFromRecipeLink(link) + -- returns nil if recipe id is not in the DB, returns the spellID otherwise + local recipeID = addon:GetIDFromLink(link) + return addon.RecipeDB[recipeID] +end + +function addon:GetMoneyString(copper, color, noTexture) + color = color or "|cFFFFD700" + + local gold = floor( copper / 10000 ); + copper = mod(copper, 10000) + local silver = floor( copper / 100 ); + copper = mod(copper, 100) + + if noTexture then -- use noTexture for places where the texture does not fit too well, ex: tooltips + copper = format("%s%s%s%s", color, copper, "|cFFEDA55F", COPPER_AMOUNT_SYMBOL) + silver = format("%s%s%s%s", color, silver, "|cFFC7C7CF", SILVER_AMOUNT_SYMBOL) + gold = format("%s%s%s%s", color, gold, "|cFFFFD700", GOLD_AMOUNT_SYMBOL) + else + copper = color..format(COPPER_AMOUNT_TEXTURE, copper, 13, 13) + silver = color..format(SILVER_AMOUNT_TEXTURE, silver, 13, 13) + gold = color..format(GOLD_AMOUNT_TEXTURE, gold, 13, 13) + end + return format("%s %s %s", gold, silver, copper) +end + +function addon:GetTimeString(seconds) + local days = floor(seconds / 86400); -- TotalTime is expressed in seconds + seconds = mod(seconds, 86400) + local hours = floor(seconds / 3600); + seconds = mod(seconds, 3600) + local minutes = floor(seconds / 60); + seconds = mod(seconds, 60) + + return format("%s|rd %s|rh %s|rm", WHITE..days, WHITE..hours, WHITE..minutes) +end + +function addon:GetFactionColour(faction) + if faction == "Alliance" then + return "|cFF2459FF" + else + return RED + end +end + +function Altoholic:GetClassColor(class) + return Altoholic.ClassInfo[class] or WHITE +end + +function addon:GetDelayInDays(delay) + return floor((time() - delay) / 86400) +end + +function Altoholic:FormatDelay(timeStamp) + -- timeStamp = value when time() was last called for a given variable (ex: last time the mailbox was checked) + if not timeStamp then + return YELLOW .. NEVER + end + + if timeStamp == 0 then + return YELLOW .. "N/A" + end + + local seconds = (time() - timeStamp) + + -- 86400 seconds per day + -- assuming 30 days / month = 2.592.000 seconds + -- assuming 365 days / year = 31.536.000 seconds + -- in the absence of possibility to track real dates, these approximations will have to do the trick, as it's not possible at this point to determine the number of days in a month, or in a year. + + local year = floor(seconds / 31536000); + seconds = mod(seconds, 31536000) + + local month = floor(seconds / 2592000); + seconds = mod(seconds, 2592000) + + local day = floor(seconds / 86400); + seconds = mod(seconds, 86400) + + local hour = floor(seconds / 3600); + seconds = mod(seconds, 3600) + + -- note: RecentTimeDate is not a direct API function, it's in UIParent.lua + return RecentTimeDate(year, month, day, hour) +end + +function addon:GetRestedXP(character) + local rate = DS:GetRestXPRate(character) + + local coeff = 1 + if addon.Options:Get("RestXPMode") == 1 then + coeff = 1.5 + end + rate = rate * coeff + + -- second return value = the actual percentage of rest xp, as a numeric value (1 to 100, not 150) + local color = GREEN + if rate >= (100 * coeff) then + rate = 100 * coeff + else + if rate < (30 * coeff) then + color = RED + elseif rate < (60 * coeff) then + color = YELLOW + end + end + return format("%s%d", color, rate).."%", rate +end + +function addon:GetSuggestion(index, level) + if addon.Suggestions[index] then + for _, v in pairs( addon.Suggestions[index] ) do + if level < v[1] then -- the suggestions are sorted by level, so whenever we're below, return the text + return v[2] + end + end + end +end + +function Altoholic:UpdateSlider(name, text, field) + local s = _G[name] + _G[name .. "Text"]:SetText(text .. " (" .. s:GetValue() ..")"); + + if not Altoholic.db then return end + local a = Altoholic.db.global + if a == nil then return end + + a.options[field] = s:GetValue() + self:MoveMinimapIcon() +end + +function Altoholic:ShowWidgetTooltip(frame) + if not frame.tooltip then return end + + AltoTooltip:SetOwner(frame, "ANCHOR_LEFT"); + AltoTooltip:ClearLines(); + AltoTooltip:AddLine(frame.tooltip) + AltoTooltip:Show(); +end + +function Altoholic:ShowClassIcons() + local entry = "AltoholicFrameClassesItem" + local i = 1 + + local realm, account = Altoholic:GetCurrentRealm() + for characterName, character in pairs(DS:GetCharacters(realm, account)) do + local itemName = entry .. i; + local itemButton = _G[itemName]; + itemButton:SetScript("OnEnter", function(self) + Altoholic:DrawCharacterTooltip(self, self.CharName) + end) + itemButton:SetScript("OnLeave", function(self) + AltoTooltip:Hide() + end) + + local _, class = DS:GetCharacterClass(character) + local tc = CLASS_ICON_TCOORDS[class] + local itemTexture = _G[itemName .. "IconTexture"] + itemTexture:SetTexture("Interface\\Glues\\CharacterCreate\\UI-CharacterCreate-Classes"); + itemTexture:SetTexCoord(tc[1], tc[2], tc[3], tc[4]); + itemTexture:SetWidth(36); + itemTexture:SetHeight(36); + itemTexture:SetAllPoints(itemButton); + + Altoholic:CreateButtonBorder(itemButton) + + if DS:GetCharacterFaction(character) == "Alliance" then + itemButton.border:SetVertexColor(0.1, 0.25, 1, 0.5) + else + itemButton.border:SetVertexColor(1, 0, 0, 0.5) + end + itemButton.border:Show() + + itemButton.CharName = characterName + itemButton:Show() + + i = i + 1 + if i > 10 then -- users of Symbolic Links might have more than 10 columns, prevent it + break + end + end + + while i <= 10 do + _G[ entry .. i ]:Hide() + _G[ entry .. i ].CharName = nil + i = i + 1 + end +end + +function addon:CreateButtonBorder(frame) + if frame.border then return end + + local border = frame:CreateTexture(nil, "OVERLAY") + border:SetWidth(67); + border:SetHeight(67) + border:SetPoint("CENTER", frame) + border:SetTexture("Interface\\Buttons\\UI-ActionButton-Border") + border:SetBlendMode("ADD") + border:Hide() + + frame.border = border +end + +function Altoholic:DrawCharacterTooltip(self, charName) + local realm, account = Altoholic:GetCurrentRealm() + local character = DS:GetCharacter(charName, realm, account) + + AltoTooltip:SetOwner(self, "ANCHOR_LEFT"); + AltoTooltip:ClearLines(); + AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character)) + + AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"], + GREEN..DS:GetCharacterLevel(character), DS:GetCharacterRace(character), DS:GetCharacterClass(character)),1,1,1) + + local zone, subZone = DS:GetLocation(character) + AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..zone, GOLD..subZone),1,1,1) + + local restXP = DS:GetRestXP(character) + if restXP and restXP > 0 then + AltoTooltip:AddLine(format("%s: %s", L["Rest XP"], GREEN..restXP),1,1,1) + end + + AltoTooltip:AddLine("Average iLevel: " .. GREEN .. format("%.1f", DS:GetAverageItemLevel(character)),1,1,1); + + if IsAddOnLoaded("DataStore_Achievements") then + if DS:GetNumCompletedAchievements(character) > 0 then + AltoTooltip:AddLine(ACHIEVEMENTS_COMPLETED ..": " .. GREEN .. DS:GetNumCompletedAchievements(character) .. "/"..DS:GetNumAchievements(character)) + AltoTooltip:AddLine(ACHIEVEMENT_TITLE ..": " .. GREEN .. DS:GetNumAchievementPoints(character)) + end + end + + AltoTooltip:Show(); +end + +function addon:SetMsgBoxHandler(func, arg1, arg2) + local msg = AltoMsgBox + + msg.ButtonHandler = func + msg.arg1 = arg1 + msg.arg2 = arg2 +end + +function addon:MsgBox_OnClick(button) + -- until I have time to check all the places where msgbox is used, keep "button" as 1 for yes, and nil for no + -- also, change the handler to work with ... + local msg = AltoMsgBox + + if msg.ButtonHandler then + msg:ButtonHandler(button, msg.arg1, msg.arg2) + msg.ButtonHandler = nil -- prevent subsequent calls from coming back here + msg.arg1 = nil + msg.arg2 = nil + else + addon:Print("MessageBox Handler not defined") + end + msg:Hide(); + msg:SetHeight(100) + AltoMsgBox_Text:SetHeight(28) +end + +-- ** Unsafe Items ** +function addon:SaveUnsafeItem(itemID) + if not addon:IsItemUnsafe(itemID) then -- if the item is not a known unsafe item, save it in the db + table.insert(Altoholic.db.global.unsafeItems, itemID) + end +end + +function addon:IsItemUnsafe(itemID) + for _, v in pairs(Altoholic.db.global.unsafeItems) do -- browse current realm's unsafe item list + if v == itemID then -- if the itemID passed as parameter is a known unsafe item .. return true to skip it + return true + end + end +end + + +-- *** Hooks *** +local Orig_ChatEdit_InsertLink = ChatEdit_InsertLink + +function ChatEdit_InsertLink(text, ...) + if text and AltoholicFrame_SearchEditBox:IsVisible() then + if not DataStore_Crafts:IsTradeSkillWindowOpen() then + AltoholicFrame_SearchEditBox:Insert(GetItemInfo(text)) + return true + end + end + return Orig_ChatEdit_InsertLink(text, ...) +end diff --git a/Altoholic-Addon/Altoholic/Altoholic.toc b/Altoholic-Addon/Altoholic/Altoholic.toc new file mode 100644 index 0000000..dff5f4b --- /dev/null +++ b/Altoholic-Addon/Altoholic/Altoholic.toc @@ -0,0 +1,70 @@ +## Interface: 30300 +## Title: Altoholic +## Title-zhCN: |cffeedd99 [物品] |r: 全角色统计 Altoholic +## X-Curse-Packaged-Version: r90 +## X-Curse-Project-Name: Altoholic +## X-Curse-Project-ID: altoholic +## X-Curse-Repository-ID: wow/altoholic/mainline + +## Notes: Provides information about your alts +## Notes-ruRU: Предоставляет информацию о вашем персонажах +## Notes-zhTW: 讓你即時撿閱你所有角色的資料 +## Notes-zhCN: 能让你全面掌握你的所有角色的信息。 + +## Author: Thaoky (EU-Marécages de Zangar) +## Version: 3.3.002b +## X-Category: Inventory, Tradeskill, Mail +## X-Localizations: enUS, frFR, zhCN, zhTW, deDE, koKR, esES, esMX, ruRU +## X-Website: http://wow.curse.com/downloads/wow-addons/details/altoholic.aspx +## X-eMail: thaoky.altoholic@yahoo.com +## X-Donate: http://wow.curse.com/downloads/wow-addons/details/altoholic.aspx +## X-Credits: My guild (Odysseüs), all translators, the wowace community, and all users for their invaluable suggestions ! +## Dependencies: DataStore, DataStore_Achievements, DataStore_Auctions, DataStore_Characters, DataStore_Containers, DataStore_Crafts, DataStore_Currencies, DataStore_Inventory, DataStore_Mails, DataStore_Pets, DataStore_Quests, DataStore_Reputations, DataStore_Skills, DataStore_Spells, DataStore_Stats, DataStore_Talents + +## OptionalDeps: Ace3, LibDataBroker-1.1, LibPeriodicTable-3.1, LibBabble-Zone-3.0, LibBabble-Boss-3.0, LibBabble-Inventory-3.0, LibBabble-Faction-3.0, LibBabble-Class-3.0, LibCompress +## SavedVariables: AltoholicDB +## X-Category: Interface Enhancements + +#@no-lib-strip@ +# Libraries +embeds.xml +#@end-no-lib-strip@ + +# Hard-Embedded libraries from other sites +embedded.xml + +locale.xml + +AltoholicTemplates.xml +Altoholic.xml + +Frames\TabSummary.xml +Frames\TabCharacters.xml +Frames\TabGuildBank.xml + +# Do not move Equipment.xml, must be loaded before TabSearch (18/03/2009, Thaoky) +# note: review this, might not be necessary anymore with the implementation of DataStore (28/07/2009) +Frames\Equipment.xml +Frames\TabSearch.xml +Frames\TabOptions.xml + +Frames\AccountSharing.xml +Frames\AccountSummary.xml +Frames\Activity.xml +Frames\AuctionHouse.xml +Frames\BagUsage.xml +Frames\Calendar.xml +Frames\Containers.xml +Frames\Currencies.xml +Frames\GuildBank.xml +Frames\GuildMembers.xml +Frames\GuildBankTabs.xml +Frames\GuildProfessions.xml +Frames\Mails.xml +Frames\Pets.xml +Frames\Reputations.xml +Frames\Recipes.xml +Frames\Quests.xml +Frames\Skills.xml +Frames\Search.xml +Frames\Talents.xml \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Altoholic.xml b/Altoholic-Addon/Altoholic/Altoholic.xml new file mode 100644 index 0000000..115dc85 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Altoholic.xml @@ -0,0 +1,765 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/AltoholicTemplates.xml b/Altoholic-Addon/Altoholic/AltoholicTemplates.xml new file mode 100644 index 0000000..e021b3d --- /dev/null +++ b/Altoholic-Addon/Altoholic/AltoholicTemplates.xml @@ -0,0 +1,323 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Bindings.xml b/Altoholic-Addon/Altoholic/Bindings.xml new file mode 100644 index 0000000..3a7ddd3 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Bindings.xml @@ -0,0 +1,5 @@ + + + Altoholic:ToggleUI() + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Changelog-Altoholic-r90.txt b/Altoholic-Addon/Altoholic/Changelog-Altoholic-r90.txt new file mode 100644 index 0000000..8fc3cde --- /dev/null +++ b/Altoholic-Addon/Altoholic/Changelog-Altoholic-r90.txt @@ -0,0 +1,37 @@ +------------------------------------------------------------------------ +r90 | Thaoky | 2010-07-06 17:50:10 +0000 (Tue, 06 Jul 2010) | 1 line +Changed paths: + M /trunk/Altoholic.toc + M /trunk/Core.lua + M /trunk/Frames/TabOptions.lua + M /trunk/changelog.txt + +Version number update/what's new/etc.. +------------------------------------------------------------------------ +r89 | Thaoky | 2010-07-01 16:38:46 +0000 (Thu, 01 Jul 2010) | 1 line +Changed paths: + M /trunk/Altoholic.lua + M /trunk/Frames/AuctionHouse.lua + M /trunk/Frames/Calendar.lua + M /trunk/Frames/Equipment.lua + M /trunk/Frames/GuildProfessions.lua + M /trunk/Frames/Mails.lua + M /trunk/Frames/Pets.lua + M /trunk/Frames/Quests.lua + M /trunk/Frames/Recipes.lua + M /trunk/Frames/Recipes.xml + M /trunk/Frames/Reputations.lua + M /trunk/Frames/Search.xml + M /trunk/Frames/Skills.lua + M /trunk/Frames/Talents.lua + M /trunk/Modules/Altoholic_Achievements/Achievements.lua + M /trunk/Modules/Altoholic_Achievements/TabAchievements.lua + +Fixed the ChatFrameEditBox issue caused by 3.3.5 +------------------------------------------------------------------------ +r88 | thaoky | 2010-04-12 18:02:22 +0000 (Mon, 12 Apr 2010) | 1 line +Changed paths: + M /trunk/Modules/Altoholic_Achievements/Achievements.lua + +Added missing raid achievements. +------------------------------------------------------------------------ diff --git a/Altoholic-Addon/Altoholic/Characters.lua b/Altoholic-Addon/Altoholic/Characters.lua new file mode 100644 index 0000000..ba1782c --- /dev/null +++ b/Altoholic-Addon/Altoholic/Characters.lua @@ -0,0 +1,311 @@ +local addonName = ... +local addon = _G[addonName] + +local WHITE = "|cFFFFFFFF" + +local THIS_ACCOUNT = "Default" +local INFO_REALM_LINE = 0 +local INFO_CHARACTER_LINE = 1 +local INFO_TOTAL_LINE = 2 + +local THISREALM_THISACCOUNT = 1 +local THISREALM_ALLACCOUNTS = 2 +local ALLREALMS_THISACCOUNT = 3 +local ALLREALMS_ALLACCOUNTS = 4 + + +addon.Characters = {} + +local ns = addon.Characters -- ns = namespace + +local characterList +local view + +local function ProcessRealms(func) + local mode = addon.Options:Get("TabSummaryMode") + local thisRealm = GetRealmName() + + -- this account only + if mode == THISREALM_THISACCOUNT then + func(THIS_ACCOUNT, thisRealm) + + elseif mode == ALLREALMS_THISACCOUNT then + for realm in pairs(DataStore:GetRealms()) do + func(THIS_ACCOUNT, realm) + end + + -- all accounts + elseif mode == THISREALM_ALLACCOUNTS then + for account in pairs(DataStore:GetAccounts()) do + for realm in pairs(DataStore:GetRealms(account)) do + if realm == thisRealm then + func(account, realm) + end + end + end + + elseif mode == ALLREALMS_ALLACCOUNTS then + for account in pairs(DataStore:GetAccounts()) do + for realm in pairs(DataStore:GetRealms(account)) do + func(account, realm) + end + end + end +end + +local totalMoney +local totalPlayed +local totalLevels +local realmCount + +local function AddRealm(AccountName, RealmName) + + local comm = Altoholic.Comm.Sharing + if comm.SharingInProgress then + if comm.account == AccountName and RealmName == GetRealmName() then + -- if we're trying to add the account+realm we're currently copying, then don't add it now. + return + end + end + + local realmMoney = 0 + local realmPlayed = 0 + local realmLevels = 0 + local realmBagSlots = 0 + local realmFreeBagSlots = 0 + local realmBankSlots = 0 + local realmFreeBankSlots = 0 + + local SkillsCache = { {name = "", rank = 0}, {name = "", rank = 0} } + + -- 1) Add the realm name + table.insert(characterList, { linetype = INFO_REALM_LINE + (realmCount*3), + isCollapsed = false, + account = AccountName, + realm = RealmName + } ) + + -- 2) Add the characters + for characterName, character in pairs(DataStore:GetCharacters(RealmName, AccountName)) do + SkillsCache[1].name = "" + SkillsCache[1].rank = 0 + SkillsCache[1].spellID = nil + SkillsCache[2].name = "" + SkillsCache[2].rank = 0 + SkillsCache[2].spellID = nil + + local i = 1 + local professions = DataStore:GetPrimaryProfessions(character) + if professions then + for SkillName, s in pairs(professions) do + SkillsCache[i].name = SkillName + SkillsCache[i].rank = DataStore:GetSkillInfo(character, SkillName) + SkillsCache[i].spellID = DataStore:GetProfessionSpellID(SkillName) + i = i + 1 + + if i > 2 then -- it seems that under certain conditions, the loop continues after 2 professions.., so break + break + end + end + end + + table.insert(characterList, { linetype = INFO_CHARACTER_LINE + (realmCount*3), + key = character, + skillName1 = SkillsCache[1].name, + skillRank1 = SkillsCache[1].rank, + spellID1 = SkillsCache[1].spellID, + skillName2 = SkillsCache[2].name, + skillRank2 = SkillsCache[2].rank, + spellID2 = SkillsCache[2].spellID, + cooking = DataStore:GetCookingRank(character), + firstaid = DataStore:GetFirstAidRank(character), + fishing = DataStore:GetFishingRank(character), + riding = DataStore:GetRidingRank(character), + } ) + + realmLevels = realmLevels + (DataStore:GetCharacterLevel(character) or 0) + realmMoney = realmMoney + (DataStore:GetMoney(character) or 0) + realmPlayed = realmPlayed + (DataStore:GetPlayTime(character) or 0) + + realmBagSlots = realmBagSlots + (DataStore:GetNumBagSlots(character) or 0) + realmFreeBagSlots = realmFreeBagSlots + (DataStore:GetNumFreeBagSlots(character) or 0) + realmBankSlots = realmBankSlots + (DataStore:GetNumBankSlots(character) or 0) + realmFreeBankSlots = realmFreeBankSlots + (DataStore:GetNumFreeBankSlots(character) or 0) + end -- end char + + -- 3) Add the totals + table.insert(characterList, { linetype = INFO_TOTAL_LINE + (realmCount*3), + level = WHITE .. realmLevels, + money = realmMoney, + played = Altoholic:GetTimeString(realmPlayed), + bagSlots = realmBagSlots, + freeBagSlots = realmFreeBagSlots, + bankSlots = realmBankSlots, + freeBankSlots = realmFreeBankSlots + } ) + + totalMoney = totalMoney + realmMoney + totalPlayed = totalPlayed + realmPlayed + totalLevels = totalLevels + realmLevels + realmCount = realmCount + 1 +end + +function ns:BuildList() + characterList = characterList or {} + wipe(characterList) + + totalMoney = 0 + totalPlayed = 0 + totalLevels = 0 + realmCount = 0 -- will be required for sorting purposes + ProcessRealms(AddRealm) + + AltoholicFrameTotalLv:SetText(format("%s |rLv", WHITE .. totalLevels)) + AltoholicFrameTotalGold:SetText(format(GOLD_AMOUNT_TEXTURE, floor( totalMoney / 10000 ), 13, 13)) + AltoholicFrameTotalPlayed:SetText(floor(totalPlayed / 86400) .. "|cFFFFD700d") +end + +local function AddRealmView(AccountName, RealmName) + for index, line in pairs(characterList) do + if mod(line.linetype, 3) == INFO_REALM_LINE then + if (line.account == AccountName) and (line.realm == RealmName) then + -- insert index to current line (INFO_REALM_LINE) + table.insert(view, index) + index = index + 1 + + -- insert index to the rest of the realm + local linetype = mod(characterList[index].linetype, 3) + while (linetype ~= INFO_REALM_LINE) do + table.insert(view, index) + index = index + 1 + if index > #characterList then + return + end + linetype = mod(characterList[index].linetype, 3) + end + return + end + end + end +end + +function ns:BuildView() + -- The character info index is a small table that basically indexes character info + -- ex: character info contains data for 4 realms on two accounts, but the index only cares about the summary tab filter, + -- and indexes just one realm, or one account + view = view or {} + wipe(view) + + ProcessRealms(AddRealmView) +end + +local function SortByPrimarySkill(a, b, skillName, ascending) + if (a.linetype ~= b.linetype) then -- sort by linetype first .. + return a.linetype < b.linetype + else -- and when they're identical, sort by field xx + if mod(a.linetype, 3) ~= INFO_CHARACTER_LINE then + return false -- don't swap lines if they're not INFO_CHARACTER_LINE + end + + local skillA = DataStore:GetSkillInfo(a.key, a[skillName]) + local skillB = DataStore:GetSkillInfo(b.key, b[skillName]) + + if ascending then + return skillA < skillB + else + return skillA > skillB + end + end +end + +local function SortByFunction(a, b, func, ascending) + if (a.linetype ~= b.linetype) then -- sort by linetype first .. + return a.linetype < b.linetype + else -- and when they're identical, sort by func xx + if mod(a.linetype, 3) ~= INFO_CHARACTER_LINE then + return false -- don't swap lines if they're not INFO_CHARACTER_LINE + end + + local retA = DataStore[func](self, a.key) or 0 -- set to zero if a return value is nil, so that they can be compared + local retB = DataStore[func](self, b.key) or 0 + + if ascending then + return retA < retB + else + return retA > retB + end + end +end + +function ns:Sort(frame, field) + local ascending = frame.ascendingSort + + -- Primary Skill + if (field == "skillName1") or (field == "skillName2") then + table.sort(characterList, function(a, b) return SortByPrimarySkill(a, b, field, ascending) + end) + else + table.sort(characterList, function(a, b) return SortByFunction(a, b, field, ascending) end) + end + + addon.Tabs.Summary:Refresh() +end + +function ns:Get(index) + return characterList[index] +end + +function ns:GetView() + return view +end + +function ns:GetNum() + return #characterList or 0 +end + +function ns:GetInfo(index) + -- with the line number in the characterList table, return the name, realm & account of a char. + local lineType = ns:GetLineType(index) + + if lineType == INFO_REALM_LINE then + local line = characterList[index] + return _, line.realm, line.account + elseif lineType == INFO_CHARACTER_LINE then + local account, realm, name = strsplit(".", characterList[index].key) + return name, realm, account + end +end + +function ns:GetLineType(index) + return mod(characterList[index].linetype, 3) +end + +function ns:GetField(index, field) + local character = characterList[index] + if character then + return character[field] + end +end + +function ns:ToggleView(frame) + for _, line in pairs(characterList) do + if mod(line.linetype, 3) == INFO_REALM_LINE then + line.isCollapsed = (frame.isCollapsed) or false + end + end +end + +function ns:ToggleHeader(frame) + local line = frame:GetParent():GetID() + if line == 0 then return end + + local header = characterList[line] + + if header.isCollapsed ~= nil then + if header.isCollapsed == true then + header.isCollapsed = false + else + header.isCollapsed = true + end + end +end diff --git a/Altoholic-Addon/Altoholic/Comm.lua b/Altoholic-Addon/Altoholic/Comm.lua new file mode 100644 index 0000000..0637aee --- /dev/null +++ b/Altoholic-Addon/Altoholic/Comm.lua @@ -0,0 +1,548 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +-- local LibComp = LibStub:GetLibrary("LibCompress") + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +Altoholic.Comm = {} + +-- Message types +local MSG_ACCOUNT_SHARING_REQUEST = 1 +local MSG_ACCOUNT_SHARING_REFUSED = 2 +local MSG_ACCOUNT_SHARING_REFUSEDINCOMBAT = 3 +local MSG_ACCOUNT_SHARING_REFUSEDDISABLED = 4 +local MSG_ACCOUNT_SHARING_ACCEPTED = 5 +local MSG_ACCOUNT_SHARING_SENDITEM = 6 +local MSG_ACCOUNT_SHARING_COMPLETED = 7 +local MSG_ACCOUNT_SHARING_ACK = 8 -- a simple ACK message, confirms message has been received, but no data is sent back + +local CMD_DATASTORE_XFER = 100 +local CMD_DATASTORE_CHAR_XFER = 101 -- these 2 require a special treatment +local CMD_DATASTORE_STAT_XFER = 102 +local CMD_BANKTAB_XFER = 103 +local CMD_REFDATA_XFER = 104 + + +local TOC_SEP = "|" -- separator used between items + +-- TOC Item Types +local TOC_SETREALM = "1" +local TOC_SETGUILD = "2" +local TOC_BANKTAB = "3" +local TOC_SETCHAR = "4" +local TOC_DATASTORE = "5" +local TOC_REFDATA = "6" + + + +--[[ *** Protocol *** + +Client Server + +==> MSG_ACCOUNT_SHARING_REQUEST +<== MSG_ACCOUNT_SHARING_REFUSED (stop) +or +<== MSG_ACCOUNT_SHARING_ACCEPTED (receives the TOC) + +while toc not empty +==> MSG_ACCOUNT_SHARING_SENDNEXT (pass the type, based on the TOC) +<== CMD_??? (transfer & save data) +wend + +==> MSG_ACCOUNT_SHARING_COMPLETED + +--]] + +Altoholic.Comm.Sharing = {} +Altoholic.Comm.Sharing.Callbacks = { + [MSG_ACCOUNT_SHARING_REQUEST] = "OnSharingRequest", + [MSG_ACCOUNT_SHARING_REFUSED] = "OnSharingRefused", + [MSG_ACCOUNT_SHARING_REFUSEDINCOMBAT] = "OnPlayerInCombat", + [MSG_ACCOUNT_SHARING_REFUSEDDISABLED] = "OnSharingDisabled", + [MSG_ACCOUNT_SHARING_ACCEPTED] = "OnSharingAccepted", + [MSG_ACCOUNT_SHARING_SENDITEM] = "OnSendItemReceived", + [MSG_ACCOUNT_SHARING_COMPLETED] = "OnSharingCompleted", + [MSG_ACCOUNT_SHARING_ACK] = "OnAckReceived", + + [CMD_DATASTORE_XFER] = "OnDataStoreReceived", + [CMD_DATASTORE_CHAR_XFER] = "OnDataStoreCharReceived", + [CMD_DATASTORE_STAT_XFER] = "OnDataStoreStatReceived", + [CMD_BANKTAB_XFER] = "OnGuildBankTabReceived", + [CMD_REFDATA_XFER] = "OnRefDataReceived", +} + +local compressionMode = 1 +local importedChars + +local function Whisper(player, messageType, ...) + local serializedData = Altoholic:Serialize(messageType, ...) + --DEFAULT_CHAT_FRAME:AddMessage(strlen(serializedData)) + + -- if compressionMode == 1 then -- no comp + Altoholic:SendCommMessage("AltoShare", serializedData, "WHISPER", player) + + -- elseif compressionMode == 2 then -- comp huff + -- local compData = LibComp:CompressHuffman(serializedData) + + -- local ser, comp + -- ser = strlen(serializedData) + -- comp = strlen(compData) + -- DEFAULT_CHAT_FRAME:AddMessage(format("Compression (%d/%d) : %2.1f", ser, comp, (comp/ser)*100)) + + -- Altoholic:SendCommMessage("AltoShare", compData, "WHISPER", player) + + -- elseif compressionMode == 3 then -- comp lzw + -- local compData = LibComp:CompressLZW(serializedData) + + -- local ser, comp + -- ser = strlen(serializedData) + -- comp = strlen(compData) + -- DEFAULT_CHAT_FRAME:AddMessage(format("Compression (%d/%d) : %2.1f", ser, comp, (comp/ser)*100)) + + -- Altoholic:SendCommMessage("AltoShare", compData, "WHISPER", player) + -- end +end + +local function GetRequestee() + local player -- name of the player to whom the account sharing request will be sent + + if AltoAccountSharing_UseTarget:GetChecked() then + player = UnitName("target") + elseif AltoAccountSharing_UseName:GetChecked() then + player = AltoAccountSharing_AccTargetEditBox:GetText() + end + + if player and strlen(player) > 0 then + return player + end +end + +local function SetStatus(text) + AltoAccountSharingTransferStatus:SetText(text) +end + +function Altoholic:AccSharingHandler(prefix, message, distribution, sender) + -- since Ace 3 communication handlers cannot be enabled/disabled on the fly, + -- let's use a function pointer to either an empty function, or the normal one + local self = Altoholic.Comm.Sharing + + if self and self.msgHandler then + self[self.msgHandler](self, prefix, message, distribution, sender) + end +end + +function Altoholic.Comm.Sharing:SetMessageHandler(handler) + self.msgHandler = handler +end + +function Altoholic.Comm.Sharing:EmptyHandler(prefix, message, distribution, sender) + -- automatically reply that the option is disabled + Whisper(sender, MSG_ACCOUNT_SHARING_REFUSEDDISABLED) +end + +function Altoholic.Comm.Sharing:ActiveHandler(prefix, message, distribution, sender) + local success, msgType, msgData + + if compressionMode == 1 then + success, msgType, msgData = Altoholic:Deserialize(message) +-- else +-- local decompData = LibComp:Decompress(message) +-- success, msgType, msgData = Altoholic:Deserialize(decompData) + end + + if not success then + self.SharingEnabled = nil + -- self:Print(msgType) + -- self:Print(string.sub(decompData, 1, 15)) + return + end + + if success and msgType then + local comm = Altoholic.Comm.Sharing + local cb = comm.Callbacks[msgType] + + if cb then + comm[cb](self, sender, msgData) -- process the message + end + end +end + +function Altoholic.Comm.Sharing:Request() + + local account = AltoAccountSharing_AccNameEditBox:GetText() + if not account or strlen(account) == 0 then -- account name cannot be empty + Altoholic:Print("[" .. L["Account Name"] .. "] " .. L["This field |cFF00FF00cannot|r be left empty."]) + return + end + + self.account = account + + local player = GetRequestee() + if player then + self.SharingInProgress = true + -- AltoAccountSharing:Hide() + -- Altoholic:Print(format(L["Sending account sharing request to %s"], player)) + SetStatus(format("Getting table of content from %s", player)) + Whisper(player, MSG_ACCOUNT_SHARING_REQUEST) + end +end + +local function ImportCharacters() + -- once data has been transfered, finalize the import by acknowledging that these alts can be seen by client addons + -- will be changed when account sharing goes into datastore. + for k, v in pairs(importedChars) do + DataStore:ImportCharacter(k, v.faction, v.guild) + end + importedChars = nil +end + +function Altoholic.Comm.Sharing:RequestNext(player) + self.NetDestCurItem = self.NetDestCurItem + 1 + local index = self.NetDestCurItem + + -- find the next checked item + local isChecked = Altoholic.Sharing.AvailableContent:IsItemChecked(index) + while not isChecked and index <= #self.DestTOC do + index = index + 1 + isChecked = Altoholic.Sharing.AvailableContent:IsItemChecked(index) + end + + if isChecked and index <= #self.DestTOC then + SetStatus(format("Transfering item %d/%d", index, #self.DestTOC )) + local TocData = self.DestTOC[index] + + local TocType = strsplit(TOC_SEP, TocData) + + if TocType == TOC_SETREALM then + _, self.ClientRealmName = strsplit(TOC_SEP, TocData) + elseif TocType == TOC_SETGUILD then + _, self.ClientGuildName = strsplit(TOC_SEP, TocData) + + elseif TocType == TOC_BANKTAB then + elseif TocType == TOC_SETCHAR then + _, self.ClientCharName = strsplit(TOC_SEP, TocData) + + elseif TocType == TOC_DATASTORE then + + elseif TocType == TOC_REFDATA then + end + + Whisper(player, MSG_ACCOUNT_SHARING_SENDITEM, index) + self.NetDestCurItem = index + return + end + + ImportCharacters() + SetStatus(L["Transfer complete"]) + Whisper(player, MSG_ACCOUNT_SHARING_COMPLETED) + + wipe(self.DestTOC) + self.DestTOC = nil + + self.SharingInProgress = nil + self.SharingEnabled = nil + self.NetDestCurItem = nil + self.ClientRealmName = nil + self.ClientGuildName = nil + self.ClientCharName = nil + + Altoholic.Sharing.AvailableContent:Clear() + self:SetMode(1) + + Altoholic:SetLastAccountSharingInfo(player, GetRealmName(), self.account) + + Altoholic.Characters:BuildList() + Altoholic.Characters:BuildView() + Altoholic.Tabs.Summary:Refresh() +end + +function Altoholic.Comm.Sharing:MsgBoxHandler(button) + + local self = Altoholic.Comm.Sharing + + AltoMsgBox.ButtonHandler = nil -- prevent any other call to msgbox from coming back here + local sender = AltoMsgBox.Sender + AltoMsgBox.Sender = nil + + if not button then + Whisper(sender, MSG_ACCOUNT_SHARING_REFUSED) + return + end + + self:SendSourceTOC(sender) +end + +local AUTH_AUTO = 1 +local AUTH_ASK = 2 +local AUTH_NEVER = 3 + +function Altoholic.Comm.Sharing:OnSharingRequest(sender, data) + self.SharingEnabled = nil + + if UnitAffectingCombat("player") ~= nil then + -- automatically reject if requestee is in combat + Whisper(sender, MSG_ACCOUNT_SHARING_REFUSEDINCOMBAT) + return + end + + local auth = Altoholic.Sharing.Clients:GetRights(sender) + + if not auth then -- if the sender is not a known client, add him with defaults rights (=ask) + Altoholic.Sharing.Clients:Add(sender) + auth = AUTH_ASK + end + + if auth == AUTH_AUTO then + self:SendSourceTOC(sender) + elseif auth == AUTH_ASK then + Altoholic:Print(format(L["Account sharing request received from %s"], sender)) + AltoMsgBox:SetHeight(130) + AltoMsgBox_Text:SetHeight(60) + AltoMsgBox.ButtonHandler = Altoholic.Comm.Sharing.MsgBoxHandler + AltoMsgBox.Sender = sender + AltoMsgBox_Text:SetText(format(L["You have received an account sharing request\nfrom %s%s|r, accept it?"], WHITE, sender) .. "\n\n" + .. format(L["%sWarning:|r if you accept, %sALL|r information known\nby Altoholic will be sent to %s%s|r (bags, money, etc..)"], WHITE, GREEN, WHITE,sender)) + AltoMsgBox:Show() + elseif auth == AUTH_NEVER then + Whisper(sender, MSG_ACCOUNT_SHARING_REFUSED) + end +end + +function Altoholic.Comm.Sharing:SendSourceTOC(sender) + self.SharingEnabled = true + self.SourceTOC = Altoholic.Sharing.Content:GetSourceTOC() + -- self.NetSrcCurItem = 0 -- to display that item is 1 of x + self.AuthorizedRecipient = sender + Altoholic:Print(format(L["Sending table of content (%d items)"], #self.SourceTOC)) + Whisper(sender, MSG_ACCOUNT_SHARING_ACCEPTED, self.SourceTOC) +end + +function Altoholic.Comm.Sharing:GetContent() + local player = GetRequestee() + if player then + self:SetMode(3) + self:RequestNext(player) + end +end + +function Altoholic.Comm.Sharing:GetAccount() + return self.account +end + +function Altoholic.Comm.Sharing:SetMode(mode) + local button = AltoAccountSharing_SendButton + if mode == 1 then -- send request, expect toc in return + button:SetText("Send Request") + button:Enable() + button.requestMode = nil + elseif mode == 2 then -- request content, get data in return + button:SetText("Request Content") + button:Enable() + button.requestMode = true + elseif mode == 3 then + importedChars = importedChars or {} + wipe(importedChars) + button:Disable() + end +end + +function Altoholic.Comm.Sharing:OnSharingRefused(sender, data) + SetStatus(format(L["Request rejected by %s"], sender)) + self.SharingInProgress = nil +end + +function Altoholic.Comm.Sharing:OnPlayerInCombat(sender, data) + SetStatus(format(L["%s is in combat, request cancelled"], sender)) + self.SharingInProgress = nil +end + +function Altoholic.Comm.Sharing:OnSharingDisabled(sender, data) + SetStatus(format(L["%s has disabled account sharing"], sender)) + self.SharingInProgress = nil +end + +function Altoholic.Comm.Sharing:OnSharingAccepted(sender, data) + self.DestTOC = data + self.NetDestCurItem = 0 + SetStatus(format(L["Table of content received (%d items)"], #self.DestTOC)) + + -- build & refresh the scroll frame + Altoholic.Sharing.AvailableContent:BuildView() + Altoholic.Sharing.AvailableContent:Update() + + -- change the text on the 'send' button + self:SetMode(2) +end + +-- Send Content +function Altoholic.Comm.Sharing:OnSendItemReceived(sender, data) + -- Server side, a request to send a given item is processed here + if not self.SharingEnabled or not self.AuthorizedRecipient then + return + end + + local DS = DataStore + local index = tonumber(data) -- get the index of the item in the toc + + local TocData = self.SourceTOC[index] + local TocType = strsplit(TOC_SEP, TocData) -- get its type + + if TocType == TOC_SETREALM then + _, self.ServerRealmName = strsplit(TOC_SEP, TocData) + Whisper(self.AuthorizedRecipient, MSG_ACCOUNT_SHARING_ACK) + elseif TocType == TOC_SETGUILD then + _, self.ServerGuildName = strsplit(TOC_SEP, TocData) + Whisper(self.AuthorizedRecipient, MSG_ACCOUNT_SHARING_ACK) + elseif TocType == TOC_BANKTAB then + local _, _, tabID = strsplit(TOC_SEP, TocData) + tabID = tonumber(tabID) + local guild = DS:GetGuild(self.ServerGuildName, self.ServerRealmName) + Whisper(self.AuthorizedRecipient, CMD_BANKTAB_XFER, DS:GetGuildBankTab(guild, tabID)) + elseif TocType == TOC_SETCHAR then -- character ? send mandatory modules (char definition = DS_Char + DS_Stats) + _, self.ServerCharacterName = strsplit(TOC_SEP, TocData) + Whisper(self.AuthorizedRecipient, CMD_DATASTORE_CHAR_XFER, DS:GetCharacterTable("DataStore_Characters", self.ServerCharacterName, self.ServerRealmName)) + Whisper(self.AuthorizedRecipient, CMD_DATASTORE_STAT_XFER, DS:GetCharacterTable("DataStore_Stats", self.ServerCharacterName, self.ServerRealmName)) + + elseif TocType == TOC_DATASTORE then -- DS ? Send the appropriate DS module + local _, moduleID = strsplit(TOC_SEP, TocData) + local moduleName = Altoholic.Sharing.Content:GetOptionalModuleName(tonumber(moduleID)) + Whisper(self.AuthorizedRecipient, CMD_DATASTORE_XFER, DS:GetCharacterTable(moduleName, self.ServerCharacterName, self.ServerRealmName)) + + elseif TocType == TOC_REFDATA then + local _, class = strsplit(TOC_SEP, TocData) + Whisper(self.AuthorizedRecipient, CMD_REFDATA_XFER, DS:GetClassReference(class)) + end +end + +function Altoholic.Comm.Sharing:OnSharingCompleted(sender, data) + self.SharingEnabled = nil + self.AuthorizedRecipient = nil + self.ServerRealmName = nil + self.ServerGuildName = nil + self.ServerCharacterName = nil + wipe(self.SourceTOC) + + self.SourceTOC = nil + Altoholic:Print(L["Transfer complete"]) +end + +function Altoholic.Comm.Sharing:OnAckReceived(sender, data) + self:RequestNext(sender) +end + + +-- Receive content +function Altoholic.Comm.Sharing:OnDataStoreReceived(sender, data) + local TocData = self.DestTOC[self.NetDestCurItem] + local _, moduleID = strsplit(TOC_SEP, TocData) + local moduleName = Altoholic.Sharing.Content:GetOptionalModuleName(tonumber(moduleID)) + + DataStore:ImportData(moduleName, data, self.ClientCharName, self.ClientRealmName, self.account) + self:RequestNext(sender) +end + +function Altoholic.Comm.Sharing:OnDataStoreCharReceived(sender, data) + DataStore:ImportData("DataStore_Characters", data, self.ClientCharName, self.ClientRealmName, self.account) + + -- temporarily deal with this here, will be changed when account sharing goes to DataStore. + local key = format("%s.%s.%s", self.account, self.ClientRealmName, self.ClientCharName) + + importedChars[key] = {} + importedChars[key].faction = data.faction + importedChars[key].guild = data.guildName + + -- NO REQUEST NEXT HERE !! +end + +function Altoholic.Comm.Sharing:OnDataStoreStatReceived(sender, data) + DataStore:ImportData("DataStore_Stats", data, self.ClientCharName, self.ClientRealmName, self.account) + -- Request next, to resume transfer after processing mandatory data + self:RequestNext(sender) +end + +function Altoholic.Comm.Sharing:OnGuildBankTabReceived(sender, data) + local TocData = self.DestTOC[self.NetDestCurItem] + local _, _, tabID = strsplit(TOC_SEP, TocData) + tabID = tonumber(tabID) + + local DS = DataStore + local guild = DS:GetGuild(self.ClientGuildName, self.ClientRealmName) + + DS:ImportGuildBankTab(guild, tabID, data) + self:RequestNext(sender) +end + +function Altoholic.Comm.Sharing:OnRefDataReceived(sender, data) + local TocData = self.DestTOC[self.NetDestCurItem] + local _, class = strsplit(TOC_SEP, TocData) + + DataStore:ImportClassReference(class, data) +-- Altoholic:Print(format(L["Reference data received (%s) !"], class)) + self:RequestNext(sender) +end + + +-- *** DataStore Event Handlers *** +function addon:DATASTORE_BANKTAB_REQUESTED(event, sender, tabName) + if addon.Options:Get("GuildBankAutoUpdate") == 1 then + DataStore:SendBankTabToGuildMember(sender, tabName) + return + end + + AltoMsgBox:SetHeight(130) + AltoMsgBox_Text:SetHeight(60) + + addon:SetMsgBoxHandler(function(self, button, sender, tabName) + if not button then + DataStore:RejectBankTabRequest(sender) + else + DataStore:SendBankTabToGuildMember(sender, tabName) + end + end, sender, tabName) + + AltoMsgBox_Text:SetText(format(L["%s%s|r has requested the bank tab %s%s|r\nSend this information ?"], WHITE, sender, WHITE, tabName) .. "\n\n" + .. format(L["%sWarning:|r make sure this user may view this information before accepting"], WHITE)) + AltoMsgBox:Show() +end + +function addon:DATASTORE_BANKTAB_REQUEST_ACK(event, sender) + addon:Print(format(L["Waiting for %s to accept .."], sender)) +end + +function addon:DATASTORE_BANKTAB_REQUEST_REJECTED(event, sender) + addon:Print(format(L["Request rejected by %s"], sender)) +end + +function addon:DATASTORE_BANKTAB_UPDATE_SUCCESS(event, sender, guildName, tabName, tabID) + addon.Tabs.GuildBank:LoadGuild("Default", GetRealmName(), guildName) + addon:Print(format(L["Guild bank tab %s successfully updated !"], tabName )) + addon.Guild.BankTabs:InvalidateView() +end + +function addon:DATASTORE_GUILD_ALTS_RECEIVED(event, sender, alts) + addon.Guild.Members:InvalidateView() + addon.Guild.Professions:InvalidateView() +end + +function addon:DATASTORE_GUILD_BANKTABS_UPDATED(event, sender) + addon.Guild.BankTabs:InvalidateView() +end + +function addon:DATASTORE_GUILD_PROFESSION_RECEIVED(event, sender, alt, data, index) + addon.Guild.Professions:InvalidateView() +end + +function addon:DATASTORE_GUILD_MEMBER_OFFLINE(event, member) + addon.Guild.Members:InvalidateView() + addon.Guild.Professions:InvalidateView() +end + +function addon:DATASTORE_GUILD_MAIL_RECEIVED(event, sender, recipient) + if addon.Options:Get("GuildMailWarning") == 1 then + addon:Print(format(L["%s|r has received a mail from %s"], GREEN..recipient, GREEN..sender)) + end +end diff --git a/Altoholic-Addon/Altoholic/Core.lua b/Altoholic-Addon/Altoholic/Core.lua new file mode 100644 index 0000000..a13052e --- /dev/null +++ b/Altoholic-Addon/Altoholic/Core.lua @@ -0,0 +1,376 @@ +local addonName = ... + +_G[addonName] = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceConsole-3.0", "AceEvent-3.0", "AceComm-3.0", "AceSerializer-3.0") + +local addon = _G[addonName] + +addon.Version = "v3.3.002b" +addon.VersionNum = 303002 + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local commPrefix = addonName + +BINDING_HEADER_ALTOHOLIC = addonName; +BINDING_NAME_ALTOHOLIC_TOGGLE = "Toggle UI"; + +local options = { + type= "group", + args = { + search = { + type = "input", + name = L['search'], + usage = "", + desc = L["Search in bags"], + get = false, + set = "CmdSearchBags", + }, + show = { + type = "execute", + name = L['show'], + desc = L["Shows the UI"], + func = function() AltoholicFrame:Show() end + }, + hide = { + type = "execute", + name = L['hide'], + desc = L["Hides the UI"], + func = function() AltoholicFrame:Hide() end + }, + toggle = { + type = "execute", + name = L['toggle'], + desc = L["Toggles the UI"], + func = function() addon:ToggleUI() end + }, + }, +} + +local AddonDB_Defaults = { + global = { + Guilds = { + ['*'] = { -- ["Account.Realm.Name"] + hideInTooltip = nil, -- true if this guild should not be shown in the tooltip counters + }, + }, + Characters = { + ['*'] = { -- ["Account.Realm.Name"] + Friends = {}, + SavedInstance = {}, -- raid timers + Calendar = {}, + Timers = {}, -- goes in pair with Calendar, different table to prevent messing with Calendar, SavedInstance and ProfessionCooldowns, used for eggs among others + ConnectMMO = {}, -- Imported events come here + }, + }, + Sharing = { + Clients = {}, + SharedContent = { -- lists the shared content + -- ["Account.Realm.Name"] = true means the char is shared, + -- ["Account.Realm.Name.Module"] = true means the module is shared for that char + }, + Domains = { + ['*'] = { -- ["Account.Realm"] + lastSharingTimestamp = nil, -- a date, the last time information from this realm/account was queried and successfully saved. + lastUpdatedWith = nil, -- last player with whom the account sharing took place + }, + }, + }, + unsafeItems = {}, + options = { + -- ** Misc options ** + TabSummaryMode = 2, + lastContainerView = 1, -- default container view = bags+bank + + -- ** General options ** + RestXPMode = 0, -- display max rest xp in normal 100% mode or in level equivalent 150% mode (1) ? + AccSharingHandlerEnabled = 0, -- account sharing communication handler is disabled by default + GuildBankAutoUpdate = 0, -- can the guild bank tabs update requests be answered automatically or not. + GuildHandlerEnabled = 1, -- guild communication handler is enabled by default + UIScale = 1.0, + UITransparency = 1.0, + ClampWindowToScreen = 0, + + -- ** Search options ** + TotalLoots = 0, -- make at least one search in the loot tables to initialize these values + UnknownLoots = 0, + SearchAutoQuery = 0, + SortDescending = 0, -- display search results in the loot table in ascending (0) or descending (1) order ? + IncludeNoMinLevel = 1, + IncludeMailbox = 1, + IncludeGuildBank = 1, + IncludeRecipes = 1, + IncludeGuildSkills = 1, -- search other guild members' professions ? (via their profession links) + + -- ** Mail options ** + GuildMailWarning = 1, -- be informed when a guildie sends a mail to one of my alts + NameAutoComplete = 1, + + -- ** Minimap options ** + MinimapIconAngle = 180, + MinimapIconRadius = 78, + ShowMinimap = 1, + + -- ** Tooltip options ** + TooltipSource = 1, + TooltipCount = 1, + TooltipTotal = 1, + TooltipRecipeInfo = 1, + TooltipPetInfo = 1, + TooltipItemID = 0, -- display item id & item level in the tooltip (default: off) + TooltipGatheringNode = 1, -- display counters when mousing over a gathering node (default: on) + TooltipCrossFaction = 1, -- display counters for both factions on a pve server + TooltipMultiAccount = 1, -- display counters for all accounts on the same realm + + TooltipGuildBank = 1, + TooltipGuildBankCount = 1, -- total count = alts + guildbank (1) or alts only (0) + TooltipGuildBankCountPerTab = 0, -- guild count = guild:count or guild (tab 1: x, tab2: y ..) + + -- ** Calendar options ** + WeekStartsMonday = 0, + WarningDialogBox = 0, -- use a dialog box for warnings (1), or default chat frame (0) + DisableWarnings = 0, + WarningType1 = "30|15|10|5|4|3|2|1", -- for profession cooldowns + WarningType2 = "30|15|10|5|4|3|2|1", -- for dungeon resets + WarningType3 = "30|15|10|5|4|3|2|1", -- for calendar events + WarningType4 = "30|15|10|5|4|3|2|1", -- for item timers (like mysterious egg) + }, +}} + +-- ** LDB Launcher ** +LibStub:GetLibrary("LibDataBroker-1.1"):NewDataObject(addonName, { + type = "launcher", + icon = "Interface\\Icons\\INV_Drink_13", + OnClick = function(clickedframe, button) + addon:ToggleUI() + end, + text = (Broker2FuBar) and addonName or nil, -- only for fubar, not for ldb + label = addonName, +}) + + +local guildMembersVersion = {} -- hash table containing guild member info + +-- Message types +local MSG_SEND_VERSION = 1 -- Send Altoholic's version +local MSG_VERSION_REPLY = 2 -- Reply + +-- *** Utility functions *** +local function GuildBroadcast(messageType, ...) + local serializedData = addon:Serialize(messageType, ...) + addon:SendCommMessage(commPrefix, serializedData, "GUILD") +end + +local function GuildWhisper(player, messageType, ...) + if DataStore:IsGuildMemberOnline(player) then + local serializedData = addon:Serialize(messageType, ...) + addon:SendCommMessage(commPrefix, serializedData, "WHISPER", player) + end +end + +local function SaveVersion(sender, version) + guildMembersVersion[sender] = version +end + +-- *** Guild Comm *** +local function OnAnnounceLogin(self, guildName) + GuildBroadcast(MSG_SEND_VERSION, addon.Version) +end + +local function OnSendVersion(sender, version) + if sender ~= UnitName("player") then -- don't send back to self + GuildWhisper(sender, MSG_VERSION_REPLY, addon.Version) -- reply by sending my own version + end + SaveVersion(sender, version) -- .. and save it +end + +local function OnVersionReply(sender, version) + SaveVersion(sender, version) +end + +local GuildCommCallbacks = { + [MSG_SEND_VERSION] = OnSendVersion, + [MSG_VERSION_REPLY] = OnVersionReply, +} + +function addon:OnInitialize() + addon.db = LibStub("AceDB-3.0"):New(addonName .. "DB", AddonDB_Defaults) + LibStub("AceConfig-3.0"):RegisterOptionsTable(addonName, options) + + addon:RegisterChatCommand("Altoholic", "ChatCommand") + addon:RegisterChatCommand("Alto", "ChatCommand") + + DataStore:SetGuildCommCallbacks(commPrefix, GuildCommCallbacks) + + addon:RegisterMessage("DATASTORE_ANNOUNCELOGIN", OnAnnounceLogin) + addon:RegisterMessage("DATASTORE_GUILD_ALTS_RECEIVED") + + addon:RegisterComm("AltoShare", "AccSharingHandler") + addon:RegisterComm(commPrefix, DataStore:GetGuildCommHandler()) + + addon:RegisterMessage("DATASTORE_BANKTAB_REQUESTED") + addon:RegisterMessage("DATASTORE_BANKTAB_REQUEST_ACK") + addon:RegisterMessage("DATASTORE_BANKTAB_REQUEST_REJECTED") + addon:RegisterMessage("DATASTORE_BANKTAB_UPDATE_SUCCESS") + addon:RegisterMessage("DATASTORE_PLAYER_EQUIPMENT_RECEIVED") + addon:RegisterMessage("DATASTORE_GUILD_BANKTABS_UPDATED") + addon:RegisterMessage("DATASTORE_GUILD_PROFESSION_RECEIVED") + addon:RegisterMessage("DATASTORE_GUILD_MEMBER_OFFLINE") + addon:RegisterMessage("DATASTORE_GUILD_MAIL_RECEIVED") + addon:RegisterMessage("DATASTORE_GLOBAL_MAIL_EXPIRY") +end + +function addon:GetGuildMemberVersion(member) + if guildMembersVersion[member] then -- version number of a main ? + return guildMembersVersion[member] -- return it immediately + end + + -- check if member is an alt + local main = DataStore:GetNameOfMain(member) + if main and guildMembersVersion[main] then + return guildMembersVersion[main] + end +end + +function addon:ChatCommand(input) + if not input then + LibStub("AceConfigDialog-3.0"):Open(addonName) + else + LibStub("AceConfigCmd-3.0").HandleCommand(addon, "Alto", "Altoholic", input) + end +end + +addon.Guild = {} +addon.TradeSkills = {} +addon.TradeSkills.Recipes = {} + + +-- ** Tabs ** +local tabList = { + "Summary", + "Characters", + "Search", + "GuildBank", + "Achievements", +} + +local function SafeLoadAddOn(name) + if not IsAddOnLoaded(name) then + LoadAddOn(name) + end +end + +local function ShowTab(name) + local tab = _G[addonName.."Tab" .. name] + if tab then + tab:Show() + end +end + +local function HideTab(name) + local tab = _G[addonName.."Tab" .. name] + if tab then + tab:Hide() + end +end + +addon.Tabs = {} + +function addon.Tabs:HideAll() + for _, tabName in pairs(tabList) do + HideTab(tabName) + end +end + +function addon.Tabs:OnClick(index) + PanelTemplates_SetTab(_G[addonName.."Frame"], index); + self:HideAll() + self.current = index + self.Columns.prefix = addonName.."Tab"..tabList[index].."_Sort" + + if index == 5 then + SafeLoadAddOn(format("%s_%s", addonName, tabList[index])) -- make this part a bit more generic once we'll have more LoD parts + end + + ShowTab(tabList[index]) +end + +addon.Tabs.Columns = {} + +function addon.Tabs.Columns:Init() + local i = 1 + local prefix = self.prefix or "AltoholicTabSummary_Sort" + local button = _G[ prefix .. i ] + local arrow = _G[ prefix .. i .. "Arrow"] + + while button do + arrow:Hide() + button.ascendingSort = nil -- not sorted by default + button:Hide() + + i = i + 1 + button = _G[ prefix .. i ] + arrow = _G[ prefix .. i .. "Arrow"] + end + self.count = 0 + self.prefix = prefix +end + +function addon.Tabs.Columns:Add(title, width, func) + local prefix = self.prefix + self.count = self.count + 1 + local button = _G[ prefix..self.count ] + + if not title then -- no title ? count the column, but hide it + button:Hide() + return + end + + button:SetText(title) + button:SetWidth(width) + button:SetScript("OnClick", function(self) + local prefix = addon.Tabs.Columns.prefix + local i = 1 + local arrow = _G[ prefix .. i .. "Arrow"] + + while arrow do -- hide all arrows + arrow:Hide() + i = i + 1 + arrow = _G[ prefix .. i .. "Arrow"] + end + + arrow = _G[ prefix .. self:GetID() .. "Arrow"] + arrow:Show() -- show selected arrow + + if not self.ascendingSort then + self.ascendingSort = true + arrow:SetTexCoord(0, 0.5625, 1.0, 0); -- arrow pointing up + else + self.ascendingSort = nil + arrow:SetTexCoord(0, 0.5625, 0, 1.0); -- arrow pointing down + end + + if func then + func(self) + end + end) + button:Show() +end + + +-- Allow ESC to close the main frame +tinsert(UISpecialFrames, "AltoholicFrame"); +tinsert(UISpecialFrames, "AltoMsgBox"); + +function addon:CmdSearchBags(arg1, arg2) + -- arg 1 is a table, no idea of what it does, investigate later, only arg2 matters at this point + + if string.len(arg2) == 0 then + DEFAULT_CHAT_FRAME:AddMessage("|cFF00FF9A" .. L["Altoholic:|r Usage = /altoholic search "]) + return + end + + if not (AltoholicFrame:IsVisible()) then + AltoholicFrame:Show(); + end + AltoholicFrame_SearchEditBox:SetText(strlower(arg2)) + addon.Search:FindItem(); +end \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/AccountSharing.lua b/Altoholic-Addon/Altoholic/Frames/AccountSharing.lua new file mode 100644 index 0000000..56fba3c --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/AccountSharing.lua @@ -0,0 +1,880 @@ +local L = LibStub("AceLocale-3.0"):GetLocale("Altoholic") + +Altoholic.Sharing = {} +Altoholic.Sharing.Clients = {} -- authorized clients +Altoholic.Sharing.Content = {} -- shared content +Altoholic.Sharing.AvailableContent = {} -- available content + +local THIS_ACCOUNT = "Default" +local WHITE = "|cFFFFFFFF" +local RED = "|cFFFF0000" +local GREEN = "|cFF00FF00" +local LIGHTBLUE = "|cFFB0B0FF" + +local AUTH_AUTO = 1 +local AUTH_ASK = 2 +local AUTH_NEVER = 3 + +local function FirstCap(s) + return strupper(s:sub(1,1)) .. strlower(s:sub(2)) -- first letter in cap, the rest lowercase +end + +local function GetNumClients() + return #Altoholic.db.global.Sharing.Clients +end + +local function GetClientInfo(index) + local info = Altoholic.db.global.Sharing.Clients[index] + if info then + local name, auth = strsplit("|", info) + return name, tonumber(auth) + end +end + +local function GetSizeInKB(size) + return format("%2.1f KB", size / 1024) +end + +-- *** Authorized Clients *** + +local ClientsScrollFrame_Desc = { + NumLines = 6, + LineHeight = 18, + Frame = "AltoholicFrameSharingClients", + GetSize = function() + return #Altoholic.db.global.Sharing.Clients + end, + Update = function(self, offset, entry, desc) + for i=1, desc.NumLines do + local line = i + offset + if line <= desc:GetSize() then + local name, auth = GetClientInfo(line) + _G[ entry..i.."NameNormalText" ].name = name + + if auth == AUTH_NEVER then + name = RED..name + elseif auth == AUTH_AUTO then + name = GREEN..name + end + + _G[ entry..i.."NameNormalText" ]:SetText(name) + _G[ entry..i.."Never" ]:SetChecked((auth == AUTH_NEVER) and 1 or nil) + _G[ entry..i.."Ask" ]:SetChecked((auth == AUTH_ASK) and 1 or nil) + _G[ entry..i.."Auto" ]:SetChecked((auth == AUTH_AUTO) and 1 or nil) + + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + else + _G[ entry..i.."NameNormalText" ].name = nil + end + end + end, +} + +function Altoholic.Sharing.Clients:Update() + Altoholic:ScrollFrameUpdate(ClientsScrollFrame_Desc) +end + +function Altoholic.Sharing.Clients:Add(name) + if type(name) ~= "string" then return end + if strlen(name) == 0 then return end + + name = FirstCap(name) + + local clients = Altoholic.db.global.Sharing.Clients + local alreadyExists + + for _, clientInfo in pairs(clients) do + local clientName = strsplit("|", clientInfo) + if clientName == name then + alreadyExists = true + end + end + + if not alreadyExists then -- if this character does not exist, add it + table.insert(clients, format("%s|%s", name, AUTH_ASK)) + end +end + +function Altoholic.Sharing.Clients:Delete(name) + if type(name) ~= "string" then return end + + name = FirstCap(name) + local clients = Altoholic.db.global.Sharing.Clients + + for index, clientInfo in pairs(clients) do + local clientName = strsplit("|", clientInfo) + if clientName == name then -- clear the name if found in the table + table.remove(clients, index) + break + end + end +end + +function Altoholic.Sharing.Clients:Auth_OnClick(self) + local line = self:GetParent():GetID() + local name = GetClientInfo(line) + local clients = Altoholic.db.global.Sharing.Clients + + clients[line] = format("%s|%s", name, self:GetID()) + Altoholic.Sharing.Clients:Update() +end + +function Altoholic.Sharing.Clients:GetRights(name) + -- returns the right of a given player + local clients = Altoholic.db.global.Sharing.Clients + + for i = 1, GetNumClients() do + local clientName, auth = GetClientInfo(i) + if clientName == name then + return auth + end + end +end + + +-- *** Shared Content *** + +local mandatoryModules = { -- mandatory modules are sent anyway (if the character is shared, of course) + "DataStore_Characters", + "DataStore_Stats", +} + +local optionalModules = { -- this defines the order in which modules should be listed + "DataStore_Achievements", + "DataStore_Auctions", + "DataStore_Containers", + "DataStore_Crafts", + "DataStore_Currencies", + "DataStore_Inventory", + "DataStore_Mails", + "DataStore_Pets", + "DataStore_Quests", + "DataStore_Reputations", + "DataStore_Skills", + "DataStore_Spells", + "DataStore_Talents", +} + +local moduleLabels = { -- these are the labels + ["DataStore_Achievements"] = ACHIEVEMENT_BUTTON, -- "Achievements" + ["DataStore_Auctions"] = format("%s & %s", AUCTIONS, BIDS), +-- ["DataStore_Characters"] = , + ["DataStore_Containers"] = L["Containers"], + ["DataStore_Crafts"] = L["Professions"], + ["DataStore_Currencies"] = CURRENCY, + ["DataStore_Inventory"] = L["Equipment"], + ["DataStore_Mails"] = L["Mails"], + ["DataStore_Pets"] = format("%s & %s", COMPANIONS, MOUNTS), + ["DataStore_Quests"] = L["Quests"], + ["DataStore_Reputations"] = L["Reputations"], + ["DataStore_Skills"] = SKILLS, + ["DataStore_Spells"] = SPELLBOOK, +-- ["DataStore_Stats"] = , + ["DataStore_Talents"] = format("%s & %s", TALENTS, GLYPHS), +} + + +local GUILD_HEADER_LINE = 1 +local GUILD_BANKTAB_LINE = 2 +local CHARACTER_HEADER_LINE = 3 +local CHARACTER_DATASTORE_LINE = 4 +local CLASS_REFDATA_LINE = 5 -- only for available content, not for shared content view + +local function isGuildShared(realm, name) + local sc = Altoholic.db.global.Sharing.SharedContent + local index = format("%s.%s.%s", THIS_ACCOUNT, realm, name) + + return sc[index] +end + +local function isGuildBankTabShared(realm, name, tabID) + local sc = Altoholic.db.global.Sharing.SharedContent + local index = format("%s.%s.%s.%s", THIS_ACCOUNT, realm, name, tabID) + + return sc[index] +end + +local function isCharacterShared(key) + local sc = Altoholic.db.global.Sharing.SharedContent + return sc[key] +end + +local function isCharacterDataShared(key, module) + local sc = Altoholic.db.global.Sharing.SharedContent + local index = key .. "." .. module + + return sc[index] +end + + + +local ContentCollapsedHeaders -- a table containing the collapsed headers (character keys) + +local ContentScrollFrame_Desc = { + NumLines = 14, + LineHeight = 18, + Frame = "AltoholicFrameSharedContent", + GetSize = function() + return #Altoholic.Sharing.Content.view + end, + Update = function(self, offset, entry, desc) + local line, LineDesc + + for i=1, desc.NumLines do + line = i + offset + local lineData = Altoholic.Sharing.Content.view[line] + if line <= desc:GetSize() then + LineDesc = desc.Lines[lineData.linetype] + LineDesc:DrawCollapseButton(lineData, entry..i) + LineDesc:DrawCheckBox(lineData, entry..i) + _G[entry..i.."CheckText"]:SetText(LineDesc:GetText(lineData)) + _G[entry..i.."Check"]:SetPoint("TOPLEFT", LineDesc:GetOffset(lineData), 0) + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + end + end + end, + Lines = { + [GUILD_HEADER_LINE] = { + GetText = function(self, line) + return format("%s|r / %s", WHITE..line.realm, GREEN..line.name) + end, + GetOffset = function(self, line) + return 20 + end, + DrawCollapseButton = function(self, line, entry) + local item = _G[ entry.."Collapse" ] + local index = format("%s.%s.%s", THIS_ACCOUNT, line.realm, line.name) + + if not ContentCollapsedHeaders[index] then + item:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + else + item:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + end + item:Show() + end, + DrawCheckBox = function(self, line, entry) + _G[ entry.."Check" ]:SetChecked(isGuildShared(line.realm, line.name)) + end, + }, + [GUILD_BANKTAB_LINE] = { + GetText = function(self, line) + local DS = DataStore + local guild = DS:GetGuild(line.name, line.realm) + local tabName = DS:GetGuildBankTabName(guild, line.tabID) + + return tabName + end, + GetOffset = function(self, line) + return 40 + end, + DrawCollapseButton = function(self, line, entry) + _G[ entry.."Collapse" ]:Hide() + end, + DrawCheckBox = function(self, line, entry) + _G[ entry.."Check" ]:SetChecked(isGuildBankTabShared(line.realm, line.name, line.tabID)) + end, + }, + [CHARACTER_HEADER_LINE] = { + GetText = function(self, line) + local _, realm, name = strsplit(".", line.key) + return format("%s|r / %s", WHITE..realm, DataStore:GetColoredCharacterName(line.key)) + end, + GetOffset = function(self, line) + return 20 + end, + DrawCollapseButton = function(self, line, entry) + local item = _G[ entry.."Collapse" ] + if not ContentCollapsedHeaders[line.key] then + item:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + else + item:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + end + item:Show() + end, + DrawCheckBox = function(self, line, entry) + _G[ entry.."Check" ]:SetChecked(isCharacterShared(line.key)) + end, + }, + [CHARACTER_DATASTORE_LINE] = { + GetText = function(self, line) + return moduleLabels[line.module] + end, + GetOffset = function(self, line) + return 40 + end, + DrawCollapseButton = function(self, line, entry) + _G[ entry.."Collapse" ]:Hide() + end, + DrawCheckBox = function(self, line, entry) + _G[ entry.."Check" ]:SetChecked(isCharacterDataShared(line.key, line.module)) + end, + }, + }, +} + + +function Altoholic.Sharing.Content:BuildView() + ContentCollapsedHeaders = ContentCollapsedHeaders or {} + self.view = self.view or {} + wipe(self.view) + + local DS = DataStore + for realm in pairs(DS:GetRealms()) do -- all realms on this account + for guildName, guild in pairs(DS:GetGuilds(realm)) do -- add guilds + table.insert(self.view, { linetype = GUILD_HEADER_LINE, realm = realm, name = guildName } ) + + local index = format("%s.%s.%s", THIS_ACCOUNT, realm, guildName) + + if not ContentCollapsedHeaders[index] then + for i=1, 6 do -- add guild bank tabs + local tabName = DS:GetGuildBankTabName(guild, i) + if tabName then + table.insert(self.view, { linetype = GUILD_BANKTAB_LINE, realm = realm, name = guildName, tabID = i } ) + end + end + end + end + + for characterName, character in pairs(DS:GetCharacters(realm)) do + table.insert(self.view, { linetype = CHARACTER_HEADER_LINE, key = character } ) + + if not ContentCollapsedHeaders[character] then + for _, v in pairs(optionalModules) do + table.insert(self.view, { linetype = CHARACTER_DATASTORE_LINE, key = character, module = v } ) + end + end + end + end +end + +function Altoholic.Sharing.Content:Update() + Altoholic:ScrollFrameUpdate(ContentScrollFrame_Desc) +end + +function Altoholic.Sharing.Content:Collapse_OnClick(self, button) + local id = self:GetParent():GetID() + local self = Altoholic.Sharing.Content + local line = self.view[id] + + local index + if line.linetype == GUILD_HEADER_LINE then + index = format("%s.%s.%s", THIS_ACCOUNT, line.realm, line.name) + elseif line.linetype == CHARACTER_HEADER_LINE then + index = line.key + end + + if not ContentCollapsedHeaders[index] then + ContentCollapsedHeaders[index] = true + else + ContentCollapsedHeaders[index] = nil + end + self:BuildView() + self:Update() +end + +function Altoholic.Sharing.Content:Check_OnClick(self, button) + local id = self:GetParent():GetID() + local isChecked = self:GetChecked() + + local self = Altoholic.Sharing.Content + local line = self.view[id] + + local sc = Altoholic.db.global.Sharing.SharedContent + local index + + if line.linetype == GUILD_HEADER_LINE then + index = format("%s.%s.%s", THIS_ACCOUNT, line.realm, line.name) + elseif line.linetype == GUILD_BANKTAB_LINE then + index = format("%s.%s.%s.%s", THIS_ACCOUNT, line.realm, line.name, line.tabID) + elseif line.linetype == CHARACTER_HEADER_LINE then + index = line.key + else + index = line.key .. "." .. line.module + end + sc[index] = isChecked + self:BuildView() + self:Update() +end + +function Altoholic.Sharing.Content:ToggleAll(self, button) + local tex + + if not self.isCollapsed then -- are all entries collapsed or not ? + self.isCollapsed = true + tex = "Interface\\Buttons\\UI-PlusButton-Up" + else + self.isCollapsed = nil + tex = "Interface\\Buttons\\UI-MinusButton-Up" + end + self:SetNormalTexture(tex); + + local DS = DataStore + for realm in pairs(DS:GetRealms()) do -- all realms on this account + for guildName, _ in pairs(DS:GetGuilds(realm)) do + local index = format("%s.%s.%s", THIS_ACCOUNT, realm, guildName) + ContentCollapsedHeaders[index] = self.isCollapsed + end + + for characterName, character in pairs(DS:GetCharacters(realm)) do + ContentCollapsedHeaders[character] = self.isCollapsed + end + end + + local self = Altoholic.Sharing.Content + self:BuildView() + self:Update() +end + +function Altoholic.Sharing.Content:CheckAll(self, button) + local sc = Altoholic.db.global.Sharing.SharedContent + + if not self.isChecked then -- are all entries collapsed or not ? + self.isChecked = true + else + self.isChecked = nil + end + self:SetChecked(self.isChecked); + + local DS = DataStore + for realm in pairs(DS:GetRealms()) do -- all realms on this account + -- guilds + for guildName, guild in pairs(DS:GetGuilds(realm)) do + local index = format("%s.%s.%s", THIS_ACCOUNT, realm, guildName) + sc[index] = self.isChecked + + for i=1, 6 do -- add guild bank tabs + if DS:GetGuildBankTabName(guild, i) then + index = format("%s.%s.%s.%s", THIS_ACCOUNT, realm, guildName, i) + sc[index] = self.isChecked + end + end + end + + -- characters + for characterName, character in pairs(DS:GetCharacters(realm)) do + sc[character] = self.isChecked + + for _, v in pairs(optionalModules) do + sc[character .. "." .. v] = self.isChecked + end + end + end + + local self = Altoholic.Sharing.Content + self:BuildView() + self:Update() +end + +local TOC_SETREALM = "1" +local TOC_SETGUILD = "2" +local TOC_BANKTAB = "3" +local TOC_SETCHAR = "4" +local TOC_DATASTORE = "5" +local TOC_REFDATA = "6" + +function Altoholic.Sharing.Content:GetOptionalModuleName(index) + return optionalModules[index] +end + +function Altoholic.Sharing.Content:GetSourceTOC() + -- prepares the table of content that will be sent to the user requesting account sharing + + -- This method adds all realms, all guilds, all characters on the current account, assuming they are shared + -- Reference data (available classes) is always sent, and mandatory modules in datastore are not sent (they're implicit, if a character is shared, they must be sent) + + -- on the receiving side, display mandatory items as part of the list, but greyed out/disabled and automatically selected for transfer + + local DS = DataStore + local serializedData, lastUpdate + local toc = {} + + for realm in pairs(DS:GetRealms()) do -- all realms on this account + table.insert(toc, format("%s|%s", TOC_SETREALM, realm)) + + for guildName, guild in pairs(DS:GetGuilds(realm)) do -- add guilds + if isGuildShared(realm, guildName) then + table.insert(toc, format("%s|%s", TOC_SETGUILD, guildName)) + + for tabID = 1, 6 do -- add guild bank tabs + local tabName = DS:GetGuildBankTabName(guild, tabID) + if tabName and isGuildBankTabShared(realm, guildName, tabID) then + serializedData = Altoholic:Serialize(DS:GetGuildBankTab(guild, tabID)) + lastUpdate = DS:GetGuildBankTabLastUpdate(guild, tabID) + table.insert(toc, format("%s|%s|%s|%s|%s", TOC_BANKTAB, tabName, tabID, strlen(serializedData), lastUpdate or 0)) + end + end + end + end + + for characterName, character in pairs(DS:GetCharacters(realm)) do + if isCharacterShared(character) then + -- get the size of mandatory modules + local size = 0 + for k, module in pairs(mandatoryModules) do + serializedData = Altoholic:Serialize(DS:GetCharacterTable(module, characterName, realm)) + size = size + strlen(serializedData) + end + + local _, class = DS:GetCharacterClass(character) + lastUpdate = DS:GetModuleLastUpdate("DataStore_Characters", characterName, realm) + table.insert(toc, format("%s|%s|%s|%s|%s", TOC_SETCHAR, characterName, class, size, lastUpdate or 0)) + + + for k, module in pairs(optionalModules) do + if isCharacterDataShared(character, module) then + -- evaluate the size of transferred data + serializedData = Altoholic:Serialize(DS:GetCharacterTable(module, characterName, realm)) + lastUpdate = DS:GetModuleLastUpdate(module, characterName, realm) + + -- only pass the key to the right datastore module (ex 4 for DataStore_Crafts) + table.insert(toc, format("%s|%s|%s|%s", TOC_DATASTORE, k, strlen(serializedData), lastUpdate or 0)) + end + end + end + end + end + + -- add reference here + for class, _ in pairs(DS:GetReferenceTable()) do + serializedData = Altoholic:Serialize(DS:GetClassReference(class)) + table.insert(toc, format("%s|%s|%s", TOC_REFDATA, class, strlen(serializedData))) + end + + return toc +end + + + + +-- *** Available Content *** +local AvailableContentCollapsedHeaders -- a table containing the collapsed headers (character keys) +local AvailableContentCheckedItems -- a table containing the items checked in the TOC (index = true) + +local AvailableContentScrollFrame_Desc = { + NumLines = 10, + LineHeight = 18, + Frame = "AltoholicFrameAvailableContent", + GetSize = function() + return #Altoholic.Sharing.AvailableContent.view + end, + Update = function(self, offset, entry, desc) + local line, LineDesc + + for i=1, desc.NumLines do + line = i + offset + local lineData = Altoholic.Sharing.AvailableContent.view[line] + if line <= desc:GetSize() then + LineDesc = desc.Lines[lineData.linetype] + LineDesc:DrawCollapseButton(lineData, entry..i) + _G[entry..i.."CheckText"]:SetText(LineDesc:GetText(lineData)) + _G[entry..i.."Check"]:SetPoint("TOPLEFT", LineDesc:GetOffset(lineData), 0) + _G[entry..i.."Check"]:SetID(lineData.parentID) + _G[entry..i.."Check"]:SetChecked(AvailableContentCheckedItems[lineData.parentID]) + + if lineData.size then + _G[entry..i.."Size"]:SetText(LIGHTBLUE..GetSizeInKB(lineData.size)) + _G[entry..i.."Size"]:Show() + else + _G[entry..i.."Size"]:Hide() + end + + if lineData.lastUpdate then + local text + if lineData.lastUpdate == 0 then + text = RED..NEVER + else + text = LineDesc:GetDate(lineData) + end + + _G[entry..i.."Date"]:SetText(text) + _G[entry..i.."Date"]:Show() + else + _G[entry..i.."Date"]:Hide() + end + + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + end + end + end, + Lines = { + [GUILD_HEADER_LINE] = { + GetText = function(self, line) + return format("%s|r / %s", WHITE..line.realm, GREEN..line.name) + end, + GetOffset = function(self, line) + return 20 + end, + DrawCollapseButton = function(self, line, entry) + local item = _G[ entry.."Collapse" ] + local index = format("%s.%s.%s", Altoholic.Comm.Sharing:GetAccount(), line.realm, line.name) + + if not AvailableContentCollapsedHeaders[index] then + item:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + else + item:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + end + item:Show() + end, + GetDate = function(self, line) + return LIGHTBLUE..date("%m/%d/%Y %H:%M", line.lastUpdate) + end, + }, + [GUILD_BANKTAB_LINE] = { + GetText = function(self, line) + return line.tabName + end, + GetOffset = function(self, line) + return 40 + end, + DrawCollapseButton = function(self, line, entry) + _G[ entry.."Collapse" ]:Hide() + end, + GetDate = function(self, line) + return LIGHTBLUE..date("%m/%d/%Y %H:%M", line.lastUpdate) + end, + }, + [CHARACTER_HEADER_LINE] = { + GetText = function(self, line) + local _, realm, name = strsplit(".", line.key) + name = Altoholic:GetClassColor(line.class) ..name + return format("%s|r / %s", WHITE..realm, name) + end, + GetOffset = function(self, line) + return 20 + end, + DrawCollapseButton = function(self, line, entry) + local item = _G[ entry.."Collapse" ] + if not AvailableContentCollapsedHeaders[line.key] then + item:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + else + item:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + end + item:Show() + end, + GetDate = function(self, line) + local account, realm, name = strsplit(".", line.key) + local last = DataStore:GetModuleLastUpdate("DataStore_Characters", name, realm, account) + + if last == line.lastUpdate then + return GREEN.."Up-to-date" + else + return LIGHTBLUE..date("%m/%d/%Y %H:%M", line.lastUpdate) + end + end, + }, + [CHARACTER_DATASTORE_LINE] = { + GetText = function(self, line) + return moduleLabels[line.module] + end, + GetOffset = function(self, line) + return 40 + end, + DrawCollapseButton = function(self, line, entry) + _G[ entry.."Collapse" ]:Hide() + end, + GetDate = function(self, line) + local account, realm, name = strsplit(".", line.key) + local last = DataStore:GetModuleLastUpdate(line.module, name, realm, account) + + if last == line.lastUpdate then + return GREEN.."Up-to-date" + else + return LIGHTBLUE..date("%m/%d/%Y %H:%M", line.lastUpdate) + end + end, + }, + [CLASS_REFDATA_LINE] = { + GetText = function(self, line) + return "Talent Tree Reference : " .. FirstCap(line.class) + end, + GetOffset = function(self, line) + return 20 + end, + DrawCollapseButton = function(self, line, entry) + _G[ entry.."Collapse" ]:Hide() + end, + GetDate = function(self, line) + return LIGHTBLUE..date("%m/%d/%Y %H:%M", line.lastUpdate) + end, + }, + }, +} + + +function Altoholic.Sharing.AvailableContent:BuildView() + AvailableContentCollapsedHeaders = AvailableContentCollapsedHeaders or {} + AvailableContentCheckedItems = AvailableContentCheckedItems or {} + self.view = self.view or {} + wipe(self.view) + + local sharing = Altoholic.Comm.Sharing + self.ToC = sharing.DestTOC + if not self.ToC then return end + + local account = sharing:GetAccount() + local realm, character, guildName + + for i = 1, #self.ToC do + local tocType, arg1, arg2, arg3, arg4 = strsplit("|", self.ToC[i]) + + if tocType == TOC_SETREALM then + realm = arg1 + elseif tocType == TOC_SETGUILD then + guildName = arg1 + table.insert(self.view, { linetype = GUILD_HEADER_LINE, realm = realm, name = guildName, parentID = i } ) + elseif tocType == TOC_BANKTAB then + local index = format("%s.%s.%s", account, realm, guildName) + if not AvailableContentCollapsedHeaders[index] then + table.insert(self.view, { + linetype = GUILD_BANKTAB_LINE, + tabName = arg1, + tabID = tonumber(arg2), + size = tonumber(arg3), + lastUpdate = tonumber(arg4), + parentID = i, + } ) + end + elseif tocType == TOC_SETCHAR then + character = format("%s.%s.%s", account, realm, arg1) + table.insert(self.view, { + linetype = CHARACTER_HEADER_LINE, + key = character, + class = arg2, + size = tonumber(arg3), + lastUpdate = tonumber(arg4), + parentID = i, + } ) + elseif tocType == TOC_DATASTORE then + if not AvailableContentCollapsedHeaders[character] then + table.insert(self.view, { + linetype = CHARACTER_DATASTORE_LINE, + key = character, + module = optionalModules[tonumber(arg1)], + size = tonumber(arg2), + lastUpdate = tonumber(arg3), + parentID = i, + } ) + end + elseif tocType == TOC_REFDATA then + if not DataStore:IsClassKnown(arg1) then -- filter to only list classes that are not yet available + table.insert(self.view, { linetype = CLASS_REFDATA_LINE, class = arg1, size = tonumber(arg2), parentID = i } ) + end + end + end +end + +function Altoholic.Sharing.AvailableContent:Update() + Altoholic:ScrollFrameUpdate(AvailableContentScrollFrame_Desc) +end + +function Altoholic.Sharing.AvailableContent:Collapse_OnClick(self, button) + local id = self:GetParent():GetID() + local content = Altoholic.Sharing.AvailableContent + local line = content.view[id] + + local index + if line.linetype == GUILD_HEADER_LINE then + index = format("%s.%s.%s", Altoholic.Comm.Sharing:GetAccount(), line.realm, line.name) + elseif line.linetype == CHARACTER_HEADER_LINE then + index = line.key + end + + if not AvailableContentCollapsedHeaders[index] then + AvailableContentCollapsedHeaders[index] = true + else + AvailableContentCollapsedHeaders[index] = nil + end + content:BuildView() + content:Update() +end + +function Altoholic.Sharing.AvailableContent:Check_OnClick(self, button) + local id = self:GetID() + + if not AvailableContentCheckedItems[id] then + AvailableContentCheckedItems[id] = true + else + AvailableContentCheckedItems[id] = nil + end +end + +function Altoholic.Sharing.AvailableContent:ToggleAll(self, button) + local tex + + if not self.isCollapsed then -- are all entries collapsed or not ? + self.isCollapsed = true + tex = "Interface\\Buttons\\UI-PlusButton-Up" + else + self.isCollapsed = nil + tex = "Interface\\Buttons\\UI-MinusButton-Up" + end + self:SetNormalTexture(tex); + + local content = Altoholic.Sharing.AvailableContent + if not content.view then return end + + for k, v in pairs(content.view) do -- parse the whole view + local index + if v.linetype == GUILD_HEADER_LINE then -- get the right index in lines that actually require it + index = format("%s.%s.%s", Altoholic.Comm.Sharing:GetAccount(), v.realm, v.name) + elseif v.linetype == CHARACTER_HEADER_LINE then + index = v.key + end + + if index then + AvailableContentCollapsedHeaders[index] = self.isCollapsed + end + end + + content:BuildView() + content:Update() +end + +function Altoholic.Sharing.AvailableContent:CheckAll(self, button) + if not self.isChecked then -- are all entries collapsed or not ? + self.isChecked = true + else + self.isChecked = nil + end + self:SetChecked(self.isChecked); + + local content = Altoholic.Sharing.AvailableContent + if not content.view then return end + + for k, v in pairs(content.view) do -- parse the whole view + AvailableContentCheckedItems[v.parentID] = self.isChecked -- check or uncheck all + end + + local self = Altoholic.Sharing.AvailableContent + self:BuildView() + self:Update() +end + +function Altoholic.Sharing.AvailableContent:IsItemChecked(index) + if self.ToC then + local TocData = self.ToC[index] + if TocData then + local TocType = strsplit("|", TocData) + + if TocType == TOC_SETREALM then + -- until I have more time to implement a fancier solution, always return true for realm lines, necessary to correctly switch realms when importing data from foreign realms + return true + end + end + end + + return AvailableContentCheckedItems[index] +end + +function Altoholic.Sharing.AvailableContent:Clear() + -- clear command, after a successful transfer + + wipe(AvailableContentCollapsedHeaders) + wipe(AvailableContentCheckedItems) + + self:BuildView() + self:Update() +end diff --git a/Altoholic-Addon/Altoholic/Frames/AccountSharing.xml b/Altoholic-Addon/Altoholic/Frames/AccountSharing.xml new file mode 100644 index 0000000..26c4795 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/AccountSharing.xml @@ -0,0 +1,768 @@ + + + + + + + + + + + + + + + + self.tooltip = "Automatically authorize account sharing requests\nsent by this player" + self:SetChecked(nil) + + + local name = self:GetParent():GetName() + + _G[name .. "Ask"]:SetChecked(nil) + _G[name .. "Never"]:SetChecked(nil) + Altoholic.Sharing.Clients:Auth_OnClick(self) + + + Altoholic:ShowWidgetTooltip(self) + + + AltoTooltip:Hide(); + + + + + + + + + + + + + + self.tooltip = "Ask me whenever an account sharing\nrequest is sent by this player" + self:SetChecked(nil) + + + local name = self:GetParent():GetName() + + _G[name .. "Auto"]:SetChecked(nil) + _G[name .. "Never"]:SetChecked(nil) + Altoholic.Sharing.Clients:Auth_OnClick(self) + + + Altoholic:ShowWidgetTooltip(self) + + + AltoTooltip:Hide(); + + + + + + + + + + + + + + self.tooltip = "Automatically REJECT account sharing\nrequests sent by this player" + self:SetChecked(nil) + + + local name = self:GetParent():GetName() + + _G[name .. "Auto"]:SetChecked(nil) + _G[name .. "Ask"]:SetChecked(nil) + Altoholic.Sharing.Clients:Auth_OnClick(self) + + + Altoholic:ShowWidgetTooltip(self) + + + AltoTooltip:Hide(); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Sharing.Clients.Update) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Sharing.Content:Check_OnClick(self, button) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Sharing.Content.Update) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Sharing.AvailableContent:Check_OnClick(self, button) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Sharing.AvailableContent.Update) + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/AccountSummary.lua b/Altoholic-Addon/Altoholic/Frames/AccountSummary.lua new file mode 100644 index 0000000..9815fc0 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/AccountSummary.lua @@ -0,0 +1,513 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() + +local INFO_REALM_LINE = 0 +local INFO_CHARACTER_LINE = 1 +local INFO_TOTAL_LINE = 2 +local THIS_ACCOUNT = "Default" + +local TEAL = "|cFF00FF9A" +local WHITE = "|cFFFFFFFF" +local GOLD = "|cFFFFD700" +local YELLOW = "|cFFFFFF00" +local GREEN = "|cFF00FF00" + +local VIEW_BAGS = 1 +local VIEW_MAILS = 3 +local VIEW_QUESTS = 4 +local VIEW_AUCTIONS = 5 +local VIEW_BIDS = 6 +local VIEW_COMPANIONS = 7 +local VIEW_MOUNTS = 8 + +local ICON_FACTION_HORDE = "Interface\\Icons\\INV_BannerPVP_01" +local ICON_FACTION_ALLIANCE = "Interface\\Icons\\INV_BannerPVP_02" + +local Characters = addon.Characters + +local function GetFactionTotals(f, line) + local _, realm, account = Characters:GetInfo(line) + + local level = 0 + local money = 0 + local played = 0 + + local DS = DataStore + for _, character in pairs(DS:GetCharacters(realm, account)) do + if DS:GetCharacterFaction(character) == f then + level = level + DS:GetCharacterLevel(character) + money = money + DS:GetMoney(character) + played = played + DS:GetPlayTime(character) + end + end + + return level, money, played +end + +local function DDM_Add(text, value, func, arg1) + -- tiny wrapper + local info = UIDropDownMenu_CreateInfo(); + + info.text = text + info.value = value + info.func = func + info.arg1 = arg1 + info.checked = nil + UIDropDownMenu_AddButton(info, 1); +end + +local function DDM_AddCloseMenu() + local info = UIDropDownMenu_CreateInfo(); + + -- Close menu item + info.text = CLOSE + info.func = function() CloseDropDownMenus() end + info.checked = nil + info.notCheckable = 1 + info.icon = nil + UIDropDownMenu_AddButton(info, 1) +end + +addon.Summary = {} + +local ns = addon.Summary -- ns = namespace + +local function ViewAltInfo(self, characterInfoLine) + local name, realm, account = Characters:GetInfo(characterInfoLine) + addon:SetCurrentCharacter(name, realm, account) + addon.Tabs.Characters:SetCurrent(name, realm, account) + + addon.Tabs:OnClick(2) + addon.Tabs.Characters:ViewCharInfo(self.value) +end + +local function DeleteAlt_MsgBox_Handler(self, button, characterInfoLine) + if not button then return end + + local name, realm, account = Characters:GetInfo(characterInfoLine) + + DataStore:DeleteCharacter(name, realm, account) + + -- rebuild the main character table, and all the menus + Characters:BuildList() + Characters:BuildView() + addon.Summary:Update() + + addon:Print(format( L["Character %s successfully deleted"], name)) +end + +local function DeleteAlt(self, characterInfoLine) + local name, realm, account = Characters:GetInfo(characterInfoLine) + + if (account == THIS_ACCOUNT) and (realm == GetRealmName()) and (name == UnitName("player")) then + addon:Print(L["Cannot delete current character"]) + return + end + + addon:SetMsgBoxHandler(DeleteAlt_MsgBox_Handler, characterInfoLine) + + AltoMsgBox_Text:SetText(L["Delete this Alt"] .. "?\n" .. name) + AltoMsgBox:Show() +end + +local function UpdateRealm(self, characterInfoLine) + local _, realm, account = Characters:GetInfo(characterInfoLine) + + AltoAccountSharing_AccNameEditBox:SetText(account) + AltoAccountSharing_UseTarget:SetChecked(nil) + AltoAccountSharing_UseName:SetChecked(1) + + local _, updatedWith = addon:GetLastAccountSharingInfo(realm, account) + AltoAccountSharing_AccTargetEditBox:SetText(updatedWith) + + addon.Tabs.Summary:AccountSharingButton_OnClick() +end + +local function DeleteRealm_MsgBox_Handler(self, button, characterInfoLine) + if not button then return end + + local _, realm, account = Characters:GetInfo(characterInfoLine) + DataStore:DeleteRealm(realm, account) + + -- if the realm being deleted was the current .. + if addon:GetCurrentRealm() == realm and addon:GetCurrentAccount() == account then + + -- reset to this player + local tc = addon.Tabs.Characters + local player = UnitName("player") + local realmName = GetRealmName() + addon:SetCurrentCharacter(player, realmName, THIS_ACCOUNT) + addon.Tabs.Characters:SetCurrent(player, realmName, THIS_ACCOUNT) + addon.Containers:UpdateCache() + tc:ViewCharInfo(VIEW_BAGS) + end + + -- rebuild the main character table, and all the menus + Characters:BuildList() + Characters:BuildView() + addon.Summary:Update() + + addon:Print(format( L["Realm %s successfully deleted"], realm)) +end + +local function DeleteRealm(self, characterInfoLine) + local _, realm, account = Characters:GetInfo(characterInfoLine) + + if (account == THIS_ACCOUNT) and (realm == GetRealmName()) then + addon:Print(L["Cannot delete current realm"]) + return + end + + addon:SetMsgBoxHandler(DeleteRealm_MsgBox_Handler, characterInfoLine) + AltoMsgBox_Text:SetText(L["Delete this Realm"] .. "?\n" .. realm) + AltoMsgBox:Show() +end + + +function ns:Update() + local VisibleLines = 14 + local frame = "AltoholicFrameSummary" + local entry = frame.."Entry" + + + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local DisplayedCount = 0 + local VisibleCount = 0 + local DrawRealm + local i=1 + + local DS = DataStore + + local view = Characters:GetView() + if not view then return end + + for _, line in pairs(view) do + local lineType = Characters:GetLineType(line) + + if (offset > 0) or (DisplayedCount >= VisibleLines) then -- if the line will not be visible + if lineType == INFO_REALM_LINE then -- then keep track of counters + if Characters:GetField(line, "isCollapsed") == false then + DrawRealm = true + else + DrawRealm = false + end + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif DrawRealm then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + end + else -- line will be displayed + if lineType == INFO_REALM_LINE then + local _, realm, account = Characters:GetInfo(line) + + if Characters:GetField(line, "isCollapsed") == false then + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + DrawRealm = true + else + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + DrawRealm = false + end + _G[entry..i.."Collapse"]:Show() + _G[entry..i.."Name"]:SetWidth(300) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 25, 0) + _G[entry..i.."NameNormalText"]:SetWidth(300) + if account == THIS_ACCOUNT then -- saved as default, display as localized. + _G[entry..i.."NameNormalText"]:SetText(format("%s (%s".. L["Account"]..": %s%s|r)", realm, WHITE, GREEN, L["Default"])) + else + local last = addon:GetLastAccountSharingInfo(realm, account) + _G[entry..i.."NameNormalText"]:SetText(format("%s (%s".. L["Account"]..": %s%s %s%s|r)", realm, WHITE, GREEN, account, YELLOW, last or "")) + end + _G[entry..i.."Level"]:SetText("") + + _G[entry..i.."Money"]:SetText("") + _G[entry..i.."Played"]:SetText("") + _G[entry..i.."XP"]:SetText("") + _G[entry..i.."Rested"]:SetText("") + _G[entry..i.."AvgILevelNormalText"]:SetText("") + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + elseif DrawRealm then + if (lineType == INFO_CHARACTER_LINE) then + local character = DS:GetCharacter( Characters:GetInfo(line) ) + + local icon + if DS:GetCharacterFaction(character) == "Alliance" then + icon = addon:TextureToFontstring(ICON_FACTION_ALLIANCE, 18, 18) .. " " + else + icon = addon:TextureToFontstring(ICON_FACTION_HORDE, 18, 18) .. " " + end + + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetWidth(170) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0) + _G[entry..i.."NameNormalText"]:SetWidth(170) + _G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character), DS:GetCharacterClass(character))) + _G[entry..i.."Level"]:SetText(GREEN .. DS:GetCharacterLevel(character)) + + _G[entry..i.."Money"]:SetText(addon:GetMoneyString(DS:GetMoney(character))) + _G[entry..i.."Played"]:SetText(addon:GetTimeString(DS:GetPlayTime(character))) + _G[entry..i.."XP"]:SetText(GREEN .. DS:GetXPRate(character) .. "%") + + if DS:GetCharacterLevel(character) == MAX_PLAYER_LEVEL then + _G[entry..i.."Rested"]:SetText(WHITE .. "0%") + else + _G[entry..i.."Rested"]:SetText( addon:GetRestedXP(character) ) + end + + _G[entry..i.."AvgILevelNormalText"]:SetText(YELLOW..format("%.1f", DS:GetAverageItemLevel(character))) + + elseif (lineType == INFO_TOTAL_LINE) then + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetWidth(200) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + _G[entry..i.."NameNormalText"]:SetWidth(200) + _G[entry..i.."NameNormalText"]:SetText(L["Totals"]) + _G[entry..i.."Level"]:SetText(Characters:GetField(line, "level")) + _G[entry..i.."Money"]:SetText(addon:GetMoneyString(Characters:GetField(line, "money"), WHITE)) + _G[entry..i.."Money"]:SetTextColor(1.0, 1.0, 1.0) + _G[entry..i.."Played"]:SetText(Characters:GetField(line, "played")) + _G[entry..i.."XP"]:SetText("") + _G[entry..i.."Rested"]:SetText("") + _G[entry..i.."AvgILevelNormalText"]:SetText("") + end + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + end + end + end + + while i <= VisibleLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + i = i + 1 + end + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18); +end + +function ns:Level_OnEnter(frame) + local line = frame:GetParent():GetID() + local lineType = Characters:GetLineType(line) + if not lineType then return end + + if lineType == INFO_REALM_LINE then + return + elseif lineType == INFO_TOTAL_LINE then + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(frame, "ANCHOR_TOP"); + AltoTooltip:AddLine(L["Totals"]); + + local aLevels, aMoney, aPlayed = GetFactionTotals("Alliance", line) + local hLevels, hMoney, hPlayed = GetFactionTotals("Horde", line) + + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddDoubleLine(WHITE..L["Levels"] , format("%s|r (%s %s|r, %s %s|r)", + Characters:GetField(line, "level"), + addon:TextureToFontstring(ICON_FACTION_ALLIANCE, 18, 18), WHITE..aLevels, + addon:TextureToFontstring(ICON_FACTION_HORDE, 18, 18), WHITE..hLevels)) + + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddDoubleLine(WHITE..MONEY, format("%s|r (%s %s|r, %s %s|r)", + addon:GetMoneyString(Characters:GetField(line, "money"), WHITE, true), + addon:TextureToFontstring(ICON_FACTION_ALLIANCE, 18, 18), + addon:GetMoneyString(aMoney, WHITE, true), + addon:TextureToFontstring(ICON_FACTION_HORDE, 18, 18), + addon:GetMoneyString(hMoney, WHITE, true))) + + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddDoubleLine(WHITE..PLAYED , format("%s|r (%s %s|r, %s %s|r)", + Characters:GetField(line, "played"), + addon:TextureToFontstring(ICON_FACTION_ALLIANCE, 18, 18), + addon:GetTimeString(aPlayed), + addon:TextureToFontstring(ICON_FACTION_HORDE, 18, 18), + addon:GetTimeString(hPlayed))) + + AltoTooltip:Show(); + return + end + + local DS = DataStore + local character = DS:GetCharacter(Characters:GetInfo(line)) + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + + AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character)) + AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"], + GREEN..DS:GetCharacterLevel(character), DS:GetCharacterRace(character), DS:GetCharacterClass(character)),1,1,1) + + local zone, subZone = DS:GetLocation(character) + AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..zone, GOLD..subZone),1,1,1) + + local guildName = DS:GetGuildInfo(character) + if guildName then + AltoTooltip:AddLine(format("%s: %s", GUILD, GREEN..guildName),1,1,1) + end + + AltoTooltip:AddLine(EXPERIENCE_COLON .. " " + .. GREEN .. DS:GetXP(character) .. WHITE .. "/" + .. GREEN .. DS:GetXPMax(character) .. WHITE .. " (" + .. GREEN .. DS:GetXPRate(character) .. "%" + .. WHITE .. ")",1,1,1); + + local restXP = DS:GetRestXP(character) + if restXP and restXP > 0 then + AltoTooltip:AddLine(format("%s: %s", L["Rest XP"], GREEN..restXP),1,1,1) + end + + local suggestion = addon:GetSuggestion("Leveling", DS:GetCharacterLevel(character)) + if suggestion then + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(L["Suggested leveling zone: "],1,1,1); + AltoTooltip:AddLine(TEAL .. suggestion,1,1,1); + end + + -- parse saved instances + local c = addon:GetCharacterTableByLine(line) + + local bLineBreak = true + for Instance, InstanceInfo in pairs (c.SavedInstance) do + local InstanceName, InstanceID = strsplit("|", Instance) + + local reset, lastcheck = strsplit("|", InstanceInfo) + reset = tonumber(reset) + lastcheck = tonumber(lastcheck) + local expiresIn = reset - (time() - lastcheck) + + if expiresIn > 0 then + if bLineBreak then + AltoTooltip:AddLine(" ",1,1,1); -- add a line break only once + bLineBreak = nil + end + AltoTooltip:AddDoubleLine(GOLD .. InstanceName .. + " (".. WHITE.."ID: " .. GREEN .. InstanceID .. "|r)", addon:GetTimeString(expiresIn)) + else + c.SavedInstance[Instance] = nil + end + end + + -- add PVP info if any + + local hk, dk, arena, honor = DS:GetStats(character, "PVP") + + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddDoubleLine(WHITE.. L["Arena points: "] .. GREEN .. arena, "HK: " .. GREEN .. hk ) + AltoTooltip:AddDoubleLine(WHITE.. L["Honor points: "] .. GREEN .. honor, "DK: " .. GREEN .. dk ) + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(GREEN .. L["Right-Click for options"]); + AltoTooltip:Show(); +end + +function ns:Level_OnClick(frame, button) + local line = frame:GetParent():GetID() + if line == 0 then return end + + local lineType = Characters:GetLineType(line) + if lineType == INFO_TOTAL_LINE then + return + end + + if button == "RightButton" then + ns.CharInfoLine = line -- line containing info about the alt on which action should be taken (delete, ..) + ToggleDropDownMenu(1, nil, AltoholicFrameSummaryRightClickMenu, frame:GetName(), 0, -5); + return + elseif button == "LeftButton" and lineType == INFO_CHARACTER_LINE then + + local tc = addon.Tabs.Characters + local charName, realm, account = Characters:GetInfo(line) + addon:SetCurrentCharacter(charName, realm, account) + addon.Tabs.Characters:SetCurrent(charName, realm, account) + + addon.Tabs:OnClick(2) + addon.Containers:UpdateCache() + tc:ViewCharInfo(VIEW_BAGS) + end +end + +function ns:AIL_OnEnter(frame) + local line = frame:GetParent():GetID() + local lineType = Characters:GetLineType(line) + + if lineType ~= INFO_CHARACTER_LINE then + return + end + + local DS = DataStore + local character = DS:GetCharacter(Characters:GetInfo(line)) + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + AltoTooltip:AddLine(DS:GetColoredCharacterName(character),1,1,1); + AltoTooltip:AddLine(WHITE .. L["Average Item Level"] ..": " .. GREEN.. format("%.1f", DS:GetAverageItemLevel(character)),1,1,1); + + addon:AiLTooltip() + AltoTooltip:Show(); +end + +function addon:AiLTooltip() + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(TEAL .. L["Level"] .. " 60",1,1,1); + AltoTooltip:AddDoubleLine(YELLOW .. "58-63", WHITE .. "Tier 0") + AltoTooltip:AddDoubleLine(YELLOW .. "66", WHITE .. "Tier 1") + AltoTooltip:AddDoubleLine(YELLOW .. "76", WHITE .. "Tier 2") + AltoTooltip:AddDoubleLine(YELLOW .. "86-92", WHITE .. "Tier 3") + AltoTooltip:AddLine(" ",1,1,1); + + AltoTooltip:AddLine(TEAL .. L["Level"] .. " 70",1,1,1); + AltoTooltip:AddDoubleLine(YELLOW .. "115", WHITE .. BZ["Karazhan"]) + AltoTooltip:AddDoubleLine(YELLOW .. "120", WHITE .. "Tier 4") + AltoTooltip:AddDoubleLine(YELLOW .. "128", WHITE .. BZ["Zul'Aman"]) + AltoTooltip:AddDoubleLine(YELLOW .. "133", WHITE .. "Tier 5") + AltoTooltip:AddDoubleLine(YELLOW .. "146-154", WHITE .. "Tier 6") + AltoTooltip:AddLine(" ",1,1,1); + + AltoTooltip:AddLine(TEAL .. L["Level"] .. " 80",1,1,1); + AltoTooltip:AddDoubleLine(YELLOW .. "200", WHITE .. BZ["Naxxramas"] .. " (10)") + AltoTooltip:AddDoubleLine(YELLOW .. "213", WHITE .. BZ["Naxxramas"] .. " (25)") + AltoTooltip:AddDoubleLine(YELLOW .. "200-219", WHITE .. BZ["Trial of the Champion"]) + AltoTooltip:AddDoubleLine(YELLOW .. "219", WHITE .. BZ["Ulduar"] .. " (10)") + AltoTooltip:AddDoubleLine(YELLOW .. "226-239", WHITE .. BZ["Ulduar"] .. " (25)") + AltoTooltip:AddDoubleLine(YELLOW .. "232-258", WHITE .. BZ["Trial of the Crusader"] .. " (10)") + AltoTooltip:AddDoubleLine(YELLOW .. "245-272", WHITE .. BZ["Trial of the Crusader"] .. " (25)") + AltoTooltip:AddDoubleLine(YELLOW .. "251-271", WHITE .. BZ["Icecrown Citadel"] .. " (10)") + AltoTooltip:AddDoubleLine(YELLOW .. "264-284", WHITE .. BZ["Icecrown Citadel"] .. " (25)") +end + +function ns:RightClickMenu_OnLoad() + local characterInfoLine = ns.CharInfoLine + if not characterInfoLine then return end + + local lineType = Characters:GetLineType(characterInfoLine) + if not lineType then return end + + if lineType == INFO_REALM_LINE then + local _, realm, account = Characters:GetInfo(characterInfoLine) + local _, updatedWith = addon:GetLastAccountSharingInfo(realm, account) + + if updatedWith then + DDM_Add(format("Update from %s", GREEN..updatedWith), nil, UpdateRealm, characterInfoLine) + end + DDM_Add(L["Delete this Realm"], nil, DeleteRealm, characterInfoLine) + return + end + + DDM_Add(L["View bags"], VIEW_BAGS, ViewAltInfo, characterInfoLine) + DDM_Add(L["View mailbox"], VIEW_MAILS, ViewAltInfo, characterInfoLine) + DDM_Add(L["View quest log"], VIEW_QUESTS, ViewAltInfo, characterInfoLine) + DDM_Add(L["View auctions"], VIEW_AUCTIONS, ViewAltInfo, characterInfoLine) + DDM_Add(L["View bids"], VIEW_BIDS, ViewAltInfo, characterInfoLine) + DDM_Add(COMPANIONS, VIEW_COMPANIONS, ViewAltInfo, characterInfoLine) + DDM_Add(MOUNTS, VIEW_MOUNTS, ViewAltInfo, characterInfoLine) + DDM_Add(L["Delete this Alt"], nil, DeleteAlt, characterInfoLine) + DDM_AddCloseMenu() +end diff --git a/Altoholic-Addon/Altoholic/Frames/AccountSummary.xml b/Altoholic-Addon/Altoholic/Frames/AccountSummary.xml new file mode 100644 index 0000000..e65f1c0 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/AccountSummary.xml @@ -0,0 +1,311 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Summary.Update) + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_Initialize(self, Altoholic.Summary.RightClickMenu_OnLoad, "MENU"); + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Activity.lua b/Altoholic-Addon/Altoholic/Frames/Activity.lua new file mode 100644 index 0000000..f4c13cf --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Activity.lua @@ -0,0 +1,345 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local INFO_REALM_LINE = 0 +local INFO_CHARACTER_LINE = 1 +local INFO_TOTAL_LINE = 2 + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" +local GREY = "|cFF808080" +local GOLD = "|cFFFFD700" +local RED = "|cFFFF0000" + +local ICON_FACTION_HORDE = "Interface\\Icons\\INV_BannerPVP_01" +local ICON_FACTION_ALLIANCE = "Interface\\Icons\\INV_BannerPVP_02" + +addon.Activity = {} + +local ns = addon.Activity -- ns = namespace +local Characters = addon.Characters + +function ns:Update() + local VisibleLines = 14 + local frame = "AltoholicFrameActivity" + local entry = frame.."Entry" + + local DS = DataStore + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local DisplayedCount = 0 + local VisibleCount = 0 + local DrawRealm + local i=1 + + for _, line in pairs(Characters:GetView()) do + local lineType = Characters:GetLineType(line) + + if (offset > 0) or (DisplayedCount >= VisibleLines) then -- if the line will not be visible + if lineType == INFO_REALM_LINE then -- then keep track of counters + if Characters:GetField(line, "isCollapsed") == false then + DrawRealm = true + else + DrawRealm = false + end + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif DrawRealm then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + end + else -- line will be displayed + if lineType== INFO_REALM_LINE then + local _, realm, account = Characters:GetInfo(line) + + if Characters:GetField(line, "isCollapsed") == false then + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + DrawRealm = true + else + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + DrawRealm = false + end + _G[entry..i.."Collapse"]:Show() + _G[entry..i.."Name"]:SetWidth(300) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 25, 0) + _G[entry..i.."NameNormalText"]:SetWidth(300) + if account == "Default" then -- saved as default, display as localized. + _G[entry..i.."NameNormalText"]:SetText(format("%s (%s".. L["Account"]..": %s%s|r)", realm, WHITE, GREEN, L["Default"])) + else + local last = addon:GetLastAccountSharingInfo(realm, account) + _G[entry..i.."NameNormalText"]:SetText(format("%s (%s".. L["Account"]..": %s%s %s%s|r)", realm, WHITE, GREEN, account, YELLOW, last or "")) + end + _G[entry..i.."Level"]:SetText("") + _G[entry..i.."MailsNormalText"]:SetText("") + _G[entry..i.."LastMailCheckNormalText"]:SetText("") + _G[entry..i.."AuctionsNormalText"]:SetText("") + _G[entry..i.."BidsNormalText"]:SetText("") + _G[entry..i.."LastAHCheckNormalText"]:SetText("") + _G[entry..i.."LastLogoutNormalText"]:SetText("") + + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + elseif DrawRealm then + if (lineType == INFO_CHARACTER_LINE) then + local character = DS:GetCharacter( Characters:GetInfo(line) ) + + local icon + if DS:GetCharacterFaction(character) == "Alliance" then + icon = addon:TextureToFontstring(ICON_FACTION_ALLIANCE, 18, 18) .. " " + else + icon = addon:TextureToFontstring(ICON_FACTION_HORDE, 18, 18) .. " " + end + + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetWidth(170) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0) + _G[entry..i.."NameNormalText"]:SetWidth(170) + _G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character), DS:GetCharacterClass(character))) + _G[entry..i.."Level"]:SetText(GREEN .. DS:GetCharacterLevel(character)) + + local color + local num = DS:GetNumMails(character) or 0 + if num == 0 then + color = GREY + _G[entry..i.."MailsNormalText"]:SetText(GREY .. "0") + else + color = GREEN -- green by default, red if at least one mail is about to expire + + local threshold = DataStore:GetOption("DataStore_Mails", "MailWarningThreshold") + if DS:GetNumExpiredMails(character, threshold) > 0 then + color = RED + end + end + _G[entry..i.."MailsNormalText"]:SetText(color .. num) + + local lastVisit = DS:GetMailboxLastVisit(character) + _G[entry..i.."LastMailCheckNormalText"]:SetText(WHITE .. addon:FormatDelay(lastVisit)) + + num = DS:GetNumAuctions(character) or 0 + _G[entry..i.."AuctionsNormalText"]:SetText(((num == 0) and GREY or GREEN) .. num) + + num = DS:GetNumBids(character) or 0 + _G[entry..i.."BidsNormalText"]:SetText(((num == 0) and GREY or GREEN) .. num) + + lastVisit = DS:GetAuctionHouseLastVisit(character) + _G[entry..i.."LastAHCheckNormalText"]:SetText(WHITE .. addon:FormatDelay(lastVisit)) + + local player, realm, account = Characters:GetInfo(line) + if (player == UnitName("player")) and (realm == GetRealmName()) and (account == "Default") then + _G[entry..i.."LastLogoutNormalText"]:SetText(GREEN .. GUILD_ONLINE_LABEL) + else + _G[entry..i.."LastLogoutNormalText"]:SetText(WHITE .. addon:FormatDelay(DS:GetLastLogout(character))) + end + elseif (lineType == INFO_TOTAL_LINE) then + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetWidth(200) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + _G[entry..i.."NameNormalText"]:SetWidth(200) + _G[entry..i.."NameNormalText"]:SetText(L["Totals"]) + _G[entry..i.."Level"]:SetText(Characters:GetField(line, "level")) + _G[entry..i.."MailsNormalText"]:SetText("") + _G[entry..i.."LastMailCheckNormalText"]:SetText("") + _G[entry..i.."AuctionsNormalText"]:SetText("") + _G[entry..i.."BidsNormalText"]:SetText("") + _G[entry..i.."LastAHCheckNormalText"]:SetText("") + _G[entry..i.."LastLogoutNormalText"]:SetText("") + end + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + end + end + end + + while i <= VisibleLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + i = i + 1 + end + + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18); +end + +function ns:OnEnter(self) + local line = self:GetParent():GetID() + local lineType = Characters:GetLineType(line) + if lineType ~= INFO_CHARACTER_LINE then + return + end + + local DS = DataStore + local character = DS:GetCharacter(Characters:GetInfo(line)) + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(self, "ANCHOR_RIGHT"); + + AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character)) + AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"], + GREEN..DS:GetCharacterLevel(character), DS:GetCharacterRace(character), DS:GetCharacterClass(character)),1,1,1) + + local zone, subZone = DS:GetLocation(character) + AltoTooltip:AddLine(format("%s: %s |r(%s|r)", L["Zone"], GOLD..zone, GOLD..subZone),1,1,1) + + AltoTooltip:AddLine(EXPERIENCE_COLON .. " " + .. GREEN .. DS:GetXP(character) .. WHITE .. "/" + .. GREEN .. DS:GetXPMax(character) .. WHITE .. " (" + .. GREEN .. DS:GetXPRate(character) .. "%" + .. WHITE .. ")",1,1,1); + + local restXP = DS:GetRestXP(character) + if restXP and restXP > 0 then + AltoTooltip:AddLine(format("%s: %s", L["Rest XP"], GREEN..restXP),1,1,1) + end + + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(GOLD..CURRENCY..":",1,1,1); + + local num = DS:GetNumCurrencies(character) or 0 + for i = 1, num do + local isHeader, name, count = DS:GetCurrencyInfo(character, i) + if isHeader then + AltoTooltip:AddLine(YELLOW..name) + else + AltoTooltip:AddLine(format(" %s: %s", name, GREEN..count),1,1,1); + end + end + + if num == 0 then + AltoTooltip:AddLine(WHITE..NONE,1,1,1); + end + + AltoTooltip:Show(); +end + +local VIEW_MAILS = 3 +local VIEW_AUCTIONS = 5 +local VIEW_BIDS = 6 + +function ns:OnClick(self) + local line = self:GetParent():GetID() + local lineType = Characters:GetLineType(line) + + if lineType ~= INFO_CHARACTER_LINE then + return + end + + local id = self:GetID() + if (id == 2) or (id >= 5) then -- exit if it's not the right column + return + end + + addon:SetCurrentCharacter( Characters:GetInfo(line) ) + + local DS = DataStore + local character = DS:GetCharacter(Characters:GetInfo(line)) + + local action, num + + if id == 1 then -- mails + num = DS:GetNumMails(character) or 0 + if num > 0 then -- only set the action if there are data to show + action = VIEW_MAILS + end + elseif id == 3 then -- auctions + num = DS:GetNumAuctions(character) or 0 + if num > 0 then + action = VIEW_AUCTIONS + end + elseif id == 4 then -- bids + num = DS:GetNumBids(character) or 0 + if num > 0 then + action = VIEW_BIDS + end + end + + if action then + addon.Tabs.Characters:SetCurrent( addon:GetCurrentCharacter() ) + addon.Tabs:OnClick(2) + addon.Tabs.Characters:ViewCharInfo(action) + end +end + +function ns:Mails_OnEnter(self) + local line = self:GetParent():GetID() + local lineType = Characters:GetLineType(line) + + if lineType ~= INFO_CHARACTER_LINE then + return + end + + local DS = DataStore + local character = DS:GetCharacter(Characters:GetInfo(line)) + local num = DS:GetNumMails(character) + if not num or num == 0 then return end + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(self, "ANCHOR_RIGHT"); + + AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), format("%sMails found: %s%d", WHITE, GREEN, num)) + + local numReturned, numDeleted, numExpired = 0, 0, 0 + local closestReturn + local closestDelete + + for index = 1, num do + local _, _, _, _, _, isReturned = DS:GetMailInfo(character, index) + local _, seconds = DS:GetMailExpiry(character, index) + + if seconds < 0 then -- mail has already expired + if isReturned then -- .. and it was a returned mail + numExpired = numExpired + 1 + end + else + if isReturned then + numDeleted = numDeleted + 1 + + if not closestDelete then + closestDelete = seconds + else + if seconds < closestDelete then + closestDelete = seconds + end + end + else + numReturned = numReturned + 1 + + if not closestReturn then + closestReturn = seconds + else + if seconds < closestReturn then + closestReturn = seconds + end + end + end + end + end + + AltoTooltip:AddLine(" "); + AltoTooltip:AddLine(format("%s%d %swill be returned upon expiry", GREEN, numReturned, WHITE)) + if closestReturn then + AltoTooltip:AddLine(format("%sClosest return in %s%s", WHITE, GREEN, SecondsToTime(closestReturn))) + end + + if numDeleted > 0 then + AltoTooltip:AddLine(" "); + AltoTooltip:AddLine(format("%s%d %swill be %sdeleted%s upon expiry", GREEN, numDeleted, WHITE, RED, WHITE)) + if closestDelete then + AltoTooltip:AddLine(format("%sClosest deletion in %s%s", WHITE, GREEN, SecondsToTime(closestDelete))) + end + end + + if numExpired > 0 then + AltoTooltip:AddLine(" "); + AltoTooltip:AddLine(format("%s%d %shave expired !", RED, numExpired, WHITE)) + end + + AltoTooltip:Show(); +end diff --git a/Altoholic-Addon/Altoholic/Frames/Activity.xml b/Altoholic-Addon/Altoholic/Frames/Activity.xml new file mode 100644 index 0000000..763049c --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Activity.xml @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Activity.Update) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/AuctionHouse.lua b/Altoholic-Addon/Altoholic/Frames/AuctionHouse.lua new file mode 100644 index 0000000..2991518 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/AuctionHouse.lua @@ -0,0 +1,406 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local ORANGE = "|cFFFF7F00" +local RED = "|cFFFF0000" +local TEAL = "|cFF00FF9A" + +local view +local viewSortField = "name" +local viewSortOrder +local isViewValid +local listType -- "Auctions" or "Bids" + +local function SortByName(a, b) + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + + local _, idA = DS:GetAuctionHouseItemInfo(character, listType, a) + local _, idB = DS:GetAuctionHouseItemInfo(character, listType, b) + + local textA = GetItemInfo(idA) or "" + local textB = GetItemInfo(idB) or "" + + if viewSortOrder then + return textA < textB + else + return textA > textB + end +end + +local function SortByPlayer(a, b) + -- sort by owner (for bids), or highBidder (for auctions), both the 4th return value + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + + local _, _, _, nameA = DS:GetAuctionHouseItemInfo(character, listType, a) + local _, _, _, nameB = DS:GetAuctionHouseItemInfo(character, listType, b) + + nameA = nameA or "" + nameB = nameB or "" + + if viewSortOrder then + return nameA < nameB + else + return nameA > nameB + end +end + +local function SortByPrice(a, b) + -- sort by owner (for bids), or highBidder (for auctions), both the 4th return value + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + + local _, _, _, _, _, priceA = DS:GetAuctionHouseItemInfo(character, listType, a) + local _, _, _, _, _, priceB = DS:GetAuctionHouseItemInfo(character, listType, b) + + if viewSortOrder then + return priceA < priceB + else + return priceA > priceB + end +end + +local PrimaryLevelSort = { -- sort functions for the mains + ["name"] = SortByName, + ["owner"] = SortByPlayer, + ["highBidder"] = SortByPlayer, + ["buyoutPrice"] = SortByPrice, +} + +local function BuildView() + view = view or {} + wipe(view) + + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + if not character then return end + + local num + if listType == "Auctions" then + num = DS:GetNumAuctions(character) or 0 + else + num = DS:GetNumBids(character) or 0 + end + + for i = 1, num do + table.insert(view, i) + end + + table.sort(view, PrimaryLevelSort[viewSortField]) + + isViewValid = true +end + +addon.AuctionHouse = {} + +local ns = addon.AuctionHouse -- ns = namespace + +local updateHandler + +function ns:Update() + if not isViewValid then + BuildView() + end + + ns[updateHandler](ns) +end + +function ns:SetUpdateHandler(h) + updateHandler = h +end + +function ns:SetListType(list) + listType = list + ns:SetUpdateHandler("Update"..list) +end + +function ns:Sort(self, field, AHType) + viewSortField = field + viewSortOrder = self.ascendingSort + + ns:SetListType(AHType) + ns:InvalidateView() +end + +function ns:InvalidateView() + isViewValid = nil + if AltoholicFrameAuctions:IsVisible() then + ns:Update() + end +end + +function ns:UpdateAuctions() + local VisibleLines = 7 + local frame = "AltoholicFrameAuctions" + local entry = frame.."Entry" + + local player = addon:GetCurrentCharacter() + + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local lastVisit = DS:GetAuctionHouseLastVisit(character) + + if lastVisit ~= 0 then + local localDate = format(L["Last visit: %s by %s"], GREEN..date("%m/%d/%Y", lastVisit)..WHITE, GREEN..player) + AltoholicFrameAuctionsInfo1:SetText(localDate .. WHITE .. " @ " .. date("%H:%M", lastVisit)) + AltoholicFrameAuctionsInfo1:Show() + else + -- never visited the AH + AltoholicFrameAuctionsInfo1:Hide() + end + + local numAuctions = DS:GetNumAuctions(character) or 0 + if numAuctions == 0 then + AltoholicTabCharactersStatus:SetText(format(L["%s has no auctions"], player)) + -- make sure the scroll frame is cleared ! + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 41) + return + else + AltoholicTabCharactersStatus:SetText("") + end + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + + for i=1, VisibleLines do + local line = i + offset + if line <= numAuctions then + local index = view[line] + + local isGoblin, itemID, count, highBidder, startPrice, buyoutPrice, timeLeft = DS:GetAuctionHouseItemInfo(character, "Auctions", index) + + local itemName, _, itemRarity = GetItemInfo(itemID) + itemName = itemName or L["N/A"] + itemRarity = itemRarity or 1 + _G[ entry..i.."Name" ]:SetText(select(4, GetItemQualityColor(itemRarity)) .. itemName) + + if not timeLeft then -- secure this in case it is nil (may happen when other auction monitoring addons are present) + timeLeft = 1 + elseif (timeLeft < 1) or (timeLeft > 4) then + timeLeft = 1 + end + + _G[ entry..i.."TimeLeft" ]:SetText( TEAL .. _G["AUCTION_TIME_LEFT"..timeLeft] + .. " (" .. _G["AUCTION_TIME_LEFT"..timeLeft .. "_DETAIL"] .. ")") + + local bidder = (isGoblin) and L["Goblin AH"] .. "\n" or "" + bidder = (highBidder) and WHITE .. highBidder or RED .. NO_BIDS + _G[ entry..i.."HighBidder" ]:SetText(bidder) + + _G[ entry..i.."Price" ]:SetText(addon:GetMoneyString(startPrice) .. "\n" + .. GREEN .. BUYOUT .. ": " .. addon:GetMoneyString(buyoutPrice)) + _G[ entry..i.."ItemIconTexture" ]:SetTexture(GetItemIcon(itemID)); + if count and count > 1 then + _G[ entry..i.."ItemCount" ]:SetText(count) + _G[ entry..i.."ItemCount" ]:Show() + else + _G[ entry..i.."ItemCount" ]:Hide() + end + + _G[ entry..i.."Item" ]:SetID(index) + _G[ entry..i ]:Show() + else + _G[ entry..i ]:Hide() + end + end + + if numAuctions < VisibleLines then + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleLines, VisibleLines, 41); + else + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], numAuctions, VisibleLines, 41); + end +end + +function ns:UpdateBids() + local VisibleLines = 7 + local frame = "AltoholicFrameAuctions" + local entry = frame.."Entry" + + local player = addon:GetCurrentCharacter() + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + + local lastVisit = DS:GetAuctionHouseLastVisit(character) + + if lastVisit ~= 0 then + local localDate = format(L["Last visit: %s by %s"], GREEN..date("%m/%d/%Y", lastVisit)..WHITE, GREEN..player) + AltoholicFrameAuctionsInfo1:SetText(localDate .. WHITE .. " @ " .. date("%H:%M", lastVisit)) + AltoholicFrameAuctionsInfo1:Show() + else + -- never visited the AH + AltoholicFrameAuctionsInfo1:Hide() + end + + local numBids = DS:GetNumBids(character) or 0 + if numBids == 0 then + AltoholicTabCharactersStatus:SetText(format(L["%s has no bids"], player)) + -- make sure the scroll frame is cleared ! + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 41) + return + else + AltoholicTabCharactersStatus:SetText("") + end + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + + for i=1, VisibleLines do + local line = i + offset + if line <= numBids then + local index = view[line] + local isGoblin, itemID, count, ownerName, bidPrice, buyoutPrice, timeLeft = DS:GetAuctionHouseItemInfo(character, "Bids", index) + + local itemName, _, itemRarity = GetItemInfo(itemID) + itemName = itemName or L["N/A"] + itemRarity = itemRarity or 1 + _G[ entry..i.."Name" ]:SetText(select(4, GetItemQualityColor(itemRarity)) .. itemName) + + _G[ entry..i.."TimeLeft" ]:SetText( TEAL .. _G["AUCTION_TIME_LEFT"..timeLeft] + .. " (" .. _G["AUCTION_TIME_LEFT"..timeLeft .. "_DETAIL"] .. ")") + + if isGoblin then + _G[ entry..i.."HighBidder" ]:SetText(L["Goblin AH"] .. "\n" .. WHITE .. ownerName) + else + _G[ entry..i.."HighBidder" ]:SetText(WHITE .. ownerName) + end + + _G[ entry..i.."Price" ]:SetText(ORANGE .. CURRENT_BID .. ": " .. addon:GetMoneyString(bidPrice) .. "\n" + .. GREEN .. BUYOUT .. ": " .. addon:GetMoneyString(buyoutPrice)) + _G[ entry..i.."ItemIconTexture" ]:SetTexture(GetItemIcon(itemID)); + if count and count > 1 then + _G[ entry..i.."ItemCount" ]:SetText(count) + _G[ entry..i.."ItemCount" ]:Show() + else + _G[ entry..i.."ItemCount" ]:Hide() + end + + _G[ entry..i.."Item" ]:SetID(index) + _G[ entry..i ]:Show() + else + _G[ entry..i ]:Hide() + end + end + + if numBids < VisibleLines then + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleLines, VisibleLines, 41); + else + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], numBids, VisibleLines, 41); + end +end + +function ns:OnEnter(frame) + local character = addon.Tabs.Characters:GetCurrent() + local _, id = DataStore:GetAuctionHouseItemInfo(character, listType, frame:GetID()) + if not id then return end + + local _, link = GetItemInfo(id) + if not link then return end + + GameTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + GameTooltip:SetHyperlink(link); + GameTooltip:Show(); +end + +function ns:OnClick(frame, button) + local character = addon.Tabs.Characters:GetCurrent() + local _, id = DataStore:GetAuctionHouseItemInfo(character, listType, frame:GetID()) + if not id then return end + + local _, link = GetItemInfo(id) + if not link then return end + + if ( button == "LeftButton" ) and ( IsControlKeyDown() ) then + DressUpItemLink(link); + elseif ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + chat:Insert(link) + else + AltoholicFrame_SearchEditBox:SetText(GetItemInfo(link)) + end + end +end + +local function ClearPlayerAHEntries(self) + local character = addon.Tabs.Characters:GetCurrent() + + if (self.value == 1) or (self.value == 3) then -- clean this faction's data + DataStore:ClearAuctionEntries(character, listType, 0) + end + + if (self.value == 2) or (self.value == 3) then -- clean goblin AH + DataStore:ClearAuctionEntries(character, listType, 1) + end + + ns:InvalidateView() +end + +function ns:RightClickMenu_OnLoad() + local info = UIDropDownMenu_CreateInfo(); + + info.text = WHITE .. L["Clear your faction's entries"] + info.value = 1 + info.func = ClearPlayerAHEntries + UIDropDownMenu_AddButton(info, 1); + + info.text = WHITE .. L["Clear goblin AH entries"] + info.value = 2 + info.func = ClearPlayerAHEntries + UIDropDownMenu_AddButton(info, 1); + + info.text = WHITE .. L["Clear all entries"] + info.value = 3 + info.func = ClearPlayerAHEntries + UIDropDownMenu_AddButton(info, 1); + + -- Close menu item + info.text = CLOSE + info.func = function() CloseDropDownMenus() end + info.checked = nil + info.icon = nil + info.notCheckable = 1 + UIDropDownMenu_AddButton(info, 1) +end + + +-- *** EVENT HANDLERS *** +local function OnClose() + addon:UnregisterEvent("AUCTION_HOUSE_CLOSED") + ns:InvalidateView() +end + +function ns:OnShow() + addon:RegisterEvent("AUCTION_HOUSE_CLOSED", OnClose) + + -- do not activate now, requires a few changes, and certainly the implementation of DataStore_Crafts + -- if not self.Orig_AuctionFrameBrowse_Update then + -- self.Orig_AuctionFrameBrowse_Update = AuctionFrameBrowse_Update + -- AuctionFrameBrowse_Update = addon.AuctionHouse.BrowseUpdateHook + -- end +end + +-- function addon.AuctionHouse.BrowseUpdateHook() + -- local self = addon.AuctionHouse + -- self.Orig_AuctionFrameBrowse_Update() -- Let default stuff happen first .. + + -- local offset = FauxScrollFrame_GetOffset(BrowseScrollFrame) + -- local link + -- for i = 1, NUM_BROWSE_TO_DISPLAY do -- NUM_BROWSE_TO_DISPLAY = 8; + -- link = GetAuctionItemLink("list", i+offset) + -- if link then -- if there's a valid item link in this slot .. + -- local itemID = addon:GetIDFromLink(link) + -- local _, _, _, _, _, itemType = GetItemInfo(itemID) + -- if itemType == BI["Recipe"] then -- is it a recipe ? + -- local tex = _G["BrowseButton" .. i .. "ItemIconTexture"] +-- tex:SetVertexColor(1, 0, 0) +-- DEFAULT_CHAT_FRAME:AddMessage("found !") + -- end + -- end + -- end +-- end + + diff --git a/Altoholic-Addon/Altoholic/Frames/AuctionHouse.xml b/Altoholic-Addon/Altoholic/Frames/AuctionHouse.xml new file mode 100644 index 0000000..f2cf05b --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/AuctionHouse.xml @@ -0,0 +1,229 @@ + + + + + + + + self:RegisterForClicks("LeftButtonDown", "RightButtonDown"); + + + if button == "RightButton" then + ToggleDropDownMenu(1, nil, AltoholicFrameAuctionsRightClickMenu, self:GetName(), 0, -5); + end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_Initialize(self, Altoholic.AuctionHouse.RightClickMenu_OnLoad, "MENU"); + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/BagUsage.lua b/Altoholic-Addon/Altoholic/Frames/BagUsage.lua new file mode 100644 index 0000000..e2ef491 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/BagUsage.lua @@ -0,0 +1,225 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local INFO_REALM_LINE = 0 +local INFO_CHARACTER_LINE = 1 +local INFO_TOTAL_LINE = 2 + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" +local GOLD = "|cFFFFD700" +local CYAN = "|cFF1CFAFE" + +local ICON_FACTION_HORDE = "Interface\\Icons\\INV_BannerPVP_01" +local ICON_FACTION_ALLIANCE = "Interface\\Icons\\INV_BannerPVP_02" + +addon.BagUsage = {} + +local ns = addon.BagUsage -- ns = namespace +local Characters = addon.Characters + +function ns:Update() + local VisibleLines = 14 + local frame = "AltoholicFrameBagUsage" + local entry = frame.."Entry" + + local DS = DataStore + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local DisplayedCount = 0 + local VisibleCount = 0 + local DrawRealm + local i=1 + + for _, line in pairs(Characters:GetView()) do + local lineType = Characters:GetLineType(line) + + if (offset > 0) or (DisplayedCount >= VisibleLines) then -- if the line will not be visible + if lineType == INFO_REALM_LINE then -- then keep track of counters + if Characters:GetField(line, "isCollapsed") == false then + DrawRealm = true + else + DrawRealm = false + end + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif DrawRealm then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + end + else -- line will be displayed + if lineType == INFO_REALM_LINE then + local _, realm, account = Characters:GetInfo(line) + + if Characters:GetField(line, "isCollapsed") == false then + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + DrawRealm = true + else + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + DrawRealm = false + end + _G[entry..i.."Collapse"]:Show() + _G[entry..i.."Name"]:SetWidth(300) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 25, 0) + _G[entry..i.."NameNormalText"]:SetWidth(300) + if account == "Default" then -- saved as default, display as localized. + _G[entry..i.."NameNormalText"]:SetText(format("%s (%s".. L["Account"]..": %s%s|r)", realm, WHITE, GREEN, L["Default"])) + else + local last = addon:GetLastAccountSharingInfo(realm, account) + _G[entry..i.."NameNormalText"]:SetText(format("%s (%s".. L["Account"]..": %s%s %s%s|r)", realm, WHITE, GREEN, account, YELLOW, last or "")) + end + _G[entry..i.."Level"]:SetText("") + _G[entry..i.."FreeBags"]:SetText("") + _G[entry..i.."FreeBank"]:SetText("") + _G[entry..i.."BagSlotsNormalText"]:SetText("") + _G[entry..i.."BankSlotsNormalText"]:SetText("") + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + elseif DrawRealm then + if (lineType == INFO_CHARACTER_LINE) then + local character = DS:GetCharacter( Characters:GetInfo(line) ) + + local icon + if DS:GetCharacterFaction(character) == "Alliance" then + icon = addon:TextureToFontstring(ICON_FACTION_ALLIANCE, 18, 18) .. " " + else + icon = addon:TextureToFontstring(ICON_FACTION_HORDE, 18, 18) .. " " + end + + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetWidth(170) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0) + _G[entry..i.."NameNormalText"]:SetWidth(170) + _G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character), DS:GetCharacterClass(character))) + _G[entry..i.."Level"]:SetText(GREEN .. DS:GetCharacterLevel(character)) + + _G[entry..i.."FreeBags"]:SetText(GREEN .. DS:GetNumFreeBagSlots(character)) + _G[entry..i.."FreeBank"]:SetText(GREEN .. DS:GetNumFreeBankSlots(character)) + + _G[entry..i.."BagSlotsNormalText"]:SetJustifyH("LEFT") + _G[entry..i.."BankSlotsNormalText"]:SetJustifyH("LEFT") + + -- Normal bags + _G[entry..i.."BagSlotsNormalText"]:SetText(format("%s/%s|r/%s|r/%s|r/%s |r(%s|r)", + DS:GetContainerSize(character, 0), + WHITE .. DS:GetContainerSize(character, 1), + WHITE .. DS:GetContainerSize(character, 2), + WHITE .. DS:GetContainerSize(character, 3), + WHITE .. DS:GetContainerSize(character, 4), + CYAN .. DS:GetNumBagSlots(character))) + + -- Bank bags + if DS:GetNumBankSlots(character) < 28 then + _G[entry..i.."BankSlotsNormalText"]:SetText(L["Bank not visited yet"]) + else + _G[entry..i.."BankSlotsNormalText"]:SetText(format("%s/%s|r/%s|r/%s|r/%s|r/%s|r/%s|r/%s |r(%s|r)", + DS:GetContainerSize(character, 100), + WHITE .. DS:GetContainerSize(character, 5), + WHITE .. DS:GetContainerSize(character, 6), + WHITE .. DS:GetContainerSize(character, 7), + WHITE .. DS:GetContainerSize(character, 8), + WHITE .. DS:GetContainerSize(character, 9), + WHITE .. DS:GetContainerSize(character, 10), + WHITE .. DS:GetContainerSize(character, 11), + CYAN .. DS:GetNumBankSlots(character))) + end + elseif (lineType == INFO_TOTAL_LINE) then + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetWidth(200) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + _G[entry..i.."NameNormalText"]:SetWidth(200) + _G[entry..i.."NameNormalText"]:SetText(L["Totals"]) + _G[entry..i.."Level"]:SetText(Characters:GetField(line, "level")) + _G[entry..i.."FreeBags"]:SetText(WHITE .. Characters:GetField(line, "freeBagSlots")) + _G[entry..i.."FreeBank"]:SetText(WHITE .. Characters:GetField(line, "freeBankSlots")) + _G[entry..i.."BagSlotsNormalText"]:SetText(WHITE .. Characters:GetField(line, "bagSlots") .. " |r" .. L["slots"]) + _G[entry..i.."BagSlotsNormalText"]:SetJustifyH("CENTER") + _G[entry..i.."BankSlotsNormalText"]:SetText(WHITE .. Characters:GetField(line, "bankSlots") .. " |r" .. L["slots"]) + _G[entry..i.."BankSlotsNormalText"]:SetJustifyH("CENTER") + end + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + end + end + end + + while i <= VisibleLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + i = i + 1 + end + + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18); +end + +local function WriteLine(size, free, link, bagtype) + AltoTooltip:AddLine( format("%s |r%s (%s|r %s) %s %s", + GOLD..size, L["slots"], + GREEN..free, L["free"], + link or "", + (bagtype and strlen(bagtype) > 0) and (YELLOW .. "(" .. bagtype .. ")") or "") ,1,1,1); +end + +function ns:OnEnter(self) + local line = self:GetParent():GetID() + local lineType = Characters:GetLineType(line) + if lineType ~= INFO_CHARACTER_LINE then + return + end + + local c = addon:GetCharacterTableByLine(line) + local DS = DataStore + local character = DS:GetCharacter(Characters:GetInfo(line)) + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(self, "ANCHOR_RIGHT"); + AltoTooltip:AddDoubleLine(DS:GetColoredCharacterName(character), DS:GetColoredCharacterFaction(character)) + AltoTooltip:AddLine(format("%s %s |r%s %s", L["Level"], + GREEN..DS:GetCharacterLevel(character), DS:GetCharacterRace(character), DS:GetCharacterClass(character)),1,1,1) + AltoTooltip:AddLine(" ",1,1,1); + + local id = self:GetID() + local numSlots + local numFree = 0 + + local link, size, free, bagtype + + if id == 1 then -- 1 for player bags, 2 for bank bags + _, link, size, free, bagtype = DS:GetContainerInfo(character, 0) + WriteLine(size, free, "[" .. BACKPACK_TOOLTIP .. "]") + + for i = 1, 4 do + _, link, size, free, bagtype = DS:GetContainerInfo(character, i) + WriteLine(size, free, link, bagtype) + end + numSlots = DS:GetNumBagSlots(character) + numFree = DS:GetNumFreeBagSlots(character) + elseif DS:GetNumBankSlots(character) < 28 then + AltoTooltip:AddLine(L["Bank not visited yet"],1,1,1); + AltoTooltip:Show(); + return + else + _, link, size, free, bagtype = DS:GetContainerInfo(character, 100) + WriteLine(size, free, "[" .. L["Bank"] .. "]") + + for i = 5, 11 do + _, link, size, free, bagtype = DS:GetContainerInfo(character, i) + WriteLine(size, free, link, bagtype) + end + numSlots = DS:GetNumBankSlots(character) + numFree = DS:GetNumFreeBankSlots(character) + end + + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(CYAN .. numSlots .. " |r" .. L["slots"] .. " (" .. GREEN .. numFree .. "|r " ..L["free"] .. ") ",1,1,1); + AltoTooltip:Show(); +end diff --git a/Altoholic-Addon/Altoholic/Frames/BagUsage.xml b/Altoholic-Addon/Altoholic/Frames/BagUsage.xml new file mode 100644 index 0000000..9714cb5 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/BagUsage.xml @@ -0,0 +1,309 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.BagUsage.Update) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Calendar.lua b/Altoholic-Addon/Altoholic/Frames/Calendar.lua new file mode 100644 index 0000000..65f796d --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Calendar.lua @@ -0,0 +1,1021 @@ +local L = LibStub("AceLocale-3.0"):GetLocale("Altoholic") + +local WHITE = "|cFFFFFFFF" +local TEAL = "|cFF00FF9A" +local GREEN = "|cFF00FF00" + +-- Weekday constants +local CALENDAR_WEEKDAY_NORMALIZED_TEX_LEFT = 0.0; +local CALENDAR_WEEKDAY_NORMALIZED_TEX_TOP = 180 / 256; +local CALENDAR_WEEKDAY_NORMALIZED_TEX_WIDTH = 90 / 256 - 0.001; -- fudge factor to prevent texture seams +local CALENDAR_WEEKDAY_NORMALIZED_TEX_HEIGHT = 28 / 256 - 0.001; -- fudge factor to prevent texture seams + +local CALENDAR_MAX_DAYS_PER_MONTH = 42; -- 6 weeks +local CALENDAR_DAYBUTTON_NORMALIZED_TEX_WIDTH = 90 / 256 - 0.001; -- fudge factor to prevent texture seams +local CALENDAR_DAYBUTTON_NORMALIZED_TEX_HEIGHT = 90 / 256 - 0.001; -- fudge factor to prevent texture seams +local CALENDAR_DAYBUTTON_HIGHLIGHT_ALPHA = 0.5; +local DAY_BUTTON = "AltoCalendarDayButton" + +local CALENDAR_FIRST_WEEKDAY = 1 +-- 1 = Sunday, recreated locally to avoid the problem caused by the calendar addon not being loaded at startup. +-- On an EU client, CALENDAR_FIRST_WEEKDAY = 1 when the game is loaded, but becomes 2 as soon as the calendar is launched. +-- So default it to 1, and add an option to select Monday as 1st day of the week instead. If need be, use a slider. +-- Although the calendar is LoD, avoid it. + +local CALENDAR_MONTH_NAMES = { CalendarGetMonthNames() }; +local CALENDAR_WEEKDAY_NAMES = { CalendarGetWeekdayNames() }; + +local CALENDAR_FULLDATE_MONTH_NAMES = { + -- month names show up differently for full date displays in some languages + FULLDATE_MONTH_JANUARY, + FULLDATE_MONTH_FEBRUARY, + FULLDATE_MONTH_MARCH, + FULLDATE_MONTH_APRIL, + FULLDATE_MONTH_MAY, + FULLDATE_MONTH_JUNE, + FULLDATE_MONTH_JULY, + FULLDATE_MONTH_AUGUST, + FULLDATE_MONTH_SEPTEMBER, + FULLDATE_MONTH_OCTOBER, + FULLDATE_MONTH_NOVEMBER, + FULLDATE_MONTH_DECEMBER, +}; + +local COOLDOWN_LINE = 1 +local INSTANCE_LINE = 2 +local CALENDAR_LINE = 3 +local CONNECTMMO_LINE = 4 +local TIMER_LINE = 5 +local SHARED_CD_LINE = 6 -- this type is used for shared cooldowns (alchemy, etc..) among others. + +Altoholic.Calendar = {} +Altoholic.Calendar.Days = {} +Altoholic.Calendar.Events = {} + +local TimeTable = {} -- to pass as an argument to time() see http://lua-users.org/wiki/OsLibraryTutorial for details +local ClockDiff +local lastServerMinute + +local function SetClockDiff(elapsed) + -- this function is called every second until the server time changes (track minutes only) + local ServerHour, ServerMinute = GetGameTime() + local continue = true -- keeps the task running + + if not lastServerMinute then -- ServerMinute not set ? this is the first pass, save it + lastServerMinute = ServerMinute + else + if lastServerMinute ~= ServerMinute then -- next minute ? do our stuff and stop + local _, ServerMonth, ServerDay, ServerYear = CalendarGetDate() + TimeTable.year = ServerYear + TimeTable.month = ServerMonth + TimeTable.day = ServerDay + TimeTable.hour = ServerHour + TimeTable.min = ServerMinute + TimeTable.sec = 0 -- minute just changed, so second is 0 + + -- our goal is achieved, we can calculate the difference between server time and local time, in seconds. + -- a positive value means that the server time is ahead of local time. + -- ex: server: 21:05, local 21.02 could lead to something like 180 (or close to it, depending on seconds) + ClockDiff = difftime(time(TimeTable), time()) + Altoholic.Calendar.Events:BuildList() -- rebuild the event list to take the known difference into account + + -- now that the difference is known, we can check events for warnings, first check should occur right now (hence 0) + Altoholic.Tasks:Add("EventWarning", 0, Altoholic.Calendar.CheckEvents, Altoholic.Calendar) + + lastServerMinute = nil + continue = nil + end + end + + if continue then + Altoholic.Tasks:Reschedule("SetClockDiff", 1) -- 1 second later + return true + end +end + +local function GetClockDiff() + return ClockDiff or 0 +end + +function Altoholic.Calendar:Init() + -- by default, the week starts on Sunday, adjust CALENDAR_FIRST_WEEKDAY if necessary + if Altoholic.Options:Get("WeekStartsMonday") == 1 then + CALENDAR_FIRST_WEEKDAY = 2 + end + + local _, thisMonth, _, thisYear = CalendarGetDate(); + CalendarSetAbsMonth(thisMonth, thisYear); + + -- only register after setting the current month + Altoholic:RegisterEvent("CALENDAR_UPDATE_EVENT_LIST", Altoholic.Calendar.OnUpdate) + + local band = bit.band; + + -- initialize weekdays + for i = 1, 7 do + local bg = _G["AltoholicFrameCalendarWeekday"..i.."Background"] + local left = (band(i, 1) * CALENDAR_WEEKDAY_NORMALIZED_TEX_WIDTH) + CALENDAR_WEEKDAY_NORMALIZED_TEX_LEFT; -- mod(index, 2) * width + local right = left + CALENDAR_WEEKDAY_NORMALIZED_TEX_WIDTH; + local top = CALENDAR_WEEKDAY_NORMALIZED_TEX_TOP; + local bottom = top + CALENDAR_WEEKDAY_NORMALIZED_TEX_HEIGHT; + bg:SetTexCoord(left, right, top, bottom); + end + + -- initialize day buttons + for i = 1, CALENDAR_MAX_DAYS_PER_MONTH do + CreateFrame("Button", DAY_BUTTON..i, AltoholicFrameCalendar, "AltoCalendarDayButtonTemplate"); + self.Days:Init(i) + end + + self.Events:BuildList() + self.Events:InitialExpiryCheck() + + -- determine the difference between local time and server time + Altoholic.Tasks:Add("SetClockDiff", 0, SetClockDiff, Altoholic.Calendar) +end + +local function GetWeekdayIndex(index) + -- GetWeekdayIndex takes an index in the range [1, n] and maps it to a weekday starting + -- at CALENDAR_FIRST_WEEKDAY. For example, + -- CALENDAR_FIRST_WEEKDAY = 1 => [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY] + -- CALENDAR_FIRST_WEEKDAY = 2 => [MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY] + -- CALENDAR_FIRST_WEEKDAY = 6 => [FRIDAY, SATURDAY, SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY] + + -- the expanded form for the left input to mod() is: + -- (index - 1) + (CALENDAR_FIRST_WEEKDAY - 1) + -- why the - 1 and then + 1 before return? because lua has 1-based indexes! awesome! + return mod(index - 2 + CALENDAR_FIRST_WEEKDAY, 7) + 1; +end + +local function GetFullDate(weekday, month, day, year) + local weekdayName = CALENDAR_WEEKDAY_NAMES[weekday]; + local monthName = CALENDAR_FULLDATE_MONTH_NAMES[month]; + return weekdayName, monthName, day, year, month; +end + +local function GetDay(fullday) + -- full day = a date as YYYY-MM-DD + -- this function is actually different than the one in Blizzard_Calendar.lua, since weekday can't necessarily be determined from a UI button + local refDate = {} -- let's use the 1st of current month as reference date + local refMonthFirstDay + refDate.month, refDate.year, _, refMonthFirstDay = CalendarGetMonth() + refDate.day = 1 + + local t = {} + local year, month, day = strsplit("-", fullday) + t.year = tonumber(year) + t.month = tonumber(month) + t.day = tonumber(day) + + local numDays = floor(difftime(time(t), time(refDate)) / 86400) + local weekday = mod(refMonthFirstDay + numDays, 7) + + -- at this point, weekday might be negative or 0, simply add 7 to keep it in the proper range + weekday = (weekday <= 0) and (weekday+7) or weekday + + return t.year, t.month, t.day, weekday +end + +local function GetEventExpiry(event) + -- returns the number of seconds in which a calendar event expires + assert(type(event) == "table") + + local year, month, day = strsplit("-", event.eventDate) + local hour, minute = strsplit(":", event.eventTime) + + TimeTable.year = tonumber(year) + TimeTable.month = tonumber(month) + TimeTable.day = tonumber(day) + TimeTable.hour = tonumber(hour) + TimeTable.min = tonumber(minute) + + return difftime(time(TimeTable), time() + GetClockDiff()) -- in seconds +end + +local TimerThresholds = { 30, 15, 10, 5, 4, 3, 2, 1 } + +local CalendarEventTypes = { + [COOLDOWN_LINE] = { + GetReadyNowWarning = function(self, event) + local name = DataStore:GetCraftCooldownInfo(event.source, event.parentID) + return format(L["%s is now ready (%s on %s)"], name, event.char, event.realm) + end, + GetReadySoonWarning = function(self, event, minutes) + local name = DataStore:GetCraftCooldownInfo(event.source, event.parentID) + return format(L["%s will be ready in %d minutes (%s on %s)"], name, minutes, event.char, event.realm) + end, + GetInfo = function(self, event) + local title, expiresIn = DataStore:GetCraftCooldownInfo(event.source, event.parentID) + return title, format("%s %s", COOLDOWN_REMAINING, Altoholic:GetTimeString(expiresIn)) + end, + }, + [INSTANCE_LINE] = { + GetReadyNowWarning = function(self, event) + local instance = strsplit("|", event.parentID) + return format(L["%s is now unlocked (%s on %s)"], instance, event.char, event.realm) + end, + GetReadySoonWarning = function(self, event, minutes) + local instance = strsplit("|", event.parentID) + return format(L["%s will be unlocked in %d minutes (%s on %s)"], instance, minutes, event.char, event.realm) + end, + GetInfo = function(self, event) + -- title gets the instance name, desc gets the raid id + local instanceName, raidID = strsplit("|", event.parentID) + + -- CALENDAR_EVENTNAME_FORMAT_RAID_LOCKOUT = "%s Unlocks"; -- %s = Raid Name + return instanceName, format("%s%s\nID: %s%s", WHITE, format(CALENDAR_EVENTNAME_FORMAT_RAID_LOCKOUT, instanceName), GREEN, raidID) + end, + }, + [CALENDAR_LINE] = { + GetReadyNowWarning = function(self, event) + local c = Altoholic:GetCharacterTable(event.char, event.realm) + local _, _, title = strsplit("|", c.Calendar[event.parentID]) + return format(CALENDAR_EVENTNAME_FORMAT_START .. " (%s/%s)", title, event.char, event.realm) + end, + GetReadySoonWarning = function(self, event, minutes) + local c = Altoholic:GetCharacterTable(event.char, event.realm) + local _, _, title = strsplit("|", c.Calendar[event.parentID]) + return format(L["%s starts in %d minutes (%s on %s)"], title, minutes, event.char, event.realm) + end, + GetInfo = function(self, event) + local c = Altoholic:GetCharacterTable(event.char, event.realm) + local _, _, title, eventType, inviteStatus = strsplit("|", c.Calendar[event.parentID]) + + inviteStatus = tonumber(inviteStatus) + + local desc + if type(inviteStatus) == "number" and (inviteStatus > 1) and (inviteStatus < 8) then + local StatusText = { + CALENDAR_STATUS_INVITED, -- CALENDAR_INVITESTATUS_INVITED = 1 + CALENDAR_STATUS_ACCEPTED, -- CALENDAR_INVITESTATUS_ACCEPTED = 2 + CALENDAR_STATUS_DECLINED, -- CALENDAR_INVITESTATUS_DECLINED = 3 + CALENDAR_STATUS_CONFIRMED, -- CALENDAR_INVITESTATUS_CONFIRMED = 4 + CALENDAR_STATUS_OUT, -- CALENDAR_INVITESTATUS_OUT = 5 + CALENDAR_STATUS_STANDBY, -- CALENDAR_INVITESTATUS_STANDBY = 6 + CALENDAR_STATUS_SIGNEDUP, -- CALENDAR_INVITESTATUS_SIGNEDUP = 7 + CALENDAR_STATUS_NOT_SIGNEDUP -- CALENDAR_INVITESTATUS_NOT_SIGNEDUP = 8 + } + + desc = format("%s: %s", STATUS, WHITE..StatusText[inviteStatus]) + else + desc = format("%s", STATUS) + end + + return title, desc + end, + }, + [CONNECTMMO_LINE] = { + GetReadyNowWarning = function(self, event) + local c = Altoholic:GetCharacterTable(event.char, event.realm) + local _, _, title = strsplit("|", c.ConnectMMO[event.parentID]) + return format(CALENDAR_EVENTNAME_FORMAT_START .. " (%s/%s)", title, event.char, event.realm) + end, + GetReadySoonWarning = function(self, event, minutes) + local c = Altoholic:GetCharacterTable(event.char, event.realm) + local _, _, title = strsplit("|", c.ConnectMMO[event.parentID]) + return format(L["%s starts in %d minutes (%s on %s)"], title, minutes, event.char, event.realm) + end, + GetInfo = function(self, event) + local c = Altoholic:GetCharacterTable(event.char, event.realm) + local _, _, title, eventType, eventDesc, attendees = strsplit("|", c.ConnectMMO[event.parentID]) + + local numPlayers, minLvl, maxLvl, privateToFriends, privateToGuild = strsplit(",", eventDesc) + local eventTable = {} + + table.insert(eventTable, WHITE .. format(L["Number of players: %s"], GREEN .. numPlayers)) + table.insert(eventTable, WHITE .. format(L["Minimum Level: %s"], GREEN .. minLvl)) + table.insert(eventTable, WHITE .. format(L["Maximum Level: %s"], GREEN .. maxLvl)) + table.insert(eventTable, WHITE .. format(L["Private to friends: %s"], GREEN .. (tonumber(privateToFriends) == 1 and YES or NO))) + table.insert(eventTable, WHITE .. format(L["Private to guild: %s"], GREEN .. (tonumber(privateToGuild) == 1 and YES or NO))) + + local attendeesTable = { strsplit(",", attendees) } + + if #attendeesTable > 0 then + table.insert(eventTable, "") + table.insert(eventTable, WHITE..L["Attendees: "].."|r") + for _, name in pairs(attendeesTable) do + table.insert(eventTable, " " .. name ) + end + table.insert(eventTable, "") + table.insert(eventTable, GREEN .. L["Left-click to invite attendees"]) + end + + return title, table.concat(eventTable, "\n") + end, + }, + [TIMER_LINE] = { + GetReadyNowWarning = function(self, event) + local c = Altoholic:GetCharacterTable(event.char, event.realm) + local item = strsplit("|", c.Timers[event.parentID]) + return format(L["%s is now ready (%s on %s)"], item, event.char, event.realm) + end, + GetReadySoonWarning = function(self, event, minutes) + local c = Altoholic:GetCharacterTable(event.char, event.realm) + local item = strsplit("|", c.Timers[event.parentID]) + return format(L["%s will be ready in %d minutes (%s on %s)"], item, minutes, event.char, event.realm) + end, + GetInfo = function(self, event) + local c = Altoholic:GetCharacterTable(event.char, event.realm) + local title = strsplit("|", c.Timers[event.parentID]) + local expiresIn = GetEventExpiry(event) + return title, format("%s %s", COOLDOWN_REMAINING, Altoholic:GetTimeString(expiresIn)) + end, + }, + [SHARED_CD_LINE] = { + GetReadyNowWarning = function(self, event) + return format(L["%s is now ready (%s on %s)"], event.source, event.char, event.realm) + end, + GetReadySoonWarning = function(self, event, minutes) + return format(L["%s will be ready in %d minutes (%s on %s)"], event.source, minutes, event.char, event.realm) + end, + GetInfo = function(self, event) + local expiresIn = GetEventExpiry(event) + return event.source, format("%s %s", COOLDOWN_REMAINING, Altoholic:GetTimeString(expiresIn)) + end, + }, +} + +local function ShowExpiryWarning(index, minutes) + local event = Altoholic.Calendar.Events:Get(index) + local CalendarEvent = CalendarEventTypes[event.eventType] + + local warning + if minutes == 0 then + warning = CalendarEvent:GetReadyNowWarning(event) + else + warning = CalendarEvent:GetReadySoonWarning(event, minutes) + end + if not warning then return end + + -- print instead of dialog box if player is in combat + if Altoholic.Options:Get("WarningDialogBox") == 1 and not UnitAffectingCombat("player") then + AltoMsgBox.ButtonHandler = Altoholic.Calendar.WarningButtonHandler + AltoMsgBox_Text:SetText(format("%s\n%s", WHITE..warning, L["Do you want to open Altoholic's calendar for details ?"])) + AltoMsgBox:Show() + else + Altoholic:Print(warning) + end +end + +local function ClearExpiredEvents() + local DS = DataStore + + for realm in pairs(DS:GetRealms()) do + for characterName, character in pairs(DS:GetCharacters(realm)) do + + -- Profession Cooldowns + local professions = DS:GetProfessions(character) + if professions then + for professionName, profession in pairs(professions) do + DS:ClearExpiredCooldowns(profession) + end + end + + local c = Altoholic:GetCharacterTable(characterName, realm) + + -- Saved Instances + for k, v in pairs(c.SavedInstance) do + local reset, lastCheck = strsplit("|", v) + reset = tonumber(reset) + lastCheck = tonumber(lastCheck) + + if reset - (time() - lastCheck) <= 0 then -- has expired + c.SavedInstance[k] = nil + end + end + + -- Other timers (like mysterious egg, etc..) + for k, v in pairs(c.Timers) do + local _, lastCheck, duration = strsplit("|", v) + lastCheck = tonumber(lastCheck) + duration = tonumber(duration) + local expires = duration + lastCheck + GetClockDiff() + if (expires - time()) <= 0 then + c.Timers[k] = nil + end + end + end + end +end + +local function IsNumberInString(number, str) + -- ex: with str = "15|10|3" returns true if value is in this string + for v in str:gmatch("(%d+)") do + if tonumber(v) == number then + return true + end + end +end + +local WARNING_TYPE_PROFESSION_CD = 1 +local WARNING_TYPE_DUNGEON_RESET = 2 +local WARNING_TYPE_CALENDAR_EVENT = 3 +local WARNING_TYPE_ITEM_TIMER = 4 + +local EventToWarningType = { + [COOLDOWN_LINE] = WARNING_TYPE_PROFESSION_CD, + [INSTANCE_LINE] = WARNING_TYPE_DUNGEON_RESET, + [CALENDAR_LINE] = WARNING_TYPE_CALENDAR_EVENT, + [CONNECTMMO_LINE] = WARNING_TYPE_CALENDAR_EVENT, + [TIMER_LINE] = WARNING_TYPE_ITEM_TIMER, + [SHARED_CD_LINE] = WARNING_TYPE_PROFESSION_CD, +} + +function Altoholic.Calendar:CheckEvents(elapsed) + if Altoholic.Options:Get("DisableWarnings") == 1 then -- warnings disabled ? do nothing + Altoholic.Tasks:Reschedule("EventWarning", 60) + return true + end + + -- called every 60 seconds + local hasEventExpired + + for k, v in pairs(Altoholic.Calendar.Events.List) do + local numMin = floor(GetEventExpiry(v) / 60) + + if numMin < 0 then + hasEventExpired = true -- at least one event has expired + elseif numMin == 0 then + ShowExpiryWarning(k, 0) + hasEventExpired = true -- at least one event has expired + elseif numMin <= 30 then + local warnings = Altoholic.Options:Get("WarningType"..EventToWarningType[v.eventType]) -- Gets something like "15|5|1" + for _, threshold in pairs(TimerThresholds) do + if threshold == numMin then -- if snooze is allowed for this value + if IsNumberInString(threshold, warnings) then + ShowExpiryWarning(k, numMin) + end + break + elseif threshold < numMin then -- save some cpu cycles, exit if threshold too low + break + end + end + end + end + + if hasEventExpired then -- if at least one event has expired, rebuild the list & refresh + ClearExpiredEvents() + Altoholic.Calendar.Events:BuildList() + Altoholic.Tabs.Summary:Refresh() + end + + -- the task was executed right after the minute changed server side, so reschedule exactly 60 seconds later + Altoholic.Tasks:Reschedule("EventWarning", 60) + return true +end + +function Altoholic.Calendar:WarningButtonHandler(button) + AltoMsgBox.ButtonHandler = nil -- prevent any other call to msgbox from coming back here + if not button then return end + + Altoholic:ToggleUI() + Altoholic.Tabs.Summary:MenuItem_OnClick(8) +end + +function Altoholic.Calendar:SetFirstDayOfWeek(day) + CALENDAR_FIRST_WEEKDAY = day +end + +function Altoholic.Calendar:Update() + -- taken from CalendarFrame_Update() in Blizzard_Calendar.lua, adjusted for my needs. + + local self = Altoholic.Calendar + self.Events:BuildList() -- force a rebuild when updating the view. In some rare cases, the list was not correctly updated. Temporary workaround 26/04/2010 + + + local presentWeekday, presentMonth, presentDay, presentYear = CalendarGetDate(); + local prevMonth, prevYear, prevNumDays = CalendarGetMonth(-1); + local nextMonth, nextYear, nextNumDays = CalendarGetMonth(1); + local month, year, numDays, firstWeekday = CalendarGetMonth(); + + -- set title + AltoholicFrameCalendar_MonthYear:SetText(CALENDAR_MONTH_NAMES[month] .. " ".. year) + + -- initialize weekdays + for i = 1, 7 do + _G["AltoholicFrameCalendarWeekday"..i.."Name"]:SetText(string.sub(CALENDAR_WEEKDAY_NAMES[GetWeekdayIndex(i)], 1, 3)); + end + + local buttonIndex = 1; + local isDarkened = true + local day; + + -- set the previous month's days before the first day of the week + local viewablePrevMonthDays = mod((firstWeekday - CALENDAR_FIRST_WEEKDAY - 1) + 7, 7); + day = prevNumDays - viewablePrevMonthDays; + + while ( GetWeekdayIndex(buttonIndex) ~= firstWeekday ) do + self.Days:Update(buttonIndex, day, prevMonth, prevYear, isDarkened) + day = day + 1; + buttonIndex = buttonIndex + 1; + end + + -- set the days of this month + day = 1; + isDarkened = false + while ( day <= numDays ) do + self.Days:Update(buttonIndex, day, month, year, isDarkened) + day = day + 1; + buttonIndex = buttonIndex + 1; + end + + -- set the first days of the next month + day = 1; + isDarkened = true + while ( buttonIndex <= CALENDAR_MAX_DAYS_PER_MONTH ) do + self.Days:Update(buttonIndex, day, nextMonth, nextYear, isDarkened) + + day = day + 1; + buttonIndex = buttonIndex + 1; + end + + self.Events:Update() +end + +function Altoholic.Calendar.Days:Init(index) + local button = _G[DAY_BUTTON..index] + button:SetID(index) + + -- set anchors + button:ClearAllPoints(); + if ( index == 1 ) then + button:SetPoint("TOPLEFT", AltoholicFrameCalendar, "TOPLEFT", 285, -1); + elseif ( mod(index, 7) == 1 ) then + button:SetPoint("TOPLEFT", _G[DAY_BUTTON..(index - 7)], "BOTTOMLEFT", 0, 0); + else + button:SetPoint("TOPLEFT", _G[DAY_BUTTON..(index - 1)], "TOPRIGHT", 0, 0); + end + + -- set the normal texture to be the background + local tex = button:GetNormalTexture(); + tex:SetDrawLayer("BACKGROUND"); + local texLeft = random(0,1) * CALENDAR_DAYBUTTON_NORMALIZED_TEX_WIDTH; + local texRight = texLeft + CALENDAR_DAYBUTTON_NORMALIZED_TEX_WIDTH; + local texTop = random(0,1) * CALENDAR_DAYBUTTON_NORMALIZED_TEX_HEIGHT; + local texBottom = texTop + CALENDAR_DAYBUTTON_NORMALIZED_TEX_HEIGHT; + tex:SetTexCoord(texLeft, texRight, texTop, texBottom); + + -- adjust the highlight texture layer + tex = button:GetHighlightTexture(); + tex:SetAlpha(CALENDAR_DAYBUTTON_HIGHLIGHT_ALPHA); +end + +function Altoholic.Calendar.Days:Update(index, day, month, year, isDarkened) + local button = _G[DAY_BUTTON..index] + local buttonName = button:GetName(); + + button.day = day + button.month = month + button.year = year + + -- set date + local dateLabel = _G[buttonName.."Date"]; + local tex = button:GetNormalTexture(); + + dateLabel:SetText(day); + if isDarkened then + tex:SetVertexColor(0.4, 0.4, 0.4) + else + tex:SetVertexColor(1.0, 1.0, 1.0) + end + + -- set count + local countLabel = _G[buttonName.."Count"]; + local count = Altoholic.Calendar.Events:GetNum(year, month, day) + + if count == 0 then + countLabel:Hide() + else + countLabel:SetText(count) + countLabel:Show() + end +end + +function Altoholic.Calendar.Days:OnClick(self, button) + local Events = Altoholic.Calendar.Events + local count = Events:GetNum(self.year, self.month, self.day) + if count == 0 then -- no events on that day ? exit + return + end + + local index = Events:GetIndex(self.year, self.month, self.day) + if index then + Events:SetOffset(index - 1) -- if the date is the 4th line, offset is 3 + Events:Update() + end +end + +function Altoholic.Calendar.Days:OnEnter(self) + + local Events = Altoholic.Calendar.Events + local count = Events:GetNum(self.year, self.month, self.day) + if count == 0 then -- no events on that day ? exit + return + end + + AltoTooltip:SetOwner(self, "ANCHOR_LEFT"); + AltoTooltip:ClearLines(); + local eventDate = format("%04d-%02d-%02d", self.year, self.month, self.day) + local weekday = GetWeekdayIndex(mod(self:GetID(), 7)) + weekday = (weekday == 0) and 7 or weekday + + AltoTooltip:AddLine(TEAL..format(FULLDATE, GetFullDate(weekday, self.month, self.day, self.year))); + + for k, v in pairs(Events.List) do + if v.eventDate == eventDate then + local char, eventTime, title = Events:GetInfo(k) + AltoTooltip:AddDoubleLine(format("%s %s", WHITE..eventTime, char), title); + end + end + AltoTooltip:Show(); +end + +local EVENT_DATE = 1 +local EVENT_INFO = 2 + +function Altoholic.Calendar.Events:InitialExpiryCheck() + for index, event in pairs(self.List) do -- browse all events + local expiresIn = GetEventExpiry(event) + if expiresIn < 0 then -- if the event has expired + event.markForDeletion = true -- .. mark it for deletion (no table.remove in this pass, to avoid messing up indexes) + ShowExpiryWarning(index, 0) -- .. and do the appropriate warning + end + end + + for i = #self.List, 1, -1 do -- browse the event table backwards + if self.List[i].markForDeletion then -- erase marked events + table.remove(self.List, i) + end + end + + ClearExpiredEvents() -- quick fix, it seems that for some reason, egg timers did not get cleared as they should without this call + self.InitialExpiryCheck = nil -- kill self, function won't be called again +end + +function Altoholic.Calendar.Events:BuildView() + self.view = self.view or {} + wipe(self.view) + + -- the following list of events : 10/05, 10/05, 12/05, 14/05, 14/05 + -- turns into this view : + -- "10/05" + -- event 1 + -- event 2 + -- "12/05" + -- event 1 + -- "14/05" + -- event 1 + -- event 2 + + + local eventDate = "" + for k, v in pairs(self.List) do + if eventDate ~= v.eventDate then + table.insert(self.view, { linetype = EVENT_DATE, eventDate = v.eventDate }) + eventDate = v.eventDate + end + table.insert(self.view, { linetype = EVENT_INFO, parentID = k }) + end +end + +function Altoholic.Calendar.Events:BuildList() + self.List = self.List or {} + wipe(self.List) + + local ClockDiff = GetClockDiff() + local DS = DataStore + + for realm in pairs(DS:GetRealms()) do + for characterName, character in pairs(DS:GetCharacters(realm)) do + -- add all timers, even expired ones. Expiries will be handled elsewhere. + + -- Profession Cooldowns + local professions = DS:GetProfessions(character) + if professions then + for professionName, profession in pairs(professions) do + local supportsSharedCD + if professionName == GetSpellInfo(2259) or -- alchemy + professionName == GetSpellInfo(3908) or -- tailoring + professionName == GetSpellInfo(2575) then -- mining + supportsSharedCD = true -- current profession supports shared cooldowns + end + + if supportsSharedCD then + local sharedCDFound -- is there a shared cd for this profession ? + for i = 1, DS:GetNumActiveCooldowns(profession) do + local name, _, reset, lastCheck = DS:GetCraftCooldownInfo(profession, i) + local expires = reset + lastCheck + ClockDiff + + if not sharedCDFound then + sharedCDFound = true + self:Add(SHARED_CD_LINE, date("%Y-%m-%d",expires), date("%H:%M",expires), characterName, realm, nil, professionName) + end + end + else + for i = 1, DS:GetNumActiveCooldowns(profession) do + local name, _, reset, lastCheck = DS:GetCraftCooldownInfo(profession, i) + local expires = reset + lastCheck + ClockDiff + + self:Add(COOLDOWN_LINE, date("%Y-%m-%d",expires), date("%H:%M",expires), characterName, realm, i, profession) + end + end + end + end + + local c = Altoholic:GetCharacterTable(characterName, realm) + + -- Saved Instances + for k, v in pairs(c.SavedInstance) do + local reset, lastCheck = strsplit("|", v) + reset = tonumber(reset) + lastCheck = tonumber(lastCheck) + + local expires = reset + lastCheck + ClockDiff + self:Add(INSTANCE_LINE, date("%Y-%m-%d",expires), date("%H:%M",expires), characterName, realm, k) + end + + -- Calendar Events + for k, v in pairs(c.Calendar) do + local eventDate, eventTime = strsplit("|", v) + -- TODO: do not add declined invitations + self:Add(CALENDAR_LINE, eventDate, eventTime, characterName, realm, k) + end + + -- ConnectMMO events + for k, v in pairs(c.ConnectMMO) do + local eventDate, eventTime = strsplit("|", v) + self:Add(CONNECTMMO_LINE, eventDate, eventTime, characterName, realm, k) + end + + -- Other timers (like mysterious egg, etc..) + for k, v in pairs(c.Timers) do + local item, lastCheck, duration = strsplit("|", v) + lastCheck = tonumber(lastCheck) + duration = tonumber(duration) + + local expires = duration + lastCheck + ClockDiff + self:Add(TIMER_LINE, date("%Y-%m-%d",expires), date("%H:%M",expires), characterName, realm, k) + end + end + end + + -- sort by time + self:Sort() + self:BuildView() +end + +local NUM_EVENTLINES = 14 + +function Altoholic.Calendar.Events:Update() + local self = Altoholic.Calendar.Events + + local VisibleLines = NUM_EVENTLINES + local frame = "AltoholicFrameCalendar" + local entry = frame.."Entry" + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + + for i=1, VisibleLines do + local line = i + offset + if line <= #self.view then + local s = self.view[line] + + if s.linetype == EVENT_DATE then + local year, month, day, weekday = GetDay(s.eventDate) + _G[ entry..i.."Date" ]:SetText(format(FULLDATE, GetFullDate(weekday, month, day, year))) + _G[ entry..i.."Date" ]:Show() + + _G[ entry..i.."Hour" ]:Hide() + _G[ entry..i.."Character" ]:Hide() + _G[ entry..i.."Title" ]:Hide() + _G[ entry..i.."_Background"]:Show() + + elseif s.linetype == EVENT_INFO then + local char, eventTime, title = self:GetInfo(s.parentID) + + _G[ entry..i.."Hour" ]:SetText(eventTime) + _G[ entry..i.."Character" ]:SetText(char) + _G[ entry..i.."Title" ]:SetText(title) + + _G[ entry..i.."Hour" ]:Show() + _G[ entry..i.."Character" ]:Show() + _G[ entry..i.."Title" ]:Show() + + _G[ entry..i.."Date" ]:Hide() + _G[ entry..i.."_Background"]:Hide() + end + + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + else + _G[ entry..i ]:Hide() + end + end + + local last = (#self.view < VisibleLines) and VisibleLines or #self.view + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], last, VisibleLines, 18); +end + +function Altoholic.Calendar.Events:Get(index) + return self.List[index] +end + +function Altoholic.Calendar.Events:GetInfo(index) + local event = self.List[index] -- dereference event + if not event then return end + + local DS = DataStore + local character = DS:GetCharacter(event.char, event.realm) + local char = DS:GetColoredCharacterName(character) + + if event.realm ~= GetRealmName() then -- different realm ? + char = format("%s %s(%s)", char, GREEN, event.realm) + end + + local CalendarEvent = CalendarEventTypes[event.eventType] + local title, desc = CalendarEvent:GetInfo(event) + + return char, event.eventTime, title, desc +end + +function Altoholic.Calendar.Events:Sort() + table.sort(self.List, function(a, b) + if (a.eventDate ~= b.eventDate) then -- sort by date first .. + return a.eventDate < b.eventDate + elseif (a.eventTime ~= b.eventTime) then -- .. then by hour + return a.eventTime < b.eventTime + elseif (a.char ~= b.char) then -- .. then by alt + return a.char < b.char + end + end) +end + +function Altoholic.Calendar.Events:Add(eventType, eventDate, eventTime, char, realm, index, externalTable) + table.insert(self.List, { + eventType = eventType, + eventDate = eventDate, + eventTime = eventTime, + char = char, + realm = realm, + parentID = index, + source = externalTable}) +end + +function Altoholic.Calendar.Events:GetNum(year, month, day) + local eventDate = format("%04d-%02d-%02d", year, month, day) + local count = 0 + for k, v in pairs(self.List) do + if v.eventDate == eventDate then + count = count + 1 + end + end + return count +end + +function Altoholic.Calendar.Events:OnEnter(frame) + local self = Altoholic.Calendar.Events + local s = self.view[frame:GetID()] + if not s or s.linetype == EVENT_DATE then return end + + + AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + AltoTooltip:ClearLines(); + -- local eventDate = format("%04d-%02d-%02d", self.year, self.month, self.day) + -- local weekday = GetWeekdayIndex(mod(self:GetID(), 7)) + -- AltoTooltip:AddLine(TEAL..format(FULLDATE, GetFullDate(weekday, self.month, self.day, self.year))); + + local char, eventTime, title, desc = self:GetInfo(s.parentID) + AltoTooltip:AddDoubleLine(format("%s %s", WHITE..eventTime, char), title); + if desc then + AltoTooltip:AddLine(" ") + AltoTooltip:AddLine(desc) + end + AltoTooltip:Show(); +end + +function Altoholic.Calendar.Events:OnClick(frame, button) + -- if an event is left-clicked, try to invite attendees. ConnectMMO events only + + local self = Altoholic.Calendar.Events + local s = self.view[frame:GetID()] + if not s or s.linetype == EVENT_DATE then return end -- date line ? exit + + local e = self.List[s.parentID] -- dereference event + -- not a connectmmo event ? or wrong realm ? exit + if not e or e.eventType ~= CONNECTMMO_LINE or e.realm ~= GetRealmName() then return end + + local c = Altoholic:GetCharacterTable(e.char, e.realm) + if not c then return end -- invalid char table ? exit + + local _, _, _, _, _, attendees = strsplit("|", c.ConnectMMO[e.parentID]) + + -- TODO, add support for raid groups + for _, name in pairs({ strsplit(",", attendees) }) do + if name ~= UnitName("player") then + InviteUnit(name) + end + end +end + +function Altoholic.Calendar.Events:GetIndex(year, month, day) + local eventDate = format("%04d-%02d-%02d", year, month, day) + for k, v in pairs(self.view) do + if v.linetype == EVENT_DATE and v.eventDate == eventDate then + -- if the date line is found, return its index + return k + end + end +end + +function Altoholic.Calendar.Events:SetOffset(offset) + -- if the view has less entries than can be displayed, don't change the offset + if #self.view <= NUM_EVENTLINES then return end + + if offset <= 0 then + offset = 0 + elseif offset > (#self.view - NUM_EVENTLINES) then + offset = (#self.view - NUM_EVENTLINES) + end + FauxScrollFrame_SetOffset( AltoholicFrameCalendarScrollFrame, offset ) + AltoholicFrameCalendarScrollFrameScrollBar:SetValue(offset * 18) +end + +function Altoholic.Calendar:Scan() + if not CalendarFrame then + -- The Calendar addon is LoD, and most functions return nil if the calendar is not loaded, so unless the CalendarFrame is valid, exit right away + return + end + Altoholic:UnregisterEvent("CALENDAR_UPDATE_EVENT_LIST") -- prevent CalendarSetAbsMonth from triggering a scan (= avoid infinite loop) + + local currentMonth, currentYear = CalendarGetMonth() -- save the current month + local _, thisMonth, thisDay, thisYear = CalendarGetDate(); + CalendarSetAbsMonth(thisMonth, thisYear); + + local c = Altoholic.ThisCharacter + wipe(c.Calendar) + + -- save this month (from today) + 6 following months + for monthOffset = 0, 6 do + local month, year, numDays = CalendarGetMonth(monthOffset) + local startDay = (monthOffset == 0) and thisDay or 1 + + for day = startDay, numDays do + for i = 1, CalendarGetNumDayEvents(monthOffset, day) do -- number of events that day .. + -- http://www.wowwiki.com/API_CalendarGetDayEvent + local title, hour, minute, calendarType, _, eventType, _, _, inviteStatus = CalendarGetDayEvent(monthOffset, day, i) + if calendarType ~= "HOLIDAY" and calendarType ~= "RAID_LOCKOUT" and + calendarType ~= "RAID_RESET" and inviteStatus ~= CALENDAR_INVITESTATUS_DECLINED then + -- don't save holiday events, they're the same for all chars, and would be redundant..who wants to see 10 fishing contests every sundays ? =) + + table.insert(c.Calendar, format("%s|%s|%s|%d|%d", + format("%04d-%02d-%02d", year, month, day), format("%02d:%02d", hour, minute), + title, eventType, inviteStatus )) + end + end + end + end + + CalendarSetAbsMonth(currentMonth, currentYear); -- restore current month + Altoholic:RegisterEvent("CALENDAR_UPDATE_EVENT_LIST", Altoholic.Calendar.OnUpdate) +end + +function Altoholic.Calendar:OnUpdate() + local self = Altoholic.Calendar + self:Scan() + self.Events:BuildList() + Altoholic.Tabs.Summary:Refresh() +end + +local function ToggleWarningThreshold(self) + local id = self.arg1 + local warnings = Altoholic.Options:Get("WarningType"..id) -- Gets something like "15|5|1" + + local t = {} -- create a temporary table to store checked values + for v in warnings:gmatch("(%d+)") do + v = tonumber(v) + if v ~= self.value then -- add all values except the one that was clicked + table.insert(t, v) + end + end + + if not IsNumberInString(self.value, warnings) then -- if number is not yet in the string, save it (we're checking it, otherwise we're unchecking) + table.insert(t, self.value) + end + + Altoholic.Options:Set("WarningType"..id, table.concat(t, "|")) -- Sets something like "15|5|10|1" +end + +function Altoholic.Calendar:WarningType_Initialize() + local info = UIDropDownMenu_CreateInfo(); + local id = self:GetID() + local warnings = Altoholic.Options:Get("WarningType"..id) -- Gets something like "15|5|1" + + for _, threshold in pairs(TimerThresholds) do + info.text = format(D_MINUTES, threshold) + info.value = threshold + info.func = ToggleWarningThreshold + info.checked = IsNumberInString(threshold, warnings) + info.arg1 = id -- save the id of the current option + UIDropDownMenu_AddButton(info, 1); + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/Calendar.xml b/Altoholic-Addon/Altoholic/Frames/Calendar.xml new file mode 100644 index 0000000..fa3ee8f --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Calendar.xml @@ -0,0 +1,413 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Calendar.Events.Update) + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Containers.lua b/Altoholic-Addon/Altoholic/Frames/Containers.lua new file mode 100644 index 0000000..0da83e7 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Containers.lua @@ -0,0 +1,433 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local GREEN = "|cFF00FF00" + +local BAGSBANK = 1 +local BAGSBANK_ALLINONE = 2 +local BAGSONLY = 3 +local BAGSONLY_ALLINONE = 4 +local BANKONLY = 5 +local BANKONLY_ALLINONE = 6 + +addon.Containers = {} + +local ns = addon.Containers -- ns = namespace + +local containerViewLabels = { + format("%s & %s", L["Bags"], L["Bank"]), + format("%s & %s %s(%s)", L["Bags"], L["Bank"], GREEN, L["All-in-one"]), + L["Bags"], + format("%s %s(%s)", L["Bags"], GREEN, L["All-in-one"]), + L["Bank"], + format("%s %s(%s)", L["Bank"], GREEN, L["All-in-one"]), +} + +local function OnContainerViewChange(self) + local value = self.value + + UIDropDownMenu_SetSelectedValue(AltoholicFrameContainers_SelectContainerView, value); + addon.Options:Set("lastContainerView", value) + ns:SetView(value) + ns:Update(); +end + +local function DropDownContainerView_Initialize() + local info = UIDropDownMenu_CreateInfo(); + + for i = 1, #containerViewLabels do + info.text = containerViewLabels[i] + info.value = i + info.func = OnContainerViewChange + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + end +end + +local function OnRarityChange(self) + UIDropDownMenu_SetSelectedValue(AltoholicFrameContainers_SelectRarity, self.value); + ns:Update(); +end + +local function DropDownRarity_Initialize() + local info = UIDropDownMenu_CreateInfo(); + + info.text = L["Any"] + info.value = 0 + info.func = OnRarityChange + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + + for i = 2, 6 do -- Quality: 0 = poor .. 5 = legendary + info.text = ITEM_QUALITY_COLORS[i].hex .. _G["ITEM_QUALITY"..i.."_DESC"] + info.value = i + info.func = OnRarityChange + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + end +end + +local bagIndices + +local function UpdateBagIndices(bag, size) + -- the BagIndices table will be used by self:Containers_Update to determine which part of a bag should be displayed on a given line + -- ex: [1] = bagID = 0, from 1, to 12 + -- ex: [2] = bagID = 0, from 13, to 16 + + local lowerLimit = 1 + + while size > 0 do -- as long as there are slots to process .. + table.insert(bagIndices, { bagID=bag, from=lowerLimit} ) + + if size <= 12 then -- no more lines ? leave + return + else + size = size - 12 -- .. or adjust counters + lowerLimit = lowerLimit + 12 + end + end +end + +local function UpdateSpread() + local mode = UIDropDownMenu_GetSelectedValue(AltoholicFrameContainers_SelectContainerView) + local rarity = UIDropDownMenu_GetSelectedValue(AltoholicFrameContainers_SelectRarity) + local VisibleLines = 7 + local frame = "AltoholicFrameContainers" + local entry = frame.."Entry" + + if #bagIndices == 0 then + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 41) + return + end + + AltoholicTabCharactersStatus:SetText("") + + local character = Altoholic.Tabs.Characters:GetCurrent() + local DS = DataStore + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + + for i=1, VisibleLines do + local line = i + offset + + if line <= #bagIndices then + + local containerID = bagIndices[line].bagID + local container = DS:GetContainer(character, containerID) + local containerIcon, _, containerSize = DS:GetContainerInfo(character, containerID) + + local itemName = entry..i .. "Item1"; + + if bagIndices[line].from == 1 then -- if this is the first line for this bag .. draw bag icon + local itemButton = _G[itemName]; + if containerIcon then + Altoholic:SetItemButtonTexture(itemName, containerIcon); + else -- will be nill for bag 100 + Altoholic:SetItemButtonTexture(itemName, "Interface\\Icons\\INV_Box_03"); + end + + itemButton:SetID(containerID) + + itemButton:SetScript("OnEnter", function(self) + local id = self:GetID() + GameTooltip:SetOwner(self, "ANCHOR_LEFT"); + if id == -2 then + GameTooltip:AddLine(KEYRING,1,1,1); + GameTooltip:AddLine(L["32 Keys Max"],1,1,1); + elseif id == 0 then + GameTooltip:AddLine(BACKPACK_TOOLTIP,1,1,1); + GameTooltip:AddLine(format(CONTAINER_SLOTS, 16, BAGSLOT),1,1,1); + + elseif id == 100 then + GameTooltip:AddLine(L["Bank"],0.5,0.5,1); + GameTooltip:AddLine(L["28 Slot"],1,1,1); + else + local character = Altoholic.Tabs.Characters:GetCurrent() + local _, link = DS:GetContainerInfo(character, id) + GameTooltip:SetHyperlink(link); + if (id >= 5) and (id <= 11) then + GameTooltip:AddLine(L["Bank bag"],0,1,0); + end + end + GameTooltip:Show(); + end) + _G[itemName .. "Count"]:Hide() + + _G[ itemName ]:Show() + else + _G[ itemName ]:Hide() + end + + _G[ entry..i .. "Item2" ]:Hide() + _G[ entry..i .. "Item2" ].id = nil + _G[ entry..i .. "Item2" ].link = nil + + for j=3, 14 do + local itemName = entry..i .. "Item" .. j; + local itemButton = _G[itemName]; + local itemTexture = _G[itemName.."IconTexture"] + + Altoholic:CreateButtonBorder(itemButton) + itemButton.border:Hide() + itemTexture:SetDesaturated(0) + + local slotID = bagIndices[line].from - 3 + j + local itemID, itemLink, itemCount = DS:GetSlotInfo(container, slotID) + + if (slotID <= containerSize) then + if itemID then + Altoholic:SetItemButtonTexture(itemName, GetItemIcon(itemID)); + + if rarity ~= 0 then + local _, _, itemRarity = GetItemInfo(itemID) + if itemRarity and itemRarity == rarity then + local r, g, b = GetItemQualityColor(itemRarity) + itemButton.border:SetVertexColor(r, g, b, 0.5) + itemButton.border:Show() + else + itemTexture:SetDesaturated(1) + end + end + else + Altoholic:SetItemButtonTexture(itemName, "Interface\\PaperDoll\\UI-Backpack-EmptySlot"); + end + + itemButton.id = itemID + itemButton.link = itemLink + itemButton:SetScript("OnEnter", function(self) + Altoholic:Item_OnEnter(self) + end) + + local countWidget = _G[itemName .. "Count"] + if not itemCount or (itemCount < 2) then + countWidget:Hide(); + else + countWidget:SetText(itemCount); + countWidget:Show(); + end + + local startTime, duration, isEnabled = DS:GetContainerCooldownInfo(container, slotID) + + itemButton.startTime = startTime + itemButton.duration = duration + + CooldownFrame_SetTimer(_G[itemName .. "Cooldown"], startTime or 0, duration or 0, isEnabled) + + itemButton:Show() + else + _G[ itemName ]:Hide() + itemButton.id = nil + itemButton.link = nil + itemButton.startTime = nil + itemButton.duration = nil + end + end + _G[ entry..i ]:Show() + else + _G[ entry..i ]:Hide() + end + end + + if #bagIndices < VisibleLines then + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleLines, VisibleLines, 41); + else + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], #bagIndices, VisibleLines, 41); + end +end + +local function UpdateAllInOne() + local mode = UIDropDownMenu_GetSelectedValue(AltoholicFrameContainers_SelectContainerView) + local rarity = UIDropDownMenu_GetSelectedValue(AltoholicFrameContainers_SelectRarity) + local VisibleLines = 7 + local frame = "AltoholicFrameContainers" + local entry = frame.."Entry" + + AltoholicTabCharactersStatus:SetText("") + + local character = Altoholic.Tabs.Characters:GetCurrent() + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + + local minSlotIndex = offset * 14 + local currentSlotIndex = 0 -- this indexes the non-empty slots + local i = 1 + local j = 1 + + local containerList = {} + + if mode ~= BANKONLY_ALLINONE then -- if it's not a bank only view, add the normal bags + table.insert(containerList, -2) + for i = 0, 4 do + table.insert(containerList, i) + end + end + + if mode ~= BAGSONLY_ALLINONE then -- if it's not a bag only view, add bank bags + for i = 5, 11 do + table.insert(containerList, i) + end + table.insert(containerList, 100) + end + + local DS = DataStore + for _, containerID in pairs(containerList) do + local container = DS:GetContainer(character, containerID) + local _, _, containerSize = DS:GetContainerInfo(character, containerID) + + for slotID = 1, containerSize do + local itemID, itemLink, itemCount = DS:GetSlotInfo(container, slotID) + if itemID then + currentSlotIndex = currentSlotIndex + 1 + if (currentSlotIndex > minSlotIndex) and (i <= VisibleLines) then + local itemName = entry..i .. "Item" .. j; + local itemButton = _G[itemName]; + local itemTexture = _G[itemName.."IconTexture"] + + Altoholic:CreateButtonBorder(itemButton) + itemButton.border:Hide() + + Altoholic:SetItemButtonTexture(itemName, GetItemIcon(itemID)); + itemTexture:SetDesaturated(0) + + if rarity ~= 0 then + local _, _, itemRarity = GetItemInfo(itemID) + if itemRarity and itemRarity == rarity then + local r, g, b = GetItemQualityColor(itemRarity) + itemButton.border:SetVertexColor(r, g, b, 0.5) + itemButton.border:Show() + else + itemTexture:SetDesaturated(1) + end + end + + itemButton.id = itemID + itemButton.link = itemLink + itemButton:SetScript("OnEnter", function(self) + Altoholic:Item_OnEnter(self) + end) + + local countWidget = _G[itemName .. "Count"] + if not itemCount or (itemCount < 2) then + countWidget:Hide(); + else + countWidget:SetText(itemCount); + countWidget:Show(); + end + + local startTime, duration, isEnabled = DS:GetContainerCooldownInfo(container, slotID) + + itemButton.startTime = startTime + itemButton.duration = duration + + CooldownFrame_SetTimer(_G[itemName .. "Cooldown"], startTime or 0, duration or 0, isEnabled) + + _G[ itemName ]:Show() + + j = j + 1 + if j > 14 then + j = 1 + i = i + 1 + end + end + end + end + end + + while i <= VisibleLines do + while j <= 14 do + _G[ entry..i .. "Item" .. j ]:Hide() + _G[ entry..i .. "Item" .. j ].id = nil + _G[ entry..i .. "Item" .. j ].link = nil + _G[ entry..i .. "Item" .. j ].startTime = nil + _G[ entry..i .. "Item" .. j ].duration = nil + j = j + 1 + end + + j = 1 + i = i + 1 + end + + for i=1, VisibleLines do + _G[ entry..i ]:Show() + end + + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], ceil(currentSlotIndex / 14), VisibleLines, 41); +end + +function ns:Init() + local mode = addon.Options:Get("lastContainerView") + mode = mode or 1 + + local f = AltoholicFrameContainers_SelectContainerView + UIDropDownMenu_SetSelectedValue(f, mode); + UIDropDownMenu_SetText(f, containerViewLabels[mode]) + UIDropDownMenu_Initialize(f, DropDownContainerView_Initialize) + + f = AltoholicFrameContainers_SelectRarity + UIDropDownMenu_SetSelectedValue(f, 0); + UIDropDownMenu_SetText(f, L["Any"]) + UIDropDownMenu_Initialize(f, DropDownRarity_Initialize) +end + +function ns:SetView(view) + view = view or 1 + if mod(view, 2) ~= 0 then -- not an all-in-one view + ns.Update = UpdateSpread + ns:UpdateCache() + FauxScrollFrame_SetOffset( AltoholicFrameContainersScrollFrame, 0) + else + ns.Update = UpdateAllInOne + end +end + +function ns:UpdateCache() + local mode = UIDropDownMenu_GetSelectedValue(AltoholicFrameContainers_SelectContainerView) + local character = addon.Tabs.Characters:GetCurrent() + + bagIndices = bagIndices or {} + wipe(bagIndices) + + local bagMin = 0 + local bagMax = 11 + + -- bags : -2 (keyring) and 0 to 4 + -- bank: 5 to 11 and 100 + if mode == BAGSONLY then + bagMax = 4 -- 0 to 4 + elseif mode == BANKONLY then + bagMin = 5 -- 5 to 11 + end + + local DS = DataStore + for bagID = bagMin, bagMax do + if DS:GetContainer(character, bagID) then + local _, _, size = DS:GetContainerInfo(character, bagID) + UpdateBagIndices(bagID, size) + end + end + + if mode ~= BANKONLY then + UpdateBagIndices(-2, 32) -- KeyRing + end + + if mode ~= BAGSONLY then + if DS:GetContainer(character, 100) then -- if bank hasn't been visited yet, exit + UpdateBagIndices(100, 28) + end + end +end + +-- *** EVENT HANDLERS *** +function ns:OnBagUpdate(bag) + addon:RefreshTooltip() + + if DataStore:IsMailBoxOpen() and AltoholicFrameMail:IsVisible() then + -- if a bag is updated while the mailbox is opened, this means an attachment has been taken. + addon.Mail:BuildView() + addon.Mail:Update() + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/Containers.xml b/Altoholic-Addon/Altoholic/Frames/Containers.xml new file mode 100644 index 0000000..85c2d4b --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Containers.xml @@ -0,0 +1,289 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 120) + UIDropDownMenu_SetButtonWidth(self, 20) + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 100) + UIDropDownMenu_SetButtonWidth(self, 20) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 41, Altoholic.Containers.Update) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Currencies.lua b/Altoholic-Addon/Altoholic/Frames/Currencies.lua new file mode 100644 index 0000000..9b8219e --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Currencies.lua @@ -0,0 +1,207 @@ +local addonName = ... +local addon = _G[addonName] + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" + +local currentTokenType +local usedTokens +local tokenTextures = {} + +addon.Currencies = {} + +local ns = addon.Currencies -- ns = namespace + +local function HashToSortedArray(hash) + local array = {} -- order them + for k, _ in pairs(hash) do + table.insert(array, k) + end + table.sort(array) + return array +end + +local function GetUsedHeaders() + local realm, account = addon:GetCurrentRealm() + local DS = DataStore + + local usedHeaders = {} + + for _, character in pairs(DS:GetCharacters(realm, account)) do -- all alts on this realm + local num = DS:GetNumCurrencies(character) or 0 + for i = 1, num do + local isHeader, name = DS:GetCurrencyInfo(character, i) -- save ech header found in the table + if isHeader then + usedHeaders[name] = true + end + end + end + + return HashToSortedArray(usedHeaders) +end + +local function GetUsedTokens(header) + -- get the list of tokens found under a specific header, across all alts + + local realm, account = addon:GetCurrentRealm() + local DS = DataStore + + local tokens = {} + local useData -- use data for a specific header or not + + for _, character in pairs(DS:GetCharacters(realm, account)) do -- all alts on this realm + local num = DS:GetNumCurrencies(character) or 0 + for i = 1, num do + local isHeader, name, _, itemID = DS:GetCurrencyInfo(character, i) + if isHeader then + if name == header then -- the header we're searching for, set the flag + useData = true + else + useData = nil + end + else + if useData then -- mark it as used + tokens[name] = true + tokenTextures[name] = GetItemIcon(itemID) + end + end + end + end + + return HashToSortedArray(tokens) +end + +local function DDM_Add(text, func, arg1, arg2) + -- tiny wrapper + local info = UIDropDownMenu_CreateInfo(); + + info.text = text + info.func = func + info.arg1 = arg1 + info.arg2 = arg2 + info.checked = nil + UIDropDownMenu_AddButton(info, 1); +end + +local function DDM_AddCloseMenu() + local info = UIDropDownMenu_CreateInfo(); + + -- Close menu item + info.text = CLOSE + info.func = function() CloseDropDownMenus() end + info.checked = nil + info.notCheckable = 1 + info.icon = nil + UIDropDownMenu_AddButton(info, 1) +end + +local function DDM_OnClick(self, header) + currentTokenType = header + UIDropDownMenu_SetText(AltoholicFrameCurrencies_SelectCurrencies, currentTokenType) + usedTokens = GetUsedTokens(currentTokenType) + ns:Update() +end + +local function Currencies_UpdateEx(self, offset, entry, desc) + local line + local size = desc:GetSize() + + local DS = DataStore + local realm, account = addon:GetCurrentRealm() + local character + + for i=1, desc.NumLines do + line = i + offset + if line <= size then + local token = usedTokens[line] + + _G[entry..i.."Name"]:SetText(WHITE .. token) + _G[entry..i.."Name"]:SetJustifyH("LEFT") + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + + for j = 1, 10 do -- loop through the 10 alts + local itemName = entry.. i .. "Item" .. j; + local itemButton = _G[itemName] + local classButton = _G["AltoholicFrameClassesItem" .. j] + + local itemTexture = _G[itemName .. "_Background"] + itemTexture:SetTexture(tokenTextures[token]) + + if classButton.CharName then -- if there's an alt in this column.. + character = DS:GetCharacter(classButton.CharName, realm, account) + local count = DS:GetCurrencyInfoByName(character, token) + itemButton.count = count + + if count then + itemTexture:SetVertexColor(0.5, 0.5, 0.5); -- greyed out + itemButton.CharName = classButton.CharName + + if count >= 100000 then + count = format("%2.1fM", count/1000000) + elseif count >= 10000 then + count = format("%2.0fk", count/1000) + elseif count >= 1000 then + count = format("%2.1fk", count/1000) + end + + _G[itemName .. "Name"]:SetText(GREEN..count) + itemButton:Show() + else + itemButton.CharName = nil + itemButton:Hide() + end + else + itemButton:Hide() + end + end + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + end + end +end + +local CurrenciesScrollFrame_Desc = { + NumLines = 8, + LineHeight = 41, + Frame = "AltoholicFrameCurrencies", + GetSize = function() return #usedTokens end, + Update = Currencies_UpdateEx, +} + +local function DropDown_Initialize() + for _, header in ipairs(GetUsedHeaders()) do -- and add them to the DDM + DDM_Add(header, DDM_OnClick, header) + end + DDM_AddCloseMenu() +end + +function ns:Init() + local headers = GetUsedHeaders() + currentTokenType = headers[1] + + local f = AltoholicFrameCurrencies_SelectCurrencies + UIDropDownMenu_SetText(f, currentTokenType) + UIDropDownMenu_Initialize(f, DropDown_Initialize) + + usedTokens = GetUsedTokens(currentTokenType) +end + +function ns:Update() + addon:ScrollFrameUpdate(CurrenciesScrollFrame_Desc) +end + +function ns:OnEnter(frame) + local charName = frame.CharName + if not charName then return end + + local DS = DataStore + local realm, account = addon:GetCurrentRealm() + local character = DS:GetCharacter(charName, realm, account) + + AltoTooltip:SetOwner(frame, "ANCHOR_LEFT"); + AltoTooltip:ClearLines(); + AltoTooltip:AddLine(DS:GetColoredCharacterName(character)); + AltoTooltip:AddLine(usedTokens[frame:GetParent():GetID()], 1, 1, 1); + AltoTooltip:AddLine(GREEN..frame.count); + AltoTooltip:Show(); +end diff --git a/Altoholic-Addon/Altoholic/Frames/Currencies.xml b/Altoholic-Addon/Altoholic/Frames/Currencies.xml new file mode 100644 index 0000000..823221a --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Currencies.xml @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 100) + UIDropDownMenu_SetButtonWidth(self, 20) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 41, Altoholic.Currencies.Update) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Equipment.lua b/Altoholic-Addon/Altoholic/Frames/Equipment.lua new file mode 100644 index 0000000..2d684c5 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Equipment.lua @@ -0,0 +1,617 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local ORANGE = "|cFFFF7F00" + +-- Class constants, for readability, these values match the ones in Altoholic.Classes (altoholic.lua) +local CLASS_MAGE = "MAGE" +local CLASS_WARRIOR = "WARRIOR" +local CLASS_HUNTER = "HUNTER" +local CLASS_ROGUE = "ROGUE" +local CLASS_WARLOCK = "WARLOCK" +local CLASS_DRUID = "DRUID" +local CLASS_SHAMAN = "SHAMAN" +local CLASS_PALADIN = "PALADIN" +local CLASS_PRIEST = "PRIEST" +local CLASS_DEATHKNIGHT = "DEATHKNIGHT" + +--[[ + +a few constants to increase readability in the tables below, +some stats are taken from WoWUI's GlobalStrings.lua, but not all of them are suitable + +SPELL_STAT1_NAME = "Strength"; +SPELL_STAT2_NAME = "Agility"; +SPELL_STAT3_NAME = "Stamina"; +SPELL_STAT4_NAME = "Intellect"; +SPELL_STAT5_NAME = "Spirit"; + +COMBAT_RATING_NAME1 = "Weapon Skill"; +COMBAT_RATING_NAME10 = "Crit Rating"; -- Ranged crit rating +COMBAT_RATING_NAME11 = "Crit Rating"; -- Spell Crit Rating +COMBAT_RATING_NAME15 = "Resilience"; +COMBAT_RATING_NAME2 = "Defense Rating"; +COMBAT_RATING_NAME24 = "Expertise"; +COMBAT_RATING_NAME3 = "Dodge Rating"; +COMBAT_RATING_NAME4 = "Parry Rating"; +COMBAT_RATING_NAME5 = "Block Rating"; +COMBAT_RATING_NAME6 = "Hit Rating"; +COMBAT_RATING_NAME7 = "Hit Rating"; -- Ranged hit rating +COMBAT_RATING_NAME8 = "Hit Rating"; -- Spell hit rating +COMBAT_RATING_NAME9 = "Crit Rating"; -- Melee crit rating + +ATTACK_POWER_TOOLTIP = "Attack Power"; +SPELLS = "Spells"; -- Generic "spells" note: replace this with a spell power constant in wotlk +MANA_REGEN = "Mana Regen"; +BONUS_HEALING = "Bonus Healing"; + +ITEM_MOD_CRIT_RATING = "Improves critical strike rating by %d."; + ITEM_MOD_CRIT_SPELL_RATING= "Improves spell critical strike rating by %d."; +ITEM_MOD_HIT_RATING = "Improves hit rating by %d."; +ITEM_MOD_HIT_SPELL_RATING = "Improves spell hit rating by %d."; +local STAT_HEALING = L["Increases healing done by up to %d+"] +local STAT_SPELLDMG = L["Increases damage and healing done by magical spells and effects by up to %d+"] +ITEM_MOD_DEFENSE_SKILL_RATING = "Increases defense rating by %d."; -- Increases defense rating by %d +ITEM_MOD_DODGE_RATING = "Increases your dodge rating by %d."; +ITEM_MOD_BLOCK_RATING = "Increases your shield block rating by %d."; +ITEM_MOD_SPELL_POWER = "Increases spell power by %d."; +ITEM_MOD_RESILIENCE_RATING = "Improves your resilience rating by %d."; +--]] + +local STAT_AP = L["Increases attack power by %d+"] +local STAT_MP5 = L["Restores %d+ mana per"] +local STAT_SHAMAN_ONLY = L["Classes: Shaman"] .. "$" +local STAT_MAGE_ONLY = L["Classes: Mage"] .. "$" +local STAT_ROGUE_ONLY = L["Classes: Rogue"] .. "$" +local STAT_HUNTER_ONLY = L["Classes: Hunter"] .. "$" +local STAT_WARRIOR_ONLY = L["Classes: Warrior"] .. "$" +local STAT_PALADIN_ONLY = L["Classes: Paladin"] .. "$" +local STAT_WARLOCK_ONLY = L["Classes: Warlock"] .. "$" +local STAT_PRIEST_ONLY = L["Classes: Priest"] .. "$" +local STAT_DK_ONLY = L["Classes: Death Knight"] .. "$" +local STAT_RESIST = L["Resistance"] + + +addon.Equipment = {} + +local ns = addon.Equipment -- ns = namespace + +-- When processing item stats, exclude an item if one of these strings is encountered, then discard the item +-- ex: if you're searching an update for the shoulder slot of your warrior, then the items listed will be of type "Armor" & subtype "Plate", +-- so parsing each line of stat is necessary to determine if a warrior can use the item.. therefore, the algorithm tries to find one of the words +-- that will help filtering out the item (if plate has +intel or +mana, it's obviously not for a warrior ..) +ns.ExcludeStats = { + [CLASS_MAGE.."DPS"] = { + STAT_RESIST, + SPELL_STAT1_NAME, + SPELL_STAT2_NAME, + STAT_AP, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_BLOCK_RATING, + STAT_PRIEST_ONLY, + STAT_WARLOCK_ONLY + }, + [CLASS_WARRIOR.."Tank"] = { + STAT_RESIST, + SPELL_STAT4_NAME, + SPELL_STAT5_NAME, + STAT_MP5, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_RESILIENCE_RATING, + STAT_AP, + STAT_PALADIN_ONLY + }, + [CLASS_WARRIOR.."DPS"] = { + STAT_RESIST, + SPELL_STAT4_NAME, + SPELL_STAT5_NAME, + STAT_MP5, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_DEFENSE_SKILL_RATING, + STAT_PALADIN_ONLY + }, + [CLASS_HUNTER.."DPS"] = { + STAT_RESIST, + SPELL_STAT1_NAME, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_BLOCK_RATING, + STAT_SHAMAN_ONLY + }, + [CLASS_ROGUE.."DPS"] = { + STAT_RESIST, + SPELL_STAT4_NAME, + STAT_MP5, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_BLOCK_RATING, + ITEM_MOD_DEFENSE_SKILL_RATING + }, + [CLASS_WARLOCK.."DPS"] = { + STAT_RESIST, + SPELL_STAT1_NAME, + SPELL_STAT2_NAME, + STAT_AP, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_BLOCK_RATING, + STAT_MAGE_ONLY, + STAT_PRIEST_ONLY + }, + [CLASS_DRUID.."Tank"] = { + STAT_RESIST, + ITEM_MOD_SPELL_POWER, + STAT_ROGUE_ONLY, + ITEM_MOD_RESILIENCE_RATING + }, + [CLASS_DRUID.."Heal"] = { + STAT_RESIST, + SPELL_STAT1_NAME, + SPELL_STAT2_NAME, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_BLOCK_RATING, + ITEM_MOD_RESILIENCE_RATING, + STAT_AP + }, + [CLASS_DRUID.."DPS"] = { + STAT_RESIST, + SPELL_STAT4_NAME, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_BLOCK_RATING, + STAT_ROGUE_ONLY + }, + [CLASS_DRUID.."Balance"] = { + STAT_RESIST, + SPELL_STAT1_NAME, + SPELL_STAT2_NAME, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_BLOCK_RATING, + STAT_AP + }, + [CLASS_SHAMAN.."Heal"] = { + STAT_RESIST, + ITEM_MOD_CRIT_RATING, + SPELL_STAT2_NAME, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_BLOCK_RATING, + ITEM_MOD_RESILIENCE_RATING, + STAT_AP + }, + [CLASS_SHAMAN.."DPS"] = { + STAT_RESIST, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_BLOCK_RATING, + STAT_HUNTER_ONLY + }, + [CLASS_SHAMAN.."Elemental"] = { + STAT_RESIST, + SPELL_STAT1_NAME, + SPELL_STAT2_NAME, + ITEM_MOD_HIT_RATING, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_BLOCK_RATING, + STAT_AP, + ITEM_MOD_CRIT_RATING + }, + [CLASS_PALADIN.."Tank"] = { + STAT_RESIST, + SPELL_STAT2_NAME, + STAT_AP, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_RESILIENCE_RATING, + ITEM_MOD_CRIT_RATING, + STAT_WARRIOR_ONLY + }, + [CLASS_PALADIN.."Heal"] = { + STAT_RESIST, + SPELL_STAT2_NAME, + ITEM_MOD_CRIT_RATING, + STAT_AP, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_BLOCK_RATING, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_HIT_RATING, + ITEM_MOD_RESILIENCE_RATING + }, + [CLASS_PALADIN.."DPS"] = { + STAT_RESIST, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_BLOCK_RATING, + ITEM_MOD_DEFENSE_SKILL_RATING, + STAT_WARRIOR_ONLY }, + [CLASS_PRIEST.."Heal"] = { + STAT_RESIST, + SPELL_STAT1_NAME, + SPELL_STAT2_NAME, + ITEM_MOD_RESILIENCE_RATING, + STAT_AP, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_BLOCK_RATING + }, + [CLASS_PRIEST.."DPS"] = { + STAT_RESIST, + SPELL_STAT1_NAME, + SPELL_STAT2_NAME, + STAT_AP, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_BLOCK_RATING, + STAT_MAGE_ONLY, + STAT_WARLOCK_ONLY + }, + [CLASS_DEATHKNIGHT.."Tank"] = { + STAT_RESIST, + SPELL_STAT4_NAME, + SPELL_STAT5_NAME, + STAT_MP5, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_RESILIENCE_RATING, + STAT_WARRIOR_ONLY, + STAT_PALADIN_ONLY + }, + [CLASS_DEATHKNIGHT.."DPS"] = { + STAT_RESIST, + SPELL_STAT4_NAME, + SPELL_STAT5_NAME, + STAT_MP5, + ITEM_MOD_DEFENSE_SKILL_RATING, + ITEM_MOD_DODGE_RATING, + ITEM_MOD_BLOCK_RATING, + ITEM_MOD_SPELL_POWER, + ITEM_MOD_RESILIENCE_RATING, + STAT_WARRIOR_ONLY, + STAT_PALADIN_ONLY + } +} + +ns.BaseStats = { -- the order of these strings should match the "-s" in the associated entry of the FormatStats table + [CLASS_MAGE.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, SPELL_STAT5_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, ITEM_MOD_SPELL_POWER }, + [CLASS_WARRIOR.."Tank"] = { SPELL_STAT3_NAME, SPELL_STAT1_NAME, ITEM_MOD_DEFENSE_SKILL_RATING, ITEM_MOD_DODGE_RATING, ITEM_MOD_HIT_RATING }, + [CLASS_WARRIOR.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT1_NAME, SPELL_STAT2_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, STAT_AP }, + [CLASS_HUNTER.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT2_NAME, SPELL_STAT4_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, STAT_AP }, + [CLASS_ROGUE.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT2_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, STAT_AP }, + [CLASS_WARLOCK.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, ITEM_MOD_SPELL_POWER }, + [CLASS_DRUID.."Tank"] = { SPELL_STAT3_NAME, SPELL_STAT1_NAME, SPELL_STAT2_NAME, ITEM_MOD_DEFENSE_SKILL_RATING, ITEM_MOD_DODGE_RATING, ITEM_MOD_HIT_RATING }, + [CLASS_DRUID.."Heal"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, SPELL_STAT5_NAME, ITEM_MOD_CRIT_RATING, STAT_MP5, ITEM_MOD_SPELL_POWER }, + [CLASS_DRUID.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT1_NAME, SPELL_STAT2_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, STAT_AP }, + [CLASS_DRUID.."Balance"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, STAT_MP5, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, ITEM_MOD_SPELL_POWER }, + [CLASS_SHAMAN.."Heal"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, ITEM_MOD_CRIT_RATING, STAT_MP5, ITEM_MOD_SPELL_POWER }, + [CLASS_SHAMAN.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT1_NAME, SPELL_STAT2_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, STAT_AP }, + [CLASS_SHAMAN.."Elemental"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, STAT_MP5, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, ITEM_MOD_SPELL_POWER }, + [CLASS_PALADIN.."Tank"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, ITEM_MOD_DEFENSE_SKILL_RATING, ITEM_MOD_DODGE_RATING, ITEM_MOD_HIT_RATING, ITEM_MOD_SPELL_POWER }, + [CLASS_PALADIN.."Heal"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, ITEM_MOD_CRIT_RATING, STAT_MP5, ITEM_MOD_SPELL_POWER }, + [CLASS_PALADIN.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT1_NAME, SPELL_STAT4_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, STAT_AP }, + [CLASS_PRIEST.."Heal"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, SPELL_STAT5_NAME, ITEM_MOD_CRIT_RATING, STAT_MP5, ITEM_MOD_SPELL_POWER }, + [CLASS_PRIEST.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT4_NAME, SPELL_STAT5_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, ITEM_MOD_SPELL_POWER }, + [CLASS_DEATHKNIGHT.."Tank"] = { SPELL_STAT3_NAME, SPELL_STAT1_NAME, ITEM_MOD_DEFENSE_SKILL_RATING, ITEM_MOD_DODGE_RATING, ITEM_MOD_HIT_RATING }, + [CLASS_DEATHKNIGHT.."DPS"] = { SPELL_STAT3_NAME, SPELL_STAT1_NAME, SPELL_STAT2_NAME, ITEM_MOD_CRIT_RATING, ITEM_MOD_HIT_RATING, STAT_AP } +} + +ns.FormatStats = { + [CLASS_MAGE.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. SPELL_STAT5_NAME .."|".. COMBAT_RATING_NAME11 .."|".. COMBAT_RATING_NAME8 .."|".. SPELLS, + [CLASS_WARRIOR.."Tank"] = SPELL_STAT3_NAME .."|".. SPELL_STAT1_NAME .."|".. COMBAT_RATING_NAME2 .."|".. COMBAT_RATING_NAME3 .."|".. COMBAT_RATING_NAME6, + [CLASS_WARRIOR.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT1_NAME .."|".. SPELL_STAT2_NAME .."|".. COMBAT_RATING_NAME9 .."|".. COMBAT_RATING_NAME6 .."|" .. ATTACK_POWER_TOOLTIP, + [CLASS_HUNTER.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT2_NAME .."|".. SPELL_STAT4_NAME .."|".. COMBAT_RATING_NAME10 .."|".. COMBAT_RATING_NAME7 .."|".. ATTACK_POWER_TOOLTIP, + [CLASS_ROGUE.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT2_NAME .."|".. COMBAT_RATING_NAME9 .."|".. COMBAT_RATING_NAME6 .."|".. ATTACK_POWER_TOOLTIP, + [CLASS_WARLOCK.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. COMBAT_RATING_NAME11 .."|".. COMBAT_RATING_NAME8 .."|".. SPELLS, + [CLASS_DRUID.."Tank"] = SPELL_STAT3_NAME .."|".. SPELL_STAT1_NAME .."|".. SPELL_STAT2_NAME .."|".. COMBAT_RATING_NAME2 .."|".. COMBAT_RATING_NAME3 .."|".. COMBAT_RATING_NAME6, + [CLASS_DRUID.."Heal"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. SPELL_STAT5_NAME .."|".. COMBAT_RATING_NAME11 .."|".. MANA_REGEN .."|".. BONUS_HEALING, + [CLASS_DRUID.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT1_NAME .."|".. SPELL_STAT2_NAME .."|".. COMBAT_RATING_NAME9 .."|".. COMBAT_RATING_NAME6 .."|".. ATTACK_POWER_TOOLTIP, + [CLASS_DRUID.."Balance"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. MANA_REGEN .."|".. COMBAT_RATING_NAME11 .."|".. COMBAT_RATING_NAME8 .."|".. SPELLS, + [CLASS_SHAMAN.."Heal"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. COMBAT_RATING_NAME11 .."|".. MANA_REGEN .."|".. BONUS_HEALING, + [CLASS_SHAMAN.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT1_NAME .."|".. SPELL_STAT2_NAME .."|".. COMBAT_RATING_NAME9 .."|".. COMBAT_RATING_NAME6 .."|".. ATTACK_POWER_TOOLTIP, + [CLASS_SHAMAN.."Elemental"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. MANA_REGEN .."|".. COMBAT_RATING_NAME11 .."|".. COMBAT_RATING_NAME8 .."|".. SPELLS, + [CLASS_PALADIN.."Tank"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. COMBAT_RATING_NAME2 .."|".. COMBAT_RATING_NAME3 .."|".. COMBAT_RATING_NAME6 .."|".. SPELLS, + [CLASS_PALADIN.."Heal"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. COMBAT_RATING_NAME11 .."|".. MANA_REGEN .."|".. BONUS_HEALING, + [CLASS_PALADIN.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT1_NAME .."|".. SPELL_STAT4_NAME .."|".. COMBAT_RATING_NAME9 .."|".. COMBAT_RATING_NAME6 .."|".. ATTACK_POWER_TOOLTIP, + [CLASS_PRIEST.."Heal"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. SPELL_STAT5_NAME .."|".. COMBAT_RATING_NAME11 .."|".. MANA_REGEN .."|".. BONUS_HEALING, + [CLASS_PRIEST.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT4_NAME .."|".. SPELL_STAT5_NAME .."|".. COMBAT_RATING_NAME11 .."|".. COMBAT_RATING_NAME8 .."|".. SPELLS, + [CLASS_DEATHKNIGHT.."Tank"] = SPELL_STAT3_NAME .."|".. SPELL_STAT1_NAME .."|".. COMBAT_RATING_NAME2 .."|".. COMBAT_RATING_NAME3 .."|".. COMBAT_RATING_NAME6, + [CLASS_DEATHKNIGHT.."DPS"] = SPELL_STAT3_NAME .."|".. SPELL_STAT1_NAME .."|".. SPELL_STAT2_NAME .."|".. COMBAT_RATING_NAME9 .."|".. COMBAT_RATING_NAME6 .."|" .. ATTACK_POWER_TOOLTIP +} + +-- These two tables are necessary to find equivalences between INVTYPEs returned by GetItemInfo and the actual equipment slots. +-- For instance, the "ranged" slot can contain bows/guns/wans/relics/thrown weapons. +local inventoryTypes = { + ["INVTYPE_HEAD"] = 1, -- 1 means first entry in the EquipmentSlots table (just below this one) + ["INVTYPE_SHOULDER"] = 2, + ["INVTYPE_CHEST"] = 3, + ["INVTYPE_ROBE"] = 3, + ["INVTYPE_WRIST"] = 4, + ["INVTYPE_HAND"] = 5, + ["INVTYPE_WAIST"] = 6, + ["INVTYPE_LEGS"] = 7, + ["INVTYPE_FEET"] = 8, + + ["INVTYPE_NECK"] = 9, + ["INVTYPE_CLOAK"] = 10, + ["INVTYPE_FINGER"] = 11, + ["INVTYPE_TRINKET"] = 12, + ["INVTYPE_WEAPON"] = 13, + ["INVTYPE_2HWEAPON"] = 14, + ["INVTYPE_WEAPONMAINHAND"] = 15, + ["INVTYPE_WEAPONOFFHAND"] = 16, + ["INVTYPE_HOLDABLE"] = 16, + ["INVTYPE_SHIELD"] = 17, + ["INVTYPE_RANGED"] = 18, + ["INVTYPE_THROWN"] = 18, + ["INVTYPE_RANGEDRIGHT"] = 18, + ["INVTYPE_RELIC"] = 18 +} + +local slotNames = { + [1] = BI["Head"], -- "INVTYPE_HEAD" + [2] = BI["Shoulder"], -- "INVTYPE_SHOULDER" + [3] = BI["Chest"], -- "INVTYPE_CHEST", "INVTYPE_ROBE" + [4] = BI["Wrist"], -- "INVTYPE_WRIST" + [5] = BI["Hands"], -- "INVTYPE_HAND" + [6] = BI["Waist"], -- "INVTYPE_WAIST" + [7] = BI["Legs"], -- "INVTYPE_LEGS" + [8] = BI["Feet"], -- "INVTYPE_FEET" + + [9] = BI["Neck"], -- "INVTYPE_NECK" + [10] = BI["Back"], -- "INVTYPE_CLOAK" + [11] = BI["Ring"], -- "INVTYPE_FINGER" + [12] = BI["Trinket"], -- "INVTYPE_TRINKET" + [13] = BI["One-Hand"], -- "INVTYPE_WEAPON" + [14] = BI["Two-Hand"], -- "INVTYPE_2HWEAPON" + [15] = BI["Main Hand"], -- "INVTYPE_WEAPONMAINHAND" + [16] = BI["Off Hand"], -- "INVTYPE_WEAPONOFFHAND", "INVTYPE_HOLDABLE" + [17] = BI["Shield"], -- "INVTYPE_SHIELD" + [18] = BI["Ranged"] -- "INVTYPE_RANGED", "INVTYPE_THROWN", "INVTYPE_RANGEDRIGHT", "INVTYPE_RELIC" +} + +local slotTypeInfo = { + { color = "|cFF69CCF0", name = BI["Head"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Head"}, + { color = "|cFFABD473", name = BI["Neck"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Neck"}, + { color = "|cFF69CCF0", name = BI["Shoulder"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Shoulder"}, + { color = WHITE, name = BI["Shirt"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Shirt"}, + { color = "|cFF69CCF0", name = BI["Chest"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Chest"}, + { color = "|cFF69CCF0", name = BI["Waist"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Waist"}, + { color = "|cFF69CCF0", name = BI["Legs"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Legs"}, + { color = "|cFF69CCF0", name = BI["Feet"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Feet"}, + { color = "|cFF69CCF0", name = BI["Wrist"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Wrists"}, + { color = "|cFF69CCF0", name = BI["Hands"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Hands"}, + { color = ORANGE, name = BI["Ring"] .. " 1", icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Finger"}, + { color = ORANGE, name = BI["Ring"] .. " 2", icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Finger"}, + { color = ORANGE, name = BI["Trinket"] .. " 1", icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Trinket"}, + { color = ORANGE, name = BI["Trinket"] .. " 2", icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Trinket"}, + { color = "|cFFABD473", name = BI["Back"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Chest"}, + { color = "|cFFFFFF00", name = BI["Main Hand"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-MainHand"}, + { color = "|cFFFFFF00", name = BI["Off Hand"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-SecondaryHand"}, + { color = "|cFFABD473", name = BI["Ranged"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Ranged"}, + { color = WHITE, name = BI["Tabard"], icon = "Interface\\PaperDoll\\UI-PaperDoll-Slot-Tabard"} +} + +function ns:GetSlotTexture(slot) + return slotTypeInfo[slot].icon +end + +function ns:GetSlotName(slot) + return slotNames[slot] +end + +function ns:GetInventoryTypeIndex(inv) + return inventoryTypes[inv] +end + +function ns:GetInventoryTypeName(inv) + return slotNames[ inventoryTypes[inv] ] +end + +function ns:Update() + local VisibleLines = 7 + local frame = "AltoholicFrameEquipment" + local entry = frame.."Entry" + + AltoholicTabCharactersStatus:SetText("") + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local realm, account = addon:GetCurrentRealm() + local character + local DS = DataStore + + for i=1, VisibleLines do + local line = i + offset + local e = slotTypeInfo[line] + + _G[ entry..i.."Name" ]:SetText(e.color .. e.name) + + for j = 1, 10 do + local itemName = entry.. i .. "Item" .. j; + local itemButton = _G[itemName] + itemButton:SetScript("OnEnter", ns.OnEnter) + itemButton:SetScript("OnClick", ns.OnClick) + + local itemCount = _G[itemName .. "Count"] + itemCount:Hide(); + + addon:CreateButtonBorder(itemButton) + itemButton.border:Hide() + + local classButton = _G["AltoholicFrameClassesItem" .. j] + if classButton.CharName then + character = DS:GetCharacter(classButton.CharName, realm, account) + + local item = DS:GetInventoryItem(character, line) + if item then + itemButton.CharName = classButton.CharName + addon:SetItemButtonTexture(itemName, GetItemIcon(item)); + + -- display the coloured border + local _, _, itemRarity, itemLevel = GetItemInfo(item) + if itemRarity and itemRarity >= 2 then + local r, g, b = GetItemQualityColor(itemRarity) + itemButton.border:SetVertexColor(r, g, b, 0.5) + itemButton.border:Show() + end + + itemCount:SetText(itemLevel); + itemCount:Show(); + else + itemButton.CharName = nil + addon:SetItemButtonTexture(itemName, e.icon); + end + + itemButton:Show() + else + itemButton:Hide() + itemButton.CharName = nil + end + end + + _G[ entry..i ]:Show() + _G[ entry..i ]:SetID(line) + end + + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], 19, VisibleLines, 41); +end + +function ns:OnEnter() + if not self.CharName then return end + + local DS = DataStore + local realm, account = addon:GetCurrentRealm() + local character = DS:GetCharacter(self.CharName, realm, account) + local item = DS:GetInventoryItem(character, self:GetParent():GetID()) + if not item then return end + + GameTooltip:SetOwner(self, "ANCHOR_LEFT"); + local link + if type(item) == "number" then + link = select(2, GetItemInfo(item)) + else + link = item + end + + if not link then + GameTooltip:AddLine(L["Unknown link, please relog this character"],1,1,1); + GameTooltip:Show(); + return + end + + GameTooltip:SetHyperlink(link); + GameTooltip:AddLine(" "); + GameTooltip:AddLine(GREEN .. L["Right-Click to find an upgrade"]); + GameTooltip:Show(); +end + +function ns:OnClick(button) + if not self.CharName then return end + + local slotID = self:GetParent():GetID() + if slotID == 0 then return end -- class icon + + local DS = DataStore + local realm, account = addon:GetCurrentRealm() + local character = DS:GetCharacter(self.CharName, realm, account) + local item = DS:GetInventoryItem(character, slotID) + if not item then return end + + local link + if type(item) == "number" then + link = select(2, GetItemInfo(item)) + else + link = item + end + + if not link then return end + + if button == "RightButton" then + Altoholic.Search:SetCurrentItem( addon:GetIDFromLink(link) ) -- item ID of the item to find an upgrade for + local _, class = DS:GetCharacterClass(character) + Altoholic.Search:SetClass(class) + + ToggleDropDownMenu(1, nil, AltoholicFrameEquipmentRightClickMenu, self:GetName(), 0, -5); + return + end + + if ( button == "LeftButton" ) and ( IsControlKeyDown() ) then + DressUpItemLink(link); + elseif ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + chat:Insert(link); + else + AltoholicFrame_SearchEditBox:SetText(GetItemInfo(link)) + end + end +end + +function Equipment_RightClickMenu_OnLoad() + local info = UIDropDownMenu_CreateInfo(); + + info.text = format("%s %s", L["Find Upgrade"], GREEN .. L["(based on iLvl)"]) + info.value = -1 + info.func = Altoholic.Search.FindEquipmentUpgrade + UIDropDownMenu_AddButton(info, 1); + + local class = Altoholic.Search:GetClass() + + -- Tank upgrade + if (class == CLASS_WARRIOR) or + (class == CLASS_DRUID) or + (class == CLASS_DEATHKNIGHT) or + (class == CLASS_PALADIN) then + + info.text = format("%s %s(%s)", L["Find Upgrade"], GREEN, L["Tank"]) + info.value = class .. "Tank" + info.func = Altoholic.Search.FindEquipmentUpgrade + UIDropDownMenu_AddButton(info, 1); + end + + -- DPS upgrade + if class then + info.text = format("%s %s(%s)", L["Find Upgrade"], GREEN, L["DPS"]) + info.value = class .. "DPS" + info.func = Altoholic.Search.FindEquipmentUpgrade + UIDropDownMenu_AddButton(info, 1); + end + + if class == CLASS_DRUID then + info.text = format("%s %s(%s)", L["Find Upgrade"], GREEN, L["Balance"]) + info.value = class .. "Balance" + info.func = Altoholic.Search.FindEquipmentUpgrade + UIDropDownMenu_AddButton(info, 1); + elseif class == CLASS_SHAMAN then + info.text = format("%s %s(%s)", L["Find Upgrade"], GREEN, L["Elemental Shaman"]) + info.value = class .. "Elemental" + info.func = Altoholic.Search.FindEquipmentUpgrade + UIDropDownMenu_AddButton(info, 1); + end + + -- Heal upgrade + if (class == CLASS_PRIEST) or + (class == CLASS_SHAMAN) or + (class == CLASS_DRUID) or + (class == CLASS_PALADIN) then + + info.text = format("%s %s(%s)", L["Find Upgrade"], GREEN, L["Heal"]) + info.value = class .. "Heal" + info.func = Altoholic.Search.FindEquipmentUpgrade + UIDropDownMenu_AddButton(info, 1); + end + + -- Close menu item + info.text = CLOSE + info.func = function() CloseDropDownMenus() end + info.checked = nil + info.icon = nil + info.notCheckable = 1 + UIDropDownMenu_AddButton(info, 1) +end diff --git a/Altoholic-Addon/Altoholic/Frames/Equipment.xml b/Altoholic-Addon/Altoholic/Frames/Equipment.xml new file mode 100644 index 0000000..9c02118 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Equipment.xml @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 41, Altoholic.Equipment.Update) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/GuildBank.lua b/Altoholic-Addon/Altoholic/Frames/GuildBank.lua new file mode 100644 index 0000000..7c1ae18 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/GuildBank.lua @@ -0,0 +1,97 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +local NUM_GUILDBANK_ROWS = 7 + +addon.GuildBank = {} + +local ns = addon.GuildBank -- ns = namespace + +function ns:DrawTab(tabID) + local selectedGuild = UIDropDownMenu_GetSelectedValue(AltoholicTabGuildBank_SelectGuild) + if not selectedGuild then return end -- not defined yet ? exit. + + if not AltoGuildBank:IsVisible() then + AltoGuildBank:Show() + end + + local account, realm, guildName = strsplit("|", selectedGuild) + local guild = DataStore:GetGuild(guildName, realm, account) + + if not tabID then + -- will be nil when clicking on the guild bank tab for the first time, so find the first available one + -- called in OnShow (tabguildbank.xml) + for i=1, 6 do + if DataStore:GetGuildBankTabName(guild, i) then + tabID = i + + for i=1, 6 do + _G[ "AltoholicTabGuildBankMenuItem"..i ]:UnlockHighlight(); + end + _G[ "AltoholicTabGuildBankMenuItem"..tabID ]:LockHighlight(); + break + end + end + end + + if not tabID then return end -- no tab found ? exit + + local entry = "AltoGuildBankEntry" + local tab = DataStore:GetGuildBankTab(guild, tabID) + if not tab.name then -- tab not yet scanned ? exit + for rowIndex = 1, NUM_GUILDBANK_ROWS do + _G[ entry..rowIndex ]:Hide() + end + return + end + + AltoholicTabGuildBankInfo1:SetText(format(L["Last visit: %s by %s"], GREEN..tab.ClientDate..WHITE, GREEN..tab.visitedBy)) + local localTime, realmTime + localTime = format("%s%02d%s:%s%02d", GREEN, tab.ClientHour, WHITE, GREEN, tab.ClientMinute ) + realmTime = format("%s%02d%s:%s%02d", GREEN, tab.ServerHour, WHITE, GREEN, tab.ServerMinute ) + AltoholicTabGuildBankInfo2:SetText(format(L["Local Time: %s %sRealm Time: %s"], localTime, WHITE, realmTime)) + + for rowIndex = 1, NUM_GUILDBANK_ROWS do + + local from = mod(rowIndex, NUM_GUILDBANK_ROWS) + if from == 0 then from = NUM_GUILDBANK_ROWS end + + for columnIndex = 14, 1, -1 do + local itemName = entry..rowIndex .. "Item" .. columnIndex; + local itemButton = _G[itemName]; + + local itemIndex = from + ((columnIndex - 1) * NUM_GUILDBANK_ROWS) + + local itemID, itemLink, itemCount = DataStore:GetSlotInfo(tab, itemIndex) + + if itemID then + addon:SetItemButtonTexture(itemName, GetItemIcon(itemID)); + else + addon:SetItemButtonTexture(itemName, "Interface\\PaperDoll\\UI-Backpack-EmptySlot"); + end + + itemButton.id = itemID + itemButton.link = itemLink + itemButton:SetScript("OnEnter", function(self) + addon:Item_OnEnter(self) + end) + + local countWidget = _G[itemName .. "Count"] + if not itemCount or (itemCount < 2) then + countWidget:Hide(); + else + countWidget:SetText(itemCount); + countWidget:Show(); + end + + _G[ itemName ]:Show() + end + _G[ entry..rowIndex ]:Show() + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/GuildBank.xml b/Altoholic-Addon/Altoholic/Frames/GuildBank.xml new file mode 100644 index 0000000..6c7df52 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/GuildBank.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/GuildBankTabs.lua b/Altoholic-Addon/Altoholic/Frames/GuildBankTabs.lua new file mode 100644 index 0000000..165693c --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/GuildBankTabs.lua @@ -0,0 +1,236 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +--local GRAY = "|cFFBBBBBB" +local GRAY = "|cFF888888" +local GREEN = "|cFF00FF00" +local LIGHTBLUE = "|cFFB0B0FF" +local YELLOW = "|cFFFFFF00" + +local view +local isViewValid +local myClientTimes = {} -- small hash table containing the current player's client times, this allows quick comparison of client times among guild members. +local expandedHeaders = {} + +local TABINFO_LINE = 0 -- Bank tab info line +local CHAR_LINE = 1 -- Character line + +local function BuildView() + view = view or {} + wipe(view) + + local guild = DataStore:GetGuild() + if not guild then return end + + local line = 0 + for tabID = 1, 6 do + local tabName = DataStore:GetGuildBankTabName(guild, tabID) + if tabName then + table.insert(view, { lineType = line, id = tabID } ) -- insert an entry for the tab name + line = line + 1 + + for member in pairs(DataStore:GetGuildBankTabSuppliers()) do + local clientTime = DataStore:GetGuildMemberBankTabInfo(member, tabName) + if clientTime then -- if there's data, we can add this member in the view for the current bank tab + table.insert(view, { lineType = line, id = member, name = tabName } ) + end + end + line = line + 1 + end + end + + isViewValid = true +end + +local function DisplayClientTime(frame, color, clientTime) + if clientTime then + frame:SetText(color .. date("%m/%d/%Y %H:%M", clientTime)) + frame:Show() + else + frame:Hide() + end +end + +local function DisplayServerTime(frame, serverHour, serverMinute) + if serverHour and serverMinute then + frame:SetText(format("%s%02d%s:%s%02d", GREEN, serverHour, WHITE, GREEN, serverMinute )) + frame:Show() + else + frame:Hide() + end +end + +addon.Guild.BankTabs = {} + +local ns = addon.Guild.BankTabs -- ns = namespace + +function ns:Update() + if not isViewValid then + BuildView() + end + + local VisibleLines = 14 + local frame = "AltoholicFrameGuildBankTabs" + local entry = frame.."Entry" + + if #view == 0 then + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 18) + return + end + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local DisplayedCount = 0 + local VisibleCount = 0 + local DrawAlts + local i=1 + + local guild = DataStore:GetGuild() + + for line, v in pairs(view) do + local lineType = mod(v.lineType, 2) + + if (offset > 0) or (DisplayedCount >= VisibleLines) then -- if the line will not be visible + if lineType == TABINFO_LINE then -- then keep track of counters + if expandedHeaders[v.id] then + DrawAlts = true + else + DrawAlts = false + end + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif DrawAlts then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + end + else -- line will be displayed + + if lineType == TABINFO_LINE then + + if expandedHeaders[v.id] then + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + DrawAlts = true + else + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + DrawAlts = false + end + + local tabName = DataStore:GetGuildBankTabName(guild, v.id) + _G[entry..i.."Collapse"]:Show() + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 25, 0) + _G[entry..i.."NameNormalText"]:SetText(YELLOW..tabName) + + local clientTime, serverHour, serverMinute = DataStore:GetGuildMemberBankTabInfo(UnitName("player"), tabName) + myClientTimes[tabName] = clientTime + DisplayClientTime( _G[entry..i.."Client"], WHITE, clientTime) + DisplayServerTime( _G[entry..i.."Server"], serverHour, serverMinute) + _G[entry..i.."UpdateTab"]:Hide() + + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + elseif DrawAlts then + local member = v.id + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + _G[entry..i.."NameNormalText"]:SetText(LIGHTBLUE..member) + + local tabName = v.name + local clientTime, serverHour, serverMinute = DataStore:GetGuildMemberBankTabInfo(member, tabName) + + local color = GRAY + if myClientTimes[tabName] then + if clientTime > myClientTimes[tabName] then + color = YELLOW + end + end + + DisplayClientTime( _G[entry..i.."Client"], color, clientTime) + DisplayServerTime( _G[entry..i.."Server"], serverHour, serverMinute) + _G[entry..i.."UpdateTab"]:Show() + + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + end + end + end + + while i <= VisibleLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + i = i + 1 + end + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18); +end + +function ns:OnClick(self, button) + if button ~= "LeftButton" then return end + + local id = self:GetParent():GetID() + if id == 0 then return end + + local line = view[id] + local member = line.id + local tabName = line.name + + if member == UnitName("player") then return end -- do nothing if clicking on own alts + + addon:Print(format(L["Requesting %s information from %s"], tabName, member )) + DataStore:RequestGuildMemberBankTab(member, tabName) +end + +function ns:OnEnter(self) + local id = self:GetParent():GetID() + if id == 0 then return end + + local line = view[id] + local member = line.id + local tabName = line.name + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(self, "ANCHOR_RIGHT"); + + AltoTooltip:AddLine(L["Guild Bank Remote Update"]); + AltoTooltip:AddLine(format(L["Clicking this button will update\nyour local %s%s|r bank tab\nbased on %s%s's|r data"], LIGHTBLUE, line.name, YELLOW, line.id),1,1,1); + AltoTooltip:Show(); +end + +function ns:Collapse_OnClick(self) + local id = self:GetParent():GetID() + if id == 0 then return end + + local line = view[id] + if expandedHeaders[line.id] then -- toggle header + expandedHeaders[line.id] = nil + else + expandedHeaders[line.id] = true + end + ns:Update() +end + +function ns:ToggleView(self) + if self.isCollapsed then -- collapse all headers + wipe(expandedHeaders) + else -- expand all headers + for _, line in pairs(view) do + if mod(line.lineType, 2) == TABINFO_LINE then + expandedHeaders[line.id] = true + end + end + end + ns:Update() +end + +function ns:InvalidateView() + isViewValid = nil + if AltoholicFrameGuildBankTabs:IsVisible() then + ns:Update() + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/GuildBankTabs.xml b/Altoholic-Addon/Altoholic/Frames/GuildBankTabs.xml new file mode 100644 index 0000000..2dd2070 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/GuildBankTabs.xml @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Guild.BankTabs.Update) + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/GuildMembers.lua b/Altoholic-Addon/Altoholic/Frames/GuildMembers.lua new file mode 100644 index 0000000..082e5df --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/GuildMembers.lua @@ -0,0 +1,538 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local GRAY = "|cFFBBBBBB" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" +local LIGHTBLUE = "|cFFB0B0FF" + +local view +local viewSortField = "name" +local viewSortOrder +local isViewValid +local expandedHeaders = {} + +local PrimaryLevelSort = { -- sort functions for the mains + ["name"] = function(a, b) + if viewSortOrder then + return a.name < b.name + else + return a.name > b.name + end + end, + ["level"] = function(a, b) + local levelA = select(4, DataStore:GetGuildMemberInfo(a.name)) + local levelB = select(4, DataStore:GetGuildMemberInfo(b.name)) + + levelA = levelA or 0 + levelB = levelB or 0 + + if viewSortOrder then + return levelA < levelB + else + return levelA > levelB + end + end, + ["averageItemLvl"] = function(a, b) + local guild = DataStore:GetGuild() + local ailA = DataStore:GetGuildMemberAverageItemLevel(guild, a.name) or 0 + local ailB = DataStore:GetGuildMemberAverageItemLevel(guild, b.name) or 0 + + if viewSortOrder then + return ailA < ailB + else + return ailA > ailB + end + end, + ["version"] = function(a, b) + local versionA = addon:GetGuildMemberVersion(a.name) or "" + local versionB = addon:GetGuildMemberVersion(b.name) or "" + + if viewSortOrder then + return versionA < versionB + else + return versionA > versionB + end + end, + ["englishClass"] = function(a, b) + local classA = select(11, DataStore:GetGuildMemberInfo(a.name)) + local classB = select(11, DataStore:GetGuildMemberInfo(b.name)) + + classA = classA or "" + classB = classB or "" + + if viewSortOrder then + return classA < classB + else + return classA > classB + end + end, +} + +local SecondaryLevelSort = {-- sort functions for the alts + ["name"] = function(a, b) + if viewSortOrder then + return a < b + else + return a > b + end + end, + ["level"] = function(a, b) + local levelA = select(4, DataStore:GetGuildMemberInfo(a)) + local levelB = select(4, DataStore:GetGuildMemberInfo(b)) + + if viewSortOrder then + return levelA < levelB + else + return levelA > levelB + end + end, + ["averageItemLvl"] = function(a, b) + local guild = DataStore:GetGuild() + local ailA = DataStore:GetGuildMemberAverageItemLevel(guild, a) or 0 + local ailB = DataStore:GetGuildMemberAverageItemLevel(guild, b) or 0 + + if viewSortOrder then + return ailA < ailB + else + return ailA > ailB + end + end, + ["version"] = function(a, b) + local versionA = addon:GetGuildMemberVersion(a) or "" + local versionB = addon:GetGuildMemberVersion(b) or "" + + if viewSortOrder then + return versionA < versionB + else + return versionA > versionB + end + end, + ["englishClass"] = function(a, b) + local classA = select(11, DataStore:GetGuildMemberInfo(a)) + local classB = select(11, DataStore:GetGuildMemberInfo(b)) + + classA = classA or "" + classB = classB or "" + + if viewSortOrder then + return classA < classB + else + return classA > classB + end + end, +} + +-- *** Utility functions *** + +local NORMALPLAYER_LINE = 0 -- a guild mate who does not use altoholic +local ALTO_MAIN_LINE = 2 -- the currently connected character of a guild mate using altoholic +local ALTO_ALT_LINE = 3 -- an alt belonging to the previous line +local OFFLINEHEADER_LINE = 4 +local OFFLINEMEMBER_LINE = 5 + +local HEADER_LINE = 0 -- line number modulo 2 = 0, it's a header + +local function BuildView() + + view = view or {} + wipe(view) + + local onlineMembers = {} -- list of online guild members (and their alts) + + -- 1) Start by adding mains, users of altoholic or not + for member in pairs(DataStore:GetOnlineGuildMembers()) do + if addon:GetGuildMemberVersion(member) then -- altoholic user + table.insert(view, { lineType = ALTO_MAIN_LINE, name = member } ) -- main character first + else -- non altoholic user + table.insert(view, { lineType = NORMALPLAYER_LINE, name = member } ) + end + onlineMembers[member] = true + end + + -- 2) sort the highest level + table.sort(view, PrimaryLevelSort[viewSortField]) + + -- 3) add the alts whenver applicable + for index, line in ipairs(view) do + if line.lineType == ALTO_MAIN_LINE then + local alts = DataStore:GetGuildMemberAlts(line.name) + if alts then + local altsTable = { strsplit("|", alts) } + + -- 4) sort the alts on the same criteria + table.sort(altsTable, SecondaryLevelSort[viewSortField]) + + local altCount = 1 -- because the insert must be done at index+1 for alt 1, index+2 for alt2, etc.. + for _, altName in ipairs(altsTable) do + table.insert(view, index + altCount, { lineType = ALTO_ALT_LINE, name = altName } ) + onlineMembers[altName] = true + altCount = altCount + 1 + end + end + end + end + + -- 5) add the header "offline members" + table.insert(view, { lineType = OFFLINEHEADER_LINE, name = L["Offline Members"] } ) + + -- 6) Prepare the list of offline members for which we have data, sort it, then add it to the view + local offlineMembers = {} + + local guild = DataStore:GetGuild() + + for i=1, GetNumGuildMembers(true) do -- browse all players (online & offline) + local member = GetGuildRosterInfo(i) + if not onlineMembers[member] then + offlineMembers[ #offlineMembers + 1 ] = member + end + end + + table.sort(offlineMembers, SecondaryLevelSort[viewSortField]) + + for _, member in ipairs(offlineMembers) do + table.insert(view, { lineType = OFFLINEMEMBER_LINE, name = member } ) + end + + isViewValid = true +end + +local EquipmentToFrame = { 1,3,5,9,10,6,7,8,11,12,13,14,15,4,2,19,16,17,18 } + +local function LoadEquipmentTextures() + local itemName + + for i = 1, 19 do + itemName = "AltoholicFrameGuildMembersItem".. i; + addon:SetItemButtonTexture(itemName, addon.Equipment:GetSlotTexture(EquipmentToFrame[i])); + _G[itemName]:Show() + end +end + +local function UpdateEquipment(member) +--[[ + button layout equipment table layout + + 1 5 9 1 10 11 + 2 6 10 3 6 12 + 3 7 11 5 7 13 + 4 8 12 9 8 14 + + 15 13 14 16 2 15 4 19 + + 17 18 19 16 17 18 +--]] + + local itemName, itemButton, itemCount + local guild = DataStore:GetGuild() + + for i = 1, 19 do + itemName = "AltoholicFrameGuildMembersItem".. i; + itemButton = _G[itemName]; + itemCount = _G[itemName .. "Count"] + itemCount:Hide(); + + addon:CreateButtonBorder(itemButton) + itemButton.border:Hide() + + local itemID = DataStore:GetGuildMemberInventoryItem(guild, member, EquipmentToFrame[i]) + if itemID then + addon:SetItemButtonTexture(itemName, GetItemIcon(itemID)); + + -- set link and id for addon:Item_OnEnter(self) + if type(itemID) == "string" then + itemButton.link = itemID + itemButton.id = addon:GetIDFromLink(itemID) + elseif type(itemID) == "number" then + itemButton.id = itemID + itemButton.link = nil + end + + -- display the coloured border + local _, _, itemRarity, itemLevel = GetItemInfo(itemID) + if itemRarity and itemRarity >= 2 then + local r, g, b = GetItemQualityColor(itemRarity) + itemButton.border:SetVertexColor(r, g, b, 0.5) + itemButton.border:Show() + end + + itemCount:SetText(itemLevel); + itemCount:Show(); + else + addon:SetItemButtonTexture(itemName, addon.Equipment:GetSlotTexture(EquipmentToFrame[i])); + itemButton.id = nil + itemButton.link = nil + end + + itemButton:Show() + end +end + +addon.Guild.Members = {} + +local ns = addon.Guild.Members -- ns = namespace + +function ns:Update() + if AltoholicFrameGuildMembers.InitRequired then + LoadEquipmentTextures() + AltoholicFrameGuildMembers.InitRequired = nil + end + + if not isViewValid then + BuildView() + end + + local VisibleLines = 14 + local frame = "AltoholicFrameGuildMembers" + local entry = frame.."Entry" + + AltoholicTabSummaryStatus:SetText(L["Click a character's AiL to see its equipment"]) + + if #view == 0 then + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 18) + return + end + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local DisplayedCount = 0 + local VisibleCount = 0 + local DrawAlts + local i=1 + + local guild = DataStore:GetGuild() + + for lineIndex, v in pairs(view) do + local lineType = mod(v.lineType, 2) + + if (offset > 0) or (DisplayedCount >= VisibleLines) then -- if the line will not be visible + if v.lineType == NORMALPLAYER_LINE then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif lineType == HEADER_LINE then -- then keep track of counters + if expandedHeaders[v.name] then + DrawAlts = true + else + DrawAlts = false + end + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif DrawAlts then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + end + else -- line will be displayed + local member = v.name + local _, _, _, level, class, _, _, _, _, _, englishClass = DataStore:GetGuildMemberInfo(member) + level = level or 0 + + local classText = L["N/A"] + if class and englishClass then + classText = format("%s%s", addon:GetClassColor(englishClass), class) + end + + local version = addon:GetGuildMemberVersion(member) or L["N/A"] + local averageItemLvl = DataStore:GetGuildMemberAverageItemLevel(guild, member) or 0 + + if v.lineType == NORMALPLAYER_LINE then + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + _G[entry..i.."NameNormalText"]:SetText(YELLOW..member) + _G[entry..i.."Level"]:SetText(GREEN .. level) + _G[entry..i.."AvgILevelNormalText"]:SetText(YELLOW..format("%.1f", averageItemLvl)) + _G[entry..i.."Version"]:SetText(WHITE..version) + _G[entry..i.."Class"]:SetText(classText) + + _G[ entry..i ].CharName = member + _G[ entry..i ]:SetID(lineIndex) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + + elseif lineType == HEADER_LINE then + if expandedHeaders[member] then + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + DrawAlts = true + else + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + DrawAlts = false + end + + if member == L["Offline Members"] then + level = "" + version = "" + classText = "" + end + + _G[entry..i.."Collapse"]:Show() + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 25, 0) + _G[entry..i.."NameNormalText"]:SetText(YELLOW..member) + _G[entry..i.."Level"]:SetText(GREEN .. level) + if member == L["Offline Members"] then + _G[entry..i.."AvgILevelNormalText"]:SetText("") + else + _G[entry..i.."AvgILevelNormalText"]:SetText(YELLOW..format("%.1f", averageItemLvl)) + end + + _G[entry..i.."Version"]:SetText(WHITE..version) + _G[entry..i.."Class"]:SetText(classText) + + _G[ entry..i ].CharName = member + _G[ entry..i ]:SetID(lineIndex) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + + elseif DrawAlts then + + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + if v.lineType == ALTO_ALT_LINE then + _G[entry..i.."NameNormalText"]:SetText(LIGHTBLUE..member) + else + _G[entry..i.."NameNormalText"]:SetText(GRAY..member) + end + _G[entry..i.."Level"]:SetText(GREEN .. level) + _G[entry..i.."AvgILevelNormalText"]:SetText(YELLOW..format("%.1f", averageItemLvl)) + _G[entry..i.."Version"]:SetText(WHITE..version) + _G[entry..i.."Class"]:SetText(classText) + + _G[ entry..i ].CharName = member + _G[ entry..i ]:SetID(lineIndex) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + end + end + end + + while i <= VisibleLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + i = i + 1 + end + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18); +end + +function ns:Sort(self, field) + viewSortField = field + viewSortOrder = self.ascendingSort + + ns:InvalidateView() +end + +function ns:Name_OnEnter(self) + local member = self:GetParent().CharName + if not member then return end + + local name, rank, rankIndex, _, _, zone, note, officernote, _, _, englishClass = DataStore:GetGuildMemberInfo(member) + if name ~= member then return end + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(self, "ANCHOR_RIGHT"); + AltoTooltip:AddLine(addon:GetClassColor(englishClass) .. member,1,1,1); + AltoTooltip:AddLine(WHITE .. RANK_COLON .. "|r " .. rank .. GREEN .. " (".. rankIndex .. ")"); + if zone then + AltoTooltip:AddLine(WHITE .. ZONE_COLON .. "|r " .. zone); + end + + if note then + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(WHITE .. NOTE .. ":"); + AltoTooltip:AddLine(note); + end + + if officernote then + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(WHITE .. GUILD_OFFICER_NOTE .. ":"); + AltoTooltip:AddLine(officernote); + end + + AltoTooltip:Show(); +end + +function ns:Level_OnClick(self, button) + if button ~= "LeftButton" then return end + + local id = self:GetParent():GetID() + local line = view[id] + if line.lineType == NORMALPLAYER_LINE then return end + + local member = self:GetParent().CharName + if member then + DataStore:RequestGuildMemberEquipment(member) + AltoholicFrameGuildMembers_Name:SetText(member) + end +end + +function ns:Level_OnEnter(self) + local id = self:GetParent():GetID() + if id == 0 then return end + + local line = view[id] + local member = line.name + local _, _, _, _, _, _, _, _, _, _, englishClass = DataStore:GetGuildMemberInfo(member) + local guild = DataStore:GetGuild() + local averageItemLvl = DataStore:GetGuildMemberAverageItemLevel(guild, member) or 0 + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(self, "ANCHOR_RIGHT"); + AltoTooltip:AddLine(addon:GetClassColor(englishClass) .. member,1,1,1); + AltoTooltip:AddLine(WHITE .. L["Average Item Level"] ..": " .. GREEN.. format("%.1f", averageItemLvl),1,1,1); + + addon:AiLTooltip() + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(GREEN .. L["Left-click to see this character's equipment"],1,1,1); + AltoTooltip:Show(); +end + +function ns:Collapse_OnClick(self) + local id = self:GetParent():GetID() + if id == 0 then return end + + local line = view[id] + if expandedHeaders[line.name] then -- toggle header + expandedHeaders[line.name] = nil + else + expandedHeaders[line.name] = true + end + ns:Update() +end + +function ns:ToggleView(frame) + if frame.isCollapsed then -- collapse all headers + wipe(expandedHeaders) + else -- expand all headers + for _, line in pairs(view) do + if mod(line.lineType, 2) == HEADER_LINE then + expandedHeaders[line.name] = true + end + end + end + ns:Update() +end + +function ns:InvalidateView() + isViewValid = nil + if AltoholicFrameGuildMembers:IsVisible() then + ns:Update() + end +end + +function ns:OnRosterUpdate() + AltoholicTabSummaryMenuItem5:SetText(format("%s %s(%d)", L["Guild Members"], GREEN, GetNumGuildMembers())) + + ns:InvalidateView() + addon.Guild.Professions:InvalidateView() + addon.Guild.BankTabs:InvalidateView() +-- addon.Tabs.Summary:Refresh() +end + +function addon:DATASTORE_PLAYER_EQUIPMENT_RECEIVED(event, sender, character) + UpdateEquipment(character) +end diff --git a/Altoholic-Addon/Altoholic/Frames/GuildMembers.xml b/Altoholic-Addon/Altoholic/Frames/GuildMembers.xml new file mode 100644 index 0000000..d416eb3 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/GuildMembers.xml @@ -0,0 +1,491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + self.InitRequired = true + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Guild.Members.Update) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/GuildProfessions.lua b/Altoholic-Addon/Altoholic/Frames/GuildProfessions.lua new file mode 100644 index 0000000..f83d6ae --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/GuildProfessions.lua @@ -0,0 +1,424 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local GRAY = "|cFFBBBBBB" +local GREEN = "|cFF00FF00" +local LIGHTBLUE = "|cFFB0B0FF" +local YELLOW = "|cFFFFFF00" + +local view +local viewSortField = "name" +local viewSortOrder +local viewSortArg1 +local isViewValid +local expandedHeaders = {} + +local PrimaryLevelSort = { -- sort functions for the mains + ["name"] = function(a, b) + if viewSortOrder then + return a.name < b.name + else + return a.name > b.name + end + end, + ["level"] = function(a, b) + local levelA = select(4, DataStore:GetGuildMemberInfo(a.name)) + local levelB = select(4, DataStore:GetGuildMemberInfo(b.name)) + + if viewSortOrder then + return levelA < levelB + else + return levelA > levelB + end + end, + ["englishClass"] = function(a, b) + local classA = select(11, DataStore:GetGuildMemberInfo(a.name)) + local classB = select(11, DataStore:GetGuildMemberInfo(b.name)) + + classA = classA or "" + classB = classB or "" + + if viewSortOrder then + return classA < classB + else + return classA > classB + end + end, + ["profLink"] = function(a, b) + local guild = DataStore:GetGuild() + local link + + _, link = DataStore:GetGuildMemberProfession(guild, a.name, viewSortArg1) + local levelA = DataStore:GetProfessionInfo(link) + _, link = DataStore:GetGuildMemberProfession(guild, b.name, viewSortArg1) + local levelB = DataStore:GetProfessionInfo(link) + + levelA = levelA or 0 + levelB = levelB or 0 + + if viewSortOrder then + return levelA < levelB + else + return levelA > levelB + end + end, +} + +local SecondaryLevelSort = {-- sort functions for the alts + ["name"] = function(a, b) + if viewSortOrder then + return a < b + else + return a > b + end + end, + ["level"] = function(a, b) + local levelA = select(4, DataStore:GetGuildMemberInfo(a)) + local levelB = select(4, DataStore:GetGuildMemberInfo(b)) + + if viewSortOrder then + return levelA < levelB + else + return levelA > levelB + end + end, + ["englishClass"] = function(a, b) + local classA = select(11, DataStore:GetGuildMemberInfo(a)) + local classB = select(11, DataStore:GetGuildMemberInfo(b)) + + classA = classA or "" + classB = classB or "" + + if viewSortOrder then + return classA < classB + else + return classA > classB + end + end, + ["profLink"] = function(a, b) + local guild = DataStore:GetGuild() + local link + + _, link = DataStore:GetGuildMemberProfession(guild, a, viewSortArg1) + local levelA = DataStore:GetProfessionInfo(link) + _, link = DataStore:GetGuildMemberProfession(guild, b, viewSortArg1) + local levelB = DataStore:GetProfessionInfo(link) + + levelA = levelA or 0 + levelB = levelB or 0 + + if viewSortOrder then + return levelA < levelB + else + return levelA > levelB + end + end, +} + +local ALTO_MAIN_LINE = 0 -- the currently connected character of a guild mate using altoholic +local ALTO_ALT_LINE = 1 -- an alt belonging to the previous line +local OFFLINEHEADER_LINE = 2 +local OFFLINEMEMBER_LINE = 3 + +local HEADER_LINE = 0 -- line number modulo 2 = 0, it's a header + +local function BuildView() + view = view or {} + wipe(view) + + local altoOnlineMembers = {} -- list of online guild members for which we have professions + + -- 1) Start by adding mains, users of altoholic only + for member in pairs(DataStore:GetOnlineGuildMembers()) do + if addon:GetGuildMemberVersion(member) then -- altoholic user + table.insert(view, { lineType = ALTO_MAIN_LINE, name = member } ) -- main character first + altoOnlineMembers[member] = true + end + end + + -- 2) sort the highest level + table.sort(view, PrimaryLevelSort[viewSortField]) + + -- 3) add the alts whenver applicable + for index, line in ipairs(view) do + if line.lineType == ALTO_MAIN_LINE then + local alts = DataStore:GetGuildMemberAlts(line.name) + if alts then + local altsTable = { strsplit("|", alts) } + + -- 4) sort the alts on the same criteria + table.sort(altsTable, SecondaryLevelSort[viewSortField]) + + local altCount = 1 -- because the insert must be done at index+1 for alt 1, index+2 for alt2, etc.. + for _, altName in ipairs(altsTable) do + table.insert(view, index + altCount, { lineType = ALTO_ALT_LINE, name = altName } ) + altoOnlineMembers[altName] = true + altCount = altCount + 1 + end + end + end + end + + -- 5) add the header "offline members" + table.insert(view, { lineType = OFFLINEHEADER_LINE, name = L["Offline Members"] } ) + + -- 6) Prepare the list of offline members for which we have data, sort it, then add it to the view + local offlineMembers = {} + + local guild = DataStore:GetGuild() + for member, crafts in pairs(DataStore:GetGuildCrafters(guild)) do + if not altoOnlineMembers[member] then + offlineMembers[ #offlineMembers + 1 ] = member + end + end + + table.sort(offlineMembers, SecondaryLevelSort[viewSortField]) + + for _, member in ipairs(offlineMembers) do + table.insert(view, { lineType = OFFLINEMEMBER_LINE, name = member } ) + end + + isViewValid = true +end + +local function DisplayProfessionLink(frameName, member, index) + local frame = _G[frameName] + if not member then + frame:Hide() + return + end + + local text = _G[frameName.."NormalText"] + local guild = DataStore:GetGuild() + local spellID, link = DataStore:GetGuildMemberProfession(guild, member, index) + + if spellID then + local icon = addon:TextureToFontstring(addon:GetSpellIcon(tonumber(spellID)), 18, 18) .. " " + if link then + local curRank, maxRank = DataStore:GetProfessionInfo(link) + local ts = addon.TradeSkills + text:SetText(icon .. ts:GetColor(curRank) .. curRank .. "/" .. maxRank) + else + local spellName = GetSpellInfo(spellID) + text:SetText(WHITE..spellName) + end + frame:Show() + else + frame:Hide() + end +end + +addon.Guild.Professions = {} + +local ns = addon.Guild.Professions -- ns = namespace + +function ns:Update() + if not isViewValid then + BuildView() + end + + local VisibleLines = 14 + local frame = "AltoholicFrameGuildProfessions" + local entry = frame.."Entry" + + if #view == 0 then + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 18) + return + end + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local DisplayedCount = 0 + local VisibleCount = 0 + local DrawAlts + local i=1 + + for lineIndex, v in pairs(view) do + local lineType = mod(v.lineType, 2) + + if (offset > 0) or (DisplayedCount >= VisibleLines) then -- if the line will not be visible + if lineType == HEADER_LINE then -- then keep track of counters + if expandedHeaders[v.name] then + DrawAlts = true + else + DrawAlts = false + end + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif DrawAlts then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + end + else -- line will be displayed + local member = v.name + local _, _, _, level, class, _, _, _, _, _, englishClass = DataStore:GetGuildMemberInfo(member) + level = level or 0 + + local classText = L["N/A"] + if class and englishClass then + classText = format("%s%s", addon:GetClassColor(englishClass), class) + end + + if lineType == HEADER_LINE then + if expandedHeaders[v.name] then + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + DrawAlts = true + else + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + DrawAlts = false + end + _G[entry..i.."Collapse"]:Show() + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 25, 0) + + _G[entry..i.."NameNormalText"]:SetText(YELLOW..member) + + if member == L["Offline Members"] then + level = "" + end + _G[entry..i.."Level"]:SetText(GREEN .. level) + + if v.lineType == ALTO_MAIN_LINE then + _G[entry..i.."Class"]:SetText(classText) + + for index = 1, 3 do + DisplayProfessionLink( entry..i.."Skill"..index, member, index ) + end + else + _G[entry..i.."Class"]:SetText("") + for index = 1, 3 do + DisplayProfessionLink( entry..i.."Skill"..index) + end + end + + _G[ entry..i ].CharName = member + _G[ entry..i ]:SetID(lineIndex) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + elseif DrawAlts then + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + _G[entry..i.."Level"]:SetText(GREEN .. level) + _G[entry..i.."Class"]:SetText(classText) + + if v.lineType == ALTO_ALT_LINE then + _G[entry..i.."NameNormalText"]:SetText(LIGHTBLUE..member) + else + _G[entry..i.."NameNormalText"]:SetText(GRAY..member) + end + + for index = 1, 3 do + DisplayProfessionLink( entry..i.."Skill"..index, member, index ) + end + + _G[ entry..i ].CharName = member + _G[ entry..i ]:SetID(lineIndex) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + end + end + end + + while i <= VisibleLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + i = i + 1 + end + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18); +end + +function ns:Sort(self, field, index) + viewSortField = field + viewSortOrder = self.ascendingSort + viewSortArg1 = index -- arg 1 = index of the profession, to use the same function for all + + ns:InvalidateView() +end + +function ns:OnEnter(self) + local member = self:GetParent().CharName + if not member then return end + + local id = self:GetID() -- id of the button that was clicked + local guild = DataStore:GetGuild() + local spellID, link, lastUpdate = DataStore:GetGuildMemberProfession(guild, member, id) + if not spellID or not link then return end + + local curRank, maxRank = DataStore:GetProfessionInfo(link) + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(self, "ANCHOR_RIGHT"); + + local _, _, _, _, _, _, _, _, _, _, englishClass = DataStore:GetGuildMemberInfo(member) + AltoTooltip:AddLine(addon:GetClassColor(englishClass) .. member,1,1,1); + + local skillName = GetSpellInfo(spellID) + AltoTooltip:AddLine(skillName,1,1,1); + + local ts = addon.TradeSkills + AltoTooltip:AddLine(ts:GetColor(curRank) .. curRank .. "/" .. maxRank,1,1,1); + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(date("%m/%d/%Y %H:%M", lastUpdate),1,1,1); + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(GREEN..L["Left click to view"],1,1,1); + AltoTooltip:AddLine(GREEN..L["Shift+Left click to link"],1,1,1); + + AltoTooltip:Show(); +end + +function ns:OnClick(self, button) + if button ~= "LeftButton" then return end + + local member = self:GetParent().CharName + if not member then return end + + local id = self:GetID() -- id of the button that was clicked + local guild = DataStore:GetGuild() + local _, link = DataStore:GetGuildMemberProfession(guild, member, id) + if not link then return end + + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() and IsShiftKeyDown() then + chat:Insert(link); + else + SetItemRef(link:match("|H([^|]+)"), "Profession", "LeftButton") + end +end + +function ns:Collapse_OnClick(self) + local id = self:GetParent():GetID() + if id == 0 then return end + + local line = view[id] + if expandedHeaders[line.name] then -- toggle header + expandedHeaders[line.name] = nil + else + expandedHeaders[line.name] = true + end + ns:Update() +end + +function ns:ToggleView(self) + if self.isCollapsed then -- collapse all headers + wipe(expandedHeaders) + else -- expand all headers + for _, line in pairs(view) do + if mod(line.lineType, 2) == HEADER_LINE then + expandedHeaders[line.name] = true + end + end + end + ns:Update() +end + +function ns:InvalidateView() + isViewValid = nil + if AltoholicFrameGuildProfessions:IsVisible() then + ns:Update() + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/GuildProfessions.xml b/Altoholic-Addon/Altoholic/Frames/GuildProfessions.xml new file mode 100644 index 0000000..2c6f2de --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/GuildProfessions.xml @@ -0,0 +1,276 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Guild.Professions.Update) + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Mails.lua b/Altoholic-Addon/Altoholic/Frames/Mails.lua new file mode 100644 index 0000000..ab9401d --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Mails.lua @@ -0,0 +1,253 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" +local RED = "|cFFFF0000" +local TEAL = "|cFF00FF9A" + +addon.Mail = {} + +local ns = addon.Mail -- ns = namespace + +local function SortByName(a, b, ascending) + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + + local textA = DS:GetMailSubject(character, a) or "" + local textB = DS:GetMailSubject(character, b) or "" + + if ascending then + return textA < textB + else + return textA > textB + end +end + +local function SortBySender(a, b, ascending) + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + + local senderA = DS:GetMailSender(character, a) + local senderB = DS:GetMailSender(character, b) + + if ascending then + return senderA < senderB + else + return senderA > senderB + end +end + +local function SortByExpiry(a, b, ascending) + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + + local _, expiryA = DS:GetMailExpiry(character, a) + local _, expiryB = DS:GetMailExpiry(character, b) + + if ascending then + return expiryA < expiryB + else + return expiryA > expiryB + end +end + +function ns:BuildView(field, ascending) + + field = field or "expiry" + + self.view = self.view or {} + wipe(self.view) + + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + if not character then return end + + local numMails = DS:GetNumMails(character) or 0 + for i = 1, numMails do + table.insert(self.view, i) + end + + if field == "name" then + table.sort(self.view, function(a, b) return SortByName(a, b, ascending) end) + elseif field == "from" then + table.sort(self.view, function(a, b) return SortBySender(a, b, ascending) end) + elseif field == "expiry" then + table.sort(self.view, function(a, b) return SortByExpiry(a, b, ascending) end) + end +end + +function ns:Update() + local VisibleLines = 7 + local frame = "AltoholicFrameMail" + local entry = frame.."Entry" + local player = addon:GetCurrentCharacter() + + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local lastVisit = DS:GetMailboxLastVisit(character) + + if lastVisit ~= 0 then + local localDate = format(L["Last visit: %s by %s"], GREEN..date("%m/%d/%Y", lastVisit)..WHITE, GREEN..player) + AltoholicFrameMailInfo1:SetText(localDate .. WHITE .. " @ " .. date("%H:%M", lastVisit)) + AltoholicFrameMailInfo1:Show() + else + -- never visited the mailbox + AltoholicFrameMailInfo1:Hide() + end + + local numMails = DS:GetNumMails(character) or 0 + if numMails == 0 then + AltoholicTabCharactersStatus:SetText(format(L["%s has no mail"], player)) + -- make sure the scroll frame is cleared ! + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 41) + return + else + AltoholicTabCharactersStatus:SetText("") + end + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + + for i=1, VisibleLines do + local line = i + offset + if line <= numMails then + local index = ns.view[line] + + local icon, count, link, _, _, wasReturned = DS:GetMailInfo(character, index) + + _G[ entry..i.."Name" ]:SetText(link or DS:GetMailSubject(character, index)) + _G[ entry..i.."Character" ]:SetText(DS:GetMailSender(character, index)) + + local msg + if not wasReturned then + msg = format(L["Will be %sreturned|r in"], GREEN, WHITE) + else + msg = format(L["Will be %sdeleted|r in"], RED, WHITE) + end + + local _, seconds = DataStore:GetMailExpiry(character, index) + _G[ entry..i.."Expiry" ]:SetText(format("%s:\n%s", msg, WHITE .. SecondsToTime(seconds))) + + _G[ entry..i.."ItemIconTexture" ]:SetTexture(icon); + if count and count > 1 then + _G[ entry..i.."ItemCount" ]:SetText(count) + _G[ entry..i.."ItemCount" ]:Show() + else + _G[ entry..i.."ItemCount" ]:Hide() + end + -- trick: pass the index of the current item in the results table, required for the tooltip + _G[ entry..i.."Item" ]:SetID(index) + _G[ entry..i ]:Show() + else + _G[ entry..i ]:Hide() + end + end + + if numMails < VisibleLines then + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleLines, VisibleLines, 41); + else + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], numMails, VisibleLines, 41); + end +end + +function ns:Sort(self, field) + ns:BuildView(field, self.ascendingSort) + ns:Update() +end + +function ns:OnEnter(self) + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local index = self:GetID() + local _, _, link, money, text = DS:GetMailInfo(character, index) + + if link then + GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); + GameTooltip:SetHyperlink(link); + GameTooltip:Show(); + else + GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); + GameTooltip:ClearLines(); + + local subject = DS:GetMailSubject(character, index) + if subject then + GameTooltip:AddLine("|cFFFFFFFF" .. subject,1,1,1); + end + if text then + GameTooltip:AddLine("|cFFFFD700" .. text, 1, 1, 1, 1, 1); + end + if money > 0 then + GameTooltip:AddLine("|rAttached Money: " .. addon:GetMoneyString(money),1,1,1); + end + GameTooltip:Show(); + end +end + +function ns:OnClick(self, button) + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local index = self:GetID() + local _, _, link = DS:GetMailInfo(character, index) + + if link then + if ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + chat:Insert(link); + end + end + end +end + +function addon:DATASTORE_GLOBAL_MAIL_EXPIRY(event, threshold) + -- at least one mail has expired + + AltoMsgBox:SetHeight(130) + AltoMsgBox_Text:SetHeight(60) + addon:SetMsgBoxHandler(function(self, button) + if button then + addon:ToggleUI() + addon.Tabs.Summary:MenuItem_OnClick(4) + end + end) + + AltoMsgBox_Text:SetText(format("%sAltoholic: %s%s", TEAL, WHITE, + "\n" .. L["Mail is about to expire on at least one character."] .. "\n" + .. L["Refer to the activity pane for more details."].. "\n\n") + .. L["Do you want to view it now ?"]) + AltoMsgBox:Show() +end + +function addon:DATASTORE_MAIL_EXPIRY(event, character, key, threshold, numExpiredMails) + -- if option then + -- local _, _, name = strsplit(".", key) + -- addon:Print(format("%d mails will expire in less than %d days on %s", numExpiredMails, threshold, name) + -- end +end + +-- *** Hooks *** +local Orig_SendMailNameEditBox_OnChar = SendMailNameEditBox:GetScript("OnChar") + +SendMailNameEditBox:SetScript("OnChar", function(...) + if addon.Options:Get("NameAutoComplete") == 1 then + local text = this:GetText(); + local textlen = strlen(text); + + for characterName, character in pairs(DataStore:GetCharacters()) do + if DataStore:GetCharacterFaction(character) == UnitFactionGroup("player") then + if ( strfind(strupper(characterName), strupper(text), 1, 1) == 1 ) then + SendMailNameEditBox:SetText(characterName); + SendMailNameEditBox:HighlightText(textlen, -1); + return; + end + end + end + end + + if Orig_SendMailNameEditBox_OnChar then + return Orig_SendMailNameEditBox_OnChar(...) + end +end) diff --git a/Altoholic-Addon/Altoholic/Frames/Mails.xml b/Altoholic-Addon/Altoholic/Frames/Mails.xml new file mode 100644 index 0000000..2ba22ce --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Mails.xml @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Pets.lua b/Altoholic-Addon/Altoholic/Frames/Pets.lua new file mode 100644 index 0000000..89f9b50 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Pets.lua @@ -0,0 +1,306 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local PETS_PER_PAGE = 12 + +local selectedID +local currentPetType +local currentPage +local currentPetName + +addon.Pets = {} + +local ns = addon.Pets -- ns = namespace + +function ns:OnEnter(frame) + local id = frame.spellID + if id then + AltoTooltip:SetOwner(frame, "ANCHOR_LEFT"); + AltoTooltip:ClearLines(); + AltoTooltip:SetHyperlink("spell:" ..id); + AltoTooltip:Show(); + end +end + +function ns:OnClick(frame, button) + if frame.spellID and ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + local link = DataStore:GetCompanionLink(frame.spellID) + if link then + chat:Insert(link) + end + end + end + + frame:SetChecked(true); + + local offset = (currentPage-1) * PETS_PER_PAGE + selectedID = offset + frame:GetID() + ns:UpdatePets() +end + +local function OnChangePetView(self) + local value = self.value + + UIDropDownMenu_SetSelectedValue(AltoholicFramePets_SelectPetView, value); + + if value == 1 or value == 3 then + AltoholicFrameClasses:Hide() + AltoholicFramePetsNormal:Show() + AltoholicFramePetsAllInOne:Hide() + else + AltoholicFrameClasses:Show() + AltoholicFramePetsNormal:Hide() + AltoholicFramePetsAllInOne:Show() + end + + AltoholicFramePets:Show() + + if value == 1 then + ns:SetType("CRITTER") + elseif value == 2 then + table.sort(DataStore:GetCompanionList(), function(a, b) + local textA = GetSpellInfo(a) or "" + local textB = GetSpellInfo(b) or "" + return textA < textB + end) + ns:UpdatePetsAllInOne() + elseif value == 3 then + ns:SetType("MOUNT") + elseif value == 4 then + table.sort(DataStore:GetMountList(), function(a, b) + local textA = GetSpellInfo(a) or "" + local textB = GetSpellInfo(b) or "" + return textA < textB + end) + ns:UpdatePetsAllInOne() + end +end + +function ns:DropDownPets_Initialize() + local info = UIDropDownMenu_CreateInfo(); + + info.text = COMPANIONS + info.value = 1 + info.func = OnChangePetView + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + + info.text = format("%s %s(%s)", COMPANIONS, GREEN, L["All-in-one"]) + info.value = 2 + info.func = OnChangePetView + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + + info.text = MOUNTS + info.value = 3 + info.func = OnChangePetView + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + + info.text = format("%s %s(%s)", MOUNTS, GREEN, L["All-in-one"]) + info.value = 4 + info.func = OnChangePetView + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); +end + +local function SetPage(pageNum) + currentPage = pageNum + + local character = addon.Tabs.Characters:GetCurrent() + local pets = DataStore:GetPets(character, currentPetType) + + if currentPage == 1 then + AltoholicFramePetsNormalPrevPage:Disable() + else + AltoholicFramePetsNormalPrevPage:Enable() + end + + local maxPages = 1 + if pets then + maxPages = ceil(DataStore:GetNumPets(pets) / PETS_PER_PAGE) + if maxPages == 0 then + maxPages = 1 + end + end + + if currentPage == maxPages then + AltoholicFramePetsNormalNextPage:Disable() + else + AltoholicFramePetsNormalNextPage:Enable() + end + + AltoholicFramePetsNormal_PageNumber:SetText(format(MERCHANT_PAGE_NUMBER, currentPage, maxPages )) + ns:UpdatePets() +end + +function ns:GoToPreviousPage() + SetPage(currentPage - 1) +end + +function ns:GoToNextPage() + SetPage(currentPage + 1) +end + +function ns:SetType(petType) + selectedID = 1 + currentPetType = petType + SetPage(1) +end + +function ns:UpdatePets() + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local pets = DS:GetPets(character, currentPetType) + + if not pets or (DS:GetNumPets(pets) == 0) then -- added this test as simply addressing the table seems to make it grow, I'd assume this is due to AceDB magic value ['*']. + for i = 1, PETS_PER_PAGE do + local button = _G["AltoholicFramePetsNormal_Button" .. i]; + + if currentPetType == "MOUNT" then + button:SetDisabledTexture([[Interface\PetPaperDollFrame\UI-PetFrame-Slots-Mounts]]) + else + button:SetDisabledTexture([[Interface\PetPaperDollFrame\UI-PetFrame-Slots-Companions]]) + end + button:Disable(); + button:SetChecked(false); + end + return + end + + local offset = (currentPage-1) * PETS_PER_PAGE + + for i = 1, PETS_PER_PAGE do + local index = offset + i + local button = _G["AltoholicFramePetsNormal_Button" .. i]; + + local modelID, name, spellID, icon = DS:GetPetInfo(pets, index) + + if icon and spellID then -- if there's a pet .. texture & enable it + button:SetNormalTexture(icon); + button:Enable() + button.spellID = spellID + else + button.spellID = nil + if currentPetType == "MOUNT" then + button:SetDisabledTexture([[Interface\PetPaperDollFrame\UI-PetFrame-Slots-Mounts]]) + else + button:SetDisabledTexture([[Interface\PetPaperDollFrame\UI-PetFrame-Slots-Companions]]) + end + button:Disable(); + end + + modelID = tonumber(modelID) + if selectedID and (index == selectedID) and modelID then + button:SetChecked(true); -- check only if it's the selected button and it has a model id + AltoholicFramePetsNormal_PetName:SetText(name) + AltoholicFramePetsNormal_ModelFrame:SetCreature(modelID); + else + button:SetChecked(false); + end + end +end + +function ns:UpdatePetsAllInOne() + local VisibleLines = 8 + local frame = "AltoholicFramePetsAllInOne" + local entry = frame.."Entry" + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + + local mode = UIDropDownMenu_GetSelectedValue(AltoholicFramePets_SelectPetView); + local petList, petType + + local DS = DataStore + if mode == 2 then + petList = DS:GetCompanionList() + petType = "CRITTER" + elseif mode == 4 then + petList = DS:GetMountList() + petType = "MOUNT" + end + + local realm, account = addon:GetCurrentRealm() + local character + + for i=1, VisibleLines do + local line = i + offset + if line <= #petList then -- if the line is visible + local spellID + + spellID = petList[line] + + local petName, _, petTexture = GetSpellInfo(spellID) + + if petName then + _G[entry..i.."Name"]:SetText(WHITE .. petName) + _G[entry..i.."Name"]:SetJustifyH("LEFT") + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + end + + for j = 1, 10 do + local itemName = entry.. i .. "Item" .. j; + local itemButton = _G[itemName] + local itemTexture = _G[itemName .. "_Background"] + + local classButton = _G["AltoholicFrameClassesItem" .. j] + if classButton.CharName then + character = DS:GetCharacter(classButton.CharName, realm, account) + + itemButton:SetScript("OnEnter", function(self) ns:OnEnter(self) end) + itemTexture:SetTexture(petTexture) + + if DS:IsPetKnown(character, petType, spellID) then + itemTexture:SetVertexColor(1.0, 1.0, 1.0); + _G[itemName .. "Name"]:SetText("\124TInterface\\RaidFrame\\ReadyCheck-Ready:14\124t") + else + itemTexture:SetVertexColor(0.4, 0.4, 0.4); + _G[itemName .. "Name"]:SetText("\124TInterface\\RaidFrame\\ReadyCheck-NotReady:14\124t") + end + itemButton.spellID = spellID + itemButton:Show() + else + itemButton.spellID = nil + itemButton:Hide() + end + end + + _G[ entry..i ]:Show() + else + _G[ entry..i ]:Hide() + end + end + + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], #petList, VisibleLines, 41); +end + +local function ScanHunter() + -- this is a specific function to scan hunter pet talents + -- DEFAULT_CHAT_FRAME:AddMessage("Scanning Pet " .. currentPetName) +end + +function ns:OnChange() + -- this event is triggered too often for our needs, some filtering is required to avoid scanning pet data too often + if arg1 ~= "player" then return end + + local name = UnitName("pet") + if not name or name == UNKNOWN then return end -- if there's a usable pet name .. + + if not currentPetName then -- not set ? initial scan + currentPetName = name + ScanHunter() + elseif currentPetName ~= name then -- already set, has it changed ? re-scan + currentPetName = name + ScanHunter() + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/Pets.xml b/Altoholic-Addon/Altoholic/Frames/Pets.xml new file mode 100644 index 0000000..ae8c97b --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Pets.xml @@ -0,0 +1,438 @@ + + + + + + + + + + + + + + + Altoholic.Pets:OnEnter(self) + + + AltoTooltip:Hide(); + + + Altoholic.Pets:OnClick(self, button) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 100) + UIDropDownMenu_SetButtonWidth(self, 20) + UIDropDownMenu_SetSelectedValue(self, 1); + UIDropDownMenu_SetText(self, COMPANIONS) + UIDropDownMenu_Initialize(self, Altoholic.Pets.DropDownPets_Initialize) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Model_OnLoad(self); + self:RegisterEvent("DISPLAY_SIZE_CHANGED"); + + + self:RefreshUnit(); + + + Model_OnUpdate(self, elapsed); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 41, Altoholic.Pets.UpdatePetsAllInOne) + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Quests.lua b/Altoholic-Addon/Altoholic/Frames/Quests.lua new file mode 100644 index 0000000..4c3f02f --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Quests.lua @@ -0,0 +1,235 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local RED = "|cFFFF0000" +local GREEN = "|cFF00FF00" +local TEAL = "|cFF00FF9A" + +local isViewValid +local collapsedHeaders + +local questSizeColors = { + [2] = GREEN, + [3] = YELLOW, + [4] = ORANGE, + [5] = RED, +} + +local function FormatQuestType(tag, size) + if questSizeColors[size] then + return format("%s%s%s (%d)", WHITE, tag, questSizeColors[size], size) + else + return format("%s%s", WHITE, tag) + end +end + +addon.Quests = {} + +local ns = addon.Quests -- ns = namespace + +function ns:Update() + local character = addon.Tabs.Characters:GetCurrent() + + + local VisibleLines = 14 + local frame = "AltoholicFrameQuests" + local entry = frame.."Entry" + + local DS = DataStore + + if DS:GetQuestLogSize(character) == 0 then + AltoholicTabCharactersStatus:SetText(L["No quest found for "] .. addon:GetCurrentCharacter()) + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 18) + return + end + AltoholicTabCharactersStatus:SetText("") + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local DisplayedCount = 0 + local VisibleCount = 0 + local DrawGroup + + collapsedHeaders = collapsedHeaders or {} + if not isViewValid then + wipe(collapsedHeaders) + isViewValid = true + end + + local i=1 + + for line = 1, DS:GetQuestLogSize(character) do + local isHeader, quest, questTag, groupSize, money, isComplete = DS:GetQuestLogInfo(character, line) + + if (offset > 0) or (DisplayedCount >= VisibleLines) then -- if the line will not be visible + if isHeader then -- then keep track of counters + + if not collapsedHeaders[line] then + DrawGroup = true + else + DrawGroup = false + end + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif DrawGroup then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + end + else -- line will be displayed + if isHeader then + if not collapsedHeaders[line] then + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + DrawGroup = true + else + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + DrawGroup = false + end + _G[entry..i.."Collapse"]:Show() + _G[entry..i.."QuestLinkNormalText"]:SetText(TEAL .. quest) + _G[entry..i.."QuestLink"]:SetID(0) + _G[entry..i.."QuestLink"]:SetPoint("TOPLEFT", 25, 0) + + _G[entry..i.."Tag"]:Hide() + _G[entry..i.."Status"]:Hide() + _G[entry..i.."Money"]:Hide() + + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + + elseif DrawGroup then + _G[entry..i.."Collapse"]:Hide() + + local _, _, level = DS:GetQuestInfo(quest) + -- quick fix, level may be nil, I suspect that due to certain locales, the quest link may require different parsing. + level = level or 0 + + _G[entry..i.."QuestLinkNormalText"]:SetText(WHITE .. "[" .. level .. "] " .. quest) + _G[entry..i.."QuestLink"]:SetID(line) + _G[entry..i.."QuestLink"]:SetPoint("TOPLEFT", 15, 0) + if questTag then + _G[entry..i.."Tag"]:SetText(FormatQuestType(questTag, groupSize)) + _G[entry..i.."Tag"]:Show() + else + _G[entry..i.."Tag"]:Hide() + end + + _G[entry..i.."Status"]:Hide() + if isComplete == 1 then + _G[entry..i.."Status"]:SetText(GREEN .. COMPLETE) + _G[entry..i.."Status"]:Show() + elseif isComplete == -1 then + _G[entry..i.."Status"]:SetText(RED .. FAILED) + _G[entry..i.."Status"]:Show() + end + + if money then + _G[entry..i.."Money"]:SetText(addon:GetMoneyString(money)) + _G[entry..i.."Money"]:Show() + else + _G[entry..i.."Money"]:Hide() + end + + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + end + end + end + + while i <= VisibleLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + i = i + 1 + end + + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18); +end + +function ns:InvalidateView() + isViewValid = nil +end + +function ns:ListCharsOnQuest(questName, player, tooltip) + if not questName then return nil end + + local DS = DataStore + local CharsOnQuest = {} + for characterName, character in pairs(DS:GetCharacters(realm)) do + if characterName ~= player then + local questLogSize = DS:GetQuestLogSize(character) or 0 + for i = 1, questLogSize do + local isHeader, link = DS:GetQuestLogInfo(character, i) + if not isHeader then + local altQuestName = DS:GetQuestInfo(link) + if altQuestName == questName then -- same quest found ? + table.insert(CharsOnQuest, DS:GetColoredCharacterName(character)) + end + end + end + end + end + + if #CharsOnQuest > 0 then + tooltip:AddLine(" ",1,1,1); + tooltip:AddLine(GREEN .. L["Are also on this quest:"],1,1,1); + tooltip:AddLine(table.concat(CharsOnQuest, "\n"),1,1,1); + end +end + +function ns:Collapse_OnClick(frame, button) + local id = frame:GetParent():GetID() + if id ~= 0 then + collapsedHeaders[id] = not collapsedHeaders[id] + ns:Update() + end +end + +function ns:Link_OnEnter(frame) + local id = frame:GetID() + if id == 0 then return end + + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local _, link = DS:GetQuestLogInfo(character, id) + if not link then return end + + local questName, questID, level = DS:GetQuestInfo(link) + if IsAddOnLoaded("Odyssey") and IsAddOnLoaded("OdysseyQuests") then + Odyssey:ShowQuestTooltip(frame, questID) + return + end + + GameTooltip:ClearLines(); + GameTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + GameTooltip:SetHyperlink(link); + GameTooltip:AddLine(" ",1,1,1); + + GameTooltip:AddDoubleLine(LEVEL .. ": |cFF00FF9A" .. level, L["QuestID"] .. ": |cFF00FF9A" .. questID); + + local player = addon:GetCurrentCharacter() + addon.Quests:ListCharsOnQuest(questName, player, GameTooltip) + GameTooltip:Show(); +end + +function ns:Link_OnClick(frame, button) + if button == "LeftButton" and IsShiftKeyDown() then + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + local id = frame:GetID() + if id == 0 then return end + + local character = addon.Tabs.Characters:GetCurrent() + local _, link = DataStore:GetQuestLogInfo(character, id) + if link then + chat:Insert(link) + end + end + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/Quests.xml b/Altoholic-Addon/Altoholic/Frames/Quests.xml new file mode 100644 index 0000000..707715a --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Quests.xml @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.Quests.Update) + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Recipes.lua b/Altoholic-Addon/Altoholic/Frames/Recipes.lua new file mode 100644 index 0000000..493b075 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Recipes.lua @@ -0,0 +1,473 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() + +local WHITE = "|cFFFFFFFF" +local TEAL = "|cFF00FF9A" +local YELLOW = "|cFFFFFF00" +local GREEN = "|cFF00FF00" +local RECIPE_GREY = "|cFF808080" +local RECIPE_GREEN = "|cFF40C040" +local RECIPE_ORANGE = "|cFFFF8040" + +local view + +local RecipeColors = { RECIPE_ORANGE, YELLOW, RECIPE_GREEN, RECIPE_GREY } +local RecipeColorNames = { BI["Orange"], BI["Yellow"], BI["Green"], L["Grey"] } + +local ns = addon.TradeSkills.Recipes -- ns = namespace + +local function GetCurrentProfessionTable() + local character = addon.Tabs.Characters:GetCurrent() + return DataStore:GetProfession(character, addon.TradeSkills.CurrentProfession) -- current profession +end + +local function GetLinkByLine(index) + local profession = GetCurrentProfessionTable() + local _, _, spellID = DataStore:GetCraftLineInfo(profession, index) + + return ns:GetLink(spellID, addon.TradeSkills.CurrentProfession) +end + +-- drop down menus +local function DDM_AddButton(text, value, func) + local info = UIDropDownMenu_CreateInfo() + + info.text = text + info.value = value + info.func = func + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); +end + +local function OnColorChange(self) + UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectColor, self.value); + ns:BuildView() + ns:Update() +end + +function ns:DropDownColor_Initialize() + local ts = Altoholic.TradeSkills + if not ts.CurrentProfession then + DDM_AddButton(L["Any"], 0, OnColorChange) + return + end + + local character = Altoholic.Tabs.Characters:GetCurrent() + local profession = DataStore:GetProfession(character, ts.CurrentProfession) + local orange, yellow, green, grey = DataStore:GetNumRecipesByColor(profession) + + DDM_AddButton(format("%s %s(%s)", L["Any"], GREEN, orange+yellow+green+grey ), 0, OnColorChange) + DDM_AddButton(format("%s %s(%s)", RecipeColors[1] .. RecipeColorNames[1], GREEN, orange ), 1, OnColorChange) + DDM_AddButton(format("%s %s(%s)", RecipeColors[2] .. RecipeColorNames[2], GREEN, yellow ), 2, OnColorChange) + DDM_AddButton(format("%s %s(%s)", RecipeColors[3] .. RecipeColorNames[3], GREEN, green ), 3, OnColorChange) + DDM_AddButton(format("%s %s(%s)", RecipeColors[4] .. RecipeColorNames[4], GREEN, grey ), 4, OnColorChange) +end + +local function OnSubClassChange(self) + UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectSubclass, self.value); + ns:BuildView() + ns:Update() +end + +function ns:DropDownSubclass_Initialize() + DDM_AddButton(ALL_SUBCLASSES, ALL_SUBCLASSES, OnSubClassChange) + + local ts = Altoholic.TradeSkills + if not ts.CurrentProfession then return end + + local character = Altoholic.Tabs.Characters:GetCurrent() + local profession = DataStore:GetProfession(character, ts.CurrentProfession) + + for index = 1, DataStore:GetNumCraftLines(profession) do + local isHeader, _, name = DataStore:GetCraftLineInfo(profession, index) + + if isHeader then + DDM_AddButton(name, name, OnSubClassChange) + end + end +end + +local function OnInvSlotChange(self) + UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectInvSlot, self.value); + ns:BuildView() + ns:Update() +end + +function ns:DropDownInvSlot_Initialize() + DDM_AddButton(ALL_INVENTORY_SLOTS, ALL_INVENTORY_SLOTS, OnInvSlotChange) + + local ts = Altoholic.TradeSkills + if not ts.CurrentProfession then return end + + local invSlots = {} + local character = Altoholic.Tabs.Characters:GetCurrent() + local profession = DataStore:GetProfession(character, ts.CurrentProfession) + + for index = 1, DataStore:GetNumCraftLines(profession) do + local isHeader, _, spellID = DataStore:GetCraftLineInfo(profession, index) + + if not isHeader then -- NON header !! + local itemID = DataStore:GetCraftInfo(spellID) + + if itemID then + local _, _, _, _, _, itemType, _, _, itemEquipLoc = GetItemInfo(itemID) + + if itemEquipLoc and strlen(itemEquipLoc) > 0 then + local slot = Altoholic.Equipment:GetInventoryTypeName(itemEquipLoc) + if slot then + invSlots[slot] = itemEquipLoc + end + end + end + end + end + + for k, v in pairs(invSlots) do -- add all the slots found + DDM_AddButton(k, v, OnInvSlotChange) + end + + --NONEQUIPSLOT = "Created Items"; -- Items created by enchanting + DDM_AddButton(NONEQUIPSLOT, NONEQUIPSLOT, OnInvSlotChange) +end + + +function ns:BuildView() + view = view or {} + wipe(view) + + local ts = addon.TradeSkills + local character = addon.Tabs.Characters:GetCurrent() + local profession = DataStore:GetProfession(character, ts.CurrentProfession) + if not profession then return end + + local selectedColor = UIDropDownMenu_GetSelectedValue(AltoholicFrameRecipesInfo_SelectColor) + local selectedClass = UIDropDownMenu_GetSelectedValue(AltoholicFrameRecipesInfo_SelectSubclass) + local selectedSlot = UIDropDownMenu_GetSelectedValue(AltoholicFrameRecipesInfo_SelectInvSlot) + + local hideCategory -- hide or show the current header ? + local hideLine -- hide or show the current line ? + + for index = 1, DataStore:GetNumCraftLines(profession) do + local isHeader, color, info = DataStore:GetCraftLineInfo(profession, index) + + if isHeader then + hideCategory = false + if selectedClass ~= ALL_SUBCLASSES and selectedClass ~= info then + hideCategory = true -- hide if a specific subclass is selected AND we're not on it + end + + if not hideCategory then + table.insert(view, { id = index, isCollapsed = false } ) + end + else -- data line + if not hideCategory then + hideLine = false + if selectedColor ~= 0 and selectedColor ~= color then + hideLine = true + elseif selectedSlot ~= ALL_INVENTORY_SLOTS then + if info then -- on a data line, info contains the itemID and is numeric + local itemID = DataStore:GetCraftInfo(info) + if itemID then + local _, _, _, _, _, itemType, _, _, itemEquipLoc = GetItemInfo(itemID) + + if itemType == BI["Armor"] or itemType == BI["Weapon"] then + if itemEquipLoc and strlen(itemEquipLoc) > 0 then + if selectedSlot ~= itemEquipLoc then + hideLine = true + end + end + else -- not a weapon or armor ? then test if it's a generic "Created item" + if selectedSlot ~= NONEQUIPSLOT then + hideLine = true + end + end + else -- enchants, like socket bracker, might not have an item id, so hide the line + hideLine = true + end + else + if selectedSlot ~= NONEQUIPSLOT then + hideLine = true + end + end + end + + if not hideLine then + table.insert(view, index) + end + end + end + end + + -- going from last to first, if two headers follow one another, it means that the smallest index is an empty category, so delete it + for i = (#view - 1), 1, -1 do + if type(view[i]) == "table" and type(view[i+1]) == "table" then + table.remove(view, i) + end + end + + -- to avoid testing for exceptions in the previous loop, deal with the only shortcoming here (if the last entry is a table, it's an empty category, delete it) + if type(view[#view]) == "table" then + table.remove(view) + end +end + +function ns:Update() + local currentProfession = addon.TradeSkills.CurrentProfession + + local VisibleLines = 14 + local frame = "AltoholicFrameRecipes" + local entry = frame.."Entry" + + local character = addon.Tabs.Characters:GetCurrent() + local profession = DataStore:GetProfession(character, currentProfession) + + AltoholicFrameRecipesInfo:Show() + AltoholicTabCharactersStatus:SetText("") + + local curRank, maxRank = DataStore:GetSkillInfo(character, currentProfession) + + AltoholicFrameRecipesInfo_NumRecipes:SetText( + format("%s" ..TEAL .. " %d/%d", currentProfession, curRank or 0, maxRank or 0 ) + ) + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local DisplayedCount = 0 + local VisibleCount = 0 + local DrawGroup = true + local i=1 + + local isHeader + local isCollapsed + + for index, s in pairs(view) do + if type(s) == "table" then + isHeader = true + isCollapsed = s.isCollapsed + else + isHeader = nil + end + + if (offset > 0) or (DisplayedCount >= VisibleLines) then -- if the line will not be visible + if isHeader then -- then keep track of counters + if isCollapsed == false then + DrawGroup = true + else + DrawGroup = false + end + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif DrawGroup then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + end + else -- line will be displayed + if isHeader then + if isCollapsed == false then + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + DrawGroup = true + else + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + DrawGroup = false + end + _G[entry..i.."Collapse"]:Show() + _G[entry..i.."Craft"]:Hide() + + local _, _, name = DataStore:GetCraftLineInfo(profession, s.id) + _G[entry..i.."RecipeLinkNormalText"]:SetText(TEAL .. name) + _G[entry..i.."RecipeLink"]:SetID(0) + _G[entry..i.."RecipeLink"]:SetPoint("TOPLEFT", 25, 0) + + for j=1, 8 do + _G[ entry..i .. "Item" .. j ]:Hide() + end + + _G[ entry..i ]:SetID(index) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + + elseif DrawGroup then + _G[entry..i.."Collapse"]:Hide() + + local _, color, spellID = DataStore:GetCraftLineInfo(profession, s) + local itemID, reagents = DataStore:GetCraftInfo(spellID) + + if itemID then + Altoholic:SetItemButtonTexture(entry..i.."Craft", GetItemIcon(itemID), 18, 18); + _G[entry..i.."Craft"]:SetID(itemID) + _G[entry..i.."Craft"]:Show() + else + _G[entry..i.."Craft"]:Hide() + end + + if spellID then + _G[entry..i.."RecipeLinkNormalText"]:SetText(ns:GetLink(spellID, currentProfession, RecipeColors[color])) + else + -- this should NEVER happen, like NEVER-EVER-ER !! + _G[entry..i.."RecipeLinkNormalText"]:SetText(L["N/A"]) + end + _G[entry..i.."RecipeLink"]:SetID(s) + _G[entry..i.."RecipeLink"]:SetPoint("TOPLEFT", 32, 0) + + local j = 1 + + if reagents then + -- "2996x2;2318x1;2320x1" + for reagent in reagents:gmatch("([^;]+)") do + local itemName = entry..i .. "Item" .. j; + local reagentID, reagentCount = strsplit("x", reagent) + reagentID = tonumber(reagentID) + + if reagentID then + reagentCount = tonumber(reagentCount) + + _G[itemName]:SetID(reagentID) + Altoholic:SetItemButtonTexture(itemName, GetItemIcon(reagentID), 18, 18); + + local itemCount = _G[itemName .. "Count"] + itemCount:SetText(reagentCount); + itemCount:Show(); + + _G[ itemName ]:Show() + j = j + 1 + else + _G[ itemName ]:Hide() + end + end + end + + while j <= 8 do + _G[ entry..i .. "Item" .. j ]:Hide() + j = j + 1 + end + + _G[ entry..i ]:SetID(index) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + end + end + end + + while i <= VisibleLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + i = i + 1 + end + + if VisibleCount == 0 then + AltoholicTabCharactersStatus:SetText(format("%s: %s", currentProfession, L["No data"])) + end + + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18); +end + +function ns:GetLink(spellID, profession, color) + local name = GetSpellInfo(spellID) + color = color or "|cffffd000" + return format("%s|Henchant:%s|h[%s: %s]|h|r", color, spellID, profession, name) +end + +function ns:ResetDropDownMenus() + UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectColor, 0); + UIDropDownMenu_SetText(AltoholicFrameRecipesInfo_SelectColor, L["Any"]) + UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectSubclass, ALL_SUBCLASSES); + UIDropDownMenu_SetText(AltoholicFrameRecipesInfo_SelectSubclass, ALL_SUBCLASSES) + UIDropDownMenu_SetSelectedValue(AltoholicFrameRecipesInfo_SelectInvSlot, ALL_INVENTORY_SLOTS); + UIDropDownMenu_SetText(AltoholicFrameRecipesInfo_SelectInvSlot, ALL_INVENTORY_SLOTS) +end + +function ns:ToggleAll(frame) + -- expand or collapse all sections of the currently displayed alt /tradeskill + if not frame.isCollapsed then + frame.isCollapsed = true + frame:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + else + frame.isCollapsed = nil + frame:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + end + + for _, s in pairs(view) do + if type(s) == "table" then -- it's a header + s.isCollapsed = (frame.isCollapsed) or false + end + end + + ns:Update() +end + +function ns:RecipeLink_OnEnter(frame) + local id = frame:GetID() + if id == 0 then return end + + local link = GetLinkByLine(id) + + if link then + GameTooltip:ClearLines(); + GameTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + GameTooltip:SetHyperlink(link); + GameTooltip:AddLine(" ",1,1,1); + GameTooltip:Show(); + end +end + +function ns:RecipeLink_OnClick(frame, button) + if ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + local id = frame:GetID() + if id == 0 then return end + + local link = GetLinkByLine(id) + if link then + chat:Insert(link) + end + end + end +end + +function ns:Collapse_OnClick(frame, button) + local id = frame:GetParent():GetID() + if id ~= 0 then + local s = view[id] + if s.isCollapsed ~= nil then + if s.isCollapsed == true then + s.isCollapsed = false + else + s.isCollapsed = true + end + end + end + ns:Update() +end + +function ns:Link_OnClick(frame, button) + if ( button ~= "LeftButton" ) then + return + end + + if addon:GetCurrentRealm() ~= GetRealmName() then + addon:Print(L["Cannot link another realm's tradeskill"]) + return + end + + local character = addon.Tabs.Characters:GetCurrent() + local profession = DataStore:GetProfession(character, addon.TradeSkills.CurrentProfession) + local link = profession.FullLink + + if not link then + addon:Print(L["Invalid tradeskill link"]) + return + end + + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + chat:Insert(addon:GetCurrentCharacter() .. ": " .. link); + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/Recipes.xml b/Altoholic-Addon/Altoholic/Frames/Recipes.xml new file mode 100644 index 0000000..2f1c0f4 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Recipes.xml @@ -0,0 +1,466 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 100) + UIDropDownMenu_SetButtonWidth(self, 20) + UIDropDownMenu_Initialize(self, Altoholic.TradeSkills.Recipes.DropDownColor_Initialize) + UIDropDownMenu_SetSelectedValue(self, 0); + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 120) + UIDropDownMenu_SetButtonWidth(self, 20) + UIDropDownMenu_Initialize(self, Altoholic.TradeSkills.Recipes.DropDownSubclass_Initialize) + UIDropDownMenu_SetSelectedValue(self, ALL_SUBCLASSES); + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 120) + UIDropDownMenu_SetButtonWidth(self, 20) + UIDropDownMenu_Initialize(self, Altoholic.TradeSkills.Recipes.DropDownInvSlot_Initialize) + UIDropDownMenu_SetSelectedValue(self, ALL_INVENTORY_SLOTS); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.TradeSkills.Recipes.Update) + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Reputations.lua b/Altoholic-Addon/Altoholic/Frames/Reputations.lua new file mode 100644 index 0000000..71bac7c --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Reputations.lua @@ -0,0 +1,361 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BF = LibStub("LibBabble-Faction-3.0"):GetLookupTable() +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local TEAL = "|cFF00FF9A" +local YELLOW = "|cFFFFFF00" +local DARK_RED = "|cFFF00000" + +local ICON_UNKNOWN = "\124TInterface\\RaidFrame\\ReadyCheck-NotReady:14\124t" +local ICON_EXALTED = "\124TInterface\\RaidFrame\\ReadyCheck-Ready:14\124t" + +local Factions = { + -- Factions reference table, based on http://www.wowwiki.com/Factions + { -- [1] + name = "Classic", + { -- [1] + name = FACTION_ALLIANCE, + { name = BZ["Darnassus"], icon = "Achievement_Character_Nightelf_Female" }, + { name = BF["Exodar"], icon = "Achievement_Character_Draenei_Male" }, + { name = BF["Gnomeregan Exiles"], icon = "Achievement_Character_Gnome_Female" }, + { name = BZ["Ironforge"], icon = "Achievement_Character_Dwarf_Male" }, + { name = BF["Stormwind"], icon = "Achievement_Character_Human_Male" }, + }, + { -- [2] + name = FACTION_HORDE, + { name = BF["Darkspear Trolls"], icon = "Achievement_Character_Troll_Male" }, + { name = BZ["Orgrimmar"], icon = "Achievement_Character_Orc_Male" }, + { name = BZ["Thunder Bluff"], icon = "Achievement_Character_Tauren_Male" }, + { name = BZ["Undercity"], icon = "Achievement_Character_Undead_Female" }, + { name = BZ["Silvermoon City"], icon = "Achievement_Character_Bloodelf_Male" }, + }, + { -- [3] + name = L["Alliance Forces"], + { name = BF["The League of Arathor"], icon = "Achievement_BG_winAB" }, + { name = BF["Silverwing Sentinels"], icon = "Achievement_BG_captureflag_WSG" }, + { name = BF["Stormpike Guard"], icon = "Achievement_BG_winAV" }, + }, + { -- [4] + name = L["Horde Forces"], + { name = BF["The Defilers"], icon = "Achievement_BG_winAB" }, + { name = BF["Warsong Outriders"], icon = "Achievement_BG_captureflag_WSG" }, + { name = BF["Frostwolf Clan"], icon = "Achievement_BG_winAV" }, + }, + { -- [5] + name = L["Steamwheedle Cartel"], + { name = BZ["Booty Bay"], icon = "Achievement_Zone_Stranglethorn_01" }, + { name = BZ["Everlook"], icon = "Achievement_Zone_Winterspring" }, + { name = BZ["Gadgetzan"], icon = "Achievement_Zone_Tanaris_01" }, + { name = BZ["Ratchet"], icon = "Achievement_Zone_Barrens_01" }, + }, + { -- [6] + name = L["Other"], + { name = BF["Argent Dawn"], icon = "INV_Jewelry_Talisman_07" }, + { name = BF["Bloodsail Buccaneers"], icon = "INV_Helmet_66" }, + { name = BF["Brood of Nozdormu"], icon = "INV_Misc_Head_Dragon_Bronze" }, + { name = BF["Cenarion Circle"], icon = "Achievement_Zone_Silithus_01" }, + { name = BF["Darkmoon Faire"], icon = "INV_Misc_Ticket_Darkmoon_01" }, + { name = BF["Gelkis Clan Centaur"], icon = "INV_Misc_Head_Centaur_01" }, + { name = BF["Hydraxian Waterlords"], icon = "Spell_Frost_SummonWaterElemental_2" }, + { name = BF["Magram Clan Centaur"], icon = "INV_Misc_Head_Centaur_01" }, + { name = BF["Ravenholdt"], icon = "INV_ThrowingKnife_04" }, + { name = BF["Shen'dralar"], icon = "Achievement_Zone_Feralas" }, + { name = BF["Syndicate"], icon = "INV_Misc_ArmorKit_03" }, + { name = BF["Thorium Brotherhood"], icon = "INV_Ingot_Thorium" }, + { name = BF["Timbermaw Hold"], icon = "Achievement_Reputation_timbermaw" }, + { name = BF["Tranquillien"], icon = "Achievement_Zone_Ghostlands" }, + { name = BF["Wintersaber Trainers"], icon = "Ability_Mount_PinkTiger" }, + { name = BF["Zandalar Tribe"], icon = "INV_Bijou_Green" }, + } + }, + { -- [2] + name = "The Burning Crusade", + { -- [1] + name = BZ["Outland"], + { name = BF["Ashtongue Deathsworn"], icon = "Achievement_Reputation_AshtongueDeathsworn" }, + { name = BF["Cenarion Expedition"], icon = "Achievement_Reputation_GuardiansofCenarius" }, + { name = BF["The Consortium"], icon = "INV_Enchant_ShardPrismaticLarge" }, + { name = BF["Honor Hold"], icon = "Spell_Misc_HellifrePVPHonorHoldFavor" }, + { name = BF["Kurenai"], icon = "INV_Misc_Foot_Centaur" }, + { name = BF["The Mag'har"], icon = "Achievement_Zone_Nagrand_01" }, + { name = BF["Netherwing"], icon = "Ability_Mount_NetherdrakePurple" }, + { name = BF["Ogri'la"], icon = "Achievement_Reputation_Ogre" }, + { name = BF["Sporeggar"], icon = "INV_Mushroom_11" }, + { name = BF["Thrallmar"], icon = "Spell_Misc_HellifrePVPThrallmarFavor" }, + }, + { -- [2] + name = BZ["Shattrath City"], + { name = BF["Lower City"], icon = "Achievement_Zone_Terrokar" }, + { name = BF["Sha'tari Skyguard"], icon = "Ability_Hunter_Pet_NetherRay" }, + { name = BF["Shattered Sun Offensive"], icon = "INV_Shield_48" }, + { name = BF["The Aldor"], icon = "Achievement_Character_Draenei_Female" }, + { name = BF["The Scryers"], icon = "Achievement_Character_Bloodelf_Female" }, + { name = BF["The Sha'tar"], icon = "Achievement_Zone_Netherstorm_01" }, + }, + { -- [3] + name = L["Other"], + { name = BF["Keepers of Time"], icon = "Achievement_Zone_HillsbradFoothills" }, + { name = BF["The Scale of the Sands"], icon = "INV_Enchant_DustIllusion" }, + { name = BF["The Violet Eye"], icon = "Spell_Holy_MindSooth" }, + } + }, + { -- [3] + name = "Wrath of the Lich King", + { -- [1] + name = BZ["Northrend"], + { name = BF["Argent Crusade"], icon = "Achievement_Reputation_ArgentCrusader" }, + { name = BF["Kirin Tor"], icon = "Achievement_Reputation_KirinTor" }, + { name = BF["The Kalu'ak"], icon = "Achievement_Reputation_Tuskarr" }, + { name = BF["The Wyrmrest Accord"], icon = "Achievement_Reputation_WyrmrestTemple" }, + { name = BF["Knights of the Ebon Blade"], icon = "Achievement_Reputation_KnightsoftheEbonBlade" }, + { name = BF["The Sons of Hodir"], icon = "Achievement_Boss_Hodir_01" }, + { name = BF["The Ashen Verdict"], icon = "Achievement_Reputation_ArgentCrusader" }, + }, + { -- [2] + name = BF["Alliance Vanguard"], + { name = BF["Alliance Vanguard"], icon = "Spell_Misc_HellifrePVPHonorHoldFavor" }, + { name = BF["Explorers' League"], icon = "Achievement_Zone_HowlingFjord_02" }, + { name = BF["The Frostborn"], icon = "Achievement_Zone_StormPeaks_01" }, + { name = BF["The Silver Covenant"], icon = "Achievement_Zone_CrystalSong_01" }, + { name = BF["Valiance Expedition"], icon = "Achievement_Zone_BoreanTundra_01" }, + }, + { -- [3] + name = BF["Horde Expedition"], + { name = BF["Horde Expedition"], icon = "Spell_Misc_HellifrePVPThrallmarFavor" }, + { name = BF["The Hand of Vengeance"], icon = "Achievement_Zone_HowlingFjord_02" }, + { name = BF["The Sunreavers"], icon = "Achievement_Zone_CrystalSong_01" }, + { name = BF["The Taunka"], icon = "Achievement_Zone_BoreanTundra_02" }, + { name = BF["Warsong Offensive"], icon = "Achievement_Zone_BoreanTundra_03" }, + }, + { -- [4] + name = BZ["Sholazar Basin"], + { name = BF["Frenzyheart Tribe"], icon = "Ability_Mount_WhiteDireWolf" }, + { name = BF["The Oracles"], icon = "Achievement_Reputation_MurlocOracle" }, + }, + }, +} + +local VertexColors = { + [FACTION_STANDING_LABEL1] = { r = 0.4, g = 0.13, b = 0.13 }, -- hated + [FACTION_STANDING_LABEL2] = { r = 0.5, g = 0.0, b = 0.0 }, -- hostile + [FACTION_STANDING_LABEL3] = { r = 0.6, g = 0.4, b = 0.13 }, -- unfriendly + [FACTION_STANDING_LABEL4] = { r = 0.6, g = 0.6, b = 0.0 }, -- neutral + [FACTION_STANDING_LABEL5] = { r = 0.0, g = 0.6, b = 0.0 }, -- friendly + [FACTION_STANDING_LABEL6] = { r = 0.0, g = 0.6, b = 0.4 }, -- honored + [FACTION_STANDING_LABEL7] = { r = 0.0, g = 0.6, b = 0.6 }, -- revered + [FACTION_STANDING_LABEL8] = { r = 1.0, g = 1.0, b = 1.0 }, -- exalted +} + +local currentXPack = 1 -- default to wow classic +local currentFactionGroup = (UnitFactionGroup("player") == "Alliance") and 1 or 2 -- default to alliance or horde + +addon.Reputations = {} + +local ns = addon.Reputations -- ns = namespace + +local function DDM_AddTitle(text) + -- tiny wrapper + local info = UIDropDownMenu_CreateInfo(); + + info.isTitle = 1 + info.text = text + info.checked = nil + info.notCheckable = 1 + info.icon = nil + UIDropDownMenu_AddButton(info, 1) +end + +local function DDM_Add(text, func, arg1, arg2) + -- tiny wrapper + local info = UIDropDownMenu_CreateInfo(); + + info.text = text + info.func = func + info.arg1 = arg1 + info.arg2 = arg2 + info.checked = nil + UIDropDownMenu_AddButton(info, 1); +end + +local function DDM_AddCloseMenu() + local info = UIDropDownMenu_CreateInfo(); + + -- Close menu item + info.text = CLOSE + info.func = function() CloseDropDownMenus() end + info.checked = nil + info.notCheckable = 1 + info.icon = nil + UIDropDownMenu_AddButton(info, 1) +end + +local function DDM_OnClick(self, xpackIndex, factionGroupIndex) + currentXPack = xpackIndex + currentFactionGroup = factionGroupIndex + + local factionGroup = Factions[currentXPack][currentFactionGroup] + UIDropDownMenu_SetText(AltoholicFrameReputations_SelectFaction, factionGroup.name) + + ns:Update() +end + +local function Reputations_UpdateEx(self, offset, entry, desc) + local line + local size = desc:GetSize() + + local DS = DataStore + local realm, account = addon:GetCurrentRealm() + local character + local factionGroup = Factions[currentXPack][currentFactionGroup] + + for i=1, desc.NumLines do + line = i + offset + if line <= size then + local faction = factionGroup[line] + + _G[entry..i.."Name"]:SetText(WHITE .. faction.name) + _G[entry..i.."Name"]:SetJustifyH("LEFT") + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + + for j = 1, 10 do -- loop through the 10 alts + local itemName = entry.. i .. "Item" .. j; + local itemButton = _G[itemName] + local classButton = _G["AltoholicFrameClassesItem" .. j] + + local itemTexture = _G[itemName .. "_Background"] + itemTexture:SetTexture("Interface\\Icons\\"..faction.icon) + + local status, rate + if classButton.CharName then -- if there's an alt in this column.. + character = DS:GetCharacter(classButton.CharName, realm, account) + status, _, _, rate = DS:GetReputationInfo(character, faction.name) + + if status and rate then + local vc = VertexColors[status] + itemTexture:SetVertexColor(vc.r, vc.g, vc.b); + + local text + if status == FACTION_STANDING_LABEL8 then + _G[itemName .. "Name"]:SetPoint("BOTTOMRIGHT", 5, 0) + text = ICON_EXALTED + else + _G[itemName .. "Name"]:SetPoint("BOTTOMRIGHT", -5, 0) + text = format("%2d", floor(rate)) .. "%" + end + + local color = WHITE + if status == FACTION_STANDING_LABEL1 or status == FACTION_STANDING_LABEL2 then + color = DARK_RED + end + + itemButton.CharName = classButton.CharName + _G[itemName .. "Name"]:SetText(color..text) + else + itemTexture:SetVertexColor(0.3, 0.3, 0.3); -- greyed out + _G[itemName .. "Name"]:SetPoint("BOTTOMRIGHT", 5, 0) + _G[itemName .. "Name"]:SetText(ICON_UNKNOWN) + itemButton.CharName = nil + end + itemButton:Show() + else + itemButton:Hide() + end + end + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + end + end +end + +local ReputationsScrollFrame_Desc = { + NumLines = 8, + LineHeight = 41, + Frame = "AltoholicFrameReputations", + GetSize = function() return #Factions[currentXPack][currentFactionGroup] end, + Update = Reputations_UpdateEx, +} + +function ns:DropDownFaction_Initialize() + for xpackIndex, xpack in ipairs(Factions) do + DDM_AddTitle(xpack.name) + + for factionGroupIndex, factionGroup in ipairs(Factions[xpackIndex]) do + DDM_Add(factionGroup.name, DDM_OnClick, xpackIndex, factionGroupIndex) + end + end + DDM_AddCloseMenu() +end + +function ns:Update() + addon:ScrollFrameUpdate(ReputationsScrollFrame_Desc) +end + +function ns:OnEnter(frame) + local charName = frame.CharName + if not charName then return end + + local DS = DataStore + local realm, account = addon:GetCurrentRealm() + local character = DS:GetCharacter(charName, realm, account) + local factionGroup = Factions[currentXPack][currentFactionGroup] + local faction = factionGroup[ frame:GetParent():GetID() ].name + + local status, currentLevel, maxLevel, rate = DS:GetReputationInfo(character, faction) + if not status then return end + + AltoTooltip:SetOwner(frame, "ANCHOR_LEFT"); + AltoTooltip:ClearLines(); + AltoTooltip:AddLine(DS:GetColoredCharacterName(character) .. WHITE .. " @ " .. TEAL .. faction,1,1,1); + + rate = format("%d", floor(rate)) .. "%" + AltoTooltip:AddLine(format("%s: %d/%d (%s)", status, currentLevel, maxLevel, rate),1,1,1 ) + + local bottom = DS:GetRawReputationInfo(character, faction) + local suggestion = addon:GetSuggestion(faction, bottom) + if suggestion then + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine("Suggestion: ",1,1,1); + AltoTooltip:AddLine(TEAL .. suggestion,1,1,1); + end + + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(format("%s = %s", ICON_UNKNOWN, UNKNOWN), 0.8, 0.13, 0.13); + AltoTooltip:AddLine(FACTION_STANDING_LABEL1, 0.8, 0.13, 0.13); + AltoTooltip:AddLine(FACTION_STANDING_LABEL2, 1.0, 0.0, 0.0); + AltoTooltip:AddLine(FACTION_STANDING_LABEL3, 0.93, 0.4, 0.13); + AltoTooltip:AddLine(FACTION_STANDING_LABEL4, 1.0, 1.0, 0.0); + AltoTooltip:AddLine(FACTION_STANDING_LABEL5, 0.0, 1.0, 0.0); + AltoTooltip:AddLine(FACTION_STANDING_LABEL6, 0.0, 1.0, 0.53); + AltoTooltip:AddLine(FACTION_STANDING_LABEL7, 0.0, 1.0, 0.8); + AltoTooltip:AddLine(format("%s = %s", ICON_EXALTED, FACTION_STANDING_LABEL8), 1, 1, 1); + + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(GREEN .. L["Shift+Left click to link"]); + AltoTooltip:Show(); +end + +function ns:OnClick(frame, button) + local charName = frame.CharName + if not charName then return end + + local DS = DataStore + local realm, account = addon:GetCurrentRealm() + local character = DS:GetCharacter(charName, realm, account) + local factionGroup = Factions[currentXPack][currentFactionGroup] + local faction = factionGroup[ frame:GetParent():GetID() ].name + + local status, currentLevel, maxLevel, rate = DS:GetReputationInfo(character, faction) + if not status then return end + + if ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + chat:Insert(format(L["%s is %s with %s (%d/%d)"], charName, status, faction, currentLevel, maxLevel)) + end + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/Reputations.xml b/Altoholic-Addon/Altoholic/Frames/Reputations.xml new file mode 100644 index 0000000..88647e3 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Reputations.xml @@ -0,0 +1,315 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + local faction = (UnitFactionGroup("player") == "Alliance") and FACTION_ALLIANCE or FACTION_HORDE + + UIDropDownMenu_SetWidth(self, 100) + UIDropDownMenu_SetButtonWidth(self, 20) + UIDropDownMenu_SetText(self, faction) + UIDropDownMenu_Initialize(self, Altoholic.Reputations.DropDownFaction_Initialize) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 41, Altoholic.Reputations.Update) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Search.lua b/Altoholic-Addon/Altoholic/Frames/Search.lua new file mode 100644 index 0000000..0e390c5 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Search.lua @@ -0,0 +1,955 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local LTL = LibStub("LibTradeLinks-1.0") + +local THIS_ACCOUNT = "Default" +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local RED = "|cFFFF0000" +local TEAL = "|cFF00FF9A" +local YELLOW = "|cFFFFFF00" + +local DS + +addon.Search = {} + +local ns = addon.Search -- ns = namespace + +function ns:Init() + DS = DataStore + + local _, build = GetBuildInfo() -- ex: "10314" string + local LTLBuild = LTL:GetBuildVersion() -- ex: 10314 number + + if tonumber(build) ~= LTLBuild then -- invalidate LTL if version is outdated, prevents scanning guild members' professions + LTL = nil + end +end + +local updateHandler + +function ns:Update() + ns[updateHandler](ns) +end + +function ns:SetUpdateHandler(h) + updateHandler = h +end + +local PLAYER_ITEM_LINE = 1 +local GUILD_ITEM_LINE = 2 +local PLAYER_CRAFT_LINE = 3 +local GUILD_CRAFT_LINE = 4 + +local function Realm_UpdateEx(self, offset, entry, desc) + local line, LineDesc + + for i=1, desc.NumLines do + line = i + offset + local result = ns:GetResult(line) + if result then + LineDesc = desc.Lines[result.linetype] + + local owner, color = LineDesc:GetCharacter(result) + _G[ entry..i.."Stat1" ]:SetText(color .. owner) + + local realm, account, faction = LineDesc:GetRealm(result) + local location = addon:GetFactionColour(faction) .. realm + if account ~= THIS_ACCOUNT then + location = location .. "\n" ..WHITE.. L["Account"] .. ": " ..GREEN.. account + end + _G[ entry..i.."Stat2" ]:SetText(location) + + local itemRarity + local hex = WHITE + local itemButton = _G[ entry..i.."Item" ] + + addon:CreateButtonBorder(itemButton) + itemButton.border:Hide() + + if result.id then + _, _, itemRarity = GetItemInfo(result.id) + if itemRarity then + local r, g, b + r, g, b, hex = GetItemQualityColor(itemRarity) + if itemRarity >= 2 then + itemButton.border:SetVertexColor(r, g, b, 0.5) + itemButton.border:Show() + end + end + end + + local name, source, sourceID = LineDesc:GetItemData(result, line) + + _G[ entry..i.."Name" ]:SetText(hex .. name) + _G[ entry..i.."SourceNormalText" ]:SetText(source) + _G[ entry..i.."Source" ]:SetID(sourceID) + _G[ entry..i.."ItemIconTexture" ]:SetTexture(LineDesc:GetItemTexture(result)); + + -- draw count + if result.count and result.count > 1 then + _G[ entry..i.."ItemCount" ]:SetText(result.count) + _G[ entry..i.."ItemCount" ]:Show() + else + _G[ entry..i.."ItemCount" ]:Hide() + end + + local id = LineDesc:GetItemID(result) + _G[ entry..i.."Item" ]:SetID(id or 0) + _G[ entry..i ]:Show() + end + end + + local numResults = desc:GetSize() + if (offset+desc.NumLines) <= numResults then + AltoholicTabSearchStatus:SetText(numResults .. L[" results found (Showing "] .. (offset+1) .. "-" .. (offset+desc.NumLines) .. ")") + else + AltoholicTabSearchStatus:SetText(numResults .. L[" results found (Showing "] .. (offset+1) .. "-" .. numResults .. ")") + end + + if not AltoholicFrameSearch:IsVisible() then + AltoholicFrameSearch:Show() + end +end + +-- The principle behind ScrollFrame description is the following: +-- FauxScrollframes follow a roughly similar pattern, and are usually displaying different types of lines +-- so the idea is to standardize data collection from the raw tables that are used to populate the scrollframe +-- that way, a function called GetXXX can be used to display this info regardless of the line type, but can also be reused by sort functions + +local RealmScrollFrame_Desc = { + NumLines = 7, + LineHeight = 41, + Frame = "AltoholicFrameSearch", + GetSize = function() return ns:GetNumResults() end, + Update = Realm_UpdateEx, + Lines = { + [PLAYER_ITEM_LINE] = { + GetItemData = function(self, result) -- GetItemData..just to avoid calling it GetItemInfo + -- return name, source, sourceID + return GetItemInfo(result.id), TEAL .. result.location, 0 + end, + GetItemTexture = function(self, result) + return (result.id) and GetItemIcon(result.id) or "Interface\\Icons\\Trade_Engraving" + end, + GetCharacter = function(self, result) + local character = result.source + return DS:GetCharacterName(character), DS:GetClassColor(character) + end, + GetRealm = function(self, result) + local character = result.source + local account, realm = strsplit(".", character) + return realm, account, DS:GetCharacterFaction(character) + end, + GetItemID = function(self, result) + return result.id + end, + }, + [GUILD_ITEM_LINE] = { + GetItemData = function(self, result) -- GetItemData..just to avoid calling it GetItemInfo + -- return name, source, sourceID + return GetItemInfo(result.id), TEAL .. result.location, 0 + end, + GetItemTexture = function(self, result) + return (result.id) and GetItemIcon(result.id) or "Interface\\Icons\\Trade_Engraving" + end, + GetCharacter = function(self, result) + local _, _, guildName = strsplit(".", result.source) + return guildName, GREEN + end, + GetRealm = function(self, result) + local account, realm, name = strsplit(".", result.source) + local guild = DS:GetGuild(name, realm, account) + + return realm, account, DS:GetGuildBankFaction(guild) + end, + GetItemID = function(self, result) + return result.id + end, + }, + [PLAYER_CRAFT_LINE] = { + GetItemData = function(self, result, line) + -- return name, source, sourceID + local _, _, spellID = DS:GetCraftLineInfo(result.profession, result.craftIndex) + local source = addon.TradeSkills.Recipes:GetLink(spellID, result.professionName) + + return GetSpellInfo(spellID), source, line + end, + GetItemTexture = function(self, result) + local _, _, spellID = DS:GetCraftLineInfo(result.profession, result.craftIndex) + local itemID = DS:GetCraftInfo(spellID) + + return (itemID) and GetItemIcon(itemID) or "Interface\\Icons\\Trade_Engraving" + end, + GetCharacter = function(self, result) + local character = result.char + local _, _, name = strsplit(".", character) + + -- name, color + return name, DS:GetClassColor(character) + end, + GetRealm = function(self, result) + local character = result.char + local account, realm, name = strsplit(".", character) + + return realm, account, DS:GetCharacterFaction(character) + end, + GetItemID = function(self, result) + local _, _, spellID = DS:GetCraftLineInfo(result.profession, result.craftIndex) + local itemID = DS:GetCraftInfo(spellID) + + return itemID + end, + }, + [GUILD_CRAFT_LINE] = { + GetItemData = function(self, result, line) + -- return name, source, sourceID + local profession = LTL:GetSkillName(result.skillID) + local source = addon.TradeSkills.Recipes:GetLink(result.spellID, profession) + + return GetSpellInfo(result.spellID), source, line + end, + GetItemTexture = function(self, result) + local itemID = DS:GetCraftInfo(result.spellID) + if itemID then -- if the craft is known, return its icon, else return the profession icon + return GetItemIcon(itemID) + end + + local profession = LTL:GetSkillName(result.skillID) + return addon:GetSpellIcon(addon.ProfessionSpellID[profession]) + end, + GetCharacter = function(self, result) + local _, _, _, _, _, _, _, _, _, _, englishClass = DataStore:GetGuildMemberInfo(result.char) + return result.char, addon:GetClassColor(englishClass) + end, + GetRealm = function(self, result) + return GetRealmName(), THIS_ACCOUNT, UnitFactionGroup("player") + end, + GetItemID = function(self, result) + return DS:GetCraftInfo(result.spellID) + end, + }, + } +} + +function ns:Realm_Update() + addon:ScrollFrameUpdate(RealmScrollFrame_Desc) +end + +function ns:Loots_Update() + local VisibleLines = 7 + local frame = "AltoholicFrameSearch" + local entry = frame.."Entry" + + local numResults = ns:GetNumResults() + + if numResults == 0 then + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 41) + return + end + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + + for i=1, VisibleLines do + local line = i + offset + local result = ns:GetResult(line) + if result then + local itemID = result.id + + local itemButton = _G[ entry..i.."Item" ] + addon:CreateButtonBorder(itemButton) + itemButton.border:Hide() + + local itemName, _, itemRarity, itemLevel = GetItemInfo(itemID) + local r, g, b, hex = GetItemQualityColor(itemRarity) + + if itemRarity >= 2 then + itemButton.border:SetVertexColor(r, g, b, 0.5) + itemButton.border:Show() + end + + _G[ entry..i.."ItemIconTexture" ]:SetTexture(GetItemIcon(itemID)); + + _G[ entry..i.."Stat2" ]:SetText(YELLOW .. itemLevel) + _G[ entry..i.."Name" ]:SetText(hex .. itemName) + _G[ entry..i.."Source" ]:SetText(TEAL .. result.dropLocation) + _G[ entry..i.."Source" ]:SetID(0) + + _G[ entry..i.."Stat1" ]:SetText(GREEN .. result.bossName) + + if (result.count ~= nil) and (result.count > 1) then + _G[ entry..i.."ItemCount" ]:SetText(result.count) + _G[ entry..i.."ItemCount" ]:Show() + else + _G[ entry..i.."ItemCount" ]:Hide() + end + + _G[ entry..i.."Item" ]:SetID(itemID) + _G[ entry..i ]:Show() + else + _G[ entry..i ]:Hide() + end + end + + if (offset+VisibleLines) <= numResults then + AltoholicTabSearchStatus:SetText(numResults .. L[" results found (Showing "] .. (offset+1) .. "-" .. (offset+VisibleLines) .. ")") + else + AltoholicTabSearchStatus:SetText(numResults .. L[" results found (Showing "] .. (offset+1) .. "-" .. numResults .. ")") + end + + if numResults < VisibleLines then + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleLines, VisibleLines, 41); + else + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], numResults, VisibleLines, 41); + end + + if not AltoholicFrameSearch:IsVisible() then + AltoholicFrameSearch:Show() + end +end + +function ns:Upgrade_Update() + local VisibleLines = 7 + local frame = "AltoholicFrameSearch" + local entry = frame.."Entry" + + local numResults = ns:GetNumResults() + + if numResults == 0 then + addon:ClearScrollFrame( _G[ frame.."ScrollFrame" ], entry, VisibleLines, 41) + return + end + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + + for i=1, VisibleLines do + local line = i + offset + local result = ns:GetResult(line) + if result then + local itemID = result.id + + local itemButton = _G[ entry..i.."Item" ] + addon:CreateButtonBorder(itemButton) + itemButton.border:Hide() + + local itemName, _, itemRarity, itemLevel = GetItemInfo(itemID) + local r, g, b, hex = GetItemQualityColor(itemRarity) + + if itemRarity >= 2 then + itemButton.border:SetVertexColor(r, g, b, 0.5) + itemButton.border:Show() + end + + _G[ entry..i.."ItemIconTexture" ]:SetTexture(GetItemIcon(itemID)); + + _G[ entry..i.."Name" ]:SetText(hex .. itemName) + _G[ entry..i.."Source" ]:SetText(TEAL .. result.dropLocation) + _G[ entry..i.."Source" ]:SetID(0) + + for j=1, 6 do + if result["stat"..j] ~= nil then + local statValue, diff = strsplit("|", result["stat"..j]) + local color + diff = tonumber(diff) + + if diff < 0 then + color = RED + elseif diff > 0 then + color = GREEN + else + color = WHITE + end + + _G[ entry..i.."Stat"..j ]:SetText(color .. statValue) + _G[ entry..i.."Stat"..j ]:Show() + else + _G[ entry..i.."Stat"..j ]:Hide() + end + end + + _G[ entry..i.."ILvl" ]:SetText(YELLOW .. itemLevel) + _G[ entry..i.."ILvl" ]:Show() + + if (result.count ~= nil) and (result.count > 1) then + _G[ entry..i.."ItemCount" ]:SetText(result.count) + _G[ entry..i.."ItemCount" ]:Show() + else + _G[ entry..i.."ItemCount" ]:Hide() + end + + _G[ entry..i.."Item" ]:SetID(itemID) + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + else + _G[ entry..i ]:Hide() + end + end + + if (offset+VisibleLines) <= numResults then + AltoholicTabSearchStatus:SetText(numResults .. L[" results found (Showing "] .. (offset+1) .. "-" .. (offset+VisibleLines) .. ")") + else + AltoholicTabSearchStatus:SetText(numResults .. L[" results found (Showing "] .. (offset+1) .. "-" .. numResults .. ")") + end + + if numResults < VisibleLines then + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleLines, VisibleLines, 41); + else + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], numResults, VisibleLines, 41); + end + + if not AltoholicFrameSearch:IsVisible() then + AltoholicFrameSearch:Show() + end +end + +-- ** Sort functions ** +local function GetCraftName(char, profession, num) + -- this is a helper function to quickly retrieve the name of a craft based on a character, profession and line number + + local c = addon:GetCharacterTableByLine(char) + local _, _, spellID = strsplit("^", c.recipes[profession].list[num]) + return GetSpellInfo(tonumber(spellID)) +end + +local function SortByItemName(a, b, ascending) + local nameA, nameB + if a.id then + nameA = GetItemInfo(a.id) + else -- some crafts do not have an item ID, since no item is created (ex: enchanting) + nameA = GetCraftName(a.char, a.location, a.craftNum) + end + + if b.id then + nameB = GetItemInfo(b.id) + else + nameB = GetCraftName(b.char, b.location, b.craftNum) + end + + if ascending then + return nameA < nameB + else + return nameA > nameB + end +end + +local function SortByName(a, b, ascending) + local desc = RealmScrollFrame_Desc -- get the line description for the 2 items + local LineDescA = desc.Lines[a.linetype] + local LineDescB = desc.Lines[b.linetype] + + local nameA = LineDescA:GetItemData(a) -- retrieve the name .. + local nameB = LineDescB:GetItemData(b) + + if ascending then + return nameA < nameB + else + return nameA > nameB + end +end + +local function SortByChar(a, b, ascending) + local desc = RealmScrollFrame_Desc -- get the line description for the 2 items + local LineDescA = desc.Lines[a.linetype] + local LineDescB = desc.Lines[b.linetype] + + local nameA = LineDescA:GetCharacter(a) -- retrieve the name .. + local nameB = LineDescB:GetCharacter(b) + + if nameA == nameB then -- if it's the same character name .. + return SortByName(a, b, ascending) -- .. then sort by item name + elseif ascending then + return nameA < nameB + else + return nameA > nameB + end +end + +local function SortByRealm(a, b, ascending) + local desc = RealmScrollFrame_Desc -- get the line description for the 2 items + local LineDescA = desc.Lines[a.linetype] + local LineDescB = desc.Lines[b.linetype] + + local nameA = LineDescA:GetRealm(a) -- retrieve the name .. + local nameB = LineDescB:GetRealm(b) + + if nameA == nameB then -- if it's the same realm .. + return SortByChar(a, b, ascending) -- .. then sort by character name + elseif ascending then + return nameA < nameB + else + return nameA > nameB + end +end + +local function SortByStat(a, b, field, ascending) + local statA = strsplit("|", a[field]) + local statB = strsplit("|", b[field]) + + statA = tonumber(statA) + statB = tonumber(statB) + + if ascending then + return statA < statB + else + return statA > statB + end +end + +local function SortByField(a, b, field, ascending) + if ascending then + return a[field] < b[field] + else + return a[field] > b[field] + end +end + +-- ** Results ** +local results + +function ns:ClearResults() + results = results or {} + wipe(results) +end + +function ns:AddResult(t) + table.insert(results, t) +end + +function ns:GetNumResults() + return #results or 0 +end + +function ns:GetResult(n) + if n then + return results[n] + end +end + +function ns:SortResults(frame, field) + if ns:GetNumResults() == 0 then return end + + local id = frame:GetID() + local ascending = frame.ascendingSort + + if field == "name" then + table.sort(results, function(a, b) return SortByName(a, b, ascending) end) + elseif field == "item" then + table.sort(results, function(a, b) return SortByItemName(a, b, ascending) end) + elseif field == "char" then + table.sort(results, function(a, b) return SortByChar(a, b, ascending) end) + elseif field == "realm" then + table.sort(results, function(a, b) return SortByRealm(a, b, ascending) end) + elseif field == "stat" then + table.sort(results, function(a, b) return SortByStat(a, b, "stat" .. id-1, ascending) end) + else + table.sort(results, function(a, b) return SortByField(a, b, field, ascending) end) + end + + ns:Update() +end + +local SEARCH_THISCHAR = 1 +local SEARCH_THISREALM_THISFACTION = 2 +local SEARCH_THISREALM_BOTHFACTIONS = 3 +local SEARCH_ALLREALMS = 4 +local SEARCH_ALLACCOUNTS = 5 +local SEARCH_LOOTS = 6 + +local filters = addon.ItemFilters + +-- ** Search attributes ** +local currentValue -- the value being searched (entered in the edit box) + +local currentResultType -- type of result currently being searched (eg: PLAYER_ITEM_LINE or GUILD_ITEM_LINE) +local currentResultKey -- key defining who is being searched (eg: a datastore character or guild key) +local currentResultLocation -- what is actually being searched (bags, bank, equipment, mail, etc..) + +local function VerifyItem(item, itemCount) + if type(item) == "string" then -- convert a link to its item id, only data saved + item = tonumber(item:match("item:(%d+)")) + end + + filters:SetSearchedItem(item) + if filters:ItemPassesFilters() then -- All conditions ok ? save it + ns:AddResult( { + linetype = currentResultType, -- PLAYER_ITEM_LINE or GUILD_ITEM_LINE + id = item, + source = currentResultKey, -- character or guild key in DataStore + count = itemCount, + location = currentResultLocation + } ) + end +end + +local function CraftMatchFound(spellID, value) + local name = GetSpellInfo(spellID) + if name and string.find(strlower(name), value, 1, true) then + return true + end +end + +local function BrowseCharacter(character) + + currentResultType = PLAYER_ITEM_LINE + currentResultKey = character + + local itemID, itemLink, itemCount + local containers = DS:GetContainers(character) + if containers then + for containerName, container in pairs(containers) do + if (containerName == "Bag100") then + currentResultLocation = L["Bank"] + elseif (containerName == "Bag-2") then + currentResultLocation = KEYRING + else + local bagNum = tonumber(string.sub(containerName, 4)) + if (bagNum >= 0) and (bagNum <= 4) then + currentResultLocation = L["Bags"] + else + currentResultLocation = L["Bank"] + end + end + + for slotID = 1, container.size do + itemID, itemLink, itemCount = DS:GetSlotInfo(container, slotID) + + -- use the link before the id if there's one + if itemID then + VerifyItem(itemLink or itemID, itemCount) + end + end + end + end + + currentResultLocation = L["Equipped"] + + local inventory = DS:GetInventory(character) + if inventory then + for _, v in pairs(inventory) do + VerifyItem(v, 1) + end + end + + if addon.Options:Get("IncludeMailbox") == 1 then -- check mail ? + currentResultLocation = L["Mail"] + local num = DS:GetNumMails(character) or 0 + for i = 1, num do + local _, count, link = DS:GetMailInfo(character, i) + if link then + VerifyItem(link, count) + end + end + end + + if addon.Options:Get("IncludeRecipes") == 1 -- check known recipes ? + and (filters:GetFilterValue("itemType") == nil) + and (filters:GetFilterValue("itemRarity") == 0) + and (filters:GetFilterValue("itemSlot") == 0) then + + local isHeader, spellID, itemID + local professions = DS:GetProfessions(character) + if professions then + for professionName, profession in pairs(professions) do + for index = 1, DS:GetNumCraftLines(profession) do + isHeader, _, spellID = DS:GetCraftLineInfo(profession, index) + + if not isHeader then + if CraftMatchFound(spellID, currentValue) then + ns:AddResult( { + linetype = PLAYER_CRAFT_LINE, + char = currentResultKey, + professionName = professionName, + profession = profession, + craftIndex = index, + } ) + end + end + end + end + end + end + + currentResultType = nil + currentResultKey = nil + currentResultLocation = nil +end + +local function BrowseRealm(realm, account, bothFactions) + for characterName, character in pairs(DS:GetCharacters(realm, account)) do + if bothFactions or DS:GetCharacterFaction(character) == UnitFactionGroup("player") then + BrowseCharacter(character) + end + end + + if addon.Options:Get("IncludeGuildBank") == 1 then -- Check guild bank(s) ? + currentResultType = GUILD_ITEM_LINE + + for guildName, guild in pairs(DS:GetGuilds(realm, account)) do + if bothFactions or DS:GetGuildBankFaction(guild) == UnitFactionGroup("player") then + currentResultKey = format("%s.%s.%s", account, realm, guildName) + + for tabID = 1, 6 do + local tab = DS:GetGuildBankTab(guild, tabID) + if tab.name then + for slotID = 1, 98 do + currentResultLocation = format("%s (%s - slot %d)", GUILD_BANK, tab.name, slotID) + local id, link, count = DS:GetSlotInfo(tab, slotID) + if id then + link = link or id + VerifyItem(link, count) + end + end + end + end + + currentResultKey = nil + end + end -- end guild + currentResultType = nil + currentResultLocation = nil + end + + if addon.Options:Get("IncludeGuildSkills") == 1 and string.len(currentValue) > 1 then -- Check guild professions ? + local guild = addon:GetGuild() + if guild and LTL then -- LTL won't be valid if there's a version mismatch (see :Init() ) + ns.GuildMembers = {} + + for member, _ in pairs(addon:GetGuildMembers(guild)) do -- add all known members into a table + table.insert(ns.GuildMembers, member) + end + addon.Tasks:Add("BrowseGuildProfessions", 0, ns.BrowseGuildProfessions, ns) + end + end +end + +local ongoingSearch + +function ns:FindItem(searchType, searchSubType) + if ongoingSearch then + return -- if a search is already happening .. then exit + end + + local value = AltoholicFrame_SearchEditBox:GetText() + + if not searchType and not searchSubType then -- if no type & subtype, it's not a menu search, so value may not be empty + if not value or strlen(value) == 0 then -- .. if empty, exit + return + end + end + + ongoingSearch = true + currentValue = strlower(value) + + -- Set Filters + local itemMinLevel = AltoholicTabSearch_MinLevel:GetNumber() + local itemMaxLevel = AltoholicTabSearch_MaxLevel:GetNumber() + local itemSlot = UIDropDownMenu_GetSelectedValue(AltoholicTabSearch_SelectSlot) + + filters:SetFilterValue("itemName", currentValue) + filters:SetFilterValue("itemType", searchType) + filters:SetFilterValue("itemSubType", searchSubType) + filters:SetFilterValue("itemRarity", UIDropDownMenu_GetSelectedValue(AltoholicTabSearch_SelectRarity)) + filters:SetFilterValue("itemMinLevel", itemMinLevel) + filters:SetFilterValue("itemMaxLevel", itemMaxLevel) + filters:SetFilterValue("itemSlot", itemSlot) + + filters:EnableFilter("Existence") + filters:EnableFilter("Type") + filters:EnableFilter("SubType") + filters:EnableFilter("Rarity") + filters:EnableFilter("MinLevel") + + if itemMaxLevel ~= 0 then -- enable the filter only if a max level has been set + filters:EnableFilter("Maxlevel") + end + + if itemSlot ~= 0 then -- don't apply filter if = 0, it means we take them all + filters:EnableFilter("EquipmentSlot") + end + filters:EnableFilter("Name") + + -- Start the search + local searchLocation = UIDropDownMenu_GetSelectedValue(AltoholicTabSearch_SelectLocation) + + ns:ClearResults() + + local SearchLoots + if searchLocation == SEARCH_THISCHAR then + BrowseCharacter(DS:GetCharacter()) + elseif searchLocation == SEARCH_THISREALM_THISFACTION or searchLocation == SEARCH_THISREALM_BOTHFACTIONS then + BrowseRealm(GetRealmName(), THIS_ACCOUNT, (searchLocation == SEARCH_THISREALM_BOTHFACTIONS)) + elseif searchLocation == SEARCH_ALLREALMS then + for realm in pairs(DS:GetRealms()) do + BrowseRealm(realm, THIS_ACCOUNT, true) + end + elseif searchLocation == SEARCH_ALLACCOUNTS then + -- this account first .. + for realm in pairs(DS:GetRealms()) do + BrowseRealm(realm, THIS_ACCOUNT, true) + end + + -- .. then all other accounts + for account in pairs(DS:GetAccounts()) do + if account ~= THIS_ACCOUNT then + for realm in pairs(DS:GetRealms(account)) do + BrowseRealm(realm, account, true) + end + end + end + else -- search loot tables + SearchLoots = true -- this value will be tested in ns:Update() to resize columns properly + addon.Loots:Find() + end + + filters:ClearFilters() + + if not AltoholicTabSearch:IsVisible() then + addon.Tabs:OnClick(3) + end + + if ns:GetNumResults() == 0 then + if currentValue == "" then + AltoholicTabSearchStatus:SetText(L["No match found!"]) + else + AltoholicTabSearchStatus:SetText(value .. L[" not found!"]) + end + end + ongoingSearch = nil -- search done + + -- currentValue = nil -- don't nil it, it may be required by the task checking guild professions + + if SearchLoots then + addon.Tabs.Search:SetMode("loots") + if addon.Options:Get("SortDescending") == 1 then -- descending sort ? + AltoholicTabSearch_Sort3.ascendingSort = true -- say it's ascending now, it will be toggled + ns:SortResults(AltoholicTabSearch_Sort3, "iLvl") + else + AltoholicTabSearch_Sort3.ascendingSort = nil + ns:SortResults(AltoholicTabSearch_Sort3, "iLvl") + end + else + addon.Tabs.Search:SetMode("realm") + end + + ns:Update() + collectgarbage() +end + +function ns:BrowseGuildProfessions() + if #ns.GuildMembers == 0 then -- no more members ? kill the task + ns.GuildMembers = nil + ns:Update() + return + end + + -- The professions of 1 guild member will be scanned in each pass + local guild = addon:GetGuild() + local member = ns.GuildMembers[#ns.GuildMembers] -- get the last item in the table + local t = {} + local skillID + + for _, v in pairs(guild.members[member]) do -- browse all links .. + if type(v) == "string" and v:match("trade:") then -- .. assuming they're valid of course + t, skillID = LTL:Decode(v) + if t then + for spellID, _ in pairs(t) do + local name = GetSpellInfo(spellID) + if string.find(strlower(name), currentValue, 1, true) then + ns:AddResult( { + linetype = GUILD_CRAFT_LINE, + spellID = spellID, + char = member, + skillID = skillID, + } ) + + end + end + end + end + end + + table.remove(ns.GuildMembers) -- kill the last item + addon.Tasks:Reschedule("BrowseGuildProfessions", 0.005) + return true +end + +local currentClass -- the current character class +local currentItemID -- itemID of the item for which we're searching for an upgrade + +function ns:SetClass(class) + currentClass = class +end + +function ns:GetClass() + return currentClass +end + +function ns:SetCurrentItem(itemID) + currentItemID = itemID +end + +function ns:GetRealmsLineDesc(line) + return RealmScrollFrame_Desc.Lines[line] +end + +function ns:FindEquipmentUpgrade() + local upgradeType = self.value + + ns:ClearResults() + + -- Set Filters + local _, itemLink, _, itemLevel, _, itemType, itemSubType, _, itemEquipLoc = GetItemInfo(currentItemID) + local itemSlot = addon.Equipment:GetInventoryTypeIndex(itemEquipLoc) + + filters:SetFilterValue("itemLevel", itemLevel) + filters:SetFilterValue("itemType", itemType) + filters:SetFilterValue("itemSubType", itemSubType) + + filters:EnableFilter("Existence") + filters:EnableFilter("ItemLevel") + filters:EnableFilter("Type") + filters:EnableFilter("SubType") + + if itemSlot ~= 0 then -- don't apply filter if = 0, it means we take them all + filters:SetFilterValue("itemSlot", itemSlot) + filters:EnableFilter("EquipmentSlot") + end + + -- Start the search + if upgradeType ~= -1 then -- not an item level upgrade + ns:SetClass(upgradeType) + addon.Loots:FindUpgradeByStats( currentItemID, upgradeType) + + else -- simple search, point to simple VerifyUpgrade method + addon.Loots:FindUpgrade() + AltoholicSearchOptionsLootInfo:SetText( GREEN .. addon.Options:Get("TotalLoots") .. "|r " .. L["Loots"] .. " / " + .. GREEN .. addon.Options:Get("UnknownLoots") .. "|r " .. L["Unknown"]) + end + + filters:ClearFilters() + currentItemID = nil + + AltoTooltip:Hide(); -- mandatory hide after processing + + if not AltoholicTabSearch:IsVisible() then + addon.Tabs:OnClick(3) + end + + if upgradeType ~= -1 then -- not an item level upgrade + addon.Tabs.Search:SetMode("upgrade") + else + addon.Tabs.Search:SetMode("loots") + end + + if addon.Options:Get("SortDescending") == 1 then -- descending sort ? + AltoholicTabSearch_Sort8.ascendingSort = true -- say it's ascending now, it will be toggled + ns:SortResults(AltoholicTabSearch_Sort8, "iLvl") + else + AltoholicTabSearch_Sort8.ascendingSort = nil + ns:SortResults(AltoholicTabSearch_Sort8, "iLvl") + end + + ns:Update() +end diff --git a/Altoholic-Addon/Altoholic/Frames/Search.xml b/Altoholic-Addon/Altoholic/Frames/Search.xml new file mode 100644 index 0000000..f4c4ca8 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Search.xml @@ -0,0 +1,338 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 41, Altoholic.Search.Update) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Skills.lua b/Altoholic-Addon/Altoholic/Frames/Skills.lua new file mode 100644 index 0000000..42e5027 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Skills.lua @@ -0,0 +1,364 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() + +local INFO_REALM_LINE = 0 +local INFO_CHARACTER_LINE = 1 +local INFO_TOTAL_LINE = 2 + +local WHITE = "|cFFFFFFFF" +local TEAL = "|cFF00FF9A" +local RED = "|cFFFF0000" +local ORANGE = "|cFFFF7F00" +local YELLOW = "|cFFFFFF00" +local GREEN = "|cFF00FF00" + +local RECIPE_GREY = "|cFF808080" +local RECIPE_GREEN = "|cFF40C040" +local RECIPE_ORANGE = "|cFFFF8040" + +local ICON_FACTION_HORDE = "Interface\\Icons\\INV_BannerPVP_01" +local ICON_FACTION_ALLIANCE = "Interface\\Icons\\INV_BannerPVP_02" + +local ns = addon.TradeSkills -- ns = namespace +local Characters = addon.Characters + +function ns:Update() + local VisibleLines = 14 + local frame = "AltoholicFrameSkills" + local entry = frame.."Entry" + + + local DS = DataStore + + local offset = FauxScrollFrame_GetOffset( _G[ frame.."ScrollFrame" ] ); + local DisplayedCount = 0 + local VisibleCount = 0 + local DrawRealm + local i=1 + + for _, line in pairs(Characters:GetView()) do + local lineType = Characters:GetLineType(line) + + if (offset > 0) or (DisplayedCount >= VisibleLines) then -- if the line will not be visible + if lineType == INFO_REALM_LINE then -- then keep track of counters + if Characters:GetField(line, "isCollapsed") == false then + DrawRealm = true + else + DrawRealm = false + end + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + elseif DrawRealm then + VisibleCount = VisibleCount + 1 + offset = offset - 1 -- no further control, nevermind if it goes negative + end + else -- line will be displayed + if lineType == INFO_REALM_LINE then + local _, realm, account = Characters:GetInfo(line) + + if Characters:GetField(line, "isCollapsed") == false then + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + DrawRealm = true + else + _G[ entry..i.."Collapse" ]:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + DrawRealm = false + end + _G[entry..i.."Collapse"]:Show() + _G[entry..i.."Name"]:SetWidth(300) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 25, 0) + _G[entry..i.."NameNormalText"]:SetWidth(300) + if account == "Default" then -- saved as default, display as localized. + _G[entry..i.."NameNormalText"]:SetText(format("%s (%s".. L["Account"]..": %s%s|r)", realm, WHITE, GREEN, L["Default"])) + else + local last = addon:GetLastAccountSharingInfo(realm, account) + _G[entry..i.."NameNormalText"]:SetText(format("%s (%s".. L["Account"]..": %s%s %s%s|r)", realm, WHITE, GREEN, account, YELLOW, last or "")) + end + _G[entry..i.."Level"]:SetText("") + _G[entry..i.."Skill1NormalText"]:SetText("") + _G[entry..i.."Skill2NormalText"]:SetText("") + _G[entry..i.."CookingNormalText"]:SetText("") + _G[entry..i.."FirstAidNormalText"]:SetText("") + _G[entry..i.."FishingNormalText"]:SetText("") + _G[entry..i.."RidingNormalText"]:SetText("") + + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + elseif DrawRealm then + if (lineType == INFO_CHARACTER_LINE) then + local character = DS:GetCharacter( Characters:GetInfo(line) ) + + local icon + if DS:GetCharacterFaction(character) == "Alliance" then + icon = addon:TextureToFontstring(ICON_FACTION_ALLIANCE, 18, 18) .. " " + else + icon = addon:TextureToFontstring(ICON_FACTION_HORDE, 18, 18) .. " " + end + + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetWidth(170) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 10, 0) + _G[entry..i.."NameNormalText"]:SetWidth(170) + _G[entry..i.."NameNormalText"]:SetText(icon .. format("%s (%s)", DS:GetColoredCharacterName(character), DS:GetCharacterClass(character))) + _G[entry..i.."Level"]:SetText(GREEN .. DS:GetCharacterLevel(character)) + + -- profession 1 + local field = Characters:GetField(line, "spellID1") + if field then + icon = addon:TextureToFontstring(addon:GetSpellIcon(field), 18, 18) .. " " + else + icon = "" + end + field = Characters:GetField(line, "skillRank1") + _G[entry..i.."Skill1NormalText"]:SetText(icon .. ns:GetColor(field) .. field) + + -- profession 2 + field = Characters:GetField(line, "spellID2") + if field then + icon = addon:TextureToFontstring(addon:GetSpellIcon(field), 18, 18) .. " " + else + icon = "" + end + field = Characters:GetField(line, "skillRank2") + _G[entry..i.."Skill2NormalText"]:SetText(icon .. ns:GetColor(field) .. field) + + -- cooking + icon = addon:TextureToFontstring(addon:GetSpellIcon(2550), 18, 18) .. " " + field = Characters:GetField(line, "cooking") + _G[entry..i.."CookingNormalText"]:SetText(icon .. ns:GetColor(field) .. field) + + -- first aid + icon = addon:TextureToFontstring(addon:GetSpellIcon(3273), 18, 18) .. " " + field = Characters:GetField(line, "firstaid") + _G[entry..i.."FirstAidNormalText"]:SetText(icon .. ns:GetColor(field) .. field) + + -- fishing + icon = addon:TextureToFontstring(addon:GetSpellIcon(7733), 18, 18) .. " " + field = Characters:GetField(line, "fishing") + _G[entry..i.."FishingNormalText"]:SetText(icon .. ns:GetColor(field) .. field) + + -- riding + field = Characters:GetField(line, "riding") + if DS:IsSpellKnown(character, 54197) then + icon = addon:TextureToFontstring(addon:GetSpellIcon(54197), 18, 18) .. " " + elseif field >= 225 then + icon = addon:TextureToFontstring("Interface\\Icons\\Ability_Mount_Gryphon_01", 18, 18) .. " " + else + icon = addon:TextureToFontstring("Interface\\Icons\\Ability_Mount_RidingHorse", 18, 18) .. " " + end + _G[entry..i.."RidingNormalText"]:SetText(icon .. ns:GetColor(field, 300) .. field) + elseif (lineType == INFO_TOTAL_LINE) then + _G[entry..i.."Collapse"]:Hide() + _G[entry..i.."Name"]:SetWidth(200) + _G[entry..i.."Name"]:SetPoint("TOPLEFT", 15, 0) + _G[entry..i.."NameNormalText"]:SetWidth(200) + _G[entry..i.."NameNormalText"]:SetText(L["Totals"]) + _G[entry..i.."Level"]:SetText(Characters:GetField(line, "level")) + _G[entry..i.."Skill1NormalText"]:SetText("") + _G[entry..i.."Skill2NormalText"]:SetText("") + _G[entry..i.."CookingNormalText"]:SetText("") + _G[entry..i.."FirstAidNormalText"]:SetText("") + _G[entry..i.."FishingNormalText"]:SetText("") + _G[entry..i.."RidingNormalText"]:SetText("") + end + _G[ entry..i ]:SetID(line) + _G[ entry..i ]:Show() + i = i + 1 + VisibleCount = VisibleCount + 1 + DisplayedCount = DisplayedCount + 1 + end + end + end + + while i <= VisibleLines do + _G[ entry..i ]:SetID(0) + _G[ entry..i ]:Hide() + i = i + 1 + end + + FauxScrollFrame_Update( _G[ frame.."ScrollFrame" ], VisibleCount, VisibleLines, 18); +end + +function ns:OnEnter(frame) + local line = frame:GetParent():GetID() + local lineType = Characters:GetLineType(line) + if lineType ~= INFO_CHARACTER_LINE then + return + end + + local id = frame:GetID() + local skillName, rank, suggestion + + if id == 1 then + skillName = Characters:GetField(line, "skillName1") + elseif id == 2 then + skillName = Characters:GetField(line, "skillName2") + elseif id == 3 then + skillName = GetSpellInfo(2550) -- cooking + elseif id == 4 then + skillName = GetSpellInfo(3273) -- First Aid + elseif id == 5 then + skillName = GetSpellInfo(24303) -- Fishing + elseif id == 6 then + skillName = L["Riding"] + end + + local DS = DataStore + local character = DS:GetCharacter(Characters:GetInfo(line)) + local curRank, maxRank = DS:GetSkillInfo(character, skillName) + local profession = DS:GetProfession(character, skillName) + + if (id >= 1) and (id <= 6) then + if id == 6 then -- riding + rank = ns:GetColor(curRank, 300) .. curRank .. "/" .. maxRank + else + rank = ns:GetColor(curRank) .. curRank .. "/" .. maxRank + end + suggestion = addon:GetSuggestion(skillName, curRank) + elseif id == 7 then -- class + local _, class = DS:GetCharacterClass(character) + if class ~= "ROGUE" then + return + end + skillName = L["Rogue Proficiencies"] + + local curLock, maxLock = DS:GetSkillInfo(character, L["Lockpicking"]) + rank = TEAL .. L["Lockpicking"] .. " " .. curLock .. "/" .. maxLock + suggestion = addon:GetSuggestion(L["Lockpicking"], curLock) + end + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + AltoTooltip:AddLine(skillName,1,1,1); + AltoTooltip:AddLine(GREEN..rank,1,1,1); + + if id <= 4 then -- all skills except fishing & riding + if skillName ~= GetSpellInfo(13614) and skillName ~= GetSpellInfo(8613) then -- no display for herbalism & skinning + AltoTooltip:AddLine(" "); + + if not profession then + AltoTooltip:AddLine(L["No data"]); + AltoTooltip:Show(); + return + end + + if DS:GetNumCraftLines(profession) == 0 then + AltoTooltip:AddLine(L["No data"].. ": 0 " .. TRADESKILL_SERVICE_LEARN,1,1,1); + else + local orange, yellow, green, grey = DS:GetNumRecipesByColor(profession) + + AltoTooltip:AddLine(orange+yellow+green+grey .. " " .. TRADESKILL_SERVICE_LEARN,1,1,1); + AltoTooltip:AddLine(format(WHITE .. "%d " .. RECIPE_GREEN .. "Green|r /" + .. WHITE .. " %d " .. YELLOW .. "Yellow|r /" + .. WHITE .. " %d " .. RECIPE_ORANGE .. "Orange", + green, yellow, orange)) + end + end + end + + local skillCap = 450 + if id == 6 then + skillCap = 300 + end + + AltoTooltip:AddLine(" "); + AltoTooltip:AddLine(RECIPE_GREY .. L["Grey"] .. "|r " .. L["up to"] .. " " .. (floor(skillCap*0.25)-1),1,1,1); + AltoTooltip:AddLine(RED .. RED_GEM .. "|r " .. L["up to"] .. " " .. (floor(skillCap*0.50)-1),1,1,1); + AltoTooltip:AddLine(ORANGE .. BI["Orange"] .. "|r " .. L["up to"] .. " " .. (floor(skillCap*0.75)-1),1,1,1); + AltoTooltip:AddLine(YELLOW .. YELLOW_GEM .. "|r " .. L["up to"] .. " " .. (skillCap-1),1,1,1); + AltoTooltip:AddLine(GREEN .. BI["Green"] .. "|r " .. L["at"] .. " "..skillCap.." " .. L["and above"],1,1,1); + + if suggestion then + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(L["Suggestion"] .. ": ",1,1,1); + AltoTooltip:AddLine(TEAL .. suggestion,1,1,1); + end + + -- parse profession cooldowns + if id ~= 7 and profession then + DS:ClearExpiredCooldowns(profession) + local numCooldows = DS:GetNumActiveCooldowns(profession) + + if numCooldows == 0 then + AltoTooltip:AddLine(" ",1,1,1); + AltoTooltip:AddLine(L["All cooldowns are up"],1,1,1); + else + AltoTooltip:AddLine(" ",1,1,1); + for i = 1, numCooldows do + local craftName, expiresIn = DS:GetCraftCooldownInfo(profession, i) + AltoTooltip:AddDoubleLine(craftName, addon:GetTimeString(expiresIn)); + end + end + end + + AltoTooltip:Show(); +end + +local VIEW_MOUNTS = 8 + +function ns:OnClick(frame, button) + local line = frame:GetParent():GetID() + local lineType = Characters:GetLineType(line) + if lineType ~= INFO_CHARACTER_LINE then + return + end + + local id = frame:GetID() + if id == 5 then return end -- fishing ? do nothing + + addon:SetCurrentCharacter( Characters:GetInfo(line) ) + + local skillName + if id == 1 then + skillName = Characters:GetField(line, "skillName1") + elseif id == 2 then + skillName = Characters:GetField(line, "skillName2") + elseif id == 3 then + skillName = GetSpellInfo(2550) -- cooking + elseif id == 4 then + skillName = GetSpellInfo(3273) -- First Aid + end + + local DS = DataStore + local character = DS:GetCharacter(Characters:GetInfo(line)) + local profession = DS:GetProfession(character, skillName) + + if skillName then + if not profession or DS:GetNumCraftLines(profession) == 0 then -- if profession hasn't been scanned (or scan failed), exit + return + end + end + + local charName, realm, account = addon:GetCurrentCharacter() + local chat = ChatEdit_GetLastActiveWindow() + + if chat:IsShown() and IsShiftKeyDown() and realm == GetRealmName() and id ~= 6 then + -- if shift-click, then display the profession link and exit + local link = profession.FullLink + if link and link:match("trade:") then + chat:Insert(link); + end + return + end + + addon.Tabs.Characters:SetCurrent(charName, realm, account) + addon.Tabs:OnClick(2) + + if id == 6 then + addon.Tabs.Characters:ViewCharInfo(VIEW_MOUNTS) + else + addon.Tabs.Characters:ViewRecipes(skillName) + end +end + +local skillColors = { RECIPE_GREY, RED, ORANGE, YELLOW, GREEN } + +function ns:GetColor(rank, skillCap) + skillCap = skillCap or 450 + return skillColors[ floor(rank / (skillCap/4)) + 1 ] +end diff --git a/Altoholic-Addon/Altoholic/Frames/Skills.xml b/Altoholic-Addon/Altoholic/Frames/Skills.xml new file mode 100644 index 0000000..96a4a35 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Skills.xml @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 18, Altoholic.TradeSkills.Update) + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/TabCharacters.lua b/Altoholic-Addon/Altoholic/Frames/TabCharacters.lua new file mode 100644 index 0000000..091cee4 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabCharacters.lua @@ -0,0 +1,465 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local THIS_ACCOUNT = "Default" +local WHITE = "|cFFFFFFFF" +local TEAL = "|cFF00FF9A" +local ORANGE = "|cFFFF7F00" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +-- These match the id's of the buttons in TabCharacters.xml +local VIEW_BAGS = 1 +local VIEW_TALENTS = 2 +local VIEW_MAILS = 3 +local VIEW_QUESTS = 4 +local VIEW_AUCTIONS = 5 +local VIEW_BIDS = 6 +local VIEW_COMPANIONS = 7 +local VIEW_MOUNTS = 8 +local VIEW_REP = 9 +local VIEW_EQUIP = 10 +local VIEW_TOKENS = 11 + +local ICON_VIEW_BAGS = "Interface\\Buttons\\Button-Backpack-Up" +local ICON_VIEW_MAILS = "Interface\\Icons\\INV_Misc_Note_01" +local ICON_VIEW_QUESTS = "Interface\\Icons\\INV_Misc_Book_07" +local ICON_VIEW_AUCTIONS = "Interface\\Icons\\INV_Misc_Coin_01" +local ICON_VIEW_BIDS = "Interface\\Icons\\INV_Misc_Coin_03" +local ICON_VIEW_COMPANIONS = "Interface\\Icons\\INV_Box_Birdcage_01" +local ICON_VIEW_MOUNTS = "Interface\\Icons\\Ability_Mount_RidingHorse" +local ICON_VIEW_REP = "Interface\\Icons\\INV_BannerPVP_02" +local ICON_VIEW_EQUIP = "Interface\\Icons\\INV_Chest_Plate04" +local ICON_VIEW_TALENTS = "Interface\\Icons\\Spell_Nature_NatureGuardian" +local ICON_VIEW_TOKENS = "Interface\\Icons\\Spell_Holy_SummonChampion" + +local CharInfoButtons = { + "AltoholicTabCharacters_Bags", + "AltoholicTabCharacters_Talents", + "AltoholicTabCharacters_Mails", + "AltoholicTabCharacters_Quests", + "AltoholicTabCharacters_Auctions", + "AltoholicTabCharacters_Bids", + "AltoholicTabCharacters_Pets", + "AltoholicTabCharacters_Mounts", + "AltoholicTabCharacters_Factions", + "AltoholicTabCharacters_Equipment", + "AltoholicTabCharacters_Tokens", +} + +local lastButton + +local function StartAutoCastShine(button) + local item = button:GetName() + AutoCastShine_AutoCastStart(_G[ item .. "Shine" ]); + lastButton = item +end + +local function StopAutoCastShine() + -- stop autocast shine on the last button that was clicked + if lastButton then + AutoCastShine_AutoCastStop(_G[ lastButton .. "Shine" ]); + end +end + +local function HideAll() + AltoholicFrameContainers:Hide() + AltoholicFrameTalents:Hide() + AltoholicFrameMail:Hide() + AltoholicFrameQuests:Hide() + AltoholicFrameAuctions:Hide() + AltoholicFramePets:Hide() + AltoholicFrameRecipes:Hide() + AltoholicFrameReputations:Hide() + AltoholicFrameEquipment:Hide() + AltoholicFrameCurrencies:Hide() + AltoholicFrameClasses:Hide() +end + +addon.Tabs.Characters = {} + +local ns = addon.Tabs.Characters -- ns = namespace + +function ns:OnShow() + if AltoholicFrameReputations:IsVisible() or + AltoholicFrameEquipment:IsVisible() or + AltoholicFrameCurrencies:IsVisible() or + AltoholicFramePetsAllInOne:IsVisible() then + AltoholicFrameClasses:Show() + end + + if not ns.InfoType then + StartAutoCastShine(AltoholicTabCharacters_Bags) + ns:ViewCharInfo(1) + end + + ns:UpdateViewIcons() +end + +function ns:UpdateViewIcons() + + local DS = DataStore + local character = ns:GetCurrent() + + if not character then + for k, v in pairs(CharInfoButtons) do + _G[v]:Hide() + end + AltoholicTabCharacters_Cooking:Hide() + AltoholicTabCharacters_FirstAid:Hide() + AltoholicTabCharacters_Prof1:Hide() + AltoholicTabCharacters_Prof2:Hide() + return + end + + local size = 30 + + -- ** Bags / Equipment / Quests ** + addon:SetItemButtonTexture("AltoholicTabCharacters_Bags", ICON_VIEW_BAGS, size, size) + AltoholicTabCharacters_Bags.text = L["Containers"] + AltoholicTabCharacters_Bags:Show() + + addon:SetItemButtonTexture("AltoholicTabCharacters_Equipment", ICON_VIEW_EQUIP, size, size) + AltoholicTabCharacters_Equipment.text = L["Equipment"] + AltoholicTabCharacters_Equipment:Show() + + addon:SetItemButtonTexture("AltoholicTabCharacters_Quests", ICON_VIEW_QUESTS, size, size) + AltoholicTabCharacters_Quests.text = L["Quests"] + AltoholicTabCharacters_Quests:Show() + + addon:SetItemButtonTexture("AltoholicTabCharacters_Talents", ICON_VIEW_TALENTS, size, size) + AltoholicTabCharacters_Talents.text = TALENTS .. " & " .. GLYPHS + AltoholicTabCharacters_Talents:Show() + + -- ** Auctions / Bids / Mails ** + addon:SetItemButtonTexture("AltoholicTabCharacters_Auctions", ICON_VIEW_AUCTIONS, size, size) + local num = DS:GetNumAuctions(character) or 0 + if num > 0 then + AltoholicTabCharacters_AuctionsCount:SetText(num) + AltoholicTabCharacters_AuctionsCount:Show() + else + AltoholicTabCharacters_AuctionsCount:Hide() + end + AltoholicTabCharacters_Auctions.text = format(L["Auctions %s(%d)"], GREEN, num) + AltoholicTabCharacters_Auctions:Show() + + addon:SetItemButtonTexture("AltoholicTabCharacters_Bids", ICON_VIEW_BIDS, size, size) + num = DS:GetNumBids(character) or 0 + if num > 0 then + AltoholicTabCharacters_BidsCount:SetText(num) + AltoholicTabCharacters_BidsCount:Show() + else + AltoholicTabCharacters_BidsCount:Hide() + end + AltoholicTabCharacters_Bids.text = format(L["Bids %s(%d)"], GREEN, num) + AltoholicTabCharacters_Bids:Show() + + addon:SetItemButtonTexture("AltoholicTabCharacters_Mails", ICON_VIEW_MAILS, size, size) + num = DS:GetNumMails(character) or 0 + if num > 0 then + AltoholicTabCharacters_MailsCount:SetText(num) + AltoholicTabCharacters_MailsCount:Show() + else + AltoholicTabCharacters_MailsCount:Hide() + end + AltoholicTabCharacters_Mails.text = format(L["Mails %s(%d)"], GREEN, num) + AltoholicTabCharacters_Mails:Show() + + -- ** Pets / Mounts / Reputations ** + local pets = DS:GetPets(character, "CRITTER") + num = DS:GetNumPets(pets) or 0 + + addon:SetItemButtonTexture("AltoholicTabCharacters_Pets", ICON_VIEW_COMPANIONS, size, size) + if num > 0 then + AltoholicTabCharacters_PetsCount:SetText(num) + AltoholicTabCharacters_PetsCount:Show() + else + AltoholicTabCharacters_PetsCount:Hide() + end + AltoholicTabCharacters_Pets.text = format(COMPANIONS .. " %s(%d)", GREEN, num) + AltoholicTabCharacters_Pets:Show() + + pets = DS:GetPets(character, "MOUNT") + num = DS:GetNumPets(pets) or 0 + + addon:SetItemButtonTexture("AltoholicTabCharacters_Mounts", ICON_VIEW_MOUNTS, size, size) + if num > 0 then + AltoholicTabCharacters_MountsCount:SetText(num) + AltoholicTabCharacters_MountsCount:Show() + else + AltoholicTabCharacters_MountsCount:Hide() + end + AltoholicTabCharacters_Mounts.text = format(MOUNTS .. " %s(%d)", GREEN, num) + AltoholicTabCharacters_Mounts:Show() + + addon:SetItemButtonTexture("AltoholicTabCharacters_Factions", ICON_VIEW_REP, size, size) + AltoholicTabCharacters_Factions.text = L["Reputations"] + AltoholicTabCharacters_Factions:Show() + + addon:SetItemButtonTexture("AltoholicTabCharacters_Tokens", ICON_VIEW_TOKENS, size, size) + AltoholicTabCharacters_Tokens.text = CURRENCY + AltoholicTabCharacters_Tokens:Show() + + -- ** Professions ** + local professionName = GetSpellInfo(2550) -- cooking + addon:SetItemButtonTexture("AltoholicTabCharacters_Cooking", addon:GetSpellIcon(DataStore:GetProfessionSpellID(professionName)), size, size) + AltoholicTabCharacters_Cooking.text = professionName + AltoholicTabCharacters_Cooking:Show() + + professionName = GetSpellInfo(3273) -- First Aid + addon:SetItemButtonTexture("AltoholicTabCharacters_FirstAid", addon:GetSpellIcon(DataStore:GetProfessionSpellID(professionName)), size, size) + AltoholicTabCharacters_FirstAid.text = professionName + AltoholicTabCharacters_FirstAid:Show() + + local i = 1 + for skillName, skill in pairs(DS:GetPrimaryProfessions(character)) do + local itemName = "AltoholicTabCharacters_Prof" .. i + local item = _G[itemName] + local spellID = DataStore:GetProfessionSpellID(skillName) + + if spellID then + addon:SetItemButtonTexture(itemName, addon:GetSpellIcon(spellID), size, size) + item.text = skillName + item:Show() + else + item.text = nil + item:Hide() + end + i = i + 1 + end +end + +function ns:MenuItem_OnClick(frame, button) + StopAutoCastShine() + StartAutoCastShine(frame) + + local id = frame:GetID() + if id > 0 then + ns:ViewCharInfo(id, true) + return + end + + if frame.text then -- profession button + ns:ViewRecipes(frame.text) + end +end + +-- ** realm selection ** +local function OnRealmChange(self, account, realm) + local OldAccount = addon:GetCurrentAccount() + local OldRealm = addon:GetCurrentRealm() + + addon:SetCurrentAccount(account) + addon:SetCurrentRealm(realm) + + UIDropDownMenu_ClearAll(AltoholicTabCharacters_SelectRealm); + UIDropDownMenu_SetSelectedValue(AltoholicTabCharacters_SelectRealm, account .."|".. realm) + UIDropDownMenu_SetText(AltoholicTabCharacters_SelectRealm, GREEN .. account .. ": " .. WHITE.. realm) + + if OldRealm and OldAccount then -- clear the "select char" drop down if realm or account has changed + if (OldRealm ~= realm) or (OldAccount ~= account) then + UIDropDownMenu_ClearAll(AltoholicTabCharacters_SelectChar); + AltoholicTabCharactersStatus:SetText("") + addon:SetCurrentCharacter(nil) + addon.TradeSkills.CurrentProfession = nil + + HideAll() + StopAutoCastShine() + -- AltoholicFrameAchievements:Hide() + ns:UpdateViewIcons() + end + end +end + +local function AddRealm(realm, account) + local info = UIDropDownMenu_CreateInfo(); + + info.text = format("%s: %s", GREEN..account, WHITE..realm) + info.value = format("%s|%s", account, realm) + info.checked = nil + info.func = OnRealmChange + info.arg1 = account + info.arg2 = realm + UIDropDownMenu_AddButton(info, 1); +end + +function ns:DropDownRealm_Initialize() + if not addon:GetCurrentAccount() or not addon:GetCurrentRealm() then return end + + -- this account first .. + for realm in pairs(DataStore:GetRealms()) do + AddRealm(realm, THIS_ACCOUNT) + end + + -- .. then all other accounts + for account in pairs(DataStore:GetAccounts()) do + if account ~= THIS_ACCOUNT then + for realm in pairs(DataStore:GetRealms(account)) do + AddRealm(realm, account) + end + end + end +end + +-- ** alt selection ** +local function OnAltChange(self) + local OldAlt = addon:GetCurrentCharacter() + local _, _, NewAlt = strsplit(".", self.value) + + UIDropDownMenu_SetSelectedValue(AltoholicTabCharacters_SelectChar, self.value); + addon:SetCurrentCharacter(NewAlt) + + ns:UpdateViewIcons() + if (not OldAlt) or (OldAlt == NewAlt) then return end + + if (type(ns.InfoType) == "string") or + ((type(ns.InfoType) == "number") and (ns.InfoType > VIEW_MOUNTS)) then -- true if we're dealing with a profession + addon.TradeSkills.CurrentProfession = nil + HideAll() + StopAutoCastShine() + else + ns:ShowCharInfo(ns.InfoType) -- this will show the same info from another alt (ex: containers/mail/ ..) + end +end + +function ns:DropDownChar_Initialize() + if not addon:GetCurrentAccount() or + not addon:GetCurrentRealm() then return end + + local info = UIDropDownMenu_CreateInfo(); + local realm, account = addon:GetCurrentRealm() + + for characterName, character in pairs(DataStore:GetCharacters(realm, account)) do + info.text = characterName + info.value = character + info.func = OnAltChange + info.checked = nil; + UIDropDownMenu_AddButton(info, 1); + end +end + +function ns:SetCurrent(name, realm, account) + -- this function sets both drop down menu to the right values + ns:DropDownRealm_Initialize() + UIDropDownMenu_SetSelectedValue(AltoholicTabCharacters_SelectRealm, account .."|".. realm) + + ns:DropDownChar_Initialize() + + local character = DataStore:GetCharacter(name, realm, account) + UIDropDownMenu_SetSelectedValue(AltoholicTabCharacters_SelectChar, character) +end + +function ns:GetCurrent() + -- the right character key is in this widget, use it to avoid querying DataStore all the time + return UIDropDownMenu_GetSelectedValue(AltoholicTabCharacters_SelectChar) +end + +function ns:ViewCharInfo(index, autoCastDone) + index = index or self.value + + if not autoCastDone then + StopAutoCastShine() + StartAutoCastShine(_G[ CharInfoButtons[index] ] ) + end + + ns.InfoType = index + HideAll() + ns:SetMode(index) + ns:ShowCharInfo(index) +end + +function ns:ViewRecipes(profession) + local ts = addon.TradeSkills + ts.CurrentProfession = profession + + ns.InfoType = profession + HideAll() + ns:SetMode() + + ts.Recipes:ResetDropDownMenus() + AltoholicFrameRecipes:Show() + ts.Recipes:BuildView() + ts.Recipes:Update() +end + +function ns:ShowCharInfo(infoType) + if infoType == VIEW_BAGS then + addon:ClearScrollFrame(_G[ "AltoholicFrameContainersScrollFrame" ], "AltoholicFrameContainersEntry", 7, 41) + + addon.Containers:SetView(addon.Options:Get("lastContainerView")) + AltoholicFrameContainers:Show() + addon.Containers:Update() + + elseif infoType == VIEW_TALENTS then + AltoholicFrameTalents:Show() + addon.Talents:Update(); + + elseif infoType == VIEW_MAILS then + AltoholicFrameMail:Show() + addon.Mail:BuildView() + addon.Mail:Update() + elseif infoType == VIEW_QUESTS then + AltoholicFrameQuests:Show() + addon.Quests:InvalidateView() + addon.Quests:Update(); + elseif infoType == VIEW_AUCTIONS then + addon.AuctionHouse:SetListType("Auctions") + AltoholicFrameAuctions:Show() + addon.AuctionHouse:Update(); + elseif infoType == VIEW_BIDS then + addon.AuctionHouse:SetListType("Bids") + AltoholicFrameAuctions:Show() + addon.AuctionHouse:Update(); + elseif infoType == VIEW_COMPANIONS then + UIDropDownMenu_SetSelectedValue(AltoholicFramePets_SelectPetView, 1); + UIDropDownMenu_SetText(AltoholicFramePets_SelectPetView, COMPANIONS) + addon.Pets:SetType("CRITTER") + AltoholicFramePetsNormal:Show() + AltoholicFramePetsAllInOne:Hide() + AltoholicFramePets:Show() + elseif infoType == VIEW_MOUNTS then + UIDropDownMenu_SetSelectedValue(AltoholicFramePets_SelectPetView, 3); + UIDropDownMenu_SetText(AltoholicFramePets_SelectPetView, MOUNTS) + addon.Pets:SetType("MOUNT") + AltoholicFramePetsNormal:Show() + AltoholicFramePetsAllInOne:Hide() + AltoholicFramePets:Show() + elseif infoType == VIEW_REP then + AltoholicFrameClasses:Show() + AltoholicFrameReputations:Show() + addon.Reputations:Update(); + elseif infoType == VIEW_EQUIP then + AltoholicFrameClasses:Show() + AltoholicFrameEquipment:Show() + addon.Equipment:Update() + elseif infoType == VIEW_TOKENS then + AltoholicFrameClasses:Show() + AltoholicFrameCurrencies:Show() + addon.Currencies:Update() + end +end + +function ns:SetMode(mode) + local Columns = addon.Tabs.Columns + Columns:Init() + + if not mode then return end -- called without parameter for professions + + if mode == VIEW_MAILS then + Columns:Add(MAIL_SUBJECT_LABEL, 220, function(self) addon.Mail:Sort(self, "name") end) + Columns:Add(FROM, 140, function(self) addon.Mail:Sort(self, "from") end) + Columns:Add(L["Expiry:"], 200, function(self) addon.Mail:Sort(self, "expiry") end) + + elseif mode == VIEW_AUCTIONS then + Columns:Add(HELPFRAME_ITEM_TITLE, 220, function(self) addon.AuctionHouse:Sort(self, "name", "Auctions") end) + Columns:Add(HIGH_BIDDER, 160, function(self) addon.AuctionHouse:Sort(self, "highBidder", "Auctions") end) + Columns:Add(CURRENT_BID, 170, function(self) addon.AuctionHouse:Sort(self, "buyoutPrice", "Auctions") end) + + elseif mode == VIEW_BIDS then + Columns:Add(HELPFRAME_ITEM_TITLE, 220, function(self) addon.AuctionHouse:Sort(self, "name", "Bids") end) + Columns:Add(NAME, 160, function(self) addon.AuctionHouse:Sort(self, "owner", "Bids") end) + Columns:Add(CURRENT_BID, 170, function(self) addon.AuctionHouse:Sort(self, "buyoutPrice", "Bids") end) + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/TabCharacters.xml b/Altoholic-Addon/Altoholic/Frames/TabCharacters.xml new file mode 100644 index 0000000..d08c80c --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabCharacters.xml @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 120) + UIDropDownMenu_SetButtonWidth(self, 20) + + local realm = GetRealmName() + UIDropDownMenu_SetSelectedValue(self, "Default|".. realm) + UIDropDownMenu_SetText(self, realm) + UIDropDownMenu_Initialize(self, Altoholic.Tabs.Characters.DropDownRealm_Initialize) + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 120) + UIDropDownMenu_SetButtonWidth(self, 20) + + local realm = GetRealmName() + local player = UnitName("player") + UIDropDownMenu_SetSelectedValue(self, format("%s.%s.%s", "Default", realm, player)) + UIDropDownMenu_SetText(self, player) + UIDropDownMenu_Initialize(self, Altoholic.Tabs.Characters.DropDownChar_Initialize) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Tabs.Characters:OnShow() + + + AltoholicFrameClasses:Hide() + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/TabGuildBank.lua b/Altoholic-Addon/Altoholic/Frames/TabGuildBank.lua new file mode 100644 index 0000000..1ee55e0 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabGuildBank.lua @@ -0,0 +1,153 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local TEAL = "|cFF00FF9A" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +local THIS_ACCOUNT = "Default" + +addon.Tabs.GuildBank = {} + +local ns = addon.Tabs.GuildBank -- ns = namespace + +local function OnGuildChange(self, account, realm) + local _, _, guildname = strsplit("|", self.value) + + UIDropDownMenu_ClearAll(AltoholicTabGuildBank_SelectGuild); + ns:LoadGuild(account, realm, guildname) +end + +local function DropDownGuild_Initialize() + if not addon.db then return end + + local DS = DataStore + + for account in pairs(DS:GetAccounts()) do + for realm in pairs(DS:GetRealms(account)) do + for guildName, guild in pairs(DS:GetGuilds(realm, account)) do + local money = DS:GetGuildBankMoney(guild) + if money then + local info = UIDropDownMenu_CreateInfo(); + + info.text = format("%s %s(%s / %s%s)", GREEN..guildName, WHITE, realm, YELLOW..account, WHITE) + info.value = format("%s|%s|%s", account, realm, guildName) + info.checked = nil; + info.func = OnGuildChange + info.arg1 = account + info.arg2 = realm + UIDropDownMenu_AddButton(info, 1); + end + end + end + end +end + +local initRequired = true + +function ns:OnShow() + if initRequired then + local currentRealm = GetRealmName() + local currentGuild = GetGuildInfo("player") + + -- if the player is not in a guild, set the drop down to the first available guild on this realm, if any. + if not currentGuild then + for guildName, guild in pairs(DataStore:GetGuilds(currentRealm, THIS_ACCOUNT)) do + local money = DataStore:GetGuildBankMoney(guild) + if money then -- if money is not nil, the guild bank has been populated + currentGuild = guildName + break -- if there's at least one guild, let's set the right value and break immediately + end + end + end + + -- if the current guild or at least a guild on this realm was found..set the right values + if currentGuild then + ns:LoadGuild(THIS_ACCOUNT, currentRealm, currentGuild) + end + + UIDropDownMenu_Initialize(AltoholicTabGuildBank_SelectGuild, DropDownGuild_Initialize) + initRequired = nil + end + + addon.GuildBank:DrawTab() +end + +function ns:LoadGuild(account, realm, name) + + local guild = DataStore:GetGuild(name, realm, account) + local money = DataStore:GetGuildBankMoney(guild) + if money then + UIDropDownMenu_SetSelectedValue(AltoholicTabGuildBank_SelectGuild, format("%s|%s|%s", account, realm, name)) + UIDropDownMenu_SetText(AltoholicTabGuildBank_SelectGuild, format("%s%s %s(%s)", GREEN, name, WHITE, realm)) + end + + AltoGuildBank:Hide() + for i = 1, 6 do + _G[ "AltoholicTabGuildBankMenuItem"..i ]:UnlockHighlight(); + + local name = DataStore:GetGuildBankTabName(guild, i) + _G[ "AltoholicTabGuildBankMenuItem" .. i ]:SetText(name and (WHITE..name) or (YELLOW..L["N/A"])) + _G[ "AltoholicTabGuildBankMenuItem" .. i ]:Show() + end + + local altoGuild = addon:GetGuild(name, realm, account) + AltoholicTabGuildBank_HideInTooltip:SetChecked(altoGuild.hideInTooltip) + AltoholicTabGuildBankMoney:SetText(MONEY .. ": " .. addon:GetMoneyString(money or 0, WHITE)) +end + +function ns:HideGuild(self) + + local value = UIDropDownMenu_GetSelectedValue(AltoholicTabGuildBank_SelectGuild) + if not value then return end + + local account, realm, name = strsplit("|", value) + local guild = addon:GetGuild(name, realm, account) + + if self:GetChecked() then + guild.hideInTooltip = true + else + guild.hideInTooltip = nil + end +end + +local function DeleteGuild_MsgBox_Handler(self, button, guildKey) + if not button then return end + + local account, realm, guildName = strsplit("|", guildKey) + local guild = addon:GetGuild(guildName, realm, account) + wipe(guild) + + for i=1, 6 do + _G[ "AltoholicTabGuildBankMenuItem"..i ]:Hide() + end + + AltoholicTabGuildBankInfo1:SetText("") + AltoholicTabGuildBankInfo2:SetText("") + AltoholicTabGuildBankMoney:SetText("") + + AltoGuildBank:Hide() + + DataStore:DeleteGuild(guildName, realm, account) + + UIDropDownMenu_ClearAll(AltoholicTabGuildBank_SelectGuild); + + addon:Print(format( L["Guild %s successfully deleted"], guildName)) +end + +function ns:DeleteGuild() + + local guildKey = UIDropDownMenu_GetSelectedValue(AltoholicTabGuildBank_SelectGuild) + if not guildKey then return end + + addon:SetMsgBoxHandler(DeleteGuild_MsgBox_Handler, guildKey) + + local _, realm, guildName = strsplit("|", guildKey) + + AltoMsgBox_Text:SetText(L["Delete Guild Bank?"] .. "\n" .. GREEN .. guildName .. WHITE .. " (" .. realm .. ")") + AltoMsgBox_Text:SetText(format("%s\n%s%s %s(%s)", L["Delete Guild Bank?"], GREEN, guildName, WHITE, realm )) + AltoMsgBox:Show() +end diff --git a/Altoholic-Addon/Altoholic/Frames/TabGuildBank.xml b/Altoholic-Addon/Altoholic/Frames/TabGuildBank.xml new file mode 100644 index 0000000..70f8d8d --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabGuildBank.xml @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 160) + UIDropDownMenu_SetButtonWidth(self, 20) + + + + + + + + + + + + + + + + + + Altoholic.Tabs.GuildBank:HideGuild(self); + + + + + + + + + + + + + Altoholic.Tabs.GuildBank:OnShow() + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/TabOptions.lua b/Altoholic-Addon/Altoholic/Frames/TabOptions.lua new file mode 100644 index 0000000..da988db --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabOptions.lua @@ -0,0 +1,490 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local TEAL = "|cFF00FF9A" +local ORANGE = "|cFFFF8400" + +local url1 = "http://wow.curse.com/downloads/wow-addons/details/altoholic.aspx" +local url2 = "http://www.wowinterface.com/downloads/info8533-Altoholic.html" +local url3 = "http://wow.curseforge.com/addons/altoholic/localization/" + +local help = { + { name = "General", + questions = { + "How do I remove a character that has been renamed/transfered/deleted?", + "Does Altoholic support command line options?", + "My minimap icon is gone, how do I get it back?", + "What are the official homepages?", + "What is this 'DataStore' thing? Why so many directories?", + "I am developper, I want to know more about DataStore", + "Does the add-on support FuBar?", + "What is the add-on's memory footprint?", + "Where have my suggestions gone?", + }, + answers = { + "Go into the 'Account Summary', mouse over the character, right-click it to get the contextual menu, and select 'Delete this Alt'.", + "Type /alto or /altoholic to get the list of command line options.", + "Go into Altoholic's main option panel, and check 'Show Minimap Icon'.\nYou can also type /alto show.", + format("%s%s\n%s\n%s", "The add-on is only released on these two sites, it is recommended NOT TO get it through other means:", GREEN, url1, url2 ), + "DataStore and its modules take care of storing data for client add-ons; Altoholic itself now only stores very little information. The main purpose of the numerous directories is to offer split databases, instead of one massive database containing all the information required by the add-on.", + "Refer to DataStore's own help topic for more information.", + "Not anymore. Instead, it supports LibDataBroker (aka LDB), if you really want FuBar, use Broker2FuBar.", + "For 10 characters and 1 guild bank, the add-on takes around 4-5mb on my machine. Note that due to its name, the add-on is one of the first in the alphabet, and often gets credited of the memory/cpu usage of its libraries.", + "Development is an iterative process, and I review parts of the add-on constantly. Depending on my spare time, some suggestions might take longer than others to make it into the add-on. Be patient, the add-on is still far from being complete.", + } + }, + { name = "Containers", + questions = { + "Do I have to open all my bags to let the add-on know about their content?", + "What about my bank? .. and my guild bank?", + "Will the content of my bags be visible in the tooltip? Can I configure that?", + }, + answers = { + "No. This happens silently and does not require any action from your part.", + "You have to open your bank in order to let the add-on read its content. Same goes for the guild bank, except that the add-on can only read it tab per tab, so make sure to open them all.", + "Yes. There are several tooltip options that can be set to specify what you want to see or not." + } + }, + { name = "Professions", + questions = { + "Do I have to open all professions manually?", + }, + answers = { + "Yes. Some advanced features require that you open the tradeskill pane once per profession.", + } + }, + { name = "Mails", + questions = { + "Can Altoholic read my mails without being at the mailbox?", + "Altoholic marks all my mails as read, how can I avoid that?", + "My mailbox is full, can Altoholic read beyond the list of visible mails?", + }, + answers = { + "No. This is a restriction imposed by Blizzard. Your character must physically be at a mailbox to retrieve your mails.", + "Go into the 'Mail Options' and disable 'Scan mail body'.", + "No. You will have to clear your mailbox to release mails that are queued server-side.", + } + }, + { name = "Localization", + questions = { + "I found a bad translation, how can I help fixing it?", + }, + answers = { + format("Use the CurseForge localization tool, at %s|r.", GREEN..url3), + } + }, +} + +local support = { + { name = "Reporting Bugs", + questions = { + "I found an error, how/where do I report it?", + "What should I do before reporting?", + "I just upgraded to the latest version, and there are so many Lua errors, what the..??", + "I have multiple Lua errors at login, should I report them all?", + "Thaoky you're so cool, can I hire you?", + }, + answers = { + "Both Curse and WoWInterface have a ticket section, I also read comments and respond as often as I materially can, so feel free to report in one of these places.", + format("%s\n\n%s\n%s\n%s\n%s\n%s\n", + "A few things:", + "1) Make sure you have the latest version of the add-on.", + "2) If you suspect a conflict with another add-on, try to reproduce the issue with only Altoholic enabled. As the add-on deals with a lot of things, a conflict is always possible.", + "3) Make sure your issue has not been reported by someone else.", + "4) Never, ever, report that 'it does not work', this is the most useless sentence in the world! Be specific about what does not work.", + "5) DO NOT copy the entire add-on list from Swatter. While conflicts are possible, they are the exception rather than the rule." + ), + "I'm just human, I make mistakes. But because I'm human, I fix them too, so be patient. This is a project that I develop in my spare time, and it fluctuates a lot.", + "No. Only the first error you will get is relevant, it means that something failed during the initialization process of the add-on, or of a library, and this is likely to cause several subsequent errors that are more often than not irrelevant.", + format("%s\n%s|r\n%s\n%s", + "That would be a very good idea! :)\nFull resume is available on demand, send serious job proposals by mail:", + GREEN.."thaoky.altoholic@yahoo.com", + "Age: 34\nSector: IT\nReady to relocate about anywhere in the EU & the US.", + "Positions sought include (but are not limited to): Project Management, Solutions Architect, Software Development." + ) + } + }, + { name = "Live support", + questions = { + "Is there an IRC channel where I could get live support?", + }, + answers = { + format("Yes. Join the %s#altoholic|r IRC channel on Freenode : %sirc://irc.freenode.net:6667/|r", WHITE, GREEN), + } + }, +} + +-- this content will be subject to frequent changes, do not bother translating it !! +local whatsnew = { + { name = "3.3.002b Changes", + bulletedList = { + "Fixed linking items/quests/etc.. to chat.", + "Several minor bugfixes.", + }, + }, + { name = "3.3.002 Changes", + bulletedList = { + "Added an information tooltip when mousing over the number of mails in the Activity pane.", + "Search is now cancelled if there is no value in the search edit box, except if you're using the categories in the search tab.", + "Reworked item filtering during searches. All types of searches now use the same code path. Also fixed a few filters that were not working properly.", + "Changed the location drop down in the Summary tab, you can now select more combinations of realms/accounts.", + "Added an option to clamp the addon's window to the screen.", + "Fixed skill tooltip displaying 'no data' when mousing over skinning or herbalism.", + "The achievement UI is now a module on its own and is loaded-on-demand. This slightly decreases resource usage if you don't use that part of the UI.", + "You can now fully disable DataStore_Achievements and Altoholic_Achievements if you do not wish to track achievements at all.", + "Winter code cleanup is almost over, almost everything has been reviewed. Next reviews: Calendar & Account Sharing (too big/touchy to review in this pass).", + }, + }, + { name = "3.3.001d Changes", + bulletedList = { + "Fixed several issues with the guild bank tab: deleting a guild, guilds that still appeared in the drop down, etc..", + "Improved the source's description when searching for items located in the guild bank.", + "Fixed an error when changing alt in the 'Characters' tab.", + }, + }, + { name = "3.3.001c Changes", + bulletedList = { + "Added back 'text' field in LDB (conditional, for Broker2FuBar)", + "Fixed LinkWrangler hook.", + "Added support for faction specific achievements. They are now displayed on the same line if a given realm contains characters of the two factions. This used to be a bug/limitation of the system in earlier versions.", + "Guild bank counters from other realms are no longer displayed in the tooltip.", + "Fixed a Lua error in the 'Guild Skills' pane.", + "Added Offline Members to the 'Guild Members' pane. The AiL of an offline member can still be clicked, and if a players' equipment has been checked earlier, it will be displayed.", + "Fixed a few Lua errors.", + "Added an option to show/hide pets already known/could be learned by xx. (Thanks bsmorgan !)", + "Pets/mounts can now be shift-clicked and linked.", + "Expiries that are supposed to be shown in a dialog box will now be printed to the chat frame instead if player is in combat.", + "Changed dependencies in the .toc file, to help the Curse Client with DataStore & its modules.", + "Updated the recipe DB.", + "Updated loot tables (ICC).", + }, + }, + { name = "3.3.001b Changes - The 'Two Year Anniversary Edition'", + bulletedList = { + "Fixed a Lua error in DataStore_Auctions.", + "Fixed missing currencies count to the tooltip.", + "Added a sorted list of achievements in the category 'Dungeons & Raids'.", + "Fixed a tooltip bug where only one of two guilds with the same name would be listed.", + "Added The Ashen Verdict faction.", + }, + }, + { name = "Earlier changes", + textLines = { + "Refer to |cFF00FF00changelog.txt", + }, + }, +} + +Altoholic.Options = {} + +function Altoholic.Options:Init() + -- create categories in Blizzard's options panel + + DataStore:AddOptionCategory(AltoholicGeneralOptions, addonName) + LibStub("LibAboutPanel").new(addonName, addonName); + DataStore:AddOptionCategory(AltoholicHelp, HELP_LABEL, addonName) + DataStore:AddOptionCategory(AltoholicSupport, "Getting support", addonName) + DataStore:AddOptionCategory(AltoholicWhatsNew, "What's new?", addonName) + DataStore:AddOptionCategory(AltoholicSearchOptions, SEARCH, addonName) + DataStore:AddOptionCategory(AltoholicMailOptions, MAIL_LABEL, addonName) + DataStore:AddOptionCategory(AltoholicAccountSharingOptions, L["Account Sharing"], addonName) + DataStore:AddOptionCategory(AltoholicSharedContent, "Shared Content", addonName) + DataStore:AddOptionCategory(AltoholicTooltipOptions, L["Tooltip"], addonName) + DataStore:AddOptionCategory(AltoholicCalendarOptions, L["Calendar"], addonName) + + DataStore:SetupInfoPanel(help, AltoholicHelp_Text) + DataStore:SetupInfoPanel(support, AltoholicSupport_Text) + DataStore:SetupInfoPanel(whatsnew, AltoholicWhatsNew_Text) + + help = nil + support = nil + whatsnew = nil + + local value + + -- ** General ** + AltoholicGeneralOptions_Title:SetText(TEAL..format("%s %s", addonName, addon.Version)) + AltoholicGeneralOptions_RestXPModeText:SetText(L["Max rest XP displayed as 150%"]) + AltoholicGeneralOptions_GuildBankAutoUpdateText:SetText(L["Automatically authorize guild bank updates"]) + AltoholicGeneralOptions_GuildBankAutoUpdate.tooltip = format("%s%s%s", + L["|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users\nto update their guild bank information with yours automatically.\n\n"], + L["When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be\nrequired before sending any information.\n\n"], + L["Security hint: disable this if you have officer rights\non guild bank tabs that may not be viewed by everyone,\nand authorize requests manually"]) + + AltoholicGeneralOptions_ClampWindowToScreenText:SetText(L["Clamp window to screen"]) + + L["|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users\nto update their guild bank information with yours automatically.\n\n"] = nil + L["When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be\nrequired before sending any information.\n\n"] = nil + L["Security hint: disable this if you have officer rights\non guild bank tabs that may not be viewed by everyone,\nand authorize requests manually"] = nil + L["Max rest XP displayed as 150%"] = nil + L["Automatically authorize guild bank updates"] = nil + + value = AltoholicGeneralOptions_SliderAngle:GetValue() + AltoholicGeneralOptions_SliderAngle.tooltipText = L["Move to change the angle of the minimap icon"] + AltoholicGeneralOptions_SliderAngleLow:SetText("1"); + AltoholicGeneralOptions_SliderAngleHigh:SetText("360"); + AltoholicGeneralOptions_SliderAngleText:SetText(format("%s (%s)", L["Minimap Icon Angle"], value)) + L["Move to change the angle of the minimap icon"] = nil + + value = AltoholicGeneralOptions_SliderRadius:GetValue() + AltoholicGeneralOptions_SliderRadius.tooltipText = L["Move to change the radius of the minimap icon"]; + AltoholicGeneralOptions_SliderRadiusLow:SetText("1"); + AltoholicGeneralOptions_SliderRadiusHigh:SetText("200"); + AltoholicGeneralOptions_SliderRadiusText:SetText(format("%s (%s)", L["Minimap Icon Radius"], value)) + L["Move to change the radius of the minimap icon"] = nil + + AltoholicGeneralOptions_ShowMinimapText:SetText(L["Show Minimap Icon"]) + L["Show Minimap Icon"] = nil + + value = AltoholicGeneralOptions_SliderAlpha:GetValue() + AltoholicGeneralOptions_SliderAlphaLow:SetText("0.1"); + AltoholicGeneralOptions_SliderAlphaHigh:SetText("1.0"); + AltoholicGeneralOptions_SliderAlphaText:SetText(format("%s (%1.2f)", L["Transparency"], value)); + + -- ** Search ** + AltoholicSearchOptions_SearchAutoQueryText:SetText(L["AutoQuery server |cFFFF0000(disconnection risk)"]) + AltoholicSearchOptions_SearchAutoQuery.tooltip = format("%s%s%s%s", + L["|cFFFFFFFFIf an item not in the local item cache\nis encountered while searching loot tables,\nAltoholic will attempt to query the server for 5 new items.\n\n"], + L["This will gradually improve the consistency of the searches,\nas more items are available in the item cache.\n\n"], + L["There is a risk of disconnection if the queried item\nis a loot from a high level dungeon.\n\n"], + L["|cFF00FF00Disable|r to avoid this risk"]) + + AltoholicSearchOptions_SortDescendingText:SetText(L["Sort loots in descending order"]) + AltoholicSearchOptions_IncludeNoMinLevelText:SetText(L["Include items without level requirement"]) + AltoholicSearchOptions_IncludeMailboxText:SetText(L["Include mailboxes"]) + AltoholicSearchOptions_IncludeGuildBankText:SetText(L["Include guild bank(s)"]) + AltoholicSearchOptions_IncludeRecipesText:SetText(L["Include known recipes"]) + AltoholicSearchOptions_IncludeGuildSkillsText:SetText(L["Include guild members' professions"]) + L["AutoQuery server |cFFFF0000(disconnection risk)"] = nil + L["Sort loots in descending order"] = nil + L["Include items without level requirement"] = nil + L["Include mailboxes"] = nil + L["Include guild bank(s)"] = nil + L["Include known recipes"] = nil + L["Include guild members' professions"] = nil + + -- ** Mail ** + AltoholicMailOptions_GuildMailWarningText:SetText(L["New mail notification"]) + L["New mail notification"] = nil + + AltoholicMailOptions_GuildMailWarning.tooltip = format("%s", + L["Be informed when a guildmate sends a mail to one of my alts.\n\nMail content is directly visible without having to reconnect the character"]) + + AltoholicMailOptions_NameAutoCompleteText:SetText("Auto-complete recipient name" ) + + -- ** Account Sharing ** + AltoholicAccountSharingOptions_AccSharingCommText:SetText(L["Account Sharing Enabled"]) + AltoholicAccountSharingOptions_AccSharingComm.tooltip = format("%s%s%s%s", + L["|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users\nto send you account sharing requests.\n"], + L["Your confirmation will still be required any time someone requests your information.\n\n"], + L["When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected.\n\n"], + L["Security hint: Only enable this when you actually need to transfer data,\ndisable otherwise"]) + + L["Account Sharing Enabled"] = nil + L["|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users\nto send you account sharing requests.\n"] = nil + L["Your confirmation will still be required any time someone requests your information.\n\n"] = nil + L["When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected.\n\n"] = nil + L["Security hint: Only enable this when you actually need to transfer data,\ndisable otherwise"] = nil + + AltoholicAccountSharingOptionsText1:SetText(WHITE.."Authorizations") + AltoholicAccountSharingOptionsText2:SetText(WHITE..L["Character"]) + AltoholicAccountSharingOptions_InfoButton.tooltip = format("%s\n%s\n\n%s", + + WHITE.."This list allows you to automate responses to account sharing requests.", + "You can choose to automatically accept or reject requests, or be asked when a request comes in.", + "If account sharing is totally disabled, this list will be ignored, and all requests will be rejected." ) + + AltoholicAccountSharingOptionsIconNever:SetText("\124TInterface\\RaidFrame\\ReadyCheck-NotReady:14\124t") + AltoholicAccountSharingOptionsIconAsk:SetText("\124TInterface\\RaidFrame\\ReadyCheck-Waiting:14\124t") + AltoholicAccountSharingOptionsIconAuto:SetText("\124TInterface\\RaidFrame\\ReadyCheck-Ready:14\124t") + + -- ** Shared Content ** + AltoholicSharedContentText1:SetText(WHITE.."Shared Content") + AltoholicSharedContent_SharedContentInfoButton.tooltip = format("%s\n%s", + WHITE.."Select the content that will be visible to players who send you", + "account sharing requests.") + + + -- ** Tooltip ** + AltoholicTooltipOptionsSourceText:SetText(L["Show item source"]) + AltoholicTooltipOptionsCountText:SetText(L["Show item count per character"]) + AltoholicTooltipOptionsTotalText:SetText(L["Show total item count"]) + AltoholicTooltipOptionsRecipeInfoText:SetText(L["Show recipes already known/learnable by"]) + AltoholicTooltipOptionsPetInfoText:SetText(L["Show pets already known/learnable by"]) + AltoholicTooltipOptionsItemIDText:SetText(L["Show item ID and item level"]) + AltoholicTooltipOptionsGatheringNodeText:SetText(L["Show counters on gathering nodes"]) + AltoholicTooltipOptionsCrossFactionText:SetText(L["Show counters for both factions"]) + AltoholicTooltipOptionsMultiAccountText:SetText(L["Show counters for all accounts"]) + AltoholicTooltipOptionsGuildBankText:SetText(L["Show guild bank count"]) + AltoholicTooltipOptionsGuildBankCountText:SetText(L["Include guild bank count in the total count"]) + AltoholicTooltipOptionsGuildBankCountPerTabText:SetText(L["Detailed guild bank count"]) + L["Show item source"] = nil + L["Show item count per character"] = nil + L["Show total item count"] = nil + L["Show guild bank count"] = nil + L["Show already known/learnable by"] = nil + L["Show recipes already known/learnable by"] = nil + L["Show pets already known/learnable by"] = nil + L["Show item ID and item level"] = nil + L["Show counters on gathering nodes"] = nil + L["Show counters for both factions"] = nil + L["Show counters for all accounts"] = nil + L["Include guild bank count in the total count"] = nil + + -- ** Calendar ** + AltoholicCalendarOptionsFirstDayText:SetText(L["Week starts on Monday"]) + AltoholicCalendarOptionsDialogBoxText:SetText(L["Display warnings in a dialog box"]) + AltoholicCalendarOptionsDisableWarningsText:SetText(L["Disable warnings"]) + L["Week starts on Monday"] = nil + L["Warn %d minutes before an event starts"] = nil + L["Display warnings in a dialog box"] = nil + + for i = 1, 4 do + UIDropDownMenu_Initialize(_G["AltoholicCalendarOptions_WarningType"..i], Altoholic.Calendar.WarningType_Initialize) + end + UIDropDownMenu_SetText(AltoholicCalendarOptions_WarningType1, "Profession Cooldowns") + UIDropDownMenu_SetText(AltoholicCalendarOptions_WarningType2, "Dungeon Resets") + UIDropDownMenu_SetText(AltoholicCalendarOptions_WarningType3, "Calendar Events") + UIDropDownMenu_SetText(AltoholicCalendarOptions_WarningType4, "Item Timers") +end + +function Altoholic.Options:RestoreToUI() + local O = Altoholic.db.global.options + + AltoholicGeneralOptions_RestXPMode:SetChecked(O.RestXPMode) + AltoholicGeneralOptions_GuildBankAutoUpdate:SetChecked(O.GuildBankAutoUpdate) + AltoholicGeneralOptions_ClampWindowToScreen:SetChecked(O.ClampWindowToScreen) + + AltoholicGeneralOptions_SliderAngle:SetValue(O.MinimapIconAngle) + AltoholicGeneralOptions_SliderRadius:SetValue(O.MinimapIconRadius) + AltoholicGeneralOptions_ShowMinimap:SetChecked(O.ShowMinimap) + AltoholicGeneralOptions_SliderScale:SetValue(O.UIScale) + AltoholicFrame:SetScale(O.UIScale) + AltoholicGeneralOptions_SliderAlpha:SetValue(O.UITransparency) + + -- set communication handlers according to user settings. + if O.AccSharingHandlerEnabled == 1 then + Altoholic.Comm.Sharing:SetMessageHandler("ActiveHandler") + else + Altoholic.Comm.Sharing:SetMessageHandler("EmptyHandler") + end + + AltoholicSearchOptions_SearchAutoQuery:SetChecked(O.SearchAutoQuery) + AltoholicSearchOptions_SortDescending:SetChecked(O.SortDescending) + AltoholicSearchOptions_IncludeNoMinLevel:SetChecked(O.IncludeNoMinLevel) + AltoholicSearchOptions_IncludeMailbox:SetChecked(O.IncludeMailbox) + AltoholicSearchOptions_IncludeGuildBank:SetChecked(O.IncludeGuildBank) + AltoholicSearchOptions_IncludeRecipes:SetChecked(O.IncludeRecipes) + AltoholicSearchOptions_IncludeGuildSkills:SetChecked(O.IncludeGuildSkills) + AltoholicSearchOptionsLootInfo:SetText(GREEN .. O.TotalLoots .. "|r " .. L["Loots"] .. " / " + .. GREEN .. O.UnknownLoots .. "|r " .. L["Unknown"]) + + AltoholicMailOptions_GuildMailWarning:SetChecked(O.GuildMailWarning) + AltoholicMailOptions_NameAutoComplete:SetChecked(O.NameAutoComplete) + + AltoholicAccountSharingOptions_AccSharingComm:SetChecked(O.AccSharingHandlerEnabled) + + AltoholicTooltipOptionsSource:SetChecked(O.TooltipSource) + AltoholicTooltipOptionsCount:SetChecked(O.TooltipCount) + AltoholicTooltipOptionsTotal:SetChecked(O.TooltipTotal) + AltoholicTooltipOptionsGuildBank:SetChecked(O.TooltipGuildBank) + AltoholicTooltipOptionsGuildBankCount:SetChecked(O.TooltipGuildBankCount) + AltoholicTooltipOptionsGuildBankCountPerTab:SetChecked(O.TooltipGuildBankCountPerTab) + AltoholicTooltipOptionsRecipeInfo:SetChecked(O.TooltipRecipeInfo) + AltoholicTooltipOptionsPetInfo:SetChecked(O.TooltipPetInfo) + AltoholicTooltipOptionsItemID:SetChecked(O.TooltipItemID) + AltoholicTooltipOptionsGatheringNode:SetChecked(O.TooltipGatheringNode) + AltoholicTooltipOptionsCrossFaction:SetChecked(O.TooltipCrossFaction) + AltoholicTooltipOptionsMultiAccount:SetChecked(O.TooltipMultiAccount) + + AltoholicCalendarOptionsFirstDay:SetChecked(O.WeekStartsMonday) + AltoholicCalendarOptionsDialogBox:SetChecked(O.WarningDialogBox) + AltoholicCalendarOptionsDisableWarnings:SetChecked(O.DisableWarnings) +end + +function Altoholic:UpdateMinimapIconCoords() + -- Thanks to Atlas for this code, modified to fit this addon's requirements though + local xPos, yPos = GetCursorPosition() + local left, bottom = Minimap:GetLeft(), Minimap:GetBottom() + + xPos = left - xPos/UIParent:GetScale() + 70 + yPos = yPos/UIParent:GetScale() - bottom - 70 + + local O = self.db.global.options + O.MinimapIconAngle = math.deg(math.atan2(yPos, xPos)) + + if(O.MinimapIconAngle < 0) then + O.MinimapIconAngle = O.MinimapIconAngle + 360 + end + AltoholicGeneralOptions_SliderAngle:SetValue(O.MinimapIconAngle) +end + +function Altoholic:MoveMinimapIcon() + local O = self.db.global.options + + AltoholicMinimapButton:SetPoint( "TOPLEFT", "Minimap", "TOPLEFT", + 54 - (O.MinimapIconRadius * cos(O.MinimapIconAngle)), + (O.MinimapIconRadius * sin(O.MinimapIconAngle)) - 55 ); +end + +function Altoholic.Options:Get(name) + if addon.db and addon.db.global then + return addon.db.global.options[name] + end +end + +function Altoholic.Options:Set(name, value) + if addon.db and addon.db.global then + addon.db.global.options[name] = value + end +end + +function Altoholic.Options:Toggle(self, option) + if self:GetChecked() then + Altoholic.Options:Set(option, 1) + else + Altoholic.Options:Set(option, 0) + end +end + +local function ResizeScrollFrame(frame, width, height) + -- just a small wrapper, nothing generic in here. + + local name = frame:GetName() + _G[name]:SetWidth(width-45) + _G[name.."_ScrollFrame"]:SetWidth(width-45) + _G[name]:SetHeight(height-30) + _G[name.."_ScrollFrame"]:SetHeight(height-30) + _G[name.."_Text"]:SetWidth(width-80) +end + +local OnSizeUpdate = { -- custom resize functions + AltoholicHelp = ResizeScrollFrame, + AltoholicSupport = ResizeScrollFrame, + AltoholicWhatsNew = ResizeScrollFrame, +} + +local OptionsPanelWidth, OptionsPanelHeight +local lastOptionsPanelWidth = 0 +local lastOptionsPanelHeight = 0 + +function Altoholic.Options:OnUpdate(self, mandatoryResize) + OptionsPanelWidth = InterfaceOptionsFramePanelContainer:GetWidth() + OptionsPanelHeight = InterfaceOptionsFramePanelContainer:GetHeight() + + if not mandatoryResize then -- if resize is not mandatory, allow exit + if OptionsPanelWidth == lastOptionsPanelWidth and OptionsPanelHeight == lastOptionsPanelHeight then return end -- no size change ? exit + end + + lastOptionsPanelWidth = OptionsPanelWidth + lastOptionsPanelHeight = OptionsPanelHeight + + local frameName = self:GetName() + if frameName and OnSizeUpdate[frameName] then + OnSizeUpdate[frameName](self, OptionsPanelWidth, OptionsPanelHeight) + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/TabOptions.xml b/Altoholic-Addon/Altoholic/Frames/TabOptions.xml new file mode 100644 index 0000000..e0b4e5c --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabOptions.xml @@ -0,0 +1,1217 @@ + + + + + + + UIDropDownMenu_SetWidth(self, 160) + UIDropDownMenu_SetButtonWidth(self, 20) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "RestXPMode") + Altoholic.Summary:Update() + + + + + + + + + + + + + + + + + if self:GetChecked() then + Altoholic.Options:Set("GuildBankAutoUpdate", 1) + else + Altoholic.Options:Set("GuildBankAutoUpdate", 0) + end + + + Altoholic:ShowWidgetTooltip(self) + + + AltoTooltip:Hide(); + + + + + + + + + + + + + + + + + AltoholicFrame:SetClampedToScreen(self:GetChecked()) + if self:GetChecked() then + Altoholic.Options:Set("ClampWindowToScreen", 1) + else + Altoholic.Options:Set("ClampWindowToScreen", 0) + end + + + Altoholic:ShowWidgetTooltip(self) + + + AltoTooltip:Hide(); + + + + + + + + + + + + + + + + + + if self:GetChecked() then + Altoholic.Options:Set("ShowMinimap", 1) + AltoholicMinimapButton:Show() + else + Altoholic.Options:Set("ShowMinimap", 0) + AltoholicMinimapButton:Hide() + end + + + + + + + + + + + + + + + + + local L = LibStub("AceLocale-3.0"):GetLocale("Altoholic") + Altoholic:UpdateSlider(self:GetName(), L["Minimap Icon Angle"], "MinimapIconAngle") + + + + + + + + + + + + + + + + + local L = LibStub("AceLocale-3.0"):GetLocale("Altoholic") + Altoholic:UpdateSlider(self:GetName(), L["Minimap Icon Radius"], "MinimapIconRadius") + + + + + + + + + + + + + + + + + + local name = self:GetName() + _G[name .. "Low"]:SetText("0.5"); + _G[name .. "High"]:SetText("4.0"); + _G[name .. "Text"]:SetText(format("%s (%1.1f)", UI_SCALE, self:GetValue())); + + + local value = self:GetValue() + _G[self:GetName() .. "Text"]:SetText(format("%s (%1.1f)", UI_SCALE, value)); + + + + + + + + + + + + + + + + + + + local L = LibStub("AceLocale-3.0"):GetLocale("Altoholic") + + local value = self:GetValue() + _G[self:GetName() .. "Text"]:SetText(format("%s (%1.2f)", L["Transparency"], value)); + AltoholicFrame:SetAlpha(value) + Altoholic.Options:Set("UITransparency", value) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "SearchAutoQuery") + + + Altoholic:ShowWidgetTooltip(self) + + + AltoTooltip:Hide(); + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "SortDescending") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "IncludeNoMinLevel") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "IncludeMailbox") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "IncludeGuildBank") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "IncludeRecipes") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "IncludeGuildSkills") + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "GuildMailWarning") + + + Altoholic:ShowWidgetTooltip(self) + + + AltoTooltip:Hide(); + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "NameAutoComplete") + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipSource") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipCount") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipTotal") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipRecipeInfo") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipPetInfo") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipItemID") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipGatheringNode") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipCrossFaction") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipMultiAccount") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipGuildBank") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipGuildBankCount") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "TooltipGuildBankCountPerTab") + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + if self:GetChecked() then + Altoholic.Options:Set("AccSharingHandlerEnabled", 1) + Altoholic.Comm.Sharing:SetMessageHandler("ActiveHandler") + else + Altoholic.Options:Set("AccSharingHandlerEnabled", 0) + Altoholic.Comm.Sharing:SetMessageHandler("EmptyHandler") + end + + + Altoholic:ShowWidgetTooltip(self) + + + AltoTooltip:Hide(); + + + + + + + + + + + + + + + + self:SetAutoFocus( true ); + + + self:ClearFocus(); + self:SetFocus(); + Altoholic.Sharing.Clients:Add( self:GetText() ) + Altoholic.Sharing.Clients:Update() + + + if self:GetText() == "" then + Altoholic:ToggleUI() + else + self:SetText("") + end + + + + + + + + + Altoholic.Sharing.Clients:Update() + + + + + + + + + + + Altoholic.Sharing.Content:BuildView() + Altoholic.Sharing.Content:Update() + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + _G[self:GetName() .. "Text"]:SetText(ALL) + + + Altoholic.Sharing.Content:CheckAll(self, button) + + + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "WeekStartsMonday") + if self:GetChecked() then + Altoholic.Calendar:SetFirstDayOfWeek(2) + else + Altoholic.Calendar:SetFirstDayOfWeek(1) + end + Altoholic.Calendar:Update() + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "WarningDialogBox") + + + + + + + + + + + + + + + + + Altoholic.Options:Toggle(self, "DisableWarnings") + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Options:OnUpdate(self) + + + Altoholic.Options:OnUpdate(self, true) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Options:OnUpdate(self) + + + Altoholic.Options:OnUpdate(self, true) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Altoholic.Options:OnUpdate(self) + + + Altoholic.Options:OnUpdate(self, true) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Altoholic-Addon/Altoholic/Frames/TabSearch.lua b/Altoholic-Addon/Altoholic/Frames/TabSearch.lua new file mode 100644 index 0000000..3ea85a3 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabSearch.lua @@ -0,0 +1,343 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local RED = "|cFFFF0000" + +local view +local highlightIndex + +addon.Tabs.Search = {} + +local ns = addon.Tabs.Search -- ns = namespace + +local function BuildView() + view = view or {} + wipe(view) + + local itemClasses = { GetAuctionItemClasses() }; + local classNum = 1 + for _, itemClass in pairs(itemClasses) do + table.insert(view, { name = itemClass, isCollapsed = true } ) + table.insert(view, L["Any"] ) + + local itemSubClasses = { GetAuctionItemSubClasses(classNum) }; + for _, itemSubClass in pairs(itemSubClasses) do + table.insert(view, itemSubClass ) + end + + classNum = classNum + 1 + end +end + +local function Header_OnClick(frame) + local header = view[frame.itemTypeIndex] + header.isCollapsed = not header.isCollapsed + + -- if header.isCollapsed == true then + -- header.isCollapsed = false + -- else + -- header.isCollapsed = true + -- end + ns:Update() +end + +local function Item_OnClick(frame) + local itemType = frame.itemTypeIndex + local itemSubType = frame.itemSubTypeIndex + + highlightIndex = itemSubType + ns:Update() + + -- around 5-7 ms on the current realm, 25-40 ms in the loot tables + if view[itemSubType] == L["Any"] then + addon.Search:FindItem(view[itemType].name) + else + addon.Search:FindItem(view[itemType].name, view[itemSubType]) + end +end + +function ns:Update() + if not view then + BuildView() + end + + local VisibleLines = 15 + + local itemTypeIndex -- index of the item type in the menu table + local itemTypeCacheIndex -- index of the item type in the cache table + local MenuCache = {} + + for k, v in pairs (view) do -- rebuild the cache + if type(v) == "table" then -- header + itemTypeIndex = k + table.insert(MenuCache, { linetype=1, nameIndex=k } ) + itemTypeCacheIndex = #MenuCache + else + if view[itemTypeIndex].isCollapsed == false then + table.insert(MenuCache, { linetype=2, nameIndex=k, parentIndex=itemTypeIndex } ) + + if (highlightIndex) and (highlightIndex == k) then + MenuCache[#MenuCache].needsHighlight = true + MenuCache[itemTypeCacheIndex].needsHighlight = true + end + end + end + end + + local buttonWidth = 156 + if #MenuCache > 15 then + buttonWidth = 136 + end + + local offset = FauxScrollFrame_GetOffset( _G[ "AltoholicSearchMenuScrollFrame" ] ); + local itemButtom = "AltoholicTabSearchMenuItem" + for i=1, VisibleLines do + local line = i + offset + + if line > #MenuCache then + _G[itemButtom..i]:Hide() + else + local p = MenuCache[line] + + _G[itemButtom..i]:SetWidth(buttonWidth) + _G[itemButtom..i.."NormalText"]:SetWidth(buttonWidth - 21) + if p.needsHighlight then + _G[itemButtom..i]:LockHighlight() + else + _G[itemButtom..i]:UnlockHighlight() + end + + if p.linetype == 1 then + _G[itemButtom..i.."NormalText"]:SetText(WHITE .. view[p.nameIndex].name) + _G[itemButtom..i]:SetScript("OnClick", Header_OnClick) + _G[itemButtom..i].itemTypeIndex = p.nameIndex + elseif p.linetype == 2 then + _G[itemButtom..i.."NormalText"]:SetText("|cFFBBFFBB " .. view[p.nameIndex]) + _G[itemButtom..i]:SetScript("OnClick", Item_OnClick) + _G[itemButtom..i].itemTypeIndex = p.parentIndex + _G[itemButtom..i].itemSubTypeIndex = p.nameIndex + end + + _G[itemButtom..i]:Show() + end + end + + FauxScrollFrame_Update( _G[ "AltoholicSearchMenuScrollFrame" ], #MenuCache, VisibleLines, 20); +end + +function ns:Reset() + AltoholicFrame_SearchEditBox:SetText("") + AltoholicTabSearch_MinLevel:SetText("") + AltoholicTabSearch_MaxLevel:SetText("") + AltoholicTabSearchStatus:SetText("") -- .. the search results + AltoholicFrameSearch:Hide() + addon.Search:ClearResults() + collectgarbage() + + if view then + for k, v in pairs(view) do -- rebuild the cache + if type(v) == "table" then -- header + v.isCollapsed = true + end + end + end + highlightIndex = nil + + for i = 1, 8 do + _G[ "AltoholicTabSearch_Sort"..i ]:Hide() + _G[ "AltoholicTabSearch_Sort"..i ].ascendingSort = nil + end + ns:Update() +end + +function ns:DropDownRarity_Initialize() + local info = UIDropDownMenu_CreateInfo(); + + for i = 0, 6 do -- Quality: 0 = poor .. 5 = legendary + info.text = ITEM_QUALITY_COLORS[i].hex .. _G["ITEM_QUALITY"..i.."_DESC"] + info.value = i + info.func = function(self) + UIDropDownMenu_SetSelectedValue(AltoholicTabSearch_SelectRarity, self.value); + end + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + end +end + +function ns:DropDownSlot_Initialize() + local function SetSearchSlot(self) + UIDropDownMenu_SetSelectedValue(AltoholicTabSearch_SelectSlot, self.value); + end + + local info = UIDropDownMenu_CreateInfo(); + info.text = L["Any"] + info.value = 0 + info.func = SetSearchSlot + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + + for i = 1, 18 do + info.text = addon.Equipment:GetSlotName(i) + info.value = i + info.func = SetSearchSlot + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + end +end + +function ns:DropDownLocation_Initialize() + local info = UIDropDownMenu_CreateInfo(); + local text = { + L["This character"], + format("%s %s(%s)", L["This realm"], GREEN, L["This faction"]), + format("%s %s(%s)", L["This realm"], GREEN, L["Both factions"]), + L["All realms"], + L["All accounts"], + L["Loot tables"] + } + + for i = 1, #text do + info.text = text[i] + info.value = i + info.func = function(self) + UIDropDownMenu_SetSelectedValue(AltoholicTabSearch_SelectLocation, self.value) + end + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + end +end + +function ns:SetMode(mode) + + local Columns = addon.Tabs.Columns + Columns:Init() + + -- sets the search mode, and prepares the frame accordingly (search update callback, column sizes, headers, etc..) + if mode == "realm" then + addon.Search:SetUpdateHandler("Realm_Update") + + Columns:Add(L["Item / Location"], 240, function(self) addon.Search:SortResults(self, "name") end) + Columns:Add(L["Character"], 160, function(self) addon.Search:SortResults(self, "char") end) + Columns:Add(L["Realm"], 150, function(self) addon.Search:SortResults(self, "realm") end) + + AltoholicTabSearch_Sort2:SetPoint("LEFT", AltoholicTabSearch_Sort1, "RIGHT", 5, 0) + AltoholicTabSearch_Sort3:SetPoint("LEFT", AltoholicTabSearch_Sort2, "RIGHT", 5, 0) + + for i=1, 7 do + _G[ "AltoholicFrameSearchEntry"..i.."Name" ]:SetWidth(240) + _G[ "AltoholicFrameSearchEntry"..i.."Stat1" ]:SetWidth(160) + _G[ "AltoholicFrameSearchEntry"..i.."Stat1" ]:SetPoint("LEFT", _G[ "AltoholicFrameSearchEntry"..i.."Name" ], "RIGHT", 5, 0) + _G[ "AltoholicFrameSearchEntry"..i.."Stat2" ]:SetWidth(150) + _G[ "AltoholicFrameSearchEntry"..i.."Stat2" ]:SetPoint("LEFT", _G[ "AltoholicFrameSearchEntry"..i.."Stat1" ], "RIGHT", 5, 0) + + for j=3, 6 do + _G[ "AltoholicFrameSearchEntry"..i.."Stat"..j ]:Hide() + end + _G[ "AltoholicFrameSearchEntry"..i.."ILvl" ]:Hide() + + _G[ "AltoholicFrameSearchEntry"..i ]:SetScript("OnEnter", nil) + _G[ "AltoholicFrameSearchEntry"..i ]:SetScript("OnLeave", nil) + end + + elseif mode == "loots" then + addon.Search:SetUpdateHandler("Loots_Update") + + Columns:Add(L["Item / Location"], 240, function(self) addon.Search:SortResults(self, "item") end) + Columns:Add(L["Source"], 160, function(self) addon.Search:SortResults(self, "bossName") end) + Columns:Add(L["Item Level"], 150, function(self) addon.Search:SortResults(self, "iLvl") end) + + AltoholicTabSearch_Sort2:SetPoint("LEFT", AltoholicTabSearch_Sort1, "RIGHT", 5, 0) + AltoholicTabSearch_Sort3:SetPoint("LEFT", AltoholicTabSearch_Sort2, "RIGHT", 5, 0) + + for i=1, 7 do + _G[ "AltoholicFrameSearchEntry"..i.."Name" ]:SetWidth(240) + _G[ "AltoholicFrameSearchEntry"..i.."Stat1" ]:SetWidth(160) + _G[ "AltoholicFrameSearchEntry"..i.."Stat1" ]:SetPoint("LEFT", _G[ "AltoholicFrameSearchEntry"..i.."Name" ], "RIGHT", 5, 0) + _G[ "AltoholicFrameSearchEntry"..i.."Stat2" ]:SetWidth(150) + _G[ "AltoholicFrameSearchEntry"..i.."Stat2" ]:SetPoint("LEFT", _G[ "AltoholicFrameSearchEntry"..i.."Stat1" ], "RIGHT", 5, 0) + + for j=3, 6 do + _G[ "AltoholicFrameSearchEntry"..i.."Stat"..j ]:Hide() + end + _G[ "AltoholicFrameSearchEntry"..i.."ILvl" ]:Hide() + + _G[ "AltoholicFrameSearchEntry"..i ]:SetScript("OnEnter", nil) + _G[ "AltoholicFrameSearchEntry"..i ]:SetScript("OnLeave", nil) + end + + elseif mode == "upgrade" then + addon.Search:SetUpdateHandler("Upgrade_Update") + + Columns:Add(L["Item / Location"], 200, function(self) addon.Search:SortResults(self, "item") end) + + for i=1, 6 do + local text = select(i, strsplit("|", addon.Equipment.FormatStats[addon.Search:GetClass()])) + + if text then + Columns:Add(string.sub(text, 1, 3), 50, function(self) + addon.Search:SortResults(self, "stat") -- use a getID to know which stat + end) + else + Columns:Add(nil) + end + end + + AltoholicTabSearch_Sort2:SetPoint("LEFT", AltoholicTabSearch_Sort1, "RIGHT", 0, 0) + AltoholicTabSearch_Sort3:SetPoint("LEFT", AltoholicTabSearch_Sort2, "RIGHT", 0, 0) + + Columns:Add("iLvl", 50, function(self) addon.Search:SortResults(self, "iLvl") end) + + for i=1, 7 do + _G[ "AltoholicFrameSearchEntry"..i.."Name" ]:SetWidth(190) + _G[ "AltoholicFrameSearchEntry"..i.."Stat1" ]:SetWidth(50) + _G[ "AltoholicFrameSearchEntry"..i.."Stat1" ]:SetPoint("LEFT", _G[ "AltoholicFrameSearchEntry"..i.."Name" ], "RIGHT", 0, 0) + _G[ "AltoholicFrameSearchEntry"..i.."Stat2" ]:SetWidth(50) + _G[ "AltoholicFrameSearchEntry"..i.."Stat2" ]:SetPoint("LEFT", _G[ "AltoholicFrameSearchEntry"..i.."Stat1" ], "RIGHT", 0, 0) + + _G[ "AltoholicFrameSearchEntry"..i ]:SetScript("OnEnter", function(self) + ns:TooltipStats(self) + end) + _G[ "AltoholicFrameSearchEntry"..i ]:SetScript("OnLeave", function(self) + AltoTooltip:Hide() + end) + end + end +end + +function ns:TooltipStats(frame) + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + + AltoTooltip:AddLine(STATS_LABEL) + AltoTooltip:AddLine(" "); + + local s = addon.Search:GetResult(frame:GetID()) + + for i=1, 6 do + local text = select(i, strsplit("|", addon.Equipment.FormatStats[addon.Search:GetClass()])) + if text then + local color + local diff = select(2, strsplit("|", s["stat"..i])) + diff = tonumber(diff) + + if diff < 0 then + color = RED + elseif diff > 0 then + color = GREEN + diff = "+" .. diff + else + color = WHITE + end + AltoTooltip:AddLine(format("%s%s %s", color, diff, text)) + end + end + AltoTooltip:Show() +end diff --git a/Altoholic-Addon/Altoholic/Frames/TabSearch.xml b/Altoholic-Addon/Altoholic/Frames/TabSearch.xml new file mode 100644 index 0000000..a97ed71 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabSearch.xml @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 20, Altoholic.Tabs.Search.Update) + + + Altoholic.Tabs.Search:Update() + + + + + + + + + + + + + + self:ClearFocus(); + + + + + + + + + + + + + self:ClearFocus(); + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 100) + UIDropDownMenu_SetButtonWidth(self, 20) + UIDropDownMenu_Initialize(self, Altoholic.Tabs.Search.DropDownRarity_Initialize) + UIDropDownMenu_SetSelectedValue(self, 0); + UIDropDownMenu_SetText(self, ITEM_QUALITY_COLORS[0].hex .. _G["ITEM_QUALITY0_DESC"]) + + + + + + + + + + + + + + local L = LibStub("AceLocale-3.0"):GetLocale("Altoholic") + + UIDropDownMenu_SetWidth(self, 80) + UIDropDownMenu_SetButtonWidth(self, 20) + UIDropDownMenu_Initialize(self, Altoholic.Tabs.Search.DropDownSlot_Initialize) + UIDropDownMenu_SetSelectedValue(self, 0); + UIDropDownMenu_SetText(self, L["Any"]) + + + + + + + + + + + + + + local L = LibStub("AceLocale-3.0"):GetLocale("Altoholic") + + UIDropDownMenu_SetWidth(self, 150) + UIDropDownMenu_SetButtonWidth(self, 20) + UIDropDownMenu_Initialize(self, Altoholic.Tabs.Search.DropDownLocation_Initialize) + UIDropDownMenu_SetSelectedValue(self, 2); + UIDropDownMenu_SetText(self, format("%s %s(%s)", L["This realm"], "|cFF00FF00", L["This faction"])) + + + + + + + + + + + + + + + + + Altoholic.Tabs.Search:Update() + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/TabSummary.lua b/Altoholic-Addon/Altoholic/Frames/TabSummary.lua new file mode 100644 index 0000000..866c078 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabSummary.lua @@ -0,0 +1,275 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local GREEN = "|cFF00FF00" + +local THISREALM_THISACCOUNT = 1 +local THISREALM_ALLACCOUNTS = 2 +local ALLREALMS_THISACCOUNT = 3 +local ALLREALMS_ALLACCOUNTS = 4 + +local currentMode + +local childrenFrames = { + "Summary", + "BagUsage", + "Skills", + "Activity", + "GuildMembers", + "GuildProfessions", + "GuildBankTabs", + "Calendar", +} + +local childrenObjects -- these are the tables that actually contain the BuildView & Update methods. Not really OOP, but enough for our needs + +addon.Tabs.Summary = {} + +local ns = addon.Tabs.Summary -- ns = namespace + +local locationLabels = { + [THISREALM_THISACCOUNT] = format("%s %s(%s)", L["This realm"], GREEN, L["This account"]), + [THISREALM_ALLACCOUNTS] = format("%s %s(%s)", L["This realm"], GREEN, L["All accounts"]), + [ALLREALMS_THISACCOUNT] = format("%s %s(%s)", L["All realms"], GREEN, L["This account"]), + [ALLREALMS_ALLACCOUNTS] = format("%s %s(%s)", L["All realms"], GREEN, L["All accounts"]), +} + +local function OnRealmFilterChange(self) + UIDropDownMenu_SetSelectedValue(AltoholicTabSummary_SelectLocation, self.value); + + addon.Options:Set("TabSummaryMode", self.value) + addon.Characters:BuildList() + addon.Characters:BuildView() + ns:Refresh() +end + +local function DropDownLocation_Initialize() + local info = UIDropDownMenu_CreateInfo(); + + info.text = locationLabels[THISREALM_THISACCOUNT] + info.value = THISREALM_THISACCOUNT + info.func = OnRealmFilterChange + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + + info.text = locationLabels[THISREALM_ALLACCOUNTS] + info.value = THISREALM_ALLACCOUNTS + info.func = OnRealmFilterChange + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + + info.text = locationLabels[ALLREALMS_THISACCOUNT] + info.value = ALLREALMS_THISACCOUNT + info.func = OnRealmFilterChange + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); + + info.text = locationLabels[ALLREALMS_ALLACCOUNTS] + info.value = ALLREALMS_ALLACCOUNTS + info.func = OnRealmFilterChange + info.checked = nil; + info.icon = nil; + UIDropDownMenu_AddButton(info, 1); +end + +function ns:Init() + childrenObjects = { + addon.Summary, + addon.BagUsage, + addon.TradeSkills, + addon.Activity, + addon.Guild.Members, + addon.Guild.Professions, + addon.Guild.BankTabs, + addon.Calendar, + } + + local f = AltoholicTabSummary_SelectLocation + UIDropDownMenu_SetSelectedValue(f, addon.Options:Get("TabSummaryMode")) + UIDropDownMenu_SetText(f, select(addon.Options:Get("TabSummaryMode"), locationLabels[THISREALM_THISACCOUNT], locationLabels[THISREALM_ALLACCOUNTS], locationLabels[ALLREALMS_THISACCOUNT], locationLabels[ALLREALMS_ALLACCOUNTS])) + UIDropDownMenu_Initialize(f, DropDownLocation_Initialize) + + addon.Calendar:Init() +end + +function ns:MenuItem_OnClick(id) + for _, v in pairs(childrenFrames) do -- hide all frames + _G[ "AltoholicFrame" .. v]:Hide() + end + + ns:SetMode(id) + + if id == 5 then -- specific treatment per frame goes here + if IsInGuild() then + GuildRoster() + end + end + + local f = _G[ "AltoholicFrame" .. childrenFrames[id]] + local o = childrenObjects[id] + + if o.BuildView then + o:BuildView() + end + f:Show() + o:Update() + + for i=1, 8 do + _G[ "AltoholicTabSummaryMenuItem"..i ]:UnlockHighlight(); + end + _G[ "AltoholicTabSummaryMenuItem"..id ]:LockHighlight(); +end + +function ns:SetMode(mode) + currentMode = mode + + AltoholicTabSummaryStatus:SetText("") + AltoholicTabSummaryToggleView:Show() + AltoholicTabSummary_SelectLocation:Show() + AltoholicTabSummary_RequestSharing:Show() + AltoholicTabSummary_Options:Show() + AltoholicTabSummary_OptionsDataStore:Show() + + local Columns = addon.Tabs.Columns + Columns:Init() + + local title + + if currentMode == 1 then + Columns:Add(NAME, 100, function(self) addon.Characters:Sort(self, "GetCharacterName") end) + Columns:Add(LEVEL, 60, function(self) addon.Characters:Sort(self, "GetCharacterLevel") end) + Columns:Add(MONEY, 115, function(self) addon.Characters:Sort(self, "GetMoney") end) + Columns:Add(PLAYED, 105, function(self) addon.Characters:Sort(self, "GetPlayTime") end) + Columns:Add(XP, 55, function(self) addon.Characters:Sort(self, "GetXPRate") end) + Columns:Add(TUTORIAL_TITLE26, 70, function(self) addon.Characters:Sort(self, "GetRestXPRate") end) + Columns:Add("AiL", 55, function(self) addon.Characters:Sort(self, "GetAverageItemLevel") end) + + elseif currentMode == 2 then + Columns:Add(NAME, 100, function(self) addon.Characters:Sort(self, "GetCharacterName") end) + Columns:Add(LEVEL, 60, function(self) addon.Characters:Sort(self, "GetCharacterLevel") end) + Columns:Add(L["Bags"], 120, function(self) addon.Characters:Sort(self, "GetNumBagSlots") end) + Columns:Add(L["free"], 50, function(self) addon.Characters:Sort(self, "GetNumFreeBagSlots") end) + Columns:Add(L["Bank"], 190, function(self) addon.Characters:Sort(self, "GetNumBankSlots") end) + Columns:Add(L["free"], 50, function(self) addon.Characters:Sort(self, "GetNumFreeBankSlots") end) + + elseif currentMode == 3 then + Columns:Add(NAME, 100, function(self) addon.Characters:Sort(self, "GetCharacterName") end) + Columns:Add(LEVEL, 60, function(self) addon.Characters:Sort(self, "GetCharacterLevel") end) + Columns:Add(L["Prof. 1"], 65, function(self) addon.Characters:Sort(self, "skillName1") end) + Columns:Add(L["Prof. 2"], 65, function(self) addon.Characters:Sort(self, "skillName2") end) + title = GetSpellInfo(2550) -- cooking + Columns:Add(title, 65, function(self) addon.Characters:Sort(self, "GetCookingRank") end) + title = GetSpellInfo(3273) -- First Aid + Columns:Add(title, 65, function(self) addon.Characters:Sort(self, "GetFirstAidRank") end) + title = GetSpellInfo(24303) -- Fishing + Columns:Add(title, 65, function(self) addon.Characters:Sort(self, "GetFishingRank") end) + Columns:Add(L["Riding"], 65, function(self) addon.Characters:Sort(self, "GetRidingRank") end) + + elseif currentMode == 4 then + Columns:Add(NAME, 100, function(self) addon.Characters:Sort(self, "GetCharacterName") end) + Columns:Add(LEVEL, 60, function(self) addon.Characters:Sort(self, "GetCharacterLevel") end) + Columns:Add(L["Mails"], 60, function(self) addon.Characters:Sort(self, "GetNumMails") end) + Columns:Add(L["Visited"], 60, function(self) addon.Characters:Sort(self, "GetMailboxLastVisit") end) + Columns:Add(AUCTIONS, 70, function(self) addon.Characters:Sort(self, "GetNumAuctions") end) + Columns:Add(BIDS, 60, function(self) addon.Characters:Sort(self, "GetNumBids") end) + Columns:Add(L["Visited"], 60, function(self) addon.Characters:Sort(self, "GetAuctionHouseLastVisit") end) + Columns:Add(LASTONLINE, 90, function(self) addon.Characters:Sort(self, "GetLastLogout") end) + + elseif currentMode == 5 then + Columns:Add(NAME, 100, function(self) addon.Guild.Members:Sort(self, "name") end) + Columns:Add(LEVEL, 60, function(self) addon.Guild.Members:Sort(self, "level") end) + Columns:Add("AiL", 65, function(self) addon.Guild.Members:Sort(self, "averageItemLvl") end) + Columns:Add(GAME_VERSION_LABEL, 80, function(self) addon.Guild.Members:Sort(self, "version") end) + Columns:Add(CLASS, 100, function(self) addon.Guild.Members:Sort(self, "englishClass") end) + + elseif currentMode == 6 then + Columns:Add(NAME, 60, function(self) addon.Guild.Professions:Sort(self, "name") end) + Columns:Add(LEVEL, 60, function(self) addon.Guild.Professions:Sort(self, "level") end) + Columns:Add(CLASS, 120, function(self) addon.Guild.Professions:Sort(self, "englishClass") end) + Columns:Add(L["Prof. 1"], 110, function(self) addon.Guild.Professions:Sort(self, "profLink", 1) end) + Columns:Add(L["Prof. 2"], 110, function(self) addon.Guild.Professions:Sort(self, "profLink", 2) end) + title = GetSpellInfo(2550) -- cooking + Columns:Add(title, 110, function(self) addon.Guild.Professions:Sort(self, "profLink", 3) end) + + elseif currentMode == 7 then + Columns:Add(NAME, 100, nil) + Columns:Add(TIMEMANAGER_TOOLTIP_LOCALTIME, 120, nil) + Columns:Add(TIMEMANAGER_TOOLTIP_REALMTIME, 120, nil) + elseif currentMode == 8 then + AltoholicTabSummaryToggleView:Hide() + AltoholicTabSummary_SelectLocation:Hide() + AltoholicTabSummary_RequestSharing:Hide() + AltoholicTabSummary_Options:Hide() + AltoholicTabSummary_OptionsDataStore:Hide() + end +end + +function ns:Refresh() + if AltoholicFrameSummary:IsVisible() then + addon.Summary:Update() + elseif AltoholicFrameBagUsage:IsVisible() then + addon.BagUsage:Update() + elseif AltoholicFrameSkills:IsVisible() then + addon.TradeSkills:Update() + elseif AltoholicFrameActivity:IsVisible() then + addon.Activity:Update() + elseif AltoholicFrameGuildMembers:IsVisible() then + addon.Guild.Members:Update() + elseif AltoholicFrameGuildProfessions:IsVisible() then + addon.Guild.Professions:Update() + elseif AltoholicFrameGuildBankTabs:IsVisible() then + addon.Guild.BankTabs:Update() + elseif AltoholicFrameCalendar:IsVisible() then + addon.Calendar.Events:BuildList() + addon.Calendar:Update() + end +end + +function ns:ToggleView(frame) + if not frame.isCollapsed then + frame.isCollapsed = true + AltoholicTabSummaryToggleView:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up"); + else + frame.isCollapsed = nil + AltoholicTabSummaryToggleView:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up"); + end + + if (currentMode >= 1) and (currentMode <= 4) then + addon.Characters:ToggleView(frame) + ns:Refresh() + elseif currentMode == 5 then + addon.Guild.Members:ToggleView(frame) + elseif currentMode == 6 then + addon.Guild.Professions:ToggleView(frame) + elseif currentMode == 7 then + addon.Guild.BankTabs:ToggleView(frame) + end +end + +function ns:AccountSharingButton_OnEnter(self) + AltoTooltip:SetOwner(self, "ANCHOR_RIGHT") + AltoTooltip:ClearLines() + AltoTooltip:SetText(L["Account Sharing Request"]) + AltoTooltip:AddLine(L["Click this button to ask a player\nto share his entire Altoholic Database\nand add it to your own"],1,1,1) + AltoTooltip:Show() +end + +function ns:AccountSharingButton_OnClick() + if addon.Options:Get("AccSharingHandlerEnabled") == 0 then + addon:Print(L["Both parties must enable account sharing\nbefore using this feature (see options)"]) + return + end + addon:ToggleUI() + + if AltoAccountSharing_SendButton.requestMode then + addon.Comm.Sharing:SetMode(2) + else + addon.Comm.Sharing:SetMode(1) + end + AltoAccountSharing:Show() +end diff --git a/Altoholic-Addon/Altoholic/Frames/TabSummary.xml b/Altoholic-Addon/Altoholic/Frames/TabSummary.xml new file mode 100644 index 0000000..f0255ff --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/TabSummary.xml @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UIDropDownMenu_SetWidth(self, 180) + UIDropDownMenu_SetButtonWidth(self, 20) + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Frames/Talents.lua b/Altoholic-Addon/Altoholic/Frames/Talents.lua new file mode 100644 index 0000000..6d83670 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Talents.lua @@ -0,0 +1,630 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" + +addon.Talents = {} +addon.Glyphs = {} + +local tns = addon.Talents -- tns = talents namespace +local gns = addon.Glyphs -- gns = glyphs namespace + +local currentTalentGroup + +-- ** Arrows ** +local INITIAL_OFFSET_X = 25 -- constants used for positioning talents +local INITIAL_OFFSET_Y = 15 +local TALENT_OFFSET_X = 62 +local TALENT_OFFSET_Y = 55 + +local numArrows + +local function ResetArrowCount() + numArrows = 1 +end + +local function HideUnusedArrows() + while numArrows <= 30 do + _G["AltoholicFrameTalents_Arrow" .. numArrows]:Hide() + numArrows = numArrows + 1 + end + numArrows = nil +end + +local function DrawArrow(tier, column, prereqTier, prereqColumn, blocked) + local arrowType -- algorithm taken from TalentFrameBase.lua, adjusted for my needs + + if (column == prereqColumn) then -- Same column ? ==> TOP + arrowType = "top" + elseif (tier == prereqTier) then -- Same tier ? ==> LEFT or RIGHT + if (column < prereqColumn) then + arrowType = "right" + else + arrowType = "left" + end + else -- None of these ? ==> diagonal + if not blocked then + arrowType = "top" + else + if (column < prereqColumn) then + arrowType = "right" + else + arrowType = "left" + end + end + end + + if not arrowType then + return + end + + local x, y + if arrowType == "top" then + x = 2 + y = 18 + elseif arrowType == "left" then + x = -17 + y = -2 + elseif arrowType == "right" then + x = 22 + y = -2 + end + + x = x + INITIAL_OFFSET_X + ((column-1) * TALENT_OFFSET_X) + y = y - (INITIAL_OFFSET_Y + ((tier-1) * TALENT_OFFSET_Y)) + + local arrow = _G["AltoholicFrameTalents_Arrow" .. numArrows] + local tc = TALENT_ARROW_TEXTURECOORDS[arrowType][1] + + arrow:SetTexCoord(tc[1], tc[2], tc[3], tc[4]); + arrow:SetPoint("TOPLEFT", tns.Parent, "TOPLEFT", x, y) + arrow:Show() + + numArrows = numArrows + 1 +end + +-- ** Buttons ** +local numButtons + +local function ResetButtonCount() + numButtons = 1 +end + +local function HideUnusedButtons() + while numButtons <= 40 do + _G["AltoholicFrameTalents_ScrollFrameTalent" .. numButtons]:Hide() + _G["AltoholicFrameTalents_ScrollFrameTalent" .. numButtons]:SetID(0) + numButtons = numButtons + 1 + end + numButtons = nil +end + +local function DrawTalent(texture, tier, column, count, id) + local itemName = "AltoholicFrameTalents_ScrollFrameTalent" .. numButtons + local itemButton = _G[itemName] + + itemButton:SetPoint("TOPLEFT", itemButton:GetParent(), "TOPLEFT", + INITIAL_OFFSET_X + ((column-1) * TALENT_OFFSET_X), + -(INITIAL_OFFSET_Y + ((tier-1) * TALENT_OFFSET_Y))) + itemButton:SetID(id) + + if texture then + addon:SetItemButtonTexture(itemName, texture, 37, 37) + end + + local itemCount = _G[itemName .. "Count"] + local itemTexture = _G[itemName .. "IconTexture"] + + if count and count > 0 then + itemCount:SetText(GREEN .. count) + itemCount:Show() + itemTexture:SetDesaturated(0) + else + itemTexture:SetDesaturated(1) + itemCount:Hide() + end + itemButton:Show() + + numButtons = numButtons + 1 +end + +-- ** Branches ** +local numBranches +local branchArray -- a 2-dimensional array to hold branches + +local function ResetBranchCount() + numBranches = 1 +end + +local function InitializeBranchArray() + branchArray = branchArray or {} + wipe(branchArray) + + for i = 1, MAX_NUM_TALENT_TIERS do + branchArray[i] = {}; + for j = 1, NUM_TALENT_COLUMNS do + branchArray[i][j] = {}; + end + end +end + +local function ClearBranchArray() + wipe(branchArray) + branchArray = nil +end + +local function InitBranch(tier, column, prereqTier, prereqColumn, blocked) + + -- algorithm taken from TalentFrameBase.lua, adjusted for my needs + local left = min(column, prereqColumn); + local right = max(column, prereqColumn); + + if (column == prereqColumn) then -- Same column ? ==> TOP + for i = prereqTier, tier - 1 do + branchArray[i][column].down = true; + if ( (i + 1) <= (tier - 1) ) then + branchArray[i+1][column].up = true; + end + end + return + end + + if (tier == prereqTier) then -- Same tier ? ==> LEFT or RIGHT + for i = left, right-1 do + branchArray[prereqTier][i].right = true; + branchArray[prereqTier][i+1].left = true; + end + return + end + + -- None of these ? ==> diagonal + if not blocked then + branchArray[prereqTier][column].down = true; + branchArray[tier][column].up = true; + + for i = prereqTier, tier - 1 do + branchArray[i][column].down = true; + branchArray[i + 1][column].up = true; + end + + for i = left, right - 1 do + branchArray[prereqTier][i].right = true; + branchArray[prereqTier][i+1].left = true; + end + else + for i=prereqTier, tier-1 do + branchArray[i][column].up = true; + branchArray[i + 1][column].down = true; + end + end +end + +local function SetBranchTexture(branchType, x, y) + local branch = _G["AltoholicFrameTalents_Branch" .. numBranches] + local tc = TALENT_BRANCH_TEXTURECOORDS[branchType][1] + + branch:SetTexCoord(tc[1], tc[2], tc[3], tc[4]); + branch:SetPoint("TOPLEFT", tns.Parent, "TOPLEFT", x, y) + branch:Show() + + numBranches = numBranches + 1 +end + +local function DrawBranches() + local x, y + local ignoreUp + + for i = 1, MAX_NUM_TALENT_TIERS do + for j = 1, NUM_TALENT_COLUMNS do + local p = branchArray[i][j] + + x = INITIAL_OFFSET_X + ((j-1) * TALENT_OFFSET_X) + 2 + y = -(INITIAL_OFFSET_Y + ((i-1) * TALENT_OFFSET_Y)) - 2 + + if p.node then -- there's a talent there + if p.up then + if not ignoreUp then + SetBranchTexture("up", x, y + TALENT_BUTTON_SIZE) + else + ignoreUp = nil + end + end + if p.down then + SetBranchTexture("down", x, y - TALENT_BUTTON_SIZE + 1) + end + if p.left then + SetBranchTexture("left", x - TALENT_BUTTON_SIZE, y) + end + if p.right then + SetBranchTexture("right", x + TALENT_BUTTON_SIZE, y) + end + else + if p.up and p.left and p.right then + SetBranchTexture("tup", x, y) + elseif p.down and p.left and p.right then + SetBranchTexture("tdown", x, y) + elseif p.left and p.down then + SetBranchTexture("topright", x, y) + SetBranchTexture("down", x, y-32) + elseif p.left and p.up then + SetBranchTexture("bottomright", x, y) + elseif p.left and p.right then + SetBranchTexture("right", x + TALENT_BUTTON_SIZE, y) + SetBranchTexture("left", x+1, y) + elseif p.right and p.down then + SetBranchTexture("topleft", x, y) + SetBranchTexture("down", x, y-32) + elseif p.right and p.up then + SetBranchTexture("bottomleft", x, y) + elseif p.up and p.down then + SetBranchTexture("up", x, y) + SetBranchTexture("down", x, y-32) + ignoreUp = true + end + end + + p.up = nil -- clear after use + p.left = nil + p.right = nil + p.down = nil + p.node = nil + end + end +end + +local function HideUnusedBranches() + while numBranches <= 30 do + _G["AltoholicFrameTalents_Branch" .. numBranches]:Hide() + numBranches = numBranches + 1 + end + numBranches = nil +end + + +-- *** TALENTS *** + +function tns:Update(treeIndex) + gns:Update() + treeIndex = treeIndex or 1 + AltoholicFrameTalents_ScrollFrameScrollBar:SetMinMaxValues(0, 330); + + -- stop all autocast + for i = 1, 3 do + AutoCastShine_AutoCastStop(_G[ "AltoholicFrameTalents_SpecIcon" .. i .. "Shine" ]); + end + AltoholicFrameTalents:Hide() + + local character = addon.Tabs.Characters:GetCurrent() + if not character then return end + + local DS = DataStore + if DS:GetActiveTalents(character) == 1 then + AltoholicFrameTalents_PrimaryText:SetText(format("%s (%s)",WHITE..TALENT_SPEC_PRIMARY..GREEN, TALENT_ACTIVE_SPEC_STATUS )) + AltoholicFrameTalents_SecondaryText:SetText(WHITE..TALENT_SPEC_SECONDARY) + else + AltoholicFrameTalents_PrimaryText:SetText(WHITE..TALENT_SPEC_PRIMARY) + AltoholicFrameTalents_SecondaryText:SetText(format("%s (%s)",WHITE..TALENT_SPEC_SECONDARY..GREEN, TALENT_ACTIVE_SPEC_STATUS )) + end + + local _, class = DS:GetCharacterClass(character) + if not DS:IsClassKnown(class) then return end + + local level = DS:GetCharacterLevel(character) + if not level or level < 10 then return end + + local treeName = DS:GetTreeNameByID(class, treeIndex) + + tns.Parent = _G["AltoholicFrameTalents_ScrollFrameTalent1"]:GetParent() + + local index = 1 + for tree in DS:GetClassTrees(class) do -- draw spec icons + local itemName = "AltoholicFrameTalents_SpecIcon"..index + local itemButton = _G[itemName] + local itemCount = _G[itemName .."Count"] + local icon = DS:GetTreeInfo(class, tree) + + addon:SetItemButtonTexture(itemName, icon, 30, 30) + itemCount:SetText(WHITE .. DS:GetNumPointsSpent(character, tree, currentTalentGroup)) + itemCount:Show() + itemButton:Show() + index = index + 1 + end + + local isActiveTalentGroup = currentTalentGroup == DS:GetActiveTalents(character) + + -- textures are 90.625% of the original size + local _, bg = DS:GetTreeInfo(class, treeName) + AltoholicFrameTalents_bgTopLeft:SetTexture(bg.."-TopLeft") + AltoholicFrameTalents_bgTopRight:SetTexture(bg.."-TopRight") + AltoholicFrameTalents_bgBottomLeft:SetTexture(bg.."-BottomLeft") + AltoholicFrameTalents_bgBottomRight:SetTexture(bg.."-BottomRight") + + SetDesaturation(AltoholicFrameTalents_bgTopLeft, not isActiveTalentGroup) + SetDesaturation(AltoholicFrameTalents_bgTopRight, not isActiveTalentGroup) + SetDesaturation(AltoholicFrameTalents_bgBottomLeft, not isActiveTalentGroup) + SetDesaturation(AltoholicFrameTalents_bgBottomRight, not isActiveTalentGroup) + + AutoCastShine_AutoCastStart(_G[ "AltoholicFrameTalents_SpecIcon" .. treeIndex .. "Shine" ]); + AltoholicFrameTalents_ScrollFrame:SetID(treeIndex) + + ResetButtonCount() + ResetArrowCount() + ResetBranchCount() + InitializeBranchArray() + + -- draw all icons in their respective slot + for i = 1, DS:GetNumTalents(class, treeName) do + local _, _, texture, tier, column = DS:GetTalentInfo(class, treeName, i) + local rank = DS:GetTalentRank(character, treeName, currentTalentGroup, i) + + DrawTalent(texture, tier, column, rank, i) + branchArray[tier][column].node = true; + + -- Draw arrows & branches where applicable + local prereqTier, prereqColumn = DS:GetTalentPrereqs(class, treeName, i) + if prereqTier and prereqColumn then + local left = min(column, prereqColumn); + local right = max(column, prereqColumn); + + if ( left == prereqColumn ) then -- Don't check the location of the current button + left = left + 1; + else + right = right - 1; + end + + local blocked -- Check for blocking talents + for j = 1, DS:GetNumTalents(class, treeName) do + local _, _, _, searchedTier, searchedColumn = DS:GetTalentInfo(class, treeName, j) + + if searchedTier == prereqTier then -- do nothing if lower tier, process if same tier, exit if higher tier + if (searchedColumn >= left) and (searchedColumn <= right) then + blocked = true + break + end + elseif searchedTier > prereqTier then + break + end + end + + DrawArrow(tier, column, prereqTier, prereqColumn, blocked) + InitBranch(tier, column, prereqTier, prereqColumn, blocked) + end + end + DrawBranches() + + HideUnusedButtons() + HideUnusedArrows() + HideUnusedBranches() + ClearBranchArray() + AltoholicFrameTalents:Show() +end + +function tns:Icon_OnEnter(frame) + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local _, class = DS:GetCharacterClass(character) + local treeName = DS:GetTreeNameByID(class, frame:GetID()) + + if treeName then + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + AltoTooltip:AddLine(treeName,1,1,1); + AltoTooltip:Show(); + end +end + +local function GetTalentLink(frame) + local DS = DataStore + local treeIndex = frame:GetParent():GetParent():GetID() + local character = addon.Tabs.Characters:GetCurrent() + local _, class = DS:GetCharacterClass(character) + local treeName = DS:GetTreeNameByID(class, treeIndex) + + local spellNumber = frame:GetID() + local id, name = DS:GetTalentInfo(class, treeName, spellNumber) + local rank = DS:GetTalentRank(character, treeName, currentTalentGroup, spellNumber) + + return DS:GetTalentLink(id, rank, name) +end + +function tns:Button_OnEnter(frame) + local link = GetTalentLink(frame) + if not link then return end + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(frame, "ANCHOR_RIGHT"); + AltoTooltip:SetHyperlink(link); + AltoTooltip:Show(); +end + +function tns:Button_OnClick(frame, button) + if ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + local link = GetTalentLink(frame) + if link then + chat:Insert(link) + end + end + end +end + +function tns:SetCurrentGroup(group) + currentTalentGroup = group +end + +function tns:OnUpdate() + if AltoholicFrameTalents:IsVisible() then + tns:Update() + end +end + + +-- *** GLYPHS *** + +local glyphSlotTexCoord = { + -- copied from Blizzard_GlyphUI.lua, no idea why they're not visible from here .. :/ + + -- Empty Texture + [0] = { left = 0.78125, right = 0.91015625, top = 0.69921875, bottom = 0.828125 }, + [1] = { left = 0, right = 0.12890625, top = 0.87109375, bottom = 1 }, + [2] = { left = 0.130859375, right = 0.259765625, top = 0.87109375, bottom = 1 }, + [3] = { left = 0.392578125, right = 0.521484375, top = 0.87109375, bottom = 1 }, + [4] = { left = 0.5234375, right = 0.65234375, top = 0.87109375, bottom = 1 }, + [5] = { left = 0.26171875, right = 0.390625, top = 0.87109375, bottom = 1 }, + [6] = { left = 0.654296875, right = 0.783203125, top = 0.87109375, bottom = 1 } +} + +local function DrawGlyph(id) + local name = "AltoholicFrameTalentsGlyph" .. id + local glyph = _G[name] + + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local enabled, glyphType, spell, icon = DS:GetGlyphInfo(character, currentTalentGroup, id) + + if glyphType == 1 then + glyph.glyph:SetVertexColor(1, 0.25, 0); + else + glyph.glyph:SetVertexColor(0, 0.25, 1); + end + + if enabled == 0 then + glyph.shine:Hide(); + glyph.background:Hide(); + glyph.glyph:Hide(); + glyph.ring:Hide(); + glyph.setting:SetTexture("Interface\\Spellbook\\UI-GlyphFrame-Locked"); + glyph.setting:SetTexCoord(.1, .9, .1, .9); + elseif not spell then + local tc = glyphSlotTexCoord[0] + + glyph.shine:Show(); + glyph.background:Show(); + glyph.background:SetTexCoord(tc.left, tc.right, tc.top, tc.bottom); + glyph.glyph:Hide(); + glyph.ring:Show(); + glyph.setting:SetTexture("Interface\\Spellbook\\UI-GlyphFrame"); + glyph.setting:SetTexCoord(0.740234375, 0.953125, 0.484375, 0.697265625); + else + local tc = glyphSlotTexCoord[id] + + glyph.shine:Show(); + glyph.background:Show(); + glyph.background:SetAlpha(1); + glyph.background:SetTexCoord(tc.left, tc.right, tc.top, tc.bottom); + glyph.glyph:Show(); + glyph.glyph:SetTexture(icon); + glyph.ring:Show(); + glyph.setting:SetTexture("Interface\\Spellbook\\UI-GlyphFrame"); + glyph.setting:SetTexCoord(0.740234375, 0.953125, 0.484375, 0.697265625); + end +end + +function gns:Update() + -- GLYPHTYPE_MAJOR = 1; + -- GLYPHTYPE_MINOR = 2; + + -- 1 + -- 3 5 + -- 6 4 + -- 2 + + for i = 1, 6 do + DrawGlyph(i) + end +end + +function gns:Button_OnLoad(frame) + local name = frame:GetName() + local id = frame:GetID() + local glyph = _G[name] + + glyph.glyph = _G[name .. "Glyph"] + glyph.setting = _G[name .. "Setting"] + glyph.highlight = _G[name .. "Highlight"] + glyph.background = _G[name .. "Background"] + glyph.ring = _G[name .. "Ring"] + glyph.shine = _G[name .. "Shine"] + + local ratio + if (id == 1) or (id == 4) or (id == 6) then -- major + ratio = 0.85 + else + ratio = 0.70 + end + + glyph.glyph:SetWidth(63 * ratio); + glyph.glyph:SetHeight(63 * ratio); + + glyph.setting:SetWidth(108 * ratio); + glyph.setting:SetHeight(108 * ratio); + glyph.setting:SetTexture("Interface\\Spellbook\\UI-GlyphFrame"); + glyph.setting:SetTexCoord(0.740234375, 0.953125, 0.484375, 0.697265625); + glyph.highlight:SetWidth(108 * ratio); + glyph.highlight:SetHeight(108 * ratio); + glyph.highlight:SetTexCoord(0.740234375, 0.953125, 0.484375, 0.697265625); + glyph.ring:SetWidth(82 * ratio); + glyph.ring:SetHeight(82 * ratio); + glyph.ring:SetPoint("CENTER", glyph, "CENTER", 0, -1); + glyph.ring:SetTexCoord(0.767578125, 0.92578125, 0.32421875, 0.482421875); + glyph.shine:SetTexCoord(0.9609375, 1, 0.9609375, 1); + glyph.background:SetWidth(70 * ratio); + glyph.background:SetHeight(70 * ratio); +end + +function gns:Button_OnEnter(frame) + local id = frame:GetID() + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local enabled, glyphType, spell, _, glyphID = DS:GetGlyphInfo(character, currentTalentGroup, id) + + local glyphTypeText + if tonumber(glyphType) == 1 then + glyphTypeText = "|cFF69CCF0" .. MAJOR_GLYPH + else + glyphTypeText = "|cFF69CCF0" .. MINOR_GLYPH + end + + AltoTooltip:SetOwner(frame, "ANCHOR_LEFT"); + AltoTooltip:ClearLines(); + if enabled == 0 then + AltoTooltip:AddLine("|cFFFF0000" .. GLYPH_LOCKED); + AltoTooltip:AddLine(glyphTypeText); + AltoTooltip:AddLine(_G["GLYPH_SLOT_TOOLTIP"..id]); + + AltoTooltip:Show(); + return + elseif not spell then + + AltoTooltip:AddLine("|cFF808080" .. GLYPH_EMPTY); + AltoTooltip:AddLine(glyphTypeText); + AltoTooltip:AddLine(GLYPH_EMPTY_DESC); + AltoTooltip:Show(); + return + end + + local link = DS:GetGlyphLink(id, spell, glyphID) + AltoTooltip:SetHyperlink(link); + AltoTooltip:Show(); +end + +function gns:Button_OnClick(frame, button) + local id = frame:GetID() + local DS = DataStore + local character = addon.Tabs.Characters:GetCurrent() + local enabled, glyphType, spell, _, glyphID = DS:GetGlyphInfo(character, currentTalentGroup, id) + + if not spell then return end + + if ( button == "LeftButton" ) and ( IsShiftKeyDown() ) then + local chat = ChatEdit_GetLastActiveWindow() + if chat:IsShown() then + local link = DS:GetGlyphLink(id, spell, glyphID) + chat:Insert(link) + end + end +end diff --git a/Altoholic-Addon/Altoholic/Frames/Talents.xml b/Altoholic-Addon/Altoholic/Frames/Talents.xml new file mode 100644 index 0000000..2a029a9 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Frames/Talents.xml @@ -0,0 +1,492 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + self:SetChecked(1) + Altoholic.Talents:SetCurrentGroup(1) + + + AltoholicFrameTalents_Secondary:SetChecked(nil) + Altoholic.Talents:SetCurrentGroup(1) + Altoholic.Talents:Update() + + + + + + + + + + + + + + self:SetChecked(nil) + + + AltoholicFrameTalents_Primary:SetChecked(nil) + Altoholic.Talents:SetCurrentGroup(2) + Altoholic.Talents:Update() + + + + + + + + + + + + + + + + + + + + + + ScrollFrame_OnLoad(self); + local scrollbar = _G[self:GetName().."ScrollBar"]; + scrollbar:SetMinMaxValues(0, 330); + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/ItemFilters.lua b/Altoholic-Addon/Altoholic/ItemFilters.lua new file mode 100644 index 0000000..338ea26 --- /dev/null +++ b/Altoholic-Addon/Altoholic/ItemFilters.lua @@ -0,0 +1,142 @@ +local addonName = ... +local addon = _G[addonName] + +local filters = {} +local searchedItem = {} + +-- item filtering functions +local function FilterExistence() + if searchedItem["itemName"] and searchedItem["itemRarity"] then + return true -- if both values are valid, the item exists in the game's item cache + end +end + +local function FilterType() + local itemType = filters["itemType"] + if not itemType or searchedItem["itemType"] == itemType then + return true -- no filter, or searched item is the same type as filter, keep it + end +end + +local function FilterSubType() + local subType = filters["itemSubType"] + if not subType or searchedItem["itemSubType"] == subType then + return true -- no filter, or searched item is the same sub type as filter, keep it + end +end + +local function FilterRarity() + local rarity = filters["itemRarity"] + if not rarity or searchedItem["itemRarity"] >= rarity then + return true -- no filter, or searched item has higher rarity than filter, keep it + end +end + +local function FilterItemLevel() + if searchedItem["itemLevel"] > filters["itemLevel"] then -- strictly superior, fully intentional + return true -- searched item has higher iLvl than filter, keep it + end +end + +local function FilterEquipmentSlot() + if addon.Equipment:GetInventoryTypeIndex(searchedItem["itemEquipLoc"]) == filters["itemSlot"] then + return true -- same slot as filter, keep the item + end +end + +local function FilterName() + if string.find(strlower(searchedItem["itemName"]), filters["itemName"], 1, true) then + return true -- name contains the filter value, keep the item + end +end + +local function FilterMinimumLevel() + local minLevel = searchedItem["itemMinLevel"] + if minLevel == 0 then + if (addon.Options:Get("IncludeNoMinLevel") == 1) then + return true -- include items with no minimum requireement + end + else + if minLevel >= filters["itemMinLevel"] then + return true -- include if within the right level boundaries + end + end +end + +local function FilterMaximumLevel() + if searchedItem["itemMinLevel"] <= filters["itemMaxLevel"] then + return true -- item min level is below max filter, keep the item + end +end + +local filterFunctions = { + ["Existence"] = FilterExistence, + ["Type"] = FilterType, + ["SubType"] = FilterSubType, + ["Rarity"] = FilterRarity, + ["ItemLevel"] = FilterItemLevel, + ["EquipmentSlot"] = FilterEquipmentSlot, + ["Name"] = FilterName, + ["MinLevel"] = FilterMinimumLevel, + ["Maxlevel"] = FilterMaximumLevel, +} + +addon.ItemFilters = {} + +local ns = addon.ItemFilters -- ns = namespace + +function ns:SetFilterValue(field, value) + filters[field] = value +end + +function ns:GetFilterValue(field) + return filters[field] +end + +function ns:EnableFilter(filter) + if filterFunctions[filter] then + filters.list = filters.list or {} + table.insert(filters.list, filterFunctions[filter]) + end +end + +function ns:ItemPassesFilters() + -- Exclusive approach: + -- by default, it is considered that no item if filtered out unless a specific filter is enabled. + -- ex: if a user wants to filter items based on their level in the UI, it means he doesn't want to see items outside of the specifies boundaries, so the filter "Level" is enabled, and items are filtered out. + + if filters.list then -- there might not be any filter + for _, func in pairs(filters.list) do + if not func() then -- if any of the filters returns false/nil, exit + return + end + end + end + return true -- return true if all filters have returned true +end + +function ns:ClearFilters() + wipe(filters) +end + +function ns:TryFilter(filter) + if filterFunctions[filter] then + return filterFunctions[filter]() + end +end + +-- currently searched item +function ns:SetSearchedItem(itemID) + local s = searchedItem + + s.itemID = itemID + s.itemName, s.itemLink, s.itemRarity, s.itemLevel, s.itemMinLevel, s.itemType, s.itemSubType, _, s.itemEquipLoc = GetItemInfo(itemID) +end + +function ns:GetSearchedItemInfo(field) + return searchedItem[field] +end + +function ns:ClearSearchedItem() + wipe(searchedItem) +end diff --git a/Altoholic-Addon/Altoholic/LICENSE.txt b/Altoholic-Addon/Altoholic/LICENSE.txt new file mode 100644 index 0000000..4301cb1 --- /dev/null +++ b/Altoholic-Addon/Altoholic/LICENSE.txt @@ -0,0 +1,2 @@ + +All Rights Reserved unless otherwise explicitly stated. \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/Locales/deDE.lua b/Altoholic-Addon/Altoholic/Locales/deDE.lua new file mode 100644 index 0000000..3118957 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/deDE.lua @@ -0,0 +1,733 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "Altoholic", "deDE" ) + +if not L then return end + +L["28 Slot"] = "28 Plätze" +L["32 Keys Max"] = "Maximal 32 Tasten" +L["Abyssal Council"] = "Abyssischer Rat" +L["Accessories"] = "Zubehör" +L["Account"] = true +L["Account Name"] = "Account-Name" +L["Account Sharing"] = "Account-Austausch" +L["Account Sharing Enabled"] = "Austausch zwischen Accounts ist aktiviert" +L["Account Sharing Request"] = "Anfrage zum Austausch zwischen Accounts" +L["Account sharing request received from %s"] = "Anfrage zu Account-Austausch von %s erhalten" +L["Account Summary"] = "Account-Überblick" +L["Activity"] = "Aktivitäten" +L["Adamantite Battlegear"] = "Adamantitschlachtrüstung" +L["Adamantite Deposit"] = "Adamantitablagerung" +L["Aged Dalaran Wizard"] = "Gealterter Hexer von Dalaran" +L["Aggem Thorncurse"] = "Aggem Dornfluch" +L["AH"] = true +L["All accounts"] = "Alle Accounts" +L["All cooldowns are up"] = "Alle Abklingzeiten abgelaufen" +L["Alliance Forces"] = "Streitkräfte der Allianz" +L["All-in-one"] = "Alle zusammen" +L["All realms"] = "Alle Realms" +L["Already known by "] = "Schon bekannt durch" +L["Altoholic:|r Usage = /altoholic search "] = "Altoholic:|r-Verwendung = /altoholic search " +L["Ancient Lichen"] = "Urflechte" +L["and above"] = "und höher" +L["Any"] = "Beliebige" +L["Anzu the Raven God (Heroic Summon)"] = "Anzu der Rabengott (Heroisch)" +L["Apprentice"] = "Lehrling" +L["Arcanoweave Vestments"] = "Arkanostoffgewänder" +L["Are also on this quest:"] = "Sind auch in dieser Quest:" +L["Arena points: "] = "Arenapunkte: " +L["Arena Season %d"] = "Arena-Saison %d" +L["Armbreaker Huffaz"] = "Armbrecher Huffaz" +L["Armorsmith"] = "Rüstungsschmied" +L["Arthas' Tears"] = "Arthas’ Tränen" +L["Artisan"] = "Fachmann" +L["at"] = "auf" +L["At least one recipe could not be read"] = "Mindestens ein Rezept konnte nicht gelesen werden" +L["Attendees: "] = "Teilnehmer:" +L["Auctions %s(%d)"] = "Auktionen %s(%d)" +L["Automatically authorize guild bank updates"] = "Gildenbankaktualisierungen automatisch erlauben." +L["AutoQuery server |cFFFF0000(disconnection risk)"] = "AutoAbfrage an den Server |cFFFF0000(Risiko eines Verbindungsabbruchs)" +L["Avatar of the Martyred"] = "Avatar des Gemarterten" +L["Average Item Level"] = "Durchschnittliche Gegenstandsstufe" +L["Azure Templar (Water)"] = "Azurblauer Templer (Wasser)" +L["Baelog's Chest"] = "Baelogs Truhe" +L["Bags"] = "Taschen" +L["Bag Usage"] = "Taschennutzung" +L["Balance"] = true +L["Balzaphon"] = true +L["Bank"] = true +L["Bank bag"] = "Banktasche" +L["Bank not visited yet"] = "Bank noch nicht besucht" +L["Barleybrew Brewery"] = "Gerstenbräu Brauerei" +L["(based on iLvl)"] = "(basiert auf iLvl)" +L["Bash'ir Landing"] = "Landeplatz von Bash'ir" +L["Battlecast Garb"] = "Gewand des Schlachtenzaubers" +L["BC Collector Edition (Europe)"] = "BC Collectors Edition (Europe)" +L["Beasts Deck"] = "Bestienkartenset" +L["Beast Training"] = "Begleiter Training" +L[ [=[Be informed when a guildmate sends a mail to one of my alts. + +Mail content is directly visible without having to reconnect the character]=] ] = [=[Informieren, wenn ein Mitglied meiner Gilde Post an einen meiner Twinks schickt. + +Der Inhalt ist sofort sichtbar, ohne mit diesem Charakter einloggen zu müssen.]=] +L["Bids %s(%d)"] = "Gebote %s(%d)" +L["Black Dragon Mail"] = "Schwarzer Drachenschuppenpanzer" +L["Black Lotus"] = "Schwarzer Lotus" +L["Blacksmithing (Lv 60)"] = "Schmiedekunst (Lv 60)" +L["Blacksmithing (Lv 70)"] = "Schmiedekunst (Lv 70)" +L["Blacksmithing Mail Sets"] = "Schmiedekunst Schwere Rüstungs-Sets" +L["Blacksmithing Plate Sets"] = "Schmiedekunst Platten-Sets" +L["Blade Edge Mountains"] = "Schergrat" +L["Blessings Deck"] = "Segenskartenset" +L["Blindweed"] = "Blindkraut" +L["Blizzard Collectables"] = "Blizzard-Sammlerstücke" +L["Blizzcon 2005"] = true +L["Blizzcon 2007"] = true +L["Bloodsoul Embrace"] = "Umarmung der Blutseele" +L["Bloodthistle"] = "Blutdistel" +L["Blood Tiger Harness"] = "Harnisch des Bluttigers" +L["Bloodvine"] = "Blutrebe" +L["Bloodvine Garb"] = "Blutrebengewand" +L["Blue Dragon Mail"] = "Blauer Drachenschuppenpanzer" +L["Books"] = "Bücher" +L["Booty Run"] = true +L["Both factions"] = "Beide Fraktionen" +L[ [=[Both parties must enable account sharing +before using this feature (see options)]=] ] = [=[Beide Parteien müssen "Account-Austausch" aktiviert haben, +ehe diese Funktion genutzt werden kann (siehe Optionen).]=] +L["Box of Chocolates"] = "Schokoladenschachtel" +L["Brewfest"] = "Braufest" +L["Briarthorn"] = "Wilddornrose" +L["Brightly Colored Egg"] = "Bunt gefärbtes Ei" +L["Bruiseweed"] = "Beulengras" +L["Burning Rage"] = "Brennender Zorn" +L["Cache of the Legion"] = "Behälter der Legion" +L["Calendar"] = "Kalender" +L["Cannot delete current character"] = "Aktueller Charakter kann nicht gelöscht werden" +L["Cannot delete current realm"] = "Aktueller Realm kann nicht gelöscht werden" +L["Cannot link another account's tradeskill"] = "Fertigkeiten eines anderen Accounts können nicht verlinkt werden" +L["Cannot link another realm's tradeskill"] = "Fertigkeiten eines anderen Realms können nicht verlinkt werden" +L["Carefully Wrapped Present"] = "Sorgfältig verpacktes Geschenk" +L["|cFF00FF00Disable|r to avoid this risk"] = "|cFF00FF00Deaktivieren|r, um dieses Risiko zu vermeiden." +L[ [=[|cFFFFFFFFIf an item not in the local item cache +is encountered while searching loot tables, +Altoholic will attempt to query the server for 5 new items. + +]=] ] = [=[|cFFFFFFFFWenn ein Gegenstand, der nicht im lokalen Gegenstands-Cache +ist, gefunden wird, während die Plündertabellen durchsucht werden, +wird Altoholic versuchen, den Server nach 5 neuen Gegenständen abzufragen. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to send you account sharing requests. +]=] ] = [=[|cFFFFFFFFWenn |cFF00FF00aktiviert|cFFFFFFFF, erlaubt diese Option anderen +Altoholic-Benutzern dir Anfragen zum Account-Austausch zu schicken.]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to update their guild bank information with yours automatically. + +]=] ] = [=[|cFFFFFFFFWenn |cFF00FF00aktiviert|cFFFFFFFF, wird diese Option anderen Altoholic-Benutzern erlauben, +ihre Gildenbankinformationen automatisch mit deinen zu aktualisieren.]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates +to see your alts and their professions. + +]=] ] = [=[|cFFFFFFFFWenn |cFF00FF00aktiviert|cFFFFFFFF, erlaubt diese Option +deinen Gildenkameraden, deine Twinks und deren Berufe zu sehen.]=] +L["Character"] = "Charakter" +L["Characters"] = "Charaktere" +L["Character %s received !"] = "Charakter %s empfangen!" +L["Character %s successfully deleted"] = "Charakter %s erfolgreich gelöscht" +L["Children's Week"] = "Kinderwoche" +L["Christmas Gift 2006"] = "Weihnachtsgeschenk 2006" +L["Clamp window to screen"] = "Fenster an Oberfläche befestigen" +L["Class Books"] = "Klassenbücher" +L["Classes: Death Knight"] = "Klassen: Todesritter" +L["Classes: Hunter"] = "Klassen: Jäger" +L["Classes: Mage"] = "Klassen: Magier" +L["Classes: Paladin"] = "Klassen: Paladin" +L["Classes: Priest"] = "Klassen: Priester" +L["Classes: Rogue"] = "Klassen: Schurke" +L["Classes: Shaman"] = "Klassen: Schamane" +L["Classes: Warlock"] = "Klassen: Hexenmeister" +L["Classes: Warrior"] = "Klassen: Krieger" +L["Class Skills"] = "Klassenfähigkeiten" +L["Clear all entries"] = "Alle Einträge löschen" +L["Clear goblin AH entries"] = "Einträge aus dem Goblin-AH löschen" +L["Clear your faction's entries"] = "Einträge der eigenen Fraktion löschen" +L["Click a character's AiL to see its equipment"] = "Das AiL eines Charakters anklicken, um seine Ausrüstung anzusehen" +L[ [=[Clicking this button will update +your local %s%s|r bank tab +based on %s%s's|r data]=] ] = [=[Durch das Anklicken dieser Schaltfläche, +wird dein örtliches %s%s|r Bank-Tab, +basierend auf %s%s's|r Daten, aktualisiert.]=] +L[ [=[Click this button to ask a player +to share his entire Altoholic Database +and add it to your own]=] ] = [=[Diese Schaltfläche anklicken, um einen Spieler zu bitten, +seine komplette Altoholic-Datenbank zur Übermittlung +freizugeben und deiner Datenbank hinzuzufügen.]=] +L["Cloaks"] = "Umhänge" +L["Cloth Set"] = "Stoff-Set" +L["Conspicuous Urn"] = "Verdächtige Urne" +L["Containers"] = "Behälter" +L["Copper Vein"] = "Kupfervorkommen" +L["Could be learned by "] = "Kann erlernt werden von" +L["Crafted Weapons"] = "Herstellbare Waffen" +L["Crimson Templar (Fire)"] = "Purpurroter Templer (Feuer)" +L["Currencies received !"] = "Zahlungsmittel empfangen!" +L["Dark Iron Deposit"] = "Dunkeleisenablagerung" +L["Darkscreecher Akkarai"] = "Dunkelkreischer Akkarai" +L[" days"] = " Tage" +L[" days ago"] = " Tage zuvor" +L["Deadly Gladiator's Weapons"] = "Waffen des tödlichen Gladiators" +L["Death Knight"] = "Todesritter" +L["Default"] = "Standardmäßig" +L["Delete Guild Bank?"] = "Gildenbank löschen?" +L["Delete this Alt"] = "Lösche diesen Twink" +L["Delete this Realm"] = "Lösche diesen Realm" +L["Detailed guild bank count"] = "Genaue Zählung in der Gildenbank" +L["Devilsaur Armor"] = "Teufelssaurierrüstung" +L["Disable warnings"] = "Warnungen deaktivieren" +L["Display warnings in a dialog box"] = "Warnungen in einem Dialogfeld anzeigen" +L["Do you want to open Altoholic's calendar for details ?"] = "Möchtest du den Altoholic-Kalender für weitere Details öffnen?" +L["Do you want to view it now ?"] = "Möchtest du es jetzt ansehen?" +L["DPS"] = true +L["Dragonscale"] = "Drachenlederverarbeitung" +L["Dreamfoil"] = "Traumblatt" +L["Dreaming Glory"] = "Traumwinde" +L["Drohn's Distillery"] = "Drohns Brauerei" +L["Druid of the Fang (Trash Mob)"] = "Druide des Giftzahns (Plunder-Mob)" +L["Druid Set"] = "Druiden-Set" +L["Earthen Templar (Earth)"] = "Irdener Templer (Erde)" +L["Earthroot"] = "Erdwurzel" +L["Elemental"] = "Elementarlederverarbeitung" +L["Elemental Invasion"] = "Invasion der Elementare" +L["Elementals Deck"] = "Elementarkartenset" +L["Elemental Shaman"] = "Elementar-Schamane" +L["E-Mail"] = true +L["Emblems of Heroism"] = "Embleme des Heldentums" +L["Emblems of Valor"] = "Embleme der Ehre" +L["Enchanted Adamantite Armor"] = "Verzauberte Adamantitrüstung" +L["Enchants"] = "Verzauberungen" +L["Engineering (Lv 60)"] = "Ingenieurskunst (Lv 60)" +L["Engineering (Lv 70)"] = "Ingenieurskunst (Lv 70)" +L[ [=[Enter an account name that will be +used for |cFF00FF00display|r purposes only.]=] ] = [=[Einen Account-Namen eingeben, der nur zum Zweck +der |cFF00FF00Anzeige|r verwendet werden soll.]=] +L["Epic Rewards"] = "Epische Belohnungen" +L["Equipment"] = "Ausrüstung" +L["Equipment Slot"] = "Ausrüstungsplatz" +L["Equipped"] = "Ausgerüstet" +L["Eric The Swift"] = "Eric \"Der Flinke\"" +L["Ethereum Prison"] = "Gefängnis des Astraleums" +L["Expert"] = "Experte" +L["Expiry:"] = "Verfall:" +L["Fadeleaf"] = "Blassblatt" +L["Faith in Felsteel"] = "Teufelsstählerner Wille" +L["Feast of Winter Veil"] = "Winterhauchfest" +L["Fel Iron Chain"] = "Teufelseisenkettenrüstung" +L["Fel Iron Chest"] = "Teufelseisentruhe" +L["Fel Iron Deposit"] = "Teufelseisenvorkommen" +L["Fel Iron Plate"] = "Teufelseisenplattenrüstung" +L["Fel Lotus"] = "Teufelslotus" +L["Felscale Armor"] = "Teufelsschuppenrüstung" +L["Fel Skin"] = "Teufelshaut" +L["Felstalker Armor"] = "Rüstung des Teufelspirschers" +L["Fel Steed"] = "Teufelsross" +L["Fel Tinkerer Zortan"] = "Teufelstüftler Zortan" +L["Felweed"] = "Teufelsgras" +L["Festive Gift"] = "Festtagsgeschenk" +L["Find Upgrade"] = "Aufrüstung suchen" +L["Firebloom"] = "Feuerblüte" +L["Fire Resistance Gear"] = "Feuerwiderstand Ausrüstung" +L["Fireworks Pack"] = "Feuerwerkspaket" +L["First Prize"] = "Erster Preis" +L["Fishing"] = "Angeln" +L["Fishing Extravaganza"] = "Angelwettbewerb" +L["Fishing Poles"] = "Angelruten" +L["Flame Cap"] = "Flammenkappe" +L["Flame Guard"] = "Flammenwächter" +L["Food"] = "Essen" +L["Forgosh"] = true +L["free"] = "frei" +L["Furies Deck"] = "Furienkartenset" +L["Fury of the Nether"] = "Netherzorn" +L["Gaily Wrapped Present"] = "Fröhlich verpacktes Geschenk" +L["Garrett Family Chest"] = "Familientruhe der Garretts" +L["General"] = "Allgemein" +L["Gently Shaken Gift"] = "Leicht geschütteltes Geschenk" +L["Gezzarak the Huntress"] = "Gezzarak die Jägerin" +L["Ghost Mushroom"] = "Geisterpilz" +L["Gift of Adoration"] = "Geschenke der Verehrung" +L["Glowcap"] = "Glühkappe" +L["Gnomish"] = "Gnomeningenieurskunst" +L["Goblin"] = "Gobliningenieurskunst" +L["Goblin AH"] = "Goblin-AH" +L["Golden Sansam"] = "Goldener Sansam" +L["Goldthorn"] = "Golddorn" +L["Gold Vein"] = "Goldvorkommen" +L["Gordok Brewery"] = "Gordokbrauerei" +L["Grave Moss"] = "Grabmoos" +L["Green Dragon Mail"] = "Grüner Drachenschuppenpanzer" +L["Grey"] = "Grau" +L["Gromsblood"] = "Gromsblut" +L["Guild Bank not visited yet (or not guilded)"] = "Gildenbank bisher nicht besucht (oder gildenlos)" +L["Guild Bank Remote Update"] = "Indirekte Aktualisierung der Gildenbank" +L["Guild Bank Tabs"] = "Gildenbank-Tabs" +L["Guild bank tab %s successfully updated !"] = "Gildenbank-Tab %s erfolgreich aktualisiert!" +L["Guild Communication Enabled"] = "Gildenkommunikation ist aktiviert" +L["Guild Members"] = "Gildenmitglieder" +L["Guild Skills"] = "Fertigkeiten der Gilde" +L["Guilds received !"] = "Gilden empfangen!" +L["Guild %s successfully deleted"] = "Gilde %s erfolgreich gelöscht" +L["Gul'bor"] = true +L["Gurubashi Arena"] = "Arena der Gurubashi" +L["Hakkari Thorium Vein"] = "Thoriumvorkommen der Hakkari" +L["Halaa (Nagrand)"] = true +L["Hallow's End"] = "Schlotternächte" +L["Hard Mode"] = "Schwieriger Modus" +L["Harvest Festival"] = "Erntedankfest" +L["(has auctions)"] = "(hat Auktionen)" +L["(has bids)"] = "(hat Gebote)" +L["has come online"] = "ist jetzt online" +L["has gone offline"] = "ist jetzt offline" +L["(has mail)"] = "(hat Post)" +L[" has no mail, last check "] = " hat keine Post, zuletzt überprüft am " +L[" has not visited his/her mailbox yet"] = " hat noch nicht sein/ihr Postfach besucht" +L["Headless Horseman"] = "Kopfloser Reiter" +L["Heal"] = "Heilung" +L["Hellfire Fortifications"] = "Höllenfeuerbefestigungen" +L["Henry Stern"] = true +L["Herbalism"] = "Kräuterkunde" +L[" (Heroic)"] = " (Heroisch)" +L["Heroic Mode Tokens"] = "Marken für heroische Instanzen" +L["hide"] = "verbergen" +L["Hides the UI"] = "Benutzeroberfläche verbergen" +L["Hide this guild in the tooltip"] = "Diese Gilde im Tooltip verbergen." +L["Highlord Kruul"] = "Hochlord Kruul" +L["Hoary Templar (Wind)"] = "Weißgrauer Templer (Wind)" +L["Honor points: "] = "Ehrenpunkte: " +L["Horde Forces"] = "Streitkräfte der Horde" +L["Hunter Set"] = "Jäger-Set" +L["Icecap"] = "Eiskappe" +L["Imbued Netherweave"] = "Magieerfüllte Netherstoffroben" +L["Imperial Plate"] = "Imperiale Plattenrüstung" +L["Incendicite Mineral Vein"] = "Pyrophormineralvorkommen" +L["Include guild bank count in the total count"] = "Zählung der Gildenbank in die Zählungssumme einbeziehen." +L["Include guild bank(s)"] = "Gildenbank(en) hinzufügen" +L["Include guild members' professions"] = "Berufe der Gildenmitglieder einschließen" +L["Include items without level requirement"] = "Gegenstände ohne Stufenbegrenzung einbeziehen" +L["Include known recipes"] = "Bereits bekannte Rezepte einbeziehen" +L["Include mailboxes"] = "Postfächer einbeziehen" +L["Increases attack power by %d+"] = "Erhöht die Angriffskraft um %d+" +L["Increases damage and healing done by magical spells and effects by up to %d+"] = "Erhöht durch magische Zauber und Effekte verursachten Schaden und Heilung um bis zu %d+" +L["Increases healing done by up to %d+"] = "Erhöht verursachte Heilung um bis zu %d+" +L["Indurium Mineral Vein"] = "Induriummineralvorkommen" +L["Inscription"] = "Inschriftenkunde" +L["Invalid tradeskill link"] = "Ungültige Fertigkeiten-Verknüpfung" +L["Iron Deposit"] = "Eisenvorkommen" +L["Ironfeather Armor"] = "Eisenfederrüstung" +L[" is "] = " ist " +L["Item Level"] = true +L["Item / Location"] = "Gegenstand / Standort" +L["Items"] = true +L["Journeyman"] = "Geselle" +L["Karrog"] = true +L["Khadgar's Whisker"] = "Khadgars Schnurrbart" +L["Khorium Vein"] = "Khoriumvorkommen" +L["Khorium Ward"] = "Khoriumschutz" +L["Kingsblood"] = "Königsblut" +L["Krom Stoutarm Chest"] = "Krom Starkarms Truhe" +L["Lady Falther'ess"] = true +L["Lake Wintergrasp"] = "Tausendwintersee" +L["Large Obsidian Chunk"] = "Großer Obsidianbrocken" +L["last check "] = "letzte Überprüfung " +L["Last visit: %s by %s"] = "Letzter Besuch: %s von %s" +L["Leather Set"] = "Leder-Set" +L["Leatherworking Leather Sets"] = "Lederverarbeitung Leder-Sets" +L["Leatherworking Mail Sets"] = "Lederverarbeitung Schwere-Rüstungs-Sets" +L["Left-click to"] = "Links-Klick, um zu" +L["Left-click to |cFF00FF00open"] = "Links-Klick zum |cFF00FF00Öffnen" +L["Left-click to invite attendees"] = "Linksklicken, um Teilnehmer einzuladen" +L["Left-click to see this character's equipment"] = "Links-Klick, um die Ausrüstung dieses Charakters zu sehen" +L["Left click to view"] = "Zum Ansehen links-klicken" +L["Legendaries"] = "Legendäres" +L["Legendary Mount"] = "Legendäres Reittier" +L["Lesser Bloodstone Deposit"] = "Geringe Blutsteinablagerung" +L["Level"] = "Stufe" +L["Level 30-39"] = "Stufe 30-39" +L["Level 40-49"] = "Stufe 40-49" +L["Level 50-60"] = "Stufe 50-60" +L["Level 70"] = "Stufe 70" +L["Level 70 Reputation PVP"] = "Stufe 70 Ruf PVP" +L["Level %d Honor PVP"] = "Stufe %d Ehre PVP" +L["Levels"] = "Stufen" +L["Liferoot"] = "Lebenswurz" +L["Local Time: %s %sRealm Time: %s"] = "Ortszeit: %s %sServerzeit: %s" +L["Location"] = "Standort" +L["Lockpicking"] = "Schlossknacken" +L["Loot Card Items"] = "Karten-Gegenstände plündern" +L["Loots"] = "Beute" +L["Loot tables"] = "Plündertabellen" +L["Lord Ahune"] = "Fürst Ahune" +L["Lord Blackwood"] = "Fürst Schwarzstahl" +L["Love is in the air"] = "Liebe ist in der Luft" +L["Lucky Red Envelope"] = "Roter Glücksumschlag" +L["Lunacy Deck"] = "Deliriumkartenset" +L["Lunar Festival"] = "Mondfest" +L["Lv %s Rewards"] = "Belohnungen (Stufe %s)" +L["Mageroyal"] = "Maguskönigskraut" +L["Mage Set"] = "Magier-Set" +L["Magregan Deepshadow"] = "Magregan Grubenschatten" +L["Mail"] = "Schwere Rüstung" +L["Mail Expiry Warning"] = "Warnung bei Verfall der Post" +L["Mail is about to expire on at least one character."] = "Bei mindestens einem Charakter wird in Kürze Post verfallen." +L["Mails"] = "Post" +L["Mail Set"] = "Schwere-Rüstungs-Set" +L["Mails %s(%d)"] = "Post %s(%d)" +L["Mail was last checked "] = "Postfach wurde zuletzt überprüft " +L["Malevus the Mad"] = "Malevus die Verrückte" +L["Mana Thistle"] = "Manadistel" +L["Master"] = "Meister" +L["Master Axesmith"] = "Axtschmiedemeister" +L["Master Hammersmith"] = "Hammerschmiedemeister" +L["Master Swordsmith"] = "Schwertschmiedemeister" +L["Maximum Level: %s"] = "Maximale Stufe: %s" +L["Max rest XP displayed as 150%"] = "Maximale \"Erholt\"-EP werden mit 150% angezeigt" +L["Midsummer Fire Festival"] = "Das Sonnenwendfest" +L["Minimap Icon Angle"] = "Positionswinkel des Minikarten-Symbols" +L["Minimap Icon Radius"] = "Positionsradius des Minikarten-Symbols" +L["Minimum Level: %s"] = "Mindeststufe: %s" +L["Mining"] = "Bergbau" +L["Miscellaneous"] = "Verschiedenes" +L["Mithril Deposit"] = "Mithrilablagerung" +L["Mooncloth"] = "Mondstoff" +L["Mountain Silversage"] = "Bergsilbersalbei" +L["Move to change the angle of the minimap icon"] = "Bewegen, um den Positionswinkel an der Minikarte zu verändern" +L["Move to change the radius of the minimap icon"] = "Bewegen, um den Positionsradius an der Minikarte zu verändern" +L["Muddy Churning Waters"] = true +L["N/A"] = true +L["Netherbloom"] = "Netherblüte" +L["Nethercite Deposit"] = "Netheritablagerung" +L["Netherdust Bush"] = "Netherstaubbusch" +L["Netherscale Armor"] = "Netherschuppenrüstung" +L["Netherstrike Armor"] = "Rüstung des Netherstoßes" +L["Netherweave Vestments"] = "Netherstoffgewänder" +L["New mail notification"] = "Benachrichtigung über neue Post" +L["Nightmare Vine"] = "Alptraumranke" +L["Noblegarden"] = "Nobelgarten" +L["No currencies found"] = "Keine Währungen gefunden" +L["No data"] = "Keine Daten" +L["No guild found"] = "Keine Gilde gefunden" +L["No match found!"] = "Kein passendes Ergebnis gefunden!" +L["Non Set Accessories"] = "Zubehör (kein Set)" +L["Non Set Cloth"] = "Stoff (kein Set)" +L["Non Set Leather"] = "Leder (kein Set)" +L["Non Set Mail"] = "Schwere Rüstung (kein Set)" +L["Non Set Plate"] = "Platte (kein Set)" +L["No quest found for "] = "Keine Quest gefunden für " +L["No reputations found"] = "Kein Ruf gefunden" +L["No rest XP"] = "Keine \"Erholt\"-EP" +L[" not found!"] = " nicht gefunden!" +L["Not started"] = "Nicht begonnen" +L["Number of players: %s"] = "Anzahl der Spieler: %s" +L["Offline Members"] = "Offline-Mitglieder" +L["Olaf"] = true +L["Ooze Covered Gold Vein"] = "Brühschlammbedecktes Goldvorkommen" +L["Ooze Covered Mithril Deposit"] = "Brühschlammbedeckte Mithrilablagerung" +L["Ooze Covered Rich Thorium Vein"] = "Brühschlammbedecktes reiches Thoriumvorkommen" +L["Ooze Covered Silver Vein"] = "Brühschlammbedecktes Silbervorkommen" +L["Ooze Covered Thorium Vein"] = "Brühschlammbedecktes Thoriumvorkommen" +L["Ooze Covered Truesilver Deposit"] = "Brühschlammbedeckte Echtsilberablagerung" +L["open/close"] = "öffnen/schließen" +L["Opera (Shared Drops)"] = "Opera (Geteilte Beutestücke)" +L["Other"] = "Andere" +L["Outdoor Bosses"] = "Bosse im Freien" +L["Paladin Set"] = "Paladin-Set" +L["Patterns"] = "Muster" +L["Peacebloom"] = "Friedensblume" +L["Plaguebloom"] = "Pestblüte" +L["Plans"] = "Pläne" +L["Plate Set"] = "Platten-Set" +L["Please open this window again"] = "Dieses Fenster bitte erneut öffnen" +L["Poisons"] = "Gifte" +L["Porfus the Gem Gorger"] = "Porfus der Edelsteinschlinger" +L["Portals Deck"] = "Portalkartenset" +L["Priest Set"] = "Priester-Set" +L["Primal Batskin"] = "Urzeitliche Fledermaushaut" +L["Primal Intent"] = "Urinstinkt" +L["Primal Mooncloth"] = "Urmondstoff" +L["Private to friends: %s"] = "Privat an Freunde: %s" +L["Private to guild: %s"] = "Privat an Gilde: %s" +L["Prof. 1"] = "Beruf 1" +L["Prof. 2"] = "Beruf 2" +L["Professions"] = "Berufe" +L["Purple Lotus"] = "Lila Lotus" +L["PVP Cloth Set"] = "PVP-Stoff-Set" +L["PVP Leather Sets"] = "PVP-Leder-Sets" +L["PVP Mail Sets"] = "PVP-Schwere-Rüstungs-Sets" +L["PVP Plate Sets"] = "PVP-Platten-Sets" +L["Pyron"] = "Übermeister Pyron" +L["QuestID"] = "Quest-ID" +L["Quest Items"] = "Quest-Gegenstände" +L["Quest rewards"] = "Quest-Belohnungen" +L["Quests"] = true +L["Ragveil"] = "Zottelkappe" +L["Rajaxx's Captains"] = "General Rajaxx' Kommandanten" +L["Random Boss"] = "Zufälliger Boss" +L["Rare Fish"] = "Seltener Fisch" +L["Rare Fish Rewards"] = "Belohnungen für seltene Fische" +L["Razorfen Spearhide"] = "Speerträger der Klingenhauer" +L["Realm"] = "Server" +L["Realm %s successfully deleted"] = "Realm %s wurde erfolgreich gelöscht" +L["Reference data not available"] = "Referenzdaten nicht verfügbar" +L["Reference data received (%s) !"] = "Referenzdaten empfangen (%s)!" +L["Refer to the activity pane for more details."] = "Verweise auf Aktivitätsfeld für weitere Details." +L["Relics"] = "Reliquien" +L["Reputations"] = "Ruf" +L["Reputations received !"] = "Ruf-Informationen empfangen!" +L["Requesting item %d of %d"] = "Erbitte Gegenstand %d von %d" +L["Requesting %s information from %s"] = "Erbitte %s-Information von %s" +L["Request rejected by %s"] = "Anfrage von %s abgewiesen" +L["Reset"] = "Zurücksetzen" +L["Resistance"] = "Widerstand" +L["Rested"] = "Erholt" +L["Restores %d+ mana per"] = "Stellt %d+ Mana wieder her pro" +L["Rest XP"] = "\"Erholt\"-XP" +L[" results found (Showing "] = " Ergebnisse gefunden (zeige " +L["Rethilgore"] = "Rotkralle" +L["Revanchion"] = true +L["Rich Adamantite Deposit"] = "Reiche Adamantitablagerung" +L["Rich Thorium Vein"] = "Reiches Thoriumvorkommen" +L["Riding"] = "Reiten" +L["Right-Click for options"] = "Optionen mittels Rechts-Klick" +L["Right-click to |cFF00FF00drag"] = "Rechts-Klick, um zu |cFF00FF00ziehen" +L["Right-Click to find an upgrade"] = "Rechts-Klicken, um Aufrüstung zu finden" +L["Rogue Proficiencies"] = "Schurken-Fertigkeiten" +L["Rogue Set"] = "Schurken-Set" +L["Roogug"] = true +L["Sanguine Hibiscus"] = "Bluthibiskus" +L["Savage Gladiator's Weapons"] = "Waffen des grausamen Gladiators" +L["Scaled Draenic Armor"] = "Geschuppte draenische Rüstung" +L[" scan failed for "] = " Scan fehlgeschlagen für " +L["Scan mail body (marks it as read)"] = "Inhalt der Postsendungen scannen (wird als gelesen markiert)" +L["Scorn"] = "des Verächters" +L["Scourge Invasion"] = "Invasion der Geißel" +L["search"] = "Suche" +L["Search Containers"] = "Durchsuche Behälter" +L["Search in bags"] = "In Taschen suchen" +L["Secondary Skills"] = "Sekundäre Fertigkeiten" +L[ [=[Security hint: disable this if you have officer rights +on guild bank tabs that may not be viewed by everyone, +and authorize requests manually]=] ] = [=[Sicherheitshinweis: dies deaktivieren, falls du Offiziersrechte +in Gildenbanktabs hast, die nicht von jedermann eingesehen +werden dürfen, und genehmige Anfragen manuell. +und die Anforderungen manuell bestätigen.]=] +L[ [=[Security hint: Only enable this when you actually need to transfer data, +disable otherwise]=] ] = [=[Sicherheitshinweis: dies nur aktivieren, wenn du wirklich Daten übertragen mußt, +ansonsten deaktivieren.]=] +L["Send account sharing request to:"] = "Anfrage zum Account-Austausch senden an:" +L["Sending account sharing request to %s"] = "Sende Anfrage wegen Account-Austausch an %s" +L["Sending character %s (%d of %d)"] = "Sende Charakter %s (%d von %d)" +L["Sending currencies (%d of %d)"] = "Sende Zahlungsmittel (%d von %d)" +L["Sending guilds (%d of %d)"] = "Gilden senden (%d von %d)" +L["Sending reference data: %s (%d of %d)"] = "Sende Referenzdaten: %s (%d von %d)" +L["Sending reputations (%d of %d)"] = "Sende Ruf-Informationen (%d von %d)" +L["Sending table of content (%d items)"] = "Sende Inhaltsverzeichnis (%d Gegenstände)" +L["Sever"] = "des Kampfmeisters" +L["Shadoweave"] = "Schattenzwirnschneiderei" +L["Shadowforge Cache"] = "Schattenschmiedecache" +L["Shadow's Embrace"] = "Umarmung der Schatten" +L["Shaman Set"] = "Schamanen-Set" +L["Shared"] = "Geteilt" +L["Shartuul"] = "Vorarbeiter Shartuul" +L["%s has disabled account sharing"] = "%s hat den Account-Austausch deaktiviert" +L["%s has disabled guild communication"] = "%s hat die Kommunikation mit der Gilde deaktiviert" +L["%s has no auctions"] = "%s hat keine Auktionen" +L["%s has no bids"] = "%s hat keine Gebote" +L["%s has no mail"] = "%s hat keine Post" +L["Shen'dralar Provisioner"] = "Versorger der Shen'dralar" +L["Shift-Click to link this info"] = "SHIFT-Klick, um diese Information zu verlinken" +L["Shift+Left click to link"] = "SHIFT+Links-Klick zum Verlinken" +L["show"] = "anzeigen" +L["Show already known/learnable by"] = "Anzeige von bereits bekannt/erlernbar durch" +L["Show counters for all accounts"] = "Zähler für alle Accounts anzeigen" +L["Show counters for both factions"] = "Zähler für beide Fraktionen anzeigen" +L["Show counters on gathering nodes"] = "Zähler bei Sammelsymbolen anzeigen" +L["Show FuBar icon"] = "FuBar-Symbol anzeigen" +L["Show FuBar text"] = "FuBar-Text anzeigen" +L["Show guild bank count"] = "Gildenbankzählung anzeigen" +L["Show item count per character"] = "Anzahl der Gegenstände pro Charakter anzeigen" +L["Show item ID and item level"] = "Gegenstands-ID und -stufe anzeigen" +L["Show item source"] = "Ursprung des Gegenstands anzeigen" +L["Show Minimap Icon"] = "Minikarten-Symbol anzeigen" +L["Show pets already known/learnable by"] = "Bereits bekannte/erlernbare Begleiter anzeigen von" +L["Show recipes already known/learnable by"] = "Bereits bekannte/erlernbare Rezepte anzeigen von" +L["Shows the UI"] = "Benutzeroberfläche anzeigen" +L["Show total item count"] = "Gesamtanzahl der Gegenstände anzeigen" +L["Silverleaf"] = "Silberblatt" +L["Silver Vein"] = "Silbervorkommen" +L["%s is in combat, request cancelled"] = "%s ist im Kampf, Anfrage wurde storniert." +L["%s is now ready (%s on %s)"] = "%s ist jetzt bereit (%s auf %s)" +L["%s is now unlocked (%s on %s)"] = "%s ist jetzt freigeschaltet (%s auf %s)" +L["%s is %s with %s (%d/%d)"] = [=[Der Ruf von %s ist %s in %s (%d/%d) +Dies soll eine schlecht formatierte Codierung ersetzen, die schon viel zu lange vorhanden war. Beispiel: "Der Ruf von Thaoky ist ehrfürchtig in Eisenschmiede (999/1000)."]=] +L["Skettis"] = true +L["Skinning"] = "Kürschnerei" +L["Skyguard Raid"] = "Angriff der Himmelswache" +L["slots"] = "Plätze" +L["Small Obsidian Chunk"] = "Kleiner Obsidianbrocken" +L["Small Thorium Vein"] = "Kleines Thoriumvorkommen" +L["Smokywood Pastures Extra-Special Gift"] = "Kokelwälder Extraspezialgeschenk" +L["Smokywood Pastures Vendor"] = "Händler der Kokelwälder" +L["Socket"] = "Sockel" +L["Sort loots in descending order"] = "Beute in absteigender Reihenfolge sortieren" +L["Sothos & Jarien"] = "Jarien und Sothos" +L["Soulcloth Embrace"] = "Seelenstoffumarmung" +L["Source"] = "Quelle" +L["Spawn Of Hakkar"] = "Brut von Hakkar" +L["Spellfire"] = "Zauberfeuer" +L["Spellstrike Infusion"] = "Insignien des Zauberschlags" +L["Spirit Towers (Terrokar)"] = "Geistertürme (Terrokar)" +L["%s|r has received a mail from %s"] = "%s|r hat Post von %s erhalten" +L[ [=[%s%s|r has requested the bank tab %s%s|r +Send this information ?]=] ] = [=[%s%s|r hat das Bank-Tab %s%s|r angefordert. +Diese Informationen senden?]=] +L["%s starts in %d minutes (%s on %s)"] = "%s beginnt in %d Minuten (%s auf %s)" +L["Started"] = "Begonnen" +L["Stasis Chambers"] = "Stasiskammern" +L["Steamwheedle Cartel"] = "Dampfdruckkartell" +L["Storms Deck"] = "Sturmkartenset" +L["Stormshroud Armor"] = "Sturmschleier" +L["Stranglekelp"] = "Würgetang" +L["Strength of the Clefthoof"] = "Macht der Grollhufe" +L["Suggested leveling zone: "] = "Vorgeschlagene Zone zum Leveln: " +L["Suggestion"] = "Vorschlag" +L["Summary"] = "Zusammenfassung" +L["Summoner's Tomb"] = "Grabmal des Beschwörers" +L["Sungrass"] = "Sonnengras" +L["Superior Rewards"] = "Überragende Gegenstände" +L[ [=[%sWarning:|r if you accept, %sALL|r information known +by Altoholic will be sent to %s%s|r (bags, money, etc..)]=] ] = [=[%sWarnung:|r bei Annahme werden %sALLE|r Informationen, die +Altoholic bekannt sind, an %s%s|r gesendet (Taschen, Geld, etc.)]=] +L["%sWarning:|r make sure this user may view this information before accepting"] = "%sWarnung:|r vor Annahme versichere dich, dass dieser Spieler diese Informationen auch einsehen darf." +L["Swiftthistle"] = "Flitzdistel" +L["%s will be ready in %d minutes (%s on %s)"] = "%s wird in %d Minuten bereit sein (%s auf %s)" +L["%s will be unlocked in %d minutes (%s on %s)"] = "%s wird freigesetzt in %d Minuten (%s auf %s)" +L["Table of content received (%d items)"] = "Inhaltsverzeichnis empfangen (%d Gegenstände)" +L["Tablet of Ryuneh"] = "Schrifttafel von Ryun'eh" +L["Tablet of Will"] = "Schrifttafel des Willens" +L["Tailoring Sets"] = "Schneiderei-Sets" +L["Tank"] = true +L["T'chali's Voodoo Brewery"] = "T'chalis Voodoobrauerei" +L["Terocone"] = "Terozapfen" +L["Terokk"] = true +L["The Darksoul"] = "Dunkelseele" +L["The Duke of Cinders (Fire)"] = "Der Fürst der Asche (Feuer)" +L["The Duke of Fathoms (Water)"] = "Der Fürst der Tiefen (Wasser)" +L["The Duke of Shards (Earth)"] = "Der Fürst der Splitter (Erde)" +L["The Duke of Zephyrs (Wind)"] = "Der Fürst der Stürme (Luft)" +L["Theldren"] = true +L[ [=[There is a risk of disconnection if the queried item +is a loot from a high level dungeon. + +]=] ] = [=[Es gibt das Risiko eines Verbindungsabbruchs, wenn der gefragte +Gegenstand eine Beute in einer hochstufigen Instanz ist. +]=] +L["The Unyielding"] = "Der Unerschütterliche" +L["The Vault"] = "Das Gewölbe" +L["Thick Draenic Armor"] = "Dicke draenische Rüstung" +L["This account"] = "Dieser Account" +L["This character"] = "Dieser Charakter" +L["This faction"] = "Diese Fraktion" +L["This field |cFF00FF00cannot|r be left empty."] = "Dieses Feld |cFF00FF00darf nicht|r leer bleiben." +L[ [=[This name can be anything you like, +it does |cFF00FF00NOT|r have to be the real account name.]=] ] = [=[Der Name kann beliebig gewählt werden, +er muss |cFF00FF00NICHT|r dem Account-Namen entsprechen.]=] +L["This realm"] = "Dieser Server" +L[ [=[This will gradually improve the consistency of the searches, +as more items are available in the item cache. + +]=] ] = [=[Dies wird allmählich die Beständigkeit der Suchvorgänge verbessern, +da mehr Gegenstände im Gegenstands-Cache vorhanden sind. + +]=] +L["Thomas Yance"] = true +L["Thunderbrew Brewery"] = "Donnerbräu Brauerei" +L["Ticking Present"] = "Tickendes Geschenk" +L["Tier 0.5 Quests"] = "Rang 0.5-Set-Quests" +L["Tier %d Tokens"] = "Rang-%d-Set-Marken" +L["Timed Chest"] = "Zeitweise vorhandene Truhe" +L["Tin Vein"] = "Zinnvorkommen" +L["toggle"] = "umschalten" +L["Toggles the UI"] = "Benutzeroberfläche umschalten" +L["Token Hand-Ins"] = "Abzugebende Abzeichen" +L["Tooltip"] = true +L["Total owned"] = "Summe aller im Besitz" +L["Totals"] = "Summen" +L["Transfer complete"] = "Übertragung vollständig" +L["Transmute"] = "Transmutieren" +L["Transparency"] = "Transparenz" +L["Trash Mobs"] = "Plunder-Mobs" +L["Treat Bag"] = "Schlotterbeutel" +L["Tribal"] = "Stammeslederverarbeitung" +L["Tribute Run"] = "Tribut-Run" +L["Trinkets"] = "Schmuckstücke" +L["Troll Mini bosses"] = "Mini-Bosse der Trolle" +L["Truesilver Deposit"] = "Echtsilberablagerung" +L["Twin Spire Ruins"] = "Ruinen der Zwillingsspitze" +L["Unknown"] = "Unbekannt" +L["Unknown link, please relog this character"] = "Unbekannte Verknüpfung, bitte diesen Charakter neu einloggen" +L["Upper Deck"] = "Oberdeck" +L["up to"] = "bis zu " +L["Vakkiz the Windrager"] = "Vakkiz der Windzürner" +L["Various Locations"] = "Verschiedene Standorte" +L["View"] = "Ansehen" +L["View auctions"] = "Auktionen ansehen" +L["View bags"] = "Taschen ansehen" +L["View bids"] = "Gebote ansehen" +L["View mailbox"] = "Postfach ansehen" +L["View quest log"] = "Questlog einsehen" +L["Visited"] = "Besucht" +L["Volcanic Armor"] = "Vulkanrüstung" +L["Waiting for %s to accept .."] = "Warte auf die Annahme von %s ..." +L["Warlock Set"] = "Hexenmeister-Set" +L["Warlords Deck"] = "Kriegsfürstenkartenset" +L["Warn %d minutes before an event starts"] = "%d Minuten bevor ein Ereignis beginnt warnen." +L["Warn when mail expires in less days than this value"] = "Warnen, wenn Post in weniger Tagen als folgendem Wert verfällt:" +L["Warrior Set"] = "Krieger-Set" +L["Weapons"] = "Waffen" +L["Weaponsmith"] = "Waffenschmied" +L["Week starts on Monday"] = "Woche beginnt Montags" +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected. + +]=] ] = "Wenn |cFFFF0000deaktiviert|cFFFFFFFF, werden alle Anfragen automatisch abgewiesen." +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = "Wenn |cFFFF0000deaktiviert|cFFFFFFFF, findet keine Kommunikation mit der Gilde statt." +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be +required before sending any information. + +]=] ] = [=[Wenn |cFFFF0000deaktiviert|cFFFFFFFF, ist deine Bestätigung +erforderlich, ehe Informationen weitergegeben werden. +]=] +L["Whitemend Wisdom"] = "Weisheit des weißen Heilers" +L["Wild Draenish Armor"] = "Wilde draenische Rüstung" +L["Wild Steelbloom"] = "Wildstahlblume" +L["Wildvine"] = "Wildranke" +L["Will be learnable by "] = "Wird demnächst erlernbar sein von" +L["Will be %sdeleted|r in"] = "%sVerfällt in" +L["Will be %sreturned|r in"] = "Wird %szurückgesendet in" +L["Windhawk Armor"] = "Rüstung des Windfalken" +L["Wintersbite"] = "Winterbiss" +L["Winter Veil Gift"] = "Winterhauchgeschenk" +L[" with "] = " bei " +L["World Drops"] = "Welt-Drops" +L["World PVP"] = "Welt-PVP" +L["WoW Collector Edition"] = "WoW-Collectors-Edition" +L["Wrathbringer Laz-tarash"] = "Zornschaffer Laz-tarash" +L["Wrath of Spellfire"] = "Zorn des Zauberfeuers" +L["Yor (Heroic Summon)"] = "Yor (heroische Beschwörung)" +L[ [=[You have received an account sharing request +from %s%s|r, accept it?]=] ] = [=[Du hast von %s%s|r eine Anfrage wegen +Account-Austausch erhalten - annehmen?]=] +L[ [=[Your confirmation will still be required any time someone requests your information. + +]=] ] = "Deine Bestätigung wird weiterhin benötigt, wann immer jemand deine Informationen erbittet." +L["Zelemar the Wrathful"] = "Zelemar der Hasserfüllte" +L["Zone"] = true + diff --git a/Altoholic-Addon/Altoholic/Locales/enUS.lua b/Altoholic-Addon/Altoholic/Locales/enUS.lua new file mode 100644 index 0000000..0a4969e --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/enUS.lua @@ -0,0 +1,704 @@ +local debug = false +--[===[@debug@ +debug = true +--@end-debug@]===] + +local L = LibStub("AceLocale-3.0"):NewLocale("Altoholic", "enUS", true, debug) + +L["28 Slot"] = true +L["32 Keys Max"] = true +L["Abyssal Council"] = true +L["Accessories"] = true +L["Account"] = true +L["Account Name"] = true +L["Account Sharing"] = true +L["Account Sharing Enabled"] = true +L["Account Sharing Request"] = true +L["Account sharing request received from %s"] = true +L["Account Summary"] = true +L["Activity"] = true +L["Adamantite Battlegear"] = true +L["Adamantite Deposit"] = true +L["Aged Dalaran Wizard"] = true +L["Aggem Thorncurse"] = true +L["AH"] = true +L["All accounts"] = true +L["All cooldowns are up"] = true +L["Alliance Forces"] = true +L["All-in-one"] = true +L["All realms"] = true +L["Already known by "] = true +L["Altoholic:|r Usage = /altoholic search "] = true +L["Ancient Lichen"] = true +L["and above"] = true +L["Any"] = true +L["Anzu the Raven God (Heroic Summon)"] = true +L["Apprentice"] = true +L["Arcanoweave Vestments"] = true +L["Are also on this quest:"] = true +L["Arena points: "] = true +L["Arena Season %d"] = true +L["Armbreaker Huffaz"] = true +L["Armorsmith"] = true +L["Arthas' Tears"] = true +L["Artisan"] = true +L["at"] = true +L["At least one recipe could not be read"] = true +L["Attendees: "] = true +L["Auctions %s(%d)"] = true +L["Automatically authorize guild bank updates"] = true +L["AutoQuery server |cFFFF0000(disconnection risk)"] = true +L["Avatar of the Martyred"] = true +L["Average Item Level"] = true +L["Azure Templar (Water)"] = true +L["Baelog's Chest"] = true +L["Bags"] = true +L["Bag Usage"] = true +L["Balance"] = true +L["Balzaphon"] = true +L["Bank"] = true +L["Bank bag"] = true +L["Bank not visited yet"] = true +L["Barleybrew Brewery"] = true +L["(based on iLvl)"] = true +L["Bash'ir Landing"] = true +L["Battlecast Garb"] = true +L["BC Collector Edition (Europe)"] = true +L["Beasts Deck"] = true +L["Beast Training"] = true +L[ [=[Be informed when a guildmate sends a mail to one of my alts. + +Mail content is directly visible without having to reconnect the character]=] ] = true +L["Bids %s(%d)"] = true +L["Black Dragon Mail"] = true +L["Black Lotus"] = true +L["Blacksmithing (Lv 60)"] = true +L["Blacksmithing (Lv 70)"] = true +L["Blacksmithing Mail Sets"] = true +L["Blacksmithing Plate Sets"] = true +L["Blade Edge Mountains"] = true +L["Blessings Deck"] = true +L["Blindweed"] = true +L["Blizzard Collectables"] = true +L["Blizzcon 2005"] = true +L["Blizzcon 2007"] = true +L["Bloodsoul Embrace"] = true +L["Bloodthistle"] = true +L["Blood Tiger Harness"] = true +L["Bloodvine"] = true +L["Bloodvine Garb"] = true +L["Blue Dragon Mail"] = true +L["Books"] = true +L["Booty Run"] = true +L["Both factions"] = true +L[ [=[Both parties must enable account sharing +before using this feature (see options)]=] ] = true +L["Box of Chocolates"] = true +L["Brewfest"] = true +L["Briarthorn"] = true +L["Brightly Colored Egg"] = true +L["Bruiseweed"] = true +L["Burning Rage"] = true +L["Cache of the Legion"] = true +L["Calendar"] = true +L["Cannot delete current character"] = true +L["Cannot delete current realm"] = true +L["Cannot link another account's tradeskill"] = true +L["Cannot link another realm's tradeskill"] = true +L["Carefully Wrapped Present"] = true +L["|cFF00FF00Disable|r to avoid this risk"] = true +L[ [=[|cFFFFFFFFIf an item not in the local item cache +is encountered while searching loot tables, +Altoholic will attempt to query the server for 5 new items. + +]=] ] = true +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to send you account sharing requests. +]=] ] = true +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to update their guild bank information with yours automatically. + +]=] ] = true +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates +to see your alts and their professions. + +]=] ] = true +L["Character"] = true +L["Characters"] = true +L["Character %s received !"] = true +L["Character %s successfully deleted"] = true +L["Children's Week"] = true +L["Christmas Gift 2006"] = true +L["Clamp window to screen"] = true +L["Class Books"] = true +L["Classes: Death Knight"] = true +L["Classes: Hunter"] = true +L["Classes: Mage"] = true +L["Classes: Paladin"] = true +L["Classes: Priest"] = true +L["Classes: Rogue"] = true +L["Classes: Shaman"] = true +L["Classes: Warlock"] = true +L["Classes: Warrior"] = true +L["Class Skills"] = true +L["Clear all entries"] = true +L["Clear goblin AH entries"] = true +L["Clear your faction's entries"] = true +L["Click a character's AiL to see its equipment"] = true +L[ [=[Clicking this button will update +your local %s%s|r bank tab +based on %s%s's|r data]=] ] = true +L[ [=[Click this button to ask a player +to share his entire Altoholic Database +and add it to your own]=] ] = true +L["Cloaks"] = true +L["Cloth Set"] = true +L["Conspicuous Urn"] = true +L["Containers"] = true +L["Copper Vein"] = true +L["Could be learned by "] = true +L["Crafted Weapons"] = true +L["Crimson Templar (Fire)"] = true +L["Currencies received !"] = true +L["Dark Iron Deposit"] = true +L["Darkscreecher Akkarai"] = true +L[" days"] = true +L[" days ago"] = true +L["Deadly Gladiator's Weapons"] = true +L["Death Knight"] = true +L["Default"] = true +L["Delete Guild Bank?"] = true +L["Delete this Alt"] = true +L["Delete this Realm"] = true +L["Detailed guild bank count"] = true +L["Devilsaur Armor"] = true +L["Disable warnings"] = true +L["Display warnings in a dialog box"] = true +L["Do you want to open Altoholic's calendar for details ?"] = true +L["Do you want to view it now ?"] = true +L["DPS"] = true +L["Dragonscale"] = true +L["Dreamfoil"] = true +L["Dreaming Glory"] = true +L["Drohn's Distillery"] = true +L["Druid of the Fang (Trash Mob)"] = true +L["Druid Set"] = true +L["Earthen Templar (Earth)"] = true +L["Earthroot"] = true +L["Elemental"] = true +L["Elemental Invasion"] = true +L["Elementals Deck"] = true +L["Elemental Shaman"] = true +L["E-Mail"] = true +L["Emblems of Heroism"] = true +L["Emblems of Valor"] = true +L["Enchanted Adamantite Armor"] = true +L["Enchants"] = true +L["Engineering (Lv 60)"] = true +L["Engineering (Lv 70)"] = true +L[ [=[Enter an account name that will be +used for |cFF00FF00display|r purposes only.]=] ] = true +L["Epic Rewards"] = true +L["Equipment"] = true +L["Equipment Slot"] = true +L["Equipped"] = true +L["Eric The Swift"] = true +L["Ethereum Prison"] = true +L["Expert"] = true +L["Expiry:"] = true +L["Fadeleaf"] = true +L["Faith in Felsteel"] = true +L["Feast of Winter Veil"] = true +L["Fel Iron Chain"] = true +L["Fel Iron Chest"] = true +L["Fel Iron Deposit"] = true +L["Fel Iron Plate"] = true +L["Fel Lotus"] = true +L["Felscale Armor"] = true +L["Fel Skin"] = true +L["Felstalker Armor"] = true +L["Fel Steed"] = true +L["Fel Tinkerer Zortan"] = true +L["Felweed"] = true +L["Festive Gift"] = true +L["Find Upgrade"] = true +L["Firebloom"] = true +L["Fire Resistance Gear"] = true +L["Fireworks Pack"] = true +L["First Prize"] = true +L["Fishing"] = true +L["Fishing Extravaganza"] = true +L["Fishing Poles"] = true +L["Flame Cap"] = true +L["Flame Guard"] = true +L["Food"] = true +L["Forgosh"] = true +L["free"] = true +L["Furies Deck"] = true +L["Fury of the Nether"] = true +L["Gaily Wrapped Present"] = true +L["Garrett Family Chest"] = true +L["General"] = true +L["Gently Shaken Gift"] = true +L["Gezzarak the Huntress"] = true +L["Ghost Mushroom"] = true +L["Gift of Adoration"] = true +L["Glowcap"] = true +L["Gnomish"] = true +L["Goblin"] = true +L["Goblin AH"] = true +L["Golden Sansam"] = true +L["Goldthorn"] = true +L["Gold Vein"] = true +L["Gordok Brewery"] = true +L["Grave Moss"] = true +L["Green Dragon Mail"] = true +L["Grey"] = true +L["Gromsblood"] = true +L["Guild Bank not visited yet (or not guilded)"] = true +L["Guild Bank Remote Update"] = true +L["Guild Bank Tabs"] = true +L["Guild bank tab %s successfully updated !"] = true +L["Guild Communication Enabled"] = true +L["Guild Members"] = true +L["Guild Skills"] = true +L["Guilds received !"] = true +L["Guild %s successfully deleted"] = true +L["Gul'bor"] = true +L["Gurubashi Arena"] = true +L["Hakkari Thorium Vein"] = true +L["Halaa (Nagrand)"] = true +L["Hallow's End"] = true +L["Hard Mode"] = true +L["Harvest Festival"] = true +L["(has auctions)"] = true +L["(has bids)"] = true +L["has come online"] = true +L["has gone offline"] = true +L["(has mail)"] = true +L[" has no mail, last check "] = true +L[" has not visited his/her mailbox yet"] = true +L["Headless Horseman"] = true +L["Heal"] = true +L["Hellfire Fortifications"] = true +L["Henry Stern"] = true +L["Herbalism"] = true +L[" (Heroic)"] = true +L["Heroic Mode Tokens"] = true +L["hide"] = true +L["Hides the UI"] = true +L["Hide this guild in the tooltip"] = true +L["Highlord Kruul"] = true +L["Hoary Templar (Wind)"] = true +L["Honor points: "] = true +L["Horde Forces"] = true +L["Hunter Set"] = true +L["Icecap"] = true +L["Imbued Netherweave"] = true +L["Imperial Plate"] = true +L["Incendicite Mineral Vein"] = true +L["Include guild bank count in the total count"] = true +L["Include guild bank(s)"] = true +L["Include guild members' professions"] = true +L["Include items without level requirement"] = true +L["Include known recipes"] = true +L["Include mailboxes"] = true +L["Increases attack power by %d+"] = true +L["Increases damage and healing done by magical spells and effects by up to %d+"] = true +L["Increases healing done by up to %d+"] = true +L["Indurium Mineral Vein"] = true +L["Inscription"] = true +L["Invalid tradeskill link"] = true +L["Iron Deposit"] = true +L["Ironfeather Armor"] = true +L[" is "] = true +L["Item Level"] = true +L["Item / Location"] = true +L["Items"] = true +L["Journeyman"] = true +L["Karrog"] = true +L["Khadgar's Whisker"] = true +L["Khorium Vein"] = true +L["Khorium Ward"] = true +L["Kingsblood"] = true +L["Krom Stoutarm Chest"] = true +L["Lady Falther'ess"] = true +L["Lake Wintergrasp"] = true +L["Large Obsidian Chunk"] = true +L["last check "] = true +L["Last visit: %s by %s"] = true +L["Leather Set"] = true +L["Leatherworking Leather Sets"] = true +L["Leatherworking Mail Sets"] = true +L["Left-click to"] = true +L["Left-click to |cFF00FF00open"] = true +L["Left-click to invite attendees"] = true +L["Left-click to see this character's equipment"] = true +L["Left click to view"] = true +L["Legendaries"] = true +L["Legendary Mount"] = true +L["Lesser Bloodstone Deposit"] = true +L["Level"] = true +L["Level 30-39"] = true +L["Level 40-49"] = true +L["Level 50-60"] = true +L["Level 70"] = true +L["Level 70 Reputation PVP"] = true +L["Level %d Honor PVP"] = true +L["Levels"] = true +L["Liferoot"] = true +L["Local Time: %s %sRealm Time: %s"] = true +L["Location"] = true +L["Lockpicking"] = true +L["Loot Card Items"] = true +L["Loots"] = true +L["Loot tables"] = true +L["Lord Ahune"] = true +L["Lord Blackwood"] = true +L["Love is in the air"] = true +L["Lucky Red Envelope"] = true +L["Lunacy Deck"] = true +L["Lunar Festival"] = true +L["Lv %s Rewards"] = true +L["Mageroyal"] = true +L["Mage Set"] = true +L["Magregan Deepshadow"] = true +L["Mail"] = true +L["Mail Expiry Warning"] = true +L["Mail is about to expire on at least one character."] = true +L["Mails"] = true +L["Mail Set"] = true +L["Mails %s(%d)"] = true +L["Mail was last checked "] = true +L["Malevus the Mad"] = true +L["Mana Thistle"] = true +L["Master"] = true +L["Master Axesmith"] = true +L["Master Hammersmith"] = true +L["Master Swordsmith"] = true +L["Maximum Level: %s"] = true +L["Max rest XP displayed as 150%"] = true +L["Midsummer Fire Festival"] = true +L["Minimap Icon Angle"] = true +L["Minimap Icon Radius"] = true +L["Minimum Level: %s"] = true +L["Mining"] = true +L["Miscellaneous"] = true +L["Mithril Deposit"] = true +L["Mooncloth"] = true +L["Mountain Silversage"] = true +L["Move to change the angle of the minimap icon"] = true +L["Move to change the radius of the minimap icon"] = true +L["Muddy Churning Waters"] = true +L["N/A"] = true +L["Netherbloom"] = true +L["Nethercite Deposit"] = true +L["Netherdust Bush"] = true +L["Netherscale Armor"] = true +L["Netherstrike Armor"] = true +L["Netherweave Vestments"] = true +L["New mail notification"] = true +L["Nightmare Vine"] = true +L["Noblegarden"] = true +L["No currencies found"] = true +L["No data"] = true +L["No guild found"] = true +L["No match found!"] = true +L["Non Set Accessories"] = true +L["Non Set Cloth"] = true +L["Non Set Leather"] = true +L["Non Set Mail"] = true +L["Non Set Plate"] = true +L["No quest found for "] = true +L["No reputations found"] = true +L["No rest XP"] = true +L[" not found!"] = true +L["Not started"] = true +L["Number of players: %s"] = true +L["Offline Members"] = true +L["Olaf"] = true +L["Ooze Covered Gold Vein"] = true +L["Ooze Covered Mithril Deposit"] = true +L["Ooze Covered Rich Thorium Vein"] = true +L["Ooze Covered Silver Vein"] = true +L["Ooze Covered Thorium Vein"] = true +L["Ooze Covered Truesilver Deposit"] = true +L["open/close"] = true +L["Opera (Shared Drops)"] = true +L["Other"] = true +L["Outdoor Bosses"] = true +L["Paladin Set"] = true +L["Patterns"] = true +L["Peacebloom"] = true +L["Plaguebloom"] = true +L["Plans"] = true +L["Plate Set"] = true +L["Please open this window again"] = true +L["Poisons"] = true +L["Porfus the Gem Gorger"] = true +L["Portals Deck"] = true +L["Priest Set"] = true +L["Primal Batskin"] = true +L["Primal Intent"] = true +L["Primal Mooncloth"] = true +L["Private to friends: %s"] = true +L["Private to guild: %s"] = true +L["Prof. 1"] = true +L["Prof. 2"] = true +L["Professions"] = true +L["Purple Lotus"] = true +L["PVP Cloth Set"] = true +L["PVP Leather Sets"] = true +L["PVP Mail Sets"] = true +L["PVP Plate Sets"] = true +L["Pyron"] = true +L["QuestID"] = true +L["Quest Items"] = true +L["Quest rewards"] = true +L["Quests"] = true +L["Ragveil"] = true +L["Rajaxx's Captains"] = true +L["Random Boss"] = true +L["Rare Fish"] = true +L["Rare Fish Rewards"] = true +L["Razorfen Spearhide"] = true +L["Realm"] = true +L["Realm %s successfully deleted"] = true +L["Reference data not available"] = true +L["Reference data received (%s) !"] = true +L["Refer to the activity pane for more details."] = true +L["Relics"] = true +L["Reputations"] = true +L["Reputations received !"] = true +L["Requesting item %d of %d"] = true +L["Requesting %s information from %s"] = true +L["Request rejected by %s"] = true +L["Reset"] = true +L["Resistance"] = true +L["Rested"] = true +L["Restores %d+ mana per"] = true +L["Rest XP"] = true +L[" results found (Showing "] = true +L["Rethilgore"] = true +L["Revanchion"] = true +L["Rich Adamantite Deposit"] = true +L["Rich Thorium Vein"] = true +L["Riding"] = true +L["Right-Click for options"] = true +L["Right-click to |cFF00FF00drag"] = true +L["Right-Click to find an upgrade"] = true +L["Rogue Proficiencies"] = true +L["Rogue Set"] = true +L["Roogug"] = true +L["Sanguine Hibiscus"] = true +L["Savage Gladiator's Weapons"] = true +L["Scaled Draenic Armor"] = true +L[" scan failed for "] = true +L["Scan mail body (marks it as read)"] = true +L["Scorn"] = true +L["Scourge Invasion"] = true +L["search"] = true +L["Search Containers"] = true +L["Search in bags"] = true +L["Secondary Skills"] = true +L[ [=[Security hint: disable this if you have officer rights +on guild bank tabs that may not be viewed by everyone, +and authorize requests manually]=] ] = true +L[ [=[Security hint: Only enable this when you actually need to transfer data, +disable otherwise]=] ] = true +L["Send account sharing request to:"] = true +L["Sending account sharing request to %s"] = true +L["Sending character %s (%d of %d)"] = true +L["Sending currencies (%d of %d)"] = true +L["Sending guilds (%d of %d)"] = true +L["Sending reference data: %s (%d of %d)"] = true +L["Sending reputations (%d of %d)"] = true +L["Sending table of content (%d items)"] = true +L["Sever"] = true +L["Shadoweave"] = true +L["Shadowforge Cache"] = true +L["Shadow's Embrace"] = true +L["Shaman Set"] = true +L["Shared"] = true +L["Shartuul"] = true +L["%s has disabled account sharing"] = true +L["%s has disabled guild communication"] = true +L["%s has no auctions"] = true +L["%s has no bids"] = true +L["%s has no mail"] = true +L["Shen'dralar Provisioner"] = true +L["Shift-Click to link this info"] = true +L["Shift+Left click to link"] = true +L["show"] = true +L["Show already known/learnable by"] = true +L["Show counters for all accounts"] = true +L["Show counters for both factions"] = true +L["Show counters on gathering nodes"] = true +L["Show FuBar icon"] = true +L["Show FuBar text"] = true +L["Show guild bank count"] = true +L["Show item count per character"] = true +L["Show item ID and item level"] = true +L["Show item source"] = true +L["Show Minimap Icon"] = true +L["Show pets already known/learnable by"] = true +L["Show recipes already known/learnable by"] = true +L["Shows the UI"] = true +L["Show total item count"] = true +L["Silverleaf"] = true +L["Silver Vein"] = true +L["%s is in combat, request cancelled"] = true +L["%s is now ready (%s on %s)"] = true +L["%s is now unlocked (%s on %s)"] = true +L["%s is %s with %s (%d/%d)"] = true +L["Skettis"] = true +L["Skinning"] = true +L["Skyguard Raid"] = true +L["slots"] = true +L["Small Obsidian Chunk"] = true +L["Small Thorium Vein"] = true +L["Smokywood Pastures Extra-Special Gift"] = true +L["Smokywood Pastures Vendor"] = true +L["Socket"] = true +L["Sort loots in descending order"] = true +L["Sothos & Jarien"] = true +L["Soulcloth Embrace"] = true +L["Source"] = true +L["Spawn Of Hakkar"] = true +L["Spellfire"] = true +L["Spellstrike Infusion"] = true +L["Spirit Towers (Terrokar)"] = true +L["%s|r has received a mail from %s"] = true +L[ [=[%s%s|r has requested the bank tab %s%s|r +Send this information ?]=] ] = true +L["%s starts in %d minutes (%s on %s)"] = true +L["Started"] = true +L["Stasis Chambers"] = true +L["Steamwheedle Cartel"] = true +L["Storms Deck"] = true +L["Stormshroud Armor"] = true +L["Stranglekelp"] = true +L["Strength of the Clefthoof"] = true +L["Suggested leveling zone: "] = true +L["Suggestion"] = true +L["Summary"] = true +L["Summoner's Tomb"] = true +L["Sungrass"] = true +L["Superior Rewards"] = true +L[ [=[%sWarning:|r if you accept, %sALL|r information known +by Altoholic will be sent to %s%s|r (bags, money, etc..)]=] ] = true +L["%sWarning:|r make sure this user may view this information before accepting"] = true +L["Swiftthistle"] = true +L["%s will be ready in %d minutes (%s on %s)"] = true +L["%s will be unlocked in %d minutes (%s on %s)"] = true +L["Table of content received (%d items)"] = true +L["Tablet of Ryuneh"] = true +L["Tablet of Will"] = true +L["Tailoring Sets"] = true +L["Tank"] = true +L["T'chali's Voodoo Brewery"] = true +L["Terocone"] = true +L["Terokk"] = true +L["The Darksoul"] = true +L["The Duke of Cinders (Fire)"] = true +L["The Duke of Fathoms (Water)"] = true +L["The Duke of Shards (Earth)"] = true +L["The Duke of Zephyrs (Wind)"] = true +L["Theldren"] = true +L[ [=[There is a risk of disconnection if the queried item +is a loot from a high level dungeon. + +]=] ] = true +L["The Unyielding"] = true +L["The Vault"] = true +L["Thick Draenic Armor"] = true +L["This account"] = true +L["This character"] = true +L["This faction"] = true +L["This field |cFF00FF00cannot|r be left empty."] = true +L[ [=[This name can be anything you like, +it does |cFF00FF00NOT|r have to be the real account name.]=] ] = true +L["This realm"] = true +L[ [=[This will gradually improve the consistency of the searches, +as more items are available in the item cache. + +]=] ] = true +L["Thomas Yance"] = true +L["Thunderbrew Brewery"] = true +L["Ticking Present"] = true +L["Tier 0.5 Quests"] = true +L["Tier %d Tokens"] = true +L["Timed Chest"] = true +L["Tin Vein"] = true +L["toggle"] = true +L["Toggles the UI"] = true +L["Token Hand-Ins"] = true +L["Tooltip"] = true +L["Total owned"] = true +L["Totals"] = true +L["Transfer complete"] = true +L["Transmute"] = true +L["Transparency"] = true +L["Trash Mobs"] = true +L["Treat Bag"] = true +L["Tribal"] = true +L["Tribute Run"] = true +L["Trinkets"] = true +L["Troll Mini bosses"] = true +L["Truesilver Deposit"] = true +L["Twin Spire Ruins"] = true +L["Unknown"] = true +L["Unknown link, please relog this character"] = true +L["Upper Deck"] = true +L["up to"] = true +L["Vakkiz the Windrager"] = true +L["Various Locations"] = true +L["View"] = true +L["View auctions"] = true +L["View bags"] = true +L["View bids"] = true +L["View mailbox"] = true +L["View quest log"] = true +L["Visited"] = true +L["Volcanic Armor"] = true +L["Waiting for %s to accept .."] = true +L["Warlock Set"] = true +L["Warlords Deck"] = true +L["Warn %d minutes before an event starts"] = true +L["Warn when mail expires in less days than this value"] = true +L["Warrior Set"] = true +L["Weapons"] = true +L["Weaponsmith"] = true +L["Week starts on Monday"] = true +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected. + +]=] ] = true +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = true +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be +required before sending any information. + +]=] ] = true +L["Whitemend Wisdom"] = true +L["Wild Draenish Armor"] = true +L["Wild Steelbloom"] = true +L["Wildvine"] = true +L["Will be learnable by "] = true +L["Will be %sdeleted|r in"] = true +L["Will be %sreturned|r in"] = true +L["Windhawk Armor"] = true +L["Wintersbite"] = true +L["Winter Veil Gift"] = true +L[" with "] = true +L["World Drops"] = true +L["World PVP"] = true +L["WoW Collector Edition"] = true +L["Wrathbringer Laz-tarash"] = true +L["Wrath of Spellfire"] = true +L["Yor (Heroic Summon)"] = true +L[ [=[You have received an account sharing request +from %s%s|r, accept it?]=] ] = true +L[ [=[Your confirmation will still be required any time someone requests your information. + +]=] ] = true +L["Zelemar the Wrathful"] = true +L["Zone"] = true diff --git a/Altoholic-Addon/Altoholic/Locales/esES.lua b/Altoholic-Addon/Altoholic/Locales/esES.lua new file mode 100644 index 0000000..6b65b03 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/esES.lua @@ -0,0 +1,737 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "Altoholic", "esES" ) + +if not L then return end + +L["28 Slot"] = "28 casillas" +L["32 Keys Max"] = "Máximo 32 llaves" +L["Abyssal Council"] = "Consejo abisal" +L["Accessories"] = "Accesorios" +L["Account"] = "Cuenta" +L["Account Name"] = "Nombre de cuenta" +L["Account Sharing"] = "Compartición de cuenta" +L["Account Sharing Enabled"] = "Compartición de cuenta activado" +L["Account Sharing Request"] = "Petición de compartir cuenta" +L["Account sharing request received from %s"] = "Petición de compartir cuenta recibida de %s" +L["Account Summary"] = "Resumen de la Cuenta" +L["Activity"] = "Actividad" +L["Adamantite Battlegear"] = "Equipo de Batalla de Adamantita" +L["Adamantite Deposit"] = "Depósito de Adamantita" +L["Aged Dalaran Wizard"] = "Zahorí de Dalaran Envegecido" +L["Aggem Thorncurse"] = "Aggem Malaespina" +L["AH"] = true +L["All accounts"] = "Todas las cuentas" +L["All cooldowns are up"] = "No hay habilidades recargándose" +L["Alliance Forces"] = "Ejercitos de la Alianza" +L["All-in-one"] = "Todo en uno" +L["All realms"] = "Todos los reinos" +L["Already known by "] = "Conocido actualmente por " +L["Altoholic:|r Usage = /altoholic search "] = "Altoholic:|r Uso = /altoholic buscar " +L["Ancient Lichen"] = "Liquen Antiguo" +L["and above"] = "y por encima" +L["Any"] = "Todos" +L["Anzu the Raven God (Heroic Summon)"] = "Anzu El dios Cuervo (Invocación Heroica)" +L["Apprentice"] = "Aprendiz" +L["Arcanoweave Vestments"] = "Vestimentas de Tejido Arcano" +L["Are also on this quest:"] = "Están en esta misión:" +L["Arena points: "] = "Puntos de arena: " +L["Arena Season %d"] = "Arena Temporada %d" +L["Armbreaker Huffaz"] = "Partebrazos Huffaz" +L["Armorsmith"] = "Forjador de Armaduras" +L["Arthas' Tears"] = "Lagrimas de Arthas" +L["Artisan"] = "Artesano" +L["at"] = "a" +L["At least one recipe could not be read"] = "Al menos una receta puede no haber sido leída" +L["Attendees: "] = "Asistentes:" +L["Auctions %s(%d)"] = "Subastas %s(%d)" +L["Automatically authorize guild bank updates"] = "Autorizar automáticamente las actualizaciones el banco de la hermandad" +L["AutoQuery server |cFFFF0000(disconnection risk)"] = "Comprobación automática |cFFFF0000(riesgo de desconexión)" +L["Avatar of the Martyred"] = "Avatar de los Martirizados" +L["Average Item Level"] = "Nivel medio de objetos" +L["Azure Templar (Water)"] = "Templario Azur (Agua)" +L["Baelog's Chest"] = "Cofre de Baelog" +L["Bags"] = "Bolsas" +L["Bag Usage"] = "Bolsas" +L["Balance"] = "Equilibrio" +L["Balzaphon"] = true +L["Bank"] = "Banco" +L["Bank bag"] = "Bolsa en banco" +L["Bank not visited yet"] = "Banco no visitado aún" +L["Barleybrew Brewery"] = "Aprendiz Cebadiz" +L["(based on iLvl)"] = "(basado en el nivel del objeto)" +L["Bash'ir Landing"] = "Alto Bash'ir" +L["Battlecast Garb"] = "Atuendo de Conjuro de Batalla" +L["BC Collector Edition (Europe)"] = "BC Edición de Coleccionista(Europa)" +L["Beasts Deck"] = "Baraja de Bestias" +L["Beast Training"] = "Entrenamiento de bestias" +L[ [=[Be informed when a guildmate sends a mail to one of my alts. + +Mail content is directly visible without having to reconnect the character]=] ] = [=[Serás avisado cuando un compañero de hermandad mande un correo a uno de tus alters. + +El contenido del correo se verá directamente sin tener que reconectar con ese personaje]=] +L["Bids %s(%d)"] = "Pujas %s(%d)" +L["Black Dragon Mail"] = "Malla de Dragón Negro" +L["Black Lotus"] = "Loto Negro" +L["Blacksmithing (Lv 60)"] = "Herrería (Niv 60)" +L["Blacksmithing (Lv 70)"] = "Herrería (Niv 70)" +L["Blacksmithing Mail Sets"] = "Conjuntos de Mallas de Herrería" +L["Blacksmithing Plate Sets"] = "Conjuntos de Placas de Herrería" +L["Blade Edge Mountains"] = "Montañas de Filoespada" +L["Blessings Deck"] = "Baraja de Bendiciones" +L["Blindweed"] = "Carolina" +L["Blizzard Collectables"] = "Coleccionables de Blizzard" +L["Blizzcon 2005"] = true +L["Blizzcon 2007"] = true +L["Bloodsoul Embrace"] = "Abrazo de Alma de Sangre" +L["Bloodthistle"] = "Cardo de Sangre" +L["Blood Tiger Harness"] = "Arnés de Tigre de Sangre" +L["Bloodvine"] = "Vid de Sangre" +L["Bloodvine Garb"] = "Atuendo de Vid de Sangre" +L["Blue Dragon Mail"] = "Malla de Dragón Azul" +L["Books"] = "Libros" +L["Booty Run"] = "El Botín Pirata" +L["Both factions"] = "Ambas facciones" +L[ [=[Both parties must enable account sharing +before using this feature (see options)]=] ] = [=[Ambas partes han de activar la compartición de cuenta +antes de usar esta característica (ver opciones)]=] +L["Box of Chocolates"] = "Caja de Bombones" +L["Brewfest"] = "Fiesta de la Cerveza" +L["Briarthorn"] = "Brezospina" +L["Brightly Colored Egg"] = "Huevo Coloreado" +L["Bruiseweed"] = "Hierba Cardenal" +L["Burning Rage"] = "Ira Ardiente" +L["Cache of the Legion"] = "Alijo de la Legión" +L["Calendar"] = "Calendario" +L["Cannot delete current character"] = "No se puede borrar el personaje actual" +L["Cannot delete current realm"] = "No se puede borrar el reino actual" +L["Cannot link another account's tradeskill"] = "No se puede enlazar el craft de otra cuenta" +L["Cannot link another realm's tradeskill"] = "No se puede enlazar el craft de otro reino" +L["Carefully Wrapped Present"] = "Presente envuelto con cuidado" +L["|cFF00FF00Disable|r to avoid this risk"] = "|cFF00FF00deshabilitar|r para evitar este riesgo" +L[ [=[|cFFFFFFFFIf an item not in the local item cache +is encountered while searching loot tables, +Altoholic will attempt to query the server for 5 new items. + +]=] ] = [=[|cFFFFFFFFSi un objeto no esta en la caché local de objetos +y es encontrado mientras se realiza una búsqueda, +Altoholic preguntará al servidor por 5 nuevos objetos. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to send you account sharing requests. +]=] ] = [=[|cFFFFFFFFSi está |cFF00FF00activada|cFFFFFFFF, esta opción permitirá a otros usuarios +de Altoholic enviarte peticiones para compartir cuenta. +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to update their guild bank information with yours automatically. + +]=] ] = [=[|cFFFFFFFFSi está |cFF00FF00activada|cFFFFFFFF, esta opción permitirá a otros usuarios de Altoholic +actualizar su información del banco de la hermandad con la tuya.. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates +to see your alts and their professions. + +]=] ] = [=[|cFFFFFFFFSi está |cFF00FF00activada|cFFFFFFFF, esta opción permitirá a tus compañeros de hermandad +ver tus alters y sus profesiones. + +]=] +L["Character"] = "Personaje" +L["Characters"] = "Personajes" +L["Character %s received !"] = "¡ Personaje %s recibidas !" +L["Character %s successfully deleted"] = "Personaje %s eliminado correctamente" +L["Children's Week"] = "La semana de los Niños" +L["Christmas Gift 2006"] = "Regalo de Navidad 2006" +L["Class Books"] = "Libros de clase" +L["Classes: Death Knight"] = "Clases: Caballero de la muerte" +L["Classes: Hunter"] = "Clases: Cazador" +L["Classes: Mage"] = "Clases: Mago" +L["Classes: Paladin"] = "Clases: Paladín" +L["Classes: Priest"] = "Clases: Sacerdote" +L["Classes: Rogue"] = "Clases: Pícaro" +L["Classes: Shaman"] = "Clases: Chamán" +L["Classes: Warlock"] = "Clases: Brujo" +L["Classes: Warrior"] = "Clases: Guerrero" +L["Class Skills"] = "Habilidades de clase" +L["Clear all entries"] = "Borrar todas las entradas" +L["Clear goblin AH entries"] = "Borrar entradas de subastas goblin" +L["Clear your faction's entries"] = "Borrar entradas de tu facción" +L["Click a character's AiL to see its equipment"] = "Click en el valor AiL para ver su equipo" +L[ [=[Clicking this button will update +your local %s%s|r bank tab +based on %s%s's|r data]=] ] = [=[Clickear en este botón actualizará +tu banco local de %s%s|r +basádose en los datos de %s%s|r]=] +L[ [=[Click this button to ask a player +to share his entire Altoholic Database +and add it to your own]=] ] = [=[Click en este botón para pedir a un jugador +que comparta su base de datos de Altoholic entera +y añadirla a la tuya]=] +L["Cloaks"] = "Capas" +L["Cloth Set"] = "Set de Tela" +L["Conspicuous Urn"] = "Urna Llamativa" +L["Containers"] = "Almacenes" +L["Copper Vein"] = "Filón de Cobre" +L["Could be learned by "] = "Puede aprenderlo " +L["Crafted Weapons"] = "Armas Construidas" +L["Crimson Templar (Fire)"] = "Templario Carmesí (Fuego)" +L["Currencies received !"] = "¡ Economía recibida !" +L["Dark Iron Deposit"] = "Depósito de Hierro Negro" +L["Darkscreecher Akkarai"] = "Estridador Oscuro Akkarai" +L[" days"] = " días" +L[" days ago"] = " días" +L["Deadly Gladiator's Weapons"] = "Armas de Gladiador mortífero" +L["Death Knight"] = "Caballero de la Muerte" +L["Default"] = "Predeterminado" +L["Delete Guild Bank?"] = "¿Borrar el Banco de la hermandad?" +L["Delete this Alt"] = "Borrar este alter" +L["Delete this Realm"] = "Borrar este reino" +L["Detailed guild bank count"] = "Recuento detallado del banco de hermandad" +L["Devilsaur Armor"] = "Armadura de Demosaurio" +L["Disable warnings"] = "Desactivar alertas" +L["Display warnings in a dialog box"] = "Mostrar alertas en un recuadro de diálogo" +L["Do you want to open Altoholic's calendar for details ?"] = "¿Desea abrir el calendario de Altoholic para obtener más información?" +L["Do you want to view it now ?"] = "¿ Quieres verlo ahora ?" +L["DPS"] = true +L["Dragonscale"] = "Escamas de Dragón" +L["Dreamfoil"] = "Hojasueño" +L["Dreaming Glory"] = "Gloria de Ensueño" +L["Drohn's Distillery"] = "Aprendiz de destilerias Drohn" +L["Druid of the Fang (Trash Mob)"] = "Druida del Colmillo (Enemigos basura)" +L["Druid Set"] = "Set de Druida" +L["Earthen Templar (Earth)"] = "Templario de Tierra (Tierra)" +L["Earthroot"] = "Raiz de Tierra" +L["Elemental"] = true +L["Elemental Invasion"] = "Invasión Elemental" +L["Elementals Deck"] = "Baraja de Elementales" +L["Elemental Shaman"] = "Chamán Elemental" +L["E-Mail"] = "Correo" +L["Emblems of Heroism"] = "Emblemas de Heroísmo" +L["Emblems of Valor"] = "Emblemas de Valor" +L["Enchanted Adamantite Armor"] = "Armadura de Adamantita Encantada" +L["Enchants"] = "Encantamientos" +L["Engineering (Lv 60)"] = "Ingeniería (Niv 60)" +L["Engineering (Lv 70)"] = "Ingeniería (Niv 70)" +L[ [=[Enter an account name that will be +used for |cFF00FF00display|r purposes only.]=] ] = "Introduce un nombre que sólo se usará para |cFF00FF00mostrar|r." +L["Epic Rewards"] = "Recompensas Épicas" +L["Equipment"] = "Equipo" +L["Equipment Slot"] = "Tipo de equipo" +L["Equipped"] = "Equipado" +L["Eric The Swift"] = "Eric 'El Veloz'" +L["Ethereum Prison"] = "Prisión de el Etereum" +L["Expert"] = "Experto" +L["Expiry:"] = "Expiración:" +L["Fadeleaf"] = "Pálida" +L["Faith in Felsteel"] = "Fé en el Acero Vil" +L["Feast of Winter Veil"] = "Festival de Invierno" +L["Fel Iron Chain"] = "Cadena de Hierro Vil" +L["Fel Iron Chest"] = "Cofre de Hierro Vil" +L["Fel Iron Deposit"] = "Depósito de Hierro Vil" +L["Fel Iron Plate"] = "Placa de Hierro Vil" +L["Fel Lotus"] = "Loto Vil" +L["Felscale Armor"] = "Armadura de Escama Vil" +L["Fel Skin"] = "Piel Vil" +L["Felstalker Armor"] = "Armadura de Acechador Vil" +L["Fel Steed"] = "Corcel Vil" +L["Fel Tinkerer Zortan"] = "Manitas Vil Zortan" +L["Felweed"] = "Hierba Vil" +L["Festive Gift"] = "Obsequio Festival" +L["Find Upgrade"] = "Encontrar mejora" +L["Firebloom"] = "Flor de Fuego" +L["Fire Resistance Gear"] = "Equipo de Resistencia al Fuego" +L["Fireworks Pack"] = "Paquete de fuegos de Artificio" +L["First Prize"] = "1er Premio" +L["Fishing"] = "Pesca" +L["Fishing Extravaganza"] = "Concurso de Pesca" +L["Fishing Poles"] = "Cañas de pescar" +L["Flame Cap"] = "Copo de LLamas" +L["Flame Guard"] = "Guardia de las Llamas" +L["Food"] = "Comida" +L["Forgosh"] = true +L["free"] = "libres" +L["Furies Deck"] = "Baraja de furias" +L["Fury of the Nether"] = "Furia del Vacio" +L["Gaily Wrapped Present"] = "Regalo con Envoltorio Alegre" +L["Garrett Family Chest"] = "Cofre de la familia Garrett" +L["General"] = true +L["Gently Shaken Gift"] = "Regalo ligeramente agitado" +L["Gezzarak the Huntress"] = "Gezzarak la Cazadora" +L["Ghost Mushroom"] = "Champiñón Fantasma" +L["Gift of Adoration"] = "Regalo de admiración" +L["Glowcap"] = "Fluochampiñón" +L["Gnomish"] = "Gnómica" +L["Goblin"] = true +L["Goblin AH"] = "Casa de subastas goblin" +L["Golden Sansam"] = "Sansam Dorado" +L["Goldthorn"] = "Espina de Oro" +L["Gold Vein"] = "Filón de Oro" +L["Gordok Brewery"] = "Aprediz de Cerveza gordok" +L["Grave Moss"] = "Musgo de Tumba" +L["Green Dragon Mail"] = "Malla de Dragón Verde" +L["Grey"] = "Gris" +L["Gromsblood"] = "Gromsanguina" +L["Guild Bank not visited yet (or not guilded)"] = "Banco de la Hermandad no visitado aún (o no tienes Hermandad)" +L["Guild Bank Remote Update"] = "Actualización remota del banco de hermandad" +L["Guild Bank Tabs"] = "Banco de hermandad" +L["Guild bank tab %s successfully updated !"] = "¡ Pestaña de banco de hermandad %s actualizada con éxito !" +L["Guild Communication Enabled"] = "Comunicación con hermandad activada" +L["Guild Members"] = "Miembros hermandad" +L["Guild Skills"] = "Habilidades hermandad" +L["Guilds received !"] = "¡ Hermandades recibidas !" +L["Guild %s successfully deleted"] = "Banco de la hermandad %s borrado" +L["Gul'bor"] = true +L["Gurubashi Arena"] = "Arena de Gurubashi" +L["Hakkari Thorium Vein"] = "Filón de Torio de Hakkari" +L["Halaa (Nagrand)"] = true +L["Hallow's End"] = "Halloween" +L["Hard Mode"] = "Modo Difícil" +L["Harvest Festival"] = "Festival de la Cosecha" +L["(has auctions)"] = "(tienes subastas)" +L["(has bids)"] = "(tienes pujas)" +L["has come online"] = "se ha conectado" +L["has gone offline"] = "se ha desconectado" +L["(has mail)"] = "(tienes correo)" +L[" has no mail, last check "] = " no tiene correo, última comprobación hace " +L[" has not visited his/her mailbox yet"] = " no ha visitado su buzón de correos aún" +L["Headless Horseman"] = "Jinete sin Cabeza" +L["Heal"] = "Curación" +L["Hellfire Fortifications"] = "Fortificaciones de Fuego Infernal" +L["Henry Stern"] = true +L["Herbalism"] = "Herboristería" +L[" (Heroic)"] = " (Heroico)" +L["Heroic Mode Tokens"] = "Insignias Heróicas" +L["hide"] = "ocultar" +L["Hides the UI"] = "Ocultar el interfaz" +L["Hide this guild in the tooltip"] = "Oculta esta hermandad de la lista" +L["Highlord Kruul"] = "Alto Señor Kruul" +L["Hoary Templar (Wind)"] = "Templario Vestusto (Viento)" +L["Honor points: "] = "Puntos de honor: " +L["Horde Forces"] = "Ejercitos de la Horda" +L["Hunter Set"] = "Set de Cazador" +L["Icecap"] = "Setelo" +L["Imbued Netherweave"] = "Tejido Abisal Imbuido" +L["Imperial Plate"] = "Placas Imperiales" +L["Incendicite Mineral Vein"] = "Filón de Incendicita" +L["Include guild bank count in the total count"] = "Incluir bancos de hermandad en el conteo total" +L["Include guild bank(s)"] = "Incluir bancos de hermandad" +L["Include guild members' professions"] = "Incluir profesiones de miembros de hermandad" +L["Include items without level requirement"] = "Incluir objetos sin requerimientos de nivel" +L["Include known recipes"] = "Incluir recetas conocidas" +L["Include mailboxes"] = "Incluir buzones de correo" +L["Increases attack power by %d+"] = "Aumenta %d+ el poder de ataque" +L["Increases damage and healing done by magical spells and effects by up to %d+"] = "Aumenta el daño y la curación realizada por hechizos mágicos y efectos hasta %d+" +L["Increases healing done by up to %d+"] = "Aumenta la curación hasta %d+" +L["Indurium Mineral Vein"] = "Filón de Indurio" +L["Inscription"] = "Inscripción" +L["Invalid tradeskill link"] = "Enlace de craft no válido" +L["Iron Deposit"] = "Depósito de Hierro" +L["Ironfeather Armor"] = "Armadura Plumahierro" +L[" is "] = " es " +L["Item Level"] = "Nivel del objeto" +L["Item / Location"] = "Objeto / Ubicación" +L["Items"] = "Objetos" +L["Journeyman"] = "Oficial" +L["Karrog"] = true +L["Khadgar's Whisker"] = "Mostacho de Khadgar" +L["Khorium Vein"] = "Filón de Korio" +L["Khorium Ward"] = "Resguardo de Korio" +L["Kingsblood"] = "Sangrerregia" +L["Krom Stoutarm Chest"] = "Cofre de Krom Brazorecio" +L["Lady Falther'ess"] = "Dama Falther'ess" +L["Lake Wintergrasp"] = "Lago Conquista del Invierno" +L["Large Obsidian Chunk"] = "Trozo de Obsidiana Grande" +L["last check "] = "ultima comprobación " +L["Last visit: %s by %s"] = "Última visita: %s por %s" +L["Leather Set"] = "Set de Cuero" +L["Leatherworking Leather Sets"] = "Sets de Cuero de Peletería" +L["Leatherworking Mail Sets"] = "Sets de Mallas de Peletería" +L["Left-click to"] = "Click-Izd. para" +L["Left-click to |cFF00FF00open"] = "Click-Izd. para |cFF00FF00abrir" +L["Left-click to invite attendees"] = "Click izquierdo para invitar a los asistentes" +L["Left-click to see this character's equipment"] = "Click-Izd. para ver el equipo de este personaje" +L["Left click to view"] = "Click-Izd. para ver" +L["Legendaries"] = "Legendarios" +L["Legendary Mount"] = "Montura legendaria" +L["Lesser Bloodstone Deposit"] = "Depósito de Sangrita Inferior" +L["Level"] = "Nivel" +L["Level 30-39"] = "Nivel 30-39" +L["Level 40-49"] = "Nivel 40-49" +L["Level 50-60"] = "Nivel 50-60" +L["Level 70"] = "Nivel 70" +L["Level 70 Reputation PVP"] = "JcJ Reputación Nivel 70" +L["Level %d Honor PVP"] = "JcJ Honor Nivel %d" +L["Levels"] = "Niveles" +L["Liferoot"] = "Vidaraíz" +L["Local Time: %s %sRealm Time: %s"] = "Hora local: %s %sHora del reino: %s" +L["Location"] = "Localización" +L["Lockpicking"] = "Ganzúa" +L["Loot Card Items"] = "Objetos de Cartas Botin" +L["Loots"] = "Saqueos" +L["Loot tables"] = "Saqueos" +L["Lord Ahune"] = "Ahune" +L["Lord Blackwood"] = "Lord Bosque Negro" +L["Love is in the air"] = "El Amor esta en el aire" +L["Lucky Red Envelope"] = "Sobre de la suerte Rojo" +L["Lunacy Deck"] = "Baraja de Locuras" +L["Lunar Festival"] = "Festival de la luna" +L["Lv %s Rewards"] = "Recompensas Nivel %s" +L["Mageroyal"] = "Marregal" +L["Mage Set"] = "Conjunto de Mago" +L["Magregan Deepshadow"] = "Magregan Sombraprofunda" +L["Mail"] = "Correo" +L["Mail Expiry Warning"] = "Advertencia de expiración del correo" +L["Mail is about to expire on at least one character."] = "Hay correo a punto de expirar en al menos un personaje." +L["Mails"] = "Correos" +L["Mail Set"] = "Conjunto de Mallas" +L["Mails %s(%d)"] = "Correos %s(%d)" +L["Mail was last checked "] = "Correo comprobado hace " +L["Malevus the Mad"] = "Malevus la Loca" +L["Mana Thistle"] = "Cardo de maná" +L["Master"] = "Maestro" +L["Master Axesmith"] = "Maestro Forjador de Hachas" +L["Master Hammersmith"] = "Maestro Forjador de Martillos" +L["Master Swordsmith"] = "Maestro Forjador de Espadas" +L["Maximum Level: %s"] = "Nivel Máximo: %s" +L["Max rest XP displayed as 150%"] = "Mostrar el maximo de XP reposado como 150%" +L["Midsummer Fire Festival"] = "Festival del Solsticio de Verano" +L["Minimap Icon Angle"] = "Angulo del icono del minimapa" +L["Minimap Icon Radius"] = "Radio del icono del minimapa" +L["Minimum Level: %s"] = "Nivel Mínimo: %s" +L["Mining"] = "Minería" +L["Miscellaneous"] = "Misc." +L["Mithril Deposit"] = "Depósito de Mithril" +L["Mooncloth"] = "Tela Lunar" +L["Mountain Silversage"] = "Salviargenta de Montaña" +L["Move to change the angle of the minimap icon"] = "Mover para cambiar el ángulo del icono en el minimapa" +L["Move to change the radius of the minimap icon"] = "Mover para cambiar el angulo del icono en el minimapa" +L["Muddy Churning Waters"] = "Cebo de Fangoapestoso" +L["N/A"] = "N/D" +L["Netherbloom"] = "Flor Abisal" +L["Nethercite Deposit"] = "Depósito de abisalita" +L["Netherdust Bush"] = "Arbusto de Polvo Abisal" +L["Netherscale Armor"] = "Armadura de Escamas Abisales" +L["Netherstrike Armor"] = "Armadura de Golpe Abisal" +L["Netherweave Vestments"] = "Vestimentas de Tejido Abisal" +L["New mail notification"] = "Notificación de nuevo correo" +L["Nightmare Vine"] = "Vid Pesadilla" +L["Noblegarden"] = "Jardín Noble" +L["No currencies found"] = "No se ha encontrado economía" +L["No data"] = "Sin datos" +L["No guild found"] = "No se ha encontrado hermandad" +L["No match found!"] = "No se encontro nada!" +L["Non Set Accessories"] = "Accesorios Independientes" +L["Non Set Cloth"] = "Armaduras de Tela Independientes" +L["Non Set Leather"] = "Armaduras de Cuero Independientes" +L["Non Set Mail"] = "Armaduras de Mallas Independientes" +L["Non Set Plate"] = "Armaduras de Placas Independientes" +L["No quest found for "] = "No hay misiones para " +L["No reputations found"] = "No se han encontrado reputaciones" +L["No rest XP"] = "Sin reposo de XP" +L[" not found!"] = " no encontrado!" +L["Not started"] = "No iniciado" +L["Number of players: %s"] = "Número de jugadores: %s" +L["Offline Members"] = "Miembros desconectados" +L["Olaf"] = true +L["Ooze Covered Gold Vein"] = "Filón de Oro Cubierto de Moco" +L["Ooze Covered Mithril Deposit"] = "Depósito de Mithril cubierto de Moco" +L["Ooze Covered Rich Thorium Vein"] = "Filón de Torio Enriquecido Cubierto de Moco" +L["Ooze Covered Silver Vein"] = "Filón de Plata cubierto de Moco" +L["Ooze Covered Thorium Vein"] = "Filón de Torio Cubierto de Moco" +L["Ooze Covered Truesilver Deposit"] = "Depósito de Veraplata Cubierto de Moco" +L["open/close"] = "abrir/cerrar" +L["Opera (Shared Drops)"] = "Opera (Loots Comunes)" +L["Other"] = "Otros" +L["Outdoor Bosses"] = "Bosses de Exteriores" +L["Paladin Set"] = "Conjunto de Paladín" +L["Patterns"] = "Patrones" +L["Peacebloom"] = "Flor de Paz" +L["Plaguebloom"] = "Flor de la Peste" +L["Plans"] = "Planos" +L["Plate Set"] = "Conjunto de Placas" +L["Please open this window again"] = "Por favor abra esta ventana de nuevo" +L["Poisons"] = "Venenos" +L["Porfus the Gem Gorger"] = "Porfus el Engullidor de Gemas" +L["Portals Deck"] = "Baraja de Portales" +L["Priest Set"] = "Conjunto de Sacerdote" +L["Primal Batskin"] = "Piel de Murciélago Primigenia" +L["Primal Intent"] = "Intención Primigenia" +L["Primal Mooncloth"] = "Tela Lunar Primigenia" +L["Private to friends: %s"] = "Exclusivo para amigos: %s" +L["Private to guild: %s"] = "Exclusivo para hermandad: %s" +L["Prof. 1"] = true +L["Prof. 2"] = true +L["Professions"] = "Profesiones" +L["Purple Lotus"] = "Loto Cárdeno" +L["PVP Cloth Set"] = "Conjunto de Tela JcJ" +L["PVP Leather Sets"] = "Conjunto de Cuero JcJ" +L["PVP Mail Sets"] = "Conjunto de Mallas JcJ" +L["PVP Plate Sets"] = "Conjunto de Placas JcJ" +L["Pyron"] = true +L["QuestID"] = "ID de misión" +L["Quest Items"] = "Objetos de misión" +L["Quest rewards"] = "Recompensas de misión" +L["Quests"] = "Misiones" +L["Ragveil"] = "Velada" +L["Rajaxx's Captains"] = "Los Capitanes de Rajaxx" +L["Random Boss"] = "Jefe aleatorio" +L["Rare Fish"] = "Peces Raros" +L["Rare Fish Rewards"] = "Recompensas por Peces Raros" +L["Razorfen Spearhide"] = "Cuerolanza de Rajacieno" +L["Realm"] = "Reino" +L["Realm %s successfully deleted"] = "Reino %s borrado correctamente" +L["Reference data not available"] = "Datos de referencia no disponibles" +L["Reference data received (%s) !"] = "Datos de referencia recibidos (%s)" +L["Refer to the activity pane for more details."] = "Revisa el panel de actividad para saber más detalles." +L["Relics"] = "Reliquias" +L["Reputations"] = "Reputación" +L["Reputations received !"] = "¡ Reputaciones recibidas !" +L["Requesting item %d of %d"] = "Pidiendo parte %d de %d" +L["Requesting %s information from %s"] = "Pidiendo %s información de %s" +L["Request rejected by %s"] = "Petición rechazada por %s" +L["Reset"] = "Reiniciar" +L["Resistance"] = "Resistencia" +L["Rested"] = "Reposo" +L["Restores %d+ mana per"] = "Restaura %d+ p. de mana cada" +L["Rest XP"] = "XP de reposo" +L[" results found (Showing "] = " resultados encontrados (mostrando " +L["Rethilgore"] = true +L["Revanchion"] = true +L["Rich Adamantite Deposit"] = "Depósito Rico de Adamantita" +L["Rich Thorium Vein"] = "Filón de Torio Enriquecido" +L["Riding"] = "Equitación" +L["Right-Click for options"] = "Click-Dch. para opciones" +L["Right-click to |cFF00FF00drag"] = "Click-Dch. para |cFF00FF00desplazar" +L["Right-Click to find an upgrade"] = "Click-Dch. para encontrar una mejora" +L["Rogue Proficiencies"] = "Habilidades de pícaro" +L["Rogue Set"] = "Conjunto de Pícaro" +L["Roogug"] = true +L["Sanguine Hibiscus"] = "Hibisco sanguino" +L["Savage Gladiator's Weapons"] = "Armas de Gladiador indómito" +L["Scaled Draenic Armor"] = "Armadura Draénica Escamada" +L[" scan failed for "] = " análisis fallido por " +L["Scan mail body (marks it as read)"] = "Analizar el contenido de los correos (marcarlos como leídos)" +L["Scorn"] = true +L["Scourge Invasion"] = "Invasión de la Plaga" +L["search"] = "buscar" +L["Search Containers"] = "Buscar contenedores" +L["Search in bags"] = "Buscar en las bolsas" +L["Secondary Skills"] = "Habilidades secundarias" +L[ [=[Security hint: disable this if you have officer rights +on guild bank tabs that may not be viewed by everyone, +and authorize requests manually]=] ] = [=[Consejo de seguridad: desaciva esto si tienes permisos de oficial +en pestañas del banco de la hermandad que no deben ser vistas por todos, +y autoriza las peticiones manualmente]=] +L[ [=[Security hint: Only enable this when you actually need to transfer data, +disable otherwise]=] ] = [=[Consejo de seguridad: Actívalo sólo cuando necesites transferir datos, +desactívalo el resto del tiempo]=] +L["Send account sharing request to:"] = "Mandar petición de compartir cuenta a:" +L["Sending account sharing request to %s"] = "Mandando petición de compartir cuenta a %s" +L["Sending character %s (%d of %d)"] = "Mandando personaje %s (%d de %d)" +L["Sending currencies (%d of %d)"] = "Mandando economía (%d de %d)" +L["Sending guilds (%d of %d)"] = "Mandando hermandades (%d de %d)" +L["Sending reference data: %s (%d of %d)"] = "Enviando datos de referencia: %s (%d de %d)" +L["Sending reputations (%d of %d)"] = "Mandando reputaciones (%d de %d)" +L["Sending table of content (%d items)"] = "Mandando tabla de contenidos (%d partes)" +L["Sever"] = true +L["Shadoweave"] = "Tejido de Sombra" +L["Shadowforge Cache"] = "Alijo de Forjatiniebla" +L["Shadow's Embrace"] = "Abrazo de las Sombras" +L["Shaman Set"] = "Conjunto de Chamán" +L["Shared"] = "Compartidos" +L["Shartuul"] = true +L["%s has disabled account sharing"] = "%s tiene desconectado la compartición de cuenta" +L["%s has disabled guild communication"] = "%s ha desactivado la comunicación de hermandad" +L["%s has no auctions"] = "%s no tiene subastas" +L["%s has no bids"] = "%s no tiene pujas" +L["%s has no mail"] = "%s no tiene correo" +L["Shen'dralar Provisioner"] = "Proveedor Shen'dralar" +L["Shift-Click to link this info"] = "Mays+Click para enlazar esta información" +L["Shift+Left click to link"] = "Mays+Click-Izd. para enlazar" +L["show"] = "mostrar" +L["Show already known/learnable by"] = "Mostrar conocido/puede aprenderse por" +L["Show counters for all accounts"] = "Mostrar contadores de todas las cuentas" +L["Show counters for both factions"] = "Mostrar contadores de ambas facciones" +L["Show counters on gathering nodes"] = "Mostrar contadores en los nodos de recolección" +L["Show FuBar icon"] = "Mostrar icono FuBar" +L["Show FuBar text"] = "Mostrar texto FuBar" +L["Show guild bank count"] = "Mostrar recuento de objetos en el banco de la hermandad" +L["Show item count per character"] = "Mostrar recuento de objetos por personaje" +L["Show item ID and item level"] = "Mostrar ID y nivel del objeto" +L["Show item source"] = "Mostrar origen del objeto" +L["Show Minimap Icon"] = "Mostrar icono del minimapa" +L["Show pets already known/learnable by"] = "Muestra las mascotas ya conocidas o por conocer por" +L["Show recipes already known/learnable by"] = "Muestra las recetas ya conocidas o por conocer por" +L["Shows the UI"] = "Mostrar el interfaz" +L["Show total item count"] = "Mostrar recuento total de objetos" +L["Silverleaf"] = "HojaPlata" +L["Silver Vein"] = "Filón de Plata" +L["%s is in combat, request cancelled"] = "%s está en combate, petición cancelada" +L["%s is now ready (%s on %s)"] = "%s ya está listo (%s en %s)" +L["%s is now unlocked (%s on %s)"] = "%s ya está desbloqueado (%s en %s)" +L["%s is %s with %s (%d/%d)"] = "%s es %s con %s (%d/%d)" +L["Skettis"] = true +L["Skinning"] = "Desollar" +L["Skyguard Raid"] = "Raid Guardiadelcielo" +L["slots"] = "casillas" +L["Small Obsidian Chunk"] = "Trozo de Obsidiana Pequeño" +L["Small Thorium Vein"] = "Filón Pequeño de Torio" +L["Smokywood Pastures Extra-Special Gift"] = "Regalo superespecial de los Pastos de Bosquehumeante" +L["Smokywood Pastures Vendor"] = "Vendedor de los Pastos de Bosquehumeante" +L["Socket"] = "Ranuras" +L["Sort loots in descending order"] = "Ordenar saqueos en orden decreciente" +L["Sothos & Jarien"] = "Sothos y Jarien" +L["Soulcloth Embrace"] = "Abrazo de Paño de Alma" +L["Source"] = "Fuente:" +L["Spawn Of Hakkar"] = "Engendro de Hakkar" +L["Spellfire"] = "Fuego de Hechizo" +L["Spellstrike Infusion"] = "Infusíon de Golpe de Hechizo" +L["Spirit Towers (Terrokar)"] = "Tour des esprits (Terrokar)" +L["%s|r has received a mail from %s"] = "%s|r ha recibido un correo de %s" +L[ [=[%s%s|r has requested the bank tab %s%s|r +Send this information ?]=] ] = [=[%s%s|r ha solicitado la pestaña del banco %s%s|r +¿ Mandar esta información ?]=] +L["%s starts in %d minutes (%s on %s)"] = "%s empieza en %d minutos (%s en %s)" +L["Started"] = "Iniciado" +L["Stasis Chambers"] = "Cámara de Estasis" +L["Steamwheedle Cartel"] = "Cártel Bonvapor" +L["Storms Deck"] = "Baraja de Tormentas" +L["Stormshroud Armor"] = "Armadura de Sudario de Tormentas" +L["Stranglekelp"] = "Alga Estranguladora" +L["Strength of the Clefthoof"] = "Fuerza de los Uñagrieta" +L["Suggested leveling zone: "] = "Zona para subir de nivel sugerida: " +L["Suggestion"] = "Sugerencia" +L["Summary"] = "Resumen" +L["Summoner's Tomb"] = "Tumba del Invocador" +L["Sungrass"] = "Solea" +L["Superior Rewards"] = "Recompensas Superiores" +L[ [=[%sWarning:|r if you accept, %sALL|r information known +by Altoholic will be sent to %s%s|r (bags, money, etc..)]=] ] = [=[%sCuidado:|r si aceptas, %sTODA|r la información conocida +por Altoholic será enviada a %s%s|r (bolsas, dinero, etc..)]=] +L["%sWarning:|r make sure this user may view this information before accepting"] = "%sCuidado:|r asegúrate de que quieres que este usuario vea la información antes de aceptar" +L["Swiftthistle"] = "Cardopresto" +L["%s will be ready in %d minutes (%s on %s)"] = "%s estará listo en %d minutos (%s en %s)" +L["%s will be unlocked in %d minutes (%s on %s)"] = "%s será desbloqueado en %d minutos (%s en %s)" +L["Table of content received (%d items)"] = "Tabla de contenidos recibida (%d partes)" +L["Tablet of Ryuneh"] = "Tablilla de Ryun'eh" +L["Tablet of Will"] = "Tablilla de voluntad" +L["Tailoring Sets"] = "Conjuntos de Sastrería" +L["Tank"] = "Tanque" +L["T'chali's Voodoo Brewery"] = "Aprendiz de cerveza vudu T'chali" +L["Terocone"] = "Teropiña" +L["Terokk"] = true +L["The Darksoul"] = "El Alma Negra" +L["The Duke of Cinders (Fire)"] = "El Duque de las Brasas (Fuego)" +L["The Duke of Fathoms (Water)"] = "El Duque de las Profundidades (Agua)" +L["The Duke of Shards (Earth)"] = "El Duque de las Esquirlas (Tierra)" +L["The Duke of Zephyrs (Wind)"] = "El Duque de los Céfiros (Viento)" +L["Theldren"] = true +L[ [=[There is a risk of disconnection if the queried item +is a loot from a high level dungeon. + +]=] ] = [=[Aun así, hay un riesgo de desconexión al preguntar por un objeto +si es un drop de una instancia de alto nivel. + +]=] +L["The Unyielding"] = "Los Implacables" +L["The Vault"] = "La Cámara" +L["Thick Draenic Armor"] = "Armadura Draenei Gruesa" +L["This character"] = "Este personaje" +L["This faction"] = "Esta facción" +L["This field |cFF00FF00cannot|r be left empty."] = "Este campo |cFF00FF00no puede|r ser dejado en blanco." +L[ [=[This name can be anything you like, +it does |cFF00FF00NOT|r have to be the real account name.]=] ] = [=[Este nombre puede ser cualquiera, +|cFF00FF00NO|r hace falta que sea un nombre real.]=] +L["This realm"] = "Este reino" +L[ [=[This will gradually improve the consistency of the searches, +as more items are available in the item cache. + +]=] ] = [=[Esto mejorará gradualmente la consistencia de las busquedas, +ya que habrá mas objetos en la cache de objetos. + +]=] +L["Thomas Yance"] = true +L["Thunderbrew Brewery"] = "Aprendiz Cebatruenos" +L["Ticking Present"] = "Obsequio que hace Tic-Tac" +L["Tier 0.5 Quests"] = "Tier 0.5 Misiones" +L["Tier %d Tokens"] = "Tier %d Insignias" +L["Timed Chest"] = "Cofres contrareloj" +L["Tin Vein"] = "Filón de Estaño" +L["toggle"] = "alternar" +L["Toggles the UI"] = "Alternar el interfaz" +L["Token Hand-Ins"] = "Insignias" +L["Tooltip"] = "Ventana emergente" +L["Total owned"] = "Total poseídos" +L["Totals"] = "Totales" +L["Transfer complete"] = "Transferencia completada" +L["Transmute"] = "Transmutar" +L["Transparency"] = "Transparencia" +L["Trash Mobs"] = "Enemigos basura" +L["Treat Bag"] = "Bolsa de premios" +L["Tribal"] = true +L["Tribute Run"] = true +L["Trinkets"] = "Abalorios" +L["Troll Mini bosses"] = "Mini Jefes Trolls" +L["Truesilver Deposit"] = "Depósito de Veraplata" +L["Twin Spire Ruins"] = true +L["Unknown"] = "Desconocido" +L["Unknown link, please relog this character"] = "Enlace desconocido, por favor, entra con este personaje" +L["Upper Deck"] = true +L["up to"] = "hasta" +L["Vakkiz the Windrager"] = "Vakkiz el Foribundo del Viento" +L["Various Locations"] = "Varios Lugares" +L["View"] = "Ver" +L["View auctions"] = "Ver las subastas" +L["View bags"] = "Ver las bolsas" +L["View bids"] = "Ver las pujas" +L["View mailbox"] = "Ver el buzón de correos" +L["View quest log"] = "Ver el libro de misiones" +L["Visited"] = "Visitado" +L["Volcanic Armor"] = "Armadura Volcánica" +L["Waiting for %s to accept .."] = "Esperando a que %s acepte .." +L["Warlock Set"] = "Conjunto de Brujo" +L["Warlords Deck"] = "Baraja de Señores de la guerra" +L["Warn %d minutes before an event starts"] = "Avisar con %d minutos de antelación del inicio de un evento" +L["Warn when mail expires in less days than this value"] = "Avisar cuando el correo expira en menos días que los indicados" +L["Warrior Set"] = "Conjunto de Guerrero" +L["Weapons"] = "Armas" +L["Weaponsmith"] = "Forjador de Armas" +L["Week starts on Monday"] = "La semana empieza el Lunes" +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected. + +]=] ] = [=[Si está |cFFFF0000desactivada|cFFFFFFFF, todas las peticiones serán automáticamente rechazadas. + +]=] +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = "Si está |cFFFF0000desactivada|cFFFFFFFF, no habrá comunicación con la hermandad." +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be +required before sending any information. + +]=] ] = [=[Si está |cFFFF0000desactivada|cFFFFFFFF, se te pedirá confirmación +antes de mandar ninguna información. + +]=] +L["Whitemend Wisdom"] = "Sabiduría con Remiendos Blancos" +L["Wild Draenish Armor"] = "Armadura Draenei Salvage" +L["Wild Steelbloom"] = "Acerita Salvaje" +L["Wildvine"] = "Atriplex Salvaje" +L["Will be learnable by "] = "Podría aprenderlo " +L["Windhawk Armor"] = "Armadura de Halcón del Viento" +L["Wintersbite"] = "Ivernalia" +L["Winter Veil Gift"] = "Regalo del Festival de Invierno" +L[" with "] = " con " +L["World Drops"] = "Saqueos del Mundo" +L["World PVP"] = "JcJ Global" +L["WoW Collector Edition"] = "WoW Edición de Coleccionista" +L["Wrathbringer Laz-tarash"] = "Encolerizador Laz-tarash" +L["Wrath of Spellfire"] = "Cólera de Hechizo de Fuego" +L["Yor (Heroic Summon)"] = "Yor (Invocación Heroica)" +L[ [=[You have received an account sharing request +from %s%s|r, accept it?]=] ] = [=[Has recibido una petición de compartir cuenta + de %s%s|r, ¿ la aceptas ?]=] +L[ [=[Your confirmation will still be required any time someone requests your information. + +]=] ] = [=[Se te pedirá confirmación cada vez que alguien solicite tu información. + +]=] +L["Zelemar the Wrathful"] = "Zelemar El Colérico" +L["Zone"] = "Zona" + diff --git a/Altoholic-Addon/Altoholic/Locales/esMX.lua b/Altoholic-Addon/Altoholic/Locales/esMX.lua new file mode 100644 index 0000000..6a181b7 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/esMX.lua @@ -0,0 +1,708 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "Altoholic", "esMX" ) + +if not L then return end + +L["28 Slot"] = "28 casillas" +L["32 Keys Max"] = "Máximo 32 llaves" +L["Abyssal Council"] = "Consejo abisal" +L["Accessories"] = "Accesorios" +L["Account"] = "Cuenta" +L["Account Name"] = "Nombre de cuenta" +L["Account Sharing"] = "Compartición de cuenta" +L["Account Sharing Enabled"] = "Compartición de cuenta activado" +L["Account Sharing Request"] = "Petición de compartir cuenta" +L["Account sharing request received from %s"] = "Petición de compartir cuenta recibida de %s" +L["Account Summary"] = "Resumen de la Cuenta" +L["Activity"] = "Actividad" +L["Adamantite Battlegear"] = "Equipo de Batalla de Adamantita" +L["Adamantite Deposit"] = "Depósito de Adamantita" +L["Aged Dalaran Wizard"] = "Zahorí de Dalaran Envegecido" +L["Aggem Thorncurse"] = "Aggem Malaespina" +L["AH"] = true +L["All accounts"] = "Todas las cuentas" +L["All cooldowns are up"] = "No hay habilidades recargándose" +L["Alliance Forces"] = "Ejercitos de la Alianza" +L["All-in-one"] = "Todo en uno" +L["All realms"] = "Todos los reinos" +L["Already known by "] = "Conocido actualmente por " +L["Altoholic:|r Usage = /altoholic search "] = "Altoholic:|r Uso = /altoholic buscar " +L["Ancient Lichen"] = "Liquen Antiguo" +L["and above"] = "y por encima" +L["Any"] = "Todos" +L["Anzu the Raven God (Heroic Summon)"] = "Anzu El dios Cuervo (Invocación Heroica)" +L["Apprentice"] = "Aprendiz" +L["Arcanoweave Vestments"] = "Vestimentas de Tejido Arcano" +L["Are also on this quest:"] = "Estan en esta misión:" +L["Arena points: "] = "Puntos de arena: " +L["Arena Season %d"] = "Arena Temporada %d" +L["Armbreaker Huffaz"] = "Partebrazos Huffaz" +L["Armorsmith"] = "Forjador de Armaduras" +L["Arthas' Tears"] = "Lagrimas de Arthas" +L["Artisan"] = "Artesano" +L["at"] = "a" +L["At least one recipe could not be read"] = "Al menos una receta puede no haber sido leída" +L["Auctions %s(%d)"] = "Subastas %s(%d)" +L["Automatically authorize guild bank updates"] = "Autorizar automáticamente las actualizaciones el banco de la hermandad" +L["AutoQuery server |cFFFF0000(disconnection risk)"] = "Comprobación automática |cFFFF0000(riesgo de desconexión)" +L["Avatar of the Martyred"] = "Avatar de los Martirizados" +L["Average Item Level"] = "Nivel medio de objetos" +L["Azure Templar (Water)"] = "Templario Azur (Agua)" +L["Baelog's Chest"] = "Cofre de Baelog" +L["Bags"] = "Bolsas" +L["Bag Usage"] = "Bolsas" +L["Balance"] = "Equilibrio" +L["Balzaphon"] = true +L["Bank"] = "Banco" +L["Bank bag"] = "Bolsa en banco" +L["Bank not visited yet"] = "Banco no visitado aún" +L["Barleybrew Brewery"] = "Aprendiz Cebadiz" +L["(based on iLvl)"] = "(basado en el nivel del objeto)" +L["Bash'ir Landing"] = "Alto Bash'ir" +L["Battlecast Garb"] = "Atuendo de Conjuro de Batalla" +L["BC Collector Edition (Europe)"] = "BC Edición de Coleccionista(Europa)" +L["Beasts Deck"] = "Baraja de Bestias" +L["Beast Training"] = "Entrenamiento de bestias" +L[ [=[Be informed when a guildmate sends a mail to one of my alts. + +Mail content is directly visible without having to reconnect the character]=] ] = [=[Serás avisado cuando un compañero de hermandad mande un correo a uno de tus alters. + +El contenido del correo se verá directamente sin tener que reconectar con ese personaje]=] +L["Bids %s(%d)"] = "Pujas %s(%d)" +L["Black Dragon Mail"] = "Malla de Dragón Negro" +L["Black Lotus"] = "Loto Negro" +L["Blacksmithing (Lv 60)"] = "Herrería (Niv 60)" +L["Blacksmithing (Lv 70)"] = "Herrería (Niv 70)" +L["Blacksmithing Mail Sets"] = "Sets de Mallas de Herrería" +L["Blacksmithing Plate Sets"] = "Sets de Placas de Herrería" +L["Blade Edge Mountains"] = "Montañas de Filoespada" +L["Blessings Deck"] = "Baraja de Bendiciones" +L["Blindweed"] = "Carolina" +L["Blizzard Collectables"] = "Blizzard Colecionables" +L["Blizzcon 2005"] = true +L["Blizzcon 2007"] = true +L["Bloodsoul Embrace"] = "Abrazo de Alma de Sangre" +L["Bloodthistle"] = "Cardo de Sangre" +L["Blood Tiger Harness"] = "Arnés de Tigre de Sangre" +L["Bloodvine"] = "Vid de Sangre" +L["Bloodvine Garb"] = "Atuendo de Vid de Sangre" +L["Blue Dragon Mail"] = "Malla de Dragón Azul" +L["Books"] = "Libros" +L["Booty Run"] = "El Botín Pirata" +L["Both factions"] = true +L[ [=[Both parties must enable account sharing +before using this feature (see options)]=] ] = [=[Ambas partes han de activar la compartición de cuenta +antes de usar esta característica (ver opciones)]=] +L["Box of Chocolates"] = "Caja de Bombones" +L["Brewfest"] = "Fiesta de la Cerveza" +L["Briarthorn"] = "Brezospina" +L["Brightly Colored Egg"] = "Huevo Coloreado" +L["Bruiseweed"] = "Hierba Cardenal" +L["Burning Rage"] = "Ira Ardiente" +L["Cache of the Legion"] = "Alijo de la Legión" +L["Cannot delete current character"] = "No se puede borrar el personaje actual" +L["Cannot delete current realm"] = "No se puede borrar el reino actual" +L["Cannot link another account's tradeskill"] = "No se puede enlazar el craft de otra cuenta" +L["Cannot link another realm's tradeskill"] = "No se puede enlazar el craft de otro reino" +L["Carefully Wrapped Present"] = "Presente envuelto con cuidado" +L["|cFF00FF00Disable|r to avoid this risk"] = "|cFF00FF00deshabilitar|r para evitar este riesgo" +L[ [=[|cFFFFFFFFIf an item not in the local item cache +is encountered while searching loot tables, +Altoholic will attempt to query the server for 5 new items. + +]=] ] = [=[|cFFFFFFFFSi un objeto no esta en la caché local de objetos +y es encontrado mientras se realiza una búsqueda, +Altoholic preguntará al servidor por 5 nuevos objetos. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to send you account sharing requests. +]=] ] = [=[|cFFFFFFFFSi está |cFF00FF00activada|cFFFFFFFF, esta opción permitirá a otros usuarios +de Altoholic enviarte peticiones para compartir cuenta. +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to update their guild bank information with yours automatically. + +]=] ] = [=[|cFFFFFFFFSi está |cFF00FF00activada|cFFFFFFFF, esta opción permitirá a otros usuarios de Altoholic +actualizar su información del banco de la hermandad con la tuya.. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates +to see your alts and their professions. + +]=] ] = [=[|cFFFFFFFFSi está |cFF00FF00activada|cFFFFFFFF, esta opción permitirá a tus compañeros de hermandad +ver tus alters y sus profesiones. + +]=] +L["Character"] = "Personaje" +L["Characters"] = "Personajes" +L["Character %s received !"] = "¡ Personaje %s recibidas !" +L["Character %s successfully deleted"] = "Personaje %s eliminado correctamente" +L["Children's Week"] = "La semana de los Niños" +L["Christmas Gift 2006"] = "Regalo de Navidad 2006" +L["Class Books"] = "Libros de clase" +L["Classes: Death Knight"] = "Clases: Caballero de la muerte" +L["Classes: Hunter"] = "Clases: Cazador" +L["Classes: Mage"] = "Clases: Mago" +L["Classes: Paladin"] = "Clases: Paladín" +L["Classes: Priest"] = "Clases: Sacerdote" +L["Classes: Rogue"] = "Clases: Pícaro" +L["Classes: Shaman"] = "Clases: Chamán" +L["Classes: Warlock"] = "Clases: Brujo" +L["Classes: Warrior"] = "Clases: Guerrero" +L["Class Skills"] = "Habilidades de clase" +L["Clear all entries"] = "Borrar todas las entradas" +L["Clear goblin AH entries"] = "Borrar entradas de subastas goblin" +L["Clear your faction's entries"] = "Borrar entradas de tu facción" +L["Click a character's AiL to see its equipment"] = "Click en el valor AiL para ver su equipo" +L[ [=[Clicking this button will update +your local %s%s|r bank tab +based on %s%s's|r data]=] ] = [=[Clickear en este botón actualizará +tu banco local de %s%s|r +basádose en los datos de %s%s|r]=] +L[ [=[Click this button to ask a player +to share his entire Altoholic Database +and add it to your own]=] ] = [=[Click en este botón para pedir a un jugador +que comparta su base de datos de Altoholic entera +y añadirla a la tuya]=] +L["Cloaks"] = "Capas" +L["Cloth Set"] = "Set de Tela" +L["Conspicuous Urn"] = "Urna Llamativa" +L["Containers"] = "Almacenes" +L["Copper Vein"] = "Filón de Cobre" +L["Could be learned by "] = "Puede aprenderlo " +L["Crafted Weapons"] = "Armas Construidas" +L["Crimson Templar (Fire)"] = "Templario Carmesí (Fuego)" +L["Currencies received !"] = "¡ Economía recibida !" +L["Dark Iron Deposit"] = "Depósito de Hierro Negro" +L["Darkscreecher Akkarai"] = "Estridador Oscuro Akkarai" +L[" days"] = " días" +L[" days ago"] = " días" +L["Deadly Gladiator's Weapons"] = "Armas de Gladiador mortífero" +L["Death Knight"] = "Caballero de la Muerte" +L["Default"] = "Predeterminado" +L["Delete Guild Bank?"] = "¿Borrar el Banco de la hermandad?" +L["Delete this Alt"] = "Borrar este alter" +L["Delete this Realm"] = "Borrar este reino" +L["Devilsaur Armor"] = "Armadura de Demosaurio" +L["Do you want to view it now ?"] = "¿ Quieres verlo ahora ?" +L["DPS"] = true +L["Dragonscale"] = "Escamas de Dragón" +L["Dreamfoil"] = "Hojasueño" +L["Dreaming Glory"] = "Gloria de Ensueño" +L["Drohn's Distillery"] = "Aprendiz de destilerias Drohn" +L["Druid of the Fang (Trash Mob)"] = "Druida del Colmillo (Enemigos basura)" +L["Druid Set"] = "Set de Druida" +L["Earthen Templar (Earth)"] = "Templario de Tierra (Tierra)" +L["Earthroot"] = "Raiz de Tierra" +L["Elemental"] = true +L["Elemental Invasion"] = "Invasión Elemental" +L["Elementals Deck"] = "Baraja de Elementales" +L["Elemental Shaman"] = "Chamán Elemental" +L["E-Mail"] = "Correo" +L["Emblems of Heroism"] = "Emblemas de Heroísmo" +L["Emblems of Valor"] = "Emblemas de Valor" +L["Enchanted Adamantite Armor"] = "Armadura de Adamantita Encantada" +L["Enchants"] = "Encantamientos" +L["Engineering (Lv 60)"] = "Ingeniería (Niv 60)" +L["Engineering (Lv 70)"] = "Ingeniería (Niv 70)" +L[ [=[Enter an account name that will be +used for |cFF00FF00display|r purposes only.]=] ] = "Introduce un nombre que sólo se usará para |cFF00FF00mostrar|r." +L["Epic Rewards"] = "Recompensas Épicas" +L["Equipment"] = "Equipo" +L["Equipment Slot"] = "Tipo de equipo" +L["Equipped"] = "Equipado" +L["Eric The Swift"] = "Eric 'El Veloz'" +L["Ethereum Prison"] = "Prisión de el Etereum" +L["Expert"] = "Experto" +L["Expiry:"] = "Expiración:" +L["Fadeleaf"] = "Pálida" +L["Faith in Felsteel"] = "Fé en el Acero Vil" +L["Feast of Winter Veil"] = "Festival de Invierno" +L["Fel Iron Chain"] = "Cadena de Hierro Vil" +L["Fel Iron Chest"] = "Cofre de Hierro Vil" +L["Fel Iron Deposit"] = "Depósito de Hierro Vil" +L["Fel Iron Plate"] = "Placa de Hierro Vil" +L["Fel Lotus"] = "Loto Vil" +L["Felscale Armor"] = "Armadura de Escama Vil" +L["Fel Skin"] = "Piel Vil" +L["Felstalker Armor"] = "Armadura de Acechador Vil" +L["Fel Steed"] = "Corcel Vil" +L["Fel Tinkerer Zortan"] = "Manitas Vil Zortan" +L["Felweed"] = "Hierba Vil" +L["Festive Gift"] = "Obsequio Festival" +L["Find Upgrade"] = "Encontrar mejora" +L["Firebloom"] = "Flor de Fuego" +L["Fire Resistance Gear"] = "Equipo de Resistencia al Fuego" +L["Fireworks Pack"] = "Paquete de fuegos de Artificio" +L["First Prize"] = "1er Premio" +L["Fishing"] = "Pesca" +L["Fishing Extravaganza"] = "Concurso de Pesca" +L["Fishing Poles"] = "Cañas de pescar" +L["Flame Cap"] = "Copo de LLamas" +L["Flame Guard"] = "Guardia de las Llamas" +L["Food"] = "Comida" +L["Forgosh"] = true +L["free"] = "libres" +L["Furies Deck"] = "Baraja de furias" +L["Fury of the Nether"] = "Furia del Vacio" +L["Gaily Wrapped Present"] = "Regalo con Emboltorio Alegre" +L["Garrett Family Chest"] = "Cofre de la familia Garrett" +L["Gently Shaken Gift"] = "Regalo ligeramente agitado" +L["Gezzarak the Huntress"] = "Gezzarak la Cazadora" +L["Ghost Mushroom"] = "Champiñon Fantasma" +L["Gift of Adoration"] = "Regalo de admiración" +L["Gnomish"] = "Gnómica" +L["Goblin"] = true +L["Goblin AH"] = "Casa de subastas goblin" +L["Golden Sansam"] = "Sansam Dorado" +L["Goldthorn"] = "Espina de Oro" +L["Gold Vein"] = "Filón de Oro" +L["Gordok Brewery"] = "Aprediz de Cerveza gordok" +L["Grave Moss"] = "Musgo de Tumba" +L["Green Dragon Mail"] = "Malla de Dragón Verde" +L["Grey"] = "Gris" +L["Gromsblood"] = "Gromsanguina" +L["Guild Bank not visited yet (or not guilded)"] = "Banco de la Hermandad no visitado aún (o no tienes Hermandad)" +L["Guild Bank Remote Update"] = "Actualización remota del banco de hermandad" +L["Guild Bank Tabs"] = "Banco de hermandad" +L["Guild bank tab %s successfully updated !"] = "¡ Pestaña de banco de hermandad %s actualizada con éxito !" +L["Guild Communication Enabled"] = "Comunicación con hermandad activada" +L["Guild Members"] = "Miembros hermandad" +L["Guild Skills"] = "Habilidades hermandad" +L["Guilds received !"] = "¡ Hermandades recibidas !" +L["Guild %s successfully deleted"] = "Banco de la hermandad %s borrado" +L["Gul'bor"] = true +L["Gurubashi Arena"] = "Arena de Gurubashi" +L["Hakkari Thorium Vein"] = "Filón de Torio de Hakkari" +L["Halaa (Nagrand)"] = true +L["Hallow's End"] = "Halloween" +L["Hard Mode"] = true +L["Harvest Festival"] = "Festival de la Cosecha" +L["(has auctions)"] = "(tienes subastas)" +L["(has bids)"] = "(tienes pujas)" +L["has come online"] = "se ha conectado" +L["has gone offline"] = "se ha desconectado" +L["(has mail)"] = "(tienes correo)" +L[" has no mail, last check "] = " no tiene correo, última comprobación hace " +L[" has not visited his/her mailbox yet"] = " no ha visitado su buzón de correos aún" +L["Headless Horseman"] = "Jinete sin Cabeza" +L["Heal"] = "Curación" +L["Hellfire Fortifications"] = "Fortificaciones de Fuego Infernal" +L["Henry Stern"] = true +L["Herbalism"] = "Herboristería" +L[" (Heroic)"] = " (Heroico)" +L["Heroic Mode Tokens"] = "Insignias Heróicas" +L["hide"] = "ocultar" +L["Hides the UI"] = "Ocultar el interfaz" +L["Hide this guild in the tooltip"] = "Oculta esta hermandad de la lista" +L["Highlord Kruul"] = "Alto Señor Kruul" +L["Hoary Templar (Wind)"] = "Templario Vestusto (Viento)" +L["Honor points: "] = "Puntos de honor: " +L["Horde Forces"] = "Ejercitos de la Horda" +L["Hunter Set"] = "Set de Cazador" +L["Icecap"] = "Setelo" +L["Imbued Netherweave"] = "Tejido Abisal Imbuido" +L["Imperial Plate"] = "Placas Imperiales" +L["Incendicite Mineral Vein"] = "Filón de Incendicita" +L["Include guild bank count in the total count"] = true +L["Include guild bank(s)"] = "Incluir bancos de hermandad" +L["Include items without level requirement"] = "Incluir objetos sin requerimientos de nivel" +L["Include known recipes"] = "Incluir recetas conocidas" +L["Include mailboxes"] = "Incluir buzones de correo" +L["Increases attack power by %d+"] = "Aumenta %d+ el poder de ataque" +L["Increases damage and healing done by magical spells and effects by up to %d+"] = "Aumenta el daño y la curación realizada por hechizos mágicos y efectos hasta %d+" +L["Increases healing done by up to %d+"] = "Aumenta la curación hasta %d+" +L["Indurium Mineral Vein"] = "Filón de Indurio" +L["Inscription"] = "Inscripción" +L["Invalid tradeskill link"] = "Enlace de craft no válido" +L["Iron Deposit"] = "Depósito de Hierro" +L["Ironfeather Armor"] = "Armadura Plumahierro" +L[" is "] = " es " +L["Item Level"] = "Nivel del objeto" +L["Item / Location"] = "Objeto / Ubicación" +L["Items"] = "Objetos" +L["Journeyman"] = "Oficial" +L["Karrog"] = true +L["Khadgar's Whisker"] = "Mostacho de Khadgar" +L["Khorium Vein"] = "Filón de Korio" +L["Khorium Ward"] = "Resguardo de Korio" +L["Kingsblood"] = "Sangrerregia" +L["Krom Stoutarm Chest"] = "Cofre de Krom Brazorecio" +L["Lady Falther'ess"] = "Dama Falther'ess" +L["Lake Wintergrasp"] = "Lago Conquista del Invierno" +L["Large Obsidian Chunk"] = "Trozo de Obsidiana Grande" +L["last check "] = "ultima comprobación " +L["Last visit: %s by %s"] = "Ultima visita: %s by %s" +L["Leather Set"] = "Set de Cuero" +L["Leatherworking Leather Sets"] = "Sets de Cuero de Peletería" +L["Leatherworking Mail Sets"] = "Sets de Mallas de Peletería" +L["Left-click to"] = "Click-izdo para" +L["Left-click to |cFF00FF00open"] = "Botón izquierdo para |cFF00FF00abrir" +L["Left-click to see this character's equipment"] = "Click-izdo para ver el equipo de este personaje" +L["Left click to view"] = true +L["Legendaries"] = "Legendarios" +L["Legendary Mount"] = "Montura legendaria" +L["Lesser Bloodstone Deposit"] = "Depósito de Sangrita Inferior" +L["Level"] = "Nivel" +L["Level 30-39"] = "Nivel 30-39" +L["Level 40-49"] = "Nivel 40-49" +L["Level 50-60"] = "Nivel 50-60" +L["Level 70"] = "Nivel 70" +L["Level 70 Reputation PVP"] = "JcJ Reputación Nivel 70" +L["Level %d Honor PVP"] = "JcJ Honor Nivel %d" +L["Levels"] = "Niveles" +L["Liferoot"] = "Vidaraíz" +L["Local Time: %s %sRealm Time: %s"] = "Hora local: %s %sHora del reino: %s" +L["Lockpicking"] = "Ganzúa" +L["Loot Card Items"] = "Objetos de Cartas Botin" +L["Loots"] = "Saqueos" +L["Loot tables"] = "Saqueos" +L["Lord Ahune"] = "Ahune" +L["Lord Blackwood"] = "Lord Bosque Negro" +L["Love is in the air"] = "El Amor esta en el aire" +L["Lucky Red Envelope"] = "Sobre de la suerte Rojo" +L["Lunacy Deck"] = "Baraja de Locuras" +L["Lunar Festival"] = "Festival de la luna" +L["Lv %s Rewards"] = "Recompensas Nivel %s" +L["Mageroyal"] = "Marregal" +L["Mage Set"] = "Set de Mago" +L["Magregan Deepshadow"] = "Magregan Sombraprofunda" +L["Mail"] = "Correo" +L["Mail Expiry Warning"] = "Advertencia de expiración del correo" +L["Mail is about to expire on at least one character."] = "Hay correo a punto de expirar en al menos un personaje." +L["Mails"] = "Correos" +L["Mail Set"] = "Set de Mallas" +L["Mails %s(%d)"] = "Correos %s(%d)" +L["Mail was last checked "] = "Correo comprobado hace " +L["Malevus the Mad"] = "Malevus la Loca" +L["Mana Thistle"] = "Cardo de maná" +L["Master"] = "Maestro" +L["Master Axesmith"] = "Maestro Forjador de Hachas" +L["Master Hammersmith"] = "Maestro Forjador de Martillos" +L["Master Swordsmith"] = "Maestro Forjador de Espadas" +L["Max rest XP displayed as 150%"] = "Mostrar el maximo de XP reposado como 150%" +L["Midsummer Fire Festival"] = "Festival del Solsticio de Verano" +L["Minimap Icon Angle"] = "Angulo del icono del minimapa" +L["Minimap Icon Radius"] = "Radio del icono del minimapa" +L["Mining"] = "Minería" +L["Miscellaneous"] = "Misc." +L["Mithril Deposit"] = "Depósito de Mithril" +L["Mooncloth"] = "Tela Lunar" +L["Mountain Silversage"] = "Salviargenta de Montaña" +L["Move to change the angle of the minimap icon"] = "Mover para cambiar el ángulo del icono en el minimapa" +L["Move to change the radius of the minimap icon"] = "Mover para cambiar el angulo del icono en el minimapa" +L["Muddy Churning Waters"] = "Cebo de Fangoapestoso" +L["N/A"] = "N/D" +L["Netherbloom"] = "Flor Abisal" +L["Nethercite Deposit"] = "Depósito de abisalita" +L["Netherdust Bush"] = "Arbusto de Polvo Abisal" +L["Netherscale Armor"] = "Armadura de Escamas Abisales" +L["Netherstrike Armor"] = "Armadura de Golpe Abisal" +L["Netherweave Vestments"] = "Vestimentas de Tejido Abisal" +L["New mail notification"] = "Notificación de nuevo correo" +L["Nightmare Vine"] = "Vid Pesadilla" +L["Noblegarden"] = true +L["No currencies found"] = "No se ha encontrado economía" +L["No data"] = "Sin datos" +L["No guild found"] = "No se ha encontrado hermandad" +L["No match found!"] = "No se encontro nada!" +L["Non Set Accessories"] = "Accesorios Independientes" +L["Non Set Cloth"] = "Armaduras de Tela Independientes" +L["Non Set Leather"] = "Armaduras de Cuero Independientes" +L["Non Set Mail"] = "Armaduras de Mallas Independientes" +L["Non Set Plate"] = "Armaduras de Placas Independientes" +L["No quest found for "] = "No hay misiones para " +L["No reputations found"] = "No se han encontrado reputaciones" +L["No rest XP"] = "Sin reposo de XP" +L[" not found!"] = " no encontrado!" +L["Not started"] = "No iniciado" +L["Offline Members"] = "Miembros desconectados" +L["Olaf"] = true +L["Ooze Covered Gold Vein"] = "Filón de Oro Cubierto de Moco" +L["Ooze Covered Mithril Deposit"] = "Depósito de Mithril cubierto de Moco" +L["Ooze Covered Rich Thorium Vein"] = "Filón de Torio Enriquecido Cubierto de Moco" +L["Ooze Covered Silver Vein"] = "Filón de Plata cubierto de Moco" +L["Ooze Covered Thorium Vein"] = "Filón de Torio Cubierto de Moco" +L["Ooze Covered Truesilver Deposit"] = "Depósito de Veraplata Cubierto de Moco" +L["open/close"] = "abrir/cerrar" +L["Opera (Shared Drops)"] = "Opera (Loots Comunes)" +L["Other"] = "Otros" +L["Outdoor Bosses"] = "Bosses de Exteriores" +L["Paladin Set"] = "Set de Paladín" +L["Patterns"] = "Patrones" +L["Peacebloom"] = "Flor de Paz" +L["Plaguebloom"] = "Flor de la Peste" +L["Plans"] = "Planos" +L["Plate Set"] = "Set de Placas" +L["Please open this window again"] = "Por favor abra esta ventana de nuevo" +L["Poisons"] = "Venenos" +L["Porfus the Gem Gorger"] = "Porfus el Engullidor de Gemas" +L["Portals Deck"] = "Baraja de Portales" +L["Priest Set"] = "Set de Sacerdote" +L["Primal Batskin"] = "Piel de Murciélago Primigenia" +L["Primal Intent"] = "Intención Primigenia" +L["Primal Mooncloth"] = "Tela Lunar Primigenia" +L["Prof. 1"] = true +L["Prof. 2"] = true +L["Professions"] = "Profesiones" +L["Purple Lotus"] = "Loto Cárdeno" +L["PVP Cloth Set"] = "Set de Tela JcJ" +L["PVP Leather Sets"] = "Set de Cuero JcJ" +L["PVP Mail Sets"] = "Set de Mallas JcJ" +L["PVP Plate Sets"] = "Set de Placas JcJ" +L["Pyron"] = true +L["QuestID"] = "ID de misión" +L["Quest Items"] = "Objetos de misión" +L["Quest rewards"] = "Recompensas de misión" +L["Quests"] = "Misiones" +L["Ragveil"] = "Velada" +L["Rajaxx's Captains"] = "Los Capitanes de Rajaxx" +L["Random Boss"] = "Jefe aleatorio" +L["Rare Fish"] = "Peces Raros" +L["Rare Fish Rewards"] = "Recompensas por Peces Raros" +L["Razorfen Spearhide"] = "Cuerolanza de Rajacieno" +L["Realm"] = "Reino" +L["Realm %s successfully deleted"] = "Reino %s borrado correctamente" +L["Reference data not available"] = true +L["Reference data received (%s) !"] = true +L["Refer to the activity pane for more details."] = "Revisa el panel de actividad para saber más detalles." +L["Relics"] = "Reliquias" +L["Reputations"] = "Reputación" +L["Reputations received !"] = "¡ Reputaciones recibidas !" +L["Requesting item %d of %d"] = "Pidiendo parte %d de %d" +L["Requesting %s information from %s"] = "Pidiendo %s información de %s" +L["Request rejected by %s"] = "Petición rechazada por %s" +L["Reset"] = "Reiniciar" +L["Resistance"] = "Resistencia" +L["Rested"] = "Reposo" +L["Restores %d+ mana per"] = "Restaura %d+ p. de mana cada" +L["Rest XP"] = "XP de reposo" +L[" results found (Showing "] = " resultados encontrados (mostrando " +L["Rethilgore"] = true +L["Revanchion"] = true +L["Rich Adamantite Deposit"] = "Depósito Rico de Adamantita" +L["Rich Thorium Vein"] = "Filón de Torio Enriquecido" +L["Riding"] = "Equitación" +L["Right-Click for options"] = "Click-dcho para opciones" +L["Right-click to |cFF00FF00drag"] = "Botón derecho para |cFF00FF00desplazar" +L["Right-Click to find an upgrade"] = "Botón derecho para encontrar una mejora" +L["Rogue Proficiencies"] = "Habilidades de pícaro" +L["Rogue Set"] = "Set de Pícaro" +L["Roogug"] = true +L["Savage Gladiator's Weapons"] = "Armas de Gladiador indómito" +L["Scaled Draenic Armor"] = "Armadura Draénica Escamada" +L[" scan failed for "] = " análisis fallido por " +L["Scan mail body (marks it as read)"] = "Analizar el contenido de los correos (marcarlos como leídos)" +L["Scorn"] = true +L["Scourge Invasion"] = "Invasión de la Plaga" +L["search"] = "buscar" +L["Search Containers"] = "Buscar contenedores" +L["Search in bags"] = "Buscar en las bolsas" +L["Secondary Skills"] = "Habilidades secundarias" +L[ [=[Security hint: disable this if you have officer rights +on guild bank tabs that may not be viewed by everyone, +and authorize requests manually]=] ] = [=[Consejo de seguridad: desaciva esto si tienes permisos de oficial +en pestañas del banco de la hermandad que no deben ser vistas por todos, +y autoriza las peticiones manualmente]=] +L[ [=[Security hint: Only enable this when you actually need to transfer data, +disable otherwise]=] ] = [=[Consejo de seguridad: Actívalo sólo cuando necesites transferir datos, +desactívalo el resto del tiempo]=] +L["Send account sharing request to:"] = "Mandar petición de compartir cuenta a:" +L["Sending account sharing request to %s"] = "Mandando petición de compartir cuenta a %s" +L["Sending character %s (%d of %d)"] = "Mandando personaje %s (%d de %d)" +L["Sending currencies (%d of %d)"] = "Mandando economía (%d de %d)" +L["Sending guilds (%d of %d)"] = "Mandando hermandades (%d de %d)" +L["Sending reference data: %s (%d of %d)"] = true +L["Sending reputations (%d of %d)"] = "Mandando reputaciones (%d de %d)" +L["Sending table of content (%d items)"] = "Mandando tabla de contenidos (%d partes)" +L["Sever"] = true +L["Shadoweave"] = "Tejido de Sombra" +L["Shadowforge Cache"] = "Alijo de Forjatiniebla" +L["Shadow's Embrace"] = "Abrazo de las Sombras" +L["Shaman Set"] = "Set de Chamán" +L["Shared"] = "Compartidos" +L["Shartuul"] = true +L["%s has disabled account sharing"] = "%s tiene desconectado la compartición de cuenta" +L["%s has disabled guild communication"] = "%s ha desactivado la comunicación de hermandad" +L["%s has no auctions"] = "%s no tiene subastas" +L["%s has no bids"] = "%s no tiene pujas" +L["%s has no mail"] = "%s no tiene correo" +L["Shen'dralar Provisioner"] = "Proveedor Shen'dralar" +L["Shift-Click to link this info"] = "Mays+Click para enlazar esta información" +L["Shift+Left click to link"] = true +L["show"] = "mostrar" +L["Show already known/learnable by"] = "Mostrar conocido/puede aprenderse por" +L["Show counters for all accounts"] = "Mostrar contadores de todas las cuentas" +L["Show counters for both factions"] = "Mostrar contadores de ambas facciones" +L["Show counters on gathering nodes"] = "Mostrar contadores en los nodos de recolección" +L["Show FuBar icon"] = "Mostrar icono FuBar" +L["Show FuBar text"] = "Mostrar texto FuBar" +L["Show guild bank count"] = "Mostrar recuento de objetos en el banco de la hermandad" +L["Show item count per character"] = "Mostrar recuento de objetos por personaje" +L["Show item ID and item level"] = "Mostrar ID y nivel del objeto" +L["Show item source"] = "Mostrar origen del objeto" +L["Show Minimap Icon"] = "Mostrar icono del minimapa" +L["Shows the UI"] = "Mostrar el interfaz" +L["Show total item count"] = "Mostrar recuento total de objetos" +L["Silverleaf"] = "HojaPlata" +L["Silver Vein"] = "Filón de Plata" +L["%s is in combat, request cancelled"] = "%s está en combate, petición cancelada" +L["Skettis"] = true +L["Skinning"] = "Desollar" +L["Skyguard Raid"] = "Raid Guardiadelcielo" +L["slots"] = "casillas" +L["Small Obsidian Chunk"] = "Trozo de Obsidiana Pequeño" +L["Small Thorium Vein"] = "Filón Pequeño de Torio" +L["Smokywood Pastures Extra-Special Gift"] = "Regalo superespecial de los Pastos de Bosquehumeante" +L["Smokywood Pastures Vendor"] = "Vendedor de los Pastos de Bosquehumeante" +L["Socket"] = "Ranuras" +L["Sort loots in descending order"] = "Ordenar saqueos en orden decreciente" +L["Sothos & Jarien"] = "Sothos y Jarien" +L["Soulcloth Embrace"] = "Abrazo de Paño de Alma" +L["Source"] = "Fuente:" +L["Spawn Of Hakkar"] = "Engendro de Hakkar" +L["Spellfire"] = "Fuego de Hechizo" +L["Spellstrike Infusion"] = "Infusíon de Golpe de Hechizo" +L["Spirit Towers (Terrokar)"] = "Tour des esprits (Terrokar)" +L["%s|r has received a mail from %s"] = "%s|r ha recibido un correo de %s" +L[ [=[%s%s|r has requested the bank tab %s%s|r +Send this information ?]=] ] = [=[%s%s|r ha solicitado la pestaña del banco %s%s|r +¿ Mandar esta información ?]=] +L["Started"] = "Iniciado" +L["Stasis Chambers"] = "Cámara de Estasis" +L["Steamwheedle Cartel"] = "Cártel Bonvapor" +L["Storms Deck"] = "Baraja de Tormentas" +L["Stormshroud Armor"] = "Armadura de Sudario de Tormentas" +L["Stranglekelp"] = "Alga Estranguladora" +L["Strength of the Clefthoof"] = "Fuerza de los Uñagrieta" +L["Suggested leveling zone: "] = "Zona para subir de nivel sugerida: " +L["Suggestion"] = "Sugerencia" +L["Summary"] = "Resumen" +L["Summoner's Tomb"] = true +L["Sungrass"] = "Solea" +L["Superior Rewards"] = "Recompensas Superiores" +L[ [=[%sWarning:|r if you accept, %sALL|r information known +by Altoholic will be sent to %s%s|r (bags, money, etc..)]=] ] = [=[%sCuidado:|r si aceptas, %sTODA|r la información conocida +por Altoholic será enviada a %s%s|r (bolsas, dinero, etc..)]=] +L["%sWarning:|r make sure this user may view this information before accepting"] = "%sCuidado:|r asegúrate de que quieres que este usuario vea la información antes de aceptar" +L["Swiftthistle"] = "CardoVeloz" +L["Table of content received (%d items)"] = "Tabla de contenidos recibida (%d partes)" +L["Tablet of Ryuneh"] = "Tablilla de Ryun'eh" +L["Tablet of Will"] = "Tablilla de voluntad" +L["Tailoring Sets"] = "Sets de Sastrería" +L["Tank"] = "Tanque" +L["T'chali's Voodoo Brewery"] = "Aprendiz de cerveza vudu T'chali" +L["Terocone"] = "Teropiña" +L["Terokk"] = true +L["The Darksoul"] = "El Alma Negra" +L["The Duke of Cinders (Fire)"] = "El Duque de las Brasas (Fuego)" +L["The Duke of Fathoms (Water)"] = "El Duque de las Profundidades (Agua)" +L["The Duke of Shards (Earth)"] = "El Duque de las Esquirlas (Tierra)" +L["The Duke of Zephyrs (Wind)"] = "El Duque de los Céfiros (Viento)" +L["Theldren"] = true +L[ [=[There is a risk of disconnection if the queried item +is a loot from a high level dungeon. + +]=] ] = [=[Aun así, hay un riesgo de desconexión al preguntar por un objeto +si es un drop de una instancia de alto nivel. + +]=] +L["The Unyielding"] = "Los Implacables" +L["The Vault"] = true +L["Thick Draenic Armor"] = "Armadura Draenei Gruesa" +L["This character"] = true +L["This faction"] = true +L["This field |cFF00FF00cannot|r be left empty."] = "Este campo |cFF00FF00no puede|r ser dejado en blanco." +L[ [=[This name can be anything you like, +it does |cFF00FF00NOT|r have to be the real account name.]=] ] = [=[Este nombre puede ser cualquiera, +|cFF00FF00NO|r hace falta que sea un nombre real.]=] +L["This realm"] = "Este reino" +L[ [=[This will gradually improve the consistency of the searches, +as more items are available in the item cache. + +]=] ] = [=[Esto mejorará gradualmente la consistencia de las busquedas, +ya que habrá mas objetos en la cache de objetos. + +]=] +L["Thomas Yance"] = true +L["Thunderbrew Brewery"] = "Aprendiz Cebatruenos" +L["Ticking Present"] = "Obsequio que hace Tic-Tac" +L["Tier 0.5 Quests"] = "Tier 0.5 Misiones" +L["Tier %d Tokens"] = "Tier %d Insignias" +L["Timed Chest"] = "Cofres contrareloj" +L["Tin Vein"] = "Filón de Estaño" +L["toggle"] = "alternar" +L["Toggles the UI"] = "Alternar el interfaz" +L["Token Hand-Ins"] = "Insignias" +L["Total owned"] = "Total poseídos" +L["Totals"] = "Totales" +L["Transfer complete"] = "Transferencia completada" +L["Transmute"] = "Transmutar" +L["Trash Mobs"] = "Enemigos basura" +L["Treat Bag"] = "Bolsa de premios" +L["Tribal"] = true +L["Tribute Run"] = true +L["Trinkets"] = "Abalorios" +L["Troll Mini bosses"] = "Mini Jefes Trolls" +L["Truesilver Deposit"] = "Depósito de Veraplata" +L["Twin Spire Ruins"] = true +L["Unknown"] = "Desconocido" +L["Unknown link, please relog this character"] = "Enlace desconocido, por favor, entra con este personaje" +L["Upper Deck"] = true +L["up to"] = "hasta" +L["Vakkiz the Windrager"] = "Vakkiz el Foribundo del Viento" +L["Various Locations"] = "Varios Lugares" +L["View"] = "Ver" +L["View auctions"] = "Ver las subastas" +L["View bags"] = "Ver las bolsas" +L["View bids"] = "Ver las pujas" +L["View mailbox"] = "Ver el buzón de correos" +L["View quest log"] = "Ver el libro de misiones" +L["Visited"] = "Visitado" +L["Volcanic Armor"] = "Armadura Volcánica" +L["Waiting for %s to accept .."] = true +L["Warlock Set"] = "Set de Brujo" +L["Warlords Deck"] = "Baraja de Señores de la guerra" +L["Warn when mail expires in less days than this value"] = "Advertir cuando el correo expira en menos días que los indicados" +L["Warrior Set"] = "Set de Guerrero" +L["Weapons"] = "Armas" +L["Weaponsmith"] = "Forjador de Armas" +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected. + +]=] ] = [=[Si está |cFFFF0000desactivada|cFFFFFFFF, todas las peticiones serán automáticamente rechazadas. + +]=] +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = "Si está |cFFFF0000desactivada|cFFFFFFFF, no habrá comunicación con la hermandad." +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be +required before sending any information. + +]=] ] = [=[Si está |cFFFF0000desactivada|cFFFFFFFF, se te pedirá confirmación +antes de mandar ninguna información. + +]=] +L["Whitemend Wisdom"] = "Sabiduría con Remiendos Blancos" +L["Wild Draenish Armor"] = "Armadura Draenei Salvage" +L["Wild Steelbloom"] = "Acerita Salvaje" +L["Wildvine"] = "Atriplex Salvaje" +L["Will be learnable by "] = "Podría aprenderlo " +L["Windhawk Armor"] = "Armadura de Halcón del Viento" +L["Wintersbite"] = "Ivernalia" +L["Winter Veil Gift"] = "Regalo del Festival de Invierno" +L[" with "] = " con " +L["World Drops"] = "Saqueos del Mundo" +L["World PVP"] = "JcJ Global" +L["WoW Collector Edition"] = "WoW Edición de Coleccionista" +L["Wrathbringer Laz-tarash"] = "Encolerizador Laz-tarash" +L["Wrath of Spellfire"] = "Cólera de Hechizo de Fuego" +L["Yor (Heroic Summon)"] = "Yor (Invocación Heroica)" +L[ [=[You have received an account sharing request +from %s%s|r, accept it?]=] ] = [=[Has recibido una petición de compartir cuenta + de %s%s|r, ¿ la aceptas ?]=] +L[ [=[Your confirmation will still be required any time someone requests your information. + +]=] ] = [=[Se te pedirá confirmación cada vez que alguien solicite tu información. + +]=] +L["Zelemar the Wrathful"] = "Zelemar El Colérico" +L["Zone"] = "Zona" + diff --git a/Altoholic-Addon/Altoholic/Locales/frFR.lua b/Altoholic-Addon/Altoholic/Locales/frFR.lua new file mode 100644 index 0000000..0f19285 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/frFR.lua @@ -0,0 +1,744 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "Altoholic", "frFR" ) + +if not L then return end + +L["28 Slot"] = "28 emplacements" +L["32 Keys Max"] = "32 Clés Max" +L["Abyssal Council"] = "Conseil abyssal" +L["Accessories"] = "Accessoires" +L["Account"] = "Accompte" +L["Account Name"] = "Nom du compte" +L["Account Sharing"] = "Partage de compte" +L["Account Sharing Enabled"] = "Partage de compte activé" +L["Account Sharing Request"] = "Demande de partage de compte" +L["Account sharing request received from %s"] = "Demande de partage de compte reçue de %s" +L["Account Summary"] = "Résumé du compte" +L["Activity"] = "Activité" +L["Adamantite Battlegear"] = "Tenue de combat en adamantite" +L["Adamantite Deposit"] = "Gisement d'adamantite" +L["Aged Dalaran Wizard"] = "Sorcier de Dalaran âgé" +L["Aggem Thorncurse"] = "Aggem Malépine" +L["AH"] = "HV" +L["All accounts"] = "Tous les comptes" +L["All cooldowns are up"] = [=[Tous les cooldowns +sont disponibles]=] +L["Alliance Forces"] = "Forces de l'Alliance" +L["All-in-one"] = "Tout-en-un" +L["All realms"] = "Tous les royaumes" +L["Already known by "] = "Déjà connu par " +L["Altoholic:|r Usage = /altoholic search "] = "Altoholic:|r Usage = /altoholic search " +L["Ancient Lichen"] = "Lichen ancien" +L["and above"] = "et au-delà" +L["Any"] = "Tout" +L["Anzu the Raven God (Heroic Summon)"] = "Anzu le Dieu Corbeau (Invocation Héroïque)" +L["Apprentice"] = "Apprenti" +L["Arcanoweave Vestments"] = "Habit de tisse-arcane" +L["Are also on this quest:"] = "Sont également sur cette quête:" +L["Arena points: "] = "Points d'arène: " +L["Arena Season %d"] = "Arène Saison %d" +L["Armbreaker Huffaz"] = "Casse-bras Huffaz" +L["Armorsmith"] = "Fabricant d'armures" +L["Arthas' Tears"] = "Larmes d'Arthas" +L["Artisan"] = true +L["at"] = "à" +L["At least one recipe could not be read"] = "Au moins une recette n'a pas pu être lue" +L["Attendees: "] = "Participants: " +L["Auctions %s(%d)"] = "Enchères %s(%d)" +L["Automatically authorize guild bank updates"] = "Autoriser automatiquement les mise à jours de la banque" +L["AutoQuery server |cFFFF0000(disconnection risk)"] = "AutoQuery server |cFFFF0000(risques de déconnexion)" +L["Avatar of the Martyred"] = "Avatar des martyrs" +L["Average Item Level"] = "Niveau moyen des objets" +L["Azure Templar (Water)"] = "Templier d'azur (Eau)" +L["Baelog's Chest"] = "Coffre de Baelog" +L["Bags"] = "Sacs" +L["Bag Usage"] = "Sacs" +L["Balance"] = "Equilibre" +L["Balzaphon"] = true +L["Bank"] = "Banque" +L["Bank bag"] = "Sac en banque" +L["Bank not visited yet"] = "Banque non visitée" +L["Barleybrew Brewery"] = "Apprenti Brasselorge" +L["(based on iLvl)"] = "(sur base de l'item level)" +L["Bash'ir Landing"] = "Point d'ancrage de Bash'ir" +L["Battlecast Garb"] = "Atours d'escarmouche" +L["BC Collector Edition (Europe)"] = "BC Edition Collector (Europe)" +L["Beasts Deck"] = "Suite de fauves" +L["Beast Training"] = "Dressage des bêtes" +L[ [=[Be informed when a guildmate sends a mail to one of my alts. + +Mail content is directly visible without having to reconnect the character]=] ] = [=[Etre informé quand un membre de la guilde envoie du +courrier à un de mes personnages. + +Le contenu du courrier est directement visible sans avoir à reconnecter le personnage]=] +L["Bids %s(%d)"] = "Offres %s(%d)" +L["Black Dragon Mail"] = "Mailles de dragon noir" +L["Black Lotus"] = "Lotus noir" +L["Blacksmithing (Lv 60)"] = "Forge (Niv 60)" +L["Blacksmithing (Lv 70)"] = "Forge (Niv 70)" +L["Blacksmithing Mail Sets"] = "Sets forge, en maille" +L["Blacksmithing Plate Sets"] = "Sets forge, en plaque" +L["Blade Edge Mountains"] = "Les Tranchantes" +L["Blessings Deck"] = "Suite de Bénédictions" +L["Blindweed"] = "Aveuglette" +L["Blizzard Collectables"] = "Goodies Blizzard" +L["Blizzcon 2005"] = true +L["Blizzcon 2007"] = true +L["Bloodsoul Embrace"] = "Etreinte d'âmesang" +L["Bloodthistle"] = "Chardon sanglant" +L["Blood Tiger Harness"] = "Harnais du tigre-sang" +L["Bloodvine"] = "Vignesang" +L["Bloodvine Garb"] = "Atours de vignesang" +L["Blue Dragon Mail"] = "Mailles de dragon bleu" +L["Books"] = "Livres" +L["Booty Run"] = "Le coffre pirate" +L["Both factions"] = "Les 2 factions" +L[ [=[Both parties must enable account sharing +before using this feature (see options)]=] ] = [=[Les deux côtés doivent avoir activé le partage de compte +avant de pouvoir utiliser cette fonctionalité (voir options)]=] +L["Box of Chocolates"] = "Boîte de chocolats" +L["Brewfest"] = "La fête des Brasseurs" +L["Briarthorn"] = "Eglantine" +L["Brightly Colored Egg"] = "Oeuf brillamment coloré" +L["Bruiseweed"] = "Doulourante" +L["Burning Rage"] = "Rage ardente" +L["Cache of the Legion"] = "Cache de la Légion" +L["Calendar"] = "Calendrier" +L["Cannot delete current character"] = "Impossible d'effacer le personnage en cours" +L["Cannot delete current realm"] = "Impossible d'effacer le royaume en cours" +L["Cannot link another account's tradeskill"] = "Lien vers une profession d'un autre compte impossible" +L["Cannot link another realm's tradeskill"] = "Lien vers une profession d'un autre royaume impossible" +L["Carefully Wrapped Present"] = "Biscuit du Voile d'hiver" +L["|cFF00FF00Disable|r to avoid this risk"] = "|cFF00FF00Désactiver|r pour éviter ce risque" +L[ [=[|cFFFFFFFFIf an item not in the local item cache +is encountered while searching loot tables, +Altoholic will attempt to query the server for 5 new items. + +]=] ] = [=[|cFFFFFFFFSi un objet n'existant pas dans le cache local +est rencontré lors d'une recherche dans la table des loots, +Altoholic va tenter d'envoyer des requêtes au serveur pour valider 5 nouveaux objets. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to send you account sharing requests. +]=] ] = [=[|cFFFFFFFFQuand elle est |cFF00FF00activée|cFFFFFFFF, cette option autorise les autres utilisateurs d'Altoholic +à vous envoyer des demandes de partage de compte. +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to update their guild bank information with yours automatically. + +]=] ] = [=[|cFFFFFFFFQuand elle est |cFF00FF00activée|cFFFFFFFF, cette option autorise les autres utilisateurs d'Altoholic +à mettre à jour automatiquement leur données de banque de guilde avec les vôtres. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates +to see your alts and their professions. + +]=] ] = [=[|cFFFFFFFFQuand elle est |cFF00FF00activée|cFFFFFFFF, cette option autorise votre guilde +à voir vos autres personnages et leurs métiers. + +]=] +L["Character"] = "Personnage" +L["Characters"] = "Personnages" +L["Character %s received !"] = "Personnage %s reçu !" +L["Character %s successfully deleted"] = "Personnage %s effacé avec succès" +L["Children's Week"] = "La Semaine des enfants" +L["Christmas Gift 2006"] = "Cadeau de Noël 2006" +L["Clamp window to screen"] = "Fixer la fenêtre à l'écran" +L["Class Books"] = "Livres de classe" +L["Classes: Death Knight"] = "Classes: Chevalier de la mort" +L["Classes: Hunter"] = "Classes: Chasseur" +L["Classes: Mage"] = true +L["Classes: Paladin"] = true +L["Classes: Priest"] = "Classes: Prêtre" +L["Classes: Rogue"] = "Classes: Voleur" +L["Classes: Shaman"] = "Classes: Chaman" +L["Classes: Warlock"] = "Classes: Démoniste" +L["Classes: Warrior"] = "Classes: Guerrier" +L["Class Skills"] = "Compétences de classe" +L["Clear all entries"] = "Effacer toutes les entrées" +L["Clear goblin AH entries"] = "Effacer les entrées de l'HV gobelin" +L["Clear your faction's entries"] = "Effacer les entrées de votre faction" +L["Click a character's AiL to see its equipment"] = "Cliquez sur l'AiL d'un personnage pour voir son équipment" +L[ [=[Clicking this button will update +your local %s%s|r bank tab +based on %s%s's|r data]=] ] = [=[Cliquer sur ce bouton mettra à jour +les données locales de l'onglet %s%s|r +avec celles de %s%s's|r data]=] +L[ [=[Click this button to ask a player +to share his entire Altoholic Database +and add it to your own]=] ] = [=[Cliquez sur ce bouton pour demander +à un joueur de partager sa base de donnée Altoholic +et l'ajouter à la vôtre]=] +L["Cloaks"] = "Capes" +L["Cloth Set"] = "Set Tissu" +L["Conspicuous Urn"] = "Urne ostentatoire" +L["Containers"] = "Conteneurs" +L["Copper Vein"] = "Filon de cuivre" +L["Could be learned by "] = "Pourrait être appris par " +L["Crafted Weapons"] = "Armes fabriquées" +L["Crimson Templar (Fire)"] = "Templier cramoisi (Feu)" +L["Currencies received !"] = "Monnaies reçues !" +L["Dark Iron Deposit"] = "Gisement de sombrefer" +L["Darkscreecher Akkarai"] = "Akkarai le Hurle-sombre" +L[" days"] = " jours" +L[" days ago"] = " jours" +L["Deadly Gladiator's Weapons"] = "Armes Gladiateur fatal" +L["Death Knight"] = "Chevalier de la mort" +L["Default"] = "Défaut" +L["Delete Guild Bank?"] = "Effacer cette banque de guilde?" +L["Delete this Alt"] = "Effacer ce reroll" +L["Delete this Realm"] = "Effacer ce royaume" +L["Detailed guild bank count"] = "Détails du compteur de la banque" +L["Devilsaur Armor"] = "Armure de diablosaure" +L["Disable warnings"] = "Désactiver les avertissements" +L["Display warnings in a dialog box"] = "Boite de dialogue pour les avertissements" +L["Do you want to open Altoholic's calendar for details ?"] = "Voulez-vous ouvrir Altoholic pour plus de détails ?" +L["Do you want to view it now ?"] = "Voulez-vous le voir maintenant ?" +L["DPS"] = true +L["Dragonscale"] = "Ecailles de dragon" +L["Dreamfoil"] = "Feuillerêve" +L["Dreaming Glory"] = "Glaurier" +L["Drohn's Distillery"] = "Apprenti de la distillerie Drohn" +L["Druid of the Fang (Trash Mob)"] = "Druide du Croc (Trash Mob)" +L["Druid Set"] = "Set Druide" +L["Earthen Templar (Earth)"] = "Templier terrestre (Terre)" +L["Earthroot"] = "Terrestrine" +L["Elemental"] = "Elémentaire" +L["Elemental Invasion"] = "Invasions élémentaires" +L["Elementals Deck"] = "Suite d'Elémentaires" +L["Elemental Shaman"] = "Chaman Elémentaire" +L["E-Mail"] = "Courrier" +L["Emblems of Heroism"] = true +L["Emblems of Valor"] = true +L["Enchanted Adamantite Armor"] = "Armure d'adamantite enchantée" +L["Enchants"] = "Enchantements" +L["Engineering (Lv 60)"] = "Ingéniérie (Niv 60)" +L["Engineering (Lv 70)"] = "Ingéniérie (Niv 70)" +L[ [=[Enter an account name that will be +used for |cFF00FF00display|r purposes only.]=] ] = [=[Entrez un nom de compte qui sera utilisé +à des fins |cFF00FF00d'afffichage|r uniquement.]=] +L["Epic Rewards"] = "Récompenses Epiques" +L["Equipment"] = "Equipement" +L["Equipment Slot"] = "Equipement" +L["Equipped"] = "Equipé" +L["Eric The Swift"] = "Eric 'l'Agile'" +L["Ethereum Prison"] = "Prison de l'Ethereum" +L["Expert"] = true +L["Expiry:"] = "Expiration:" +L["Fadeleaf"] = "Pâlerette" +L["Faith in Felsteel"] = "Foi dans le gangracier" +L["Feast of Winter Veil"] = "La fête du Voile d'hiver" +L["Fel Iron Chain"] = "Anneaux de gangrefer" +L["Fel Iron Chest"] = "Coffre en gangrefer" +L["Fel Iron Deposit"] = "Gisement de gangrefer" +L["Fel Iron Plate"] = "Plaque de gangrefer" +L["Fel Lotus"] = "Gangrelotus" +L["Felscale Armor"] = "Armure en gangrécaille" +L["Fel Skin"] = "Gangrepeau" +L["Felstalker Armor"] = "Armure de traqueur gangrené" +L["Fel Steed"] = "Palefroi corrompu" +L["Fel Tinkerer Zortan"] = "Bricoleur gangrené Zortan" +L["Felweed"] = "Gangrelette" +L["Festive Gift"] = "Cadeau de fête" +L["Find Upgrade"] = "Trouver mieux" +L["Firebloom"] = "Fleur de feu" +L["Fire Resistance Gear"] = "Equipements de Résistance au Feu" +L["Fireworks Pack"] = "Sac de feux d'artifice" +L["First Prize"] = "1er prix" +L["Fishing"] = "Pêche" +L["Fishing Extravaganza"] = "Concours de pêche" +L["Fishing Poles"] = "Cannes à pêche" +L["Flame Cap"] = "Chapeflamme" +L["Flame Guard"] = "Garde des flammes" +L["Food"] = "Nourriture" +L["Forgosh"] = true +L["free"] = "libre" +L["Furies Deck"] = "Suite de Furies" +L["Fury of the Nether"] = "Furie du Néant" +L["Gaily Wrapped Present"] = "Cadeau à l'emballage multicolore" +L["Garrett Family Chest"] = "Coffre de la famille Garrett" +L["General"] = "Général" +L["Gently Shaken Gift"] = "Cadeau secoué doucement" +L["Gezzarak the Huntress"] = "Gezzarak la Chasseresse" +L["Ghost Mushroom"] = "Champignon fantôme" +L["Gift of Adoration"] = "Cadeau d'adoration" +L["Glowcap"] = "Chapeluisant" +L["Gnomish"] = "Gnome" +L["Goblin"] = "Gobelin" +L["Goblin AH"] = "HV Gobelin" +L["Golden Sansam"] = "Sansam doré" +L["Goldthorn"] = "Dorépine" +L["Gold Vein"] = "Filon d'or" +L["Gordok Brewery"] = "Apprenti de la bière gordok" +L["Grave Moss"] = "Tombeline" +L["Green Dragon Mail"] = "Mailles de dragon vert" +L["Grey"] = "Gris" +L["Gromsblood"] = "Gromsang" +L["Guild Bank not visited yet (or not guilded)"] = "Banque de guilde non visitée (ou non guildé)" +L["Guild Bank Remote Update"] = "Mise-à-jour à distance de la banque de guilde" +L["Guild Bank Tabs"] = "Onglets banque de guilde" +L["Guild bank tab %s successfully updated !"] = "Onglet de banque %s mis à jour !" +L["Guild Communication Enabled"] = "Communication de guilde activée" +L["Guild Members"] = "Membres de guilde" +L["Guild Skills"] = "Métiers de guilde" +L["Guilds received !"] = "Guildes reçues !" +L["Guild %s successfully deleted"] = "Guilde %s effacée" +L["Gul'bor"] = true +L["Gurubashi Arena"] = "Arène de Gurubashi" +L["Hakkari Thorium Vein"] = "Filon de thorium Hakkari" +L["Halaa (Nagrand)"] = true +L["Hallow's End"] = "La Sanssaint" +L["Hard Mode"] = "Mode Difficile" +L["Harvest Festival"] = "La Fête des moissons" +L["(has auctions)"] = "(a des enchères)" +L["(has bids)"] = true +L["has come online"] = "vient de se connecter" +L["has gone offline"] = "vient de se déconnecter" +L["(has mail)"] = "(a du courrier)" +L[" has no mail, last check "] = " n'a pas de courrier, dernière visite il y a " +L[" has not visited his/her mailbox yet"] = " n'a pas encore visité son/sa boîte aux lettres" +L["Headless Horseman"] = "Cavalier sans tête" +L["Heal"] = "Soin" +L["Hellfire Fortifications"] = "Fortifications des flammes infernales" +L["Henry Stern"] = true +L["Herbalism"] = "Herboristerie" +L[" (Heroic)"] = " (Heroïque)" +L["Heroic Mode Tokens"] = "Insignes Mode Héroïque" +L["hide"] = true +L["Hides the UI"] = "Cache l'interface" +L["Hide this guild in the tooltip"] = "Cacher cette guilde dans le tooltip" +L["Highlord Kruul"] = "Généralissime Kruul" +L["Hoary Templar (Wind)"] = "Templier chenu (Vent)" +L["Honor points: "] = "Points d'honneur: " +L["Horde Forces"] = "Forces de la Horde" +L["Hunter Set"] = "Set Chasseur" +L["Icecap"] = "Calot de glace" +L["Imbued Netherweave"] = "Tisse-néant imprégné" +L["Imperial Plate"] = "Armure impériale en plaques" +L["Incendicite Mineral Vein"] = "Filon d'incendicite" +L["Include guild bank count in the total count"] = "Inclure la banque de guilde dans le décompte total" +L["Include guild bank(s)"] = "Incl. banque de guilde" +L["Include guild members' professions"] = "Inclure les métiers de guilde" +L["Include items without level requirement"] = "Incl. les objets sans niveau requis" +L["Include known recipes"] = "Incl. recettes connues" +L["Include mailboxes"] = "Incl. boites aux lettres" +L["Increases attack power by %d+"] = "Augmente de %d+ la puissance d'attaque" +L["Increases damage and healing done by magical spells and effects by up to %d+"] = "Augmente les dégâts et les soins produits par les sorts et effets magiques de %d+" +L["Increases healing done by up to %d+"] = "Augmente les soins prodigués d'un maximum de %d+" +L["Indurium Mineral Vein"] = "Filon d'indurium" +L["Inscription"] = "Calligraphie" +L["Invalid tradeskill link"] = "Lien de profession invalide" +L["Iron Deposit"] = "Gisement de fer" +L["Ironfeather Armor"] = "Armure de plumacier" +L[" is "] = " est " +L["Item Level"] = "Niveau de l'objet" +L["Item / Location"] = "Objet / Lieu" +L["Items"] = "Objets" +L["Journeyman"] = "Compagnon" +L["Karrog"] = true +L["Khadgar's Whisker"] = "Moustache de Khadgar" +L["Khorium Vein"] = "Filon de khorium" +L["Khorium Ward"] = "Gardien de khorium" +L["Kingsblood"] = "Sang-royal" +L["Krom Stoutarm Chest"] = "Coffre de Krom Rudebras" +L["Lady Falther'ess"] = "Dame Falther'ess" +L["Lake Wintergrasp"] = "Lac Joug-d'hiver" +L["Large Obsidian Chunk"] = "Grand morceau d'obsidienne" +L["last check "] = "dernière visite " +L["Last visit: %s by %s"] = "Dernière visite: %s par %s" +L["Leather Set"] = "Set Cuir" +L["Leatherworking Leather Sets"] = "Sets travail du cuir, en cuir" +L["Leatherworking Mail Sets"] = "Sets travail du cuir, en maille" +L["Left-click to"] = "Clic-gauche pour" +L["Left-click to |cFF00FF00open"] = "Clic-gauche pour |cFF00FF00ouvrir" +L["Left-click to invite attendees"] = "Clic-gauche pour inviter les participants" +L["Left-click to see this character's equipment"] = "Clic-gauche pour voir l'équipement de ce personnage" +L["Left click to view"] = "Clic gauche pour voir" +L["Legendaries"] = "Légendaires" +L["Legendary Mount"] = "Monture légendaire" +L["Lesser Bloodstone Deposit"] = "Gisement de pierre de sang inférieure" +L["Level"] = "Niveau" +L["Level 30-39"] = "Niveau 30-39" +L["Level 40-49"] = "Niveau 40-49" +L["Level 50-60"] = "Niveau 50-60" +L["Level 70"] = "Niveau 70" +L["Level 70 Reputation PVP"] = "JcJ Réputation Niveau 70" +L["Level %d Honor PVP"] = "JcJ Honneur Niveau %d" +L["Levels"] = "Niveaux" +L["Liferoot"] = "Vietérule" +L["Local Time: %s %sRealm Time: %s"] = "Heure Locale: %s %sHeure Royaume: %s" +L["Location"] = "Lieu" +L["Lockpicking"] = "Crochetage" +L["Loot Card Items"] = "Butin des cartes à jouer" +L["Loots"] = true +L["Loot tables"] = "Loots" +L["Lord Ahune"] = "Seigneur Ahune" +L["Lord Blackwood"] = "Seigneur Noirbois" +L["Love is in the air"] = "De l'amour dans l'air" +L["Lucky Red Envelope"] = "Enveloppe rouge porte-bonheur" +L["Lunacy Deck"] = "Suite de Déraison" +L["Lunar Festival"] = "La fête lunaire" +L["Lv %s Rewards"] = "Récompenses Niveau %s" +L["Mageroyal"] = "Mage royal" +L["Mage Set"] = "Set Mage" +L["Magregan Deepshadow"] = "Magregan Fondombre" +L["Mail"] = "Courrier" +L["Mail Expiry Warning"] = "Avertis. d'expiration du courrier" +L["Mail is about to expire on at least one character."] = "Du courrier va bientôt expirer sur au moins un personnage." +L["Mails"] = "Courrier" +L["Mail Set"] = "Set Maille" +L["Mails %s(%d)"] = "Courrier %s(%d)" +L["Mail was last checked "] = "Courrier relevé il y a " +L["Malevus the Mad"] = "Malevus le Fol" +L["Mana Thistle"] = "Chardon de mana" +L["Master"] = "Maître" +L["Master Axesmith"] = "Maître fabricant de haches" +L["Master Hammersmith"] = "Maître fabricant de marteaux" +L["Master Swordsmith"] = "Maître fabricant d'épées" +L["Maximum Level: %s"] = "Niveau Maximum: %s" +L["Max rest XP displayed as 150%"] = "XP de repos max affichée comme 150%" +L["Midsummer Fire Festival"] = "Solstice d'été : la fête du Feu" +L["Minimap Icon Angle"] = "Angle de l'icône minimap" +L["Minimap Icon Radius"] = "Rayon de l'icône minimap" +L["Minimum Level: %s"] = "Niveau Minimum: %s" +L["Mining"] = "Minage" +L["Miscellaneous"] = "Divers" +L["Mithril Deposit"] = "Gisement de mithril" +L["Mooncloth"] = "Etoffe Lunaire" +L["Mountain Silversage"] = "Sauge-argent des montagnes" +L["Move to change the angle of the minimap icon"] = "Déplacer pour changer l'angle de l'icône minimap" +L["Move to change the radius of the minimap icon"] = "Déplacer pour changer le rayon de l'icône minimap" +L["Muddy Churning Waters"] = true +L["N/A"] = "N/D" +L["Netherbloom"] = "Néantine" +L["Nethercite Deposit"] = "Gisement de néanticite" +L["Netherdust Bush"] = "Buisson de pruinéante" +L["Netherscale Armor"] = "Armure en écailles du Néant" +L["Netherstrike Armor"] = "Armure Coup-de-Néant" +L["Netherweave Vestments"] = "Habit en tisse-néant" +L["New mail notification"] = "Alerte nouveau courrier" +L["Nightmare Vine"] = "Cauchemardelle" +L["Noblegarden"] = "Le jardin des nobles" +L["No currencies found"] = "Pas de monnaies" +L["No data"] = "Aucune données" +L["No guild found"] = "Pas de guilde" +L["No match found!"] = "Aucun résultat trouvé!" +L["Non Set Accessories"] = "Accessoires Hors-Set" +L["Non Set Cloth"] = "Tissu Hors-Set" +L["Non Set Leather"] = "Cuir Hors-Set" +L["Non Set Mail"] = "Maille Hors-Set" +L["Non Set Plate"] = "Plaque Hors-Set" +L["No quest found for "] = "Pas de quête trouvée pour " +L["No reputations found"] = "Pas de réputations" +L["No rest XP"] = "Pas d'XP de repos" +L[" not found!"] = " non trouvé!" +L["Not started"] = "Pas commencé" +L["Number of players: %s"] = "Nombre de joueurs: %s" +L["Offline Members"] = "Membres déconnectés" +L["Olaf"] = true +L["Ooze Covered Gold Vein"] = "Filon d'or couvert de limon" +L["Ooze Covered Mithril Deposit"] = "Gisement de mithril couvert de vase" +L["Ooze Covered Rich Thorium Vein"] = "Riche filon de thorium couvert de limon" +L["Ooze Covered Silver Vein"] = "Filon d'argent couvert de limon" +L["Ooze Covered Thorium Vein"] = "Filon de thorium couvert de limon" +L["Ooze Covered Truesilver Deposit"] = "Gisement de vrai-argent couvert de vase" +L["open/close"] = "ouvrir/fermer" +L["Opera (Shared Drops)"] = "Opéra (Loots partagés)" +L["Other"] = "Autres" +L["Outdoor Bosses"] = "Boss Extérieurs" +L["Paladin Set"] = "Set Paladin" +L["Patterns"] = "Patrons" +L["Peacebloom"] = "Pacifique" +L["Plaguebloom"] = "Fleur de peste" +L["Plans"] = true +L["Plate Set"] = "Set Plaque" +L["Please open this window again"] = "Veuillez ouvrir cette fenêtre à nouveau" +L["Poisons"] = true +L["Porfus the Gem Gorger"] = "Porfus le Goinfre-gemmes" +L["Portals Deck"] = "Suite de Portails" +L["Priest Set"] = "Set Prêtre" +L["Primal Batskin"] = "Peau de chauve-souris primodiale" +L["Primal Intent"] = "Intention primordiale" +L["Primal Mooncloth"] = "Etoffe lunaire primordiale" +L["Private to friends: %s"] = "Limité aux amis: %s" +L["Private to guild: %s"] = "Limité à la guilde: %s" +L["Prof. 1"] = true +L["Prof. 2"] = true +L["Professions"] = "Métiers" +L["Purple Lotus"] = "Lotus pourpre" +L["PVP Cloth Set"] = "Set Tissu JcJ" +L["PVP Leather Sets"] = "Set Cuir JcJ" +L["PVP Mail Sets"] = "Set Maille JcJ" +L["PVP Plate Sets"] = "Set Plaque JcJ" +L["Pyron"] = true +L["QuestID"] = "ID Quête" +L["Quest Items"] = "Objets de quête" +L["Quest rewards"] = "Récompenses de quête" +L["Quests"] = "Quêtes" +L["Ragveil"] = "Voile-misère" +L["Rajaxx's Captains"] = "Les Capitaines de Rajaxx" +L["Random Boss"] = "Boss aléatoire" +L["Rare Fish"] = "Poissons rares" +L["Rare Fish Rewards"] = "Récompenses des poissons rares" +L["Razorfen Spearhide"] = "Lanceur de Tranchebauge" +L["Realm"] = "Royaume" +L["Realm %s successfully deleted"] = "Royaume %s effacé avec succès" +L["Reference data not available"] = "Données de référence non disponibles" +L["Reference data received (%s) !"] = "Données de référence reçues (%s) !" +L["Refer to the activity pane for more details."] = "Référez vous à l'onglet Activité pour plus de details." +L["Relics"] = "Reliques" +L["Reputations"] = "Réputations" +L["Reputations received !"] = "Réputations reçues !" +L["Requesting item %d of %d"] = "Demande de l'objet %d de %d" +L["Requesting %s information from %s"] = "Demande de l'onglet %s envoyée à %s" +L["Request rejected by %s"] = "Demande rejetée par %s" +L["Reset"] = "R.à.z." +L["Resistance"] = true +L["Rested"] = "Reposé" +L["Restores %d+ mana per"] = "Rend %d+ points de mana toutes les" +L["Rest XP"] = "XP de repos" +L[" results found (Showing "] = " résultats trouvés (Affichés " +L["Rethilgore"] = "Rethiltripe" +L["Revanchion"] = true +L["Rich Adamantite Deposit"] = "Riche gisement d'adamantite" +L["Rich Thorium Vein"] = "Riche filon de thorium" +L["Riding"] = "Monte" +L["Right-Click for options"] = "Clic-droit pour plus d'options" +L["Right-click to |cFF00FF00drag"] = "Clic-droit pour |cFF00FF00déplacer" +L["Right-Click to find an upgrade"] = "Clic-Droit pour trouver mieux" +L["Rogue Proficiencies"] = "Aptitudes du voleur" +L["Rogue Set"] = "Set Voleur" +L["Roogug"] = true +L["Sanguine Hibiscus"] = "Hibiscus sanguin" +L["Savage Gladiator's Weapons"] = "Armes Gladiateur sauvage" +L["Scaled Draenic Armor"] = "Armure draenique en écailles" +L[" scan failed for "] = " " +L["Scan mail body (marks it as read)"] = "Lire le courrier (le marque comme lu)" +L["Scorn"] = true +L["Scourge Invasion"] = "Invasion du Fléau" +L["search"] = true +L["Search Containers"] = "Recherche Conteneurs" +L["Search in bags"] = "Recherche dans les sacs" +L["Secondary Skills"] = "Compétences secondaires" +L[ [=[Security hint: disable this if you have officer rights +on guild bank tabs that may not be viewed by everyone, +and authorize requests manually]=] ] = [=[Conseil Sécurité: désactivez cette option si vous avez des droits d'officier +sur des onglets de banque de guilde qui ne peuvent pas être vus de tous, +et autorisez les requêtes manuellement]=] +L[ [=[Security hint: Only enable this when you actually need to transfer data, +disable otherwise]=] ] = [=[Conseil Sécurité: N'activez cette option que quand vous devez transférer des données, +désactivez le reste du temps]=] +L["Send account sharing request to:"] = "Envoyer la demande de partage à :" +L["Sending account sharing request to %s"] = "Envoi de la demande de partage à %s" +L["Sending character %s (%d of %d)"] = "Envoi du personnage %s (%d de %d)" +L["Sending currencies (%d of %d)"] = "Envoi des monnaies (%d de %d)" +L["Sending guilds (%d of %d)"] = "Envoi des guildes (%d de %d)" +L["Sending reference data: %s (%d of %d)"] = "Envoi des données de référence : %s (%d of %d)" +L["Sending reputations (%d of %d)"] = "Envoi des réputations (%d de %d)" +L["Sending table of content (%d items)"] = "Envoi de la table des matières (%d objets)" +L["Sever"] = true +L["Shadoweave"] = "Tisse ombre" +L["Shadowforge Cache"] = "Cachette d'Ombreforge" +L["Shadow's Embrace"] = "Etreinte de l'ombre" +L["Shaman Set"] = "Set Chaman" +L["Shared"] = "Partagés" +L["Shartuul"] = true +L["%s has disabled account sharing"] = "%s a désactivé le partage de compte" +L["%s has disabled guild communication"] = "%s a désactivé la communication de guilde" +L["%s has no auctions"] = "%s n'a pas d'enchères" +L["%s has no bids"] = "%s n'a pas d'offres" +L["%s has no mail"] = "%s n'a pas de courrier" +L["Shen'dralar Provisioner"] = "Approvisionneur Shen'dralar" +L["Shift-Click to link this info"] = "Shift-Clic pour linker cette info" +L["Shift+Left click to link"] = "Shift+Clic gauche pour linker" +L["show"] = true +L["Show already known/learnable by"] = "Afficher Déjà Connu/Peut être appris par" +L["Show counters for all accounts"] = "Afficher les compteurs de tous les comptes" +L["Show counters for both factions"] = "Afficher les compteurs des deux factions" +L["Show counters on gathering nodes"] = "Afficher les compteurs sur mines et plantes" +L["Show FuBar icon"] = "Afficher l'icône FuBar" +L["Show FuBar text"] = "Afficher le texte FuBar" +L["Show guild bank count"] = "Afficher la banque de guilde" +L["Show item count per character"] = "Afficher le décompte par personnage" +L["Show item ID and item level"] = "Afficher l'item ID et l'item level" +L["Show item source"] = "Afficher la source de l'objet" +L["Show Minimap Icon"] = "Afficher l'icône minimap" +L["Show pets already known/learnable by"] = "Afficher les familiers déjà connus/pouvant être appris par" +L["Show recipes already known/learnable by"] = "Afficher les recettes déjà connues/pouvant être apprises par" +L["Shows the UI"] = "Affiche l'interface" +L["Show total item count"] = "Afficher le décompte total" +L["Silverleaf"] = "Feuillargent" +L["Silver Vein"] = "Filon d'argent" +L["%s is in combat, request cancelled"] = "%s est en combat, demande annulée" +L["%s is now ready (%s on %s)"] = "%s est maintenant prêt (%s sur %s)" +L["%s is now unlocked (%s on %s)"] = "%s est maintenant accessible (%s sur %s)" +L["%s is %s with %s (%d/%d)"] = "%s est %s chez %s (%d/%d)" +L["Skettis"] = true +L["Skinning"] = "Dépeçage" +L["Skyguard Raid"] = true +L["slots"] = "emplacements" +L["Small Obsidian Chunk"] = "Petit morceau d'obsidienne" +L["Small Thorium Vein"] = "Petit filon de thorium" +L["Smokywood Pastures Extra-Special Gift"] = "Cadeau extra-spécial des Gourmandises Fumebois" +L["Smokywood Pastures Vendor"] = "Vendeurs de Gourmandises Fumebois" +L["Socket"] = "Châsse" +L["Sort loots in descending order"] = "Tri des loots décroissant" +L["Sothos & Jarien"] = "Sothos et Jarien" +L["Soulcloth Embrace"] = "Etreinte d'âmétoffe" +L["Source"] = true +L["Spawn Of Hakkar"] = "Rejeton d'Hakkar" +L["Spellfire"] = "Feu Sorcier" +L["Spellstrike Infusion"] = "Infusion frappe-sort" +L["Spirit Towers (Terrokar)"] = "Tour des esprits (Terrokar)" +L["%s|r has received a mail from %s"] = "%s|r a reçu du courrier de %s" +L[ [=[%s%s|r has requested the bank tab %s%s|r +Send this information ?]=] ] = [=[%s%s|r désire l'onglet de banque %s%s|r +Envoyer ces informations ?]=] +L["%s starts in %d minutes (%s on %s)"] = "%s débute dans %d minutes (%s sur %s)" +L["Started"] = "Commencé" +L["Stasis Chambers"] = "Chambre de stase" +L["Steamwheedle Cartel"] = "Cartel Gentepression" +L["Storms Deck"] = "Suite d'Orages" +L["Stormshroud Armor"] = "Armure tempétueuse" +L["Stranglekelp"] = "Etouffante" +L["Strength of the Clefthoof"] = "Force du sabot-fourchu" +L["Suggested leveling zone: "] = "Zone suggérée: " +L["Suggestion"] = true +L["Summary"] = "Résumé" +L["Summoner's Tomb"] = "Tombe de l'invocateur" +L["Sungrass"] = "Soleillette" +L["Superior Rewards"] = "Récompenses Supérieures" +L[ [=[%sWarning:|r if you accept, %sALL|r information known +by Altoholic will be sent to %s%s|r (bags, money, etc..)]=] ] = "%sAvertissement:|r si vous acceptez, %sTOUTES|r les informations connues d'Altoholic seront envoyées à %s%s|r (sacs, argent, etc..)" +L["%sWarning:|r make sure this user may view this information before accepting"] = "%sAvertissement:|r Vérifiez que ce joueur a le droit de voir ces informations avant d'accepter" +L["Swiftthistle"] = "Chardonnier" +L["%s will be ready in %d minutes (%s on %s)"] = "%s sera prêt dans %d minutes (%s sur %s)" +L["%s will be unlocked in %d minutes (%s on %s)"] = "%s sera accessible dans %d minutes (%s sur %s)" +L["Table of content received (%d items)"] = "Table des matières reçue (%d objets)" +L["Tablet of Ryuneh"] = "Tablette de Ryun'eh" +L["Tablet of Will"] = "Tablette de volonté" +L["Tailoring Sets"] = "Sets couture" +L["Tank"] = true +L["T'chali's Voodoo Brewery"] = "Apprenti de la brasserie vaudou de T'chali" +L["Terocone"] = "Terocône" +L["Terokk"] = true +L["The Darksoul"] = "La Ténébrâme" +L["The Duke of Cinders (Fire)"] = "Le duc des Cendres (Feu)" +L["The Duke of Fathoms (Water)"] = "Le duc des Profondeurs (Eau)" +L["The Duke of Shards (Earth)"] = "Le duc des Eclats (Terre)" +L["The Duke of Zephyrs (Wind)"] = "Le duc des Zéphyrs (Vent)" +L["Theldren"] = true +L[ [=[There is a risk of disconnection if the queried item +is a loot from a high level dungeon. + +]=] ] = [=[Il existe un risque de déconnexion si l'objet +est un loot d'une instance haut niveau. + +]=] +L["The Unyielding"] = "L'Inflexible" +L["The Vault"] = "La Chambre forte" +L["Thick Draenic Armor"] = "Armure draenique épaisse" +L["This account"] = "Ce compte" +L["This character"] = "Ce personnage" +L["This faction"] = "Cette faction" +L["This field |cFF00FF00cannot|r be left empty."] = "Ce champ |cFF00FF00ne peut pas|r être laissé vide." +L[ [=[This name can be anything you like, +it does |cFF00FF00NOT|r have to be the real account name.]=] ] = [=[Ce nom peut être ce que vous voulez, +il ne doit |cFF00FF00PAS|r forcément être le nom réel du compte.]=] +L["This realm"] = "Ce royaume" +L[ [=[This will gradually improve the consistency of the searches, +as more items are available in the item cache. + +]=] ] = [=[Ceci va graduellement améliorer la consistance des recherches, +puisque plus d'objets seront disponibles dans le cache local. + +]=] +L["Thomas Yance"] = true +L["Thunderbrew Brewery"] = "Apprenti Tonnebière" +L["Ticking Present"] = "Cadeau tic-taquant" +L["Tier 0.5 Quests"] = "Quêtes T0.5" +L["Tier %d Tokens"] = "Insignes T%d" +L["Timed Chest"] = "Course au coffre" +L["Tin Vein"] = "Filon d'étain" +L["toggle"] = true +L["Toggles the UI"] = "Inverse l'état de l'interface" +L["Token Hand-Ins"] = "Insignes de l'Aube / Croisade" +L["Tooltip"] = true +L["Total owned"] = "Total possédé" +L["Totals"] = "Totaux" +L["Transfer complete"] = "Transfert terminé" +L["Transmute"] = true +L["Transparency"] = "Transparence" +L["Trash Mobs"] = true +L["Treat Bag"] = "Sac de friandises" +L["Tribal"] = "Tribale" +L["Tribute Run"] = "Tribut du Roi" +L["Trinkets"] = "Bijoux" +L["Troll Mini bosses"] = "Mini Boss Trolls" +L["Truesilver Deposit"] = "Gisement de vrai-argent" +L["Twin Spire Ruins"] = "Ruines des flèches jumelles" +L["Unknown"] = "Inconnus" +L["Unknown link, please relog this character"] = "Lien inconnu, veuillez reconnecter ce personnage" +L["Upper Deck"] = true +L["up to"] = "jusqu'à" +L["Vakkiz the Windrager"] = "Vakkiz le Ragevent" +L["Various Locations"] = "Lieux divers" +L["View"] = "Voir" +L["View auctions"] = "Voir les enchères" +L["View bags"] = "Voir les sacs" +L["View bids"] = "Voir les offres" +L["View mailbox"] = "Voir le courrier" +L["View quest log"] = "Voir le journal de quête" +L["Visited"] = "Visité" +L["Volcanic Armor"] = "Armure volcanique" +L["Waiting for %s to accept .."] = "Attente d'une réponse de %s .." +L["Warlock Set"] = "Set Démoniste" +L["Warlords Deck"] = "Suite de Seigneurs de guerre" +L["Warn %d minutes before an event starts"] = "Avertir %d minutes avant le début d'un évènement" +L["Warn when mail expires in less days than this value"] = [=[Avertir quand du courrier arrive à expiration +dans moins de jours que cette valeur]=] +L["Warrior Set"] = "Set Guerrier" +L["Weapons"] = "Armes" +L["Weaponsmith"] = "Fabricant d'armes" +L["Week starts on Monday"] = "Commencer la semaine le lundi" +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected. + +]=] ] = [=[Quand elle est |cFFFF0000désactivée|cFFFFFFFF, toutes ces requêtes seront automatiquement rejetées. + +]=] +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = "Quand elle est |cFFFF0000désactivée|cFFFFFFFF, il n'y aura aucune communication avec la guilde." +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be +required before sending any information. + +]=] ] = [=[Quand elle est |cFFFF0000désactivée|cFFFFFFFF, votre confirmation sera +requise avant tout envoi d'information. + +]=] +L["Whitemend Wisdom"] = "Sagesse de la blanche guérison" +L["Wild Draenish Armor"] = "Armure draenique sauvage" +L["Wild Steelbloom"] = "Aciérite sauvage" +L["Wildvine"] = "Sauvageonne" +L["Will be learnable by "] = "Pourra être appris par " +L["Will be %sdeleted|r in"] = "Sera %seffacé|r dans" +L["Will be %sreturned|r in"] = "Sera %srenvoyé|r dans" +L["Windhawk Armor"] = "Armure Faucont-du-vent" +L["Wintersbite"] = "Hivernale" +L["Winter Veil Gift"] = "Rob-fusée mécanique" +L[" with "] = " chez " +L["World Drops"] = true +L["World PVP"] = "PVP Sauvage" +L["WoW Collector Edition"] = "WoW Edition Collector" +L["Wrathbringer Laz-tarash"] = "Porte-courroux Laz-tarash" +L["Wrath of Spellfire"] = "Habit du feu-sorcier" +L["Yor (Heroic Summon)"] = "Yor (Invocation Héroïque)" +L[ [=[You have received an account sharing request +from %s%s|r, accept it?]=] ] = [=[%s%s|r vous a envoyé une demande de partage de compte +Accepter?]=] +L[ [=[Your confirmation will still be required any time someone requests your information. + +]=] ] = [=[Votre confirmation sera toujours requise à chaque fois que vous recevrez une demande de partage. + +]=] +L["Zelemar the Wrathful"] = "Zelemar le Courroucé" +L["Zone"] = true + diff --git a/Altoholic-Addon/Altoholic/Locales/koKR.lua b/Altoholic-Addon/Altoholic/Locales/koKR.lua new file mode 100644 index 0000000..91805c3 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/koKR.lua @@ -0,0 +1,695 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "Altoholic", "koKR" ) + +if not L then return end + +L["28 Slot"] = "28 칸" +L["32 Keys Max"] = "최대 32개 열쇠" +L["Abyssal Council"] = true +L["Accessories"] = "장신구" +L["Account"] = "계정" +L["Account Name"] = "계정명" +L["Account Sharing"] = "계정 공유" +L["Account Sharing Enabled"] = "계정 공유 사용 중" +L["Account Sharing Request"] = "계정 공유 요청" +L["Account sharing request received from %s"] = "%s한테서 계정 공유 요청을 받음" +L["Account Summary"] = "계정 요약" +L["Activity"] = "활동" +L["Adamantite Battlegear"] = true +L["Adamantite Deposit"] = "아다만타이트 광맥" +L["Aged Dalaran Wizard"] = true +L["Aggem Thorncurse"] = true +L["AH"] = "경매장" +L["All accounts"] = "모든 계정" +L["All cooldowns are up"] = "재사용 대기시간 중인 것 없음" +L["Alliance Forces"] = "얼라이언스 연합" +L["All-in-one"] = "한꺼번에" +L["All realms"] = "모든 서버" +L["Already known by "] = "이미 배움" +L["Altoholic:|r Usage = /altoholic search "] = "Altoholic:|r 사용법 = /altoholic search <아이템 이름>" +L["Ancient Lichen"] = true +L["and above"] = "이상" +L["Any"] = "모두" +L["Anzu the Raven God (Heroic Summon)"] = true +L["Apprentice"] = "수습" +L["Arcanoweave Vestments"] = true +L["Are also on this quest:"] = true +L["Arena points: "] = "투기장 점수" +L["Arena Season %d"] = "투기장 시즌 %d" +L["Armbreaker Huffaz"] = true +L["Armorsmith"] = "갑옷제작" +L["Arthas' Tears"] = "아서스의 눈물" +L["Artisan"] = "전문가" +L["at"] = true +L["At least one recipe could not be read"] = "제조법을 하나도 읽을 수 없음" +L["Attendees: "] = "입찰자: " +L["Auctions %s(%d)"] = "경매 %s(%d)" +L["Automatically authorize guild bank updates"] = true +L["AutoQuery server |cFFFF0000(disconnection risk)"] = "AutoQuery 서버 |cFFFF0000(연결이 끊길 수도 있음)" +L["Avatar of the Martyred"] = true +L["Average Item Level"] = "아이템 레벨 평균" +L["Azure Templar (Water)"] = true +L["Baelog's Chest"] = true +L["Bags"] = "가방" +L["Bag Usage"] = "가방 사용" +L["Balance"] = true +L["Balzaphon"] = true +L["Bank"] = "은행" +L["Bank bag"] = "은행 가방" +L["Bank not visited yet"] = "아직 은행을 방문하지 않았음" +L["Barleybrew Brewery"] = true +L["(based on iLvl)"] = "(아이템 레벨(iLvl) 기준으로)" +L["Bash'ir Landing"] = true +L["Battlecast Garb"] = true +L["BC Collector Edition (Europe)"] = "BC 컬렉터 에디션 (유럽)" +L["Beasts Deck"] = true +L["Beast Training"] = "야수 조련" +L[ [=[Be informed when a guildmate sends a mail to one of my alts. + +Mail content is directly visible without having to reconnect the character]=] ] = true +L["Bids %s(%d)"] = "입찰 %s(%d)" +L["Black Dragon Mail"] = true +L["Black Lotus"] = true +L["Blacksmithing (Lv 60)"] = "대장기술 (60 레벨)" +L["Blacksmithing (Lv 70)"] = "대장기술 (70 레벨)" +L["Blacksmithing Mail Sets"] = "대장기술 사슬 세트" +L["Blacksmithing Plate Sets"] = "대장기술 판금 세트" +L["Blade Edge Mountains"] = "칼날 산맥" +L["Blessings Deck"] = true +L["Blindweed"] = "실명초" +L["Blizzard Collectables"] = true +L["Blizzcon 2005"] = "블리즈컨 2005" +L["Blizzcon 2007"] = "블리즈컨 2007" +L["Bloodsoul Embrace"] = true +L["Bloodthistle"] = true +L["Blood Tiger Harness"] = true +L["Bloodvine"] = true +L["Bloodvine Garb"] = true +L["Blue Dragon Mail"] = true +L["Books"] = "책" +L["Booty Run"] = true +L["Both factions"] = "양쪽 평판" +L[ [=[Both parties must enable account sharing +before using this feature (see options)]=] ] = true +L["Box of Chocolates"] = true +L["Brewfest"] = true +L["Briarthorn"] = "찔레가시" +L["Brightly Colored Egg"] = true +L["Bruiseweed"] = "생채기풀" +L["Burning Rage"] = true +L["Cache of the Legion"] = true +L["Calendar"] = "달력" +L["Cannot delete current character"] = "현재 캐릭터는 삭제할 수 없음" +L["Cannot delete current realm"] = "현재 서버는 삭제할 수 없음" +L["Cannot link another account's tradeskill"] = "다른 계정의 전문/보조기술을 링크할 수 없음" +L["Cannot link another realm's tradeskill"] = "다른 서버의 전문/보조기술을 링크할 수 없음" +L["Carefully Wrapped Present"] = true +L["|cFF00FF00Disable|r to avoid this risk"] = true +L[ [=[|cFFFFFFFFIf an item not in the local item cache +is encountered while searching loot tables, +Altoholic will attempt to query the server for 5 new items. + +]=] ] = true +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to send you account sharing requests. +]=] ] = true +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to update their guild bank information with yours automatically. + +]=] ] = true +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates +to see your alts and their professions. + +]=] ] = true +L["Character"] = "캐릭터" +L["Characters"] = "캐릭터" +L["Character %s received !"] = "%s 캐릭터를 받았습니다 !" +L["Character %s successfully deleted"] = "%s 캐릭터가 성공적으로 삭제됨" +L["Children's Week"] = "어린이 주간" +L["Christmas Gift 2006"] = "2006 크리스마스 선물" +L["Class Books"] = true +L["Classes: Death Knight"] = "직업: 죽음의 기사" +L["Classes: Hunter"] = "직업: 사냥꾼" +L["Classes: Mage"] = "직업: 마법사" +L["Classes: Paladin"] = "직업: 성기사" +L["Classes: Priest"] = "직업: 사제" +L["Classes: Rogue"] = "직업: 도적" +L["Classes: Shaman"] = "직업: 주술사" +L["Classes: Warlock"] = "직업: 흑마법사" +L["Classes: Warrior"] = "직업: 전사" +L["Class Skills"] = "직업 기술" +L["Clear all entries"] = "모든 항목 삭제" +L["Clear goblin AH entries"] = "고블린 경매장 품목 삭제" +L["Clear your faction's entries"] = "평판 항목 삭제" +L["Click a character's AiL to see its equipment"] = "장비를 보려면 캐릭터의 AiL을 클릭" +L[ [=[Clicking this button will update +your local %s%s|r bank tab +based on %s%s's|r data]=] ] = true +L[ [=[Click this button to ask a player +to share his entire Altoholic Database +and add it to your own]=] ] = true +L["Cloaks"] = "망토" +L["Cloth Set"] = "천 세트" +L["Conspicuous Urn"] = true +L["Containers"] = "보관함" +L["Copper Vein"] = "동 광맥" +L["Could be learned by "] = "배울 수 있음 " +L["Crafted Weapons"] = "제작된 무기" +L["Crimson Templar (Fire)"] = true +L["Currencies received !"] = true +L["Dark Iron Deposit"] = true +L["Darkscreecher Akkarai"] = true +L[" days"] = " 일" +L[" days ago"] = " 일 전" +L["Deadly Gladiator's Weapons"] = true +L["Death Knight"] = "죽음의 기사" +L["Default"] = "기본값" +L["Delete Guild Bank?"] = "길드 은행 삭제?" +L["Delete this Alt"] = "이 캐릭터 삭제" +L["Delete this Realm"] = "이 서버 삭제" +L["Devilsaur Armor"] = true +L["Disable warnings"] = "경고 무시" +L["Display warnings in a dialog box"] = "경고를 대화 상자로 표시" +L["Do you want to open Altoholic's calendar for details ?"] = "상세 내용을 Altoholic 달력으로 열까요?" +L["Do you want to view it now ?"] = "지금 보기를 원하십니까?" +L["DPS"] = "초 당 데미지(DPS)" +L["Dragonscale"] = "용비늘" +L["Dreamfoil"] = "꿈풀" +L["Dreaming Glory"] = "꿈초롱이" +L["Drohn's Distillery"] = true +L["Druid of the Fang (Trash Mob)"] = true +L["Druid Set"] = "드루이드 세트" +L["Earthen Templar (Earth)"] = true +L["Earthroot"] = "뱀뿌리" +L["Elemental"] = "원소" +L["Elemental Invasion"] = true +L["Elementals Deck"] = true +L["Elemental Shaman"] = true +L["E-Mail"] = "전자우편" +L["Emblems of Heroism"] = true +L["Emblems of Valor"] = true +L["Enchanted Adamantite Armor"] = true +L["Enchants"] = "마법부여" +L["Engineering (Lv 60)"] = "기계공학 (60 레벨)" +L["Engineering (Lv 70)"] = "기계공학 (70 레벨)" +L[ [=[Enter an account name that will be +used for |cFF00FF00display|r purposes only.]=] ] = true +L["Epic Rewards"] = "에픽 보상" +L["Equipment"] = "장비" +L["Equipment Slot"] = "장비 칸" +L["Equipped"] = "착용" +L["Eric The Swift"] = true +L["Ethereum Prison"] = true +L["Expert"] = "숙련" +L["Expiry:"] = "소멸 기한" +L["Fadeleaf"] = "미명초" +L["Faith in Felsteel"] = true +L["Feast of Winter Veil"] = true +L["Fel Iron Chain"] = "지옥무쇠 사슬" +L["Fel Iron Chest"] = "지옥무쇠 상자" +L["Fel Iron Deposit"] = "지옥무쇠 광맥" +L["Fel Iron Plate"] = "지옥무쇠 판금" +L["Fel Lotus"] = "지옥 연꽃" +L["Felscale Armor"] = true +L["Fel Skin"] = true +L["Felstalker Armor"] = true +L["Fel Steed"] = true +L["Fel Tinkerer Zortan"] = true +L["Felweed"] = "지옥풀" +L["Festive Gift"] = true +L["Find Upgrade"] = true +L["Firebloom"] = true +L["Fire Resistance Gear"] = true +L["Fireworks Pack"] = true +L["First Prize"] = true +L["Fishing"] = "낚시" +L["Fishing Extravaganza"] = true +L["Fishing Poles"] = "낚싯대" +L["Flame Cap"] = true +L["Flame Guard"] = true +L["Food"] = "음식" +L["Forgosh"] = true +L["free"] = "여유" +L["Furies Deck"] = true +L["Fury of the Nether"] = true +L["Gaily Wrapped Present"] = true +L["Garrett Family Chest"] = true +L["General"] = "일반" +L["Gently Shaken Gift"] = true +L["Gezzarak the Huntress"] = true +L["Ghost Mushroom"] = "유령버섯" +L["Gift of Adoration"] = true +L["Glowcap"] = true +L["Gnomish"] = "노움" +L["Goblin"] = "고블린" +L["Goblin AH"] = "고블린 경매장" +L["Golden Sansam"] = "황금산삼" +L["Goldthorn"] = "황금가시" +L["Gold Vein"] = "금 광맥" +L["Gordok Brewery"] = true +L["Grave Moss"] = "무덤이끼" +L["Green Dragon Mail"] = true +L["Grey"] = "회색" +L["Gromsblood"] = true +L["Guild Bank not visited yet (or not guilded)"] = "아직 길드 은행 미방문(또는 길드 미가입)" +L["Guild Bank Remote Update"] = "원격으로 길드 뱅크 업데이트" +L["Guild Bank Tabs"] = "길드 은행 탭" +L["Guild bank tab %s successfully updated !"] = "%s 길드 은행 탭을 성공적으로 업데이트함 !" +L["Guild Communication Enabled"] = "길드 대화 사용 중" +L["Guild Members"] = "길드원" +L["Guild Skills"] = "길드 기술" +L["Guilds received !"] = "길드들을 받았습니다!" +L["Guild %s successfully deleted"] = "%s 길드를 성공적으로 삭제함" +L["Gul'bor"] = true +L["Gurubashi Arena"] = "구루바시 투기장" +L["Hakkari Thorium Vein"] = "학카리 토륨 광맥" +L["Halaa (Nagrand)"] = "할라아 (나그란드)" +L["Hallow's End"] = true +L["Hard Mode"] = true +L["Harvest Festival"] = "추수감사절 축제" +L["(has auctions)"] = "(경매물 있음)" +L["(has bids)"] = "(입찰건 있음)" +L["has come online"] = "온라인 상태" +L["has gone offline"] = "오프라인 상태" +L["(has mail)"] = "(우편물 있음)" +L[" has no mail, last check "] = "최근 확인한 바로는 우편물 없음" +L[" has not visited his/her mailbox yet"] = "아직 우편함을 열어보지 않음" +L["Headless Horseman"] = true +L["Heal"] = "힐" +L["Hellfire Fortifications"] = true +L["Henry Stern"] = true +L["Herbalism"] = "약초채집" +L[" (Heroic)"] = " (영웅)" +L["Heroic Mode Tokens"] = "영웅 모드 토큰" +L["hide"] = "숨김" +L["Hides the UI"] = "UI 숨김" +L["Hide this guild in the tooltip"] = "툴팁에서 이 길드 숨김" +L["Highlord Kruul"] = true +L["Hoary Templar (Wind)"] = true +L["Honor points: "] = "전장 점수: " +L["Horde Forces"] = "호드 연합" +L["Hunter Set"] = "사냥꾼 세트" +L["Icecap"] = "얼음송이" +L["Imbued Netherweave"] = true +L["Imperial Plate"] = true +L["Incendicite Mineral Vein"] = true +L["Include guild bank count in the total count"] = "총계에 길드 은행도 포함" +L["Include guild bank(s)"] = "길드 은행도 포함" +L["Include guild members' professions"] = "길드원의 전문기술도 포함" +L["Include items without level requirement"] = "레벨 제한 없는 아이템도 포함" +L["Include known recipes"] = "배운 제조법도 포함" +L["Include mailboxes"] = "우편함도 포함" +L["Increases attack power by %d+"] = "공격력 증가 %d+" +L["Increases damage and healing done by magical spells and effects by up to %d+"] = true +L["Increases healing done by up to %d+"] = true +L["Indurium Mineral Vein"] = true +L["Inscription"] = "주문각인" +L["Invalid tradeskill link"] = "잘못된 전문/보조기술 링크" +L["Iron Deposit"] = "철 광맥" +L["Ironfeather Armor"] = true +L[" is "] = true +L["Item Level"] = "아이템 레벨" +L["Item / Location"] = "아이템 / 위치" +L["Items"] = "아이템" +L["Journeyman"] = "중급" +L["Karrog"] = true +L["Khadgar's Whisker"] = "카드가의 수염" +L["Khorium Vein"] = "코륨 광맥" +L["Khorium Ward"] = true +L["Kingsblood"] = "왕꽃잎풀" +L["Krom Stoutarm Chest"] = true +L["Lady Falther'ess"] = true +L["Lake Wintergrasp"] = "겨울손아귀 호수" +L["Large Obsidian Chunk"] = true +L["last check "] = "최근 확인" +L["Last visit: %s by %s"] = "마지막 방문: %s %s" +L["Leather Set"] = "가죽 세트" +L["Leatherworking Leather Sets"] = "가죽세공 가죽 세트" +L["Leatherworking Mail Sets"] = "가죽세트 사슬 세트" +L["Left-click to"] = "왼쪽 클릭" +L["Left-click to |cFF00FF00open"] = "왼쪽 클릭 |cFF00FF00열기" +L["Left-click to invite attendees"] = true +L["Left-click to see this character's equipment"] = "이 캐릭터의 장비를 보려면 왼쪽 클릭" +L["Left click to view"] = "보려면 왼쪽 클릭" +L["Legendaries"] = "전설" +L["Legendary Mount"] = "전설급 탈것" +L["Lesser Bloodstone Deposit"] = true +L["Level"] = "레벨" +L["Level 30-39"] = "레벨 30-39" +L["Level 40-49"] = "레벨 40-49" +L["Level 50-60"] = "레벨 50-60" +L["Level 70"] = "레벨 70" +L["Level 70 Reputation PVP"] = true +L["Level %d Honor PVP"] = true +L["Levels"] = "레벨" +L["Liferoot"] = true +L["Local Time: %s %sRealm Time: %s"] = "지역 시간: %s %s서버 시간: %s" +L["Location"] = "위치" +L["Lockpicking"] = "자물쇠 따기" +L["Loot Card Items"] = true +L["Loots"] = "전리품" +L["Loot tables"] = "전리품 표" +L["Lord Ahune"] = true +L["Lord Blackwood"] = true +L["Love is in the air"] = true +L["Lucky Red Envelope"] = true +L["Lunacy Deck"] = true +L["Lunar Festival"] = "달의 축제" +L["Lv %s Rewards"] = "레벨 %s 보상" +L["Mageroyal"] = "마법초꽃잎" +L["Mage Set"] = "마법사 세트" +L["Magregan Deepshadow"] = true +L["Mail"] = "우편" +L["Mail Expiry Warning"] = "우편 소멸 경고" +L["Mail is about to expire on at least one character."] = "한 캐릭터 이상에서 우편물 소멸이 가까워졌습니다." +L["Mails"] = "우편" +L["Mail Set"] = "사슬 세트" +L["Mails %s(%d)"] = "우편물 %s(%d)" +L["Mail was last checked "] = true +L["Malevus the Mad"] = true +L["Mana Thistle"] = true +L["Master"] = "전문가" +L["Master Axesmith"] = "도끼 제작 전문가" +L["Master Hammersmith"] = "둔기 제작 전문가" +L["Master Swordsmith"] = "검 제작 전문가" +L["Maximum Level: %s"] = "최대 레벨: %s" +L["Max rest XP displayed as 150%"] = "휴식 경험치 최대치를 150%로 표시" +L["Midsummer Fire Festival"] = "한여름의 불꽃 축제" +L["Minimap Icon Angle"] = "미니맵 아이콘 각도" +L["Minimap Icon Radius"] = "미니맵 아이콘 거리" +L["Minimum Level: %s"] = "최소 레벨: %s" +L["Mining"] = "채광" +L["Miscellaneous"] = "기타" +L["Mithril Deposit"] = "미스릴 광맥" +L["Mooncloth"] = "달빛옷감" +L["Mountain Silversage"] = "은초롱이" +L["Move to change the angle of the minimap icon"] = "미니맵 아이콘의 각도를 바꿈" +L["Move to change the radius of the minimap icon"] = "미니맵 아이콘의 거리를 바꿈" +L["Muddy Churning Waters"] = true +L["N/A"] = "해당 없음" +L["Netherbloom"] = true +L["Nethercite Deposit"] = true +L["Netherdust Bush"] = true +L["Netherscale Armor"] = true +L["Netherstrike Armor"] = true +L["Netherweave Vestments"] = true +L["New mail notification"] = "새 우편물 알림" +L["Nightmare Vine"] = true +L["Noblegarden"] = true +L["No currencies found"] = "화폐를 찾을 수 없음" +L["No data"] = "데이터 없음" +L["No guild found"] = "길드 없음" +L["No match found!"] = "찾지 못 함" +L["Non Set Accessories"] = "세트 아닌 장신구" +L["Non Set Cloth"] = "세트 아닌 천" +L["Non Set Leather"] = "세트 아닌 가죽" +L["Non Set Mail"] = "세트 아닌 사슬" +L["Non Set Plate"] = "세트 아닌 판금" +L["No quest found for "] = "퀘스트를 찾을 수 없음" +L["No reputations found"] = "평판을 찾을 수 없음" +L["No rest XP"] = "휴식 경험치 없음" +L[" not found!"] = "찾지 못 함!" +L["Not started"] = "시작 안 함" +L["Number of players: %s"] = "사용자 수: %s" +L["Offline Members"] = "오프라인 멤버" +L["Olaf"] = true +L["Ooze Covered Gold Vein"] = true +L["Ooze Covered Mithril Deposit"] = true +L["Ooze Covered Rich Thorium Vein"] = true +L["Ooze Covered Silver Vein"] = true +L["Ooze Covered Thorium Vein"] = true +L["Ooze Covered Truesilver Deposit"] = true +L["open/close"] = "열기/닫기" +L["Opera (Shared Drops)"] = true +L["Other"] = "기타" +L["Outdoor Bosses"] = true +L["Paladin Set"] = "성기사 세트" +L["Patterns"] = true +L["Peacebloom"] = "평온초" +L["Plaguebloom"] = "역병초" +L["Plans"] = true +L["Plate Set"] = "판금 세트" +L["Please open this window again"] = true +L["Poisons"] = "독" +L["Porfus the Gem Gorger"] = true +L["Portals Deck"] = true +L["Priest Set"] = "사제 세트" +L["Primal Batskin"] = true +L["Primal Intent"] = true +L["Primal Mooncloth"] = true +L["Private to friends: %s"] = true +L["Private to guild: %s"] = true +L["Prof. 1"] = "전문기술1" +L["Prof. 2"] = "전문기술2" +L["Professions"] = "전문기술" +L["Purple Lotus"] = "보라연꽃" +L["PVP Cloth Set"] = "PvP 천 세트" +L["PVP Leather Sets"] = "PvP 가죽 세트" +L["PVP Mail Sets"] = "PvP 사슬 세트" +L["PVP Plate Sets"] = "PvP 판금 세트" +L["Pyron"] = true +L["QuestID"] = "퀘스트ID" +L["Quest Items"] = "퀘스트 아이템" +L["Quest rewards"] = "퀘스트 보상" +L["Quests"] = "퀘스트" +L["Ragveil"] = true +L["Rajaxx's Captains"] = true +L["Random Boss"] = "랜덤 보스" +L["Rare Fish"] = "희귀 물고기" +L["Rare Fish Rewards"] = "희귀 물고기 보상" +L["Razorfen Spearhide"] = true +L["Realm"] = "서버" +L["Realm %s successfully deleted"] = "%s 서버가 성공적으로 삭제됨" +L["Reference data not available"] = "참조 데이터를 쓸 수 없음" +L["Reference data received (%s) !"] = "참조 데이터 받음 (%s) !" +L["Refer to the activity pane for more details."] = true +L["Relics"] = true +L["Reputations"] = "평판" +L["Reputations received !"] = "평판들을 받았습니다 !" +L["Requesting item %d of %d"] = "아이템 요청 중 %d / %d" +L["Requesting %s information from %s"] = "%s 정보를 %s에게서 요청 중" +L["Request rejected by %s"] = "%s, 요청을 거절함" +L["Reset"] = "초기화" +L["Resistance"] = "저항" +L["Rested"] = "남음" +L["Restores %d+ mana per"] = "%d+ 마나 복원 / " +L["Rest XP"] = "휴식 경험치" +L[" results found (Showing "] = " 결과를 찾음 (보임 " +L["Rethilgore"] = true +L["Revanchion"] = true +L["Rich Adamantite Deposit"] = "풍부한 아다만타이트 광맥" +L["Rich Thorium Vein"] = "풍부한 토륨 광맥" +L["Riding"] = "탈것 타기" +L["Right-Click for options"] = "옵션은 오른쪽 클릭" +L["Right-click to |cFF00FF00drag"] = "|cFF00FF00드래그 는 오른쪽 클릭" +L["Right-Click to find an upgrade"] = "업그레이드할 것을 찾으려면 오른쪽 클릭" +L["Rogue Proficiencies"] = true +L["Rogue Set"] = "도적 세트" +L["Roogug"] = true +L["Sanguine Hibiscus"] = true +L["Savage Gladiator's Weapons"] = true +L["Scaled Draenic Armor"] = true +L[" scan failed for "] = " 검색 실패 " +L["Scan mail body (marks it as read)"] = "우편물 내용을 검색 (읽은 것으로 표시됨)" +L["Scorn"] = true +L["Scourge Invasion"] = true +L["search"] = "검색" +L["Search Containers"] = "보관함 검색" +L["Search in bags"] = "가방에서 검색" +L["Secondary Skills"] = "보조기술" +L[ [=[Security hint: disable this if you have officer rights +on guild bank tabs that may not be viewed by everyone, +and authorize requests manually]=] ] = true +L[ [=[Security hint: Only enable this when you actually need to transfer data, +disable otherwise]=] ] = true +L["Send account sharing request to:"] = "계정 공유 요청을 보냄:" +L["Sending account sharing request to %s"] = "%s에게 계정 공유 요청을 보내는 중" +L["Sending character %s (%d of %d)"] = "%s 캐릭터를 보내는 중 (%d/%d)" +L["Sending currencies (%d of %d)"] = true +L["Sending guilds (%d of %d)"] = "길드 보내는 중 (%d/%d)" +L["Sending reference data: %s (%d of %d)"] = "참조 데이터 보내는 중: %s (%d/%d)" +L["Sending reputations (%d of %d)"] = "평판 보내는 중 (%d/%d)" +L["Sending table of content (%d items)"] = true +L["Sever"] = "서버" +L["Shadoweave"] = true +L["Shadowforge Cache"] = true +L["Shadow's Embrace"] = true +L["Shaman Set"] = "주술사 세트" +L["Shared"] = "공유됨" +L["Shartuul"] = true +L["%s has disabled account sharing"] = "%s, 계정 공유 해제" +L["%s has disabled guild communication"] = "%s, 길드 대화 해제" +L["%s has no auctions"] = "%s 경매물 없음" +L["%s has no bids"] = "%s 입찰건 없음" +L["%s has no mail"] = "%s 우편물 없음" +L["Shen'dralar Provisioner"] = true +L["Shift-Click to link this info"] = "이 정보를 링크하려면 쉬프트 클릭" +L["Shift+Left click to link"] = "링크하려면 쉬프트 왼쪽 클릭" +L["show"] = "보이기" +L["Show already known/learnable by"] = "이미 배움/배울 수 있음 보이기" +L["Show counters for all accounts"] = "모든 계정의 갯수 보이기" +L["Show counters for both factions"] = "양 진영의 갯수 보이기" +L["Show counters on gathering nodes"] = true +L["Show FuBar icon"] = "FuBar 아이콘 보이기" +L["Show FuBar text"] = "FuBar 텍스트 보이기" +L["Show guild bank count"] = "길드 은행 수 보이기" +L["Show item count per character"] = "캐릭터 당 아이템 갯수 보이기" +L["Show item ID and item level"] = "아이템 ID와 레벨 보이기" +L["Show item source"] = "아이템 출처 보이기" +L["Show Minimap Icon"] = "미니맵 아이콘 보이기" +L["Shows the UI"] = "UI 보이기" +L["Show total item count"] = "총 아이템 갯수 보이기" +L["Silverleaf"] = "은엽수잎" +L["Silver Vein"] = "은 광맥" +L["%s is in combat, request cancelled"] = "%s 전투 중, 요청이 중단됨" +L["%s is now ready (%s on %s)"] = "%s 지금 준비 (%s %s)" +L["%s is now unlocked (%s on %s)"] = "%s 지금 풀림 (%s %s)" +L["%s is %s with %s (%d/%d)"] = true +L["Skettis"] = true +L["Skinning"] = "무두질" +L["Skyguard Raid"] = true +L["slots"] = "칸" +L["Small Obsidian Chunk"] = true +L["Small Thorium Vein"] = "작은 토륨 광맥" +L["Smokywood Pastures Extra-Special Gift"] = true +L["Smokywood Pastures Vendor"] = true +L["Socket"] = "소켓" +L["Sort loots in descending order"] = true +L["Sothos & Jarien"] = true +L["Soulcloth Embrace"] = true +L["Source"] = "출처" +L["Spawn Of Hakkar"] = true +L["Spellfire"] = true +L["Spellstrike Infusion"] = true +L["Spirit Towers (Terrokar)"] = true +L["%s|r has received a mail from %s"] = "%s|r %s의 우편물을 받았음" +L[ [=[%s%s|r has requested the bank tab %s%s|r +Send this information ?]=] ] = true +L["%s starts in %d minutes (%s on %s)"] = true +L["Started"] = "시작됨" +L["Stasis Chambers"] = true +L["Steamwheedle Cartel"] = "스팀휘들 무역연합" +L["Storms Deck"] = true +L["Stormshroud Armor"] = true +L["Stranglekelp"] = true +L["Strength of the Clefthoof"] = true +L["Suggested leveling zone: "] = "권장 레벨링 지역: " +L["Suggestion"] = "권장" +L["Summary"] = "요약" +L["Summoner's Tomb"] = true +L["Sungrass"] = "태양풀" +L["Superior Rewards"] = true +L[ [=[%sWarning:|r if you accept, %sALL|r information known +by Altoholic will be sent to %s%s|r (bags, money, etc..)]=] ] = true +L["%sWarning:|r make sure this user may view this information before accepting"] = true +L["Swiftthistle"] = true +L["%s will be ready in %d minutes (%s on %s)"] = true +L["Table of content received (%d items)"] = true +L["Tablet of Ryuneh"] = true +L["Tablet of Will"] = true +L["Tailoring Sets"] = "재봉기술 세트" +L["Tank"] = "탱커" +L["T'chali's Voodoo Brewery"] = true +L["Terocone"] = true +L["Terokk"] = true +L["The Darksoul"] = true +L["The Duke of Cinders (Fire)"] = true +L["The Duke of Fathoms (Water)"] = true +L["The Duke of Shards (Earth)"] = true +L["The Duke of Zephyrs (Wind)"] = true +L["Theldren"] = true +L[ [=[There is a risk of disconnection if the queried item +is a loot from a high level dungeon. + +]=] ] = true +L["The Unyielding"] = true +L["The Vault"] = "금고" +L["Thick Draenic Armor"] = true +L["This character"] = "이 캐릭터" +L["This faction"] = "이 평판" +L["This field |cFF00FF00cannot|r be left empty."] = true +L[ [=[This name can be anything you like, +it does |cFF00FF00NOT|r have to be the real account name.]=] ] = true +L["This realm"] = "이 서버" +L[ [=[This will gradually improve the consistency of the searches, +as more items are available in the item cache. + +]=] ] = true +L["Thomas Yance"] = true +L["Thunderbrew Brewery"] = true +L["Ticking Present"] = true +L["Tier 0.5 Quests"] = "티어 0.5 퀘스트" +L["Tier %d Tokens"] = "티어 %d 토큰" +L["Timed Chest"] = true +L["Tin Vein"] = "주석 광맥" +L["toggle"] = "토글" +L["Toggles the UI"] = "UI 숨기기/보이기" +L["Token Hand-Ins"] = true +L["Tooltip"] = "툴팁" +L["Total owned"] = "총 소유" +L["Totals"] = "총합" +L["Transfer complete"] = "전송 완료" +L["Transmute"] = true +L["Transparency"] = "투명도" +L["Trash Mobs"] = true +L["Treat Bag"] = true +L["Tribal"] = "전통" +L["Tribute Run"] = true +L["Trinkets"] = "장신구" +L["Troll Mini bosses"] = true +L["Truesilver Deposit"] = "진은 광맥" +L["Twin Spire Ruins"] = true +L["Unknown"] = "알 수 없음" +L["Unknown link, please relog this character"] = "알 수 없는 링크, 이 캐릭터를 다시 로긴해보세요." +L["Upper Deck"] = true +L["up to"] = "~" +L["Vakkiz the Windrager"] = true +L["Various Locations"] = "여러 지역" +L["View"] = "보기" +L["View auctions"] = "경매 보기" +L["View bags"] = "가방 보기" +L["View bids"] = "입찰 보기" +L["View mailbox"] = "우편함 보기" +L["View quest log"] = "퀘스트 기록 보기" +L["Visited"] = "방문함" +L["Volcanic Armor"] = true +L["Waiting for %s to accept .."] = "%s 승인을 기다리는 중 .." +L["Warlock Set"] = "흑마법사 세트" +L["Warlords Deck"] = true +L["Warn %d minutes before an event starts"] = "이벤트 시작 %d 분 전에 경고" +L["Warn when mail expires in less days than this value"] = "우편물의 소멸 날짜가 이 값보다 더 적으면 경고" +L["Warrior Set"] = "전사 세트" +L["Weapons"] = "무기" +L["Weaponsmith"] = "무기제작" +L["Week starts on Monday"] = "한 주 시작을 월요일부터" +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected. + +]=] ] = [=[|cFFFF0000해제|cFFFFFFFF 시, +자동으로 모든 요청을 거절합니다." ]=] +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = "|cFFFF0000해제|cFFFFFFFF 시, 길드 대화하지 않습니다." +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be +required before sending any information. + +]=] ] = [=[|cFFFF0000해제|cFFFFFFFF 시, + 정보를 보내기 전에 확인을 받습니다.]=] +L["Whitemend Wisdom"] = true +L["Wild Draenish Armor"] = true +L["Wild Steelbloom"] = "야생 철쭉" +L["Wildvine"] = true +L["Will be learnable by "] = "추후 학습 가능" +L["Windhawk Armor"] = true +L["Wintersbite"] = true +L["Winter Veil Gift"] = true +L[" with "] = true +L["World Drops"] = "월드 드랍" +L["World PVP"] = "월드 PvP" +L["WoW Collector Edition"] = "WoW 컬렉터 에디션" +L["Wrathbringer Laz-tarash"] = true +L["Wrath of Spellfire"] = true +L["Yor (Heroic Summon)"] = true +L[ [=[You have received an account sharing request +from %s%s|r, accept it?]=] ] = "%s%s|r의 계정 공유 요청을 승인하겠습니까?" +L[ [=[Your confirmation will still be required any time someone requests your information. + +]=] ] = "당신의 정보 요구하는 모든 요청에 대해 승인 절차를 거치게 될 것입니다." +L["Zelemar the Wrathful"] = true +L["Zone"] = "지역" diff --git a/Altoholic-Addon/Altoholic/Locales/repoenUS.lua b/Altoholic-Addon/Altoholic/Locales/repoenUS.lua new file mode 100644 index 0000000..29bfa65 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/repoenUS.lua @@ -0,0 +1,775 @@ +local L = LibStub("AceLocale-3.0"):NewLocale("Altoholic", "enUS", true, true) + +if not L then return end + +-- Note: since 2.4.004 and the support of LibBabble, certain lines are commented, but remain there for clarity (especially those concerning the menu) +-- A lot of translations, especially those concerning the loot table, come from atlas loot, credit goes to their team for gathering this info, I (Thaoky) simply took what I needed. + +L["Death Knight"] = true + +-- note: these string are the ones found in item tooltips, make sure to respect the case when translating, and to distinguish them (like crit vs spell crit) +L["Increases healing done by up to %d+"] = true +L["Increases damage and healing done by magical spells and effects by up to %d+"] = true +L["Increases attack power by %d+"] = true +L["Restores %d+ mana per"] = true +L["Classes: Shaman"] = true +L["Classes: Mage"] = true +L["Classes: Rogue"] = true +L["Classes: Hunter"] = true +L["Classes: Warrior"] = true +L["Classes: Paladin"] = true +L["Classes: Warlock"] = true +L["Classes: Priest"] = true +L["Classes: Death Knight"] = true +L["Resistance"] = true + +--skills +L["Class Skills"] = true +L["Professions"] = true +L["Secondary Skills"] = true +L["Fishing"] = true +L["Riding"] = true +L["Herbalism"] = true +L["Mining"] = true +L["Skinning"] = true +L["Lockpicking"] = true +L["Poisons"] = true +L["Beast Training"] = true +L["Inscription"] = true + +--factions not in LibFactions or LibZone +L["Alliance Forces"] = true +L["Horde Forces"] = true +L["Steamwheedle Cartel"] = true +L["Other"] = true + +-- menu +L["Reputations"] = true +L["Containers"] = true +L["Guild Bank not visited yet (or not guilded)"] = true +L["E-Mail"] = true +L["Quests"] = true +L["Equipment"] = true + +--Altoholic.lua +L["Account"] = true +L["Default"] = true +L["Loots"] = true +L["Unknown"] = true +L["has come online"] = true +L["has gone offline"] = true +L["Bank not visited yet"] = true +L["Levels"] = true +L["(has mail)"] = true +L["(has auctions)"] = true +L["(has bids)"] = true + +L["No rest XP"] = true +L["Rested"] = true +L["Transmute"] = true + +L["Bags"] = true +L["Bank"] = true +L["AH"] = true -- for auction house, obviously +L["Equipped"] = true +L["Mail"] = true +L["Mails %s(%d)"] = true +L["Mails"] = true +L["Visited"] = true +L["Auctions %s(%d)"] = true +L["Bids %s(%d)"] = true + +L["Level"] = true +L["Zone"] = true +L["Rest XP"] = true + +L["Source"] = true +L["Total owned"] = true +L["Already known by "] = true +L["Will be learnable by "] = true +L["Could be learned by "] = true + +L["At least one recipe could not be read"] = true +L["Please open this window again"] = true + +--Calendar.lua +L["Number of players: %s"] = true +L["Minimum Level: %s"] = true +L["Maximum Level: %s"] = true +L["Private to friends: %s"] = true +L["Private to guild: %s"] = true +L["Attendees: "] = true +L["%s starts in %d minutes (%s on %s)"] = true +L["%s will be ready in %d minutes (%s on %s)"] = true +L["%s is now ready (%s on %s)"] = true +L["%s is now unlocked (%s on %s)"] = true +L["%s will be unlocked in %d minutes (%s on %s)"] = true +L["Left-click to invite attendees"] = true +L["Display warnings in a dialog box"] = true +L["Do you want to open Altoholic's calendar for details ?"] = true + +--Comm.lua +L["Sending account sharing request to %s"] = true +L["Account sharing request received from %s"] = true +L["You have received an account sharing request\nfrom %s%s|r, accept it?"] = true +L["%sWarning:|r if you accept, %sALL|r information known\nby Altoholic will be sent to %s%s|r (bags, money, etc..)"] = true +L["Request rejected by %s"] = true +L["%s is in combat, request cancelled"] = true +L["%s has disabled account sharing"] = true +L["Table of content received (%d items)"] = true +L["Sending reputations (%d of %d)"] = true +L["Sending currencies (%d of %d)"] = true +L["Sending guilds (%d of %d)"] = true +L["Sending character %s (%d of %d)"] = true +L["No reputations found"] = true +L["No currencies found"] = true +L["No guild found"] = true +L["Transfer complete"] = true +L["Reputations received !"] = true +L["Currencies received !"] = true +L["Guilds received !"] = true +L["Character %s received !"] = true +L["Requesting item %d of %d"] = true +L["Sending table of content (%d items)"] = true +L["Guild bank tab %s successfully updated !"] = true +L["%s has disabled guild communication"] = true +L["%s%s|r has requested the bank tab %s%s|r\nSend this information ?"] = true +L["%sWarning:|r make sure this user may view this information before accepting"] = true +L["%s|r has received a mail from %s"] = true +L["Sending reference data: %s (%d of %d)"] = true +L["Reference data not available"] = true +L["Reference data received (%s) !"] = true +L["Waiting for %s to accept .."] = true + +--GuildBankTabs.lua +L["Requesting %s information from %s"] = true +L["Guild Bank Remote Update"] = true +L["Clicking this button will update\nyour local %s%s|r bank tab\nbased on %s%s's|r data"] = true + +--GuildMembers.lua +L["Left-click to see this character's equipment"] = true +L["Click a character's AiL to see its equipment"] = true + +--GuildProfessions.lua +L["Offline Members"] = true +L["Left click to view"] = true +L["Shift+Left click to link"] = true + +--Core.lua +L['search'] = true +L["Search in bags"] = true +L['show'] = true +L["Shows the UI"] = true +L['hide'] = true +L["Hides the UI"] = true +L['toggle'] = true +L["Toggles the UI"] = true +L["Altoholic:|r Usage = /altoholic search "] = true + +--AltoholicFu.lua +L["Left-click to"] = true +L["open/close"] = true + +--AccountSummary.lua +L["View bags"] = true +L["All-in-one"] = true +L["View mailbox"] = true +L["View quest log"] = true +L["View auctions"] = true +L["View bids"] = true +L["Delete this Alt"] = true +L["Cannot delete current character"] = true +L["Character %s successfully deleted"] = true +L["Delete this Realm"] = true +L["Cannot delete current realm"] = true +L["Realm %s successfully deleted"] = true +L["Suggested leveling zone: "] = true +L["Arena points: "] = true +L["Honor points: "] = true +L["Right-Click for options"] = true +L["Average Item Level"] = true + +-- AuctionHouse.lua +L["%s has no auctions"] = true +L["%s has no bids"] = true +L["last check "] = true +L["Goblin AH"] = true +L["Clear your faction's entries"] = true +L["Clear goblin AH entries"] = true +L["Clear all entries"] = true + +--BagUsage.lua +L["Totals"] = true +L["slots"] = true +L["free"] = true + +--Containers.lua +L["32 Keys Max"] = true +L["28 Slot"] = true +L["Bank bag"] = true +L["Unknown link, please relog this character"] = true + +--Equipment.lua +L["Find Upgrade"] = true +L["(based on iLvl)"] = true +L["Right-Click to find an upgrade"] = true +L["Tank"] = true +L["DPS"] = true +L["Balance"] = true +L["Elemental Shaman"] = true -- shaman spec ! +L["Heal"] = true + +--GuildBank.lua +L["Last visit: %s by %s"] = true +L["Local Time: %s %sRealm Time: %s"] = true + +--Mails.lua +L[" has not visited his/her mailbox yet"] = true +L["%s has no mail"] = true +L[" has no mail, last check "] = true +L[" days ago"] = true +L["Mail was last checked "] = true +L[" days"] = true +L["Mail is about to expire on at least one character."] = true +L["Refer to the activity pane for more details."] = true +L["Do you want to view it now ?"] = true +L["Will be %sreturned|r in"] = true +L["Will be %sdeleted|r in"] = true + +--Quests.lua +L["No quest found for "] = true +L["QuestID"] = true +L["Are also on this quest:"] = true + +--Recipes.lua +L["No data"] = true +L[" scan failed for "] = true + +--Reputations.lua +L["Shift-Click to link this info"] = true +L[" is "] = true +L[" with "] = true +L["%s is %s with %s (%d/%d)"] = true + +--Search.lua +L["Item Level"] = true +L[" results found (Showing "] = true +L["No match found!"] = true +L[" not found!"] = true +L["Socket"] = true + +--skills.lua +L["Rogue Proficiencies"] = true +L["up to"] = true +L["at"] = true +L["and above"] = true +L["Suggestion"] = true +L["Prof. 1"] = true +L["Prof. 2"] = true +L["Grey"] = true +L["All cooldowns are up"] = true + +-- TabSummary.lua +L["All accounts"] = true + +-- TabCharacters.lua +L["Cannot link another realm's tradeskill"] = true +L["Cannot link another account's tradeskill"] = true +L["Invalid tradeskill link"] = true +L["Expiry:"] = true + +-- TabGuildBank.lua +L["N/A"] = true +L["Delete Guild Bank?"] = true +L["Guild %s successfully deleted"] = true + +-- TabSearch.lua +L["Any"] = true +L["Miscellaneous"] = true +L["Fishing Poles"] = true +L["This realm"] = true +L["All realms"] = true +L["Loot tables"] = true +L["This character"] = true +L["This faction"] = true +L["Both factions"] = true + +--loots.lua +--Instinct drop +L["Hard Mode"] = true +L["Trash Mobs"] = true +L["Random Boss"] = true +L["Druid Set"] = true +L["Hunter Set"] = true +L["Mage Set"] = true +L["Paladin Set"] = true +L["Priest Set"] = true +L["Rogue Set"] = true +L["Shaman Set"] = true +L["Warlock Set"] = true +L["Warrior Set"] = true +L["Legendary Mount"] = true +L["Legendaries"] = true +L["Muddy Churning Waters"] = true +L["Shared"] = true +L["Enchants"] = true +L["Rajaxx's Captains"] = true +L["Class Books"] = true +L["Quest Items"] = true +L["Druid of the Fang (Trash Mob)"] = true +L["Spawn Of Hakkar"] = true +L["Troll Mini bosses"] = true +L["Henry Stern"] = true +L["Magregan Deepshadow"] = true +L["Tablet of Ryuneh"] = true +L["Krom Stoutarm Chest"] = true +L["Garrett Family Chest"] = true +L["Eric The Swift"] = true +L["Olaf"] = true +L["Baelog's Chest"] = true +L["Conspicuous Urn"] = true +L["Tablet of Will"] = true +L["Shadowforge Cache"] = true +L["Roogug"] = true +L["Aggem Thorncurse"] = true +L["Razorfen Spearhide"] = true +L["Pyron"] = true +L["Theldren"] = true +L["The Vault"] = true +L["Summoner's Tomb"] = true +L["Plans"] = true +L["Zelemar the Wrathful"] = true +L["Rethilgore"] = true +L["Fel Steed"] = true +L["Tribute Run"] = true +L["Shen'dralar Provisioner"] = true +L["Books"] = true +L["Trinkets"] = true +L["Sothos & Jarien"] = true +L["Fel Iron Chest"] = true +L[" (Heroic)"] = true +L["Yor (Heroic Summon)"] = true +L["Avatar of the Martyred"] = true +L["Anzu the Raven God (Heroic Summon)"] = true +L["Thomas Yance"] = true +L["Aged Dalaran Wizard"] = true +L["Cache of the Legion"] = true +L["Opera (Shared Drops)"] = true +L["Timed Chest"] = true +L["Patterns"] = true + +--Rep +L["Token Hand-Ins"] = true +L["Items"] = true +L["Beasts Deck"] = true +L["Elementals Deck"] = true +L["Warlords Deck"] = true +L["Portals Deck"] = true +L["Furies Deck"] = true +L["Storms Deck"] = true +L["Blessings Deck"] = true +L["Lunacy Deck"] = true +L["Quest rewards"] = true + +--World drop +L["Outdoor Bosses"] = true +L["Highlord Kruul"] = true +L["Bash'ir Landing"] = true +L["Skyguard Raid"] = true +L["Stasis Chambers"] = true +L["Skettis"] = true +L["Darkscreecher Akkarai"] = true +L["Karrog"] = true +L["Gezzarak the Huntress"] = true +L["Vakkiz the Windrager"] = true +L["Terokk"] = true +L["Ethereum Prison"] = true +L["Armbreaker Huffaz"] = true +L["Fel Tinkerer Zortan"] = true +L["Forgosh"] = true +L["Gul'bor"] = true +L["Malevus the Mad"] = true +L["Porfus the Gem Gorger"] = true +L["Wrathbringer Laz-tarash"] = true +L["Abyssal Council"] = true +L["Crimson Templar (Fire)"] = true +L["Azure Templar (Water)"] = true +L["Hoary Templar (Wind)"] = true +L["Earthen Templar (Earth)"] = true +L["The Duke of Cinders (Fire)"] = true +L["The Duke of Fathoms (Water)"] = true +L["The Duke of Zephyrs (Wind)"] = true +L["The Duke of Shards (Earth)"] = true +L["Elemental Invasion"] = true +L["Gurubashi Arena"] = true +L["Booty Run"] = true +L["Fishing Extravaganza"] = true +L["First Prize"] = true +L["Rare Fish"] = true +L["Rare Fish Rewards"] = true +L["Children's Week"] = true +L["Love is in the air"] = true +L["Gift of Adoration"] = true +L["Box of Chocolates"] = true +L["Hallow's End"] = true +L["Various Locations"] = true +L["Treat Bag"] = true +L["Headless Horseman"] = true +L["Feast of Winter Veil"] = true +L["Smokywood Pastures Vendor"] = true +L["Gaily Wrapped Present"] = true +L["Festive Gift"] = true +L["Winter Veil Gift"] = true +L["Gently Shaken Gift"] = true +L["Ticking Present"] = true +L["Carefully Wrapped Present"] = true +L["Noblegarden"] = true +L["Brightly Colored Egg"] = true +L["Smokywood Pastures Extra-Special Gift"] = true +L["Harvest Festival"] = true +L["Food"] = true +L["Scourge Invasion"] = true +L["Miscellaneous"] = true +L["Cloth Set"] = true +L["Leather Set"] = true +L["Mail Set"] = true +L["Plate Set"] = true +L["Balzaphon"] = true +L["Lord Blackwood"] = true +L["Revanchion"] = true +L["Scorn"] = true +L["Sever"] = true +L["Lady Falther'ess"] = true +L["Lunar Festival"] = true +L["Fireworks Pack"] = true +L["Lucky Red Envelope"] = true +L["Midsummer Fire Festival"] = true +L["Lord Ahune"] = true +L["Shartuul"] = true +L["Blade Edge Mountains"] = true +L["Brewfest"] = true +L["Barleybrew Brewery"] = true +L["Thunderbrew Brewery"] = true +L["Gordok Brewery"] = true +L["Drohn's Distillery"] = true +L["T'chali's Voodoo Brewery"] = true + +--craft +L["Crafted Weapons"] = true +L["Master Swordsmith"] = true +L["Master Axesmith"] = true +L["Master Hammersmith"] = true +L["Blacksmithing (Lv 60)"] = true +L["Blacksmithing (Lv 70)"] = true +L["Engineering (Lv 60)"] = true +L["Engineering (Lv 70)"] = true +L["Blacksmithing Plate Sets"] = true +L["Imperial Plate"] = true +L["The Darksoul"] = true +L["Fel Iron Plate"] = true +L["Adamantite Battlegear"] = true +L["Flame Guard"] = true +L["Enchanted Adamantite Armor"] = true +L["Khorium Ward"] = true +L["Faith in Felsteel"] = true +L["Burning Rage"] = true +L["Blacksmithing Mail Sets"] = true +L["Bloodsoul Embrace"] = true +L["Fel Iron Chain"] = true +L["Tailoring Sets"] = true +L["Bloodvine Garb"] = true +L["Netherweave Vestments"] = true +L["Imbued Netherweave"] = true +L["Arcanoweave Vestments"] = true +L["The Unyielding"] = true +L["Whitemend Wisdom"] = true +L["Spellstrike Infusion"] = true +L["Battlecast Garb"] = true +L["Soulcloth Embrace"] = true +L["Primal Mooncloth"] = true +L["Shadow's Embrace"] = true +L["Wrath of Spellfire"] = true +L["Leatherworking Leather Sets"] = true +L["Volcanic Armor"] = true +L["Ironfeather Armor"] = true +L["Stormshroud Armor"] = true +L["Devilsaur Armor"] = true +L["Blood Tiger Harness"] = true +L["Primal Batskin"] = true +L["Wild Draenish Armor"] = true +L["Thick Draenic Armor"] = true +L["Fel Skin"] = true +L["Strength of the Clefthoof"] = true +L["Primal Intent"] = true +L["Windhawk Armor"] = true +L["Leatherworking Mail Sets"] = true +L["Green Dragon Mail"] = true +L["Blue Dragon Mail"] = true +L["Black Dragon Mail"] = true +L["Scaled Draenic Armor"] = true +L["Felscale Armor"] = true +L["Felstalker Armor"] = true +L["Fury of the Nether"] = true +L["Netherscale Armor"] = true +L["Netherstrike Armor"] = true +L["Armorsmith"] = true +L["Weaponsmith"] = true +L["Dragonscale"] = true +L["Elemental"] = true +L["Tribal"] = true +L["Mooncloth"] = true +L["Shadoweave"] = true +L["Spellfire"] = true +L["Gnomish"] = true +L["Goblin"] = true +L["Apprentice"] = true +L["Journeyman"] = true +L["Expert"] = true +L["Artisan"] = true +L["Master"] = true + +--Set & PVP +L["Superior Rewards"] = true +L["Epic Rewards"] = true +L["Lv %s Rewards"] = true +L["PVP Cloth Set"] = true +L["PVP Leather Sets"] = true +L["PVP Mail Sets"] = true +L["PVP Plate Sets"] = true +L["World PVP"] = true +L["Hellfire Fortifications"] = true +L["Twin Spire Ruins"] = true +L["Spirit Towers (Terrokar)"] = true +L["Halaa (Nagrand)"] = true +L["Arena Season %d"] = true +L["Weapons"] = true +L["Accessories"] = true +L["Level 70 Reputation PVP"] = true +L["Level %d Honor PVP"] = true +L["Savage Gladiator\'s Weapons"] = true +L["Deadly Gladiator\'s Weapons"] = true +L["Lake Wintergrasp"] = true +L["Non Set Accessories"] = true +L["Non Set Cloth"] = true +L["Non Set Leather"] = true +L["Non Set Mail"] = true +L["Non Set Plate"] = true +L["Tier 0.5 Quests"] = true +L["Tier %d Tokens"] = true +L["Blizzard Collectables"] = true +L["WoW Collector Edition"] = true +L["BC Collector Edition (Europe)"] = true +L["Blizzcon 2005"] = true +L["Blizzcon 2007"] = true +L["Christmas Gift 2006"] = true +L["Upper Deck"] = true +L["Loot Card Items"] = true +L["Heroic Mode Tokens"] = true +L["Fire Resistance Gear"] = true +L["Emblems of Valor"] = true +L["Emblems of Heroism"] = true + +L["Cloaks"] = true +L["Relics"] = true +L["World Drops"] = true +L["Level 30-39"] = true +L["Level 40-49"] = true +L["Level 50-60"] = true +L["Level 70"] = true + +-- Altoholic.Gathering : Mining +L["Copper Vein"] = true +L["Tin Vein"] = true +L["Iron Deposit"] = true +L["Silver Vein"] = true +L["Gold Vein"] = true +L["Mithril Deposit"] = true +L["Ooze Covered Mithril Deposit"] = true +L["Truesilver Deposit"] = true +L["Ooze Covered Silver Vein"] = true +L["Ooze Covered Gold Vein"] = true +L["Ooze Covered Truesilver Deposit"] = true +L["Ooze Covered Rich Thorium Vein"] = true +L["Ooze Covered Thorium Vein"] = true +L["Small Thorium Vein"] = true +L["Rich Thorium Vein"] = true +L["Hakkari Thorium Vein"] = true +L["Dark Iron Deposit"] = true +L["Lesser Bloodstone Deposit"] = true +L["Incendicite Mineral Vein"] = true +L["Indurium Mineral Vein"] = true +L["Fel Iron Deposit"] = true +L["Adamantite Deposit"] = true +L["Rich Adamantite Deposit"] = true +L["Khorium Vein"] = true +L["Large Obsidian Chunk"] = true +L["Small Obsidian Chunk"] = true +L["Nethercite Deposit"] = true + +-- Altoholic.Gathering : Herbalism +L["Peacebloom"] = true +L["Silverleaf"] = true +L["Earthroot"] = true +L["Mageroyal"] = true +L["Briarthorn"] = true +L["Swiftthistle"] = true +L["Stranglekelp"] = true +L["Bruiseweed"] = true +L["Wild Steelbloom"] = true +L["Grave Moss"] = true +L["Kingsblood"] = true +L["Liferoot"] = true +L["Fadeleaf"] = true +L["Goldthorn"] = true +L["Khadgar's Whisker"] = true +L["Wintersbite"] = true +L["Firebloom"] = true +L["Purple Lotus"] = true +L["Wildvine"] = true +L["Arthas' Tears"] = true +L["Sungrass"] = true +L["Blindweed"] = true +L["Ghost Mushroom"] = true +L["Gromsblood"] = true +L["Golden Sansam"] = true +L["Dreamfoil"] = true +L["Mountain Silversage"] = true +L["Plaguebloom"] = true +L["Icecap"] = true +L["Bloodvine"] = true +L["Black Lotus"] = true +L["Felweed"] = true +L["Dreaming Glory"] = true +L["Terocone"] = true +L["Ancient Lichen"] = true +L["Bloodthistle"] = true +L["Mana Thistle"] = true +L["Netherbloom"] = true +L["Nightmare Vine"] = true +L["Ragveil"] = true +L["Flame Cap"] = true +L["Fel Lotus"] = true +L["Netherdust Bush"] = true + +L["Glowcap"] = true +L["Sanguine Hibiscus"] = true + +-- Old XML strings + +L["Location"] = true +L["Left-click to |cFF00FF00open"] = true +L["Right-click to |cFF00FF00drag"] = true +L["Enter an account name that will be\nused for |cFF00FF00display|r purposes only."] = true +L["This name can be anything you like,\nit does |cFF00FF00NOT|r have to be the real account name."] = true +L["This field |cFF00FF00cannot|r be left empty."] = true + +L["Summary"] = true +L["Characters"] = true + +L["Account Summary"] = true +L["Bag Usage"] = true +L["Activity"] = true +L["Guild Members"] = true +L["Guild Skills"] = true +L["Guild Bank Tabs"] = true +L["Calendar"] = true + +L["Account Sharing Request"] = true +L["Click this button to ask a player\nto share his entire Altoholic Database\nand add it to your own"] = true +L["Both parties must enable account sharing\nbefore using this feature (see options)"] = true +L["Account Sharing"] = true + +L["Realm"] = true +L["Character"] = true +L["View"] = true + +L["Item / Location"] = true + +L["Hide this guild in the tooltip"] = true + +L["Not started"] = true +L["Started"] = true + +L["General"] = true +L["Tooltip"] = true + +L["Totals"] = true +L["Search Containers"] = true +L["Equipment Slot"] = true +L["Reset"] = true + +L["Account Name"] = true +L["Send account sharing request to:"] = true + +--TabOptions.lua + +-- ** Frame 1 : General ** +L["Max rest XP displayed as 150%"] = true +L["Show FuBar icon"] = true +L["Show FuBar text"] = true +L["Account Sharing Enabled"] = true +L["Guild Communication Enabled"] = true + +L["|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users\nto send you account sharing requests.\n"] = true +L["Your confirmation will still be required any time someone requests your information.\n\n"] = true +L["When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected.\n\n"] = true +L["Security hint: Only enable this when you actually need to transfer data,\ndisable otherwise"] = true + +L["|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates\nto see your alts and their professions.\n\n"] = true +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = true + +L["Automatically authorize guild bank updates"] = true + +L["|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users\nto update their guild bank information with yours automatically.\n\n"] = true +L["When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be\nrequired before sending any information.\n\n"] = true +L["Security hint: disable this if you have officer rights\non guild bank tabs that may not be viewed by everyone,\nand authorize requests manually"] = true +L["Transparency"] = true + +-- ** Frame 2 : Search ** +L["AutoQuery server |cFFFF0000(disconnection risk)"] = true +L["|cFFFFFFFFIf an item not in the local item cache\nis encountered while searching loot tables,\nAltoholic will attempt to query the server for 5 new items.\n\n"] = true +L["This will gradually improve the consistency of the searches,\nas more items are available in the item cache.\n\n"] = true +L["There is a risk of disconnection if the queried item\nis a loot from a high level dungeon.\n\n"] = true +L["|cFF00FF00Disable|r to avoid this risk"] = true + + +L["Sort loots in descending order"] = true +L["Include items without level requirement"] = true +L["Include mailboxes"] = true +L["Include guild bank(s)"] = true +L["Include known recipes"] = true +L["Include guild members' professions"] = true + +-- ** Frame 3 : Mail ** +L["Warn when mail expires in less days than this value"] = true +L["Mail Expiry Warning"] = true +L["Scan mail body (marks it as read)"] = true +L["New mail notification"] = true +L["Be informed when a guildmate sends a mail to one of my alts.\n\nMail content is directly visible without having to reconnect the character"] = true + +-- ** Frame 4 : Minimap ** +L["Move to change the angle of the minimap icon"] = true +L["Minimap Icon Angle"] = true +L["Move to change the radius of the minimap icon"] = true +L["Minimap Icon Radius"] = true +L["Show Minimap Icon"] = true + +-- ** Frame 5 : Tooltip ** +L["Show item source"] = true +L["Show item count per character"] = true +L["Show total item count"] = true +L["Show guild bank count"] = true +L["Show already known/learnable by"] = true +L["Show recipes already known/learnable by"] = true +L["Show pets already known/learnable by"] = true +L["Show item ID and item level"] = true +L["Show counters on gathering nodes"] = true +L["Show counters for both factions"] = true +L["Show counters for all accounts"] = true +L["Include guild bank count in the total count"] = true +L["Detailed guild bank count"] = true + +-- ** Frame 6 : Calendar ** +L["Week starts on Monday"] = true +L["Warn %d minutes before an event starts"] = true +L["Disable warnings"] = true diff --git a/Altoholic-Addon/Altoholic/Locales/ruRU.lua b/Altoholic-Addon/Altoholic/Locales/ruRU.lua new file mode 100644 index 0000000..676b999 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/ruRU.lua @@ -0,0 +1,745 @@ +-- +-- Russian localization made by Hellbot & Interim @ EU Realms +-- Перевод выполнен Хэлла и Интерим @ Азурегос +-- + +local L = LibStub("AceLocale-3.0"):NewLocale( "Altoholic", "ruRU" ) + +if not L then return end + +L["28 Slot"] = "28 ячеек" +L["32 Keys Max"] = "32 ключа максимум" +L["Abyssal Council"] = "Совет Бездны" +L["Accessories"] = "Аксессуары" +L["Account"] = "Уч.запись" +L["Account Name"] = "Название уч.записи" +L["Account Sharing"] = "Деление уч.записи" +L["Account Sharing Enabled"] = "Включение совместного использования данных" +L["Account Sharing Request"] = "Запрос совместного использования данных" +L["Account sharing request received from %s"] = "Получение запрос от |3-1(%s),на совместное использование данных" +L["Account Summary"] = "Отчет" +L["Activity"] = "Активность" +L["Adamantite Battlegear"] = "Адамантитовая броня" +L["Adamantite Deposit"] = "Залежи адамантита" +L["Aged Dalaran Wizard"] = "Даларанский старый волшебник" +L["Aggem Thorncurse"] = "Аггем Терновое Проклятие" +L["AH"] = "АУК" +L["All accounts"] = "Все уч.записи" +L["All cooldowns are up"] = "Все восстановления готовы" +L["Alliance Forces"] = "Силы Альянса" +L["All-in-one"] = "объединить" +L["All realms"] = "Все миры" +L["Already known by "] = "Изучено: " +L["Altoholic:|r Usage = /altoholic search "] = "Altoholic:|r Используйте = /altoholic search <название предмета>" +L["Ancient Lichen"] = "Древний лишайник" +L["and above"] = "и выше" +L["Any"] = "Любое" +L["Anzu the Raven God (Heroic Summon)"] = "Анзу (Вызов на героическом уровне сложности)" +L["Apprentice"] = "Ученик" +L["Arcanoweave Vestments"] = "Одеяния из тайной ткани" +L["Are also on this quest:"] = "Этот квест также выполняют:" +L["Arena points: "] = "Очки арены: " +L["Arena Season %d"] = "Арена (сезон %d)" +L["Armbreaker Huffaz"] = "Руколом Хуффаз" +L["Armorsmith"] = "Бронник" +L["Arthas' Tears"] = "Слезы Артаса" +L["Artisan"] = "Искусник" +L["at"] = "на" +L["At least one recipe could not be read"] = "Как минимум один рецепт не прочитан" +L["Attendees: "] = "Участники: " +L["Auctions %s(%d)"] = "Аукционы %s(%d)" +L["Automatically authorize guild bank updates"] = "Разрешать автоматическое обновление банка гильдии" +L["AutoQuery server |cFFFF0000(disconnection risk)"] = "Запрашивать информацию о предмете у сервера |cFFFF0000(риск отключения от сервера)" +L["Avatar of the Martyred"] = "Аватара Мученика" +L["Average Item Level"] = true +L["Azure Templar (Water)"] = "Лазурный храмовник (Водный)" +L["Baelog's Chest"] = "Сундук Бейлога" +L["Bags"] = "Сумки" +L["Bag Usage"] = "Сумки" +L["Balance"] = "Баланс" +L["Balzaphon"] = "Балзафон" +L["Bank"] = "В банке" +L["Bank bag"] = "Сумки в банке" +L["Bank not visited yet"] = "Вы еще не посещали банк" +L["Barleybrew Brewery"] = "Ячменевый пивоваренный завод" +L["(based on iLvl)"] = "(основано на уровне предмета)" +L["Bash'ir Landing"] = "Лагерь Баш'ир" +L["Battlecast Garb"] = "Одеяния Боевого заклятья" +L["BC Collector Edition (Europe)"] = "Коллекционое издание WOW:TBC" +L["Beasts Deck"] = "Колода Зверей" +L["Beast Training"] = "Дрессировка" +L[ [=[Be informed when a guildmate sends a mail to one of my alts. + +Mail content is directly visible without having to reconnect the character]=] ] = [=[Будете информированы, когда приятель из гильдии отправляет письмо одному из ваших персонажей. + +Содержание почты видно без повторного захода персонажем]=] +L["Bids %s(%d)"] = "Ставки %s(%d)" +L["Black Dragon Mail"] = "Кольчуга Черного дракона" +L["Black Lotus"] = "Черный лотос" +L["Blacksmithing (Lv 60)"] = "Кузнечное дело (уровень 60)" +L["Blacksmithing (Lv 70)"] = "Кузнечное дело (уровень 70)" +L["Blacksmithing Mail Sets"] = "Кольчуга (Кузнечное дело)" +L["Blacksmithing Plate Sets"] = "Латы (Кузнечное дело)" +L["Blade Edge Mountains"] = "Острогорье" +L["Blessings Deck"] = "Колода Благословений" +L["Blindweed"] = "Слепырник" +L["Blizzard Collectables"] = true +L["Blizzcon 2005"] = true +L["Blizzcon 2007"] = true +L["Bloodsoul Embrace"] = "Объятия Кровавого Духа" +L["Bloodthistle"] = "Кровопийка" +L["Blood Tiger Harness"] = "Доспехи Кровавого тигра" +L["Bloodvine"] = "Кровавая лоза" +L["Bloodvine Garb"] = "Одеяния Кровавой Лозы" +L["Blue Dragon Mail"] = "Кольчуга Синего дракона" +L["Books"] = "Книги" +L["Booty Run"] = "Схватка за добычу на Арене Гурубаши" +L["Both factions"] = "Обе фракции" +L[ [=[Both parties must enable account sharing +before using this feature (see options)]=] ] = [=[Обе стороны должны включить совместного использования данных +Прежде чем использовать эту функцию (см. настройки)]=] +L["Box of Chocolates"] = "Коробка шоколадных конфет" +L["Brewfest"] = "Фестиваль пива" +L["Briarthorn"] = "Остротерн" +L["Brightly Colored Egg"] = "Ярко раскрашеное яйцо" +L["Bruiseweed"] = "Синячник" +L["Burning Rage"] = "Пламенная ярость" +L["Cache of the Legion"] = "Склад легиона" +L["Calendar"] = "Календарь" +L["Cannot delete current character"] = "Нельзя удалить текущего персонажа" +L["Cannot delete current realm"] = "Нельзя удалить текущий мир" +L["Cannot link another account's tradeskill"] = "Нельзя дать ссылку на ремесло другой уч.записи" +L["Cannot link another realm's tradeskill"] = "Нельзя дать ссылку на ремесло, с другого игрового мира" +L["Carefully Wrapped Present"] = "Тщательно упакованный подарок" +L["|cFF00FF00Disable|r to avoid this risk"] = "|cFF00FF00Не включайте|r если не хотите рисковать." +L[ [=[|cFFFFFFFFIf an item not in the local item cache +is encountered while searching loot tables, +Altoholic will attempt to query the server for 5 new items. + +]=] ] = [=[|cFFFFFFFFЕсли предмет не найден в локальном кэше клиента, но обнаружен во время поиска, +Altoholic попытается запросить информацию о предмете у сервера (не более 5 за раз). + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to send you account sharing requests. +]=] ] = [=[|cFFFFFFFFЕсли данная опция |cFF00FF00включена|cFFFFFFFF, это позволит другим +пользователям Altoholic отсылать вам запрос на совместное использование данных. +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to update their guild bank information with yours automatically. + +]=] ] = [=[|cFFFFFFFFЕсли данная опция |cFF00FF00включена|cFFFFFFFF, это позволит другим +пользователям Altoholic автоматически обновлять данные их гильдийского банка с вашим. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates +to see your alts and their professions. + +]=] ] = [=[|cFFFFFFFFЕсли данная опция |cFF00FF00включена|cFFFFFFFF, это позволит +вашим приятелям с гильдии видеть ваших персонажей и их профессии. + +]=] +L["Character"] = "Персонаж" +L["Characters"] = "Персонажи" +L["Character %s received !"] = "Получен персонаж: %s !" +L["Character %s successfully deleted"] = "Персонаж %s успешно удален" +L["Children's Week"] = "Детская неделя" +L["Christmas Gift 2006"] = "Рождественский подарок 2006" +L["Clamp window to screen"] = "Фиксировать окно на экране" +L["Class Books"] = "Классовые книги" +L["Classes: Death Knight"] = "Классы: Рыцарь смерти" +L["Classes: Hunter"] = "Классы: Охотник" +L["Classes: Mage"] = "Классы: Маг" +L["Classes: Paladin"] = "Классы: Паладин" +L["Classes: Priest"] = "Классы: Жрец" +L["Classes: Rogue"] = "Классы: Разбойник" +L["Classes: Shaman"] = "Классы: Шаман" +L["Classes: Warlock"] = "Классы: Чернокнижник" +L["Classes: Warrior"] = "Классы: Воин" +L["Class Skills"] = "Классовые навыки" +L["Clear all entries"] = "Стереть все записи" +L["Clear goblin AH entries"] = "Стереть записи нейтрального аукциона" +L["Clear your faction's entries"] = "Стереть записи аукциона вашей фракции" +L["Click a character's AiL to see its equipment"] = "Для просмотра снаряжения, кликните по AiL персонажа" +L[ [=[Clicking this button will update +your local %s%s|r bank tab +based on %s%s's|r data]=] ] = [=[Щелчек по кнопке обновит +ваш локальную закладку банка %s%s|r bank tab +основываясь на данные %s%s's|r]=] +L[ [=[Click this button to ask a player +to share his entire Altoholic Database +and add it to your own]=] ] = [=[Нажмите эту кнопку, чтобы спросить игрока, +не желает ли он поделиться всей своей +базой данных Altoholic'а и добавить ее в свою]=] +L["Cloaks"] = "Плащи" +L["Cloth Set"] = "Тряпичный комлект" +L["Conspicuous Urn"] = "Подозрительная урна" +L["Containers"] = "Сумки" +L["Copper Vein"] = "Медная Жила" +L["Could be learned by "] = "Может быть изучено: " +L["Crafted Weapons"] = "Оружие (Кузнечное дело)" +L["Crimson Templar (Fire)"] = "Багровый храмовник (Огненный)" +L["Currencies received !"] = "Получена валюта!" +L["Dark Iron Deposit"] = "Залежи Темной Стали" +L["Darkscreecher Akkarai"] = "Темный Крикун Аккарай" +L[" days"] = " дней назад" +L[" days ago"] = " дней" +L["Deadly Gladiator's Weapons"] = "Оружие смертоносного гладиатора" +L["Death Knight"] = "Рыцарь смерти" +L["Default"] = "По умолчению" +L["Delete Guild Bank?"] = "Удалить банк гильдии?" +L["Delete this Alt"] = "Удалить этого персонажа" +L["Delete this Realm"] = "Удалить этот мир" +L["Detailed guild bank count"] = "Детализованная ячейка банка гильдии" -- Needs review +L["Devilsaur Armor"] = "Доспехи из кожи девизавра" +L["Disable warnings"] = "Отключить предупреждения" +L["Display warnings in a dialog box"] = "Показывать предупреждения в диалоговых окошках" +L["Do you want to open Altoholic's calendar for details ?"] = "Вы хотите открыть календарь Altoholic'а для подробной информации?" +L["Do you want to view it now ?"] = "Вы хотите просмотреть теперь?" +L["DPS"] = "Боец" +L["Dragonscale"] = "Школа чешуи драконов" +L["Dreamfoil"] = "Снолист" +L["Dreaming Glory"] = "Соннославник" +L["Drohn's Distillery"] = "Винокурня Дрона" +L["Druid of the Fang (Trash Mob)"] = "Друид клыка" +L["Druid Set"] = "Комплект друида" +L["Earthen Templar (Earth)"] = "Земной храмовник (Земляной)" +L["Earthroot"] = "Землекорень" +L["Elemental"] = "Сила стихий" +L["Elemental Invasion"] = "Вторжение стихий" +L["Elementals Deck"] = "Колода Элементалей" +L["Elemental Shaman"] = "Укротитель стихий" +L["E-Mail"] = "Почта" +L["Emblems of Heroism"] = "Эмблем героизма" +L["Emblems of Valor"] = "Эмблемы доблести" +L["Enchanted Adamantite Armor"] = "Зачарованная адамантитовая броня" +L["Enchants"] = "Зачарования" +L["Engineering (Lv 60)"] = "Инженерное дело (уровень 60)" +L["Engineering (Lv 70)"] = "Инженерное дело (уровень 70)" +L[ [=[Enter an account name that will be +used for |cFF00FF00display|r purposes only.]=] ] = [=[Введите имя учетной записи, которое будет +использоваться только для |cFF00FF00отображения|r данных.]=] +L["Epic Rewards"] = "Эпические награды" +L["Equipment"] = "Экипировка" +L["Equipment Slot"] = "Ячейка снаряжения" +L["Equipped"] = "Надето" +L["Eric The Swift"] = "Эрик \"Быстрый\"" +L["Ethereum Prison"] = "Тюрьма братства Эфириум" +L["Expert"] = "Умелец" +L["Expiry:"] = "Истечение:" +L["Fadeleaf"] = "Бледнолист" +L["Faith in Felsteel"] = "Верность оскверненной стали" +L["Feast of Winter Veil"] = "Новый Год" +L["Fel Iron Chain"] = "Кольчуга из оскверненного железа" +L["Fel Iron Chest"] = "Сундук из оскверненного железа" +L["Fel Iron Deposit"] = "Месторождение оскверненного железа" +L["Fel Iron Plate"] = "Латы из оскверненного железа" +L["Fel Lotus"] = "Оскверненный лотос" +L["Felscale Armor"] = "Доспехи Чешуи Скверны" +L["Fel Skin"] = "Кожа Скверны" +L["Felstalker Armor"] = "Доспехи Темного следопыта" +L["Fel Steed"] = "Конь скверны" +L["Fel Tinkerer Zortan"] = "Ремонтник Скверны Зортан" +L["Felweed"] = "Скверноплевел" +L["Festive Gift"] = "Праздничный дар" +L["Find Upgrade"] = "Найти лучший " +L["Firebloom"] = "Огнецвет" +L["Fire Resistance Gear"] = "Экипировка с устойчивостью к огню" +L["Fireworks Pack"] = "Пачка фейерверков" +L["First Prize"] = "Первый приз" +L["Fishing"] = "Рыбная ловля" +L["Fishing Extravaganza"] = "Рыболовная феерия" +L["Fishing Poles"] = "Удочки" +L["Flame Cap"] = "Огнеголовик" +L["Flame Guard"] = "Пламенный Страж" +L["Food"] = "Еда" +L["Forgosh"] = "Форгош" +L["free"] = "пустых" +L["Furies Deck"] = "Колода Ярости" +L["Fury of the Nether"] = "Ярость Пустоты" +L["Gaily Wrapped Present"] = "Подарок в яркой упаковке" +L["Garrett Family Chest"] = "Сундук семейства Гарретт" +L["General"] = "Общее" +L["Gently Shaken Gift"] = "Слегка растрясенный дар" +L["Gezzarak the Huntress"] = "Геззарак Охотница" +L["Ghost Mushroom"] = "Призрачная поганка" +L["Gift of Adoration"] = "Дар дружбы" +L["Glowcap"] = "Огнешляпка" +L["Gnomish"] = "Гномский механик" +L["Goblin"] = "Гоблинский механик" +L["Goblin AH"] = "Нейтральный аукцион" +L["Golden Sansam"] = "Золотой сансам" +L["Goldthorn"] = "Златошип" +L["Gold Vein"] = "Золотая Жила" +L["Gordok Brewery"] = "Пивоваренный завод Гордока" +L["Grave Moss"] = "Могильный мох" +L["Green Dragon Mail"] = "Кольчуга Зеленого дракона" +L["Grey"] = "Серый" +L["Gromsblood"] = "Кровь Грома" +L["Guild Bank not visited yet (or not guilded)"] = "Вы еще не посетили банк гильдии (или не состоите в гильдии" +L["Guild Bank Remote Update"] = "Удаленное обновление банка гильдии" +L["Guild Bank Tabs"] = "Закладки банка гильдии" +L["Guild bank tab %s successfully updated !"] = "Закладка банка %s, обновлена!" +L["Guild Communication Enabled"] = "Обмен данных с гильдией включен" +L["Guild Members"] = "Участники гильдии" +L["Guild Skills"] = "Навыки гильдии" +L["Guilds received !"] = "Получена гильдия!" +L["Guild %s successfully deleted"] = "Гильдия %s удалена" +L["Gul'bor"] = "Гул'бор" +L["Gurubashi Arena"] = "Арена Гурубаши" +L["Hakkari Thorium Vein"] = "Ториевая жила Хаккари" +L["Halaa (Nagrand)"] = "Халаа (Награнд)" +L["Hallow's End"] = "Тыквовин" +L["Hard Mode"] = "Сложный режим" +L["Harvest Festival"] = "Фестиваль урожая" +L["(has auctions)"] = "(есть аукционы)" +L["(has bids)"] = "(есть ставки)" +L["has come online"] = "входит в игру" +L["has gone offline"] = "выходит из игры" +L["(has mail)"] = "(есть почта)" +L[" has no mail, last check "] = " не получает писем, уже " +L[" has not visited his/her mailbox yet"] = " еще не читал(а) свою почту " +L["Headless Horseman"] = "Всадник без головы " +L["Heal"] = "Лекарь" +L["Hellfire Fortifications"] = "Штурмовые укрепления" +L["Henry Stern"] = "Генри Штерн" +L["Herbalism"] = "Травничество" +L[" (Heroic)"] = " (Героическая сложность)" +L["Heroic Mode Tokens"] = "За Знаки справедливости" +L["hide"] = "скрыть" +L["Hides the UI"] = "Скрыть интерфейс" +L["Hide this guild in the tooltip"] = "Скрыть данную гильдию в подсказках" +L["Highlord Kruul"] = true +L["Hoary Templar (Wind)"] = "Седой храмовник (Воздушный)" +L["Honor points: "] = "Очки чести: " +L["Horde Forces"] = "Силы Орды" +L["Hunter Set"] = "Комплект охотника" +L["Icecap"] = "Льдяник" +L["Imbued Netherweave"] = "Прочная ткань Пустоты" +L["Imperial Plate"] = "Имперские латы" +L["Incendicite Mineral Vein"] = "Ароматитовая жила" +L["Include guild bank count in the total count"] = "Включая в общее количество, количество из банка гильдии" +L["Include guild bank(s)"] = "Включая содержимое банков гильдии" +L["Include guild members' professions"] = "Включать профессии членов гильдии" +L["Include items without level requirement"] = "Включая предметы без требований к уровню" +L["Include known recipes"] = "Включая изученные рецепты" +L["Include mailboxes"] = "Включая содержимое почтовых ящиков" +L["Increases attack power by %d+"] = "Увеличивает силу атаку на %d+" +L["Increases damage and healing done by magical spells and effects by up to %d+"] = "Увеличение урона и целительного действия магических заклинаний и эффектов не более чем на %d+" +L["Increases healing done by up to %d+"] = "Увлечение исцеляющих эффектов на %d+" +L["Indurium Mineral Vein"] = "Индарилиевая жила" +L["Inscription"] = "Начертание" +L["Invalid tradeskill link"] = "Неверная ссылка ремесла" +L["Iron Deposit"] = "Залежь Железа" +L["Ironfeather Armor"] = "Железноперые доспехи" +L[" is "] = " имеет репутацию " +L["Item Level"] = "Уровень предмета" +L["Item / Location"] = "Предметы / Нахождение" +L["Items"] = "Предметы" +L["Journeyman"] = "Подмастерье" +L["Karrog"] = "Каррог" +L["Khadgar's Whisker"] = "Кадгаров ус" +L["Khorium Vein"] = "Кориевая жила" +L["Khorium Ward"] = "Кориевая Опека" +L["Kingsblood"] = "Королевская кровь" +L["Krom Stoutarm Chest"] = "Сундук Крома Крепкорука" +L["Lady Falther'ess"] = "Леди Фалтер'есс" +L["Lake Wintergrasp"] = "Озеро Ледяных Оков" +L["Large Obsidian Chunk"] = "Большая обсидиановая глыба" +L["last check "] = "последняя проверка" +L["Last visit: %s by %s"] = "Последнее посещение: %s - %s" +L["Leather Set"] = "Кожаный комплект" +L["Leatherworking Leather Sets"] = "Кожаные доспехи (Кожевенное дело)" +L["Leatherworking Mail Sets"] = "Кольчуга (Кожевенное дело)" +L["Left-click to"] = "Левый щелчок для" +L["Left-click to |cFF00FF00open"] = "Щелкните левой кнопкой мыши чтобы |cFF00FF00открыть" +L["Left-click to invite attendees"] = "[Левый-клик] - пригласить участника" +L["Left-click to see this character's equipment"] = "[Левый-клик] - просмотр снаряжения персонажа" +L["Left click to view"] = "[Левый-клик] - просмотр" +L["Legendaries"] = "Легендарное" +L["Legendary Mount"] = "Легендарное ездовое животное" +L["Lesser Bloodstone Deposit"] = "Малое месторождение кровавого камня" +L["Level"] = "Уровень" +L["Level 30-39"] = "Уровень 30-39" +L["Level 40-49"] = "Уровень 40-49" +L["Level 50-60"] = "Уровень 50-60" +L["Level 70"] = "Уровень 70" +L["Level 70 Reputation PVP"] = "За репутацию (70 уровень)" +L["Level %d Honor PVP"] = "За очки доблести (%d уровень)" +L["Levels"] = "уровн(я,ей)" +L["Liferoot"] = "Жизнекорень" +L["Local Time: %s %sRealm Time: %s"] = "Местное время: %s %sСерверное время: %s" +L["Location"] = "Место" +L["Lockpicking"] = "Взлом замка" +L["Loot Card Items"] = true +L["Loots"] = "предметов" +L["Loot tables"] = "Списки добычи" +L["Lord Ahune"] = "Повелитель Ахун" +L["Lord Blackwood"] = "Лорд Блэквуд" +L["Love is in the air"] = "В воздухе витает любовь" +L["Lucky Red Envelope"] = "Красный конверт Счастья" +L["Lunacy Deck"] = " Колода Безумия" +L["Lunar Festival"] = "Лунный Фестиваль" +L["Lv %s Rewards"] = "Награды %s уровня" +L["Mageroyal"] = "Магороза" +L["Mage Set"] = "Комплект мага" +L["Magregan Deepshadow"] = "Магреган Чернотень" +L["Mail"] = "В почте" +L["Mail Expiry Warning"] = "Сообщать об истечении срока хранения почты" +L["Mail is about to expire on at least one character."] = "Срок хранения почты скоро истечет, по крайней мере у одного персонажа." +L["Mails"] = "Письма" +L["Mail Set"] = "Кольчужный комлпект" +L["Mails %s(%d)"] = "Письма %s(%d)" +L["Mail was last checked "] = "Последняя проверка почты " +L["Malevus the Mad"] = "Малевус Безумная" +L["Mana Thistle"] = "Манрепейник" +L["Master"] = "Мастер" +L["Master Axesmith"] = "Мастер школы топора" +L["Master Hammersmith"] = "Мастер школы Молота" +L["Master Swordsmith"] = "Мастер ковки клинков" +L["Maximum Level: %s"] = "Макс уровень: %s" +L["Max rest XP displayed as 150%"] = "Максимальную бодрость показывать как 150%" +L["Midsummer Fire Festival"] = "Огненный солнцеворот" +L["Minimap Icon Angle"] = "Расположение иконки на мини-карте" +L["Minimap Icon Radius"] = "Отступ иконки от мини-карты" +L["Minimum Level: %s"] = "Мин уровень: %s" +L["Mining"] = "Горное дело" +L["Miscellaneous"] = "Разное" +L["Mithril Deposit"] = "Митриловые залежи" +L["Mooncloth"] = "Шитье из луноткани" +L["Mountain Silversage"] = "Горный серебряный шалфей" +L["Move to change the angle of the minimap icon"] = "Изменяет местположение иконки относительно мини-карты" +L["Move to change the radius of the minimap icon"] = "Изменяет отступ иконки от мини-карты" +L["Muddy Churning Waters"] = "Грязный водоворот" +L["N/A"] = true +L["Netherbloom"] = "Пустоцвет" +L["Nethercite Deposit"] = "Месторождение хаотита" +L["Netherdust Bush"] = "Пыльник хаотический" +L["Netherscale Armor"] = "Доспехи из чешуи дракона Пустоты" +L["Netherstrike Armor"] = "Доспехи удара Пустоты" +L["Netherweave Vestments"] = "Одеяния из ткани Пустоты" +L["New mail notification"] = "Извещать о получении новой почты" +L["Nightmare Vine"] = "Лозный кошмарник" +L["Noblegarden"] = "Пасха" +L["No currencies found"] = "Валюты не найдено" +L["No data"] = "Нет данных" +L["No guild found"] = "Гильдия не найдена" +L["No match found!"] = "Нет совпадений" +L["Non Set Accessories"] = "Аксессуары (не из комплекта)" +L["Non Set Cloth"] = "Тряпичная броня (не из комплекта)" +L["Non Set Leather"] = "Кожаные доспехи (не из комплекта)" +L["Non Set Mail"] = "Кольчужные доспехи (не из комплекта)" +L["Non Set Plate"] = "Латы (не из комплекта)" +L["No quest found for "] = "Не найдено задание для " +L["No reputations found"] = "Репутации не найденно" +L["No rest XP"] = "Нет бодрости" +L[" not found!"] = " не найден!" +L["Not started"] = "Не начато" +L["Number of players: %s"] = "Число игроков: %s" +L["Offline Members"] = "Игроки вне сети" +L["Olaf"] = "Олаф" +L["Ooze Covered Gold Vein"] = "Покрытая слизью золотая жила" +L["Ooze Covered Mithril Deposit"] = "Покрытые слизью мифриловые залежи" +L["Ooze Covered Rich Thorium Vein"] = "Покрытая слизью богатая ториевая жила" +L["Ooze Covered Silver Vein"] = "Покрытая слизью серебряння жила" +L["Ooze Covered Thorium Vein"] = "Покрытая слизью ториевая жила" +L["Ooze Covered Truesilver Deposit"] = "Покрытые слизью залежи истинного серебра" +L["open/close"] = "открыть / закрыть" +L["Opera (Shared Drops)"] = "Опера (общий список добычи)" +L["Other"] = "Другое" +L["Outdoor Bosses"] = "Боссы на континентах" +L["Paladin Set"] = "Комплект паладина" +L["Patterns"] = "Рецепты" +L["Peacebloom"] = "Мироцвет" +L["Plaguebloom"] = "Чумоцвет" +L["Plans"] = "Планы" +L["Plate Set"] = "Латы" +L["Please open this window again"] = "Пожалуйста откройте это окно снова" +L["Poisons"] = "Яды" +L["Porfus the Gem Gorger"] = "Порфус Пожиратель Самоцветов" +L["Portals Deck"] = "Колода Порталов" +L["Priest Set"] = "Комплект жреца" +L["Primal Batskin"] = "Простая шкура нетопыря" +L["Primal Intent"] = "Изначальная цель" +L["Primal Mooncloth"] = "Изначальная луноткань" +L["Private to friends: %s"] = "Лично для друзей: %s" +L["Private to guild: %s"] = "Лично для гильдии: %s" +L["Prof. 1"] = "Проф. 1" +L["Prof. 2"] = "Проф. 2" +L["Professions"] = "Профессии" +L["Purple Lotus"] = "Лиловый лотос" +L["PVP Cloth Set"] = "Тряпичный ПвП комплект" +L["PVP Leather Sets"] = "Кожаный ПвП комплект" +L["PVP Mail Sets"] = "Кольчужный ПвП комплект" +L["PVP Plate Sets"] = "Латный ПвП комплект" +L["Pyron"] = "Подчинитель Пирон" +L["QuestID"] = "ID задания" +L["Quest Items"] = "Предмет задания" +L["Quest rewards"] = "Награда за выполнения задания" +L["Quests"] = "Задания" +L["Ragveil"] = "Кисейница" +L["Rajaxx's Captains"] = "Капитаны Раджакса" +L["Random Boss"] = "Случайный босс" +L["Rare Fish"] = "Редкая рыба" +L["Rare Fish Rewards"] = "Награда за редкую рыбу" +L["Razorfen Spearhide"] = "Копьешкур из племени Иглошкурых" +L["Realm"] = "Игровой мир" +L["Realm %s successfully deleted"] = "Мир %s, успешно удален" +L["Reference data not available"] = "Справочные данные не доступны" +L["Reference data received (%s) !"] = "Получение справочных данных: (%s)!" +L["Refer to the activity pane for more details."] = "Обратитесь к панели активности, для более подробной информации." +L["Relics"] = "Реликвии" +L["Reputations"] = "Репутация" +L["Reputations received !"] = "Получена репутация!" +L["Requesting item %d of %d"] = "Запрос предмета %d - %d" +L["Requesting %s information from %s"] = "Запрос информации %s от |3-1(%s)" +L["Request rejected by %s"] = "Запрос отклонен |3-4(%s)" +L["Reset"] = "Сброс" +L["Resistance"] = "Устойчивость" +L["Rested"] = "Отдыха" +L["Restores %d+ mana per"] = "Восполнение %d+ маны раз в" +L["Rest XP"] = "Опыт за отдых" +L[" results found (Showing "] = " предметов найдено (Отображено " +L["Rethilgore"] = "Ретилгор" +L["Revanchion"] = "Реваншион" +L["Rich Adamantite Deposit"] = "Богатые залежи адамантита" +L["Rich Thorium Vein"] = "Богатая ториевая жила" +L["Riding"] = "Верховая езда" +L["Right-Click for options"] = "[Правый-щелчок] - настройки" +L["Right-click to |cFF00FF00drag"] = "Щелкните правой кнопкой мыши чтобы |cFF00FF00перетащить" +L["Right-Click to find an upgrade"] = "Правый щелчок для поиска улучшений" +L["Rogue Proficiencies"] = "Специализация разбойника" +L["Rogue Set"] = "Комплект разбойника" +L["Roogug"] = "Ругуг" +L["Sanguine Hibiscus"] = "Кровавый гибискус" +L["Savage Gladiator's Weapons"] = "Оружие свирепого гладиатора" +L["Scaled Draenic Armor"] = "Чешуйчатые дренейские доспехи" +L[" scan failed for "] = " сканирование не удалось для " +L["Scan mail body (marks it as read)"] = "Просматривать почту (отмечает как прочитаную)" +L["Scorn"] = "Отвергнутый" +L["Scourge Invasion"] = "Вторжение Плети" +L["search"] = "поиск" +L["Search Containers"] = "Поиск по сумкам" +L["Search in bags"] = "Искать в сумках" +L["Secondary Skills"] = "Разное" +L[ [=[Security hint: disable this if you have officer rights +on guild bank tabs that may not be viewed by everyone, +and authorize requests manually]=] ] = [=[Совет безопасности: отключите это если вы обладаете правами человека +который может просмотреть недоступные каждому закладки банка гильдии, +и принимайте запросы вручную]=] +L[ [=[Security hint: Only enable this when you actually need to transfer data, +disable otherwise]=] ] = [=[Совет безопасности: Включайте только при крайнем необходимости, +когда действительно это нужно для передачи данных. +Во всём остальном, отключайте]=] +L["Send account sharing request to:"] = "Отослать запрос совместного использования данных к:" +L["Sending account sharing request to %s"] = "Отсылка запроса |3-2(%s), о совместном использовании данных уч.записи" +L["Sending character %s (%d of %d)"] = "Отсылка данных персонажа %s (%d - %d)" +L["Sending currencies (%d of %d)"] = "Отсылка данных о валюте (%d - %d)" +L["Sending guilds (%d of %d)"] = "Отсылка данных о гильдии (%d - %d)" +L["Sending reference data: %s (%d of %d)"] = "Отсылка справочных данных: %s (%d - %d)" +L["Sending reputations (%d of %d)"] = "Отсылка данных о репутации (%d - %d)" +L["Sending table of content (%d items)"] = "Отсылка содержания (%d предметов)" +L["Sever"] = "Покалеченный" +L["Shadoweave"] = "Шитье из тенеткани" +L["Shadowforge Cache"] = "Тайник Кузни Теней" +L["Shadow's Embrace"] = "Объятия Тени" +L["Shaman Set"] = "Комплект шамана" +L["Shared"] = "Общее" +L["Shartuul"] = "Шартуул" +L["%s has disabled account sharing"] = "%s отключил совместное использование данных уч.записи" +L["%s has disabled guild communication"] = "%s отключил обмен данных с гильдией" +L["%s has no auctions"] = "%s нет аукционов" +L["%s has no bids"] = "%s нет ставок" +L["%s has no mail"] = "%s не получает писем" +L["Shen'dralar Provisioner"] = "Шен'дралар (в ДМ !)" +L["Shift-Click to link this info"] = "[Shift+Клик] вывод ссылки с этой информацией" +L["Shift+Left click to link"] = "[Shift+Левый клик] - вывод ссылки" +L["show"] = "показывать" +L["Show already known/learnable by"] = "Включая изученные / доступные для изучения рецепты" +L["Show counters for all accounts"] = "Показ количества всех уч.записей" +L["Show counters for both factions"] = "Показ количества обоих фракций" +L["Show counters on gathering nodes"] = "Показ количества на точках сбора" +L["Show FuBar icon"] = "Отображать иконку FuBar" +L["Show FuBar text"] = "Отображать текст FuBar" +L["Show guild bank count"] = "Включая количество предметов в банке гильдии" +L["Show item count per character"] = "Количество предметов у каждого персонажа" +L["Show item ID and item level"] = "Показывать ID и уровень предмета" +L["Show item source"] = "Источник происхождения предмета" +L["Show Minimap Icon"] = "Показывать иконку на мини-карте" +L["Show pets already known/learnable by"] = "Показать питомцев, которые уже знакомы" +L["Show recipes already known/learnable by"] = "Показать рецепты, которые уже известны" +L["Shows the UI"] = "Показать интерфейс" +L["Show total item count"] = "Показывать общее количество предметов" +L["Silverleaf"] = "Сребролист" +L["Silver Vein"] = "Серебрянная Жила" +L["%s is in combat, request cancelled"] = "%s в бою, запрос отменён" +L["%s is now ready (%s on %s)"] = "%s уже готово (%s - %s)" +L["%s is now unlocked (%s on %s)"] = "%s уже открыто (%s on %s)" +L["%s is %s with %s (%d/%d)"] = "У |3-1(%s) %s репутация с фракцией %s (%d/%d)" +L["Skettis"] = "Скеттис" +L["Skinning"] = "Cнятие шкур" +L["Skyguard Raid"] = "Отряд стражей небес" +L["slots"] = "ячеек" +L["Small Obsidian Chunk"] = "Маленький кусочек обсидиана" +L["Small Thorium Vein"] = "Малая ториевая жила" +L["Smokywood Pastures Extra-Special Gift"] = "Эксклюзивный дар Пастбищ Дымного Леса" +L["Smokywood Pastures Vendor"] = "Торговец Пастбищ Дымного Леса" +L["Socket"] = "Гнездо" +L["Sort loots in descending order"] = "Сортировать предметы в порядке убывания" +L["Sothos & Jarien"] = "Сотос и Джариен" +L["Soulcloth Embrace"] = "Объятия ткани Душ" +L["Source"] = "Источник" +L["Spawn Of Hakkar"] = "Порождение Хаккара" +L["Spellfire"] = "Шитье из чароткани" +L["Spellstrike Infusion"] = "Разящее колдовство" +L["Spirit Towers (Terrokar)"] = "Башня Духов (Лес Террокар)" +L["%s|r has received a mail from %s"] = true +L[ [=[%s%s|r has requested the bank tab %s%s|r +Send this information ?]=] ] = [=[%s%s|r запросил информацию по закладкам банка %s%s|r +Отослать информацию ?]=] +L["%s starts in %d minutes (%s on %s)"] = "%s начнётся через %d минут (%s - %s)" +L["Started"] = "Начато" +L["Stasis Chambers"] = "Палаты стазиса" +L["Steamwheedle Cartel"] = "Картель Хитрая Шестеренка" +L["Storms Deck"] = "Колода Бурь" +L["Stormshroud Armor"] = "Доспехи Грозового покрова" +L["Stranglekelp"] = "Удавник" +L["Strength of the Clefthoof"] = "Сила копытня" +L["Suggested leveling zone: "] = "Рекомендуемая зона: " +L["Suggestion"] = "Рекомендации" +L["Summary"] = "Сводная информация" +L["Summoner's Tomb"] = true +L["Sungrass"] = "Солнечник" +L["Superior Rewards"] = "Наилучшие награды" +L[ [=[%sWarning:|r if you accept, %sALL|r information known +by Altoholic will be sent to %s%s|r (bags, money, etc..)]=] ] = [=[%sВнимание:|r Если вы согласитесь то, %sВСЯ|r известная информация +Altoholic'ом будет отослана к %s%s|r (сумки, валюта, и т.д..)]=] +L["%sWarning:|r make sure this user may view this information before accepting"] = "%sВнимание:|r Прежде чем принять, убедитесь, может ли этот пользователь просматривать эту информацию, т.е. доверяете ли вы ему" +L["Swiftthistle"] = "Быстрорепей" +L["%s will be ready in %d minutes (%s on %s)"] = "%s будет готово через %d минут (%s - %s)" +L["%s will be unlocked in %d minutes (%s on %s)"] = "%s будет разблокировано через %d минут(ы)" +L["Table of content received (%d items)"] = "Получение содержимого (%d предметов)" +L["Tablet of Ryuneh"] = "Табличка Рьюн'эха" +L["Tablet of Will"] = "Табличка Воли" +L["Tailoring Sets"] = "Тряпичная броня (Портняжное дело)" +L["Tank"] = "Танк" +L["T'chali's Voodoo Brewery"] = "Пивоваренный завод Тчали Вуду" +L["Terocone"] = "Терошишка" +L["Terokk"] = "Терокк" +L["The Darksoul"] = "Темная душа" +L["The Duke of Cinders (Fire)"] = "Герцог Пепла (Огненный)" +L["The Duke of Fathoms (Water)"] = "Герцог Глубин (Водный)" +L["The Duke of Shards (Earth)"] = "Герцог Осколков (Земляной)" +L["The Duke of Zephyrs (Wind)"] = "Герцог Ветров (Воздушный)" +L["Theldren"] = "Телдрен" +L[ [=[There is a risk of disconnection if the queried item +is a loot from a high level dungeon. + +]=] ] = [=[предмет является добычей из инстанса слишком высогого уровня, недоступного этому серверу. + +]=] +L["The Unyielding"] = "Непреклонность" +L["The Vault"] = "Хранилище" +L["Thick Draenic Armor"] = "Утолщенные дренейские доспехи" +L["This account"] = "Этот Аккаунт" +L["This character"] = "Этот персонаж" +L["This faction"] = "Эта фракция" +L["This field |cFF00FF00cannot|r be left empty."] = "Это поле |cFF00FF00не может|r быть оставлено пустым." +L[ [=[This name can be anything you like, +it does |cFF00FF00NOT|r have to be the real account name.]=] ] = [=[Имя может быть любым, какое угодно вам, +оно |cFF00FF00НЕ|r обязательно должно быть реальной уч.записью.]=] +L["This realm"] = "Этот мир" +L[ [=[This will gradually improve the consistency of the searches, +as more items are available in the item cache. + +]=] ] = [=[Это значительно улучшает эффективность работы, поскольку больше количество предметов +будет включено в кэш клиента. Однако существует риск отключения от сервера, если запрощеный +]=] +L["Thomas Yance"] = "Томас Янс" +L["Thunderbrew Brewery"] = "Пивоваренный завод Громоварского" +L["Ticking Present"] = "Тикающий подарочек" +L["Tier 0.5 Quests"] = "Комплект ранга 0.5" +L["Tier %d Tokens"] = "Талисманы комплекта ранга %d" +L["Timed Chest"] = "Сундук за поход на время" +L["Tin Vein"] = "Оловянная Жила" +L["toggle"] = "переключить" +L["Toggles the UI"] = "Показать / скрыть интерфейс" +L["Token Hand-Ins"] = "Предметы для повышения репутации" +L["Tooltip"] = "Подсказка" +L["Total owned"] = "Общее количество" +L["Totals"] = "Всего" +L["Transfer complete"] = "Передача завершена" +L["Transmute"] = "Трансмутация" +L["Transparency"] = "Прозрачность" +L["Trash Mobs"] = "Существа" +L["Treat Bag"] = "Сумка с лакомствами" +L["Tribal"] = "Традиции предков" +L["Tribute Run"] = "Трибьют ран" +L["Trinkets"] = "Аксессуары" +L["Troll Mini bosses"] = "Тролли мини-боссы" +L["Truesilver Deposit"] = "Залежи истинного серебра" +L["Twin Spire Ruins"] = "Руины Двух Шпилей" +L["Unknown"] = "неизвестно" +L["Unknown link, please relog this character"] = "Неизвестная ссылка, пожалуйста перезайдите этим персонажем" +L["Upper Deck"] = true +L["up to"] = "до" +L["Vakkiz the Windrager"] = "Ваккиз Ветрояр" +L["Various Locations"] = "В различных зонах" +L["View"] = "Просмотр" +L["View auctions"] = "Показать аукционы" +L["View bags"] = "Показать сумки" +L["View bids"] = "Показать ставки" +L["View mailbox"] = "Показать почту" +L["View quest log"] = "Показать журнал заданий" +L["Visited"] = "Визит" +L["Volcanic Armor"] = "Вулканические доспехи" +L["Waiting for %s to accept .."] = "Ожидание принятия %s .." +L["Warlock Set"] = "Комплект чернокнижника" +L["Warlords Deck"] = "Колода Полководцев" +L["Warn %d minutes before an event starts"] = "Извещать за %d минут до начала мероприятия" +L["Warn when mail expires in less days than this value"] = "Извещать о истечении срока хранения почты. Указанное значение измеряется в днях." +L["Warrior Set"] = "Комплект воина" +L["Weapons"] = "Оружие" +L["Weaponsmith"] = "Оружейник" +L["Week starts on Monday"] = "Начало недели с понедельника" +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected. + +]=] ] = [=[Если |cFFFF0000отключено|cFFFFFFFF, все запросы будут автоматически отвергаться. + +]=] +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = "Если |cFFFF0000отключено|cFFFFFFFF, обмен данных с гильдией не будет производиться." +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be +required before sending any information. + +]=] ] = [=[Если |cFFFF0000отключено|cFFFFFFFF, перед отправкой любой информации +необходимо будет ваше подтверждение. + +]=] +L["Whitemend Wisdom"] = "Мудрость Белого целителя" +L["Wild Draenish Armor"] = "Доспехи дренейского дикаря" +L["Wild Steelbloom"] = "Дикий сталецвет" +L["Wildvine"] = "Дикий виноград" +L["Will be learnable by "] = "Будет изучено: " +L["Will be %sdeleted|r in"] = "%s будет удалён через" +L["Will be %sreturned|r in"] = "%s будет возвращён через" -- Needs review +L["Windhawk Armor"] = "Доспехи Ветроястреба" +L["Wintersbite"] = "Зимник" +L["Winter Veil Gift"] = "Подарок на Зимний покров" +L[" with "] = " с " +L["World Drops"] = "С кого угодно" +L["World PVP"] = "Мировое ПвП" +L["WoW Collector Edition"] = "Коллекционое издание WoW" +L["Wrathbringer Laz-tarash"] = "Вестник Зла Лаз-тараш" +L["Wrath of Spellfire"] = "Гнев Чародейского огня" +L["Yor (Heroic Summon)"] = "Йор (Вызов на героическом уровне сложности)" +L[ [=[You have received an account sharing request +from %s%s|r, accept it?]=] ] = [=[Вы получили запрос о совместном использование данных уч.записи +от %s%s|r, принять?]=] +L[ [=[Your confirmation will still be required any time someone requests your information. + +]=] ] = [=[Ваше подтверждение все равно будет необходимо в любое время при запросе информации. + +]=] +L["Zelemar the Wrathful"] = "Зелемар Гневный" +L["Zone"] = "Зона" + diff --git a/Altoholic-Addon/Altoholic/Locales/zhCN.lua b/Altoholic-Addon/Altoholic/Locales/zhCN.lua new file mode 100644 index 0000000..6c51e20 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/zhCN.lua @@ -0,0 +1,734 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "Altoholic", "zhCN" ) + +if not L then return end + +L["28 Slot"] = "28格" +L["32 Keys Max"] = "最大32格" +L["Abyssal Council"] = "深渊议会" +L["Accessories"] = "配件" +L["Account"] = "账号" +L["Account Name"] = "账户名称" +L["Account Sharing"] = "账户共享" +L["Account Sharing Enabled"] = "启用账号共享" +L["Account Sharing Request"] = "账户共享请求" +L["Account sharing request received from %s"] = "收到%s的帐户共享请求" +L["Account Summary"] = "账号统计" +L["Activity"] = "活跃度" +L["Adamantite Battlegear"] = "精金战甲" +L["Adamantite Deposit"] = "精金矿脉" +L["Aged Dalaran Wizard"] = "老迈的达拉然巫师" +L["Aggem Thorncurse"] = "阿格姆" +L["AH"] = "拍卖行" +L["All accounts"] = "所有账户" +L["All cooldowns are up"] = "所有冷却已完成" +L["Alliance Forces"] = "联盟部队" +L["All-in-one"] = "整合" +L["All realms"] = "搜索所有服务器" +L["Already known by "] = "已学会:" +L["Altoholic:|r Usage = /altoholic search "] = "Altoholic:|r 用法 = /altoholic search <物品名字>" +L["Ancient Lichen"] = "远古苔" +L["and above"] = "及以上" +L["Any"] = "所有" +L["Anzu the Raven God (Heroic Summon)"] = "安苏,乌鸦之王(英雄模式召唤)" +L["Apprentice"] = "初级" +L["Arcanoweave Vestments"] = "奥法交织套装" +L["Are also on this quest:"] = "有相同任务: " +L["Arena points: "] = "竞技场点数: " +L["Arena Season %d"] = "竞技场第 %d 季" +L["Armbreaker Huffaz"] = "断臂者霍法斯" +L["Armorsmith"] = "防具锻造" +L["Arthas' Tears"] = "阿尔萨斯之泪" +L["Artisan"] = "专家级" +L["at"] = "在" +L["At least one recipe could not be read"] = "最少有一个配方未能读取" +L["Attendees: "] = "参与者: " +L["Auctions %s(%d)"] = "拍卖行 %s(%d)" +L["Automatically authorize guild bank updates"] = "自动授权公会仓库更新" +L["AutoQuery server |cFFFF0000(disconnection risk)"] = "自动向服务器查询|cFFFF0000(可能会掉线!)" +L["Avatar of the Martyred"] = "殉难者的化身" +L["Average Item Level"] = "平均物品等级" +L["Azure Templar (Water)"] = "碧蓝圣殿骑士(水)" +L["Baelog's Chest"] = "巴尔洛戈的箱子" +L["Bags"] = "背包" +L["Bag Usage"] = "背包用量" +L["Balance"] = "平衡" +L["Balzaphon"] = "巴尔萨冯" +L["Bank"] = "银行" +L["Bank bag"] = "银行背包" +L["Bank not visited yet"] = "尚未访问银行" +L["Barleybrew Brewery"] = "美酒节日酒桶" +L["(based on iLvl)"] = "(基于物品等级)" +L["Bash'ir Landing"] = "巴什伊尔码头" +L["Battlecast Garb"] = "战斗施法套装" +L["BC Collector Edition (Europe)"] = "燃烧的远征收藏版(欧洲版)" +L["Beasts Deck"] = "野兽套牌" +L["Beast Training"] = "野兽训练" +L[ [=[Be informed when a guildmate sends a mail to one of my alts. + +Mail content is directly visible without having to reconnect the character]=] ] = [=[通知我如果有工会成员发送邮件给小号. + +邮件内容直接可视而不必联系该角色]=] +L["Bids %s(%d)"] = "一口价 %s(%d)" +L["Black Dragon Mail"] = "黑龙锁甲" +L["Black Lotus"] = "黑莲花" +L["Blacksmithing (Lv 60)"] = "锻造(60级)" +L["Blacksmithing (Lv 70)"] = "锻造(70级)" +L["Blacksmithing Mail Sets"] = "锻造链甲套装" +L["Blacksmithing Plate Sets"] = "锻造板甲套装" +L["Blade Edge Mountains"] = "刀锋山" +L["Blessings Deck"] = "祝福套牌" +L["Blindweed"] = "盲目草" +L["Blizzard Collectables"] = "暴雪收藏品" +L["Blizzcon 2005"] = "暴雪嘉年华2005" +L["Blizzcon 2007"] = "暴雪嘉年华2007" +L["Bloodsoul Embrace"] = "血魂的拥抱" +L["Bloodthistle"] = "血蓟" +L["Blood Tiger Harness"] = "血虎" +L["Bloodvine"] = "血藤" +L["Bloodvine Garb"] = "血藤" +L["Blue Dragon Mail"] = "蓝龙锁甲" +L["Books"] = "书籍" +L["Booty Run"] = "宝箱争夺战" +L["Both factions"] = "双方阵营" +L[ [=[Both parties must enable account sharing +before using this feature (see options)]=] ] = [=[双方都必须启用账户共享 +来使用此功能 (参考选项)]=] +L["Box of Chocolates"] = "一盒巧克力" +L["Brewfest"] = "美酒节" +L["Briarthorn"] = "石南草" +L["Brightly Colored Egg"] = "明亮的彩蛋" +L["Bruiseweed"] = "跌打草" +L["Burning Rage"] = "钢铁之怒" +L["Cache of the Legion"] = "军团储藏室" +L["Calendar"] = "日历" +L["Cannot delete current character"] = "无法删除当前人物镜像" +L["Cannot delete current realm"] = "无法删除当前服务器内容" +L["Cannot link another account's tradeskill"] = "不能使用其它帐户的专业技能连结" +L["Cannot link another realm's tradeskill"] = "不能使用其它服务器的专业技能连结" +L["Carefully Wrapped Present"] = "精心包裹的礼物" +L["|cFF00FF00Disable|r to avoid this risk"] = "|cFF00FF00禁用|r以防止发生这类现象。" +L[ [=[|cFFFFFFFFIf an item not in the local item cache +is encountered while searching loot tables, +Altoholic will attempt to query the server for 5 new items. + +]=] ] = [=[|cFFFFFFFF如果一个不在本地缓存中物品 +被在搜索物品时被搜索到, +Altoholic将会尝试以5个每次的频率向服务器查询。 + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to send you account sharing requests. +]=] ] = [=[|cFFFFFFFF当 |cFF00FF00启用|cFFFFFFFF时, 这选项允许其他Altoholic用户 +向你发送帐户共享请求. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to update their guild bank information with yours automatically. + +]=] ] = [=[|cFFFFFFFF当 |cFF00FF00启用|cFFFFFFFF时, 此选项将允许其他Altoholic用户 +与你的公会仓库资料作自动更新. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates +to see your alts and their professions. + +]=] ] = [=[|cFFFFFFFF当 |cFF00FF00启用|cFFFFFFFF时, 这选项会让你公会的公会成员 +看见你的小号和其专业技能. + +]=] +L["Character"] = "人物" +L["Characters"] = "人物" +L["Character %s received !"] = "角色%s已接收!" +L["Character %s successfully deleted"] = "人物: %s 成功删除!" +L["Children's Week"] = "儿童周" +L["Christmas Gift 2006"] = "圣诞礼物2006" +L["Class Books"] = "职业书籍" +L["Classes: Death Knight"] = "职业:死亡骑士" +L["Classes: Hunter"] = "职业:猎人" +L["Classes: Mage"] = "职业:法师" +L["Classes: Paladin"] = "职业:圣骑士" +L["Classes: Priest"] = "职业:牧师" +L["Classes: Rogue"] = "职业:潜行者" +L["Classes: Shaman"] = "职业:萨满祭司" +L["Classes: Warlock"] = "职业:术士" +L["Classes: Warrior"] = "职业:战士" +L["Class Skills"] = "职业技能" +L["Clear all entries"] = "清理所有拍卖行的相关信息" +L["Clear goblin AH entries"] = "清理地精拍卖行的相关信息" +L["Clear your faction's entries"] = "清理你阵营的拍卖行的相关信息" +L["Click a character's AiL to see its equipment"] = "点击角色的 AiL 来查看他的装备" +L[ [=[Clicking this button will update +your local %s%s|r bank tab +based on %s%s's|r data]=] ] = [=[点击此按钮将更新 +你本服的%s%s|r 公会仓库分页 +基于 %s%s's|r 的资料]=] +L[ [=[Click this button to ask a player +to share his entire Altoholic Database +and add it to your own]=] ] = [=[点击此按钮来询问玩家 +是否共享整个Altoholic数据库 +并将其添加到自己的数据库]=] +L["Cloaks"] = "披风" +L["Cloth Set"] = "布甲套装" +L["Conspicuous Urn"] = "明显的墓碑" +L["Containers"] = "容器" +L["Copper Vein"] = "铜矿" +L["Could be learned by "] = "可学习:" +L["Crafted Weapons"] = "制作的武器" +L["Crimson Templar (Fire)"] = "赤红圣殿骑士(火)" +L["Currencies received !"] = "收到金钱资料!" +L["Dark Iron Deposit"] = "黑铁矿脉" +L["Darkscreecher Akkarai"] = "黑暗尖啸者阿克卡莱" +L[" days"] = " 天" +L[" days ago"] = " 天前" +L["Deadly Gladiator's Weapons"] = "致命角斗士的武器" +L["Death Knight"] = "死亡骑士" +L["Default"] = "默认" +L["Delete Guild Bank?"] = "删除公会仓库吗?" +L["Delete this Alt"] = "删除该人物镜像" +L["Delete this Realm"] = "删除此服务器内容" +L["Devilsaur Armor"] = "魔暴龙护甲" +L["Disable warnings"] = "禁用警告" +L["Display warnings in a dialog box"] = "在对话框中显示警告" +L["Do you want to open Altoholic's calendar for details ?"] = "你想开启Altoholic日历来了解详情吗?" +L["Do you want to view it now ?"] = "现在想查看吗?" +L["DPS"] = "伤害输出" +L["Dragonscale"] = "龙鳞" +L["Dreamfoil"] = "梦叶草" +L["Dreaming Glory"] = "梦露花" +L["Drohn's Distillery"] = "德罗恩的节日佳酿酒桶" +L["Druid of the Fang (Trash Mob)"] = "尖牙德鲁伊(小怪)" +L["Druid Set"] = "德鲁伊套装" +L["Earthen Templar (Earth)"] = "土色圣殿骑士(地)" +L["Earthroot"] = "地根草" +L["Elemental"] = "元素" +L["Elemental Invasion"] = "元素入侵" +L["Elementals Deck"] = "元素套牌" +L["Elemental Shaman"] = "元素" +L["E-Mail"] = "邮件" +L["Emblems of Heroism"] = "英雄纹章" +L["Emblems of Valor"] = "勇气纹章" +L["Enchanted Adamantite Armor"] = "魔化精金套装" +L["Enchants"] = "附魔" +L["Engineering (Lv 60)"] = "工程学(60级)" +L["Engineering (Lv 70)"] = "工程学(70级)" +L[ [=[Enter an account name that will be +used for |cFF00FF00display|r purposes only.]=] ] = [=[输入一个账户名称 +仅用作 |cFF00FF00显示|r .]=] +L["Epic Rewards"] = "史诗奖励" +L["Equipment"] = "装备" +L["Equipment Slot"] = "装备位置" +L["Equipped"] = "已装备" +L["Eric The Swift"] = "埃瑞克" +L["Ethereum Prison"] = "复仇军监牢" +L["Expert"] = "高级" +L["Expiry:"] = "到期:" +L["Fadeleaf"] = "枯叶草" +L["Faith in Felsteel"] = "魔钢的信仰" +L["Feast of Winter Veil"] = "冬幕节" +L["Fel Iron Chain"] = "魔铁链甲" +L["Fel Iron Chest"] = "魔铁宝箱" +L["Fel Iron Deposit"] = "魔铁矿脉" +L["Fel Iron Plate"] = "魔铁板甲" +L["Fel Lotus"] = "魔莲花" +L["Felscale Armor"] = "魔鳞套装" +L["Fel Skin"] = "魔能之肤" +L["Felstalker Armor"] = "魔能猎手" +L["Fel Steed"] = "地狱战马" +L["Fel Tinkerer Zortan"] = "魔能工匠索尔坦" +L["Felweed"] = "魔草" +L["Festive Gift"] = "节日礼物" +L["Find Upgrade"] = "发现更高级" +L["Firebloom"] = "火焰花" +L["Fire Resistance Gear"] = "火抗套装" +L["Fireworks Pack"] = "春节烟花包" +L["First Prize"] = "第一名奖励" +L["Fishing"] = "钓鱼" +L["Fishing Extravaganza"] = "荆棘谷钓鱼大赛" +L["Fishing Poles"] = "鱼竿" +L["Flame Cap"] = "烈焰菇" +L["Flame Guard"] = "烈焰卫士" +L["Food"] = "食物" +L["Forgosh"] = "弗尔高什" +L["free"] = "空余" +L["Furies Deck"] = "报复套牌" +L["Fury of the Nether"] = "虚空之怒" +L["Gaily Wrapped Present"] = "微微震动的礼物" +L["Garrett Family Chest"] = "加瑞特家族的箱子" +L["General"] = "一般" +L["Gently Shaken Gift"] = "精美的礼品" +L["Gezzarak the Huntress"] = "猎手吉萨拉克" +L["Ghost Mushroom"] = "幽灵菇" +L["Gift of Adoration"] = "爱慕的礼物" +L["Glowcap"] = "亮顶蘑菇" +L["Gnomish"] = "侏儒" +L["Goblin"] = "地精" +L["Goblin AH"] = "地精拍卖行" +L["Golden Sansam"] = "黄金参" +L["Goldthorn"] = "金棘草" +L["Gold Vein"] = "金矿石" +L["Gordok Brewery"] = "戈多克节日酒桶" +L["Grave Moss"] = "墓地苔" +L["Green Dragon Mail"] = "绿龙锁甲" +L["Grey"] = "灰色" +L["Gromsblood"] = "格罗姆之血" +L["Guild Bank not visited yet (or not guilded)"] = "公会银行未访问(或你没加入任何公会)" +L["Guild Bank Remote Update"] = "公会仓库远程更新" +L["Guild Bank Tabs"] = "公会银行标签" +L["Guild bank tab %s successfully updated !"] = "%s公会仓库分页已更新成功!" +L["Guild Communication Enabled"] = "启用工会交流" +L["Guild Members"] = "公会成员" +L["Guild Skills"] = "公会技能" +L["Guilds received !"] = "收到公会资料!" +L["Guild %s successfully deleted"] = "公会仓库 %s 删除成功" +L["Gul'bor"] = "古尔博" +L["Gurubashi Arena"] = "古拉巴什竞技场" +L["Hakkari Thorium Vein"] = "哈卡莱瑟银矿脉" +L["Halaa (Nagrand)"] = "哈兰(纳格兰)" +L["Hallow's End"] = "万圣节" +L["Hard Mode"] = "困难模式" +L["Harvest Festival"] = "收获节" +L["(has auctions)"] = "(有新的拍卖行通知)" +L["(has bids)"] = "(有新的一口价货物)" +L["has come online"] = "上线了。" +L["has gone offline"] = "下线了。" +L["(has mail)"] = "(有新的邮件)" +L[" has no mail, last check "] = " 无邮件,上次访问于 " +L[" has not visited his/her mailbox yet"] = " 尚未访问其邮箱" +L["Headless Horseman"] = "无头骑士" +L["Heal"] = "治疗" +L["Hellfire Fortifications"] = "地狱火半岛的工事" +L["Henry Stern"] = "亨利·斯特恩" +L["Herbalism"] = "草药学" +L[" (Heroic)"] = "(英雄模式)" +L["Heroic Mode Tokens"] = "公正徽章换取" +L["hide"] = "隐藏" +L["Hides the UI"] = "隐藏图形界面" +L["Hide this guild in the tooltip"] = "在提示信息里隐藏这个公会仓库的显示" +L["Highlord Kruul"] = "魔王库鲁尔" +L["Hoary Templar (Wind)"] = "苍白圣殿骑士(风)" +L["Honor points: "] = "荣誉点数: " +L["Horde Forces"] = "部落部队" +L["Hunter Set"] = "猎人套装" +L["Icecap"] = "冰盖草" +L["Imbued Netherweave"] = "魔化灵纹套装" +L["Imperial Plate"] = "君王板甲" +L["Incendicite Mineral Vein"] = "火岩矿脉" +L["Include guild bank count in the total count"] = "总计(包括公会银行物品数量)" +L["Include guild bank(s)"] = "包括公会银行" +L["Include guild members' professions"] = "公会成员专业技能" +L["Include items without level requirement"] = "包含没有等级要求的物品" +L["Include known recipes"] = "包括已知配方" +L["Include mailboxes"] = "包括邮箱" +L["Increases attack power by %d+"] = "攻击强度提高%d+" +L["Increases damage and healing done by magical spells and effects by up to %d+"] = "提高法术和魔法效果所造成的治疗效果,最多%d+" +L["Increases healing done by up to %d+"] = "法术治疗提高%d+" +L["Indurium Mineral Vein"] = "精铁矿脉" +L["Inscription"] = "铭文" +L["Invalid tradeskill link"] = "无效的技能连结" +L["Iron Deposit"] = "铁矿石" +L["Ironfeather Armor"] = "铁羽护甲" +L[" is "] = " 为 " +L["Item Level"] = "物品等级" +L["Item / Location"] = "物品 / 地点" +L["Items"] = "物品" +L["Journeyman"] = "中级" +L["Karrog"] = "卡尔洛格" +L["Khadgar's Whisker"] = "卡德加的胡须" +L["Khorium Vein"] = "氪金矿脉" +L["Khorium Ward"] = "氪金套装" +L["Kingsblood"] = "皇血草" +L["Krom Stoutarm Chest"] = "克罗姆·粗臂的箱子" +L["Lady Falther'ess"] = "法瑟蕾丝夫人" +L["Lake Wintergrasp"] = true +L["Large Obsidian Chunk"] = "大型黑曜石碎块" +L["last check "] = "上次检查于 " +L["Last visit: %s by %s"] = "最后一次访问: %s 到访者: %s" +L["Leather Set"] = "皮甲套装" +L["Leatherworking Leather Sets"] = "制皮皮甲套装" +L["Leatherworking Mail Sets"] = "制皮链甲套装" +L["Left-click to"] = "左键点击" +L["Left-click to |cFF00FF00open"] = "左键点击|cFF00FF00打开" +L["Left-click to invite attendees"] = "左键点击来邀请参与者" +L["Left-click to see this character's equipment"] = "左键点击来观看这角色的装备" +L["Left click to view"] = "左键点击查看" +L["Legendaries"] = "传说装备" +L["Legendary Mount"] = "史诗坐骑" +L["Lesser Bloodstone Deposit"] = "次级血石矿脉" +L["Level"] = "等级" +L["Level 30-39"] = "30-39级" +L["Level 40-49"] = "40-49级" +L["Level 50-60"] = "50-60级" +L["Level 70"] = "70级" +L["Level 70 Reputation PVP"] = "70级PVP声望装" +L["Level %d Honor PVP"] = "%d级PVP荣誉装" +L["Levels"] = "级" +L["Liferoot"] = "活根草" +L["Local Time: %s %sRealm Time: %s"] = "本地时间: %s %s服务器时间: %s" +L["Location"] = "地点" +L["Lockpicking"] = "开锁" +L["Loot Card Items"] = "稀有纸牌物品" +L["Loots"] = "拾取" +L["Loot tables"] = "搜索掉落列表" +L["Lord Ahune"] = "埃霍恩" +L["Lord Blackwood"] = "布莱克伍德公爵" +L["Love is in the air"] = "爱情的气息" +L["Lucky Red Envelope"] = "红包" +L["Lunacy Deck"] = "愚人套牌" +L["Lunar Festival"] = "新年" +L["Lv %s Rewards"] = "%s级奖励" +L["Mageroyal"] = "魔皇草" +L["Mage Set"] = "法师套装" +L["Magregan Deepshadow"] = "马格雷甘·深影" +L["Mail"] = "邮件" +L["Mail Expiry Warning"] = "邮件过期警告" +L["Mail is about to expire on at least one character."] = "至少一个角色的邮件即将到期." +L["Mails"] = "邮件" +L["Mail Set"] = "链甲套装" +L["Mails %s(%d)"] = "邮件 %s(%d)" +L["Mail was last checked "] = "邮箱上次访问于 " +L["Malevus the Mad"] = "疯狂的玛尔弗斯" +L["Mana Thistle"] = "法力蓟" +L["Master"] = "宗师级" +L["Master Axesmith"] = "宗师级铸斧" +L["Master Hammersmith"] = "宗师级铸锤" +L["Master Swordsmith"] = "宗师级铸剑" +L["Maximum Level: %s"] = "最高等级: %s" +L["Max rest XP displayed as 150%"] = "最大奖励经验显示为150%" +L["Midsummer Fire Festival"] = "仲夏焰火节" +L["Minimap Icon Angle"] = "迷你地图图标角度" +L["Minimap Icon Radius"] = "迷你地图图标半径" +L["Minimum Level: %s"] = "最低等级: %s" +L["Mining"] = "采矿" +L["Miscellaneous"] = "杂项" +L["Mithril Deposit"] = "秘银矿脉" +L["Mooncloth"] = "月布" +L["Mountain Silversage"] = "山鼠草" +L["Move to change the angle of the minimap icon"] = "移动迷你地图图标的角度" +L["Move to change the radius of the minimap icon"] = "移动迷你地图图标的半径" +L["Muddy Churning Waters"] = "混浊的水" +L["N/A"] = "暂不提供" +L["Netherbloom"] = "虚空花" +L["Nethercite Deposit"] = "虚空矿脉" +L["Netherdust Bush"] = "灵尘灌木丛" +L["Netherscale Armor"] = "虚空之鳞" +L["Netherstrike Armor"] = "虚空打击" +L["Netherweave Vestments"] = "灵纹套装" +L["New mail notification"] = "新邮件提示" +L["Nightmare Vine"] = "噩梦藤" +L["Noblegarden"] = "贵族的花园" +L["No currencies found"] = "没找到金钱资料" +L["No data"] = "无数据" +L["No guild found"] = "没找到公会资料" +L["No match found!"] = "未发现匹配的!" +L["Non Set Accessories"] = "非套装配件" +L["Non Set Cloth"] = "非套装布甲" +L["Non Set Leather"] = "非套装皮甲" +L["Non Set Mail"] = "非套装链甲" +L["Non Set Plate"] = "非套装板甲" +L["No quest found for "] = "未发现任务:" +L["No reputations found"] = "没找到声望资料" +L["No rest XP"] = "无经验奖励" +L[" not found!"] = " 未发现!" +L["Not started"] = "未启动" +L["Number of players: %s"] = "玩家数量: %s" +L["Offline Members"] = "下线成员" +L["Olaf"] = "奥拉夫" +L["Ooze Covered Gold Vein"] = "软泥覆盖的金矿脉" +L["Ooze Covered Mithril Deposit"] = "软泥覆盖的秘银矿脉" +L["Ooze Covered Rich Thorium Vein"] = "软泥覆盖的富瑟银矿脉" +L["Ooze Covered Silver Vein"] = "软泥覆盖的银矿脉" +L["Ooze Covered Thorium Vein"] = "软泥覆盖的瑟银矿脉" +L["Ooze Covered Truesilver Deposit"] = "软泥覆盖的真银矿脉" +L["open/close"] = "打开/关闭" +L["Opera (Shared Drops)"] = "剧场(共享掉落)" +L["Other"] = "其他" +L["Outdoor Bosses"] = "户外首领" +L["Paladin Set"] = "圣骑士套装" +L["Patterns"] = "图样" +L["Peacebloom"] = "宁神花" +L["Plaguebloom"] = "瘟疫花" +L["Plans"] = "设计图" +L["Plate Set"] = "板甲套装" +L["Please open this window again"] = "请再次打开窗口" +L["Poisons"] = "毒药" +L["Porfus the Gem Gorger"] = "掘钻者波弗斯" +L["Portals Deck"] = "入口套牌" +L["Priest Set"] = "牧师套装" +L["Primal Batskin"] = "原始蝙蝠皮套装" +L["Primal Intent"] = "原始打击" +L["Primal Mooncloth"] = "原始月布" +L["Private to friends: %s"] = "对好友保密: %s" +L["Private to guild: %s"] = "对公会保密: %s" +L["Prof. 1"] = "商业技能" +L["Prof. 2"] = "辅助技能" +L["Professions"] = "专业" +L["Purple Lotus"] = "紫莲花" +L["PVP Cloth Set"] = "PVP布甲套装" +L["PVP Leather Sets"] = "PVP皮甲套装" +L["PVP Mail Sets"] = "PVP链甲套装" +L["PVP Plate Sets"] = "PVP板甲套装" +L["Pyron"] = "征服者派隆" +L["QuestID"] = "任务编号" +L["Quest Items"] = "任务物品" +L["Quest rewards"] = "任务奖励" +L["Quests"] = "任务" +L["Ragveil"] = "邪雾草" +L["Rajaxx's Captains"] = "拉贾克斯将军的随从" +L["Random Boss"] = "随机首领" +L["Rare Fish"] = "稀有鱼类" +L["Rare Fish Rewards"] = "稀有鱼类奖励" +L["Razorfen Spearhide"] = "剃刀沼泽刺鬃守卫" +L["Realm"] = "服务器" +L["Realm %s successfully deleted"] = "服务器 %s 删除成功" +L["Reference data not available"] = "暂无参考数据" +L["Reference data received (%s) !"] = "接受的参考数据 (%s) !" +L["Refer to the activity pane for more details."] = "更多信息请查看现用的方框." +L["Relics"] = "圣物" +L["Reputations"] = "声望" +L["Reputations received !"] = "收到声望资料!" +L["Requesting item %d of %d"] = "物品要求 %d 之 %d" +L["Requesting %s information from %s"] = "请求%s资料,目标%s" +L["Request rejected by %s"] = "请求被%s驳回" +L["Reset"] = "重置" +L["Resistance"] = "抗性" +L["Rested"] = "经验奖励" +L["Restores %d+ mana per"] = "秒恢复(%d+)点法力值" +L["Rest XP"] = "奖励经验" +L[" results found (Showing "] = " 个结果 (显示 " +L["Rethilgore"] = "雷希戈尔" +L["Revanchion"] = "雷瓦克安" +L["Rich Adamantite Deposit"] = "富精金矿脉" +L["Rich Thorium Vein"] = "富瑟银矿" +L["Riding"] = "骑术" +L["Right-Click for options"] = "右键点击打开选项" +L["Right-click to |cFF00FF00drag"] = "右键点击|cFF00FF00拖拽" +L["Right-Click to find an upgrade"] = "右键点击查找高端进阶装备" +L["Rogue Proficiencies"] = "潜行者专有技能" +L["Rogue Set"] = "潜行者套装" +L["Roogug"] = "鲁古格" +L["Sanguine Hibiscus"] = "红色木槿" +L["Savage Gladiator's Weapons"] = "凶残角斗士的武器" +L["Scaled Draenic Armor"] = "缀鳞德拉诺套装" +L[" scan failed for "] = " 扫描失败于 " +L["Scan mail body (marks it as read)"] = "扫描邮件内容(标记为已读)" +L["Scorn"] = "瑟克恩" +L["Scourge Invasion"] = "天灾入侵" +L["search"] = "搜索" +L["Search Containers"] = "搜索容器" +L["Search in bags"] = "在背包中搜索" +L["Secondary Skills"] = "辅助技能" +L[ [=[Security hint: disable this if you have officer rights +on guild bank tabs that may not be viewed by everyone, +and authorize requests manually]=] ] = [=[安全提示:如果您有公会管理的权利请关闭 +有查看限制的公会金库分页来防止被任何人观看, +如需要同步时请用手动授权.]=] +L[ [=[Security hint: Only enable this when you actually need to transfer data, +disable otherwise]=] ] = [=[安全性提示: 只有当您需要实际的数据传输时才启用, +反之请关闭它]=] +L["Send account sharing request to:"] = "发送账户共享请求到:" +L["Sending account sharing request to %s"] = "向%s发送帐户共享的请求" +L["Sending character %s (%d of %d)"] = "发送角色资料 %s (%d 之 %d)" +L["Sending currencies (%d of %d)"] = "发送金钱资料 (%d 之 %d)" +L["Sending guilds (%d of %d)"] = "发送公会资料 (%d 之 %d)" +L["Sending reference data: %s (%d of %d)"] = "发送参考数据: %s (%d of %d)" +L["Sending reputations (%d of %d)"] = "发送声望资料 (%d 之 %d)" +L["Sending table of content (%d items)"] = "发送列表内容 (%d 物品)" +L["Sever"] = "塞沃尔" +L["Shadoweave"] = "暗纹" +L["Shadowforge Cache"] = "暗炉储藏室" +L["Shadow's Embrace"] = "暗影之拥" +L["Shaman Set"] = "萨满祭司套装" +L["Shared"] = "共享掉落" +L["Shartuul"] = "沙图尔" +L["%s has disabled account sharing"] = "%s的帐户共享功能关闭" +L["%s has disabled guild communication"] = "%s关闭公会联系" +L["%s has no auctions"] = "%s 无拍卖行通知" +L["%s has no bids"] = "%s 无一口价货物" +L["%s has no mail"] = "%s 无邮件" +L["Shen'dralar Provisioner"] = "辛德拉圣职者" +L["Shift-Click to link this info"] = "Shift+点击链接此信息" +L["Shift+Left click to link"] = "Shift+左键点击可链接" +L["show"] = "显示" +L["Show already known/learnable by"] = "包括已学习/可学习:" +L["Show counters for all accounts"] = "显示所有账户的数值" +L["Show counters for both factions"] = "显示双方的声望数值" +L["Show counters on gathering nodes"] = "在采集点上显示数量" +L["Show FuBar icon"] = "显示FuBar图标" +L["Show FuBar text"] = "显示FuBar文字" +L["Show guild bank count"] = "包括公会银行内的物品" +L["Show item count per character"] = "显示每个人物的物品数量" +L["Show item ID and item level"] = "显示物品ID和物品等级" +L["Show item source"] = "显示物品来源" +L["Show Minimap Icon"] = "显示迷你地图图标" +L["Shows the UI"] = "显示图形界面" +L["Show total item count"] = "显示物品总计数量" +L["Silverleaf"] = "银叶草" +L["Silver Vein"] = "银矿" +L["%s is in combat, request cancelled"] = "%s在战斗中, 请求被驳回" +L["%s is now ready (%s on %s)"] = "%s 现准备好 (%s 之 %s)" +L["%s is now unlocked (%s on %s)"] = "%s 现解锁 (%s 之 %s)" +L["Skettis"] = "斯克提斯" +L["Skinning"] = "剥皮" +L["Skyguard Raid"] = "天空卫队团队任务" +L["slots"] = "格" +L["Small Obsidian Chunk"] = "小型黑曜石碎块" +L["Small Thorium Vein"] = "瑟银矿脉" +L["Smokywood Pastures Extra-Special Gift"] = "烟林牧场的超级特殊礼物" +L["Smokywood Pastures Vendor"] = "烟林牧场商人" +L["Socket"] = "插槽" +L["Sort loots in descending order"] = "拾取按照逆序排列" +L["Sothos & Jarien"] = "索托斯和亚雷恩" +L["Soulcloth Embrace"] = "灵魂布之拥" +L["Source"] = "来源" +L["Spawn Of Hakkar"] = "哈卡的后代" +L["Spellfire"] = "魔焰" +L["Spellstrike Infusion"] = "法术打击" +L["Spirit Towers (Terrokar)"] = "灵魂之塔(泰罗卡森林,白骨荒野)" +L["%s|r has received a mail from %s"] = "%s|r 已收到%s的邮件" +L[ [=[%s%s|r has requested the bank tab %s%s|r +Send this information ?]=] ] = [=[%s%s|r 要求公会仓库分页 %s%s|r +要传送这项资料吗 ?]=] +L["%s starts in %d minutes (%s on %s)"] = "%s 在 %d 分钟后开始 (%s 之 %s)" +L["Started"] = "已启动" +L["Stasis Chambers"] = "阿尔法静止间" +L["Steamwheedle Cartel"] = "热砂港" +L["Storms Deck"] = "风暴套牌" +L["Stormshroud Armor"] = "雷暴" +L["Stranglekelp"] = "荆棘藻" +L["Strength of the Clefthoof"] = "裂蹄之力" +L["Suggested leveling zone: "] = "推荐升级地区: " +L["Suggestion"] = "建议" +L["Summary"] = "概要" +L["Summoner's Tomb"] = "召唤者之墓" +L["Sungrass"] = "太阳草" +L["Superior Rewards"] = "精良奖励" +L[ [=[%sWarning:|r if you accept, %sALL|r information known +by Altoholic will be sent to %s%s|r (bags, money, etc..)]=] ] = [=[%s警告:|r 如接受, %s所有|r 已知的资料 +会被 Altoholic 传送给 %s%s|r (背包, 金钱, 等等..)]=] +L["%sWarning:|r make sure this user may view this information before accepting"] = "%s警告:|r 请确定此用户可以查看分页的资料才接受" +L["Swiftthistle"] = "雨燕草" +L["%s will be ready in %d minutes (%s on %s)"] = "%s 在 %d 分钟后准备好 (%s on %s)" +L["Table of content received (%d items)"] = "收到列表的内容(%d 物品)" +L["Tablet of Ryuneh"] = "雷乌纳石板" +L["Tablet of Will"] = "意志石板" +L["Tailoring Sets"] = "裁缝套装" +L["Tank"] = "坦克" +L["T'chali's Voodoo Brewery"] = "塔卡里的节日巫毒酒桶" +L["Terocone"] = "泰罗果" +L["Terokk"] = "泰罗克" +L["The Darksoul"] = "黑暗之魂" +L["The Duke of Cinders (Fire)"] = "灰烬公爵(火)" +L["The Duke of Fathoms (Water)"] = "深渊公爵(水)" +L["The Duke of Shards (Earth)"] = "碎石公爵(地)" +L["The Duke of Zephyrs (Wind)"] = "微风公爵(风)" +L["Theldren"] = "塞尔德林" +L[ [=[There is a risk of disconnection if the queried item +is a loot from a high level dungeon. + +]=] ] = [=[当然,向服务器查询物品时有掉线的风险, +特别是那些没有被完全推倒的首领! + +]=] +L["The Unyielding"] = "不屈的力量" +L["The Vault"] = "宝窟" +L["Thick Draenic Armor"] = "厚重德莱尼套装" +L["This character"] = "此角色" +L["This faction"] = "此阵营" +L["This field |cFF00FF00cannot|r be left empty."] = "这栏 |cFF00FF00不能|r be 留空." +L[ [=[This name can be anything you like, +it does |cFF00FF00NOT|r have to be the real account name.]=] ] = [=[可任意名称, +并 |cFF00FF00不需要|r 是真实的账户名称.]=] +L["This realm"] = "仅搜索该服务器" +L[ [=[This will gradually improve the consistency of the searches, +as more items are available in the item cache. + +]=] ] = [=[这将会逐渐的改进搜索的效率, +因为越来越多的物品将被保存到物品缓存中。 + +]=] +L["Thomas Yance"] = "托马斯·杨斯" +L["Thunderbrew Brewery"] = "雷酒节日酒桶" +L["Ticking Present"] = "条纹礼物盒" +L["Tier 0.5 Quests"] = "T0.5任务换取" +L["Tier %d Tokens"] = "T%d(换取,遗忘胜利者系列)" +L["Timed Chest"] = "限时宝箱" +L["Tin Vein"] = "锡矿" +L["toggle"] = "切换" +L["Toggles the UI"] = "切换图形界面的显示/隐藏" +L["Token Hand-Ins"] = "上缴物品交换" +L["Tooltip"] = "提示" +L["Total owned"] = "总计" +L["Totals"] = "总计" +L["Transfer complete"] = "传输完成" +L["Transmute"] = "转化" +L["Transparency"] = "透明度" +L["Trash Mobs"] = "小怪掉落" +L["Treat Bag"] = "糖果包" +L["Tribal"] = "部族" +L["Tribute Run"] = "贡品出产" +L["Trinkets"] = "饰品" +L["Troll Mini bosses"] = "巨魔小首领" +L["Truesilver Deposit"] = "真银矿石" +L["Twin Spire Ruins"] = "双塔废墟" +L["Unknown"] = "未知" +L["Unknown link, please relog this character"] = "未知链接,请重新登入角色" +L["Upper Deck"] = "桌面纸牌" +L["up to"] = "升到" +L["Vakkiz the Windrager"] = "风怒者瓦克奇斯" +L["Various Locations"] = "多个地点" +L["View"] = "浏览" +L["View auctions"] = "浏览拍卖行" +L["View bags"] = "背包浏览" +L["View bids"] = "浏览一口价" +L["View mailbox"] = "邮箱浏览" +L["View quest log"] = "任务浏览" +L["Visited"] = "已访问" +L["Volcanic Armor"] = "火山" +L["Waiting for %s to accept .."] = "等待 %s 同意 .." -- Needs review +L["Warlock Set"] = "术士套装" +L["Warlords Deck"] = "督军套牌" +L["Warn %d minutes before an event starts"] = "在事件开始前 %d 分钟警告" +L["Warn when mail expires in less days than this value"] = "在邮件过期前多少天进行警告" +L["Warrior Set"] = "战士套装" +L["Weapons"] = "武器" +L["Weaponsmith"] = "武器锻造" +L["Week starts on Monday"] = "每周从周一开始" +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected. + +]=] ] = [=[当 |cFFFF0000关闭|cFFFFFFFF时, 所有帐户共享请求会被拒. + +]=] +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = "当 |cFFFF0000关闭|cFFFFFFFF时, 将不会有任何公会联系." +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be +required before sending any information. + +]=] ] = [=[当 |cFFFF0000关闭|cFFFFFFFF时, 发送任何信息 +之前将需要您的确认. + +]=] +L["Whitemend Wisdom"] = "白色治愈" +L["Wild Draenish Armor"] = "野性德莱尼套装" +L["Wild Steelbloom"] = "野钢花" +L["Wildvine"] = "野葡萄藤" +L["Will be learnable by "] = "将学习:" +L["Windhawk Armor"] = "风鹰" +L["Wintersbite"] = "冬刺草" +L["Winter Veil Gift"] = "冬幕节的礼物" +L[" with "] = " 对 " +L["World Drops"] = "世界掉落" +L["World PVP"] = "世界PVP" +L["WoW Collector Edition"] = "魔兽世界收藏版" +L["Wrathbringer Laz-tarash"] = "天罚使者拉塔莱什" +L["Wrath of Spellfire"] = "魔焰之怒" +L["Yor (Heroic Summon)"] = "尤尔(英雄模式召唤)" +L[ [=[You have received an account sharing request +from %s%s|r, accept it?]=] ] = [=[你收到帐户共享请求 +请求者 %s%s|r, 接受吗?]=] +L[ [=[Your confirmation will still be required any time someone requests your information. + +]=] ] = [=[任何时候玩家请求你信息都必须得到你的确认. + +]=] +L["Zelemar the Wrathful"] = "愤怒者塞雷玛尔" +L["Zone"] = "地区" + diff --git a/Altoholic-Addon/Altoholic/Locales/zhTW.lua b/Altoholic-Addon/Altoholic/Locales/zhTW.lua new file mode 100644 index 0000000..f09c3b1 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Locales/zhTW.lua @@ -0,0 +1,741 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "Altoholic", "zhTW" ) + +if not L then return end + +L["28 Slot"] = "28格" +L["32 Keys Max"] = "32鑰匙最大數" +L["Abyssal Council"] = "深淵議會" +L["Accessories"] = "配件" +L["Account"] = "帳戶" +L["Account Name"] = "帳戶名稱" +L["Account Sharing"] = "帳戶共享" +L["Account Sharing Enabled"] = "啟用帳戶共享" +L["Account Sharing Request"] = "要求帳戶共享資料" +L["Account sharing request received from %s"] = "收到%s的帳戶共享資料要求" +L["Account Summary"] = "帳戶摘要" +L["Activity"] = "活躍度" +L["Adamantite Battlegear"] = "堅鋼戰裝" +L["Adamantite Deposit"] = "堅鋼礦床" +L["Aged Dalaran Wizard"] = "年邁的達拉然巫師" +L["Aggem Thorncurse"] = "阿格姆" +L["AH"] = "拍賣場" +L["All accounts"] = "所有帳戶" +L["All cooldowns are up"] = "所有冷卻已完成" +L["Alliance Forces"] = "聯盟部隊" +L["All-in-one"] = "單一撿視" +L["All realms"] = "搜索所有伺服器" +L["Already known by "] = "已經學會" +L["Altoholic:|r Usage = /altoholic search "] = "Altoholic:|r 使用方法 = /altoholic search <物品名稱>" +L["Ancient Lichen"] = "古老青苔" +L["and above"] = "及以上" +L["Any"] = "任何" +L["Anzu the Raven God (Heroic Summon)"] = "安祖·烏鴉神(英雄模式召喚)" +L["Apprentice"] = "初級" +L["Arcanoweave Vestments"] = "奧紋套裝" +L["Are also on this quest:"] = "也有這個任務:" +L["Arena points: "] = "兢技場分數" +L["Arena Season %d"] = "競技場第 %d 季" +L["Armbreaker Huffaz"] = "斷臂者霍法茲" +L["Armorsmith"] = "鑄甲大師" +L["Arthas' Tears"] = "阿薩斯之淚" +L["Artisan"] = "專家級" +L["at"] = "在" +L["At least one recipe could not be read"] = "最少有一個配方未被讀取" +L["Attendees: "] = "參與者:" +L["Auctions %s(%d)"] = "拍賣 %s(%d)" +L["Automatically authorize guild bank updates"] = "自動授權公會金庫更新" +L["AutoQuery server |cFFFF0000(disconnection risk)"] = "自動向伺服器查詢 |cFFFF0000(有可能導至斷線)" +L["Avatar of the Martyred"] = "馬丁瑞德的化身" +L["Average Item Level"] = "平均物品等級" +L["Azure Templar (Water)"] = "碧藍聖殿騎士 (水)" +L["Baelog's Chest"] = "巴爾洛戈的箱子" +L["Bags"] = "背包" +L["Bag Usage"] = "背包使用度" +L["Balance"] = "平衡" +L["Balzaphon"] = "巴爾薩馮" +L["Bank"] = "銀行" +L["Bank bag"] = "銀行包" +L["Bank not visited yet"] = "銀行沒有訪問過" +L["Barleybrew Brewery"] = "麥酒釀造廠" +L["(based on iLvl)"] = "(根據物品等級)" +L["Bash'ir Landing"] = "貝許爾平臺" +L["Battlecast Garb"] = "戰放裝束" +L["BC Collector Edition (Europe)"] = "燃燒的遠征收藏版(歐洲版)" +L["Beasts Deck"] = "野獸套卡" +L["Beast Training"] = "野獸訓練" +L[ [=[Be informed when a guildmate sends a mail to one of my alts. + +Mail content is directly visible without having to reconnect the character]=] ] = [=[當公會成員發送了一封郵件給我的一個角色會發出通知. + +郵件內容是直接可見而不必重新登錄該角色]=] +L["Bids %s(%d)"] = "競標 %s(%d)" +L["Black Dragon Mail"] = "黑龍鎖甲" +L["Black Lotus"] = "黑蓮花" +L["Blacksmithing (Lv 60)"] = "鍛造 (Lv 60)" +L["Blacksmithing (Lv 70)"] = "鍛造 (Lv 70)" +L["Blacksmithing Mail Sets"] = "鍛造鎖甲套裝" +L["Blacksmithing Plate Sets"] = "鍛造鎧甲套裝" +L["Blade Edge Mountains"] = "劍刃山脈" +L["Blessings Deck"] = "祝福套卡" +L["Blindweed"] = "盲目草" +L["Blizzard Collectables"] = "暴雪收藏品" +L["Blizzcon 2005"] = "暴雪嘉年華2005" +L["Blizzcon 2007"] = "暴雪嘉年華2007" +L["Bloodsoul Embrace"] = "血魂的擁抱" +L["Bloodthistle"] = "血薊" +L["Blood Tiger Harness"] = "血虎套索" +L["Bloodvine"] = "血藤" +L["Bloodvine Garb"] = "血藤之服" +L["Blue Dragon Mail"] = "藍龍鎖甲" +L["Books"] = "書籍" +L["Booty Run"] = "藏寶競技" +L["Both factions"] = "這兩個陣營聲望" +L[ [=[Both parties must enable account sharing +before using this feature (see options)]=] ] = [=[雙方都必須啟用帳戶共享 +來使用此功能 (請參考選項)]=] +L["Box of Chocolates"] = "巧克力盒" +L["Brewfest"] = "啤酒節" +L["Briarthorn"] = "石南草" +L["Brightly Colored Egg"] = "彩蛋" +L["Bruiseweed"] = "跌打草" +L["Burning Rage"] = "燃燒狂怒" +L["Cache of the Legion"] = "軍團儲藏箱" +L["Calendar"] = "日曆" +L["Cannot delete current character"] = "不能刪除現有角色" +L["Cannot delete current realm"] = "不能刪除當前的伺服器" +L["Cannot link another account's tradeskill"] = "不能使用其它帳戶的技能連結" +L["Cannot link another realm's tradeskill"] = "不能使用其它伺服器的技能連結" +L["Carefully Wrapped Present"] = "仔細包裝的禮物" +L["|cFF00FF00Disable|r to avoid this risk"] = "|cFF00FF00關閉|r 這選項可避免這種情況發生" +L[ [=[|cFFFFFFFFIf an item not in the local item cache +is encountered while searching loot tables, +Altoholic will attempt to query the server for 5 new items. + +]=] ] = [=[|cFFFFFFFF當物品不在本機的內存時 +當在搜索表裡找到, +Altoholic 將試圖查詢服務器下5個新項目. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to send you account sharing requests. +]=] ] = [=[|cFFFFFFFF當 |cFF00FF00啟用|cFFFFFFFF時, 這選項會讓共它Altoholic用家 +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow other Altoholic users +to update their guild bank information with yours automatically. + +]=] ] = [=[|cFFFFFFFF當 |cFF00FF00啟用|cFFFFFFFF時, 此選項將允許其他Altoholic用戶 +與你的公會金庫資料作自動更新. + +]=] +L[ [=[|cFFFFFFFFWhen |cFF00FF00enabled|cFFFFFFFF, this option will allow your guildmates +to see your alts and their professions. + +]=] ] = [=[|cFFFFFFFF當 |cFF00FF00啟用|cFFFFFFFF時, 這選項會讓你公會的會友 +看見你的分身和其專業技能. + +]=] +L["Character"] = "角色" +L["Characters"] = "角色" +L["Character %s received !"] = "角色%s已接收!" +L["Character %s successfully deleted"] = "角色 %s 刪除成功" +L["Children's Week"] = "兒童週" +L["Christmas Gift 2006"] = "聖誕禮物2006" +L["Clamp window to screen"] = "將視窗固定在畫面上" +L["Class Books"] = "職業技能書" +L["Classes: Death Knight"] = "職業: 死亡騎士" +L["Classes: Hunter"] = "職業: 獵人" +L["Classes: Mage"] = "職業: 法師" +L["Classes: Paladin"] = "職業: 聖騎士" +L["Classes: Priest"] = "職業: 牧師" +L["Classes: Rogue"] = "職業: 盜賊" +L["Classes: Shaman"] = "職業: 薩滿" +L["Classes: Warlock"] = "職業: 術士" +L["Classes: Warrior"] = "職業: 戰士" +L["Class Skills"] = "職業技能" +L["Clear all entries"] = "清除所有的項目" +L["Clear goblin AH entries"] = "清除中立拍賣場的項目" +L["Clear your faction's entries"] = "清除現有陣營的項目" +L["Click a character's AiL to see its equipment"] = "點擊角色的 AiL 來查看他的裝備" +L[ [=[Clicking this button will update +your local %s%s|r bank tab +based on %s%s's|r data]=] ] = [=[點擊此按鈕將更新 +你本服的%s%s|r 公會金庫分頁 +基於 %s%s's|r 的資料]=] +L[ [=[Click this button to ask a player +to share his entire Altoholic Database +and add it to your own]=] ] = [=[按一下這個按鈕來詢問玩家 +要求分享Altoholic的數據庫 +並將其添加到您自己數據庫內]=] +L["Cloaks"] = "披風" +L["Cloth Set"] = "布甲套裝" +L["Conspicuous Urn"] = "顯眼的石罐" +L["Containers"] = "容器" +L["Copper Vein"] = "銅礦脈" +L["Could be learned by "] = "這可以被誰學會:" +L["Crafted Weapons"] = "精製裝備武器" +L["Crimson Templar (Fire)"] = "赤紅聖殿騎士 (火)" +L["Currencies received !"] = "收到金錢資料!" +L["Dark Iron Deposit"] = "黑鐵礦床" +L["Darkscreecher Akkarai"] = "黑暗尖叫者阿卡萊" +L[" days"] = " 日." +L[" days ago"] = " 日前." +L["Deadly Gladiator's Weapons"] = "致命鬥士武器" +L["Death Knight"] = "死亡騎士" +L["Default"] = "預設" +L["Delete Guild Bank?"] = "刪除公會金庫嗎?" +L["Delete this Alt"] = "刪除這角色" +L["Delete this Realm"] = "刪除此伺服器" +L["Detailed guild bank count"] = "公會銀行計數詳情" +L["Devilsaur Armor"] = "魔暴龍護甲" +L["Disable warnings"] = "禁用警告" +L["Display warnings in a dialog box"] = "在對話框中顯示警告" +L["Do you want to open Altoholic's calendar for details ?"] = "你想開啟Altoholic日曆來了解詳情嗎?" +L["Do you want to view it now ?"] = "你想立即查看嗎 ?" +L["DPS"] = "秒傷" +L["Dragonscale"] = "龍鱗製皮" +L["Dreamfoil"] = "夢葉草" +L["Dreaming Glory"] = "譽夢草" +L["Drohn's Distillery"] = "德羅恩的釀酒廠" +L["Druid of the Fang (Trash Mob)"] = "尖牙德魯伊 (小怪)" +L["Druid Set"] = "德魯伊套裝" +L["Earthen Templar (Earth)"] = "土色聖殿騎士 (土)" +L["Earthroot"] = "地根草" +L["Elemental"] = "元素製皮" +L["Elemental Invasion"] = "元素入侵" +L["Elementals Deck"] = "元素套卡" +L["Elemental Shaman"] = "元素" +L["E-Mail"] = "郵件" +L["Emblems of Heroism"] = "英雄紋章" +L["Emblems of Valor"] = "勇氣紋章" +L["Enchanted Adamantite Armor"] = "附魔堅鋼護甲" +L["Enchants"] = "公式" +L["Engineering (Lv 60)"] = "工程學 (Lv 60)" +L["Engineering (Lv 70)"] = "工程學 (Lv 70)" +L[ [=[Enter an account name that will be +used for |cFF00FF00display|r purposes only.]=] ] = [=[輸入帳戶名稱 +用作|cFF00FF00識別而已|r .]=] +L["Epic Rewards"] = "史詩獎勵" +L["Equipment"] = "裝備" +L["Equipment Slot"] = "設備格" +L["Equipped"] = "已裝備" +L["Eric The Swift"] = "『迅捷』艾利克" +L["Ethereum Prison"] = "伊斯利恩監獄" +L["Expert"] = "高級" +L["Expiry:"] = "過期於:" +L["Fadeleaf"] = "枯葉草" +L["Faith in Felsteel"] = "信仰魔鋼" +L["Feast of Winter Veil"] = "冬幕節" +L["Fel Iron Chain"] = "魔鐵鍊甲" +L["Fel Iron Chest"] = "魔鐵箱" +L["Fel Iron Deposit"] = "魔鐵礦床" +L["Fel Iron Plate"] = "魔鐵鎧甲" +L["Fel Lotus"] = "魔獄蓮花" +L["Felscale Armor"] = "魔鱗護甲" +L["Fel Skin"] = "惡魔皮膚" +L["Felstalker Armor"] = "惡魔捕獵者套裝" +L["Fel Steed"] = "地獄戰馬" +L["Fel Tinkerer Zortan"] = "惡魔工匠祖坦" +L["Felweed"] = "魔獄草" +L["Festive Gift"] = "節慶禮物" +L["Find Upgrade"] = "找尋裝備升級" +L["Firebloom"] = "火焰花" +L["Fire Resistance Gear"] = "火抗套裝" +L["Fireworks Pack"] = "煙火包" +L["First Prize"] = "頭獎" +L["Fishing"] = "釣魚" +L["Fishing Extravaganza"] = "釣魚大賽" +L["Fishing Poles"] = "魚竿" +L["Flame Cap"] = "火帽花" +L["Flame Guard"] = "烈焰套裝" +L["Food"] = "食物" +L["Forgosh"] = "弗古斯" +L["free"] = "可用" +L["Furies Deck"] = "狂怒套卡" +L["Fury of the Nether"] = "虛空之怒套裝" +L["Gaily Wrapped Present"] = "精心包裝的禮物" +L["Garrett Family Chest"] = "加勒特的家族寶藏" +L["General"] = "一般" +L["Gently Shaken Gift"] = "輕輕搖晃過的禮物" +L["Gezzarak the Huntress"] = "女獵人吉札拉" +L["Ghost Mushroom"] = "鬼魂菇" +L["Gift of Adoration"] = "愛慕之禮" +L["Glowcap"] = "白閃菇" +L["Gnomish"] = "地精工程學" +L["Goblin"] = "哥布林工程學" +L["Goblin AH"] = "中立拍賣場" +L["Golden Sansam"] = "黃金蔘" +L["Goldthorn"] = "金棘草" +L["Gold Vein"] = "金礦脈" +L["Gordok Brewery"] = "戈多克綠酒釀造廠" +L["Grave Moss"] = "墓地苔" +L["Green Dragon Mail"] = "綠龍鎖甲" +L["Grey"] = "灰色" +L["Gromsblood"] = "格羅姆之血" +L["Guild Bank not visited yet (or not guilded)"] = "公會金庫沒開啟過 (或沒有公會)" +L["Guild Bank Remote Update"] = "公會金庫遙距更新" +L["Guild Bank Tabs"] = "公會金庫分頁" +L["Guild bank tab %s successfully updated !"] = "%s公會金庫分頁已更新成功!" +L["Guild Communication Enabled"] = "啟用公會聯系" +L["Guild Members"] = "公會成員" +L["Guild Skills"] = "公會技能" +L["Guilds received !"] = "收到公會資料!" +L["Guild %s successfully deleted"] = "公會金庫 %s 刪除成功" +L["Gul'bor"] = "古柏爾" +L["Gurubashi Arena"] = "古拉巴什競技場" +L["Hakkari Thorium Vein"] = "哈卡萊瑟銀礦脈" +L["Halaa (Nagrand)"] = "哈刺(納格蘭)" +L["Hallow's End"] = "復活節" +L["Hard Mode"] = "困難模式" +L["Harvest Festival"] = "收穫節" +L["(has auctions)"] = "(有拍賣)" +L["(has bids)"] = "(有競標)" +L["has come online"] = "上線了。" +L["has gone offline"] = "下線了。" +L["(has mail)"] = "(有郵件)" +L[" has no mail, last check "] = "沒有郵件, 最後檢查 " +L[" has not visited his/her mailbox yet"] = "沒有訪問過他/她的郵箱" +L["Headless Horseman"] = "無頭騎士" +L["Heal"] = "治療" +L["Hellfire Fortifications"] = "地獄火半島防禦" +L["Henry Stern"] = "亨利·斯特恩" +L["Herbalism"] = "草藥學" +L[" (Heroic)"] = " (英雄)" +L["Heroic Mode Tokens"] = "正義徽章" +L["hide"] = "隱藏" +L["Hides the UI"] = "隱藏圖形介面" +L["Hide this guild in the tooltip"] = "在提示框隱藏這公會金庫的顯示" +L["Highlord Kruul"] = "卡魯歐領主" +L["Hoary Templar (Wind)"] = "蒼白聖殿騎士 (風)" +L["Honor points: "] = "榮譽點數" +L["Horde Forces"] = "部落部隊" +L["Hunter Set"] = "獵人套裝" +L["Icecap"] = "冰蓋草" +L["Imbued Netherweave"] = "魔染幽紋套裝" +L["Imperial Plate"] = "帝王鎧甲" +L["Incendicite Mineral Vein"] = "火岩礦脈" +L["Include guild bank count in the total count"] = "總數包括公會金庫計數" +L["Include guild bank(s)"] = "包括公會金庫" +L["Include guild members' professions"] = "公會成員專業技能" +L["Include items without level requirement"] = "包括沒等級要求的物品" +L["Include known recipes"] = "包括已學的配方" +L["Include mailboxes"] = "包括郵箱" +L["Increases attack power by %d+"] = "提高攻擊強度%d+點" +L["Increases damage and healing done by magical spells and effects by up to %d+"] = "使所有法術和魔法效果所做成的傷害效果提高%d+點" +L["Increases healing done by up to %d+"] = "使所有法術和魔法效果所做成的治療效果提高%d+點" +L["Indurium Mineral Vein"] = "精鐵礦脈" +L["Inscription"] = "銘文學" +L["Invalid tradeskill link"] = "無效的技能連結" +L["Iron Deposit"] = "鐵礦床" +L["Ironfeather Armor"] = "鐵羽護甲" +L[" is "] = " 是 " +L["Item Level"] = "物品等級" +L["Item / Location"] = "物品 / 地點" +L["Items"] = "物品" +L["Journeyman"] = "中級" +L["Karrog"] = "凱羅格" +L["Khadgar's Whisker"] = "卡德加的鬍鬚" +L["Khorium Vein"] = "克銀礦脈" +L["Khorium Ward"] = "克銀結界" +L["Kingsblood"] = "皇血草" +L["Krom Stoutarm Chest"] = "克羅姆·蒼臂的寶藏" +L["Lady Falther'ess"] = "法瑟蕾絲夫人" +L["Lake Wintergrasp"] = "冬握湖" +L["Large Obsidian Chunk"] = "大型黑曜石礦" +L["last check "] = "前次的撿查 " +L["Last visit: %s by %s"] = "最後一次訪問: %s 到訪者: %s" +L["Leather Set"] = "皮甲套裝" +L["Leatherworking Leather Sets"] = "製皮套裝" +L["Leatherworking Mail Sets"] = "製皮鎖甲套裝" +L["Left-click to"] = "左擊" +L["Left-click to |cFF00FF00open"] = "左鍵 |cFF00FF00開啟" +L["Left-click to invite attendees"] = "左鍵點擊邀請參與者" +L["Left-click to see this character's equipment"] = "左鍵單擊來觀看這角色的裝備" +L["Left click to view"] = "左擊查看" +L["Legendaries"] = "傳說物品" +L["Legendary Mount"] = "傳說坐騎" +L["Lesser Bloodstone Deposit"] = "次級血石礦脈" +L["Level"] = "等級" +L["Level 30-39"] = "30-39級" +L["Level 40-49"] = "40-49級" +L["Level 50-60"] = "50-60級" +L["Level 70"] = "70級" +L["Level 70 Reputation PVP"] = "70級PVP聲望裝" +L["Level %d Honor PVP"] = "%d級PVP榮譽裝" +L["Levels"] = "等級" +L["Liferoot"] = "活根草" +L["Local Time: %s %sRealm Time: %s"] = "本地時間: %s %s伺服器時間: %s" +L["Location"] = "地點" +L["Lockpicking"] = "開鎖" +L["Loot Card Items"] = "稀有紙牌物品" +L["Loots"] = "戰利品" +L["Loot tables"] = "搜索物品掉落表" +L["Lord Ahune"] = "艾胡恩" +L["Lord Blackwood"] = "黑木公爵" +L["Love is in the air"] = "愛就在身邊" +L["Lucky Red Envelope"] = "幸運紅包袋" +L["Lunacy Deck"] = "失心套卡" +L["Lunar Festival"] = "新年節" +L["Lv %s Rewards"] = "%s級獎勵" +L["Mageroyal"] = "魔皇草" +L["Mage Set"] = "法師套裝" +L["Magregan Deepshadow"] = "馬格雷甘·深影" +L["Mail"] = "郵件" +L["Mail Expiry Warning"] = "郵件屆滿警告" +L["Mail is about to expire on at least one character."] = "至少有一個角色的郵件即將到期." +L["Mails"] = "郵件" +L["Mail Set"] = "鎖甲套裝" +L["Mails %s(%d)"] = "郵件 %s(%d)" +L["Mail was last checked "] = "郵件最後一次檢查是 " +L["Malevus the Mad"] = "狂怒者馬拉弗斯" +L["Mana Thistle"] = "法力薊" +L["Master"] = "大師級" +L["Master Axesmith"] = "鑄斧大師" +L["Master Hammersmith"] = "鑄錘大師" +L["Master Swordsmith"] = "鑄劍大師" +L["Maximum Level: %s"] = "最高等級: %s" +L["Max rest XP displayed as 150%"] = "充份休息經驗值以150%來顯示" +L["Midsummer Fire Festival"] = "仲夏火燄節慶" +L["Minimap Icon Angle"] = "小地圖圖示角度" +L["Minimap Icon Radius"] = "小地圖圖示半徑距離" +L["Minimum Level: %s"] = "最低等級: %s" +L["Mining"] = "採礦" +L["Miscellaneous"] = "雜項" +L["Mithril Deposit"] = "秘銀礦脈" +L["Mooncloth"] = "月布專精" +L["Mountain Silversage"] = "山鼠草" +L["Move to change the angle of the minimap icon"] = "移動來改變小地圖圖示的角度" +L["Move to change the radius of the minimap icon"] = "移動來改變小地圖圖示的半徑距離" +L["Muddy Churning Waters"] = "混濁的水" +L["N/A"] = "暫不提供" +L["Netherbloom"] = "虛空花" +L["Nethercite Deposit"] = "虛空傳喚礦床" +L["Netherdust Bush"] = "虛空之塵灌木叢" +L["Netherscale Armor"] = "虛空鱗護甲" +L["Netherstrike Armor"] = "地擊套裝" +L["Netherweave Vestments"] = "幽紋套裝" +L["New mail notification"] = "新郵件通知" +L["Nightmare Vine"] = "夢魘根" +L["Noblegarden"] = "貴族花園" +L["No currencies found"] = "沒找到金錢資料" +L["No data"] = "無資料" +L["No guild found"] = "沒找到公會資料" +L["No match found!"] = "未找到相應!" +L["Non Set Accessories"] = "非套裝配件" +L["Non Set Cloth"] = "非套裝布甲" +L["Non Set Leather"] = "非套裝皮甲" +L["Non Set Mail"] = "非套裝鎖甲" +L["Non Set Plate"] = "非套裝鎧甲" +L["No quest found for "] = "沒有找到任務: " +L["No reputations found"] = "沒找到聲望資料" +L["No rest XP"] = "沒有充份休息經驗值" +L[" not found!"] = "*沒找到" +L["Not started"] = "尚未啟動" +L["Number of players: %s"] = "玩家數量: %s" +L["Offline Members"] = "離線會員" +L["Olaf"] = "奧拉夫" +L["Ooze Covered Gold Vein"] = "軟泥覆蓋的金礦脈" +L["Ooze Covered Mithril Deposit"] = "軟泥覆蓋的秘銀礦床" +L["Ooze Covered Rich Thorium Vein"] = "軟泥覆蓋的富瑟銀礦脈" +L["Ooze Covered Silver Vein"] = "軟泥覆蓋的銀礦脈" +L["Ooze Covered Thorium Vein"] = "軟泥覆蓋的瑟銀礦脈" +L["Ooze Covered Truesilver Deposit"] = "軟泥覆蓋的真銀礦床" +L["open/close"] = "開啟/關閉" +L["Opera (Shared Drops)"] = "歌劇院 (隨機掉落)" +L["Other"] = "其他" +L["Outdoor Bosses"] = "野外首領" +L["Paladin Set"] = "聖騎士套裝" +L["Patterns"] = "卷軸" +L["Peacebloom"] = "寧神花" +L["Plaguebloom"] = "瘟疫花" +L["Plans"] = "黑暗神廟卷軸" +L["Plate Set"] = "鎧甲套裝" +L["Please open this window again"] = "請重啟這視窗" +L["Poisons"] = "毒藥" +L["Porfus the Gem Gorger"] = "寶石吞噬者波弗斯" +L["Portals Deck"] = "傳送門套卡" +L["Priest Set"] = "牧師套裝" +L["Primal Batskin"] = "原始蝙蝠皮套裝" +L["Primal Intent"] = "原始之意套裝" +L["Primal Mooncloth"] = "原始月布" +L["Private to friends: %s"] = "對好友保密: %s" +L["Private to guild: %s"] = "對公會保密: %s" +L["Prof. 1"] = "專業1" +L["Prof. 2"] = "專業2" +L["Professions"] = "專業技能" +L["Purple Lotus"] = "紫蓮花" +L["PVP Cloth Set"] = "PVP布甲套裝" +L["PVP Leather Sets"] = "PVP皮甲套裝" +L["PVP Mail Sets"] = "PVP鎖甲套裝" +L["PVP Plate Sets"] = "PVP鎧甲套裝" +L["Pyron"] = "征服者派隆" +L["QuestID"] = "任務ID" +L["Quest Items"] = "任務物品" +L["Quest rewards"] = "任務獎勵" +L["Quests"] = "任務" +L["Ragveil"] = "拉格維花" +L["Rajaxx's Captains"] = "拉賈克斯的上尉們" +L["Random Boss"] = "隨機首領" +L["Rare Fish"] = "稀有魚類" +L["Rare Fish Rewards"] = "稀有釣魚獎勵" +L["Razorfen Spearhide"] = "剃刀沼澤刺鬃守衛" +L["Realm"] = "伺服器" +L["Realm %s successfully deleted"] = "伺服器 %s 成功刪除" +L["Reference data not available"] = "無法提供相關資料" +L["Reference data received (%s) !"] = "收到相關的數據 (%s) !" +L["Refer to the activity pane for more details."] = "詳細請參照活躍度." +L["Relics"] = "聖物" +L["Reputations"] = "聲望" +L["Reputations received !"] = "收到聲望資料!" +L["Requesting item %d of %d"] = "物品要求 %d 之 %d" +L["Requesting %s information from %s"] = "要求%s資料,目標%s" +L["Request rejected by %s"] = "要求被%s駁回" +L["Reset"] = "重置" +L["Resistance"] = "抗性" +L["Rested"] = "充份休息" +L["Restores %d+ mana per"] = "每5秒恢復%d+點法力" +L["Rest XP"] = "充份休息經驗值" +L[" results found (Showing "] = " 結果被找出 (顯示)" +L["Rethilgore"] = "雷希戈爾" +L["Revanchion"] = "雷瓦克安" +L["Rich Adamantite Deposit"] = "豐沃的堅鋼礦床" +L["Rich Thorium Vein"] = "富瑟銀礦" +L["Riding"] = "騎術" +L["Right-Click for options"] = "右鍵點擊選單" +L["Right-click to |cFF00FF00drag"] = "右鍵 |cFF00FF00拖曳" +L["Right-Click to find an upgrade"] = "右擊來找尋裝備升級" +L["Rogue Proficiencies"] = "盜賊熟練度" +L["Rogue Set"] = "盜賊套裝" +L["Roogug"] = "魯古格" +L["Sanguine Hibiscus"] = "血紅木槿" +L["Savage Gladiator's Weapons"] = "蠻荒鬥士武器" +L["Scaled Draenic Armor"] = "德萊尼鱗護甲" +L[" scan failed for "] = "掃描失敗: " +L["Scan mail body (marks it as read)"] = "掃描郵件內容 (標記為己讀取)" +L["Scorn"] = "瑟克恩" +L["Scourge Invasion"] = "天譴軍團" +L["search"] = "搜索" +L["Search Containers"] = "搜索容器" +L["Search in bags"] = "在背包中搜索" +L["Secondary Skills"] = "次要技能" +L[ [=[Security hint: disable this if you have officer rights +on guild bank tabs that may not be viewed by everyone, +and authorize requests manually]=] ] = [=[安全提示:如果您有公會理事的權利請關閉 +有查看限制的公會金庫分頁來防止被任何人觀看, +如需要同步時請用手動受權.]=] +L[ [=[Security hint: Only enable this when you actually need to transfer data, +disable otherwise]=] ] = [=[安全性提示: 只有當您需要實際的數據傳輸時才啟用, +反之請關閉它]=] +L["Send account sharing request to:"] = "發送帳戶共享資料的要求:" +L["Sending account sharing request to %s"] = "向%s發送帳戶共享資料的要求" +L["Sending character %s (%d of %d)"] = "發送角色資料 %s (%d 之 %d)" +L["Sending currencies (%d of %d)"] = "發送金錢資料 (%d 之 %d)" +L["Sending guilds (%d of %d)"] = "發送公會資料 (%d 之 %d)" +L["Sending reference data: %s (%d of %d)"] = "發送相關資料: %s (%d of %d)" +L["Sending reputations (%d of %d)"] = "發送聲望資料 (%d 之 %d)" +L["Sending table of content (%d items)"] = "發送列表內容 (%d 物品)" +L["Sever"] = "塞沃爾" +L["Shadoweave"] = "暗影布專精" +L["Shadowforge Cache"] = "破碎項鍊上的紅寶石" +L["Shadow's Embrace"] = "暗影的擁抱" +L["Shaman Set"] = "薩滿套裝" +L["Shared"] = "隨機掉落" +L["Shartuul"] = "夏圖歐" +L["%s has disabled account sharing"] = "%s的帳戶共享資料功能關閉" +L["%s has disabled guild communication"] = "%s關閉公會聯繫" +L["%s has no auctions"] = "%s 沒有拍賣" +L["%s has no bids"] = "%s 沒有競標" +L["%s has no mail"] = "%s 沒有郵件" +L["Shen'dralar Provisioner"] = "辛德拉聖職者" +L["Shift-Click to link this info"] = "Shift-左擊來連結這資訊" +L["Shift+Left click to link"] = "Shift+左鍵點擊可鏈接" +L["show"] = "顯示" +L["Show already known/learnable by"] = "包括已學會/可被學會" +L["Show counters for all accounts"] = "顯示所有帳戶的數值" +L["Show counters for both factions"] = "顯示兩方的聲望數值" +L["Show counters on gathering nodes"] = "在採集點上顯示數量" +L["Show FuBar icon"] = "顯示圖示" +L["Show FuBar text"] = "顯示文字" +L["Show guild bank count"] = "包括公會金庫" +L["Show item count per character"] = "顯示每個角色的物品數量" +L["Show item ID and item level"] = "顯示物品ID和物品等級ILVL" +L["Show item source"] = "顯示物品來源" +L["Show Minimap Icon"] = "顯示小地圖圖示" +L["Show pets already known/learnable by"] = "顯示已學會寵物的有" +L["Show recipes already known/learnable by"] = "顯示已學會食譜的有" +L["Shows the UI"] = "顯示圖形介面" +L["Show total item count"] = "顯示物品總數量" +L["Silverleaf"] = "銀葉草" +L["Silver Vein"] = "銀礦" +L["%s is in combat, request cancelled"] = "%s在戰鬥中, 要求被駁回" +L["%s is now ready (%s on %s)"] = "%s 現準備好 (%s 之 %s)" +L["%s is now unlocked (%s on %s)"] = "%s現在已重置 (%s-%s)" +L["%s is %s with %s (%d/%d)"] = "%s 在 %s 達到 %s (%d/%d)" +L["Skettis"] = "司凱堤斯" +L["Skinning"] = "剝皮" +L["Skyguard Raid"] = "禦天者空防" +L["slots"] = "空格" +L["Small Obsidian Chunk"] = "小型黑曜石礦" +L["Small Thorium Vein"] = "瑟銀礦脈" +L["Smokywood Pastures Extra-Special Gift"] = "燻木牧場的超特別禮物" +L["Smokywood Pastures Vendor"] = "燻木牧場商人" +L["Socket"] = "插糟" +L["Sort loots in descending order"] = "戰利品排序" +L["Sothos & Jarien"] = "索索斯及賈林" +L["Soulcloth Embrace"] = "靈魂布的擁抱" +L["Source"] = "來源" +L["Spawn Of Hakkar"] = "哈卡的後代" +L["Spellfire"] = "魔法布專精" +L["Spellstrike Infusion"] = "法擊套裝" +L["Spirit Towers (Terrokar)"] = "靈魂哨塔(泰羅卡森林,白骨荒野)" +L["%s|r has received a mail from %s"] = "%s|r 已收到的郵件, 寄件者: %s" +L[ [=[%s%s|r has requested the bank tab %s%s|r +Send this information ?]=] ] = [=[%s%s|r 要求公會金庫分頁 %s%s|r +要傳送這項資料嗎 ?]=] +L["%s starts in %d minutes (%s on %s)"] = "%s 在 %d 分鐘后開始 (%s 之 %s)" +L["Started"] = "已啟動" +L["Stasis Chambers"] = "貝許爾的靜止密室" +L["Steamwheedle Cartel"] = "熱砂企業" +L["Storms Deck"] = "風暴套卡" +L["Stormshroud Armor"] = "雷暴護甲" +L["Stranglekelp"] = "荊棘藻" +L["Strength of the Clefthoof"] = "裂蹄力量" +L["Suggested leveling zone: "] = "建議升級的地區" +L["Suggestion"] = "建議" +L["Summary"] = "摘要" +L["Summoner's Tomb"] = "召喚者之墓" +L["Sungrass"] = "太陽草" +L["Superior Rewards"] = "精良獎勵" +L[ [=[%sWarning:|r if you accept, %sALL|r information known +by Altoholic will be sent to %s%s|r (bags, money, etc..)]=] ] = [=[%s警告:|r 如接受, %s所有|r 已知的資料 +會被 Altoholic 傳送給 %s%s|r (背包, 金錢, 等等..)]=] +L["%sWarning:|r make sure this user may view this information before accepting"] = "%s警告:|r 請確定此用戶可以查看分頁的資料才接受" +L["Swiftthistle"] = "雨燕草" +L["%s will be ready in %d minutes (%s on %s)"] = "%s 在 %d 分鐘后準備好 (%s 之 %s)" +L["%s will be unlocked in %d minutes (%s on %s)"] = "%s將在%d分鐘後重置(%s-%s)" +L["Table of content received (%d items)"] = "收到列表的內容(%d 物品)" +L["Tablet of Ryuneh"] = "雷烏納石板" +L["Tablet of Will"] = "意志石板" +L["Tailoring Sets"] = "裁縫套裝" +L["Tank"] = "坦克" +L["T'chali's Voodoo Brewery"] = "提洽里的巫毒釀酒廠" +L["Terocone"] = "泰魯草" +L["Terokk"] = "泰洛克" +L["The Darksoul"] = "黑暗之魂" +L["The Duke of Cinders (Fire)"] = "辛德爾公爵 (火)" +L["The Duke of Fathoms (Water)"] = "深淵公爵 (水)" +L["The Duke of Shards (Earth)"] = "碎石公爵 (土)" +L["The Duke of Zephyrs (Wind)"] = "微風公爵 (風)" +L["Theldren"] = "瑟爾倫" +L[ [=[There is a risk of disconnection if the queried item +is a loot from a high level dungeon. + +]=] ] = [=[如查詢的物品是一件非常高級的副本掉落 +極有可能導至斷線. + +]=] +L["The Unyielding"] = "不屈套裝" +L["The Vault"] = "黑色寶庫" +L["Thick Draenic Armor"] = "厚德萊尼護甲" +L["This account"] = "這個帳號" +L["This character"] = "這角色" +L["This faction"] = "這陣營聲望" +L["This field |cFF00FF00cannot|r be left empty."] = "這欄 |cFF00FF00不能|r 留空." +L[ [=[This name can be anything you like, +it does |cFF00FF00NOT|r have to be the real account name.]=] ] = [=[這個名稱可以隨你歡喜, +並 |cFF00FF00不需要|r 是真實的帳戶名稱.]=] +L["This realm"] = "只搜索這伺服器" +L[ [=[This will gradually improve the consistency of the searches, +as more items are available in the item cache. + +]=] ] = [=[隨著越來越多的項目緩存在本機, +這將逐步改善搜查的效率. + +]=] +L["Thomas Yance"] = "湯瑪斯·陽斯" +L["Thunderbrew Brewery"] = "雷霆啤酒釀造廠" +L["Ticking Present"] = "滴答作響的禮物" +L["Tier 0.5 Quests"] = "T0.5任務" +L["Tier %d Tokens"] = "T%d代換品" +L["Timed Chest"] = "限時任務獎勵箱子" +L["Tin Vein"] = "錫礦" +L["toggle"] = "切換" +L["Toggles the UI"] = "切換圖形介面的顯示/隱藏" +L["Token Hand-Ins"] = "可兌換的獎勵" +L["Tooltip"] = "提示" +L["Total owned"] = "總共擁有" +L["Totals"] = "總數" +L["Transfer complete"] = "傳輸完成" +L["Transmute"] = "轉化" +L["Transparency"] = "透明度" +L["Trash Mobs"] = "一般怪物" +L["Treat Bag"] = "糖果包" +L["Tribal"] = "部族製皮" +L["Tribute Run"] = "貢品" +L["Trinkets"] = "飾品" +L["Troll Mini bosses"] = "食人妖小頭目" +L["Truesilver Deposit"] = "真銀礦石" +L["Twin Spire Ruins"] = "雙塔廢墟" +L["Unknown"] = "未知" +L["Unknown link, please relog this character"] = "不知名的連結, 請重登這角色" +L["Upper Deck"] = "桌面紙牌" +L["up to"] = "最高至" +L["Vakkiz the Windrager"] = "風怒者瓦奇茲" +L["Various Locations"] = "多個地方" +L["View"] = "顯示" +L["View auctions"] = "查看拍賣" +L["View bags"] = "查看背包" +L["View bids"] = "查看競標" +L["View mailbox"] = "查看郵件" +L["View quest log"] = "查看任務日誌" +L["Visited"] = "已到訪" +L["Volcanic Armor"] = "火山護甲" +L["Waiting for %s to accept .."] = "正等待 %s 接收 .." +L["Warlock Set"] = "術士套裝" +L["Warlords Deck"] = "督軍套卡" +L["Warn %d minutes before an event starts"] = "在事件 %d 分鐘開始前發出警告" +L["Warn when mail expires in less days than this value"] = "當郵件屆滿少過此值的日數時發出警告" +L["Warrior Set"] = "戰士套裝" +L["Weapons"] = "武器" +L["Weaponsmith"] = "武器大師" +L["Week starts on Monday"] = "每周從周一開始" +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, all requests will be automatically rejected. + +]=] ] = [=[當 |cFFFF0000關閉|cFFFFFFFF時, 所有帳戶資料要求會被拒. + +]=] +L["When |cFFFF0000disabled|cFFFFFFFF, there will be no communication with the guild."] = "當 |cFFFF0000關閉|cFFFFFFFF時, 將不會有任何公會聯系." +L[ [=[When |cFFFF0000disabled|cFFFFFFFF, your confirmation will be +required before sending any information. + +]=] ] = [=[當 |cFFFF0000關閉|cFFFFFFFF時, 發送任何信息 +之前將需要您的確認. + +]=] +L["Whitemend Wisdom"] = "白癒智慧" +L["Wild Draenish Armor"] = "狂野德萊尼護甲" +L["Wild Steelbloom"] = "野鋼花" +L["Wildvine"] = "野葡萄藤" +L["Will be learnable by "] = "這將以被誰學會:" +L["Will be %sdeleted|r in"] = "將在%s後刪除" +L["Will be %sreturned|r in"] = "將在%s後返回" +L["Windhawk Armor"] = "風之隼護甲" +L["Wintersbite"] = "冬刺草" +L["Winter Veil Gift"] = "冬幕節禮物" +L[" with "] = " 和 " +L["World Drops"] = "世界掉落" +L["World PVP"] = "世界PVP" +L["WoW Collector Edition"] = "魔獸世界收藏版" +L["Wrathbringer Laz-tarash"] = "憤怒使者拉茲泰拉西" +L["Wrath of Spellfire"] = "魔焰之怒" +L["Yor (Heroic Summon)"] = "約兒 (英雄模式召喚)" +L[ [=[You have received an account sharing request +from %s%s|r, accept it?]=] ] = [=[你收到帳戶共享資料的要求 +要求者 %s%s|r, 接受嗎?]=] +L[ [=[Your confirmation will still be required any time someone requests your information. + +]=] ] = [=[可向你發送帳戶資料要求. + +]=] +L["Zelemar the Wrathful"] = "憤怒者塞雷瑪爾" +L["Zone"] = "地區" + diff --git a/Altoholic-Addon/Altoholic/Loots.lua b/Altoholic-Addon/Altoholic/Loots.lua new file mode 100644 index 0000000..98e6806 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Loots.lua @@ -0,0 +1,1185 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BB = LibStub("LibBabble-Boss-3.0"):GetLookupTable() +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" + +-- Simplified loot table containing item ID's only, based on AtlasLoot v5.09.00 +local lootTable = { + + -- to do: HardModeArena & HardModeArena2 from sets_en.lua + -- to do : wotlk crafts + -- to do : pvp non set 80, line 3000 in wotlk.lua of AL 5.04 + -- tier 8 + + -- ** Miscellaneous ** + [L["Bash'ir Landing"]] = { + [L["Skyguard Raid"]] = { 32596, 32600, 32599, 32597, 32634, 32637, 32635, 32636, 32639, 32638, + 32641, 32640, 32759, 32630, 32631, 32627, 32625, 32629, 32628, 32626, 32624 }, + [L["Stasis Chambers"]] = { 32522, 31577, 31569, 31553, 31561}, + }, + [L["Skettis"]] = { + [L["Darkscreecher Akkarai"]] = { 32529, 32715, 31558, 31555, 31566, 31563, 31574, 31571, 31582, 31579, 32514 }, + [L["Karrog"]] = { 32533, 32717, 31558, 31555, 31566, 31563, 31574, 31571, 31582, 31579, 32514 }, + [L["Gezzarak the Huntress"]] = { 32531, 32716, 31558, 31555, 31566, 31563, 31574, 31571, 31582, 31579, 32514 }, + [L["Vakkiz the Windrager"]] = { 32532, 32718, 31558, 31555, 31566, 31563, 31574, 31571, 31582, 31579, 32514 }, + [L["Terokk"]] = { 32540, 32541, 31556, 31564, 31572, 31580, 32535, 32534, 32782, 32536, 32537 } + }, + [L["Ethereum Prison"]] = { + [L["Armbreaker Huffaz"]] = { 31943, 31939, 31938, 31936, 31935, 31937, 31957, 31928, 31929, 31925, 31926, 31927 }, + [L["Fel Tinkerer Zortan"]] = { 31573, 31939, 31938, 31936, 31935, 31937, 31957, 31928, 31929, 31925, 31926, 31927 }, + [L["Forgosh"]] = { 31940, 31939, 31938, 31936, 31935, 31937, 31957, 31928, 31929, 31925, 31926, 31927 }, + [L["Gul'bor"]] = { 31940, 31939, 31938, 31936, 31935, 31937, 31957, 31928, 31929, 31925, 31926, 31927 }, + [L["Malevus the Mad"]] = { 31581, 31939, 31938, 31936, 31935, 31937, 31957, 31928, 31929, 31925, 31926, 31927 }, + [L["Porfus the Gem Gorger"]] = { 31557, 31939, 31938, 31936, 31935, 31937, 31957, 31928, 31929, 31925, 31926, 31927 }, + [L["Wrathbringer Laz-tarash"]] = { 32520, 31939, 31938, 31936, 31935, 31937, 31957, 31928, 31929, 31925, 31926, 31927 } + }, + [L["Abyssal Council"] .. " (" .. BZ["Silithus"] .. ")"] = { + [L["Crimson Templar (Fire)"]] = { 20657, 20655, 20656 }, + [L["Azure Templar (Water)"]] = { 20654, 20652, 20653 }, + [L["Hoary Templar (Wind)"]] = { 20658, 20659, 20660 }, + [L["Earthen Templar (Earth)"]] = { 20661, 20662, 20663 }, + [L["The Duke of Cinders (Fire)"]] = { 20665, 20666, 20514, 20664, 21989 }, + [L["The Duke of Fathoms (Water)"]] = { 20668, 20669, 20514, 20667 }, + [L["The Duke of Zephyrs (Wind)"]] = { 20674, 20675, 20514, 20673 }, + [L["The Duke of Shards (Earth)"]] = { 20671, 20672, 20514, 20670 }, + [BB["Prince Skaldrenox"] .. " (Fire)"] = { 20682, 20515, 20681, 20680 }, + [BB["Lord Skwol"] .. " (Water)"] = { 20685, 20515, 20684, 20683 }, + [BB["High Marshal Whirlaxis"] .. " (Wind)"] = { 20691, 20515, 20690, 20689 }, + [BB["Baron Kazum"] .. " (Earth)"] = { 20688, 20515, 20686, 20687 } + }, + [L["Elemental Invasion"]] = { + [BB["Baron Charr"] .. " (" .. BZ["Un'Goro Crater"] .. ")"] = { 18671, 19268, 18672 }, + [BB["Princess Tempestria"] .. " (" .. BZ["Winterspring"] .. ")"] = { 18678, 19268, 21548, 18679 }, + [BB["Avalanchion"] .. " (" .. BZ["Azshara"] .. ")"] = { 18673, 19268, 18674 }, + [BB["The Windreaver"] .. " (" .. BZ["Silithus"] .. ")"] = { 18676, 19268, 21548, 18677 } + }, + [L["Gurubashi Arena"]] = { + [L["Booty Run"]] = { 18709, 18710, 18711, 18712, 18706, 19024 } + }, + [L["Fishing Extravaganza"]] = { + [L["First Prize"]] = { 19970, 19979 }, + [L["Rare Fish"]] = { 19805, 19803, 19806, 19808 }, + [L["Rare Fish Rewards"]] = { 19972, 19969, 19971 } + }, + [L["Children's Week"]] = { + [BZ["Azeroth"]] = { 23007, 23015, 23002, 23022 }, + [BZ["Outland"]] = { 32616, 32622, 32617 } + }, + [L["Love is in the air"]] = { + [L["Gift of Adoration"]] = { 34480, 22279, 22235, 22200, 22261, 22218, 21813, 34258 }, + [L["Box of Chocolates"]] = { 22237, 22238, 22236, 22239 }, + [L["Quest rewards"]] = { 22276, 22278, 22280, 22277, 22281, 22282 } + }, + [L["Hallow's End"]] = { + [L["Various Locations"]] = { 33117, 20400, 18633, 18632, 18635, 20557 }, + [L["Treat Bag"]] = { 20410, 20409, 20399, 20398, 20397, 20413, 20411, 20414, 20389, 20388, + 20390, 20561, 20391, 20566, 20564, 20570, 20572, 20568, 20573, 20562, + 20392, 20565, 20563, 20569, 20571, 20567, 20574 }, + [L["Headless Horseman"]] = { 33808, 34075, 34073, 34074, 33292, 33154, 34068, 33226, 33182, 33184, + 33176, 33183, 33189 } + }, + [L["Feast of Winter Veil"]] = { + [L["Various Locations"]] = { 21525, 21524, 17712, 17202, 34191, 21212, 21519 }, + [L["Smokywood Pastures Vendor"]] = { 34262, 34319, 34261, 34413, 17201, 17200, 17344, 17406, 17407, 17408, + 34410, 17404, 17405, 34412, 17196, 17403, 17402, 17194, 17303, 17304, 17307 }, + [L["Gaily Wrapped Present"]] = { 21301, 21308, 21305, 21309 }, + [L["Festive Gift"]] = { 21328 }, + [L["Winter Veil Gift"]] = { 34425 }, + [L["Gently Shaken Gift"]] = { 21235, 21241 }, + [L["Ticking Present"]] = { 21325, 21213, 17706, 17725, 17720, 17722, 17709, 17724 }, + [L["Carefully Wrapped Present"]] = { 21254 }, + [L["Smokywood Pastures Extra-Special Gift"]] = { 21215 } + }, + [L["Noblegarden"]] = { + [L["Brightly Colored Egg"]] = { 19028, 6833, 6835, 7807, 7808, 7806 } + }, + [L["Harvest Festival"]] = { + [L["Quest rewards"]] = { 19697, 20009, 20010 }, + [L["Food"]] = { 19994, 19995, 19996, 19997 } + }, + [L["Scourge Invasion"]] = { + [L["Miscellaneous"]] = { 23123, 23122, 22999, 23194, 23195, 23196 }, + [L["Cloth Set"]] = { 23085, 23091, 23084 }, + [L["Leather Set"]] = { 23089, 23093, 23081 }, + [L["Mail Set"]] = { 23088, 23092, 23082 }, + [L["Plate Set"]] = { 23087, 23090, 23078 }, + [L["Balzaphon"]] = { 23126, 23125, 23124 }, + [L["Lord Blackwood"]] = { 23156, 23132, 23139 }, + [L["Revanchion"]] = { 23127, 23129, 23128 }, + [L["Scorn"]] = { 23170, 23169, 23168 }, + [L["Sever"]] = { 23173, 23171 }, + [L["Lady Falther'ess"]] = { 23178, 23177 } + }, + [L["Lunar Festival"]] = { + [L["Miscellaneous"]] = { 21540, 21157, 21538, 21539, 21541, 21544, 21543, 21537, 21713, 21100 }, + [L["Fireworks Pack"]] = { 21558, 21559, 21557, 21561, 21562, 21589, 21590, 21592, 21593, 21595 }, + [L["Lucky Red Envelope"]] = { 21744, 21745 }, + [BI["Engineering"]] = { 21738, 21724, 21725, 21726, 21727, 21728, 21729, 21737, 21730, 21731, + 21732, 21733, 21734, 21735 }, + [BI["Tailoring"]] = { 21722, 21723 } + }, + [L["Midsummer Fire Festival"]] = { + [L["Miscellaneous"]] = { 34686, 23379, 23083, 23247, 23246, 23435, 23327, 23326, + 23211, 34684, 23323, 23324, 34685, 34683 }, + [L["Lord Ahune"]] = { 35494, 35495, 35496, 35497, 35498, 35514, 35723, 34955, 35279, 35280 }, + [L["Lord Ahune"] .. L[" (Heroic)"]] = { 35507, 35509, 35508, 35511, 35498, 34955, 35723, 35279, 35280, 35497, + 35496, 35494, 35495, 35514 } + }, + [L["Shartuul"]] = { + [L["Blade Edge Mountains"]] = { 32941, 32676, 32675, 32677, 32678, 32672, 32673, 32674, 32670, 32671, + 32679, 32942, 32655, 32656, 32665, 32664, 32658, 32659, 32660, 32663, + 32661, 32662 } + }, + [L["Brewfest"]] = { + [L["Miscellaneous"]] = { 33927, 33047, 33968, 33864, 33967, 33969, 33862, 33863, 33868, 33966, + 33978, 33977, 33976, 32912, 34140, 32233, 33455, 34063, 34064, 33023, + 33024, 33025, 33026, 33043, 33929 }, + [L["Barleybrew Brewery"]] = { 33030, 33028, 33029 }, + [L["Thunderbrew Brewery"]] = { 33031, 33032, 33033 }, + [L["Gordok Brewery"]] = { 33034, 33036, 33035 }, + ["Coren Direbrew"] = { 37127, 38289, 38290, 38288, 38287, 37597 }, + [L["Drohn's Distillery"]] = { 34017, 34018, 34019 }, + [L["T'chali's Voodoo Brewery"]] = { 34020, 34021, 34022 } + }, + + -- ** Sets & PVP *** + [BZ["Alterac Valley"]] = { + [L["Miscellaneous"].." (" .. FACTION_ALLIANCE .. ")"] = { 19045, 19032 }, + [L["Miscellaneous"].." (" .. FACTION_HORDE .. ")"] = { 19046, 19031 }, + [L["Miscellaneous"]] = { 19316, 17348, 17349, 19301, 19307, 19317, 17351, 17352, 19318 }, + [L["Superior Rewards"].." (" .. FACTION_ALLIANCE .. ")"] = { 19086, 19084, 19094, 19093, 19092, 19091, 19098, 19097, 19100, 19104, + 19102, 19320, 19319 }, + [L["Superior Rewards"].." (" .. FACTION_HORDE .. ")"] = { 19085, 19083, 19090, 19089, 19088, 19087, 19096, 19095, 19099, 19103, + 19101, 19320, 19319 }, + [L["Epic Rewards"].." (" .. FACTION_ALLIANCE .. ")"] = { 19030 }, + [L["Epic Rewards"].." (" .. FACTION_HORDE .. ")"] = { 19029 }, + [L["Epic Rewards"]] = { 19325, 19312, 19308, 19309, 19324, 19321, 21563, 19315, 19311, 19310, 19323 } + }, + [BZ["Arathi Basin"]] = { + [L["Miscellaneous"].." (" .. FACTION_ALLIANCE .. ")"] = { 17349, 17352, 20225, 20227, 20226, 20243, 20237, 20244 }, + [L["Miscellaneous"].." (" .. FACTION_HORDE .. ")"] = { 17349, 17352, 20222, 20224, 20223, 20234, 20232, 20235 }, + [format(L["Lv %s Rewards"], "20-29").." (" .. FACTION_ALLIANCE .. ")"] = { 20099, 20096, 20117, 20105, 20120, 20090, 20114, 20102, 20123, 20093, + 20108, 20126, 20111, 20129, 21119 }, + [format(L["Lv %s Rewards"], "20-29").." (" .. FACTION_HORDE .. ")"] = { 20164, 20162, 20191, 20172, 20152, 20197, 20188, 20169, 20201, 20157, + 20178, 20207, 20182, 20210, 21120 }, + [format(L["Lv %s Rewards"], "30-39").." (" .. FACTION_ALLIANCE .. ")"] = { 20098, 20095, 20116, 20104, 20113, 20101, 21118 }, + [format(L["Lv %s Rewards"], "30-39").." (" .. FACTION_HORDE .. ")"] = { 20166, 20161, 20192, 20173, 20187, 20168, 21116 }, + [format(L["Lv %s Rewards"], "40-49").." (" .. FACTION_ALLIANCE .. ")"] = { 20097, 20094, 20115, 20103, 20112, 20100, 20089, 20088, 20119, 20118, + 20092, 20091, 20122, 20121, 20107, 20106, 20125, 20124, 20110, 20109, + 20128, 20127, 21117 }, + [format(L["Lv %s Rewards"], "40-49").." (" .. FACTION_HORDE .. ")"] = { 20165, 20160, 20193, 20174, 20189, 20170, 20153, 20151, 20198, 20196, + 20156, 20155, 20200, 20202, 20180, 20179, 20206, 20205, 20183, 20185, + 20209, 20211, 21115 }, + [format(L["Lv %s Rewards"], "50-59").." (" .. FACTION_ALLIANCE .. ")"] = { 20047, 20054, 20045, 20046, 20052, 20053, 20043, 20050, 20042, 20041, + 20049, 20048, 20071 }, + [format(L["Lv %s Rewards"], "50-59").." (" .. FACTION_HORDE .. ")"] = { 20163, 20159, 20190, 20171, 20186, 20167, 20150, 20195, 20154, 20199, + 20204, 20208, 20072 }, + [format(L["Lv %s Rewards"], "60").." (" .. FACTION_ALLIANCE .. ")"] = { 20073, 20061, 20059, 20060, 20055, 20056, 20058, 20057, 20070, 20069 }, + [format(L["Lv %s Rewards"], "60").." (" .. FACTION_HORDE .. ")"] = { 20068, 20176, 20194, 20175, 20158, 20203, 20212, 20214, 20220 }, + [L["PVP Cloth Set"].." (" .. FACTION_ALLIANCE .. ")"] = { 20061, 20047, 20054 }, + [L["PVP Cloth Set"].." (" .. FACTION_HORDE .. ")"] = { 20176, 20163, 20159 }, + [L["PVP Leather Sets"].." (" .. FACTION_ALLIANCE .. ")"] = { 20059, 20045, 20052, 20060, 20046, 20053 }, + [L["PVP Leather Sets"].." (" .. FACTION_HORDE .. ")"] = { 20194, 20190, 20186, 20175, 20171, 20167 }, + [L["PVP Mail Sets"].." (" .. FACTION_ALLIANCE .. ")"] = { 20055, 20043, 20050, 20056, 20044, 20051 }, + [L["PVP Mail Sets"].." (" .. FACTION_HORDE .. ")"] = { 20158, 20150, 20154, 20203, 20195, 20199 }, + [L["PVP Plate Sets"].." (" .. FACTION_ALLIANCE .. ")"] = { 20057, 20041, 20048, 20058, 20042, 20049 }, + [L["PVP Plate Sets"].." (" .. FACTION_HORDE .. ")"] = { 20212, 20204, 20208 } + }, + [BZ["Warsong Gulch"]] = { + [L["Miscellaneous"].." (" .. FACTION_ALLIANCE .. ")"] = { 19506 }, + [L["Miscellaneous"].." (" .. FACTION_HORDE .. ")"] = { 19505 }, + [L["Miscellaneous"]] = { 17348, 17349, 19060, 19062, 19067, 17351, 17352, 19061, 19066, 19068 }, + [format(L["Lv %s Rewards"], "10-19").." (" .. FACTION_ALLIANCE .. ")"] = { 20428, 20444, 20431, 20439, 20443, 20440, 20434, 20438 }, + [format(L["Lv %s Rewards"], "10-19").." (" .. FACTION_HORDE .. ")"] = { 20427, 20442, 20426, 20429, 20441, 20430, 20425, 20437 }, + [format(L["Lv %s Rewards"], "20-29").." (" .. FACTION_ALLIANCE .. ")"] = { 19533, 19541, 19525, 19517, 21568, 21566, 19549, 19557, 19573, 19565 }, + [format(L["Lv %s Rewards"], "20-29").." (" .. FACTION_HORDE .. ")"] = { 19529, 19537, 19521, 19513, 21568, 21566, 19545, 19553, 19569, 19561 }, + [format(L["Lv %s Rewards"], "30-39").." (" .. FACTION_ALLIANCE .. ")"] = { 19532, 19540, 19524, 19515, 19548, 19556, 19572, 19564 }, + [format(L["Lv %s Rewards"], "30-39").." (" .. FACTION_HORDE .. ")"] = { 19528, 19536, 19520, 19512, 19544, 19552, 19568, 19560 }, + [format(L["Lv %s Rewards"], "40-49").." (" .. FACTION_ALLIANCE .. ")"] = { 19597, 19590, 19584, 19581, 19531, 19539, 19523, 19516, 21567, 21565, + 19547, 19555, 19571, 19563 }, + [format(L["Lv %s Rewards"], "40-49").." (" .. FACTION_HORDE .. ")"] = { 19597, 19590, 19584, 19581, 19527, 19535, 19519, 19511, 21567, 21565, + 19543, 19551, 19567, 19559 }, + [format(L["Lv %s Rewards"], "50-59").." (" .. FACTION_ALLIANCE .. ")"] = { 19596, 19589, 19583, 19580, 19530, 19538, 19522, 19514, 19546, 19554, 19570, 19562 }, + [format(L["Lv %s Rewards"], "50-59").." (" .. FACTION_HORDE .. ")"] = { 19596, 19589, 19583, 19580, 19526, 19534, 19518, 19510, 19542, 19550, + 19566, 19558 }, + [format(L["Lv %s Rewards"], "60").." (" .. FACTION_ALLIANCE .. ")"] = { 19595, 22752, 19587, 22749, 22750, 19582, 22748, 30497, 19578, 22753, 22672 }, + [format(L["Lv %s Rewards"], "60").." (" .. FACTION_HORDE .. ")"] = { 19595, 22747, 19587, 22740, 22741, 19582, 22673, 22676, 19578, 30498, 22651 } + }, + [L["World PVP"]] = { + [L["Hellfire Fortifications"]] = { 27833, 27786, 28360, 27830, 27785, 27777, 24520, 24579, 24522, 24581 }, + [L["Twin Spire Ruins"]] = { 27990, 27984, 27922, 27929, 27939, 27983, 27920, 27927, 27930 }, + [L["Spirit Towers (Terrokar)"]] = { 28553, 28557, 28759, 28574, 28575, 28577, 28560, 28761, 32947, 28555, + 28556, 28760, 28561, 28576, 28758, 28559, 32948 }, + [L["Halaa (Nagrand)"]] = { 28915, 27679, 27649, 27648, 27650, 27647, 27652, 27654, 27653, 24208, + 29228, 27680, 27638, 27645, 27637, 27646, 27643, 27644, 27639, 33783, + 32071, 30611, 30615, 30598, 30597, 30599, 30612, 30571, 30570, 30568 } + }, + + [format(L["Arena Season %d"], 1)] = { + [L["Druid Set"]] = { 28127, 28129, 28130, 28126, 28128, 28137, 28139, 28140, 28136, 28138, + 31376, 31378, 31379, 31375, 31377 }, + [L["Hunter Set"]] = { 28331, 28333, 28334, 28335, 28332 }, + [L["Mage Set"]] = { 25855, 25854, 25856, 25857, 25858 }, + [L["Paladin Set"]] = { 27704, 27706, 27702, 27703, 27705, 27881, 27883, 27879, 27880, 27882, + 31616, 31619, 31613, 31614, 31618 }, + [L["Priest Set"]] = { 27708, 27710, 27711, 27707, 27709, 31410, 31412, 31413, 31409, 31411 }, + [L["Rogue Set"]] = { 25830, 25832, 25831, 25834, 25833 }, + [L["Shaman Set"]] = { 25998, 25999, 25997, 26000, 26001,27471, 27473, 27469, 27470, 27472, + 31400, 31407, 31396, 31397, 31406 }, + [L["Warlock Set"]] = { 24553, 24554, 24552, 24556, 24555, 30187, 30186, 30200, 30188, 30201 }, + [L["Warrior Set"]] = { 24545, 24546, 24544, 24549, 24547 }, + [L["Weapons"]] = { 28313, 28314, 28297, 28312, 28310, 28295, 28307, 24550, 28308, 28309, + 28298, 32450, 32451, 28305, 28302, 28299, 28476, 28300, 24557, 28358, + 28319, 28294, 28320, 28346, 32452, 33945, 33942, 28355, 33936, 28356, + 33948, 33939, 33951, 28357 } + }, + [format(L["Arena Season %d"], 2)] = { + [L["Druid Set"]] = { 31968, 31971, 31972, 31967, 31969, 32057, 32059, 32060, 32056, 32058, + 31988, 31990, 31991, 31987, 31989 }, + [L["Hunter Set"]] = { 31962, 31964, 31960, 31961, 31963 }, + [L["Mage Set"]] = { 32048, 32047, 32050, 32049, 32051 }, + [L["Paladin Set"]] = { 31997, 31996, 31992, 31993, 31995, 32041, 32043, 32039, 32040, 32042, + 32022, 32024, 32020, 32021, 32023 }, + [L["Priest Set"]] = { 32035, 32037, 32038, 32034, 32036, 32016, 32018, 32019, 32015, 32017 }, + [L["Rogue Set"]] = { 31999, 32001, 32002, 31998, 32000 }, + [L["Shaman Set"]] = { 32006, 32008, 32004, 32005, 32007, 32011, 32013, 32009, 32010, 32012, + 32031, 32033, 32029, 32030, 32032 }, + [L["Warlock Set"]] = { 31974, 31976, 31977, 31973, 31975, 31980, 31979, 31982, 31981, 31983 }, + [L["Warrior Set"]] = { 30488, 30490, 30486, 30487, 30489 }, + [L["Weapons"]] = { 32028, 32003, 32053, 32044, 32046, 32052, 32027, 31984, 31965, 31985, + 31966, 32963, 32964, 32026, 31958, 31959, 32014, 32025, 32055, 33313, + 33309, 32045, 32054, 31986, 32962, 31978, 32961, 33946, 33943, 33076, + 33937, 33077, 33949, 33940, 33952, 33078 } + }, + [format(L["Arena Season %d"], 3)] = { + [L["Druid Set"]] = { 33672, 33674, 33675, 33671, 33673, 33768, 33770, 33771, 33767, 33769, + 33691, 33693, 33694, 33690, 33692 }, + [L["Hunter Set"]] = { 33666, 33668, 33664, 33665, 33667 }, + [L["Mage Set"]] = { 33758, 33757, 33760, 33759, 33761 }, + [L["Paladin Set"]] = { 33697, 33699, 33695, 33696, 33698, 33751, 33753, 33749, 33750, 33752, + 33724, 33726, 33722, 33723, 33725 }, + [L["Priest Set"]] = { 33745, 33747, 33748, 33744, 33746, 33718, 33720, 33721, 33717, 33719 }, + [L["Rogue Set"]] = { 33701, 33703, 33704, 33700, 33702 }, + [L["Shaman Set"]] = { 33708, 33710, 33706, 33707, 33709, 33713, 33715, 33711, 33712, 33714, + 33740, 33742, 33738, 33739, 33741 }, + [L["Warlock Set"]] = { 33677, 33679, 33680, 33676, 33678, 33683, 33682, 33685, 33684, 33686 }, + [L["Warrior Set"]] = { 33730, 33732, 33728, 33729, 33731 }, + [L["Weapons"]] = { 33737, 33705, 34016, 33763, 33754, 33801, 33756, 33762, 33734, 33688, + 33669, 34015, 33689, 33670, 34014, 33687, 33743, 33733, 33662, 33663, + 33727, 34540, 33716, 33766, 33661, 33735, 33755, 33765, 34529, 33006, + 34530, 34059, 34066, 33764, 33681, 34033, 33736, 33947, 33944, 33841, + 33938, 33842, 33950, 33941, 33953, 33843 } + }, + [format(L["Arena Season %d"], 4)] = { + [L["Druid Set"]] = { 34999, 35001, 35002, 34998, 35000, 35112, 35114, 35115, 35111, 35113, + 35023, 35025, 35026, 35022, 35024 }, + [L["Hunter Set"]] = { 34992, 34994, 34990, 34991, 34993 }, + [L["Mage Set"]] = { 35097, 35096, 35099, 35098, 35100 }, + [L["Paladin Set"]] = { 35029, 35031, 35027, 5028, 35030, 35090, 35092, 35088, 35089, 35091, + 35061, 35063, 35059, 35060, 35062 }, + [L["Priest Set"]] = { 35084, 35086, 35087, 35083, 35085, 35054, 35056, 35057, 35053, 35055 }, + [L["Rogue Set"]] = { 35033, 35035, 35036, 35032, 35034 }, + [L["Shaman Set"]] = { 35044, 35046, 35042, 35043, 35045, 35050, 35052, 35048, 35049, 35051, + 35079, 35081, 35077, 35078, 35080 }, + [L["Warlock Set"]] = { 35004, 35006, 35007, 35003, 35005, 35010, 35009, 35012, 35011, 35013 }, + [L["Warrior Set"]] = { 35068, 35070, 35066, 35067, 35069 }, + [L["Weapons"]] = { 35076, 35038, 35037, 35102, 37739, 35093, 35058, 35095, 35101, 35072, + 35015, 34996, 34995, 35017, 34997, 35110, 35014, 35082, 37740, 35071, + 34988, 34989, 35064, 34987, 35103, 35109, 34986, 35073, 35094, 35108, + 35047, 35018, 35075, 34985, 35065, 35107, 35008, 35016, 35074, 35019, + 35020, 35021, 35039, 35040, 35041, 35104, 35105, 35106 } + }, + [format(L["Arena Season %d"], 5)] = { + [L["Death Knight"]] = { + 40817, 40857, 40779, 40799, 40837, 40820, 40860, 40781, 40803, 40841, 40824, 40863, 40784, 40806, 40845 + }, + [L["Druid Set"]] = { + 41324, 41278, 41313, 41290, 41301, 41325, 41279, 41314, 41291, 41302, 41326, 41280, 41315, 41292, 41303, -- balance + 41675, 41712, 41658, 41770, 41664, 41676, 41713, 41659, 41771, 41665, 41677, 41714, 41660, 41772, 41666, -- feral + 41269, 41271, 41272, 41268, 41270, 41319, 41273, 41308, 41284, 41296, 41320, 41274, 41309, 41286, 41297 -- resto + }, + [L["Hunter Set"]] = { + 41154, 41214, 41084, 41140, 41202, 41155, 41215, 41085, 41141, 41203, 41156, 41216, 41086, 41142, 41204 + }, + [L["Mage Set"]] = { + 41943, 41962, 41949, 41968, 41956, 41944, 41963, 41950, 41969, 41957, 41945, 41964, 41951, 41970, 41958 + }, + [L["Paladin Set"]] = { + 40818, 40858, 40780, 40798, 40838, 40821, 40861, 40782, 40802, 40842, 40825, 40864, 40785, 40805, 40846, -- retrib + 40930, 40960, 40898, 40918, 40936, 40931, 40961, 40904, 40925, 40937, 40932, 40962, 40905, 40926, 40938 -- holy + }, + [L["Priest Set"]] = { + 41912, 41930, 41918, 41937, 41924, 41913, 41931, 41919, 41938, 41925, 41914, 41933, 41920, 41939, 41926, -- shadow + 41848, 41850, 41851, 41847, 41849, 41852, 41867, 41857, 41872, 41862, 41853, 41868, 41858, 41873, 41863, -- holy + }, + [L["Rogue Set"]] = { + 41644, 41646, 41647, 41643, 41645, 41670, 41681, 41648, 41765, 41653, 41671, 41682, 41649, 41766, 41654 + }, + [L["Shaman Set"]] = { + 41016, 41041, 40987, 41004, 41030, 41017, 41042, 40989, 41005, 41031, 41018, 41043, 40991, 41006, 41032, -- elem + 41148, 41208, 41078, 41134, 41160, 41149, 41209, 41079, 41135, 41162, 41150, 41210, 41080, 41136, 41198, -- enh + 41010, 41024, 40986, 40998, 41023, 41011, 41036, 40988, 40999, 41025, 41012, 41037, 40990, 41000, 41026 -- resto + }, + [L["Warlock Set"]] = { + 41990, 42008, 41996, 42014, 42002, 41991, 42009, 42001, 42015, 42003, 41992, 42010, 41997, 42016, 42004 + }, + [L["Warrior Set"]] = { + 40816, 40856, 40778, 40797, 40836, 40819, 40859, 40783, 40801, 40840, 40823, 40862, 40786, 40804, 40844 + }, + + }, + [format(L["Arena Season %d"], 6)] = { + [L["Death Knight"]] = { 40827, 40868, 40787, 40809, 40848 }, + [L["Druid Set"]] = { 41327, 41281, 41316, 41293, 41304, 41678, 41715, 41661, 41773, 41667, + 41321, 41275, 41310, 41287, 41298 }, + [L["Hunter Set"]] = { 41157, 41217, 41087, 41143, 41205 }, + [L["Mage Set"]] = { 41946, 41965, 41953, 41971, 41959 }, + [L["Paladin Set"]] = { 40828, 40869, 40788, 40808, 40849, 40933, 40963, 40907, 40927, 40939 }, + [L["Priest Set"]] = { 41915, 41934, 41921, 41940, 41927, 41854, 41869, 41859, 41874, 41864 }, + [L["Rogue Set"]] = { 41672, 41683, 41650, 41767, 41655 }, + [L["Shaman Set"]] = { 41019, 41044, 40993, 41007, 41033, 41151, 41211, 41081, 41137, 41199, + 41013, 41038, 40992, 41001, 41027 }, + [L["Warlock Set"]] = { 41993, 42011, 41998, 42017, 42005 }, + [L["Warrior Set"]] = { 40826, 40866, 40789, 40807, 40847 }, + }, + [format(L["Arena Season %d"], 7)] = { + [L["Death Knight"]] = { 40830, 40871, 40791, 40811, 40851 }, + [L["Druid Set"]] = { 41328, 41282, 41317, 41294, 41305, 41679, 41716, 41662, 41774, 41668, + 41322, 41276, 41311, 41288, 41299 }, + [L["Hunter Set"]] = { 41158, 41218, 41088, 41144, 41206 }, + [L["Mage Set"]] = { 41947, 41966, 41954, 41972, 41960 }, + [L["Paladin Set"]] = { 40831, 40872, 40792, 40812, 40852, 40934, 40964, 40910, 40928, 40940 }, + [L["Priest Set"]] = { 41916, 41935, 41922, 41941, 41928, 41855, 41870, 41860, 41875, 41865 }, + [L["Rogue Set"]] = { 41673, 41684, 41651, 41768, 41656 }, + [L["Shaman Set"]] = { 41020, 41045, 40995, 41008, 41034, 41152, 41212, 41082, 41138, 41200, + 41014, 41039, 40994, 41002, 41028 }, + [L["Warlock Set"]] = { 41994, 42012, 41999, 42018, 42006 }, + [L["Warrior Set"]] = { 40829, 40870, 40790, 40810, 40850 }, + }, + + [format(L["Level %d Honor PVP"], 60)] = { + [L["Druid Set"]] = { 16451, 16449, 16452, 16448, 16450, 16459, 23308, 23309, 23294, 23280, + 23295, 23281, 16550, 16551, 16549, 16555, 16552, 16554, 23253, 23254, + 22877, 22863, 22878, 22852 }, + [L["Hunter Set"]] = { 16465, 16468, 16466, 16463, 16467, 16462, 23306, 23307, 23292, 23279, + 23293, 23278, 16566, 16568, 16565, 16571, 16567, 16569, 23251, 23252, + 22874, 22862, 22875, 22843 }, + [L["Mage Set"]] = { 16441, 16444, 16443, 16440, 16442, 16437, 23318, 23319, 23305, 23290, + 23304, 23291, 16533, 16536, 16535, 16540, 16534, 16539, 23263, 23264, + 22886, 22870, 22883, 22860 }, + [L["Paladin Set"]] = { 16474, 16476, 16473, 16471, 16475, 16472, 23276, 23277, 23272, 23274, + 23273, 23275, 29616, 29617, 29615, 29613, 29614, 29612, 29604, 29605, + 29602, 29600, 29603, 29601 }, + [L["Priest Set"]] = { 17602, 17604, 17605, 17608, 17603, 17607, 23316, 23317, 23303, 23288, + 23302, 23289, 17623, 17622, 17624, 17620, 17625, 17618, 23261, 23262, + 22885, 22869, 22882, 22859 }, + [L["Rogue Set"]] = { 16455, 16457, 16453, 16454, 16456, 16446, 23312, 23313, 23298, 23284, + 23299, 23285, 16561, 16562, 16563, 16560, 16564, 16558, 23257, 23258, + 22879, 22864, 22880, 22856 }, + [L["Shaman Set"]] = { 29610, 29611, 29609, 29607, 29608, 29606, 29598, 29599, 29596, 29595, + 29597, 29594, 16578, 16580, 16577, 16574, 16579, 16573, 23259, 23260, + 22876, 22867, 22887, 22857 }, + [L["Warlock Set"]] = { 17578, 17580, 17581, 17584, 17579, 17583, 23310, 23311, 23297, 23282, + 23296, 23283, 17591, 17590, 17592, 17588, 17593, 17586, 23255, 23256, + 22884, 22865, 22881, 22855 }, + [L["Warrior Set"]] = { 16478, 16480, 16477, 16484, 16479, 16483, 23314, 23315, 23300, 23286, + 23301, 23287, 16542, 16544, 16541, 16548, 16543, 16545, 23244, 23243, + 22872, 22868, 22873, 22858 }, + [L["Weapons"] .. " (" .. FACTION_ALLIANCE .. ")"] = { 18843, 18847, 23451, 18838, 12584, 23456, 18876, 18827, 18830, 23454, + 18865, 18867, 23455, 18869, 18873, 18825, 18833, 18836, 18855, 23452, 23453 }, + [L["Weapons"] .. " (" .. FACTION_HORDE .. ")"] = { 18844, 18848, 23466, 18840, 16345, 23467, 18877, 18828, 18831, 23464, + 18866, 18868, 23465, 18871, 18874, 18826, 18835, 18837, 18860, 23468, 23469 }, + [L["Accessories"] .. " (" .. FACTION_ALLIANCE .. ")"] = { 29465, 29467, 29468, 29471, 35906, 18863, 18856, 18859, 18864, 18862, + 18857, 29593, 18858, 18854, 18440, 18441, 16342, 18457, 18456, 18455, + 18454, 18453, 18452, 18449, 18448, 18447, 18445, 18442, 18444, 18443, + 15196, 15198, 18606, 18839, 18841, 32455 }, + [L["Accessories"] .. " (" .. FACTION_HORDE .. ")"] = { 29466, 29469, 29470, 29472, 34129, 18853, 18846, 18850, 29592, 18851, + 18849, 18845, 18852, 18834, 18427, 16341, 18461, 18437, 16486, 18436, + 18434, 18435, 16497, 18432, 16532, 18430, 18429, 15200, 18428, 16335, + 15197, 15199, 18607, 18839, 18841, 32455 } + }, + [L["Level 70 Reputation PVP"]] = { + [L["Druid Set"]] = { 35357, 35359, 35360, 35356, 35358, 35372, 35374, 35375, 35371, 35373, + 35362, 35364, 35365, 35361, 35363, 35469, 35470, 35471 }, + [L["Hunter Set"]] = { 35378, 35380, 35376, 35377, 35379, 35475 }, + [L["Mage Set"]] = { 35344, 35343, 35346, 35345, 35347, 35465 }, + [L["Paladin Set"]] = { 35414, 35416, 35412, 35413, 35415, 35404, 35406, 35402, 35403, 35405, 35476, 35477 }, + [L["Priest Set"]] = { 35339, 35341, 35342, 35338, 35340, 35333, 35336, 35337, 35335, 35334, 35467, 35466 }, + [L["Rogue Set"]] = { 35367, 35369, 35370, 35366, 35368, 35468 }, + [L["Shaman Set"]] = { 35383, 35385, 35381, 35382, 35384, 35388, 35390, 35386, 35387, 35389, + 35393, 35395, 35391, 35392, 35394, 35472, 35473, 35474 }, + [L["Warlock Set"]] = { 35329, 35331, 35332, 35328, 35330, 35464 }, + [L["Warrior Set"]] = { 35409, 35411, 35407, 35408, 35410, 35478 } + }, + [format(L["Level %d Honor PVP"], 70)] = { + [L["Weapons"] .. " (" .. FACTION_ALLIANCE .. ")"] = { 28953, 28947, 28957, 28954, 28955, 28956, 28952, 28943, 28944, 28946, + 28945, 28950, 28951, 28942, 28948, 28949, 28959, 28940, 28960, 28941 }, + [L["Weapons"] .. " (" .. FACTION_HORDE .. ")"] = { 28928, 28922, 28931, 28929, 28930, 28937, 28926, 28293, 28920, 28921, + 28918, 28924, 28925, 28917, 28919, 28923, 28935, 28939, 28933, 28938 }, + [L["Accessories"] .. " (" .. FACTION_ALLIANCE .. ")"] = { 25829, 28235, 28237, 28238, 28236, 30349, 28234, 30351, 30348, 30350, + 28246, 28247 }, + [L["Accessories"] .. " (" .. FACTION_HORDE .. ")"] = { 24551, 28241, 28243, 28239, 28242, 30346, 28240, 30345, 30343, 30344, + 28246, 28247 }, + [L["Accessories"]] = { 28362, 28119, 28363, 31853, 31839, 31855, 31841, 32453, 28118, 28120, + 28123, 31838, 31852, 31840, 31854 }, + [L["Non Set Accessories"]] = { 28378, 28377, 33920, 33921, 33922, 35317, 35319, 33923, 33056, 33064, + 33057, 34576, 34577, 34578, 35326, 34579, 34580, 33853, 33918, 35320, 33919 }, + [L["Non Set Cloth"]] = { 33883, 33882, 33884, 33901, 33900, 33902, 33913, 33912, 33914 }, + [L["Non Set Leather"]] = { 33881, 33879, 33880, 33887, 33885, 33886, 33893, 33891, 33892, 33917, + 33915, 33916 }, + [L["Non Set Mail"]] = { 33876, 33877, 33878, 33894, 33895, 33896, 33897, 33898, 33899, 33906, + 33907, 33908 }, + [L["Non Set Plate"]] = { 33889, 33888, 33890, 33904, 33903, 33905, 33813, 33811, 33812, 33910, + 33909, 33911 } + }, + [format(L["Level %d Honor PVP"], 80)] = { + [L["Non Set Accessories"]] = { 42020, 42021, 42022, 42023, 42024, 42025, 42026, 42110, 42112, 42055, + 42056, 42057, 42058, 42059, 42060, 42061, 42122, 42123, 42128, 42129, 42130, 42131, 42132 }, + [L["Non Set Cloth"]] = { 41907, 41896, 41901, 41878, 41877, 41879, 41908, 41897, 41902, 41892, 41880, 41884 }, + [L["Non Set Leather"]] = { 41638, 41628, 41633, 41332, 41330, 41331, 41830, 41827, 41828, 41639, + 41629, 41634, 41624, 41616, 41620, 41839, 41831, 41835 }, + [L["Non Set Mail"]] = { 41063, 41068, 41073, 41047, 41050, 41049, 41223, 41233, 41228, 41064, + 41069, 41074, 41059, 41048, 41054, 41224, 41234, 41229 }, + [L["Non Set Plate"]] = { 40972, 40966, 40973, 40887, 40877, 40878, 40982, 40974, 40975, 40888, 40879, 40880 }, + [L["Savage Gladiator\'s Weapons"]] = { 42294, 42295, 42297, 42445, 42343, 42356, 42448, 42446, 42213, 42217, + 42220, 42221, 42223, 42447, 42557, 42568, 42344, 42296, 42206, 42216, + 42222, 42224, 42218, 42212, 42214, 42219, 42517, 42511, 42556, 42444, + 42618, 42574, 42575, 42576, 42612, 42611, 42595, 42593, 42594 }, + [L["Deadly Gladiator\'s Weapons"]] = { 42317, 42322, 42332, 42346, 42454, 42227, 42248, 42270, 42280, 42290, + 42352, 42327, 42208, 42242, 42275, 42285, 42260, 42232, 42237, 42265, + 42362, 42384, 44420, 44419, 42564, 42570, 42559, 42450, 42490, 42495, + 42485, 42513, 42519, 42502, 42525, 42537, 42531, 42588, 42583, 42578, + 42614, 42852, 42620, 42597, 42607, 42602 }, + [BZ["Wintergrasp"]] = { 43956, 44077, 44066, 44075, 44069, 44068, 44067, 44081, 44084, 44082, + 44076, 44078, 44087, 44088, 44089, 41730, 41732, 41733, 41735, 41739, + 41736, 41738, 41734, 41727, 41740, 41728, 41742, 41743, 41744, 44107, + 44103, 44105, 44102, 44101, 44100, 44099, 44098, 44097, 44091, 44096, + 44092, 44094, 44095, 44093, 44115, 44910, 44909, 44899, 44900, 44907, + 44906, 44908, 44891, 44892, 44893, 44914, 44912, 44903, 44904, 44905, + 44896, 44897, 44898, 44901, 44902, 44894, 44895, }, + [BZ["Grizzly Hills"]] = { 38354, 38355, 38353, 38358, 38359, 38357, 38356, 38360, 38365, 38366, + 38364, 38363, 38362, 37836, 38368, 38367, 38361, 40875, 40822, 40867 }, + }, + + -- Tier 0 (dungeon 1) is already in the level 60 instances (strat, scholo ..) + [L["Tier 0.5 Quests"]] = { + [L["Druid Set"]] = { 22109, 22112, 22113, 22108, 22110, 22106, 22111, 22107 }, + [L["Hunter Set"]] = { 22013, 22016, 22060, 22011, 22015, 22010, 22017, 22061 }, + [L["Mage Set"]] = { 22065, 22068, 22069, 22063, 22066, 22062, 22067, 22064 }, + [L["Paladin Set"]] = { 22091, 22093, 22089, 22088, 22090, 22086, 22092, 22087 }, + [L["Priest Set"]] = { 22080, 22082, 22083, 22079, 22081, 22078, 22085, 22084 }, + [L["Rogue Set"]] = { 22005, 22008, 22009, 22004, 22006, 22002, 22007, 22003 }, + [L["Shaman Set"]] = { 22097, 22101, 22102, 22095, 22099, 22098, 22100, 22096 }, + [L["Warlock Set"]] = { 22074, 22073, 22075, 22071, 22077, 22070, 22072, 22076 }, + [L["Warrior Set"]] = { 21999, 22001, 21997, 21996, 21998, 21994, 22000, 21995 } + }, + -- Dungeon 3 (level 70) is already in the BC 5-men + + -- Tier 1 is already in MC + -- Tier 2 is already in BWL, Ony + + [format(L["Tier %d Tokens"], 3)] = { + [L["Druid Set"]] = { 22490, 22491, 22488, 22495, 22493, 22494, 22489, 22492, 23064 }, + [L["Hunter Set"]] = { 22438, 22439, 22436, 22443, 22441, 22442, 22437, 22440, 23067 }, + [L["Mage Set"]] = { 22498, 22499, 22496, 22503, 22501, 22502, 22497, 22500, 23062 }, + [L["Paladin Set"]] = { 22428, 22429, 22425, 22424, 22426, 22431, 22427, 22430, 23066 }, + [L["Priest Set"]] = { 22514, 22515, 22512, 22519, 22517, 22518, 22513, 22516, 23061 }, + [L["Rogue Set"]] = { 22478, 22479, 22476, 22483, 22481, 22482, 22477, 22480, 23060 }, + [L["Shaman Set"]] = { 22466, 22467, 22464, 22471, 22469, 22470, 22465, 22468, 23065 }, + [L["Warlock Set"]] = { 22506, 22507, 22504, 22511, 22509, 22510, 22505, 22508, 23063 }, + [L["Warrior Set"]] = { 22418, 22419, 22416, 22423, 22421, 22422, 22417, 22420, 23059 } + }, + [format(L["Tier %d Tokens"], 4)] = { + [BB["Prince Malchezaar"] .. " (" .. BZ["Karazhan"] .. ")"] = { 29098, 29086, 29093, 29081, 29076, 29068, 29073, + 29061, 29049, 29058, 29044, 29040, 29028, 29035, 28963, 29011, 29021 }, -- T4 helm + [BB["High King Maulgar"] .. " (" .. BZ["Gruul's Lair"] .. ")"] = { 29100, 29089, 29095, 29084, 29079, 29070, 29075, + 29064, 29054, 29060, 29047, 29043, 29031, 29037, 28967, 29016, 29023 }, -- T4 shoulder + [BB["Magtheridon"] .. " (" .. BZ["Magtheridon's Lair"] .. ")"] = { 29096, 29087, 29091, 29082, 29077, 29066, 29071, + 29062, 29050, 29056, 29045, 29038, 29029, 29033, 28964, 29012, 29019 }, -- T4 chest + [BB["The Curator"] .. " (" .. BZ["Karazhan"] .. ")"] = { 29097, 29090, 29092, 29085, 29080, 29067, 29072, + 29065, 29055, 29057, 29048, 29039, 29032, 29034, 28968, 29017, 29020 }, -- T4 gloves + [BB["Gruul the Dragonkiller"] .. " (" .. BZ["Gruul's Lair"] .. ")"] = { 29099, 29088, 29094, 29083, 29078, 29069, 29074, + 29063, 29053, 29059, 29046, 29042, 29030, 29036, 28966, 29015, 29022 } -- T4 leggings + }, + [format(L["Tier %d Tokens"], 5)] = { + [BB["Lady Vashj"] .. " (" .. BZ["Serpentshrine Cavern"] .. ")"] = { 30228, 30219, 30233, 30141, 30206, 30125, 30131, + 30136, 30152, 30161, 30146, 30190, 30166, 30171, 30212, 30115, 30120 }, -- T5 helm + [BB["Void Reaver"] .. " (" .. BZ["The Eye"] .. ")"] = { 30230, 30221, 30235, 30143, 30210, 30127, 30133, + 30138, 30154, 30163, 30149, 30194, 30168, 30173, 30215, 30117, 30122 }, -- T5 shoulders + [BB["Kael'thas Sunstrider"] .. " (" .. BZ["The Eye"] .. ")"] = { 30222, 30216, 30231, 30139, 30196, 30123, 30129, + 30134, 30150, 30159, 30144, 30185, 30164, 30169, 30214, 30113, 30118 }, -- T5 chest + [BB["Leotheras the Blind"] .. " (" .. BZ["Serpentshrine Cavern"] .. ")"] = { 30223, 30217, 30232, 30140, 30205, 30124, 30130, + 30135, 30151, 30160, 30145, 30189, 30165, 30170, 30211, 30114, 30119 }, -- T5 gloves + [BB["Fathom-Lord Karathress"] .. " (" .. BZ["Serpentshrine Cavern"] .. ")"] = { 30229, 30220, 30234, 30142, 30207, 30126, 30132, + 30137, 30153, 30162, 30148, 30192, 30167, 30172, 30213, 30116, 30121 } -- T5 leggings + }, + [format(L["Tier %d Tokens"], 6)] = { + [BB["Azgalor"] .. " (" .. BZ["Hyjal Summit"] .. ")"] = { 31034, 31032, 31035, 31001, 31055, 30985, 30982, + 30983, 31060, 31061, 31026, 31011, 31007, 31008, 31050, 30970, 30969 }, -- T6 gloves + [BB["Archimonde"] .. " (" .. BZ["Hyjal Summit"] .. ")"] = { 31039, 31037, 31040, 31003, 31056, 30987, 30989, + 30988, 31063, 31064, 31027, 31015, 31012, 31014, 31051, 30974, 30972 }, -- T6 helm + [BB["Mother Shahraz"] .. " (" .. BZ["Black Temple"] .. ")"] = { 31048, 31047, 31049, 31006, 31059, 30997, 30998, + 30996, 31069, 31070, 31030, 31024, 31022, 31023, 31054, 30980, 30979 }, -- T6 shoulders + [BB["The Illidari Council"] .. " (" .. BZ["Black Temple"] .. ")"] = { 31044, 31045, 31046, 31005, 31058, 30995, 30993, + 30994, 31068, 31067, 31029, 31021, 31019, 31020, 31053, 30978, 30977 }, -- T6 leggings + [BB["Illidan Stormrage"] .. " (" .. BZ["Black Temple"] .. ")"] = { 31042, 31041, 31043, 31004, 31057, 30991, 30990, + 30992, 31066, 31065, 31028, 31018, 31016, 31017, 31052, 30976, 30975 }, -- T6 chest + [BB["Kalecgos"] .. " (" .. BZ["Sunwell Plateau"] .. ")"] = { 34444, 34445, 34446, 34443, 34447, 34433, 34431, + 34432, 34435, 34434, 34448, 34439, 34438, 34437, 34436, 34442, 34441 }, -- T6 bracers + [BB["Brutallus"] .. " (" .. BZ["Sunwell Plateau"] .. ")"] = { 34556, 34554, 34555, 34549, 34557, 34488, 34485, + 34487, 34527, 34528, 34558, 34545, 34543, 34542, 34541, 34547, 34546 }, -- T6 belt + [BB["Felmyst"] .. " (" .. BZ["Sunwell Plateau"] .. ")"] = { 34573, 34571, 34572, 34570, 34574, 34560, 34561, + 34559, 34562, 34563, 34575, 34567, 34565, 34566, 34564, 34568, 34569 } -- T6 boots + }, + [format(L["Tier %d Tokens"], 7) .. " (10)"] = { + [BB["Kel'Thuzad"]] = { 39619, 39625, 39553, 39531, 39545, 39578, 39491, 39628, 39635, 39640, + 39521, 39514, 39561, 39594, 39602, 39583, 39496, 39605, 39610 }, + [BB["Loatheb"]] = { 39621, 39627, 39556, 39542, 39548, 39581, 39494, 39631, 39637, 39642, + 39529, 39518, 39565, 39596, 39604, 39590, 39499, 39608, 39613 }, + [BB["The Four Horsemen"]] = { 39617, 39623, 39554, 39538, 39547, 39579, 39492, 39629, 39633, 39638, + 39523, 39515, 39558, 39592, 39597, 39588, 39497, 39606, 39611 }, + [BB["Thaddius"]] = { 39620, 39626, 39555, 39539, 39546, 39580, 39493, 39630, 39636, 39641, + 39528, 39517, 39564, 39595, 39603, 39589, 39498, 39607, 39612 }, + [BB["Sartharion"]] = { 39618, 39624, 39557, 39543, 39544, 39582, 39495, 39632, 39634, 39639, + 39530, 39519, 39560, 39593, 39601, 39591, 39500, 39609, 39622 }, + }, + [format(L["Tier %d Tokens"], 7) .. " (25)"] = { + [BB["Kel'Thuzad"]] = { 40565, 40554, 40473, 40461, 40467, 40505, 40416, 40571, 40576, 40581, + 40456, 40447, 40499, 40510, 40521, 40516, 40421, 40528, 40546 }, + [BB["Loatheb"]] = { 40568, 40557, 40494, 40465, 40470, 40507, 40419, 40573, 40578, 40584, + 40459, 40450, 40502, 40513, 40524, 40518, 40424, 40530, 40548 }, + [BB["The Four Horsemen"]] = { 40559, 40550, 40471, 40463, 40469, 40503, 40418, 40569, 40574, 40579, + 40458, 40449, 40495, 40508, 40523, 40514, 40423, 40525, 40544 }, + [BB["Thaddius"]] = { 40567, 40556, 40493, 40462, 40468, 40506, 40417, 40572, 40577, 40583, + 40457, 40448, 40500, 40512, 40522, 40517, 40422, 40529, 40547 }, + [BB["Sartharion"]] = { 40563, 40552, 40472, 40460, 40466, 40504, 40415, 40570, 40575, 40580, + 40454, 40445, 40496, 40509, 40520, 40515, 40420, 40527, 40545 }, + }, + [L["Blizzard Collectables"]] = { + [L["WoW Collector Edition"]] = { 13582, 13583, 13584 }, + [L["BC Collector Edition (Europe)"]] = { 25535, 30360 }, + [L["Blizzcon 2005"]] = { 20371 }, + [L["Blizzcon 2007"]] = { 33079 }, + ["Worldwide Invitational Paris 2008"] = { 39656 }, + [L["Christmas Gift 2006"]] = { 22114 } + }, + [L["Upper Deck"]] = { + [L["Loot Card Items"]] = { 23705, 23713, 23720, 32588, 32566, 32542, 33225, 33224, 33223, 33219, + 34493, 34492, 34499, 35226, 35225, 35223, 23709, 23714, 23716, 35227, + 38050, 38301, 38233, 38312, 23709, 38313, 38309, 38310, 38314, 38314, + 38311, 23716, 23714 } + }, + + [L["Heroic Mode Tokens"]] = { + [L["Fire Resistance Gear"]] = { 30762, 30764, 30761, 30763, 30776, 30780, 30778, 30779, 30773, 30774, + 30772, 30770, 30769, 30767, 30766, 30768 }, + [BI["Cloth"] .. " (" .. BZ["Shattrath City"] .. ")"] = { 32090, 32089, 33588, 33589, 33587, 33586, 33291, 33584, 33585 }, + [BI["Cloth"] .. " (" .. BZ["Isle of Quel'Danas"] .. ")"] = { 34924, 34917, 34936, 34938, 34925, 34937, 34918, 34919, 34926 }, + [BI["Leather"] .. " (" .. BZ["Shattrath City"] .. ")"] = { 32088, 33972, 32087, 33287, 33973, 33566, 33579, 33578, 33580, 33557, + 33540, 33974, 33539, 33559, 33583, 33552, 33538, 33582, 33222, 33577 }, + [BI["Leather"] .. " (" .. BZ["Isle of Quel'Danas"] .. ")"] = { 34906, 34903, 34900, 34927, 34904, 34902, 34901, + 34911, 34929, 34905, 34910, 34928 }, + [BI["Mail"] .. " (" .. BZ["Shattrath City"] .. ")"] = { 32086, 32085, 33970, 33965, 33535, 33532, 33529, 33528, 33534, 33531, + 33386, 33536, 33280, 33530, 33527, 33537, 33324 }, + [BI["Mail"] .. " (" .. BZ["Isle of Quel'Danas"] .. ")"] = { 34912, 34933, 34930, 34916, 34935, 34932, 34914, 34931, 34934 }, + [BI["Plate"] .. " (" .. BZ["Shattrath City"] .. ")"] = { 33810, 32083, 32084, 33514, 33522, 33516, 33513, 33520, 33517, 33512, + 33519, 33331, 33524, 33279, 33501, 33518, 33515, 33207, 33523 }, + [BI["Plate"] .. " (" .. BZ["Isle of Quel'Danas"] .. ")"] = { 34942, 34939, 34921, 34945, 34944, 34941, 34923, 34922, 34946, 34943, + 34940, 34947 }, + [L["Cloaks"] .. " (" .. BZ["Shattrath City"] .. ")"] = { 29375, 29382, 35321, 33304, 35324, 33484, 29385, 33333, 29369, 33593 }, + [L["Relics"] .. " (" .. BZ["Shattrath City"] .. ")"] = { 29390, 33508, 33509, 33510, 33506, 33507, 33505, 29389, 33503, 33504, + 33502, 29388 }, + [L["Accessories"] .. " (" .. BZ["Shattrath City"] .. ")"] = { 33296, 29381, 29374, 29386, 29368, 29373, 29379, 29367, 29384, 23572, + 35326, 34049, 34163, 34162, 33832, 34050, 29383, 29376, 29387, 29370, 30183 }, + [L["Accessories"] .. " (" .. BZ["Isle of Quel'Danas"] .. ")"] = { 34887, 34890, 34889, 34888, 32227, 32228, 32229, + 32231, 32249, 32230, 35318, 35315, 35316}, + [L["Weapons"] .. " (" .. BZ["Shattrath City"] .. ")"] = { 29275, 33192, 29268, 29267, 29266, 33334, 29270, 29273, 29272, 29269, + 29271, 29274, 33325 }, + [L["Weapons"] .. " (" .. BZ["Isle of Quel'Danas"] .. ")"] = { 34894, 34896, 34895, 34893, 34951, 34950, 34949, 34952, 34891, 34898, 34892 }, + [L["Emblems of Valor"]] = { 40724, 40723, 40722, 40721, 40741, 40740, 40751, 40750, 40739, 40738, + 40748, 40749, 40736, 40737, 40746, 40747, 40734, 40733, 40735, 40742, + 40743, 40745, 40719, 40720, 40717, 40718, 40634, 40635, 40636, 40637, 40638, 40639 }, + [L["Emblems of Heroism"]] = { 40697, 40696, 40694, 40695, 40693, 40692, 40691, 40688, 40689, 40610, + 40611, 40612, 40613, 40614, 40615, 43102, 40704, 40702, 40703, 40716, + 40701, 40700, 40699, 40698, 40679, 40680, 40681, 40678, 40684, 40682, + 40685, 40683, 40711, 40712, 40713, 40707, 40706, 40705, 40715, 40709, + 40710, 40708, 42985, 42984, 42952, 42950, 42951, 42949, 42992, 42991, + 42944, 42945, 42943, 42948, 42947, 42946 } + }, + + [L["World Drops"]] = { + [L["Level 30-39"]] = { 867, 1981, 1980, 869, 1982, 870, 868, 873, 1204, 2825 }, + [L["Level 40-49"]] = { 3075, 940, 14551, 17007, 14549, 1315, 942, 1447, 2164, 2163, + 809, 871, 2291, 810, 2915, 812, 943, 1169, 1979, 2824, 2100 }, + [L["Level 50-60"]] = { 3475, 14553, 2245, 14552, 14554, 1443, 14558, 2246, 833, 14557, + 1728, 14555, 2244, 2801, 647, 811, 1263, 2243, 944, 1168, 2099 }, + [L["Level 70"]] = { 34703, 28189, 31329, 31340, 31343, 31333, 31330, 31328, 31335, 31320, + 31338, 31321, 31319, 31339, 31326, 31331, 31336, 31332, 31318, 31342, + 31322, 31334, 34622, 31323 } + }, + + -- not in LPT + [BZ["Onyxia's Lair"] .. " (10)"] = { + [BB["Onyxia"]] = { 49307, 49316, 49317, 49315, 49318, 49322, 49327, 49328, 49326, 49331, + 49330, 49329, 49319, 49320, 49321, 49333, 49332, 49323, 49325, 49324, + 49306, 49309, 49463, 49310, 49308, 49304, 49437, 49298, 49303, 49296, + 49299, 49297, 49302, 49301, 49305, 49644, 49485, 49486, 49487, 49295, + 49294, 49636 }, + }, + [BZ["Onyxia's Lair"] .. " (25)"] = { + [BB["Onyxia"]] = { 49491, 49482, 49483, 49484, 49481, 49477, 49472, 49473, 49471, 49469, + 49468, 49470, 49480, 49479, 49478, 49467, 49466, 49476, 49475, 49474, + 49492, 49489, 49464, 49488, 49490, 49295, 49636, 49294, 49494, 49465, + 49499, 49495, 49501, 49498, 49500, 49496, 49497, 49493, 49644, 49485, + 49486, 49487 }, + }, + + [BZ["Trial of the Champion"]] = { + [BB["Faction Champions"]] = { 47173, 47170, 47174, 47175, 47172, 47171 }, + [BB["Argent Confessor Paletress"]] = { 47181, 47218, 47185, 47217, 47177, 47178, 47211, 47176, 47212, 47219, + 47213, 47214 }, + [BB["Eadric the Pure"]] = { 47181, 47185, 47210, 47177, 47202, 47178, 47176, 47197, 47201, 47199, + 47200, 47213 }, + [BB["The Black Knight"]] = { 47232, 47226, 47230, 47221, 47231, 47228, 47220, 47229, 47227, 47222, + 47215, 47216 }, + }, + [BZ["Trial of the Champion"] .. L[" (Heroic)"]] = { + [BB["Faction Champions"]] = { 45624, 47249, 47248, 47250, 47244, 47243, 47493, 44990 }, + [BB["Argent Confessor Paletress"]] = { 45624, 47498, 47496, 47245, 47497, 47514, 47510, 47495, 47511, 47494, + 47512, 47500, 47522, 44990 }, + [BB["Eadric the Pure"]] = { 45624, 47501, 47496, 47498, 47504, 47497, 47502, 47495, 47503, 47494, + 47500, 47509, 47508, 44990 }, + [BB["The Black Knight"]] = { 45624, 47564, 47527, 47560, 47529, 47561, 47563, 47565, 47567, 47562, + 47566, 47569, 49682, 47568, 43102, 44990, 48418 }, + }, + + [BZ["Trial of the Crusader"] .. " (10)"] = { + [BB["The Beasts of Northrend"]] = { 47617, 47613, 47608, 47616, 47610, 47611, 47609, 47615, 47614, 47607, + 47578, 47612, 47855, 47857, 47853, 47860, 47850, 47852, 47851, 47859, 47858, 47849, 47854, 47856 }, + [BB["Lord Jaraxxus"]] = { 47663, 47620, 47669, 47621, 49235, 47683, 47680, 47711, 47619, 47679, + 47618, 47703, 47676, 47861, 47865, 47863, 47866, 49236, 47867, 47869, + 47870, 47872, 47864, 47862, 47868, 47871 }, + [BB["Faction Champions"]] = { 47721, 47719, 47718, 47717, 47720, 47728, 47727, 47726, 47725, 47724, + 47873, 47878, 47875, 47876, 47877, 47880, 47882, 47879, 47881, 47874 }, + [BB["The Twin Val'kyr"]] = { 47745, 49231, 47746, 47739, 47744, 47738, 47747, 47700, 47742, 47736, + 47737, 47743, 47740, 47889, 49232, 47891, 47887, 47893, 47885, 47890, + 47888, 47913, 47886, 47884, 47892, 47883 }, + [BB["Anub'arak"]] = { 47838, 47837, 47832, 47813, 47829, 47811, 47836, 47830, 47810, 47814, + 47808, 47809, 47816, 47834, 47815, 47835, 47812, 47741, 47906, 47909, + 47904, 47897, 47901, 47896, 47902, 47908, 47899, 47903, 47898, 47894, + 47905, 47911, 47900, 47910, 47895, 47907 }, + [L["Patterns"]] = { 47654, 47655, 47656, 47657, 47629, 47635, 47631, 47630, 47628, 47634, + 47632, 47633, 47622, 47623, 47627, 47626, 47624, 47625, 47556, 47639, + 47638, 47637, 47636, 47646, 47647, 47648, 47649, 47650, 47651, 47652, + 47653, 47640, 47641, 47642, 47643, 47644, 47645 }, + }, + + [BZ["Trial of the Crusader"] .. " (25)"] = { + [BB["The Beasts of Northrend"]] = { 46970, 46976, 46992, 46972, 46974, 46988, 46960, 46990, 46962, 46961, + 46985, 46959, 46979, 46958, 46963, 47242, 47257, 47256, 47264, 47258, 47259, 47262, 47251, 47265, + 47254, 47253, 47263, 47252, 47261, 47255, 47260 }, + [BB["Lord Jaraxxus"]] = { 47042, 47051, 47000, 47055, 47056, 46999, 47057, 47052, 46997, 47043, + 47223, 47041, 47053, 46996, 46994, 47242, 47275, 47274, 47270, 47277, + 47280, 47268, 47279, 47273, 47269, 47272, 47278, 47271, 47276, 47266, + 47267, 47242 }, + [BB["Faction Champions"]] = { 47089, 47081, 47092, 47094, 47071, 47073, 47083, 47090, 47082, 47093, + 47072, 47070, 47080, 47069, 47079, 47242, 47291, 47286, 47293, 47292, + 47284, 47281, 47289, 47295, 47288, 47294, 47283, 47282, 47290, 47285, + 47287 }, + [BB["The Twin Val'kyr"]] = { 47126, 47141, 47107, 47140, 47106, 47142, 47108, 47121, 47116, 47105, + 47139, 47115, 47138, 47104, 47114, 47242, 47301, 47306, 47308, 47299, + 47296, 47310, 47298, 47304, 47307, 47305, 47297, 47303, 47309, 47300, + 47302 }, + [BB["Anub'arak"]] = { 47225, 47183, 47203, 47235, 47187, 47194, 47151, 47186, 47204, 47152, + 47184, 47234, 47195, 47150, 47054, 47149, 47182, 47148, 47193, 47233, + 47242, 47328, 47320, 47324, 47326, 47317, 47321, 47313, 47318, 47325, + 47311, 47319, 47330, 47323, 47312, 47315, 47327, 47316, 47314, 47322, + 47329 }, + }, + + [BZ["Trial of the Crusader"] .. " (10)" .. L[" (Heroic)"]] = { + [BB["The Beasts of Northrend"]] = { 47921, 47923, 47919, 47926, 47916, 47918, 47917, 47924, 47925, 47915, + 47920, 47922, 47994, 47996, 47992, 47999, 47989, 47991, 47990, 47998, + 47997, 47988, 47993, 47995 }, + [BB["Lord Jaraxxus"]] = { 47927, 47931, 47929, 47932, 49238, 47933, 47935, 47937, 47930, 47939, + 47928, 47934, 47938, 48000, 48004, 48002, 48005, 49237, 48006, 48008, + 48009, 48011, 48003, 48001, 48007, 48010 }, + [BB["Faction Champions"]] = { 47940, 47945, 47942, 47943, 47944, 47947, 47949, 47946, 47948, 47941, + 48012, 48017, 48014, 48015, 48016, 48019, 48021, 48018, 48020, 48013 }, + [BB["The Twin Val'kyr"]] = { 47956, 49234, 47959, 47954, 47961, 47952, 47957, 47955, 47958, 47953, + 47951, 47960, 47950, 48028, 49233, 48034, 48026, 48038, 48024, 48030, + 48027, 48032, 48025, 48023, 48036, 48022 }, + [BB["Anub'arak"]] = { 47974, 47977, 47972, 47965, 47969, 47964, 47976, 47970, 47967, 47971, + 47966, 47962, 47973, 47979, 47968, 47978, 47963, 47975, 48051, 48054, + 48049, 48042, 48046, 48041, 48047, 48053, 48044, 48048, 48043, 48039, + 48050, 48056, 48045, 48055, 48040, 48052 }, + [L["Tribute Run"]] = { 47242, 48712, 48708, 48713, 48709, 48714, 48710, 48711, 48673, + 48675, 48674, 48671, 48672, 49044, 48703, 48701, 48695, 48693, + 48699, 48705, 48697, 48668, 48669, 48670, 48666, 48667, 49046 }, + }, + [BZ["Trial of the Crusader"] .. " (25)" .. L[" (Heroic)"]] = { + [BB["The Beasts of Northrend"]] = { 46971, 46977, 46993, 46973, 46975, 46989, 46965, 46991, 46968, 46967, + 46986, 46966, 46980, 46969, 46964, 47242, 47418, 47417, 47425, 47419, + 47420, 47423, 47412, 47426, 47415, 47414, 47424, 47413, 47422, 47416, + 47421 }, + [BB["Lord Jaraxxus"]] = { 47063, 47062, 47004, 47066, 47068, 47002, 47067, 47061, 47003, 47060, + 47224, 47059, 47064, 47001, 46995, 47242, 47436, 47435, 47431, 47438, + 47441, 47429, 47440, 47434, 47430, 47433, 47439, 47432, 47437, 47427, + 47428 }, + [BB["Faction Champions"]] = { 47095, 47084, 47097, 47096, 47077, 47074, 47087, 47099, 47086, 47098, + 47076, 47075, 47088, 47078, 47085, 47242, 47452, 47447, 47454, 47453, + 47445, 47442, 47450, 47456, 47449, 47455, 47444, 47443, 47451, 47446, + 47448 }, + [BB["The Twin Val'kyr"]] = { 47129, 47143, 47112, 47145, 47109, 47147, 47111, 47132, 47133, 47110, + 47144, 47131, 47146, 47113, 47130, 47242, 47462, 47467, 47469, 47460, + 47457, 47471, 47459, 47465, 47468, 47466, 47458, 47464, 47470, 47461, + 47463 }, + [BB["Anub'arak"]] = { 47238, 47192, 47208, 47236, 47189, 47205, 47155, 47190, 47209, 47153, + 47191, 47240, 47207, 47154, 47237, 47157, 47188, 47156, 47206, 47239, + 47242, 47490, 47481, 47485, 47487, 47478, 47482, 47474, 47479, 47486, + 47472, 47480, 47492, 47484, 47473, 47476, 47489, 47477, 47475, 47483, + 47491 }, + [L["Tribute Run"]] = { 47557, 47558, 47517, 47506, 47515, 47526, 47519, 47524, 47521, 47553, + 47552, 47549, 47545, 47547, 47518, 47513, 47516, 47528, 47520, 47525, + 47523, 47551, 47550, 47548, 47554, 47546 }, + }, + + -- 3.3 + + [BZ["The Forge of Souls"]] = { + [BB["Bronjahm"]] = { 49788, 49785, 49786, 49787, 49784, 49783, 50317, 50316 }, + [BB["Devourer of Souls"]] = { 49792, 49796, 49798, 49791, 49797, 49794, 49795, 49799, 49800, 49789, 49790, 49793 }, + [L["Trash Mobs"]] = { 49854, 49855, 49853, 49852 }, + }, + [BZ["The Forge of Souls"] .. L[" (Heroic)"]] = { + [BB["Bronjahm"]] = { 50193, 50197, 50194, 50196, 50191, 50169, 50317, 50316 }, + [BB["Devourer of Souls"]] = { 50213, 50206, 50212, 50214, 50209, 50208, 50207, 50215, 50211, 50198, + 50203, 50210 }, + [L["Trash Mobs"]] = { 50318, 50315, 50319, 50380, 50379 }, + }, + [BZ["Pit of Saron"]] = { + [BB["Forgemaster Garfrost"]] = { 49805, 49806, 49804, 49803, 49802, 49801 }, + -- temporarily not localized + ["Krick and Ick"] = { 49809, 49810, 49811, 49808, 49812, 49807 }, + [BB["Scourgelord Tyrannus"]] = { 49823, 49825, 49822, 49817, 49824, 49826, 49820, 49819, 49816, 49818, + 49821, 49813, }, + [L["Trash Mobs"]] = { 49854, 49855, 49853, 49852 }, + }, + [BZ["Pit of Saron"] .. L[" (Heroic)"]] = { + [BB["Forgemaster Garfrost"]] = { 50233, 50234, 50230, 50229, 50228, 50227 }, + -- temporarily not localized + ["Krick and Ick"] = { 50266, 50263, 50624, 50265, 50235, 50262 }, + [BB["Scourgelord Tyrannus"]] = { 50286, 50269, 50270, 50283, 50272, 50285, 50284, 50271, 50259, 50268, + 50267, 50273 }, + [L["Trash Mobs"]] = { 50318, 50315, 50319, 50380, 50379 }, + }, + [BZ["Halls of Reflection"]] = { + -- temporarily not localized + [BB["Falric"]] = { 49832, 49828, 49830, 49831, 49829, 49827 }, + [BB["Marwyn"]] = { 49834, 49838, 49837, 49836, 49833, 49835, 49828 }, + [BB["The Lich King"]] = { 49842, 49849, 49848, 49841, 49847, 49851, 49843, 49846, 49839, 49840, + 49845, 49844, }, + [L["Trash Mobs"]] = { 49854, 49855, 49853, 49852 }, + }, + [BZ["Halls of Reflection"] .. L[" (Heroic)"]] = { + [BB["Falric"]] = { 50292, 50293, 50295, 50294, 50290, 50291 }, + [BB["Marwyn"]] = { 50298, 50299, 50300, 50297, 50260, 50296 }, + [BB["The Lich King"]] = { 50314, 50312, 50308, 50304, 50311, 50305, 50310, 50313, 50306, 50309, + 50302, 50303 }, + [L["Trash Mobs"]] = { 50318, 50315, 50319, 50380, 50379 }, + }, + + [BZ["Icecrown Citadel"] .. " (10)"] = { + [BB["Lord Marrowgar"]] = { 50764, 50773, 50774, 50762, 50775, 50772, 50763, 50339, 50771, 50761, 50759, 50760, }, + [BB["Lady Deathwhisper"]] = { 50785, 50782, 50780, 50778, 50783, 50777, 50784, 50779, 50786, 50342, 50781, 50776 }, + [BB["Icecrown Gunship Battle"]] = { 50791, 50795, 50797, 50792, 50789, 50796, 50788, 50790, 50340, 50793, 50787, 50794 }, + [BB["Deathbringer Saurfang"]] = { 50807, 50804, 50799, 50806, 50800, 50801, 50802, 50808, 50809, 50803, 50798, 50805 }, + [BB["Festergut"]] = { 50859, 50988, 50990, 50985, 50858, 50812, 50967, 50811, 50852, 50986, 50810, 50966 }, + [BB["Rotface"]] = { 51007, 51005, 51009, 51002, 51006, 51000, 51008, 51001, 51003, 51004, 50998, 50999 }, + [BB["Professor Putricide"]] = { 51020, 51017, 51013, 51015, 51019, 51014, 51018, 51012, 51016, 50341, 51011, 51010 }, + [BB["Blood Princes"]] = { 51382, 51379, 51380, 51023, 51325, 51383, 51025, 51381, 51024, 51021, 51022, 51326 }, + [BB["Blood-Queen Lana'thel"]] = { 51554, 51552, 51550, 51551, 51386, 51556, 51555, 51548, 51387, 51384, 51385, 51553 }, + [BB["Valithria Dreamwalker"]] = { 51584, 51777, 51585, 51565, 51583, 51566, 51586, 51563, 51564, 51562, 51582, 51561,}, + [BB["Sindragosa"]] = { 51790, 51783, 51789, 51792, 51785, 51782, 51786, 51787, 51026, 51779, + 51784, 51788, 51791 }, + [BB["The Lich King"]] = { }, + }, + [BZ["Icecrown Citadel"] .. " (25)"] = { + [BB["Lord Marrowgar"]] = { 49978, 49979, 49950, 49952, 49980, 49951, 49960, 49964, 49975, 49949, 49977, 49967, 49968, 50415, 49976, 50274, 49908 }, + [BB["Lady Deathwhisper"]] = { 49991, 49994, 49987, 49996, 49988, 49993, 49986, 49995, 49983, 49989, 49985, 49990, 49982, 49992, 50034, 50274, 49908 }, + [BB["Icecrown Gunship Battle"]] = { 49998, 50006, 50011, 50001, 50009, 50000, 50003, 50002, 50010, 50274, + 49908, 50005, 50008, 49999, 50359, 50352, 50411 }, + [BB["Deathbringer Saurfang"]] = { 50014, 50333, 50015, 50362, 50412, 50274, 49908, 52027, 52026, 52025, }, + [BB["Festergut"]] = { 50063, 50056, 50062, 50042, 50041, 50059, 50038, 50064, 50413, 50060, + 50037, 50036, 50061, 50414, 50035, 50040, 50226, 50274, 49908, }, + [BB["Rotface"]] = { 50019, 50032, 50026, 50021, 50022, 50030, 50020, 50024, 50027, 50023, + 50025, 50353, 50028, 50016, 50033, 50231, 50274, 49908 }, + [BB["Professor Putricide"]] = { 50067, 50069, 50351, 50179, 50068, 50274, 49908, 52027, 52026, 52025}, + [BB["Blood Princes"]] = { 50074, 50172, 50176, 50073, 50171, 50177, 50071, 50072, 50075, 50175, + 50174, 50170, 50173, 50184, 49919, 50274, 49908 }, + [BB["Blood-Queen Lana'thel"]] = { 50182, 50180, 50354, 50178, 50181, 50065, 50274, 49908, 52027, 52026, 52025 }, + [BB["Valithria Dreamwalker"]] = { 50205, 50418, 50417, 50202, 50188, 50187, 50199, 50192, 50416, 50190, + 50195, 50185, 50186, 50183, 50472, 50274, 49908 }, + [BB["Sindragosa"]] = { 50421, 50424, 50360, 50361, 50423, 50274, 49908, 51026, 52027, 52026, 52025, }, + [BB["The Lich King"]] = { }, + [L["Trash Mobs"]] = { 50449, 50450, 50451, 50452, 50447, 50453, 50444 }, + }, + [BZ["Icecrown Citadel"] .. " (10)" .. L[" (Heroic)"]] = { + [BB["Lord Marrowgar"]] = { }, + [BB["Lady Deathwhisper"]] = { }, + [BB["Icecrown Gunship Battle"]] = { }, + [BB["Deathbringer Saurfang"]] = { }, + [BB["Festergut"]] = { }, + [BB["Rotface"]] = { }, + [BB["Professor Putricide"]] = { }, + [BB["Blood Princes"]] = { }, + [BB["Blood-Queen Lana'thel"]] = { }, + [BB["Valithria Dreamwalker"]] = { }, + [BB["Sindragosa"]] = { }, + [BB["The Lich King"]] = { }, + }, + [BZ["Icecrown Citadel"] .. " (25)" .. L[" (Heroic)"]] = { + [BB["Lord Marrowgar"]] = { }, + [BB["Lady Deathwhisper"]] = { }, + [BB["Icecrown Gunship Battle"]] = { }, + [BB["Deathbringer Saurfang"]] = { }, + [BB["Festergut"]] = { }, + [BB["Rotface"]] = { }, + [BB["Professor Putricide"]] = { }, + [BB["Blood Princes"]] = { }, + [BB["Blood-Queen Lana'thel"]] = { }, + [BB["Valithria Dreamwalker"]] = { }, + [BB["Sindragosa"]] = { }, + [BB["The Lich King"]] = { }, + }, + + -- [] = { + -- }, + +} + +local DataProviders + +addon.Loots = {} + +local ns = addon.Loots -- ns = namespace + +function ns:GetSource(searchedID) + DataProviders = DataProviders or { -- list of sources that have a :GetSource() method + DataStore_Reputations, + DataStore_Crafts, + DataStore_Inventory, + } + + local domain, subDomain + for _, provider in pairs(DataProviders) do + domain, subDomain = provider:GetSource(searchedID) + if domain and subDomain then + return domain, subDomain + end + end + + -- extremely fast: takes from 0.3 to 3 ms max, depends on the location of the item in the table (obviously longer if the item is at the end) + for Instance, BossList in pairs(lootTable) do + for Boss, LootList in pairs(BossList) do + for itemID, _ in pairs(LootList) do + if LootList[itemID] == searchedID then + return Instance, Boss + end + end + end + end + return nil +end + +local filters = addon.ItemFilters + +local function ParseAltoholicLoots(OnMatch, OnNoMatch) + assert(type(OnMatch) == "function") + local count = 0 + + for Instance, BossList in pairs(lootTable) do + for Boss, LootList in pairs(BossList) do + for _, itemID in pairs(LootList) do + count = count + 1 + filters:SetSearchedItem(itemID) + + if filters:ItemPassesFilters() then + OnMatch(Instance, Boss) + else + if OnNoMatch then + OnNoMatch() + end + end + end + end + end + + filters:ClearSearchedItem() + return count +end + +local function ParseLPTSet(set, OnMatch, OnNoMatch) + assert(type(OnMatch) == "function") + + local PT = LibStub("LibPeriodicTable-3.1") + if not PT then return 0 end -- exit if LPT is not active + + -- LPT stores certain sets twice, but does not offer the possibility to differentiate entries (instances that are part of hubs) + -- So keep track of the sets we've already parsed, to avoid returning items twice. + local doneSets = {} + local count = 0 + + for _, list in pairs(PT:GetSetTable(set)) do + local _, domain, subdomain = strsplit(".", list.set) + + if not doneSets[list.set] then -- if this set hasn't been parsed yet, proceed.. + for itemID, value in pairs(list) do + if tostring(itemID) ~= "set" then + count = count + 1 + filters:SetSearchedItem(itemID) + + if filters:ItemPassesFilters() then + OnMatch(domain, subdomain or value) -- pass the value in case "subdomain" is nil + else + if OnNoMatch then + OnNoMatch() + end + end + end + end + end + doneSets[list.set] = true + end + + filters:ClearSearchedItem() + return count +end + +local allowedQueries, unknownCount + +local function OnMatch(domain, subdomain) + Altoholic.Search:AddResult( { + id = filters:GetSearchedItemInfo("itemID"), + iLvl = filters:GetSearchedItemInfo("itemLevel"), + dropLocation = domain, + bossName = subdomain, + } ) +end + +local function Currency_OnMatch(domain, subdomain) + Altoholic.Search:AddResult( { + id = filters:GetSearchedItemInfo("itemID"), + iLvl = filters:GetSearchedItemInfo("itemLevel"), + dropLocation = domain, + bossName = subdomain.."x", + } ) +end + +local function OnNoMatch() +-- if FilterByExistence() then return end -- if the item exists, do nothing + if filters:TryFilter("Existence") then return end -- if the item exists, do nothing + unknownCount = unknownCount + 1 + + if allowedQueries > 0 then + if Altoholic.Options:Get("SearchAutoQuery") == 1 then -- if autoquery is enabled + local itemID = filters:GetSearchedItemInfo("itemID") + if not addon:IsItemUnsafe(itemID) then -- if the item is not known to be unsafe + GameTooltip:SetHyperlink("item:"..itemID..":0:0:0:0:0:0:0") -- this line queries the server for an unknown id + GameTooltip:ClearLines(); -- don't leave residual info in the tooltip after the server query + + -- save ALL tested id's, clean the list in OnEnable during the next session. + -- the unsafe list will be cleaned in OnEnable, by parsing all ids and testing if getiteminfo returns a nil or not, if so, it's a definite unsafe link + addon:SaveUnsafeItem(itemID) -- save id to unsafe list + end + end + allowedQueries = allowedQueries - 1 + end +end + +function ns:Find() + unknownCount = 0 + allowedQueries = 5 + local count = ParseAltoholicLoots(OnMatch, OnNoMatch) + count = count + ParseLPTSet("InstanceLoot", OnMatch, OnNoMatch) + count = count + ParseLPTSet("InstanceLootHeroic", OnMatch, OnNoMatch) + count = count + ParseLPTSet("CurrencyItems", Currency_OnMatch, OnNoMatch) + + addon.Options:Set("TotalLoots", count) + addon.Options:Set("UnknownLoots", unknownCount) +end + +function ns:FindUpgrade() + local function OnMatch(domain, subdomain) + addon.Search:AddResult( { + id = filters:GetSearchedItemInfo("itemID"), + iLvl = filters:GetSearchedItemInfo("itemLevel"), + dropLocation = domain, + bossName = subdomain, + } ) + end + + ParseAltoholicLoots(OnMatch) + ParseLPTSet("InstanceLoot", OnMatch) + ParseLPTSet("InstanceLootHeroic", OnMatch) + ParseLPTSet("CurrencyItems", Currency_OnMatch) +end + +local tooltipLines -- cache containing the text lines of the tooltip "+15 stamina, etc.." +local rawItemStats -- contains the raw stats of the item currently being searched, placed here to avoid creating/deleting the table during the search +local currentItemStats -- contains the stats of the item for which we'll try to find upgrades + +local classExcludedStats +local classBaseStats + +local function AddCurrentlyEquippedItem(itemID, class) + + AltoTooltip:SetOwner(AltoholicFrame, "ANCHOR_LEFT") + local _, itemLink, _, itemLevel = GetItemInfo(itemID) + AltoTooltip:SetHyperlink(itemLink) + + local statLine = addon.Equipment.FormatStats[class] + local numLines = AltoTooltip:NumLines() + + local j=1 + for _, BaseStat in pairs(classBaseStats) do + for i = 4, numLines do + local tooltipText = _G[ "AltoTooltipTextLeft" .. i]:GetText() + if tooltipText then + if string.find(tooltipText, BaseStat) ~= nil then + currentItemStats[BaseStat] = tonumber(string.sub(tooltipText, string.find(tooltipText, "%d+"))) + statLine = string.gsub(statLine, "-s", WHITE .. currentItemStats[BaseStat], 1) + + rawItemStats[j] = currentItemStats[BaseStat] .. "|0" + break + end + end + end + if not currentItemStats[BaseStat] then + rawItemStats[j] = "0|0" + + currentItemStats[BaseStat] = 0 -- Set the current stat to zero if it was not found on the item + statLine = string.gsub(statLine, "-s", WHITE .. "0", 1) + end + j = j + 1 + end + AltoTooltip:ClearLines(); + + -- Save currently equipped item to the results table + addon.Search:AddResult( { + id = itemID, + iLvl = itemLevel, + dropLocation = "Currently equipped", + stat1 = rawItemStats[1], + stat2 = rawItemStats[2], + stat3 = rawItemStats[3], + stat4 = rawItemStats[4], + stat5 = rawItemStats[5], + stat6 = rawItemStats[6] + } ) +end + +local function MatchUpgradeByStats(itemID) + filters:SetSearchedItem(itemID) + if not filters:ItemPassesFilters() then + filters:ClearSearchedItem() + return + end + + AltoTooltip:ClearLines(); + AltoTooltip:SetOwner(AltoholicFrame, "ANCHOR_LEFT"); + AltoTooltip:SetHyperlink(filters:GetSearchedItemInfo("itemLink")) + + -- save some time by trying to find out if the item could be excluded + wipe(tooltipLines) + for i = 4, AltoTooltip:NumLines() do -- parse all tooltip lines, one by one, start at 4 since 1= item name, 2 = binds on.., 3 = type/slot/unique ..etc + -- in this first pass, save the lines into a cache, reused below + local tooltipLine = _G[ "AltoTooltipTextLeft" .. i]:GetText() + if tooltipLine then + if string.find(tooltipLine, L["Socket"]) == nil then + for _, v in pairs(classExcludedStats) do + --if string.find(tooltipLine, v, 1, true) ~= nil then return end + if string.find(tooltipLine, v) ~= nil then return end + end + tooltipLines[i] = tooltipLine + end + end + end + + local statFound + local j=1 + for _, BaseStat in pairs(classBaseStats) do + + statFound = nil + for i, tooltipText in pairs(tooltipLines) do + --if string.find(tooltipText, BaseStat, 1, true) ~= nil then + if string.find(tooltipText, BaseStat) ~= nil then + --local stat = tonumber(string.sub(tooltipText, string.find(tooltipText, "%d+"))) + local stat = tonumber(string.match(tooltipText, "%d+")) + + rawItemStats[j] = stat .. "|" .. (stat - currentItemStats[BaseStat]) + table.remove(tooltipLines, i) -- remove the current entry, so it won't be parsed in the next loop cycle + statFound = true + break + end + end + + if not statFound then + rawItemStats[j] = "0|" .. (0 - currentItemStats[BaseStat]) + end + j = j + 1 + end + + local iLvl = filters:GetSearchedItemInfo("itemLevel") + filters:ClearSearchedItem() + + -- All conditions ok ? save it + return true, iLvl +end + +-- modify this one after 3.2, to use GetItemStats +function ns:FindUpgradeByStats(currentID, class) + classExcludedStats = addon.Equipment.ExcludeStats[class] + classBaseStats = addon.Equipment.BaseStats[class] + + rawItemStats = {} + currentItemStats = {} + tooltipLines = {} + + AddCurrentlyEquippedItem(currentID, class) + + for Instance, BossList in pairs(lootTable) do -- parse the loot table to find an upgrade + for Boss, LootList in pairs(BossList) do + for _, itemID in pairs(LootList) do + + local matches, itemLevel = MatchUpgradeByStats(itemID) + + if matches then + addon.Search:AddResult( { + id = itemID, + iLvl = itemLevel, + dropLocation = Instance .. ", " .. GREEN .. Boss, + stat1 = rawItemStats[1], + stat2 = rawItemStats[2], + stat3 = rawItemStats[3], + stat4 = rawItemStats[4], + stat5 = rawItemStats[5], + stat6 = rawItemStats[6] + } ) + end + end + end + end + + classExcludedStats = nil + classBaseStats = nil + currentItemStats = nil + tooltipLines = nil + rawItemStats = nil +end diff --git a/Altoholic-Addon/Altoholic/Profiler.lua b/Altoholic-Addon/Altoholic/Profiler.lua new file mode 100644 index 0000000..2648100 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Profiler.lua @@ -0,0 +1,86 @@ +-- Simple code profiler, inspired by Chapter 1.14 (p120-130) of Game Programming Gems 1 +-- Ported from C++ to Lua by Thaoky. It will most likely evolve as my needs change. + +local addonName = "Altoholic" +local addon = _G[addonName] + +addon.Profiler = {} + +local ns = addon.Profiler -- ns = namespace + +local samples +local startProfile +local level -- for the code hierarchy, unused for now, but already valid, will be useful when Dumping into a real frame +local count -- to sort samples + +function ns:Init() + samples = samples or {} + wipe(samples) + startProfile = GetTime() + level = 0 + count = 0 +end + +function ns:Begin(name) + samples[name] = samples[name] or {} + local p = samples[name] + + p.startTime = GetTime() + if p.numPasses then -- if numPasses exists, it's an existing entry, update it and exit + p.numPasses = p.numPasses + 1 + return + end + + p.accumulator = 0 + p.duration = 0 + p.numPasses = 1 + + p.level = level + level = level + 1 + count = count + 1 + p.position = count +end + +function ns:End(name) + local p = samples[name] + if not p then return end + + p.duration = GetTime() - p.startTime + p.minTime = p.minTime or p.duration + if p.duration < p.minTime then -- new min ? + p.minTime = p.duration + end + + p.maxTime = p.maxTime or p.duration -- new max ? + if p.duration > p.maxTime then + p.maxTime = p.duration + end + + p.accumulator = p.accumulator + p.duration + level = level - 1 +end + +function ns:Dump() + local view = {} + + for k, _ in pairs(samples) do + table.insert(view, k) + end + + sort(view, function(a, b) + return samples[a].position < samples[b].position + end) + + addon:Print("Profiler Samples") + addon:Print(" Avg | Min | Max | Num | Name") + for _, name in ipairs(view) do + local v = samples[name] + addon:Print(format(" %.1f ms | %.1f ms | %.1f ms | %d | %s", + (v.accumulator/v.numPasses)*1000, v.minTime*1000, v.maxTime*1000, v.numPasses, name)) + end +end + +function ns:GetSampleDuration(name) + local p = samples[name] + return p and p.duration or 0 +end diff --git a/Altoholic-Addon/Altoholic/RecipeDB.lua b/Altoholic-Addon/Altoholic/RecipeDB.lua new file mode 100644 index 0000000..afb145f --- /dev/null +++ b/Altoholic-Addon/Altoholic/RecipeDB.lua @@ -0,0 +1,511 @@ +--[[ + This table is used to determine that the recipe with item ID x teaches you the spell ID y + [x] = y + + As of June 16, 2009, this table is based on information gathered by Ackis for ARL. + source: AckisRecipeList\Datamine.lua, last updated Jan 27th, 2010 +--]] + +------------------------------------------------------------------------------- +-- Mined via Data-tools +-- Table is Public Domain now +-- Look up table of Spell IDs to the recipe which trains them. +------------------------------------------------------------------------------- +local SPELL_ITEM = { + ------------------------------------------------------------------------------- + -- First Aid + ------------------------------------------------------------------------------- + [7929] = 16112, [7935] = 6454, [10840] = 16113, [23787] = 19442, + [27032] = 21992, [27033] = 21993, [45546] = 39152, + + ------------------------------------------------------------------------------- + -- Alchemy + ------------------------------------------------------------------------------- + [2333] = 3396, [2335] = 2555, [3172] = 3393, [3174] = 3394, + [3175] = 3395, [3188] = 6211, [3230] = 2553, [3449] = 6068, + [3450] = 3830, [3451] = 3831, [3453] = 3832, [3454] = 14634, + [4508] = 4597, [4942] = 4624, [6617] = 5640, [6618] = 5643, + [6624] = 5642, [7255] = 6053, [7256] = 6054, [7257] = 6055, + [7258] = 6056, [7259] = 6057, [8240] = 6663, [11453] = 9293, + [11456] = 10644, [11458] = 9294, [11459] = 9303, [11464] = 9295, + [11466] = 9296, [11468] = 9297, [11472] = 9298, [11473] = 9302, + [11476] = 9301, [11477] = 9300, [11479] = 9304, [11480] = 9305, + [17187] = 12958, [17552] = 13476, [17553] = 13477, [17554] = 13478, + [17555] = 13479, [17556] = 13480, [17557] = 13481, [17559] = 13482, + [17560] = 13483, [17561] = 13484, [17562] = 13485, [17563] = 13486, + [17564] = 13487, [17565] = 13488, [17566] = 13489, [17570] = 13490, + [17571] = 13491, [17572] = 13492, [17573] = 13493, [17574] = 13494, + [17575] = 13495, [17576] = 13496, [17577] = 13497, [17578] = 13499, + [17580] = 13501, [17632] = 13517, [17634] = 13518, [17635] = 31354, + [17636] = 31356, [17637] = 31355, [17638] = 31357, [21923] = 17709, + [22732] = 18257, [24365] = 20011, [24366] = 20012, [24367] = 20013, + [24368] = 20014, [25146] = 20761, [26277] = 21547, [28543] = 22900, + [28546] = 22901, [28549] = 22902, [28550] = 22903, [28552] = 22904, + [28553] = 24001, [28554] = 22906, [28555] = 22907, [28556] = 22908, + [28557] = 22909, [28558] = 22910, [28562] = 22911, [28563] = 22912, + [28564] = 35295, [28565] = 22914, [28566] = 22915, [28567] = 22916, + [28568] = 30443, [28569] = 22918, [28570] = 22919, [28571] = 22920, + [28572] = 22921, [28573] = 22922, [28575] = 22923, [28576] = 22924, + [28577] = 22925, [28578] = 35294, [28579] = 22927, [29688] = 23574, + [32765] = 25869, [32766] = 29232, [38960] = 31680, [38961] = 31682, + [38962] = 31681, [39637] = 32070, [39639] = 32071, [42736] = 33209, + [47046] = 35752, [47048] = 35753, [47049] = 35754, [47050] = 35755, + [53936] = 44564, [53937] = 44566, [53938] = 44568, [53939] = 44565, + [53942] = 44567, + + ------------------------------------------------------------------------------- + -- Blacksmithing + ------------------------------------------------------------------------------- + [2667] = 2881, [2673] = 5578, [3295] = 2883, [3297] = 3608, + [3321] = 3609, [3325] = 3610, [3330] = 2882, [3334] = 3611, + [3336] = 3612, [3492] = 12162, [3493] = 3866, [3494] = 10858, + [3495] = 3867, [3496] = 12163, [3497] = 3868, [3498] = 12164, + [3500] = 3869, [3503] = 6047, [3504] = 3870, [3505] = 3871, + [3507] = 3872, [3511] = 3873, [3513] = 3874, [3515] = 3875, + [6518] = 5543, [7221] = 6044, [7222] = 6045, [7224] = 6046, + [8367] = 6735, [9811] = 7978, [9813] = 7979, [9814] = 7980, + [9818] = 7981, [9820] = 7982, [9933] = 7975, [9937] = 7995, + [9939] = 7976, [9945] = 7983, [9950] = 7984, [9952] = 7985, + [9964] = 7989, [9966] = 7991, [9970] = 7990, [9995] = 7992, + [9997] = 8029, [10005] = 7993, [10009] = 8028, [10013] = 8030, + [11454] = 10713, [11643] = 9367, [12259] = 10424, [15292] = 11610, + [15293] = 11614, [15294] = 11611, [15295] = 11615, [15296] = 11612, + [15973] = 12261, [16642] = 12682, [16643] = 12683, [16644] = 12684, + [16645] = 12685, [16646] = 12687, [16647] = 12688, [16648] = 12689, + [16649] = 12690, [16650] = 12691, [16651] = 12692, [16652] = 12693, + [16653] = 12694, [16654] = 12695, [16655] = 12699, [16656] = 12697, + [16657] = 12700, [16658] = 12701, [16659] = 12702, [16660] = 12698, + [16661] = 12703, [16662] = 12704, [16663] = 12705, [16664] = 12706, + [16665] = 12707, [16667] = 12696, [16724] = 12711, [16725] = 12713, + [16726] = 12714, [16728] = 12716, [16729] = 12717, [16730] = 12715, + [16731] = 12718, [16732] = 12719, [16741] = 12720, [16742] = 12725, + [16744] = 12726, [16745] = 12727, [16746] = 12728, [16969] = 12819, + [16970] = 12821, [16971] = 12823, [16973] = 12824, [16978] = 12825, + [16983] = 12827, [16984] = 12828, [16985] = 12830, [16988] = 12833, + [16990] = 12834, [16991] = 12835, [16992] = 12836, [16993] = 12837, + [16994] = 12838, [16995] = 12839, [20872] = 17049, [20873] = 17053, + [20874] = 17051, [20876] = 17052, [20890] = 17059, [20897] = 17060, + [21161] = 18592, [21913] = 17706, [22757] = 18264, [23628] = 19202, + [23629] = 19204, [23632] = 19203, [23633] = 19205, [23636] = 19206, + [23637] = 19207, [23638] = 19208, [23639] = 19209, [23650] = 19210, + [23652] = 19211, [23653] = 19212, [24136] = 19776, [24137] = 19777, + [24138] = 19778, [24139] = 19779, [24140] = 19780, [24141] = 19781, + [24399] = 20040, [24912] = 20553, [24913] = 20555, [24914] = 20554, + [27585] = 22209, [27586] = 22219, [27587] = 22222, [27588] = 22214, + [27589] = 22220, [27590] = 22221, [27829] = 22388, [27830] = 22390, + [27832] = 22389, [28461] = 22766, [28462] = 22767, [28463] = 22768, + [29566] = 23590, [29568] = 23591, [29569] = 23592, [29571] = 23593, + [29603] = 23594, [29605] = 23595, [29606] = 23596, [29608] = 23597, + [29610] = 23599, [29611] = 23598, [29613] = 23600, [29614] = 23601, + [29615] = 23602, [29616] = 23603, [29617] = 23604, [29619] = 23605, + [29620] = 23606, [29621] = 23607, [29622] = 23621, [29628] = 23608, + [29629] = 23609, [29630] = 23610, [29642] = 23611, [29643] = 23612, + [29645] = 23613, [29648] = 23615, [29649] = 23617, [29656] = 23618, + [29657] = 24002, [29658] = 23620, [29662] = 23622, [29663] = 23623, + [29664] = 23624, [29668] = 23625, [29669] = 23626, [29671] = 23627, + [29672] = 23628, [29692] = 23629, [29693] = 23630, [29694] = 23631, + [29695] = 23632, [29696] = 23633, [29697] = 23634, [29698] = 23635, + [29699] = 23636, [29700] = 23637, [29728] = 23638, [29729] = 23639, + [32285] = 25526, [32656] = 25846, [32657] = 25847, [34608] = 28632, + [36389] = 30321, [36390] = 30322, [36391] = 30323, [36392] = 30324, + [38473] = 31390, [38475] = 31391, [38476] = 31392, [38477] = 31393, + [38478] = 31394, [38479] = 31395, [40033] = 32441, [40034] = 32442, + [40035] = 32443, [40036] = 32444, [41132] = 32736, [41133] = 32737, + [41134] = 32738, [41135] = 32739, [42688] = 35296, [43549] = 33792, + [43846] = 33954, [46140] = 35208, [46141] = 35209, [46142] = 35210, + [46144] = 35211, [54978] = 41124, [54979] = 41123, [54980] = 41120, + [54981] = 41122, [62202] = 44938, [63187] = 45088, [63188] = 45089, + [63189] = 45090, [63190] = 45091, [63191] = 45092, [63192] = 45093, + [67091] = 47622, [67130] = 47460, [67092] = 47623, [67131] = 47641, + [67096] = 47627, [67135] = 47642, [67095] = 47626, [67134] = 47643, + [67093] = 47624, [67132] = 47644, [67094] = 47625, [67133] = 47645, + + ------------------------------------------------------------------------------- + -- Cooking + ------------------------------------------------------------------------------- + [2542] = 2697, [2543] = 728, [2545] = 2698, [2547] = 2699, + [2548] = 2700, [2549] = 2701, [2795] = 2889, [3370] = 3678, + [3371] = 3679, [3372] = 3680, [3373] = 3681, [3376] = 3682, + [3377] = 3683, [3397] = 3734, [3398] = 3735, [3399] = 3736, + [3400] = 3737, [4094] = 4609, [6412] = 5482, [6413] = 5483, + [6414] = 5484, [6415] = 5485, [6416] = 5486, [6417] = 44977, + [6418] = 5488, [6419] = 5489, [6501] = 5528, [7213] = 6039, + [7751] = 6325, [7752] = 6326, [7753] = 6328, [7754] = 6329, + [7755] = 6330, [7827] = 6368, [7828] = 6369, [8238] = 6661, + [8607] = 6892, [9513] = 18160, [15853] = 12227, [15855] = 12228, + [15856] = 12229, [15861] = 12231, [15863] = 12232, [15865] = 12233, + [15906] = 12239, [15910] = 12240, [15915] = 16111, [15933] = 16110, + [15935] = 12226, [18238] = 13939, [18239] = 13940, [18240] = 13942, + [18241] = 13941, [18242] = 13943, [18243] = 13945, [18244] = 13946, + [18245] = 13947, [18246] = 13948, [18247] = 13949, [20626] = 16767, + [20916] = 17062, [21143] = 17200, [21144] = 17201, [22480] = 18046, + [22761] = 18267, [24418] = 20075, [25659] = 21025, [25704] = 21099, + [25954] = 21219, [28267] = 22647, [33276] = 27685, [33277] = 27686, + [33278] = 27687, [33279] = 27684, [33284] = 27688, [33285] = 27689, + [33286] = 27690, [33287] = 27691, [33288] = 27692, [33289] = 27693, + [33290] = 27694, [33291] = 27695, [33292] = 27696, [33293] = 27697, + [33294] = 27698, [33295] = 27699, [33296] = 27700, [36210] = 30156, + [38867] = 31675, [38868] = 31674, [43707] = 33870, [43758] = 33871, + [43761] = 33869, [43765] = 33873, [43772] = 33875, [43779] = 33925, + [45022] = 34413, [45555] = 43018, [45556] = 43019, [45557] = 43020, + [45558] = 43021, [45559] = 43022, [45567] = 43023, [45568] = 43024, + [45570] = 43026, [45571] = 43025, [45695] = 34834, [46684] = 35564, + [46688] = 35566, [53056] = 39644, [57423] = 43017, [57433] = 43027, + [57434] = 43028, [57435] = 43029, [57436] = 43030, [57437] = 43031, + [57438] = 43032, [57439] = 43033, [57440] = 43034, [57441] = 43035, + [57442] = 43036, [57443] = 43037, [58512] = 43507, [58521] = 43508, + [58523] = 43509, [58525] = 43510, [58527] = 43505, [58528] = 43506, + [62350] = 44954, + + ------------------------------------------------------------------------------- + -- Enchanting + ------------------------------------------------------------------------------- + [7443] = 6342, [7766] = 6344, [7776] = 6346, [7782] = 6347, + [7786] = 6348, [7793] = 6349, [7859] = 6375, [7867] = 6377, + [13380] = 11038, [13419] = 11039, [13464] = 11081, [13522] = 11098, + [13536] = 11101, [13612] = 11150, [13617] = 11151, [13620] = 11152, + [13646] = 11163, [13653] = 11164, [13655] = 11165, [13687] = 11167, + [13689] = 11168, [13698] = 11166, [13817] = 11202, [13841] = 11203, + [13846] = 11204, [13868] = 11205, [13882] = 11206, [13898] = 11207, + [13915] = 11208, [13931] = 11223, [13933] = 11224, [13945] = 11225, + [13947] = 11226, [15596] = 11813, [15596] = 45050, + [20009] = 16218, [20010] = 16246, [20011] = 16251, [20012] = 16219, + [20014] = 16216, [20015] = 16224, [20016] = 16222, + [20017] = 16217, [20020] = 16215, [20023] = 16245, [20024] = 16220, + [20025] = 16253, [20026] = 16221, [20028] = 16242, [20029] = 16223, + [20030] = 16247, [20031] = 16250, [20032] = 16254, [20033] = 16248, + [20034] = 16252, [20035] = 16255, [20036] = 16249, [20051] = 16243, + [21931] = 17725, [22749] = 18259, [22750] = 18260, [23799] = 19444, + [23800] = 19445, [23801] = 19446, [23802] = 19447, [23803] = 19448, + [23804] = 19449, [25072] = 33153, [25072] = 20726, [25073] = 20727, + [25074] = 20728, [25078] = 20729, [25079] = 20730, [25080] = 33152, + [25080] = 20731, [25081] = 20732, [25082] = 20733, [25083] = 33149, + [25083] = 20734, [25084] = 20735, [25084] = 33150, [25084] = 33151, + [25086] = 20736, [25086] = 33148, [25124] = 20758, [25125] = 20752, + [25126] = 20753, [25127] = 20754, [25128] = 20755, [25129] = 20756, + [25130] = 20757, [27837] = 22392, [27906] = 22530, [27911] = 22531, + [27911] = 24000, [27913] = 22532, [27914] = 22533, [27917] = 22534, + [27920] = 22535, [27924] = 22536, [27926] = 22537, [27927] = 22538, + [27945] = 22539, [27946] = 22540, [27947] = 22541, [27948] = 35298, + [27948] = 22542, [27950] = 22543, [27951] = 22544, [27954] = 22545, + [27960] = 24003, [27960] = 22547, [27962] = 22548, [27967] = 22552, + [27968] = 22551, [27971] = 22554, [27972] = 22553, [27975] = 22555, + [27977] = 22556, [27981] = 22560, [27982] = 22561, [27984] = 22559, + [28003] = 22558, [28004] = 22557, [28016] = 22562, [28019] = 22563, + [28022] = 22565, [32665] = 25848, [32667] = 25849, [33992] = 28270, + [33994] = 28271, [33997] = 28272, [33999] = 28273, [34003] = 28274, + [34005] = 28276, [34006] = 28277, [34007] = 35299, [34007] = 28279, + [34008] = 35297, [34008] = 28280, [34009] = 28282, [34010] = 28281, + [42620] = 33165, [42974] = 33307, [44483] = 37332, [44494] = 37333, + [44524] = 37344, [44556] = 37331, [44575] = 44484, [44576] = 44494, + [44588] = 37340, [44590] = 37334, [44591] = 37347, [44595] = 44473, + [44596] = 37330, [44621] = 37339, [44625] = 44485, [44631] = 37349, + [45765] = 34872, [46578] = 35498, [46594] = 35500, [47051] = 35756, + [47672] = 44471, [47898] = 44472, [47899] = 44488, [47901] = 44491, + [59619] = 44496, [59621] = 44492, [59625] = 44495, [60691] = 44483, + [60692] = 44489, [60707] = 44486, [60714] = 44487, [60763] = 44490, + [60767] = 44498, [62256] = 44944, [62257] = 44945, [62948] = 45059, + [64441] = 46027, [64579] = 46348, + + ------------------------------------------------------------------------------- + --Engineering + ------------------------------------------------------------------------------- + [3928] = 4408, [3933] = 4409, [3939] = 13309, [3940] = 4410, + [3944] = 4411, [3952] = 14639, [3954] = 4412, [3957] = 13308, + [3959] = 4413, [3960] = 4414, [3966] = 4415, [3968] = 4416, + [3969] = 13311, [3971] = 7742, [3972] = 4417, [3979] = 13310, + [8243] = 6672, [8339] = 6716, [9269] = 7560, [9273] = 7561, + [12587] = 10601, [12597] = 10602, [12607] = 10603, [12614] = 10604, + [12615] = 10605, [12616] = 10606, [12617] = 10607, [12620] = 10608, + [12624] = 10609, [15628] = 11828, [15633] = 11827, [19790] = 16041, + [19791] = 16042, [19792] = 16043, [19793] = 16044, [19794] = 16045, + [19795] = 16047, [19796] = 16048, [19799] = 16049, [19800] = 16051, + [19814] = 16046, [19815] = 16050, [19819] = 16052, [19825] = 16053, + [19830] = 16054, [19831] = 16055, [19833] = 16056, [21940] = 17720, + [22793] = 18290, [22795] = 18292, [22797] = 18291, [23066] = 18647, + [23067] = 18649, [23068] = 18648, [23069] = 18650, [23071] = 18651, + [23077] = 18652, [23078] = 18653, [23079] = 18655, [23080] = 18656, + [23081] = 18657, [23082] = 18658, [23096] = 18654, [23129] = 18661, + [23507] = 19027, [24356] = 20000, [24357] = 20001, [26416] = 21724, + [26417] = 21725, [26418] = 21726, [26420] = 21727, [26421] = 21728, + [26422] = 21729, [26423] = 21730, [26424] = 21731, [26425] = 21732, + [26426] = 21733, [26427] = 21734, [26428] = 21735, [26442] = 44919, + [26443] = 44918, [28327] = 22729, [30313] = 23799, [30314] = 23800, + [30315] = 23802, [30316] = 23803, [30317] = 23804, [30318] = 23805, + [30325] = 23806, [30329] = 23807, [30332] = 23808, [30334] = 23809, + [30337] = 23810, [30341] = 23811, [30344] = 23814, [30347] = 23815, + [30348] = 23816, [30349] = 23817, [30547] = 23874, [30548] = 23888, + [30551] = 35310, [30552] = 35311, [30556] = 23887, [32814] = 25887, + [39895] = 32381, [43676] = 33804, [44391] = 34114, [46106] = 35191, + [46107] = 35187, [46108] = 35189, [46109] = 35190, [46110] = 35192, + [46111] = 35186, [46112] = 35193, [46113] = 35194, [46114] = 35195, + [46115] = 35196, [46116] = 35197, [46697] = 35582, [60866] = 44502, [60867] = 44503, + + ------------------------------------------------------------------------------- + --Inscription + ------------------------------------------------------------------------------- + + ------------------------------------------------------------------------------- + --Jewelcrafting + ------------------------------------------------------------------------------- + [25320] = 20856, [25323] = 20855, [25339] = 20854, [25610] = 20970, + [25612] = 20971, [25617] = 20973, [25618] = 20974, [25619] = 20975, + [25622] = 20976, [26873] = 21940, [26875] = 21941, [26878] = 21942, + [26881] = 21943, [26882] = 21944, [26887] = 21945, [26896] = 21947, + [26897] = 21948, [26900] = 21949, [26906] = 21952, [26909] = 21953, + [26910] = 21954, [26912] = 21955, [26914] = 21956, [26915] = 21957, + [28903] = 23130, [28905] = 23131, [28906] = 23133, [28907] = 23134, + [28910] = 23135, [28912] = 23136, [28914] = 23137, [28915] = 23138, + [28916] = 23140, [28917] = 23141, [28918] = 31359, [28924] = 23143, + [28927] = 23145, [28933] = 23146, [28936] = 23147, + [28938] = 23148, [28944] = 23149, [28947] = 23150, [28948] = 23151, + [28950] = 23152, [28953] = 23153, [28955] = 23154, [28957] = 23155, + [31053] = 24158, [31054] = 24159, [31055] = 24160, [31056] = 24161, + [31057] = 24162, [31058] = 24163, [31060] = 24164, [31061] = 24165, + [31062] = 24174, [31063] = 24175, [31064] = 24176, [31065] = 24177, + [31066] = 24178, [31067] = 24166, [31068] = 24167, [31070] = 24168, + [31071] = 24169, [31072] = 24170, [31076] = 24171, [31077] = 24172, + [31078] = 24173, [31079] = 24179, [31080] = 31358, [31081] = 24181, + [31082] = 24182, [31083] = 24183, [31084] = 24193, [31085] = 24194, + [31087] = 24195, [31088] = 35305, [31089] = 35306, [31090] = 24197, + [31091] = 24198, [31092] = 35304, [31094] = 24201, [31095] = 24202, + [31096] = 24203, [31097] = 24204, [31098] = 35307, [31099] = 24206, + [31100] = 24207, [31101] = 24208, [31102] = 24209, [31103] = 24210, + [31104] = 24211, [31105] = 24212, [31106] = 24213, [31107] = 24214, + [31108] = 24215, [31109] = 24216, [31110] = 24217, [31111] = 24218, + [31112] = 24219, [31113] = 24220, [31149] = 24200, [32866] = 25902, + [32867] = 25903, [32868] = 25905, [32869] = 25906, [32870] = 25904, + [32871] = 25907, [32872] = 25909, [32873] = 25908, [32874] = 25910, + [34069] = 28291, [34590] = 28596, [37855] = 30826, [38503] = 31401, + [38504] = 31402, [39451] = 31870, [39452] = 31875, [39455] = 31871, + [39458] = 31872, [39462] = 31877, [39463] = 31876, [39466] = 31873, + [39467] = 31874, [39470] = 31878, [39471] = 31879, [39705] = 35244, + [39706] = 35246, [39710] = 35250, [39711] = 35248, [39712] = 35245, + [39713] = 35249, [39714] = 35247, [39715] = 35263, [39716] = 35264, + [39717] = 35262, [39718] = 35265, [39719] = 35255, [39720] = 35260, + [39721] = 35259, [39722] = 35256, [39723] = 35261, [39724] = 35258, + [39725] = 35257, [39727] = 35243, [39728] = 35242, [39729] = 35238, + [39730] = 35240, [39731] = 35239, [39732] = 35241, [39733] = 35267, + [39734] = 35269, [39735] = 35268, [39736] = 35266, [39737] = 35270, + [39738] = 35271, [39739] = 35252, [39740] = 35254, [39741] = 35251, + [39742] = 35253, [39961] = 33622, [39963] = 32411, [42558] = 33305, + [42588] = 33155, [42589] = 33156, [42590] = 33157, [42591] = 33158, + [42592] = 33159, [42593] = 33160, [43493] = 33783, [44794] = 34689, + [46122] = 35198, [46123] = 35538, [46124] = 35200, [46125] = 35201, + [46126] = 35533, [46127] = 35203, [46403] = 35322, [46404] = 35323, + [46405] = 35325, [46597] = 35502, [46601] = 35505, [46775] = 35695, + [46776] = 35696, [46777] = 35697, [46778] = 35698, [46779] = 35699, + [46803] = 35708, [47053] = 35769, [47054] = 35766, [47055] = 35767, + [47056] = 35768, [48789] = 37504, [53830] = 41576, [53857] = 41559, + [53865] = 41575, [53869] = 41574, [53875] = 41566, [53877] = 41562, + [53879] = 41565, [53884] = 41563, [53885] = 41561, [53888] = 41564, + [53917] = 41567, [53919] = 41572, [53921] = 41568, [53924] = 41571, + [53929] = 41573, [53932] = 41570, [53933] = 41569, [53943] = 41560, + [53945] = 41577, [53946] = 41718, [53948] = 41719, [53949] = 41578, + [53950] = 41817, [53951] = 41790, [53952] = 42138, [53954] = 41581, + [53955] = 41728, [53957] = 41720, [53958] = 41580, [53959] = 41791, + [53960] = 41727, [53961] = 41579, [53962] = 41784, [53963] = 41747, + [53964] = 41785, [53965] = 41725, [53966] = 41783, [53967] = 41701, + [53968] = 41740, [53970] = 41796, [53971] = 41703, [53972] = 41820, + [53973] = 41702, [53974] = 41726, [53975] = 41789, [53976] = 41777, + [53977] = 41780, [53978] = 41734, [53979] = 41794, [53980] = 41582, + [53981] = 41733, [53982] = 41792, [53983] = 41689, [53984] = 41686, + [53985] = 41688, [53986] = 41730, [53987] = 41690, [53988] = 41721, + [53990] = 41732, [53991] = 41687, [53992] = 41779, [53993] = 41722, + [53994] = 41818, [53995] = 41795, [53996] = 41723, [53997] = 41698, + [53998] = 41697, [54000] = 41738, [54001] = 41693, [54002] = 41699, + [54003] = 41781, [54004] = 41782, [54005] = 41737, [54006] = 41694, + [54008] = 41724, [54009] = 41696, [54010] = 41739, [54011] = 41692, + [54012] = 41819, [54013] = 41736, [54014] = 41735, [54019] = 41793, + [54023] = 41778, [55384] = 41705, [55387] = 41743, [55388] = 41744, + [55389] = 41704, [55390] = 41786, [55392] = 41706, [55393] = 41742, + [55395] = 41787, [55396] = 41708, [55397] = 41798, [55398] = 41799, + [55400] = 41710, [55401] = 41797, [55403] = 41711, [55404] = 41709, + [55405] = 41788, [55407] = 41707, [56049] = 42298, [56052] = 42301, + [56053] = 42309, [56054] = 42299, [56055] = 42314, [56056] = 42302, + [56074] = 42300, [56076] = 42303, [56077] = 42304, [56079] = 42305, + [56081] = 42306, [56083] = 42307, [56084] = 42308, [56085] = 42310, + [56086] = 42311, [56087] = 42312, [56088] = 42313, [56089] = 42315, + [56496] = 42648, [56497] = 42649, [56498] = 42650, [56499] = 42651, + [56500] = 42652, [56501] = 42653, [58147] = 43317, [58148] = 43318, + [58149] = 43319, [58150] = 43320, [58492] = 43485, [58507] = 43497, + [58954] = 43597, [66556] = 46937, [66447] = 46917 , [66429] = 46899, + [66557] = 46938, [66430] = 46900, [66432] = 46902, [66433] = 46903, + [66497] = 46924, [66561] = 46942, [66434] = 46904, [66498] = 46925, + [66499] = 46926, [66436] = 46906, [66500] = 46927, [66437] = 46907, + [66501] = 46928, [66565] = 46946, [66438] = 46908, [66502] = 46929, + [66566] = 46947, [66439] = 46909, [66503] = 46930 , [66567] = 46948, + [66440] = 46910, [66504] = 46931, [66441] = 46911, [66505] = 46932, + [66569] = 46950, [66442] = 46912, [66506] = 46933, [66570] = 46951, + [66443] = 46913, [66444] = 46914, [66572] = 46953, [66445] = 46915, + [66573] = 46956, [66446] = 46916, [66574] = 47007, [66575] = 47008, + [66448] = 46918, [66576] = 47010, [66449] = 46919, [66577] = 47011, + [66450] = 46920, [66578] = 47012, [66451] = 46921, [66579] = 47015, + [66452] = 46922, [66580] = 47016, [66453] = 46923, [66581] = 47017, + [66582] = 47018, [66583] = 47019, [66584] = 47020, [66586] = 47022, + [68253] = 49112, [66338] = 46897, [66571] = 46952, [66564] = 46945, + [66562] = 46943, [66560] = 46941, [66558] = 46939, [66554] = 46935, + [66559] = 46940, [66585] = 47021, [66555] = 46936, [66587] = 47023, + [66431] = 46901, [66428] = 46898, [66435] = 46905, [66563] = 46944, + [66553] = 46934 , [66568] = 46949, + + ------------------------------------------------------------------------------- + --Leatherworking + ------------------------------------------------------------------------------- + [2158] = 2406, [2163] = 2407, [2164] = 2408, [2169] = 2409, + [3762] = 4293, [3765] = 7360, [3767] = 4294, [3769] = 4296, + [3771] = 4297, [3772] = 7613, [3773] = 4299, [3775] = 4298, + [3777] = 4300, [3778] = 14635, [3779] = 4301, [4096] = 13287, + [4097] = 13288, [5244] = 5083, [6702] = 5786, [6703] = 5787, + [6704] = 5788, [6705] = 5789, [7133] = 5972, [7149] = 5973, + [7153] = 5974, [7953] = 6474, [7954] = 6475, [7955] = 6476, + [8322] = 6710, [9064] = 7288, [9070] = 7289, [9072] = 7290, + [9146] = 7361, [9147] = 7362, [9148] = 7363, [9149] = 7364, + [9195] = 7449, [9197] = 7450, [9202] = 7451, [9207] = 7452, + [9208] = 7453, [10490] = 8384, [10509] = 8385, [10516] = 8409, + [10520] = 8386, [10525] = 8395, [10529] = 8403, [10531] = 8387, + [10533] = 8397, [10542] = 8398, [10544] = 8404, [10546] = 8405, + [10554] = 8399, [10560] = 8389, [10562] = 8390, [10564] = 8400, + [10566] = 8406, [10568] = 8401, [10570] = 8402, [10572] = 8407, + [10574] = 8408, [19048] = 15724, [19049] = 15725, [19050] = 15726, + [19051] = 15727, [19052] = 15728, [19053] = 15729, [19054] = 15730, + [19055] = 15731, [19059] = 15732, [19060] = 15733, [19061] = 15734, + [19062] = 15735, [19063] = 15737, [19064] = 15738, [19065] = 15739, + [19066] = 15740, [19067] = 15741, [19068] = 20253, [19070] = 15743, + [19071] = 15744, [19072] = 15745, [19073] = 15746, [19074] = 15747, + [19075] = 15748, [19076] = 15749, [19077] = 15751, [19078] = 15752, + [19079] = 15753, [19080] = 20254, [19081] = 15755, [19082] = 15756, + [19083] = 15757, [19084] = 15758, [19085] = 15759, [19086] = 15760, + [19087] = 15761, [19088] = 15762, [19089] = 15763, [19090] = 15764, + [19091] = 15765, [19092] = 15768, [19093] = 15769, [19094] = 15770, + [19095] = 15771, [19097] = 15772, [19098] = 15773, [19100] = 15774, + [19101] = 15775, [19102] = 15776, [19103] = 15777, [19104] = 15779, + [19107] = 15781, [20853] = 17022, [20854] = 17023, [20855] = 17025, + [21943] = 17722, [22711] = 18239, [22727] = 18252, [22921] = 18514, + [22922] = 18515, [22923] = 18516, [22926] = 18517, [22927] = 18518, + [22928] = 18519, [23190] = 18731, [23399] = 18949, [23703] = 19326, + [23704] = 19327, [23705] = 19328, [23706] = 19329, [23707] = 19330, + [23708] = 19331, [23709] = 19332, [23710] = 19333, [24121] = 19769, + [24122] = 19770, [24123] = 19771, [24124] = 19772, [24125] = 19773, + [24703] = 20382, [24846] = 20506, [24847] = 20507, [24848] = 20508, + [24849] = 20509, [24850] = 20510, [24851] = 20511, [24940] = 20576, + [26279] = 21548, [28472] = 22771, [28473] = 22770, [28474] = 22769, + [32455] = 25720, [32457] = 25721, [32458] = 25722, [32461] = 25725, + [32482] = 25726, [32485] = 25728, [32487] = 25729, [32488] = 25731, + [32489] = 25730, [32490] = 25732, [32493] = 25733, [32494] = 25734, + [32495] = 25735, [32496] = 25736, [32497] = 25737, [32498] = 29213, + [32499] = 29214, [32500] = 29215, [32501] = 29217, [32502] = 29219, + [32503] = 29218, [35520] = 29669, [35521] = 29672, [35522] = 29673, + [35523] = 29674, [35524] = 29675, [35525] = 29677, [35526] = 29682, + [35527] = 29684, [35528] = 29691, [35529] = 29689, [35530] = 30444, + [35531] = 29693, [35532] = 29698, [35533] = 29700, [35534] = 29701, + [35535] = 29702, [35536] = 29703, [35537] = 29704, [35538] = 29713, + [35539] = 34175, [35543] = 29717, [35544] = 34173, [35549] = 31361, + [35554] = 31362, [35555] = 29720, [35557] = 29721, [35558] = 29723, + [35559] = 35302, [35560] = 29725, [35561] = 29726, [35562] = 35303, + [35563] = 29728, [35564] = 29729, [35567] = 29730, [35568] = 35300, + [35572] = 29732, [35573] = 35301, [35574] = 29734, [36349] = 30301, + [36351] = 30302, [36352] = 30303, [36353] = 30304, [36355] = 30305, + [36357] = 30306, [36358] = 30307, [36359] = 30308, [39997] = 32429, + [40001] = 32431, [40002] = 32432, [40003] = 32433, [40004] = 32434, + [40005] = 32435, [40006] = 32436, [41156] = 32744, [41157] = 35523, + [41158] = 35527, [41160] = 35528, [41161] = 35517, [41162] = 35524, + [41163] = 35520, [41164] = 35521, [42546] = 33124, [42731] = 33205, + [44359] = 34200, [44768] = 34218, [44953] = 34262, [45117] = 34491, + [46132] = 35546, [46133] = 35541, [46134] = 35214, [46135] = 35215, + [46136] = 35216, [46137] = 35217, [46138] = 35218, [46139] = 35549, + [50970] = 44509, [50971] = 44510, [52733] = 32430, [57683] = 43097, + [57692] = 44559, [57694] = 44560, [57696] = 44561, [57699] = 44562, + [57701] = 44563, [60645] = 44511, [60647] = 44512, [60697] = 44513, + [60702] = 44514, [60703] = 44515, [60704] = 44516, [60705] = 44517, + [60706] = 44518, [60711] = 44519, [60712] = 44520, [60715] = 44521, + [60716] = 44522, [60718] = 44523, [60720] = 44524, [60721] = 44525, + [60723] = 44526, [60725] = 44527, [60727] = 44528, [60728] = 44530, + [60729] = 44531, [60730] = 44532, [60731] = 44533, [60732] = 44534, + [60734] = 44535, [60735] = 44536, [60737] = 44537, [60743] = 44538, + [60746] = 44539, [60747] = 44540, [60748] = 44541, [60749] = 44542, + [60750] = 44543, [60751] = 44544, [60752] = 44545, [60754] = 44546, + [60755] = 44547, [60756] = 44548, [60757] = 44549, [60758] = 44550, + [60759] = 44551, [60760] = 44552, [60761] = 44553, [60996] = 44584, + [60997] = 44585, [60998] = 44586, [60999] = 44587, [61000] = 44588, + [61002] = 44589, [62176] = 44932, [62177] = 44933, [63194] = 45094, + [63195] = 45095, [63196] = 45096, [63197] = 45097, [63198] = 45098, + [63199] = 45099, [63200] = 45100, [63201] = 45101, + + ------------------------------------------------------------------------------- + --Smelting + ------------------------------------------------------------------------------- + [22967] = 44956, [46353] = 35273, + + ------------------------------------------------------------------------------- + --Tailoring + ------------------------------------------------------------------------------- + [2389] = 2598, [2403] = 2601, [3758] = 4292, [3844] = 4346, + [3847] = 4345, [3849] = 4347, [3851] = 4349, [3854] = 7114, + [3856] = 4350, [3857] = 14630, [3858] = 4351, [3860] = 4352, + [3862] = 4355, [3863] = 4353, [3864] = 4356, [3868] = 4348, + [3869] = 14627, [3870] = 6401, [3872] = 4354, [3873] = 10728, + [6686] = 5771, [6688] = 5772, [6692] = 5773, [6693] = 5774, + [6695] = 5775, [7629] = 6271, [7630] = 6270, [7633] = 6272, + [7639] = 6274, [7643] = 6275, [7892] = 6390, [7893] = 6391, + [8780] = 7092, [8782] = 7091, [8784] = 7090, [8786] = 7089, + [8789] = 7087, [8793] = 7084, [8795] = 7085, [8797] = 7086, + [8802] = 7088, [12047] = 10316, [12056] = 10300, [12059] = 10301, + [12060] = 10302, [12064] = 10311, [12066] = 10312, [12075] = 10314, + [12078] = 10315, [12080] = 10317, [12081] = 10318, [12084] = 10320, + [12085] = 10321, [12086] = 10463, [12089] = 10323, [12091] = 10325, + [12093] = 10326, [18403] = 14466, [18404] = 14467, [18405] = 14468, + [18406] = 14469, [18407] = 14470, [18408] = 14471, [18409] = 14472, + [18410] = 14473, [18411] = 14474, [18412] = 14476, [18413] = 14477, + [18414] = 14478, [18415] = 14479, [18416] = 14480, [18417] = 14481, + [18418] = 14482, [18419] = 14483, [18420] = 14484, [18421] = 14485, + [18422] = 14486, [18423] = 14488, [18424] = 14489, [18434] = 14490, + [18436] = 14493, [18437] = 14492, [18438] = 14491, [18439] = 14494, + [18440] = 14497, [18441] = 14495, [18442] = 14496, [18444] = 14498, + [18445] = 14499, [18446] = 14500, [18447] = 14501, [18448] = 14507, + [18449] = 14504, [18450] = 14505, [18451] = 14506, [18452] = 14509, + [18453] = 14508, [18454] = 14511, [18455] = 14510, [18456] = 14512, + [18457] = 14513, [18458] = 14514, [18560] = 14526, [20848] = 17017, + [20849] = 17018, [21945] = 17724, [22759] = 18265, [22866] = 18414, + [22867] = 18415, [22868] = 18416, [22869] = 18417, [22870] = 18418, + [22902] = 18487, [23662] = 19215, [23663] = 19218, [23664] = 19216, + [23665] = 19217, [23666] = 19219, [23667] = 19220, [24091] = 19764, + [24092] = 19765, [24093] = 19766, [24901] = 20546, [24902] = 20548, + [24903] = 20547, [26085] = 21358, [26087] = 21371, [26403] = 44916, + [26407] = 44917, [26747] = 21892, [26749] = 21893, [26750] = 21894, + [26751] = 21895, [26752] = 21908, [26753] = 21909, [26754] = 21910, + [26755] = 21911, [26756] = 21912, [26757] = 21914, [26758] = 21913, + [26759] = 21915, [26760] = 21916, [26761] = 21918, [26762] = 21917, + [26763] = 21919, [26773] = 21896, [26774] = 21897, [26775] = 21898, + [26776] = 21899, [26777] = 21900, [26778] = 21901, [26779] = 21902, + [26780] = 21903, [26781] = 21904, [26782] = 21905, [26783] = 21906, + [26784] = 21907, [27658] = 22307, [27659] = 22308, [27660] = 22309, + [27724] = 22310, [27725] = 22312, [28210] = 22683, [28480] = 22774, + [28481] = 22773, [28482] = 22772, [31373] = 24316, [31430] = 24292, + [31431] = 24293, [31432] = 24294, [31433] = 24295, [31434] = 35308, + [31435] = 24297, [31437] = 24298, [31438] = 24299, [31440] = 24300, + [31441] = 24301, [31442] = 35309, [31443] = 24303, [31444] = 24304, + [31448] = 24305, [31449] = 24306, [31450] = 24307, [31451] = 24308, + [31452] = 24309, [31453] = 24310, [31454] = 24311, [31455] = 24312, + [31456] = 24313, [31459] = 24314, [36315] = 30280, [36316] = 30281, + [36317] = 30282, [36318] = 30283, [36686] = 30483, [37873] = 30833, + [37882] = 30842, [37883] = 30843, [37884] = 30844, [40020] = 32437, + [40021] = 32438, [40023] = 32439, [40024] = 32440, [40060] = 32447, + [41205] = 35518, [41206] = 32755, [41207] = 32752, [41208] = 32753, + [44950] = 34261, [44958] = 34319, [46128] = 35204, [46129] = 35205, + [46130] = 35206, [46131] = 35207, [49677] = 37915, [50194] = 38229, + [50644] = 38327, [50647] = 38328, [55993] = 42172, [55994] = 42173, + [55996] = 42175, [55997] = 42177, [55998] = 42176, [55999] = 42178, + [56004] = 42183, [56005] = 42184, [56006] = 42185, [56009] = 42187, + [56011] = 42188, [63924] = 45774, +} + +-- create the reverse table, which is what we actually need +Altoholic.RecipeDB = {} +for k, v in pairs(SPELL_ITEM) do + Altoholic.RecipeDB[v] = k +end + +-- release memory +wipe(SPELL_ITEM) +SPELL_ITEM = nil diff --git a/Altoholic-Addon/Altoholic/Suggestions.lua b/Altoholic-Addon/Altoholic/Suggestions.lua new file mode 100644 index 0000000..50b8331 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Suggestions.lua @@ -0,0 +1,587 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() +local BF = LibStub("LibBabble-Faction-3.0"):GetLookupTable() + +-- temporary test, until all locales are done for the suggestions, test the ones that are done in order to use them instead of enUS, this test will be replaced later on. +if (GetLocale() == "frFR") or + (GetLocale() == "ruRU") or + (GetLocale() == "deDE") or + (GetLocale() == "zhCN") or + (GetLocale() == "zhTW") then return end -- exit to use zhCN, zhTW or frFR instead of enUS + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +-- This table contains a list of suggestions to get to the next level of reputation, craft or skill +addon.Suggestions = { + [L["Riding"]] = { + { 75, "Apprentice riding skill (Lv 20): |cFFFFFFFF4g\n|cFFFFD700Standard mount in/near a capital city: |cFFFFFFFF1g" }, + { 150, "Journeyman riding skill (Lv 40): |cFFFFFFFF50g\n|cFFFFD700Epic mount in/near a capital city: |cFFFFFFFF10g" }, + { 225, "Expert riding skill (Lv 60): |cFFFFFFFF600g\n|cFFFFD700Flying mount in Shadowmoon Valley: |cFFFFFFFF50g" }, + { 300, "Artisan riding skill (Lv 70): |cFFFFFFFF5000g\n|cFFFFD700Epic flying mount in Shadowmoon Valley: |cFFFFFFFF200g" } + }, + + -- source : http://forums.worldofwarcraft.com/thread.html?topicId=102789457&sid=1 + -- ** Primary professions ** + [BI["Tailoring"]] = { + { 50, "Up to 50: Bolt of Linen Cloth" }, + { 70, "Up to 70: Linen Bag" }, + { 75, "Up to 75: Reinforced Linen Cape" }, + { 105, "Up to 105: Bolt of Woolen Cloth" }, + { 110, "Up to 110: Gray Woolen Shirt"}, + { 125, "Up to 125: Double-stitched Woolen Shoulders" }, + { 145, "Up to 145: Bolt of Silk Cloth" }, + { 160, "Up to 160: Azure Silk Hood" }, + { 170, "Up to 170: Silk Headband" }, + { 175, "Up to 175: Formal White Shirt" }, + { 185, "Up to 185: Bolt of Mageweave" }, + { 205, "Up to 205: Crimson Silk Vest" }, + { 215, "Up to 215: Crimson Silk Pantaloons" }, + { 220, "Up to 220: Black Mageweave Leggings\nor Black Mageweave Vest" }, + { 230, "Up to 230: Black Mageweave Gloves" }, + { 250, "Up to 250: Black Mageweave Headband\nor Black Mageweave Shoulders" }, + { 260, "Up to 260: Bolt of Runecloth" }, + { 275, "Up to 275: Runecloth Belt" }, + { 280, "Up to 280: Runecloth Bag" }, + { 300, "Up to 300: Runecloth Gloves" }, + { 325, "Up to 325: Bolts of Netherweave\n|cFFFFD700Don't sell them, you'll need them later" }, + { 340, "Up to 340: Bolts of Imbued Netherweave\n|cFFFFD700Don't sell them, you'll need them later" }, + { 350, "Up to 350: Netherweave Boots\n|cFFFFD700Disenchant them for Arcane Dust" }, + { 375, "Up to 375: Bolts of Frostweave" }, + { 380, "Up to 380: Frostwoven Boots" }, + { 395, "Up to 395: Frostwoven Cowl" }, + { 405, "Up to 405: Duskweave Cowl" }, + { 410, "Up to 410: Duskweave Wristwraps" }, + { 415, "Up to 415: Duskweave Gloves" }, + { 425, "Up to 425: Ebonweave, Moonshroud, or Spellweave\nFrostweave Bag" }, + { 450, "Up to 450: Whatever makes you earn a point,\ndepending on your needs" } + }, + [BI["Leatherworking"]] = { + { 35, "Up to 35: Light Armour Kit" }, + { 55, "Up to 55: Cured Light Hide" }, + { 85, "Up to 85: Embossed Leather Gloves" }, + { 100, "Up to 100: Fine Leather Belt" }, + { 120, "Up to 120: Cured Medium Hide" }, + { 125, "Up to 125: Fine Leather Belt" }, + { 150, "Up to 150: Dark Leather Belt" }, + { 160, "Up to 160: Cured Heavy Hide" }, + { 170, "Up to 170: Heavy Armour Kit" }, + { 180, "Up to 180: Dusky Leather Leggings\nor Guardian Pants" }, + { 195, "Up to 195: Barbaric Shoulders" }, + { 205, "Up to 205: Dusky Bracers" }, + { 220, "Up to 220: Thick Armor Kit" }, + { 225, "Up to 225: Nightscape Headband" }, + { 250, "Up to 250: Depends on your specialization\nNightscape Headband/Tunic/Pants (Elemental)\nTough Scorpid Breastplate/Gloves (Dragonscale)\nTurtle Scale set (Tribal)" }, + { 260, "Up to 260: Nightscape Boots" }, + { 270, "Up to 270: Wicked Leather Gauntlets" }, + { 285, "Up to 285: Wicked Leather Bracers" }, + { 300, "Up to 300: Wicked Leather Headband" }, + { 310, "Up to 310: Knothide Leather" }, + { 320, "Up to 320: Wild Draenish Gloves" }, + { 325, "Up to 325: Thick Draenic Boots" }, + { 335, "Up to 335: Heavy Knothide Leather\n|cFFFFD700Don't sell them, you'll need them later" }, + { 340, "Up to 340: Thick Draenic Vest" }, + { 350, "Up to 350: Felscale Breastplate" }, + { 375, "Up to 375: Borean Armor Kit" }, + { 385, "Up to 385: Arctic Boots" }, + { 395, "Up to 395: Arctic Belt" }, + { 400, "Up to 400: Arctic Wristguards" }, + { 405, "Up to 405: Nerubian Leg Armor" }, + { 410, "Up to 410: Any Dark Chestpiece or Leggings" }, + { 425, "Up to 425: Any Fur Lining\nTradeskill bags" }, + { 450, "Up to 450: Whatever makes you earn a point,\ndepending on your needs" } + }, + [BI["Engineering"]] = { + { 40, "Up to 40: Rough Blasting Powder" }, + { 50, "Up to 50: Handful of Copper Bolt" }, + { 51, "Craft one Arclight Spanner" }, + { 65, "Up to 65: Copper Tubes" }, + { 75, "Up to 75: Rough Boom Sticks" }, + { 95, "Up to 95: Coarse Blasting Powder" }, + { 105, "Up to 105: Silver Contacts" }, + { 120, "Up to 120: Bronze Tubes" }, + { 125, "Up to 125: Small Bronze Bombs" }, + { 145, "Up to 145: Heavy Blasting Powder" }, + { 150, "Up to 150: Big Bronze Bombs" }, + { 175, "Up to 175: Blue, Green or Red Fireworks" }, + { 176, "Craft one Gyromatic Micro-Adjustor" }, + { 190, "Up to 190: Solid Blasting Powder" }, + { 195, "Up to 195: Big Iron Bomb" }, + { 205, "Up to 205: Mithril Tubes" }, + { 210, "Up to 210: Unstable Triggers" }, + { 225, "Up to 225: Hi-Impact Mithril Slugs" }, + { 235, "Up to 235: Mithril Casings" }, + { 245, "Up to 245: Hi-Explosive Bomb" }, + { 250, "Up to 250: Mithril Gyro-Shot" }, + { 260, "Up to 260: Dense Blasting Powder" }, + { 290, "Up to 290: Thorium Widget" }, + { 300, "Up to 300: Thorium Tubes\nor Thorium Shells (cheaper)" }, + { 310, "Up to 310: Fel Iron Casing,\nHandful of Fel Iron Bolts,\n and Elemental Blasting Powder\nKeep them all for future crafts" }, + { 320, "Up to 320: Fel Iron Bomb" }, + { 335, "Up to 335: Fel Iron Musket" }, + { 350, "Up to 350: White Smoke Flare" }, + { 375, "Up to 375: Cobalt Frag Bomb" }, + { 430, "Up to 430: Mana & Healing Injector Kit\nYou'll need them on the long run" }, + { 435, "Up to 435: Mana Injector Kit" }, + { 450, "Up to 450: Whatever makes you earn a point,\ndepending on your needs" } + }, + [BI["Jewelcrafting"]] = { + { 20, "Up to 20: Delicate Copper Wire" }, + { 30, "Up to 30: Rough Stone Statue" }, + { 50, "Up to 50: Tigerseye Band" }, + { 75, "Up to 75: Bronze Setting" }, + { 80, "Up to 80: Solid Bronze Ring" }, + { 90, "Up to 90: Elegant Silver Ring" }, + { 110, "Up to 110: Ring of Silver Might" }, + { 120, "Up to 120: Heavy Stone Statue" }, + { 150, "Up to 150: Pendant of the Agate Shield\nor Golden Dragon Ring" }, + { 180, "Up to 180: Mithril Filigree" }, + { 200, "Up to 200: Engraved Truesilver Ring" }, + { 210, "Up to 210: Citrine Ring of Rapid Healing" }, + { 225, "Up to 225: Aquamarine Signet" }, + { 250, "Up to 250: Thorium Setting" }, + { 255, "Up to 255: Red Ring of Destruction" }, + { 265, "Up to 265: Truesilver Healing Ring" }, + { 275, "Up to 275: Simple Opal Ring" }, + { 285, "Up to 285: Sapphire Signet" }, + { 290, "Up to 290: Diamond Focus Ring" }, + { 300, "Up to 300: Emerald Lion Ring" }, + { 310, "Up to 310: Any green quality gem" }, + { 315, "Up to 315: Fel Iron Blood Ring\nor any green quality gem" }, + { 320, "Up to 320: Any green quality gem" }, + { 325, "Up to 325: Azure Moonstone Ring" }, + { 335, "Up to 335: Mercurial Adamantite (required later)\nor any green quality gem" }, + { 350, "Up to 350: Heavy Adamantite Ring" }, + { 355, "Up to 355: Any blue quality gem" }, + { 360, "Up to 360: World drop recipes like:\nLiving Ruby Pendant\nor Thick Felsteel Necklace" }, + { 365, "Up to 365: Ring of Arcane Shielding\nThe Sha'tar - Honored" }, + { 375, "Up to 375: Transmute diamonds\nWorld drops (blue quality)\nRevered with Sha'tar, Honor Hold, Thrallmar" }, + { 400, "Up to 400: Any green quality gem" }, + { 420, "Up to 420: Shadowmight ring" }, + }, + [BI["Enchanting"]] = { + { 2, "Up to 2: Runed Copper Rod" }, + { 75, "Up to 75: Enchant Bracer - Minor Health" }, + { 85, "Up to 85: Enchant Bracer - Minor Deflection" }, + { 100, "Up to 100: Enchant Bracer - Minor Stamina" }, + { 101, "Craft one Runed Silver Rod" }, + { 105, "Up to 105: Enchant Bracer - Minor Stamina" }, + { 120, "Up to 120: Greater Magic Wand" }, + { 130, "Up to 130: Enchant Shield - Minor Stamina" }, + { 150, "Up to 150: Enchant Bracer - Lesser Stamina" }, + { 151, "Craft one Runed Golden Rod" }, + { 160, "Up to 160: Enchant Bracer - Lesser Stamina" }, + { 165, "Up to 165: Enchant Shield - Lesser Stamina" }, + { 180, "Up to 180: Enchant Bracer - Spirit" }, + { 200, "Up to 200: Enchant Bracer - Strength" }, + { 201, "Craft one Runed Truesilver Rod" }, + { 205, "Up to 205: Enchant Bracer - Strength" }, + { 225, "Up to 225: Enchant Cloak - Greater Defense" }, + { 235, "Up to 235: Enchant Gloves - Agility" }, + { 245, "Up to 245: Enchant Chest - Superior Health" }, + { 250, "Up to 250: Enchant Bracer - Greater Strength" }, + { 270, "Up to 270: Lesser Mana Oil\nRecipe is sold in Silithus" }, + { 290, "Up to 290: Enchant Shield - Greater Stamina\nor Enchant Boots: Greater Stamina" }, + { 291, "Craft one Runed Arcanite Rod" }, + { 300, "Up to 300: Enchant Cloak - Superior Defense" }, + { 301, "Craft one Runed Fel Iron Rod" }, + { 305, "Up to 305: Enchant Cloak - Superior Defense" }, + { 315, "Up to 315: Enchant Bracers - Assault" }, + { 325, "Up to 325: Enchant Cloak - Major Armor\nor Enchant Gloves - Assault" }, + { 335, "Up to 335: Enchant Chest - Major Spirit" }, + { 340, "Up to 340: Enchant Shield - Major Stamina" }, + { 345, "Up to 345: Superior Wizard Oil\nDo this up to 350 if you have the mats" }, + { 350, "Up to 350: Enchant Gloves - Major Strength" }, + { 351, "Craft one Runed Adamantite Rod" }, + { 360, "Up to 360: Enchant Gloves - Major Strength" }, + { 370, "Up to 370: Enchant Gloves - Spell Strike\nRequires Revered with Cenarion Expedition" }, + { 375, "Up to 375: Enchant Ring - Healing Power\nRequires Revered with The Sha'tar" }, + { 376, "Craft one Runed Eternium Rod" }, + { 380, "Up to 380: Enchant Chest - Super Stats" }, + { 390, "Up to 390: Enchant Weapon - Greater Potency" }, + }, + [BI["Blacksmithing"]] = { + { 25, "Up to 25: Rough Sharpening Stones" }, + { 45, "Up to 45: Rough Grinding Stones" }, + { 75, "Up to 75: Copper Chain Belt" }, + { 80, "Up to 80: Coarse Grinding Stones" }, + { 100, "Up to 100: Runed Copper Belt" }, + { 105, "Up to 105: Silver Rod" }, + { 125, "Up to 125: Rough Bronze Leggings" }, + { 150, "Up to 150: Heavy Grinding Stone" }, + { 155, "Up to 155: Golden Rod" }, + { 165, "Up to 165: Green Iron Leggings" }, + { 185, "Up to 185: Green Iron Bracers" }, + { 200, "Up to 200: Golden Scale Bracers" }, + { 210, "Up to 210: Solid Grinding Stone" }, + { 215, "Up to 215: Golden Scale Bracers" }, + { 235, "Up to 235: Steel Plate Helm\nor Mithril Scale Bracers (cheaper)\nRecipe in Aerie Peak (A) or Stonard (H)" }, + { 250, "Up to 250: Mithril Coif\nor Mithril Spurs (cheaper)" }, + { 260, "Up to 260: Dense Sharpening Stones" }, + { 270, "Up to 270: Thorium Belt or Bracers (cheaper)\nEarthforged Leggings (Armorsmith)\nLight Earthforged Blade (Swordsmith)\nLight Emberforged Hammer (Hammersmith)\nLight Skyforged Axe (Axesmith)" }, + { 295, "Up to 295: Imperial Plate Bracers" }, + { 300, "Up to 300: Imperial Plate Boots" }, + { 305, "Up to 305: Fel Weightstone" }, + { 320, "Up to 320: Fel Iron Plate Belt" }, + { 325, "Up to 325: Fel Iron Plate Boots" }, + { 330, "Up to 330: Lesser Rune of Warding" }, + { 335, "Up to 335: Fel Iron Breastplate" }, + { 340, "Up to 340: Adamantite Cleaver\nSold in Shattrah, Silvermoon, Exodar" }, + { 345, "Up to 345: Lesser Rune of Shielding\nSold in Wildhammer Stronghold and Thrallmar" }, + { 350, "Up to 350: Adamantite Cleaver" }, + { 360, "Up to 360: Adamantite Weightstone\nRequires Cenarion Expedition - Honored" }, + { 370, "Up to 370: Felsteel Gloves (Auchenai Crypts)\nFlamebane Gloves (Aldor - Honored)\nEnchanted Adamantite Belt (Scryer - Friendly)" }, + { 375, "Up to 375: Felsteel Gloves (Auchenai Crypts)\nFlamebane Breastplate (Aldor - Revered)\nEnchanted Adamantite Belt (Scryer - Friendly)" }, + { 385, "Up to 385: Cobalt Gauntlets" }, + { 393, "Up to 393: Spiked Cobalt Shoulders\nor Chestpiece" }, + { 395, "Up to 395: Spiked Cobalt Gauntlets" }, + { 400, "Up to 400: Spiked Cobalt Belt" }, + { 410, "Up to 410: Spiked Cobalt Bracers" }, + { 415, "Up to 415: Tempered Saronite Shoulders" }, + { 420, "Up to 420: Tempered Saronite Bracers" }, + { 430, "Up to 430: Daunting Handguards" }, + { 445, "Up to 445: Daunting Legplates" }, + { 450, "Up to 450: Any Epic" }, + }, + [BI["Alchemy"]] = { + { 60, "Up to 60: Minor Healing Potion" }, + { 110, "Up to 110: Lesser Healing Potion" }, + { 140, "Up to 140: Healing Potion" }, + { 155, "Up to 155: Lesser Mana Potion" }, + { 185, "Up to 185: Greater Healing Potion" }, + { 210, "Up to 210: Elixir of Agility" }, + { 215, "Up to 215: Elixir of Greater Defense" }, + { 230, "Up to 230: Superior Healing Potion" }, + { 250, "Up to 250: Elixir of Detect Undead" }, + { 265, "Up to 265: Elixir of Greater Agility" }, + { 285, "Up to 285: Superior Mana Potion" }, + { 300, "Up to 300: Major Healing Potion" }, + { 315, "Up to 315: Volatile Healing Potion\nor Major Mana Potion" }, + { 350, "Up to 350: Mad Alchemists's Potion\nTurns yellow at 335, but cheap to make" }, + { 375, "Up to 375: Major Dreamless Sleep Potion\nSold in Allerian Stronghold (A)\nor Thunderlord Stronghold (H)" } + }, + [L["Mining"]] = { + { 65, "Up to 65: Mine Copper\nAvailable in all starting zones" }, + { 125, "Up to 125: Mine Tin, Silver, Incendicite and Lesser Bloodstone\n\nMine Incendicite at Thelgen Rock (Wetlands)\nEasy leveling up to 125" }, + { 175, "Up to 175: Mine Iron and Gold\nDesolace, Ashenvale, Badlands, Arathi Highlands,\nAlterac Mountains, Stranglethorn Vale, Swamp of Sorrows" }, + { 250, "Up to 250: Mine Mithril and Truesilver\nBlasted Lands, Searing Gorge, Badlands, The Hinterlands,\nWestern Plaguelands, Azshara, Winterspring, Felwood, Stonetalon Mountains, Tanaris" }, + { 300, "Up to 300: Mine Thorium \nUn’goro Crater, Azshara, Winterspring, Blasted Lands\nSearing Gorge, Burning Steppes, Eastern Plaguelands, Western Plaguelands" }, + { 330, "Up to 330: Mine Fel Iron\nHellfire Peninsula, Zangarmarsh" }, + { 375, "Up to 375: Mine Fel Iron and Adamantite\nTerrokar Forest, Nagrand\nBasically everywhere in Outland" } + }, + [L["Herbalism"]] = { + { 50, "Up to 50: Collect Silverleaf and Peacebloom\nAvailable in all starting zones" }, + { 70, "Up to 70: Collect Mageroyal and Earthroot\nThe Barrens, Westfall, Silverpine Forest, Loch Modan" }, + { 100, "Up to 100: Collect Briarthorn\nSilverpine Forest, Duskwood, Darkshore,\nLoch Modan, Redridge Mountains" }, + { 115, "Up to 115: Collect Bruiseweed\nAshenvale, Stonetalon Mountains, Southern Barrens\nLoch Modan, Redridge Mountains" }, + { 125, "Up to 125: Collect Wild Steelbloom\nStonetalon Mountains, Arathi Highlands, Stranglethorn Vale\nSouthern Barrens, Thousand Needles" }, + { 160, "Up to 160: Collect Kingsblood\nAshenvale, Stonetalon Mountains, Wetlands,\nHillsbrad Foothills, Swamp of Sorrows" }, + { 185, "Up to 185: Collect Fadeleaf\nSwamp of Sorrows" }, + { 205, "Up to 205: Collect Khadgar's Whisker\nThe Hinterlands, Arathi Highlands, Swamp of Sorrows" }, + { 230, "Up to 230: Collect Firebloom\nSearing Gorge, Blasted Lands, Tanaris" }, + { 250, "Up to 250: Collect Sungrass\nFelwood, Feralas, Azshara\nThe Hinterlands" }, + { 270, "Up to 270: Collect Gromsblood\nFelwood, Blasted Lands,\nMannoroc Coven in Desolace" }, + { 285, "Up to 285: Collect Dreamfoil\nUn'goro Crater, Azshara" }, + { 300, "Up to 300: Collect Plagueblooms\nEastern & Western Plaguelands, Felwood\nor Icecaps in Winterspring" }, + { 330, "Up to 330: Collect Felweed\nHellfire Peninsula, Zangarmarsh" }, + { 375, "Up to 375: Any flower available in Outland\nFocus on Zangarmarsh & Terrokar Forest" } + }, + [L["Skinning"]] = { + { 375, "Up to 375: Divide your current skill level by 5,\nand skin mobs of that level" } + }, + + -- source: http://www.elsprofessions.com/inscription/leveling.html + [L["Inscription"]] = { + { 18, "Up to 18: Ivory Ink" }, + { 35, "Up to 35: Scroll of Intellect, Spirit or Stamina" }, + { 50, "Up to 50: Moonglow Ink\nSave if for Minor Inscription Research" }, + { 75, "Up to 75: Scroll of Recall, Armor Vellum" }, + { 79, "Up to 79: Midnight Ink" }, + { 80, "Up to 80: Minor Inscription Research" }, + { 85, "Up to 85: Glyph of Backstab, Frost Nova\nRejuvenation, ..." }, + { 87, "Up to 87: Hunter's Ink" }, + { 90, "Up to 90: Glyph of Corruption, Flame Shock\nRapid Charge, Wrath" }, + { 100, "Up to 100: Glyph of Ice Armor, Maul\nSerpent Sting" }, + { 104, "Up to 104: Lion's Ink" }, + { 105, "Up to 105: Glyph of Arcane Shot, Arcane Explosion" }, + { 110, "Up to 110: Glyph of Eviscerate, Holy Light, Fade" }, + { 115, "Up to 115: Glyph of Fire Nova Totem\nHealth Funel, Rending" }, + { 120, "Up to 120: Glyph of Arcane Missiles, Healing Touch" }, + { 125, "Up to 125: Glyph of Expose Armor\nFlash Heal, Judgment" }, + { 130, "Up to 130: Dawnstar Ink" }, + { 135, "Up to 135: Glyph of Blink\nImmolation, Moonfire" }, + { 140, "Up to 140: Glyph of Lay on Hands\nGarrote, Inner Fire" }, + { 142, "Up to 142: Glyph of Sunder Armor\nImp, Lightning Bolt" }, + { 150, "Up to 150: Strange Tarot" }, + { 155, "Up to 155: Jadefire Ink" }, + { 160, "Up to 160: Scroll of Stamina III" }, + { 165, "Up to 165: Glyph of Gouge, Renew" }, + { 170, "Up to 170: Glyph of Shadow Bolt\nStrength of Earth Totem" }, + { 175, "Up to 175: Glyph of Overpower" }, + { 177, "Up to 177: Royal Ink" }, + { 183, "Up to 183: Scroll of Agility III" }, + { 185, "Up to 185: Glyph of Cleansing\nShadow Word: Pain" }, + { 190, "Up to 190: Glyph of Insect Swarm\nFrost Shock, Sap" }, + { 192, "Up to 192: Glyph of Revenge\nVoidwalker" }, + { 200, "Up to 200: Arcane Tarot" }, + { 204, "Up to 204: Celestial Ink" }, + { 210, "Up to 210: Armor Vellum II" }, + { 215, "Up to 215: Glyph of Smite, Sinister Strike" }, + { 220, "Up to 220: Glyph of Searing Pain\nHealing Stream Totem" }, + { 225, "Up to 225: Glyph of Starfire\nBarbaric Insults" }, + { 227, "Up to 227: Fiery Ink" }, + { 230, "Up to 230: Scroll of Agility IV" }, + { 235, "Up to 235: Glyph of Dispel Magic" }, + { 250, "Up to 250: Weapon Vellum II" }, + { 255, "Up to 255: Scroll of Stamina V" }, + { 260, "Up to 260: Scroll of Spirit V" }, + { 265, "Up to 265: Glyph of Freezing Trap, Shred" }, + { 270, "Up to 270: Glyph of Exorcism, Bone Shield" }, + { 275, "Up to 275: Glyph of Fear Ward, Frost Strike" }, + { 285, "Up to 285: Ink of the Sky" }, + { 295, "Up to 295: Glyph of Execution\nSprint, Death Grip" }, + { 300, "Up to 300: Scroll of Spirit VI" }, + { 304, "Up to 304: Ethereal Ink" }, + { 305, "Up to 305: Glyph of Plague Strike\nEarthliving Weapon, Flash of Light" }, + { 310, "Up to 310: Glyph of Feint" }, + { 315, "Up to 315: Glyph of Rake, Rune Tap" }, + { 320, "Up to 320: Glyph of Holy Nova, Rapid Fire" }, + { 325, "Up to 325: Glyph of Blood Strike, Sweeping Strikes" }, + { 327, "Up to 327: Darkflame Ink" }, + { 330, "Up to 330: Glyph of Mage Armor, Succubus" }, + { 335, "Up to 335: Glyph of Scourge Strike, Windfury Weapon" }, + { 340, "Up to 340: Glyph of Arcane Power, Seal of Command" }, + { 345, "Up to 345: Glyph of Ambush, Death Strike" }, + { 350, "Up to 350: Glyph of Whirlwind" }, + { 360, "Up to 360: Glyph of Mind Flay, Banish" }, + { 365, "Up to 365: Scroll of Intellect VII" }, + { 370, "Up to 370: Scroll of Strength VII" }, + { 375, "Up to 375: Scroll of Agility VII" }, + { 380, "Up to 380: Glyph of Focus, Strangulate" }, + { 400, "Up to 400: Northrend Inscription Research" }, + + { 450, "Up to 450: Not yet implemented" } + }, + + -- source: http://www.almostgaming.com/wowguides/world-of-warcraft-lockpicking-guide + [L["Lockpicking"]] = { + { 85, "Up to 85: Thieves Training\nAtler Mill, Redridge Moutains (A)\nShip near Ratchet (H)" }, + { 150, "Up to 150: Chest near the boss of the poison quest\nWestfall (A) or The Barrens (H)" }, + { 185, "Up to 185: Murloc camps (Wetlands)" }, + { 225, "Up to 225: Sar'Theris Strand (Desolace)\n" }, + { 250, "Up to 250: Angor Fortress (Badlands)" }, + { 275, "Up to 275: Slag Pit (Searing Gorge)" }, + { 300, "Up to 300: Lost Rigger Cove (Tanaris)\nBay of Storms (Azshara)" }, + { 325, "Up to 325: Feralfen Village (Zangarmarsh)" }, + { 350, "Up to 350: Kil'sorrow Fortress (Nagrand)\nPickpocket the Boulderfists in Nagrand" } + }, + + -- ** Secondary professions ** + [BI["First Aid"]] = { + { 40, "Up to 40: Linen Bandages" }, + { 80, "Up to 80: Heavy Linen Bandages\nBecome Journeyman at 50" }, + { 115, "Up to 115: Wool Bandages" }, + { 150, "Up to 150: Heavy Wool Bandages" }, + { 180, "Up to 180: Silk Bandages" }, + { 210, "Up to 210: Heavy Silk Bandages" }, + { 240, "Up to 240: Mageweave Bandages\nFirst Aid quest at level 35\nTheramore Isle (A) or Hammerfall (H)" }, + { 260, "Up to 260: Heavy Mageweave Bandages" }, + { 290, "Up to 290: Runecloth Bandages" }, + { 330, "Up to 330: Heavy Runecloth Bandages\nBuy Master First Aid book\nTemple of Telhamat (A) or Falcon Watch (H)" }, + { 360, "Up to 360: Netherweave Bandages\nBuy the book in the Temple of Telhamat (A) or in Falcon Watch (H)" }, + { 375, "Up to 375: Heavy Netherweave Bandages\nBuy the book in the Temple of Telhamat (A) or in Falcon Watch (H)" } + }, + [BI["Cooking"]] = { + { 40, "Up to 40: Spice Bread" }, + { 85, "Up to 85: Smoked Bear Meat, Crab Cake" }, + { 100, "Up to 100: Cooked Crab Claw (A)\nDig Rat Stew (H)" }, + { 125, "Up to 125: Dig Rat Stew (H)\nSeasoned Wolf Kabob (A)" }, + { 175, "Up to 175: Curiously Tasty Omelet (A)\nHot Lion Chops (H)" }, + { 200, "Up to 200: Roast Raptor" }, + { 225, "Up to 225: Spider Sausage\n\n|cFFFFFFFFCooking quest:\n|cFFFFD70012 Giant Eggs,\n10 Zesty Clam Meat,\n20 Alterac Swiss " }, + { 275, "Up to 275: Monster Omelet\nor Tender Wolf Steaks" }, + { 285, "Up to 285: Runn Tum Tuber Surprise\nDire Maul (Pusillin)" }, + { 300, "Up to 300: Smoked Desert Dumplings\nQuest in Silithus" }, + { 325, "Up to 325: Ravager Dogs, Buzzard Bites" }, + { 350, "Up to 350: Roasted Clefthoof\nWarp Burger, Talbuk Steak" }, + { 375, "Up to 375: Crunchy Serpent\nMok'nathal Treats" } + }, + -- source: http://www.wowguideonline.com/fishing.html + [BI["Fishing"]] = { + { 50, "Up to 50: Any starting zone" }, + { 75, "Up to 75:\nThe Canals in Stormwind\nThe Pond in Orgrimmar" }, + { 150, "Up to 150: Hillsbrad Foothills' river" }, + { 225, "Up to 225: Expert Fishing book sold in Booty Bay\nFish in Desolace or Arathi Highlands" }, + { 250, "Up to 250: Hinterlands, Tanaris\n\n|cFFFFFFFFFishing quest in Dustwallow Marsh\n|cFFFFD700Savage Coast Blue Sailfin (Stranglethorn Vale)\nFeralas Ahi (Verdantis River, Feralas)\nSer'theris Striker (Northern Sartheris Strand, Desolace)\nMisty Reed Mahi Mahi (Swamp of Sorrows coastline)" }, + { 260, "Up to 260: Felwood" }, + { 300, "Up to 300: Azshara" }, + { 330, "Up to 330: Fish in Eastern Zangarmarsh\nArtisan Fishing Book at the Cenarion Expedition" }, + { 345, "Up to 345: Western Zangarmarsh" }, + { 360, "Up to 360: Terrokar Forest" }, + { 375, "Up to 375: Terrokar Forest, in altitude\nFlying mount required" } + }, + + -- suggested leveling zones, compiled by Thaoky, based on too many sources to list + my own leveling experience on Alliance side + ["Leveling"] = { + { 10, "Up to 10: Any starting zone" }, + { 20, "Up to 20: " .. BZ["Loch Modan"] .. "\n" .. BZ["Westfall"] .. "\n" .. BZ["Darkshore"] .. "\n" .. BZ["Bloodmyst Isle"] + .. "\n" .. BZ["Silverpine Forest"] .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Ghostlands"]}, + { 25, "Up to 25: " .. BZ["Wetlands"] .. "\n" .. BZ["Redridge Mountains"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Hillsbrad Foothills"] }, + { 28, "Up to 28: " .. BZ["Duskwood"] .. "\n" .. BZ["Wetlands"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Thousand Needles"] }, + { 31, "Up to 31: " .. BZ["Duskwood"] .. "\n" .. BZ["Thousand Needles"] .. "\n" .. BZ["Ashenvale"] }, + { 35, "Up to 35: " .. BZ["Thousand Needles"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Alterac Mountains"] + .. "\n" .. BZ["Arathi Highlands"] .. "\n" .. BZ["Desolace"] }, + { 40, "Up to 40: " .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Desolace"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 43, "Up to 43: " .. BZ["Tanaris"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 45, "Up to 45: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] }, + { 48, "Up to 48: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] .. "\n" .. BZ["Searing Gorge"] }, + { 51, "Up to 51: " .. BZ["Tanaris"] .. "\n" .. BZ["Azshara"] .. "\n" .. BZ["Blasted Lands"] + .. "\n" .. BZ["Searing Gorge"] .. "\n" .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] }, + { 55, "Up to 55: " .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] .. "\n" .. BZ["Burning Steppes"] + .. "\n" .. BZ["Blasted Lands"] .. "\n" .. BZ["Western Plaguelands"] }, + { 58, "Up to 58: " .. BZ["Winterspring"] .. "\n" .. BZ["Burning Steppes"] .. "\n" .. BZ["Western Plaguelands"] + .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 60, "Up to 60: " .. BZ["Winterspring"] .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 62, "Up to 62: " .. BZ["Hellfire Peninsula"] }, + { 64, "Up to 64: " .. BZ["Zangarmarsh"] .. "\n" .. BZ["Terokkar Forest"]}, + { 65, "Up to 65: " .. BZ["Terokkar Forest"] }, + { 66, "Up to 66: " .. BZ["Terokkar Forest"] .. "\n" .. BZ["Nagrand"]}, + { 67, "Up to 67: " .. BZ["Nagrand"]}, + { 68, "Up to 68: " .. BZ["Blade's Edge Mountains"]}, + { 70, "Up to 70: " .. BZ["Blade's Edge Mountains"] .. "\n" .. BZ["Netherstorm"] .. "\n" .. BZ["Shadowmoon Valley"]}, + { 72, "Up to 72: " .. BZ["Howling Fjord"] .. "\n" .. BZ["Borean Tundra"]}, + { 74, "Up to 74: " .. BZ["Grizzly Hills"] .. "\n" .. BZ["Dragonblight"]}, + { 76, "Up to 76: " .. BZ["Dragonblight"] .. "\n" .. BZ["Zul'Drak"]}, + { 78, "Up to 78: " .. BZ["Zul'Drak"] .. "\n" .. BZ["Sholazar Basin"]}, + { 80, "Up to 80: " .. BZ["The Storm Peaks"] .. "\n" .. BZ["Icecrown"]}, + }, + + -- Reputation levels + -- -42000 = "Hated" + -- -6000 = "Hostile" + -- -3000 = "Unfriendly" + -- 0 = "Neutral" + -- 3000 = "Friendly" + -- 9000 = "Honored" + -- 21000 = "Revered" + -- 42000 = "Exalted" + + -- Outland factions: source: http://www.mmo-champion.com/ + [BF["The Aldor"]] = { + { 0, "Up to Neutral:\n" .. WHITE .. "[Dreadfang Venom Sac]|r +250 rep\n\n" + .. YELLOW .. "Dreadfang Lurker,\nDreadfang Widow\n" + .. WHITE .. "(Terrokar Forest)" }, + { 9000, "Up to Honored:\n" .. WHITE .. "[Mark of Kil'jaeden]|r\n+25 rep" }, + { 42000, "Up to Exalted:\n" .. WHITE .. "[Mark of Sargeras]|r +25 rep per mark\n" + .. GREEN .. "[Fel Armament]|r +350 rep (+1 Holy Dust)" } + }, + [BF["The Scryers"]] = { + { 0, "Up to Neutral:\n" .. WHITE .. "[Dampscale Basilisk Eye]|r +250 rep\n\n" + .. YELLOW .. "Ironspine Petrifier,\nDampscale Devourer,\nDampscale Basilisk\n" + .. WHITE .. "(Terrokar Forest)" }, + { 9000, "Up to Honored:\n" .. WHITE .. "[Firewing Signet]|r\n+25 rep" }, + { 42000, "Up to Exalted:\n" .. WHITE .. "[Sunfury Signet]|r +25 rep per mark\n" + .. GREEN .. "[Arcane Tome]|r +350 rep (+1 Arcane Rune)" } + }, + [BF["Netherwing"]] = { + { 3000, "Up to Friendly, repeat these quests:\n\n" + .. YELLOW .. "A Slow Death (Daily)|r 250 rep\n" + .. YELLOW.. "Netherdust Pollen (Daily)|r 250 rep\n" + .. YELLOW.. "Netherwing crystal (Daily)|r 250 rep\n" + .. YELLOW.. "Not so friendly skies (Daily)\n" + .. YELLOW.. "Great Netherwing egg hunt (Repeatable)|r 250 rep" }, + { 9000, "Up to Honored, repeat these quests:\n\n" + .. YELLOW .. "Overseeing and you: making the right choices|r 350 rep\n" + .. YELLOW .. "The Booterang: A Cure ... (Daily)|r 350 rep\n" + .. YELLOW .. "Picking up the pieces (Daily)|r 350 rep\n" + .. YELLOW .. "Dragons are the least of our problems (Daily)|r 350 rep\n" + .. YELLOW .. "Crazed & confused|r 350 rep\n" }, + { 21000, "Up to Revered, repeat these quests:\n\n" + .. YELLOW .. "Subduing the Subduer|r 500 rep\n" + .. YELLOW .. "Disrupting the Twiligth Generator (Daily)|r 500 rep\n" + .. YELLOW .. "Race quests 500 each for first 5, 1000 for 6th\n" }, + { 42000, "Up to Exalted, repeat this quest:\n\n" + .. YELLOW .. "The greatest trap ever (Daily) (3 man group)|r 500 rep" } + }, + [BF["Honor Hold"]] = { + { 9000, "Up to Honored:\n\n" + .. YELLOW .. "Quest in Hellfire Peninsula\n" + .. GREEN .. "Hellfire Remparts |r(Normal)\n" + .. GREEN .. "Blood Furnace |r(Normal)" }, + { 42000, "Up to Exalted:\n\n" + .. GREEN .. "Shattered Halls |r(Normal & Heroic)\n" + .. GREEN .. "Hellfire Remparts |r(Heroic)\n" + .. GREEN .. "Blood Furnace |r(Heroic)" } + }, + [BF["Thrallmar"]] = { + { 9000, "Up to Honored:\n\n" + .. YELLOW .. "Quest in Hellfire Peninsula\n" + .. GREEN .. "Hellfire Remparts |r(Normal)\n" + .. GREEN .. "Blood Furnace |r(Normal)" }, + { 42000, "Up to Exalted:\n\n" + .. GREEN .. "Shattered Halls |r(Normal & Heroic)\n" + .. GREEN .. "Hellfire Remparts |r(Heroic)\n" + .. GREEN .. "Blood Furnace |r(Heroic)" } + }, + [BF["Cenarion Expedition"]] = { + { 3000, "Up to Friendly:\n\n" + .. WHITE .. "Darkcrest & Bloodscale Nagas (+5 rep)\n" + .. YELLOW .. "Quest in Zangarmarsh\n" + .. "|rRun any " .. GREEN .. "Coilfang|r instance\n\n" + .. WHITE .. "Keep [Unidentified Plant Parts] for later" }, + { 9000, "Up to Honored:\n\n" + .. WHITE .. "Turn in [Unidentified Plant Parts] x240\n" + .. YELLOW .. "Quest in Zangarmarsh\n" + .. "|rRun any " .. GREEN .. "Coilfang|r instance" }, + { 42000, "Up to Exalted:\n\n" + .. WHITE .. "Turn in [Coilfang Armaments] +75 rep\n\n" + .. GREEN .. "Steamvault |r(Normal)\n" + .. GREEN .. "Any Coilfang instance |r(Heroic)" } + }, + [BF["Keepers of Time"]] = { + { 42000, "Up to Exalted:\n\n" + .. "|rRun the " .. GREEN .. "Old Hillsbrad Foothills|r & " .. GREEN .. "The Black Morass\n\n" + .. YELLOW .. "Keep quests for later:\nOld Hillsbrad quesline = 5000 rep\nBlack Morass questline = 8000 rep" } + }, + [BF["The Sha'tar"]] = { + { 42000, "Up to Exalted:\n\n" + .. GREEN .. "The Botanica |r(Normal & Heroic)\n" + .. GREEN .. "The Mechanar |r(Normal & Heroic)\n" + .. GREEN .. "The Arcatraz |r(Normal & Heroic)\n" } + }, + [BF["Lower City"]] = { + { 9000, "Up to Honored:\n\n" + .. WHITE .. "Turn in [Arrakoa Feather] x30 (+250 rep)\n" + .. GREEN .. "Shadow Labyrinth |r(Normal)\n" + .. GREEN .. "Auchenai Crypts |r(Normal)\n" + .. GREEN .. "Sethekk Halls |r(Normal)" }, + { 42000, "Up to Exalted:\n\n" + .. GREEN .. "Shadow Labyrinth |r(Normal & Heroic)\n" + .. GREEN .. "Auchenai Crypts |r(Heroic)\n" + .. GREEN .. "Sethekk Halls |r(Heroic)" } + }, + [BF["The Consortium"]] = { + { 3000, "Up to Friendly:\n\n" + .. "|rTurn in [Oshu'gun Crystal Fragment] +250 rep\n" + .. "Turn in [Pair of Ivory Tusks] +250 rep\n\n" + .. GREEN .. "Mana-Tombs |r(Normal)" }, + { 9000, "Up to Honored:\n\n" + .. "|rTurn in [Obsidian Warbeads] +250 rep\n\n" + .. GREEN .. "Mana-Tombs |r(Normal)" }, + { 42000, "Up to Exalted:\n\n" + .. "|rTurn in [Zaxxis Insignia] +250 rep\n" + .. "|rTurn in [Obsidian Warbeads] +250 rep\n\n" + .. GREEN .. "Mana-Tombs |r(Heroic)" } + } + + -- Northrend factions +} diff --git a/Altoholic-Addon/Altoholic/Suggestions_deDE.lua b/Altoholic-Addon/Altoholic/Suggestions_deDE.lua new file mode 100644 index 0000000..7dff9e3 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Suggestions_deDE.lua @@ -0,0 +1,479 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() +local BF = LibStub("LibBabble-Faction-3.0"):GetLookupTable() + +if GetLocale() ~= "deDE" then return end + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +-- This table contains a list of suggestions to get to the next level of reputation, craft or skill +addon.Suggestions = { + [L["Riding"]] = { + { 75, "Unerfahrener Reiter (Lv 20): |cFFFFFFFF4g\n|cFFFFD700Standard mount in der Nähe einer Hauptstadt: |cFFFFFFFF1g" }, + { 150, "Geübter Reiter (Lv 40): |cFFFFFFFF50g\n|cFFFFD700Epic mount in der Nähe einer Hauptstadt: |cFFFFFFFF10g" }, + { 225, "Erfahrener Reiter (Lv 60): |cFFFFFFFF600g\n|cFFFFD700Flugmount im Schattenmondtal: |cFFFFFFFF50g" }, + { 300, "Gekonnter Reiter (Lv 70): |cFFFFFFFF5000g\n|cFFFFD700Epic Flugmount im Schattenmondtal: |cFFFFFFFF200g" } + }, + + -- source : http://forums.worldofwarcraft.com/thread.html?topicId=102789457&sid=1 + -- ** Primary professions ** + [BI["Tailoring"]] = { + { 50, "bis zu 50: Leinenstoffballen" }, + { 70, "bis zu 70: Leinentasche" }, + { 75, "bis zu 75: Verstärktes Leinencape" }, + { 105, "bis zu 105: Wollstoffballen" }, + { 110, "bis zu 110: Graues Wollhemd"}, + { 125, "bis zu 125: Doppeltgenähte Wollschultern" }, + { 145, "bis zu 145: Seidenstoffballen" }, + { 160, "bis zu 160: Azurblaue Seidenkapuze" }, + { 170, "bis zu 170: Seidenes Stirnband" }, + { 175, "bis zu 175: Formelles weißes Hemd" }, + { 185, "bis zu 185: Magiestoffballen" }, + { 205, "bis zu 205: Purpurrote Seidenweste" }, + { 215, "bis zu 215: Purpurrote Seidenpantalons" }, + { 220, "bis zu 220: Schwarze Magiestoffgamaschen\noder Schwarze Magiestoffweste" }, + { 230, "bis zu 230: Schwarze Magiestoffhandschuhe" }, + { 250, "bis zu 250: Schwarzes Magiestoffstirnband\noder Schwarze Magiestoffschultern" }, + { 260, "bis zu 260: Runenstoffballen" }, + { 275, "bis zu 275: Runenstoffgürtel" }, + { 280, "bis zu 280: Runenstofftasche" }, + { 300, "bis zu 300: Runenstoffhandschuhe" }, + { 325, "bis zu 325: Netherstoffballen\n|cFFFFD700Nicht verkaufen! Du brauchst sie später noch!" }, + { 340, "bis zu 340: Magieerfüllter Netherstoffballen\n|cFFFFD700Nicht verkaufen! Du brauchst sie später noch!" }, + { 350, "bis zu 350: Netherstoffstiefel\n|cFFFFD700Entzaubern um Arkanen Staub zu bekommen" }, + { 360, "bis zu 360: Netherstofftunika\n|cFFFFD700Entzaubern um Arkanen Staub zu bekommen" }, + { 375, "bis zu 375: Magieerfüllte Netherstofftunika\nStelle das Set her, auf das du dich spezialisiert hast" } + }, + [BI["Leatherworking"]] = { + { 35, "bis zu 35: Leichtes Rüstungsset" }, + { 55, "bis zu 55: Geschmeidiger leichter Balg" }, + { 85, "bis zu 85: Geprägte Lederhandschuhe" }, + { 100, "bis zu 100: Feiner Ledergürtel" }, + { 120, "bis zu 120: Geschmeidiger mittlerer Balg" }, + { 125, "bis zu 125: Feiner Ledergürtel" }, + { 150, "bis zu 150: Dunkler Ledergürtel" }, + { 160, "bis zu 160: Geschmeidiger schwerer Balg" }, + { 170, "bis zu 170: Schweres Rüstungsset" }, + { 180, "bis zu 180: Schwärzliche Ledergamaschen\noder Wächterhose" }, + { 195, "bis zu 195: Barbarische Schultern" }, + { 205, "bis zu 205: Schwärzliche Armschienen" }, + { 220, "bis zu 220: Dickes Rüstungsset" }, + { 225, "bis zu 225: Stirnband des Nachtschleichers" }, + { 250, "bis zu 250: Kommt auf deine Spezialisierung an\nStirnband des Nachtschleichers/Tunika des Nachtschleichers/Hose des Nachtschleichers (Elementar)\nFeste Skorpidbrustplatte/Feste Skorpidhandschuhe (Drachenleder)\nSchildkrötenschuppenset (Stammesleder)" }, + { 260, "bis zu 260: Stiefel des Nachtschleichers" }, + { 270, "bis zu 270: Tückische Lederstulpen" }, + { 285, "bis zu 285: Tückische Lederarmschienen" }, + { 300, "bis zu 300: Tückisches Lederstirnband" }, + { 310, "bis zu 310: Knotenhautleder" }, + { 320, "bis zu 320: Wilde draenische Handschuhe" }, + { 325, "bis zu 325: Dicke draenische Stiefel" }, + { 335, "bis zu 335: Schweres Knotenhautleder\n|cFFFFD700Nicht verkaufen! Du brauchst es später noch!" }, + { 340, "bis zu 340: Dicke draenische Weste" }, + { 355, "bis zu 355: Teufelsschuppenbrustplatte" }, + { 365, "bis zu 365: Schwere Grollhufstiefel\n|cFFFFD700Farme Grollhufleder in Nagrand" }, + { 375, "bis zu 375: Trommeln der Schlacht\n|cFFFFD700Benötigt Die Sha'tar - Wohlwollend" } + }, + [BI["Engineering"]] = { + { 40, "bis zu 40: Raues Sprengpulver" }, + { 50, "bis zu 50: Eine Hand voll Kupferbolzen" }, + { 51, "Stelle einen Bogenlichtschraubenschlüssel her" }, + { 65, "bis zu 65: Kupferrohr" }, + { 75, "bis zu 75: Raues Schießeisen" }, + { 95, "bis zu 95: Grobes Sprengpulver" }, + { 105, "bis zu 105: Silberkontakt" }, + { 120, "bis zu 120: Bronzeröhre" }, + { 125, "bis zu 125: Kleine Bronzebombe" }, + { 145, "bis zu 145: Schweres Sprengpulver" }, + { 150, "bis zu 150: Große Bronzebombe" }, + { 175, "bis zu 175: Blaue, grüne oder rote Feuerwerksrakete" }, + { 176, "Stelle einen Gyromatischer Mikroregler her" }, + { 190, "bis zu 190: Robustes Sprengpulver" }, + { 195, "bis zu 195: Große Eisenbombe" }, + { 205, "bis zu 205: Mithrilrohr" }, + { 210, "bis zu 210: Instabiler Auslöser" }, + { 225, "bis zu 225: Stark einschlagende Mithrilpatronen" }, + { 235, "bis zu 235: Mithrilgehäuse" }, + { 245, "bis zu 245: Hochexplosive Bombe" }, + { 250, "bis zu 250: Gyromithrilgeschoss" }, + { 260, "bis zu 260: Dichtes Sprengpulver" }, + { 290, "bis zu 290: Thoriumapparat" }, + { 300, "bis zu 300: Thoriumröhre\noder Thoriumpatronen (günstiger)" }, + { 310, "bis zu 310: Teufelseisengehäuse,\nEine Hand voll Teufelseisenbolzen,\n und Elementarsprengpulver\nWird später noch benötigt" }, + { 320, "bis zu 320: Teufelseisenbombe" }, + { 335, "bis zu 335: Teufelseisenmuskete" }, + { 350, "bis zu 350: Weißes Rauchsignal" }, + { 360, "bis zu 360: Khoriumkraftkern\nUm 375 zu erreichen brauchst du 20 Stück davon" }, + { 375, "bis zu 375: Feldreparaturbot 110G" } + }, + [BI["Jewelcrafting"]] = { + { 20, "bis zu 20: Feiner Kupferdraht" }, + { 30, "bis zu 30: Raue Steinstatue" }, + { 50, "bis zu 50: Tigeraugenband" }, + { 75, "bis zu 75: Bronzefassung" }, + { 80, "bis zu 80: Robuster Bronzering" }, + { 90, "bis zu 90: Eleganter Silberring" }, + { 110, "bis zu 110: Ring der Silbermacht" }, + { 120, "bis zu 120: Schwere Steinstatue" }, + { 150, "bis zu 150: Anhänger des Achatschilds\noder Goldener Drachenring" }, + { 180, "bis zu 180: Filigranarbeit aus Mithril" }, + { 200, "bis zu 200: Gravierter Echtsilberring" }, + { 210, "bis zu 210: Citrinring der rapiden Heilung" }, + { 225, "bis zu 225: Aquamarinsiegel" }, + { 250, "bis zu 250: Thoriumfassung" }, + { 255, "bis zu 255: Roter Ring der Zerstörung" }, + { 265, "bis zu 265: Echtsilberring der Heilung" }, + { 275, "bis zu 275: Einfacher Opalring" }, + { 285, "bis zu 285: Saphirsiegel" }, + { 290, "bis zu 290: Diamantener Fokusring" }, + { 300, "bis zu 300: Smaragdring des Löwen" }, + { 310, "bis zu 310: Seltene (grüne) Gems" }, + { 315, "bis zu 315: Teufelseisenblutring\noder Seltene (grüne) Gems" }, + { 320, "bis zu 320: Seltene (grüne) Gems" }, + { 325, "bis zu 325: Azurmondsteinring" }, + { 335, "bis zu 335: Quecksilberadamantit (später benötigt)\noder Seltene (grüne) Gems" }, + { 350, "bis zu 350: Schwerer Adamantitring" }, + { 355, "bis zu 355: Rare (blaue) Gems" }, + { 360, "bis zu 360: World drop Rezepte wie z.B.:\nLebendiger Rubinanhänger\noder Dicke Teufelsstahlhalskette" }, + { 365, "bis zu 365: Ring des Arkanschutzes\nBenötigt Die Sha'tar - Wohlwollend" }, + { 375, "bis zu 375: Wandeln Sie Diamanten um\nWorld drops (blau)\nRespektvoll: Die Sha'tar, Ehrenfeste, Thrallmar" } + }, + [BI["Enchanting"]] = { + { 2, "bis zu 2: Runenverzierte Kupferrute" }, + { 75, "bis zu 75: Armschiene - Schwache Gesundheit" }, + { 85, "bis zu 85: Armschiene - Schwache Abwehr" }, + { 100, "bis zu 100: Armschiene - Schwache Ausdauer" }, + { 101, "Stelle eine Runenverzierte Silberrute her" }, + { 105, "bis zu 105: Armschiene - Schwache Ausdauer" }, + { 120, "bis zu 120: Großer Magiezauberstab" }, + { 130, "bis zu 130: Schild - Schwache Ausdauer" }, + { 150, "bis zu 150: Armschiene - Geringe Ausdauer" }, + { 151, "Stelle eine Runenverzierte Goldrute her" }, + { 160, "bis zu 160: Armschiene - Geringe Ausdauer" }, + { 165, "bis zu 165: Schild - Geringe Ausdauer" }, + { 180, "bis zu 180: Armschiene - Geringe Willenskraft" }, + { 200, "bis zu 200: Armschiene - Geringe Stärke" }, + { 201, "Stelle eine Runenverzierte Echtsilberrute her" }, + { 205, "bis zu 205: Armschiene - Geringe Stärke" }, + { 225, "bis zu 225: Umhang - Große Verteidigung" }, + { 235, "bis zu 235: Handschuhe - Beweglichkeit" }, + { 245, "bis zu 245: Brust - Überragende Gesundheit" }, + { 250, "bis zu 250: Armschiene - Große Stärke" }, + { 270, "bis zu 270: Geringes Manaöl\nRezept wird verkauft in Silithus" }, + { 290, "bis zu 290: Schild - Große Ausdauer\noder Stiefel - Große Ausdauer" }, + { 291, "Stelle eine Runenverzierte Arkanitrute her" }, + { 300, "bis zu 300: Umhang - Überragende Verteidigung" }, + { 301, "Stelle eine Runenverzierte Teufelseisenrute her" }, + { 305, "bis zu 305: Umhang - Überragende Verteidigung" }, + { 315, "bis zu 315: Armschiene - Sturmangriff" }, + { 325, "bis zu 325: Umhang - Erhebliche Rüstung\noder Handschuhe - Sturmangriff" }, + { 335, "bis zu 335: Brust - Erhebliche Willenskraft" }, + { 340, "bis zu 340: Schild - Erhebliche Ausdauer" }, + { 345, "bis zu 345: Überragendes Zauberöl\nBis 350 herstellen wenn die Mats vorhanden sind" }, + { 350, "bis zu 350: Handschuhe - Erhebliche Stärke" }, + { 351, "Stelle eine Runenverzierte Adamantitrute her" }, + { 360, "bis zu 360: Handschuhe - Erhebliche Stärke" }, + { 370, "bis zu 370: Handschuhe - Zauberschlag\nBenötigt Respektvoll bei Expedition des Cenarius" }, + { 375, "bis zu 375: Ring - Heilkraft\nBenötigt Respektvoll bei Die Sha'tar" } + }, + [BI["Blacksmithing"]] = { + { 25, "bis zu 25: Rauer Wetzstein" }, + { 45, "bis zu 45: Rauer Schleifstein" }, + { 75, "bis zu 75: Kupferner Kettengürtel" }, + { 80, "bis zu 80: Grober Schleifstein" }, + { 100, "bis zu 100: Runenverzierter Kupfergürtel" }, + { 105, "bis zu 105: Silberrute" }, + { 125, "bis zu 125: Raue bronzene Gamaschen" }, + { 150, "bis zu 150: Schwerer Schleifstein" }, + { 155, "bis zu 155: Goldrute" }, + { 165, "bis zu 165: Grüne Eisengamaschen" }, + { 185, "bis zu 185: Grüne Eisenarmschienen" }, + { 200, "bis zu 200: Goldene Schuppenarmschienen" }, + { 210, "bis zu 210: Robuster Schleifstein" }, + { 215, "bis zu 215: Goldene Schuppenarmschienen" }, + { 235, "bis zu 235: Stahlplattenhelm\noder Mithrilschuppenarmschienen (günstiger)\nRezept zu kaufen in Der Nistgipfel (A) oder Steinard (H)" }, + { 250, "bis zu 250: Mithrilhelmkappe\noder Mithrilsporen (günstiger)" }, + { 260, "bis zu 260: Verdichteter Wetzstein" }, + { 270, "bis zu 270: Thoriumgürtel oder Thoriumarmschienen (günstiger)\nErdgeschmiedete Gamaschen (Rüstungsschmied)\nLeichte erdgeschmiedete Klinge (Schwertschmiedemeister)\nLeichter glutgeschmiedeter Hammer (Hammerschmiedemeister)\nLeichte himmelsgeschmiedete Axt (Axtschmiedemeister)" }, + { 295, "bis zu 295: Imperiale Plattenarmschienen" }, + { 300, "bis zu 300: Imperiale Plattenstiefel" }, + { 305, "bis zu 305: Teufelsgewichtsstein" }, + { 320, "bis zu 320: Teufelseisenplattengürtel" }, + { 325, "bis zu 325: Teufelseisenplattenstiefel" }, + { 330, "bis zu 330: Geringe Rune des Schutzes" }, + { 335, "bis zu 335: Teufelseisenbrustplatte" }, + { 340, "bis zu 340: Adamantitbeil\nZu kaufen in Shattrah, Silbermond, Exodar" }, + { 345, "bis zu 345: Geringer Zauberschutz der Abschirmung\nZu kaufen im Schattenmondtal und Thrallmar" }, + { 350, "bis zu 350: Adamantitbeil" }, + { 360, "bis zu 360: Adamantitgewichtsstein\nBenötigt Expedition des Cenarius - Wohlwollend" }, + { 370, "bis zu 370: Teufelsstahlhandschuhe (Auchenaikrypta)\nFlammenbannhandschuhe (Aldor - Wohlwollend)\nVerzauberter Adamantitgürtel (Seher - Freundlich)" }, + { 375, "bis zu 375: Teufelsstahlhandschuhe (Auchenaikrypta)\nFlammenbannbrustplatte (Aldor - Respektvoll)\nVerzauberter Adamantitgürtel (Seher - Freundlich)" } + }, + [BI["Alchemy"]] = { + { 60, "bis zu 60: Schwacher Heiltrank" }, + { 110, "bis zu 110: Geringer Heiltrank" }, + { 140, "bis zu 140: Heiltrank" }, + { 155, "bis zu 155: Geringer Manatrank" }, + { 185, "bis zu 185: Großer Heiltrank" }, + { 210, "bis zu 210: Elixier der Beweglichkeit" }, + { 215, "bis zu 215: Elixier der großen Verteidigung" }, + { 230, "bis zu 230: Überragender Heiltrank" }, + { 250, "bis zu 250: Elixier der Untotenentdeckung" }, + { 265, "bis zu 265: Elixier der großen Beweglichkeit" }, + { 285, "bis zu 285: Überragender Manatrank" }, + { 300, "bis zu 300: Erheblicher Heiltrank" }, + { 315, "bis zu 315: Flüchtiger Heiltrank\noder Erheblicher Manatrank" }, + { 350, "bis zu 350: Trank des verrückten Alchimisten\nWird ab 335 gelb, ist aber günstig herzustellen" }, + { 375, "bis zu 375: Erheblicher Trank des traumlosen Schlafs\nZu kaufen in Allerias Feste (A)\noder Donnerfeste (H)" } + }, + [L["Mining"]] = { + { 65, "bis zu 65: Baue Kupfer ab\nVerfügbar in allen Startgebieten" }, + { 125, "bis zu 125: Baue Zinn, Silber, Pyrophor and geringes Blutsteinerz ab\n\nBaue Phyrophorerz in Thelgen Rock (Sumpfland)\nEinfach zu skillen bis 125" }, + { 175, "bis zu 175: \nDesolace,Eschental, Ödland, Arathihochland,\nAlteracgebirge, Schlingendorntal, Sümpfe des Elends" }, + { 250, "bis zu 250: Baue Mithril und Echtsilber ab\nVerwüstete Lande, Sengende Schlucht, Ödland, Hinterland,\nWestliche Pestländer, Azshara, Winterquell, Teufelswald, Steinkrallengebirge, Tanaris" }, + { 300, "bis zu 300: Baue Thorium ab \nKrater von Un'goro, Azshara, Winterquell, Verwüstete Lande\nSengende Schlucht, Brennende Steppe, Östliche Pestländer, Westliche Pestländer" }, + { 330, "bis zu 330: Baue Teufelseisen ab\nHöllenfeuerhalbinsel, Zangarmarschen" }, + { 375, "bis zu 375: Baue Teufelseisen und Adamantit ab\nWälder von Terokkar, Nagrand\nEigentlich überall in der Scherbenwelt" } + }, + [L["Herbalism"]] = { + { 50, "bis zu 50: Sammel Silberblatt und Friedensblume\nVerfügbar in allen Startgebieten" }, + { 70, "bis zu 70: Sammel Maguskönigskraut and Erdwurzel\nBrachland, Westfall, Silberwald, Loch Modan" }, + { 100, "bis zu 100: Sammel Wilddornrose\nSilberwald, Dämmerwald, Dunkelküste,\nLoch Modan, Rotkammgebirge" }, + { 115, "bis zu 115: Sammel Beulengras\nEschental, Steinkrallengebirge, Südliches Brachland\nLoch Modan, Rotkammgebirge" }, + { 125, "bis zu 125: Sammel Wildstahlblume\nSteinkrallengebirge, Arathihochland, Schlingendorntal\nSüdliches Brachland, Tausend Nadeln" }, + { 160, "bis zu 160: Sammel Königsblut\nEschental, Steinkrallengebirge, Sumpfland,\nVorgebirge des Hügellands, Sümpfe des Elends" }, + { 185, "bis zu 185: Sammel Blassblatt\nSümpfe des Elends" }, + { 205, "bis zu 205: Sammel Khadgars Schnurrbart\nHinterland, Arathihochland, Sümpfe des Elends" }, + { 230, "bis zu 230: Sammel Feuerblüte\nSengende Schlucht, Verwüstete Lande, Tanaris" }, + { 250, "bis zu 250: Sammel Sonnengras\nTeufelswald, Feralas, Azshara\nHinterland" }, + { 270, "bis zu 270: Sammel Gromsblut\nTeufelswald, Verwüstete Lande,\nMannoroc Coven in Desolace" }, + { 285, "bis zu 285: Sammel Traumblatt\nKrater von Un'Goro, Azshara" }, + { 300, "bis zu 300: Sammel Pestblüte\nÖstliche & Westliche Pestländer, Teufelswald\noder Eiskappen in Winterquell" }, + { 330, "bis zu 330: Sammel Teufelsgras\nHöllenfeuerhalbinsel, Zangarmarschen" }, + { 375, "bis zu 375: Alles was in der Scherenwelt verfügbar ist aufsammeln\nBesonders in Zangarmarschen & Wälder von Terokkar" } + }, + [L["Skinning"]] = { + { 375, "bis zu 375: Teilen Sie Ihr gegenwärtiges Fähigkeitsniveau durch 5\nund kürschnern sie Mobs mit diesem Level" } + }, + -- source: http://www.almostgaming.com/wowguides/world-of-warcraft-lockpicking-guide + [L["Lockpicking"]] = { + { 85, "bis zu 85: Thieves Training\nAtler Mill, Rotkammgebirge (A)\nSchiff in der Nähe von Ratchet (H)" }, + { 150, "bis zu 150: Kasten in der Nähe vom Boss der Gift Quest\nWestfall (A) or Brachland (H)" }, + { 185, "bis zu 185: Murloc Camps (Sumpfland)" }, + { 225, "bis zu 225: Sar'Theris Strand (Desolace)\n" }, + { 250, "bis zu 250: Angor Fortress (Ödland)" }, + { 275, "bis zu 275: Slag Pit (Sengende Schlucht)" }, + { 300, "bis zu 300: Lost Rigger Cove (Tanaris)\nBay of Storms (Azshara)" }, + { 325, "bis zu 325: Feralfen Village (Zangarmarschen)" }, + { 350, "bis zu 350: Kil'sorrow Fortress (Nagrand)\nWende Taschendiebstahl an den Felsfäuste in Nagrand an" } + }, + + -- ** Secondary professions ** + [BI["First Aid"]] = { + { 40, "bis zu 40: Leinenverbände" }, + { 80, "bis zu 80: Schwerer Leinenverband\nWerde Geselle mit 50" }, + { 115, "bis zu 115: Wollverband" }, + { 150, "bis zu 150: Schwerer Wollverband\nHol dir das Erste Hilfe Buch mit 125\nKaufe die 2 Rezepte in Stromgarde (A) or Brackenwall (H)" }, + { 180, "bis zu 180: Seidenverband" }, + { 210, "bis zu 210: Schwerer Seidenverband" }, + { 240, "bis zu 240: Magiestoffverband\nErste Hilfe Quest mit level 35 in\nTheramore (A) oder Hammerfall (H)" }, + { 260, "bis zu 260: Schwerer Magiestoffverband" }, + { 290, "bis zu 290: Runenstoffverband" }, + { 330, "bis zu 330: Schwerer Runenstoffverband\nKaufe das Erste Hilfe Buch für Meister\nTempel von Telhamat (A) oder Falkenwacht (H)" }, + { 360, "bis zu 360: Netherstoffverband\nKaufe das Buch im Tempel von Telhamat (A) oder in der Falkenwacht (H)" }, + { 375, "bis zu 375: Schwerer Netherstoffverband\nKaufe das Buch im Tempel von Telhamat (A) oder in der Falkenwacht (H)" } + }, + [BI["Cooking"]] = { + { 40, "bis zu 40: Gewürzbrot" }, + { 85, "bis zu 85: Geräuchertes Bärenfleisch, Krebsküchlein" }, + { 100, "bis zu 100: Gekochte Krebsschere (A)\nGrubenratteneintopf (H)" }, + { 125, "bis zu 125: Grubenratteneintopf (H)\nGewürzter Wolfskebab (A)" }, + { 175, "bis zu 175: Seltsam schmeckendes Omelett (A)\nScharfe Löwenkoteletts (H)" }, + { 200, "bis zu 200: Gerösteter Raptor" }, + { 225, "bis zu 225: Spinnenwurst\n\n|cFFFFFFFFKoch Quest:\n|cFFFFD70012 Rieseneier,\n10 Scharfes Muschelfleisch,\n20 Alteraclochkäse " }, + { 275, "bis zu 275: Monsteromelett\noder Zartes Wolfsteak" }, + { 285, "bis zu 285: Runn Tum Knolle Surprise\nDüsterbruch (Pusillin)" }, + { 300, "bis zu 300: Geräucherte Wüstenknödel\nQuest in Silithus" }, + { 325, "bis zu 325: Heißer Hetzer, Bussardbissen" }, + { 350, "bis zu 350: Gerösteter Grollhuf\nDoppelwarper, Talbuksteak" }, + { 375, "bis zu 375: Knusperschlange\nLeckerbissen der Mok'Nathal" } + }, + -- source: http://www.wowguideonline.com/fishing.html + [BI["Fishing"]] = { + { 50, "bis zu 50: Jedes Startgebiet" }, + { 75, "bis zu 75:\nDie Kanäle in Sturmwind\nDer Teich in Orgrimmar" }, + { 150, "bis zu 150: Vorgebirge des Hügellands' Fluss" }, + { 225, "bis zu 225: Expertenangelbuch wird in Beutebuch verkauft\nAngel in Desolace oder Arathihochland" }, + { 250, "bis zu 250: Hinterland, Tanaris\n\n|cFFFFFFFFAngelquest in Düstermarschen\n|cFFFFD700Blauwimpel von der ungezähmten Küste (Schlingendorntal)\nFeralas Ahi (Verdantis Fluss, Feralas)\nSar'therisbarsch (Nördlicher Sartheris Strand, Desolace)\nNebelschilf-Mahi-Mahi (Sümpfe des Elends Küste)" }, + { 260, "bis zu 260: Teufelswald" }, + { 300, "bis zu 300: Azshara" }, + { 330, "bis zu 330: Angel in den östlichen Zangarmarschen\nDas Fachmann Anglerbuch gibt es in der Expedition des Cenarius " }, + { 345, "bis zu 345: Westliche Zangarmarschen" }, + { 360, "bis zu 360: Wälder von Terokkar" }, + { 375, "bis zu 375: Wälder von Terokkar, in der Hochebene\nFlugmount benötigt" } + }, + + -- suggested leveling zones, compiled by Thaoky, based on too many sources to list + my own leveling experience on Alliance side + ["Leveling"] = { + { 10, "bis Level 10: Jedes Startgebiet" }, + { 20, "bis Level 20: " .. BZ["Loch Modan"] .. "\n" .. BZ["Westfall"] .. "\n" .. BZ["Darkshore"] .. "\n" .. BZ["Bloodmyst Isle"] + .. "\n" .. BZ["Silverpine Forest"] .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Ghostlands"]}, + { 25, "bis Level 25: " .. BZ["Wetlands"] .. "\n" .. BZ["Redridge Mountains"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Hillsbrad Foothills"] }, + { 28, "bis Level 28: " .. BZ["Duskwood"] .. "\n" .. BZ["Wetlands"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Thousand Needles"] }, + { 31, "bis Level 31: " .. BZ["Duskwood"] .. "\n" .. BZ["Thousand Needles"] .. "\n" .. BZ["Ashenvale"] }, + { 35, "bis Level 35: " .. BZ["Thousand Needles"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Alterac Mountains"] + .. "\n" .. BZ["Arathi Highlands"] .. "\n" .. BZ["Desolace"] }, + { 40, "bis Level 40: " .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Desolace"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 43, "bis Level 43: " .. BZ["Tanaris"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 45, "bis Level 45: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] }, + { 48, "bis Level 48: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] .. "\n" .. BZ["Searing Gorge"] }, + { 51, "bis Level 51: " .. BZ["Tanaris"] .. "\n" .. BZ["Azshara"] .. "\n" .. BZ["Blasted Lands"] + .. "\n" .. BZ["Searing Gorge"] .. "\n" .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] }, + { 55, "bis Level 55: " .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] .. "\n" .. BZ["Burning Steppes"] + .. "\n" .. BZ["Blasted Lands"] .. "\n" .. BZ["Western Plaguelands"] }, + { 58, "bis Level 58: " .. BZ["Winterspring"] .. "\n" .. BZ["Burning Steppes"] .. "\n" .. BZ["Western Plaguelands"] + .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 60, "bis Level 60: " .. BZ["Winterspring"] .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 62, "bis Level 62: " .. BZ["Hellfire Peninsula"] }, + { 64, "bis Level 64: " .. BZ["Zangarmarsh"] .. "\n" .. BZ["Terokkar Forest"]}, + { 65, "bis Level 65: " .. BZ["Terokkar Forest"] }, + { 66, "bis Level 66: " .. BZ["Terokkar Forest"] .. "\n" .. BZ["Nagrand"]}, + { 67, "bis Level 67: " .. BZ["Nagrand"]}, + { 68, "bis Level 68: " .. BZ["Blade's Edge Mountains"]}, + { 70, "bis Level 70: " .. BZ["Blade's Edge Mountains"] .. "\n" .. BZ["Netherstorm"] .. "\n" .. BZ["Shadowmoon Valley"]}, + { 72, "bis Level 72: " .. BZ["Howling Fjord"] .. "\n" .. BZ["Borean Tundra"]}, + { 74, "bis Level 74: " .. BZ["Grizzly Hills"] .. "\n" .. BZ["Dragonblight"]}, + { 76, "bis Level 76: " .. BZ["Dragonblight"] .. "\n" .. BZ["Zul'Drak"]}, + { 78, "bis Level 78: " .. BZ["Zul'Drak"] .. "\n" .. BZ["Sholazar Basin"]}, + { 80, "bis Level 80: " .. BZ["The Storm Peaks"] .. "\n" .. BZ["Icecrown"]}, + }, + + -- Reputation levels + -- -42000 = "Hasserfüllt" + -- -6000 = "Feindselig" + -- -3000 = "Unfreundlich" + -- 0 = "Neutral" + -- 3000 = "Freundlich" + -- 9000 = "Wohlwollend" + -- 21000 = "Respektvoll" + -- 42000 = "Ehrfürchtig" + + -- Outland factions: source: http://www.mmo-champion.com/ + [BF["The Aldor"]] = { + { 0, "bis zu Neutral:\n" .. WHITE .. "[Schreckensgiftbeutel]|r +250 Ruf\n\n" + .. YELLOW .. "Schreckenslauerer,\nSchreckenswitwe\n" + .. WHITE .. "(Wälder von Terokkar)" }, + { 9000, "bis zu Wohlwollend:\n" .. WHITE .. "[Mal von Kil'jaeden]|r\n+25 Ruf" }, + { 42000, "bis zu Ehrfürchtig:\n" .. WHITE .. "[Mal des Sargeras]|r +25 Ruf pro Mal\n" + .. GREEN .. "[Teuflische Waffen]|r +350 Ruf (+1 Heiliger Staub)" } + }, + [BF["The Scryers"]] = { + { 0, "bis zu Neutral:\n" .. WHITE .. "[Auge eines Dunstschuppenbasilisken]|r +250 Ruf\n\n" + .. YELLOW .. "Eisenrückenversteinerer,\nDunstschuppenbeißer,\nDunstschuppenbasilisk\n" + .. WHITE .. "(Wälder von Terokkar)" }, + { 9000, "bis zu Wohlwollend:\n" .. WHITE .. "[Siegel der Feuerschwingen]|r\n+25 Ruf" }, + { 42000, "bis zu Ehrfürchtig:\n" .. WHITE .. "[Siegel des Sonnenzorns]|r +25 Ruf pro Siegel\n" + .. GREEN .. "[Arkaner Foliant]|r +350 Ruf (+1 Arkane Rune)" } + }, + [BF["Netherwing"]] = { + { 3000, "bis zu Freundlich, wiederhole diese Quests:\n\n" + .. YELLOW .. "Ein langsamer Tod (Daily)|r 250 Ruf\n" + .. YELLOW.. "Netherstaubpollen (Daily)|r 250 Ruf\n" + .. YELLOW.. "Kristalle der Netherschwingen (Daily)|r 250 Ruf\n" + .. YELLOW.. "Ein Schatten am Horizont (Daily)\n" + .. YELLOW.. "Die große Eierjagd (Wiederholbar)|r 250 Ruf" }, + { 9000, "bis zu Wohlwollend, wiederhole diese Quests:\n\n" + .. YELLOW .. "Aufsehen und Ihr: Die richtige Wahl treffen|r 350 Ruf\n" + .. YELLOW .. "Der Schuhmerang: Das Mittel gegen den wertlosen Peon (Daily)|r 350 Ruf\n" + .. YELLOW .. "Die Dinge in den Griff bekommen... (Daily)|r 350 Ruf\n" + .. YELLOW .. "Drachen sind unsere geringste Sorge (Daily)|r 350 Ruf\n" + .. YELLOW .. "Verrückt und verwirrt|r 350 Ruf\n" }, + { 21000, "bis zu Respektvoll, wiederhole diese Quests:\n\n" + .. YELLOW .. "Unterdrückt den Unterdrücker|r 500 Ruf\n" + .. YELLOW .. "Schwächt das Portal des Zwielichts (Daily)|r 500 Ruf\n" + .. YELLOW .. "Rennen Quests: 500 für die ersten 5, 1000 für das 6.\n" }, + { 42000, "bis zu Ehrfürchtig, wiederhole diese Quest:\n\n" + .. YELLOW .. "Die tödlichste Falle aller Zeiten (Daily) (3er Gruppenquest)|r 500 Ruf" } + }, + [BF["Honor Hold"]] = { + { 9000, "bis zu Wohlwollend:\n\n" + .. YELLOW .. "Quest in Höllenfeuerhalbinsel\n" + .. GREEN .. "Höllenfeuerbollwerk |r(Normal)\n" + .. GREEN .. "Der Blutkessel |r(Normal)" }, + { 42000, "bis zu Ehrfürchtig:\n\n" + .. GREEN .. "Die zerschmetterten Hallen |r(Normal & Heroisch)\n" + .. GREEN .. "Höllenfeuerbollwerk |r(Heroisch)\n" + .. GREEN .. "Der Blutkessel |r(Heroisch)" } + }, + [BF["Thrallmar"]] = { + { 9000, "bis zu Wohlwollend:\n\n" + .. YELLOW .. "Quest in Höllenfeuerhalbinsel\n" + .. GREEN .. "Höllenfeuerbollwerk |r(Normal)\n" + .. GREEN .. "Der Blutkessel |r(Normal)" }, + { 42000, "bis zu Ehrfürchtig:\n\n" + .. GREEN .. "Die zerschmetterten Hallen |r(Normal & Heroisch)\n" + .. GREEN .. "Höllenfeuerbollwerk |r(Heroisch)\n" + .. GREEN .. "Der Blutkessel |r(Heroisch)" } + }, + [BF["Cenarion Expedition"]] = { + { 3000, "bis zu Freundlich:\n\n" + .. WHITE .. "Dunkelkämme & Blutschuppen Nagas (+5 Ruf)\n" + .. YELLOW .. "Quest in Zangarmarschen\n" + .. "|rGehe in jede " .. GREEN .. "Echsenkessel|r Instanz\n\n" + .. WHITE .. "Bewahre [Unbekannte Pflanzenteile] auf für später" }, + { 9000, "bis zu Wohlwollend:\n\n" + .. WHITE .. "Gebe [Unbekannte Pflanzenteile] 240x ab\n" + .. YELLOW .. "Quest in Zangarmarschen\n" + .. "|rGehe in jede " .. GREEN .. "Echsenkessel|r Instanz" }, + { 42000, "bis zu Ehrfürchtig:\n\n" + .. WHITE .. "Gebe [Waffen des Echsenkessels] ab (+75 Ruf)\n\n" + .. GREEN .. "Dampfkammer |r(Normal)\n" + .. GREEN .. "Jede Echsenkessel Instanz |r(Heroisch)" } + }, + [BF["Keepers of Time"]] = { + { 42000, "bis zu Ehrfürchtig:\n\n" + .. "|rGehe in die Instanzen " .. GREEN .. "Durnholde|r & " .. GREEN .. "Der Schwarze Morast\n\n" + .. YELLOW .. "Behalte die Quests für später:\nDurnholde Questreihe = 5000 Ruf\nSchwarzer Morast Questreihe = 8000 Ruf" } + }, + [BF["The Sha'tar"]] = { + { 42000, "bis zu Ehrfürchtig:\n\n" + .. GREEN .. "Die Botanica |r(Normal & Heroisch)\n" + .. GREEN .. "Die Mechanar |r(Normal & Heroisch)\n" + .. GREEN .. "Die Arcatraz |r(Normal & Heroisch)\n" } + }, + [BF["Lower City"]] = { + { 9000, "bis zu Wohlwollend:\n\n" + .. WHITE .. "Gebe [Arrakoa Feder] 30x ab (+250 Ruf)\n" + .. GREEN .. "Schattenlabyrinth |r(Normal)\n" + .. GREEN .. "Auchenaikrypta |r(Normal)\n" + .. GREEN .. "Sethekkhallen |r(Normal)" }, + { 42000, "bis zu Ehrfürchtig:\n\n" + .. GREEN .. "Schattenlabyrinth |r(Normal & Heroisch)\n" + .. GREEN .. "Auchenaikrypta |r(Heroisch)\n" + .. GREEN .. "Sethekkhallen |r(Heroisch)" } + }, + [BF["The Consortium"]] = { + { 3000, "bis zu Freundlich:\n\n" + .. "|rGebe [Kristallfragment von Oshu'gun] ab (+250 Ruf)\n" + .. "Gebe [Paar Elfenbeinstoßzähne] ab (+250 Ruf)\n\n" + .. GREEN .. "Managruft |r(Normal)" }, + { 9000, "bis zu Wohlwollend:\n\n" + .. "|rGebe [Obsidiankriegsperlen] ab (+250 Ruf)\n\n" + .. GREEN .. "Managruft |r(Normal)" }, + { 42000, "bis zu Ehrfürchtig:\n\n" + .. "|rGebe [Insigne der Zaxxis] ab (+250 Ruf)\n" + .. "|rGebe [Obsidiankriegsperlen] ab (+250 Ruf)\n\n" + .. GREEN .. "Managruft |r(Heroisch)" } + } + +} + diff --git a/Altoholic-Addon/Altoholic/Suggestions_frFR.lua b/Altoholic-Addon/Altoholic/Suggestions_frFR.lua new file mode 100644 index 0000000..7c441c0 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Suggestions_frFR.lua @@ -0,0 +1,594 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() +local BF = LibStub("LibBabble-Faction-3.0"):GetLookupTable() + +if GetLocale() ~= "frFR" then return end -- ** French translation by Laumac ** + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +-- This table contains a list of suggestions to get to the next level of reputation, craft or skill +addon.Suggestions = { + [L["Riding"]] = { + { 75, "Apprenti cavalier (Lv 20): |cFFFFFFFF4g\n|cFFFFD700Monture standard dans/pr\195\168s d'une capitale: |cFFFFFFFF1g" }, + { 150, "Compagnon cavalier (Lv 40): |cFFFFFFFF50g\n|cFFFFD700Monture \195\169pique dans/pr\195\168s d'une capitale: |cFFFFFFFF10g" }, + { 225, "Expert cavalier (Lv 60): |cFFFFFFFF600g\n|cFFFFD700Monture volante dans la vall\195\169e d'Ombrelune: |cFFFFFFFF50g" }, + { 225, "Vol par temps froid (Lv 77): |cFFFFFFFF5000g\n|cFFFFD700Monture volante par temps froid \195\160 Dalaran sur l'aire de Krasus : |cFFFFFFFF1000g" }, + { 300, "Artisan cavalier (Lv 70): |cFFFFFFFF5000g\n|cFFFFD700Monture volante \195\169pique dans la vall\195\169e d'Ombrelune: |cFFFFFFFF200g" } + }, + + -- source : http://forums.worldofwarcraft.com/th...02789457&sid=1 + -- ** Primary professions ** + [BI["Tailoring"]] = { + { 50, "Atteindre 50: Rouleau d'\195\169toffe en lin" }, + { 70, "Atteindre 70: Sac en lin" }, + { 75, "Atteindre 75: Cape en lin renforc\195\169" }, + { 105, "Atteindre 105: Rouleau d'\195\169toffe de laine" }, + { 110, "Atteindre 110: Chemise grise en laine"}, + { 125, "Atteindre 125: Epauli\195\168res \195\160 double couture en laine" }, + { 145, "Atteindre 145: Rouleau d'\195\169toffe de soie" }, + { 160, "Atteindre 160: Chaperon azur en soie" }, + { 170, "Atteindre 170: Bandeau en soie" }, + { 175, "Atteindre 175: Chemise blanche habill\195\169e" }, + { 185, "Atteindre 185: Rouleau de tisse-mage" }, + { 205, "Atteindre 205: Gilet cramoisi en soie" }, + { 215, "Atteindre 215: Culotte cramoisie en soie" }, + { 220, "Atteindre 220: Jambi\195\168res noires en tisse-mage\nou Robe noire en tisse-mage" }, + { 230, "Atteindre 230: Gants noirs en tisse-mage" }, + { 250, "Atteindre 250: Bandeau noir en tisse-mage\nou Epauli\195\168res noires en tisse-mage" }, + { 260, "Atteindre 260: Rouleau d'\195\169toffe runique" }, + { 275, "Atteindre 275: Ceinture en \195\169toffe runique" }, + { 280, "Atteindre 280: Sac en \195\169toffe runique" }, + { 300, "Atteindre 300: Gants en \195\169toffe runique" }, +----------- OUTRETERRE + { 325, "Atteindre 325: Rouleau de tisse-n\195\169ant\n|cFFFFD700Ne pas vendre, sera tr\195\168s utile pour plus tard" }, + { 340, "Atteindre 340: Rouleau de tisse-n\195\169ant impr\195\169gn\195\169\n|cFFFFD700Ne pas vendre, sera tr\195\168s utile pour plus tard" }, + { 350, "Atteindre 350: Bottes en tisse-n\195\169ant\n|cFFFFD700A d\195\169senchanter en poussi\195\168re des arcanes" }, +-- OBSOLETE { 360, "Atteindre 360: Tunique en tisse-n\195\169ant\n|cFFFFD700A d\195\169senchanter en poussi\195\168re des arcanes" }, +-- OBSOLETE { 375, "Atteindre 375: Tunique en tisse-n\195\169ant impr\195\169gn\195\169\nFabriquer son emsemble de sp\195\169cialisation" }, +----------- NORFENDRE + { 375, "Atteindre 375: Rouleau de tisse-givre\n|cFFFFD700En faire un maximum pour la suite (genre 600)" }, + { 380, "Atteindre 380: Ceinture tiss\195\169e de givre" }, + { 385, "Atteindre 385: Bottes tiss\195\169es de givre" }, + { 395, "Atteindre 395: Coiffe tiss\195\169e de givre" }, + { 400, "Atteindre 400: Ceinture en tisse-brune" }, + { 405, "Atteindre 405: Rouleau de tisse-givre impr\195\169gn\195\169\n|cFFFFD700En pr\195\169voir environ 120 pour la suite" }, + { 410, "Atteindre 410: Bandelettes en tisse-brune" }, + { 415, "Atteindre 415: Gants en tisse-brune" }, + { 425, "Atteindre 425: Bottes en tisse-brune" }, + { 440, "Atteindre 440: Sac en tisse-givre\n|cFFFFD700Devient vert au-dessus de 430 mais reste rentable" }, + { 450, "Atteindre 450: N'importe quel craft \195\169pique de haut niveau\nSinon continuer \195\160 faire des sacs\nvoire le sac glaciaire apr\195\168s 445 (exalt\195\169 Fils de Hodir)" } + }, + [BI["Leatherworking"]] = { + { 35, "Atteindre 35: Renfort d'armure l\195\169ger" }, + { 55, "Atteindre 55: Peau l\195\169g\195\168re trait\195\169e" }, + { 85, "Atteindre 85: Gants en cuir estamp\195\169" }, + { 100, "Atteindre 100: Bottes \195\169l\195\169gantes en cuir" }, + { 120, "Atteindre 120: Peau moyenne trait\195\169e" }, + { 125, "Atteindre 125: Bottes \195\169l\195\169gantes en cuir" }, + { 150, "Atteindre 150: Bottes noires en cuir" }, + { 160, "Atteindre 160: Peau lourde trait\195\169e" }, + { 170, "Atteindre 170: Renfort d'armure lourd" }, + { 180, "Atteindre 180: Jambi\195\168res en cuir mat\nou Pantalon du gardien" }, + { 195, "Atteindre 195: Epauli\195\168res barbares" }, + { 205, "Atteindre 205: Brassards mats" }, + { 220, "Atteindre 220: Renfort d'armure \195\169pais" }, + { 225, "Atteindre 225: Bandeau de la nuit" }, + { 250, "Atteindre 250: D\195\169pend de votre sp\195\169cialisation\nBandeau/Tunique/Pantalon de la nuit (El\195\169mentaire)\nCuirasse/Gants arm\195\169s du scorpide (Ecailles de dragon)\nEnsemble en \195\169cailles de tortue (Tribal)" }, + { 260, "Atteindre 260: Bottes de la nuit" }, + { 270, "Atteindre 270: Gantelets corrompus en cuir" }, + { 285, "Atteindre 285: Brassards corrompus en cuir" }, + { 300, "Atteindre 300: Bandeau corrompu en cuir" }, +----------- OUTRETERRE + { 310, "Atteindre 310: Cuir granuleux" }, + { 320, "Atteindre 320: Gants draeniques sauvages" }, + { 325, "Atteindre 325: Bottes draeniques \195\169paisses" }, + { 335, "Atteindre 335: Cuir granuleux lourd\n|cFFFFD700Ne pas vendre, sera tr\195\168s utile pour plus tard" }, + { 340, "Atteindre 340: Gilet draenique \195\169pais" }, + { 350, "Atteindre 350: Bottes draeniques en \195\169cailles" }, +-- OBSOLETE { 365, "Atteindre 365: Bottes du sabot-fourchu \195\169paisses\n|cFFFFD700Farmer le cuir sabot-fourchu \195\160 Nagrand" }, +-- OBSOLETE { 375, "Atteindre 375: Tambours de bataille\n|cFFFFD700Requiert Les Sha'tar - Honor\195\169" }, +----------- NORFENDRE + { 380, "Atteindre 380: Renfort d'armure bor\195\169en" }, + { 385, "Atteindre 385: Gants arctiques" }, + { 390, "Atteindre 390: Prot\195\168ge-\195\169paules cryost\195\168nes" }, + { 405, "Atteindre 405: Cuir bor\195\169en lourd\n|cFFFFD700En pr\195\169voir environ 300 pour la suite" }, + { 415, "Atteindre 415: Armure de jambe du jormungar" }, + { 420, "Atteindre 420: Sac des poches infinies" }, + { 425, "Atteindre 425: Brassards surjet\195\169s ou \195\169quivalent selon la classe" }, + { 435, "Atteindre 435: Prot\195\168ge-mains surjet\195\169s ou \195\169quivalent selon la classe" }, + { 440, "Atteindre 440: Renforts de jambe givrepeau ou \nArmure de jambe en \195\169cailles de glace\nSinon continuer sur les Prot\195\168ge-mains surjet\195\169s ou \195\169quivalent" }, + { 450, "Atteindre 450: N'importe quel craft \195\169pique de haut niveau\nCela reste inutile car aucun craft n\195\169c\195\169ssite d'\195\170tre plus de 440" } + }, + [BI["Engineering"]] = { + { 40, "Atteindre 40: Poudre d'explosion basique" }, + { 50, "Atteindre 50: Poign\195\169e de boulons en cuivre" }, + { 51, "Cr\195\169er une Cl\195\169 plate" }, + { 65, "Atteindre 65: Tube en cuivre" }, + { 75, "Atteindre 75: Dynamite grossi\195\168re" }, + { 95, "Atteindre 95: Poudre d'explosion grossi\195\168re" }, + { 105, "Atteindre 105: Contact en argent" }, + { 120, "Atteindre 120: Tube en bronze" }, + { 125, "Atteindre 125: Petite bombe en bronze" }, + { 145, "Atteindre 145: Poudre d'explosion majeure" }, + { 150, "Atteindre 150: Grande bombe en bronze" }, + { 175, "Atteindre 175: Fus\195\169e bleue, rouge ou verte" }, + { 176, "Cr\195\169er un Micro-ajusteur gyromatique" }, + { 190, "Atteindre 190: Poudre noire solide" }, + { 195, "Atteindre 195: Grande bombe en fer" }, + { 205, "Atteindre 205: Tube en mithril" }, + { 210, "Atteindre 210: D\195\169clencheur instable" }, + { 225, "Atteindre 225: Balles per\185\167antes en mithril" }, + { 235, "Atteindre 235: Armature en mithril" }, + { 245, "Atteindre 245: Bombe explosive" }, + { 250, "Atteindre 250: Balle gyroscopique en mithril" }, + { 260, "Atteindre 260: Poudre d'explosion dense" }, + { 290, "Atteindre 290: Rouage en thorium" }, + { 300, "Atteindre 300: Tube en thorium\nou Obus en thorium (plus rentable)" }, +----------- OUTRETERRE + { 310, "Atteindre 310: Etui en gangrefer,\nPoign\195\169e de boulons en gangrefer,\n et Poudre d'explosion \195\169l\195\169mentaire\nA garder pour des fabrications futures" }, + { 320, "Atteindre 320: Obus en gangrefer" }, + { 335, "Atteindre 335: Mousquet en gangrefer" }, + { 350, "Atteindre 350: Fumig\195\168ne blanc" }, +-- OBSOLETE { 360, "Atteindre 360: Batterie en khorium\nEn faire 20, vous les utiliserez pour monter jusqu'\195\160 375" }, +-- OBSOLETE { 375, "Atteindre 375: Robot r\195\169parateur 110G" }, +----------- NORFENDRE + { 370, "Atteindre 370: Poign\195\169e de boulons en cobalt\nEn pr\195\169voir environ 50 pour la suite" }, + { 377, "Atteindre 377: D\195\169clencheur d'explosion volatile\nEn pr\195\169voir environ 36 pour la suite" }, + { 385, "Atteindre 385: Condensateur surcharg\195\169\nEn pr\195\169voir 10 pour la suite" }, + { 380, "Atteindre 380: Leurre explosif" }, + { 400, "Atteindre 400: Tube en givracier\nEn pr\195\169voir 15 pour la suite" }, + { 405, "Atteindre 405: Lunette \195\160 r\195\169fracteur en diamant taill\195\169" }, + { 415, "Atteindre 415: Bo\195\174te de bombes" }, + { 420, "Atteindre 420: Trousse d'injection de mana\nPeut \195\170tre lucratif et surement utile" }, + { 430, "Atteindre 430: Lunettes de glacier m\195\169canis\195\169es" }, + { 435, "Atteindre 435: Machine \195\160 bruit\nUtiliser les composants mis de cot\195\169" }, + { 450, "Atteindre 450: Couteau de l'arm\195\169e gnome\nPr\195\169voir un point vers la fin pour le craft de t\195\170te" } + }, + [BI["Jewelcrafting"]] = { + { 20, "Atteindre 20: Fil de cuivre d\195\169licat" }, + { 30, "Atteindre 30: Statue de pierre brute" }, + { 50, "Atteindre 50: Bague d'oeil de tigre" }, + { 75, "Atteindre 75: Monture en bronze" }, + { 80, "Atteindre 80: Anneau solide en bronze" }, + { 90, "Atteindre 90: Anneau d'argent \195\169l\195\169gant" }, + { 110, "Atteindre 110: Anneau du pouvoir argent\195\169" }, + { 120, "Atteindre 120: Statue en pierre lourde" }, + { 150, "Atteindre 150: Pendentif du bouclier d'agate\nou Anneau dor\195\169 du dragon" }, + { 180, "Atteindre 180: Filigrane en mithril" }, + { 200, "Atteindre 200: Anneau cisel\195\169 en vrai-argent" }, + { 210, "Atteindre 210: Citrine Ring of Rapid Healing" }, + { 225, "Atteindre 225: Chevali\195\168re d'aigue-marine" }, + { 250, "Atteindre 250: Monture en thorium" }, + { 255, "Atteindre 255: Bague de destruction rouge" }, + { 265, "Atteindre 265: Anneau de soin en vrai-argent" }, + { 275, "Atteindre 275: Anneau d'opale simple" }, + { 285, "Atteindre 285: Chevali\195\168re de saphir" }, + { 290, "Atteindre 290: Bague \195\160 diamant de focalisation" }, + { 300, "Atteindre 300: Anneau d'\195\169meraude du lion" }, +----------- OUTRETERRE + { 310, "Atteindre 310: Toute gemme de qualit\195\169 verte" }, + { 315, "Atteindre 315: Anneau de sang en gangrefer\nou toute gemme de qualit\195\169 verte" }, + { 320, "Atteindre 320: Toute gemme de qualit\195\169 verte" }, + { 325, "Atteindre 325: Anneau de pierre de lune azur" }, + { 335, "Atteindre 335: Adamantite mercurienne (requis pour plus tard)\nou toute gemme de qualit\195\169 verte" }, + { 350, "Atteindre 350: Anneau \195\169pais en adamantite" }, +-- OBSOLETE { 355, "Atteindre 355: Toute gemme de qualit\195\169 bleue" }, +-- OBSOLETE { 360, "Atteindre 360: Butin mondial comme:\nPendentif de rubis vivant\nou Collier \195\169pais en gangracier" }, +-- OBSOLETE { 365, "Atteindre 365: Anneau de protection contre les arcanes\nRequiert Les Sha'tar - Honor\195\169" }, +-- OBSOLETE { 375, "Atteindre 375: Butins mondiaux de qualit\195\169 bleue\nou transmutations de diamants\nRequiert Les Sha'tar,Thrallmar ou Bastion de l'honneur - R\195\169v\195\169r\195\169" }, +----------- NORFENDRE + { 395, "Atteindre 395: Toute nouvelle gemme de Norfendre de qualit\195\169 verte" }, + { 400, "Atteindre 400: Bague de pierre de sang, Amulette en calc\195\169doine cristalline (la plus lucrative)\nCollier en citrine cristalline ou Anneau roche-soleil" }, + { 420, "Atteindre 420: Bague du garde de pierre" }, + { 425, "Atteindre 425: Toute nouvelle gemme de Norfendre de qualit\195\169 bleue\nLes plus interessantes sont Saphir c\195\169leste solide, Rubis \195\169carlate \195\169clatant..." }, + { 450, "Atteindre 450: Faire des m\195\169ta-gemmes\nPenser \195\160 faire les qu\195\170tes journali\195\168res de Dalaran" } + }, + [BI["Enchanting"]] = { + { 2, "Atteindre 2: B\195\162tonnet runique en cuivre" }, + { 75, "Atteindre 75: Ench. de brassards (Vie mineure)" }, + { 85, "Atteindre 85: Ench. de brassards (D\195\169viation mineure)" }, + { 100, "Atteindre 100: Ench. de brassards (Endurance mineure)" }, + { 101, "Cr\195\169er un B\195\162tonnet runique en argent" }, + { 105, "Atteindre 105: Ench. de brassards (Endurance mineure)" }, + { 120, "Atteindre 120: Baguette magique sup\195\169rieure" }, + { 130, "Atteindre 130: Ench. de bouclier (Endurance mineure)" }, + { 150, "Atteindre 150: Ench. de brassards (Endurance inf\195\169rieure)" }, + { 151, "Cr\195\169er un B\195\162tonnet runique en or" }, + { 160, "Atteindre 160: Ench. de brassards (Endurance inf\195\169rieure)" }, + { 165, "Atteindre 165: Ench. de bouclier (Endurance inf\195\169rieure)" }, + { 180, "Atteindre 180: Ench. de brassards (Esprit)" }, + { 200, "Atteindre 200: Ench. de brassards (Force)" }, + { 201, "Cr\195\169er un B\195\162tonnet runique en vrai-argent" }, + { 205, "Atteindre 205: Ench. de brassards (Force)" }, + { 225, "Atteindre 225: Ench. de cape (D\195\169fense sup\195\169rieure)" }, + { 235, "Atteindre 235: Ench. de gants (Agilit\195\169)" }, + { 245, "Atteindre 245: Ench. de plastron (Sant\195\169 excellente)" }, + { 250, "Atteindre 250: Ench. de brassards (Force sup\195\169rieure)" }, + { 270, "Atteindre 270: Huile de mana inf\195\169rieure\nRecette vendue \195\160 Silithus" }, + { 290, "Atteindre 290: Ench. de bouclier (Endurance sup\195\169rieure)\nou Ench. de bottes (Endurance sup\195\169rieure)" }, + { 291, "Cr\195\169er un B\195\162tonnet runique en arcanite" }, + { 300, "Atteindre 300: Ench. de cape (D\195\169fense excellente)" }, +----------- OUTRETERRE + { 301, "Cr\195\169er un B\195\162tonnet runique en gangrefer" }, + { 305, "Atteindre 305: Ench. de cape (D\195\169fense excellente)" }, + { 315, "Atteindre 315: Ench. de brassards (Assaut)" }, + { 325, "Atteindre 325: Ench. de cape (Armure majeure)\nou Ench. de gants (Assaut)" }, + { 335, "Atteindre 335: Ench. de plastron (Esprit majeur)" }, + { 340, "Atteindre 340: Ench. de bouclier (Endurance majeure)" }, + { 345, "Atteindre 345: Huile de sorcier excellente\nFaire cel\195\160 jusqu'\195\160 atteindre 350 si vous avez les composants" }, + { 350, "Atteindre 350: Ench. de gants (Force majeure)" }, +-- OBSOLETE { 351, "Cr\195\169er un B\195\162tonnet runique en adamantite" }, +-- OBSOLETE { 360, "Atteindre 360: Ench. de gants (Force majeure)" }, +-- OBSOLETE { 370, "Atteindre 370: Ench. de gants (Frappe-sort)\nRequiert Exp\195\169dition C\195\169narienne - R\195\169v\195\169r\195\169" }, +-- OBSOLETE { 375, "Atteindre 375: Ench. d'anneau (Pouvoir de gu\195\169rison)\nRequiert Les Sha'tar - R\195\169v\195\169r\195\169" }, +----------- NORFENDRE + { 360, "Atteindre 360: Enchantement de cape (Vitesse)" }, + { 375, "Atteindre 375: Enchantement. de brassards (Frappe)" }, + { 376, "Cr\195\169er un B\195\162tonnet runique en \195\169ternium" }, + { 380, "Atteindre 380: Enchantement. de brassards (Frappe)" }, + { 385, "Atteindre 385: Enchantement. de brassards (Intel. exceptionnelle)" }, + { 395, "Atteindre 395: Enchantement. de bottes (Marcheglace)" }, + { 415, "Atteindre 415: Enchantement. de cape (Agilit\195\169 excellente)" }, + { 420, "Atteindre 420: Enchantement. de bottes (Esprit sup\195\169rieur)" }, + { 425, "Atteindre 425: Enchantement. de bouclier (D\195\169fense)" }, + { 426, "Cr\195\169er un B\195\162tonnet runique en titane" }, + { 430, "Atteindre 430: Enchantement. de bouclier (D\195\169fense)" }, + { 435, "Atteindre 435: Enchantement. de cape (Armure puissante)\n|cFFFFD700Disponible chez Vanessa Sellers \195\160 Dalaran pour 4 \195\169clats de r\195\170ve" }, + { 445, "Atteindre 445: Enchantement. de gants (Homme d'armes)\n|cFFFFD700Disponible chez Vanessa Sellers \195\160 Dalaran pour 4 \195\169clats de r\195\170ve" }, + { 450, "Atteindre 450: Enchantement. de bottes (Assaut sup\195\169rieur)\n|cFFFFD700Disponible chez Vanessa Sellers \195\160 Dalaran pour 4 \195\169clats de r\195\170ve" } + }, + [BI["Blacksmithing"]] = { + { 25, "Atteindre 25: Pierre \195\160 aiguiser brute" }, + { 45, "Atteindre 45: Pierre de lest brute" }, + { 75, "Atteindre 75: Ceinture en anneaux de cuivre" }, + { 80, "Atteindre 80: Pierre de lest grossi\195\168re" }, + { 100, "Atteindre 100: Ceinture runique en cuivre" }, + { 105, "Atteindre 105: B\195\162tonnet en argent" }, + { 125, "Atteindre 125: Epauli\195\168res grossi\195\168res en bronze" }, + { 150, "Atteindre 150: Pierre de lest lourde" }, + { 155, "Atteindre 155: B\195\162tonnet dor\195\169" }, + { 165, "Atteindre 165: Epauli\195\168res en fer \195\169meraude" }, + { 185, "Atteindre 185: Brassards en fer \195\169meraude" }, + { 200, "Atteindre 200: Brassards en \195\169cailles dor\195\169es" }, + { 210, "Atteindre 210: Pierre de lest solide" }, + { 215, "Atteindre 215: Gantelets en \195\169cailles dor\195\169es" }, + { 235, "Atteindre 235: Heaume en plaques d'acier\nou Brassards en \195\169cailles de mithril (plus rentable)\nRecette \195\160 Nid-de-l'aigle (A) ou Pierr\195\170che (H)" }, + { 250, "Atteindre 250: Camail en mithril\nou Eperons en mithril (plus rentable)" }, + { 260, "Atteindre 260: Pierre \195\160 aiguiser dense" }, + { 270, "Atteindre 270: Ceinture en thorium ou Brassards en thorium (plus rentable)\nJambi\195\168res de forge-terre (Sp\195\169 armure)\nLame l\195\169g\195\168re de forge-terre (Sp\195\169 arme)\nMarteau l\195\169ger de forge-braise (Sp\195\169 marteau)\nHache l\195\169g\195\168re de forge-ciel (Sp\195\169 hache)" }, + { 295, "Atteindre 295: Brassards imp\195\169riaux en plaques" }, + { 300, "Atteindre 300: Bottes imp\195\169riales en plaques" }, +----------- OUTRETERRE + { 305, "Atteindre 305: Pierre de lest gangren\195\169e" }, + { 320, "Atteindre 320: Ceinture en plaques de gangrefer" }, + { 325, "Atteindre 325: Bottes en plaques de gangrefer" }, + { 330, "Atteindre 330: Rune de garde inf\195\169rieure" }, + { 335, "Atteindre 335: Cuirasse en gangrefer" }, + { 340, "Atteindre 340: Fendoir en adamantite\nVendu \195\160 Shattrah, Lune-d'argent, Exodar" }, + { 345, "Atteindre 345: Gardien de sauvegarde inf\195\169rieur\nVendu au bastion des Marteaux-hardis et Thrallmar" }, + { 350, "Atteindre 350: Fendoir en adamantite" }, +-- OBSOLETE { 360, "Atteindre 360: Pierre de lest d'adamantite\nRequiert Exp\195\169dition C\195\169narienne - Honor\195\169" }, +-- OBSOLETE { 370, "Atteindre 370: Gants en gangracier (Cryptes d'Auchenai)\nGants plaie-des-flammes (Aldor - Honor\195\169)\nCeinture enchant\195\169e en adamantite (Clairvoyants - Amical)" }, +-- OBSOLETE { 375, "Atteindre 375: Gants en gangracier (Cryptes d'Auchenai)\nCuirasse plaie-des-flammes (Aldor - R\195\169v\195\169r\195\169)\nCeinture enchant\195\169e en adamantite (Clairvoyants - Amical)" }, +----------- NORFENDRE + { 360, "Atteindre 360: Ceinture en cobalt" }, + { 370, "Atteindre 370: Brassards en cobalt" }, + { 375, "Atteindre 375: Heaume en cobalt" }, + { 380, "Atteindre 380: Gantelets en cobalt" }, + { 385, "Atteindre 385: Bottes \195\160 pointes en cobalt" }, + { 390, "Atteindre 390: Shuriken au vol s\195\187r" }, + { 395, "Atteindre 395: Hache de guerre \195\169br\195\169ch\195\169e en cobalt" }, + { 400, "Atteindre 400: Ceinture brillante en saronite" }, + { 405, "Atteindre 405: Casque \195\160 cornes en cobalt" }, + { 410, "Atteindre 410: Bottes brillantes en saronite" }, + { 415, "Atteindre 415: Brassards en saronite tremp\195\169e" }, + { 425, "Atteindre 425: Boucle de ceinture \195\169ternelle\nTr\195\168s lucratives" }, + { 430, "Atteindre 430: Dragonne en titane\nSe revend bien" }, + { 435, "Atteindre 435: Haubert sauvage en saronite" }, + { 445, "Atteindre 445: Cuissards d'intimidation" }, + { 450, "Atteindre 450: Fabriquer des pi\195\168ces \195\169piques utiles\nSinon continuer Cuissards d'intimidation (mais vert)\n" } + }, + [BI["Alchemy"]] = { + { 60, "Atteindre 60: Potion de soins mineure" }, + { 110, "Atteindre 110: Potion de soins inf\195\169rieure" }, + { 140, "Atteindre 140: Potion de soins" }, + { 155, "Atteindre 155: Potion de mana inf\195\169rieure" }, + { 185, "Atteindre 185: Potion de soins sup\195\169rieure" }, + { 210, "Atteindre 210: Elixir d'Agilit\195\169" }, + { 215, "Atteindre 215: Elixir de d\195\169fense sup\195\169rieure" }, + { 230, "Atteindre 230: Potion de soins excellente" }, + { 250, "Atteindre 250: Elixir de d\195\169tection des morts-vivants" }, + { 265, "Atteindre 265: Elixir d'agilit\195\169 sup\195\169rieure" }, + { 285, "Atteindre 285: Potion de mana excellente" }, + { 300, "Atteindre 300: Potion de soins majeure" }, +----------- OUTRETERRE + { 315, "Atteindre 315: Potion de super-soins\nou Potion de super-mana" }, + { 350, "Atteindre 350: Potion de l'alchimiste fou\nPasse rapidement jaune (335), mais rentable \195\160 faire" }, +-- OBSOLETE { 375, "Atteindre 375: Potion de sommeil sans r\195\170ve majeure\nVendu au Bastion All\195\169rien (A)\nou Bastion des Sirre-Tonnerre (H)" }, +----------- NORFENDRE + { 365, "Atteindre 365: Potion de mana glaciale" }, + { 380, "Atteindre 380: Elixir de puissance des sorts" }, + { 385, "Atteindre 385: Potion des cauchemars" }, + { 395, "Atteindre 395: Elixir de force puissante" }, + { 405, "Atteindre 405: Elixir d'agilit\195\169 puissante\nPass\195\169 400 on peut utiliser la Recherches en alchimie de Norfendre (passe vert \195\160 420)" }, + { 410, "Atteindre 410: Potion de soins runique" }, + { 425, "Atteindre 425: Potion de mana runique" }, + { 435, "Atteindre 435: Diamant si\195\168geterre" }, + { 450, "Atteindre 450: N'importe quel flacon\nMonter au-del\195\160 de 335 est juste utile pour la Transmutation \195\169ternelle : Pouvoir" } + }, + [L["Mining"]] = { + { 65, "Atteindre 65: Miner le cuivre\nToutes zones de d\195\169part" }, + { 125, "Atteindre 125: Miner l'\195\169tain, l'argent, l'incendicite et la pierre de sang inf\195\169rieur\n\nMiner l'incendicite au Rocher de Thelgen (Les Paluns)\nProgression rapide jusqu'\195\160 125" }, + { 175, "Atteindre 175: Miner le fer et l'or\nD\195\169solace, Orneval, Terres ingrates, Hautes-terres d'Arathi,\nMontagnes d'Alt\195\169rac, Vall\195\169e de strangleronce, Marais des chagrins" }, + { 250, "Atteindre 250: Miner le mithril et le vrai-argent\nTerres foudroy\195\169es, Gorge des vents br\195\187lants, Terres ingrates, Les Hinterlands,\nMaleterres de l'ouest, Azshara, Berceau-de-l'hiver, Gangrebois, Les Serres-Rocheuses, Tanaris" }, + { 300, "Atteindre 300: Miner le thorium \nCrat\195\168re d'Un'Goro, Azshara, Berceau-de-l'hiver, Terres foudroy\195\169es\nGorge des vents br\195\187lants, Steppes ardentes, Maleterres (Est et Ouest)" }, +----------- OUTRETERRE + { 330, "Atteindre 330: Miner le gangrefer\nP\195\169ninsule des flammes infernales, Mar\195\169cage de Zangar" }, + { 350, "Atteindre 350: Miner le gangrefer et l'adamantite\nFor\195\170t de Terrokar, Nagrand\nSimplement partout en Outreterre" }, +----------- NORFENDRE + { 400, "Atteindre 400: Miner le cobalt dans le Ford Hurlant, Zul'Drak et la d\195\169solation des dragons\nPermet aussi de monter 450" }, + { 450, "Atteindre 450: Miner la saronite dans le bassin de Sholazar, la couronne de glace et les Pics foudroy\195\169s" } + }, + [L["Herbalism"]] = { + { 50, "Atteindre 50: Collecter du Feuillargent et Pacifique\nToutes zones de d\195\169part" }, + { 70, "Atteindre 70: Collecter de la Mage royale et Terrestrine\nLes tarides, Marche de l'ouest, For\195\170t des pins argent\195\169s, Loch Modan" }, + { 100, "Atteindre 100: Collecter de l'Eglantine\nFor\195\170t des pins argent\195\169s, Bois de la p\195\169nombre, Sombrivage,\nLoch Modan, Les Carmines" }, + { 115, "Atteindre 115: Collecter de la Doulourante\nOrneval, Les Serres-Rocheuses, Sud des Tarides\nLoch Modan, Les Carmines" }, + { 125, "Atteindre 125: Collecter de l'Aci\195\169rite sauvage\nLes Serres-Rocheuses, Hautes-Terres d'Arathi, Vall\195\169e de Strangleronce\nSud des Tarides, Milles pointes" }, + { 160, "Atteindre 160: Collecter du Sang royal\nOrneval, Les Serres-Rocheuses, Les Paluns,\nContreforts de Hautebrande, Marais des chagrins" }, + { 185, "Atteindre 185: Collecter de l'Aveuglette\nMarais des chagrins" }, + { 205, "Atteindre 205: Collecter de la Moustaches de Khadgar\nLes Hinterlands, Hautes-Terres d'Arathi, Marais des chagrins" }, + { 230, "Atteindre 230: Collecter de la Fleur de feu\nGorge des vents br\195\187lants, Les terres foudroy\195\169es, Tanaris" }, + { 250, "Atteindre 250: Collecter de la Soleillette\nGangrebois, Feralas, Azshara\nLes Hinterlands" }, + { 270, "Atteindre 270: Collecter du Gromsang\nGangrebois, Les terres foudroy\195\169es,\nConvent de Mannoroc en D\195\169solace" }, + { 285, "Atteindre 285: Collecter du Feuiller\195\170ve\nCrat\195\168re d'Un'Goro, Azshara" }, + { 300, "Atteindre 300: Collecter de la Fleur de peste\nMaleterres (Est et Ouest), Gangrebois\nou Calot de glace au Berceau-de-l'hiver" }, +----------- OUTRETERRE + { 330, "Atteindre 330: Collecter de la Gangrelette\nP\195\169ninsule des flammes infernales, Le mar\195\169cage de Zangar" }, + { 350, "Atteindre 350: Toute fleur disponible en Outreterre\nCibler le mar\195\169cage de Zangar et la for\195\170t de Terrokar" }, +----------- NORFENDRE + { 400, "Atteindre 400: Collecter du Tr\195\168fle dor\195\169\nLa Toundra Bor\195\169enne, Ford Hurlant" }, + { 450, "Atteindre 450: Collecter du Lys tigr\195\169\nLe bassin de sholazar, les Grisonnes, Ford Hurlant" } + }, + [L["Skinning"]] = { + { 375, "Atteindre 375: Diviser le niveau actuel de d\195\169pe\185\167age par 5,\net tuer les monstres d\195\169pe\185\167ables du niveau obtenu" } + }, + -- source: http://www.almostgaming.com/wowguide...kpicking-guide + [L["Lockpicking"]] = { + { 85, "Atteindre 85: Coffre d'entrainement pour voleur\nScierie d'Alther dans les Carmines (A)\nBateau au sud de Cabestan (H)" }, + { 150, "Atteindre 150: Coffre pr\195\168s du boss de la qu\195\170te du poison\nMarche de l'ouest (A) ou Les tarides (H)" }, + { 185, "Atteindre 185: Camps des Murlocs (Les Paluns)" }, + { 225, "Atteindre 225: Gr\195\168ve de Sar'Theris (D\195\169solace)\n" }, + { 250, "Atteindre 250: Forteresse d'Angor (Terres ingrates)" }, + { 275, "Atteindre 275: La fosse aux scories (Gorge des vents br\195\187lants)" }, + { 300, "Atteindre 300: Crique des gr\195\169ements (Tanaris)\nPlage des cr\195\170tes du sud (Azshara)" }, +----------- OUTRETERRE + { 325, "Atteindre 325: Village des Tourbe-farouche (Le mar\195\169cage de Zangar)" }, + { 350, "Atteindre 350: Forteresse Kil'sorrau (Nagrand)\nVoler les Rochepoing \195\160 Nagrand" }, +----------- NORFENDRE + { 400, "Atteindre 400: Faire du vol \195\160 la tire sur les humanoides du Norfendre\n R\195\169cup\195\169rer des Coffrets renforc\195\169s pour les crocheter" } + }, + + -- ** Secondary professions ** + [BI["First Aid"]] = { + { 40, "Atteindre 40: Bandages en lin" }, + { 80, "Atteindre 80: Bandage \195\169pais en lin\nDevenir compagnon \195\160 50" }, + { 115, "Atteindre 115: Bandages en laine" }, + { 150, "Atteindre 150: Bandages \195\169pais en laine\nObtenir le manuel de secourisme expert \195\160 125\nAcheter le manuel \195\160 Stormgarde (A) ou \195\160 Mur-de-foug\195\168res (H)" }, + { 180, "Atteindre 180: Bandage en soie" }, + { 210, "Atteindre 210: Bandage \195\169pais en soie" }, + { 240, "Atteindre 240: Bandages en tisse-mage\nQu\195\170te de secourisme au niveau 35\nIle de Theramore (A) ou Tr\195\169pas d'Orgrim (H)" }, + { 260, "Atteindre 260: Bandage \195\169pais en tisse-mage\nValider niveau suivant au donneur de qu\195\170te secourisme" }, + { 290, "Atteindre 290: Bandage en \195\169toffe runique\nValider niveau suivant au donneur de qu\195\170te secourisme" }, +----------- OUTRETERRE + { 330, "Atteindre 330: Bandage \195\169pais en \195\169toffe runique\nAcheter le manuel de maitre en secourisme\nTemple de Telhamat (A) Guet de l'\195\169pervier (H)" }, + { 360, "Atteindre 360: Bandage en tisse-n\195\169ant\nAcheter le manuel au Temple de Telhamat (A) ou au Guet de l'\195\169pervier (H)" }, + { 375, "Atteindre 375: Bandage \195\169pais en tisse-n\195\169ant\nAcheter le manuel au Temple de Telhamat (A) ou au Guet de l'\195\169pervier (H)" }, +----------- NORFENDRE + { 400, "Atteindre 400: Bandage en tisse-givre\nValider niveau suivant au donneur de qu\195\170te secourisme" }, + { 450, "Atteindre 450: Bandage \195\169pais en tisse-givre\nLe manuel est un butin mondial est n\195\169c\195\169ssite d'\195\170tre au moins 390\nCertains conseillent les trolls de Zul'drak pour le trouver" } + }, + [BI["Cooking"]] = { + { 40, "Atteindre 40: Pain \195\169pic\195\169" }, + { 85, "Atteindre 85: Viande d'ours fum\195\169e, Beignet de crabe" }, + { 100, "Atteindre 100: Pince de crabe farcie (A)\nBrouet de rat (H)" }, + { 125, "Atteindre 125: Brouet de rat (H)\nK\195\169bab de loup assaisonn\195\169 (A)" }, + { 175, "Atteindre 175: Omelette au go\195\187t \195\169trange (A)\nC\195\180telettes de lion \195\169pic\195\169es (H)" }, + { 200, "Atteindre 200: R\195\180ti de raptor" }, + { 225, "Atteindre 225: Saucisse d'araign\195\169e\n\n|cFFFFFFFFQu\195\170te de cuisine:\n|cFFFFD70012 Oeufs g\195\169ants,\n10 Chair de palourde piquante,\n20 Emmental d'Alterac " }, + { 275, "Atteindre 275: Omelette monstrueuse\nou Steak de loup tendre" }, + { 285, "Atteindre 285: Courante-surprise\nHaches-trippes (Pusillin)" }, + { 300, "Atteindre 300: Boulettes fum\195\169es du d\195\169sert\nQu\195\170te en Silithus" }, +----------- OUTRETERRE + { 325, "Atteindre 325: Croque-ravageur, Bouch\195\169es de busard" }, + { 335, "Atteindre 335: Sabot-fourchu r\195\180ti\nSteak dimensionnel, Steak de talbuk" }, +-- OBSOLETE { 375, "Atteindre 375: Serpent croustillant\nC\195\180telettes mok'nathal" }, +----------- NORFENDRE + { 350, "Atteindre 350: Rago\195\187t nordique\n|cFFFFFFFFQu\195\170te de cuisine disponible dans les zones de d\195\169part" }, + { 400, "Atteindre 400: Steak de brochepelle si la zone de d\195\169part est Fjord Hurlant\nMenu de mammouth si la zone de d\195\169part est la Toundra Bor\195\169enne" }, + { 450, "Atteindre 450: Toutes les recettes disponibles via les qu\195\170tes journali\195\168res de Dalaran" } + }, + -- source: http://www.wowguideonline.com/fishing.html + [BI["Fishing"]] = { + { 50, "Atteindre 50: Toute zone de d\195\169part" }, + { 75, "Atteindre 75: Les canaux \195\160 Hurlevent (A)\nLe bassin d'eau d'Orgrimmar (H)" }, + { 150, "Atteindre 150: Rivi\195\168re des contreforts de hautebrande" }, + { 225, "Atteindre 225: Acheter le manuel d'expert en p\195\170che \195\160 Baie-du-butin\nP\195\170cher en D\195\169solace ou hautes-terres d'Arathi" }, + { 250, "Atteindre 250: Hinterlands, Tanaris\n\n|cFFFFFFFFQu\195\170te de p\195\170che dans les mar\195\169cages d'Aprefrange\n|cFFFFD700Savage Coast Blue Sailfin (Vall\195\169e de Strangleronce)\nFeralas Ahi (Verdantis River, Feralas)\nSer'theris Striker (Northern Sartheris Strand, D\195\169solace)\nMisty Reed Mahi Mahi (Marais des chagrins coastline)" }, + { 260, "Atteindre 260: Gangrebois" }, + { 300, "Atteindre 300: Azshara" }, +----------- OUTRETERRE + { 330, "Atteindre 330: Est du Mar\195\169cage de Zangar\nAcheter le manuel d'artisan p\195\170che \195\160 l'Exp\195\169dition C\195\169narienne" }, + { 345, "Atteindre 345: Ouest du Mar\195\169cage de Zangar" }, + { 360, "Atteindre 360: For\195\170t de Terrokar" }, + { 375, "Atteindre 375: For\195\170t de Terrokar (Skettis), en altitude\nMonture volante requise" }, +----------- NORFENDRE + { 450, "Atteindre 450: Avoir de la patience et des appats\nVoir le maitre des p\195\170cheurs, pas besoin de manuel" } + }, + + -- suggested leveling zones, compiled by Thaoky, based on too many sources to list + my own leveling experience on Alliance side + ["Leveling"] = { + { 10, "Atteindre 10: Toute zone de d\195\169part" }, + { 20, "Atteindre 20: " .. BZ["Loch Modan"] .. "\n" .. BZ["Westfall"] .. "\n" .. BZ["Darkshore"] .. "\n" .. BZ["Bloodmyst Isle"] + .. "\n" .. BZ["Silverpine Forest"] .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Ghostlands"]}, + { 25, "Atteindre 25: " .. BZ["Wetlands"] .. "\n" .. BZ["Redridge Mountains"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Hillsbrad Foothills"] }, + { 28, "Atteindre 28: " .. BZ["Duskwood"] .. "\n" .. BZ["Wetlands"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Thousand Needles"] }, + { 31, "Atteindre 31: " .. BZ["Duskwood"] .. "\n" .. BZ["Thousand Needles"] .. "\n" .. BZ["Ashenvale"] }, + { 35, "Atteindre 35: " .. BZ["Thousand Needles"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Alterac Mountains"] + .. "\n" .. BZ["Arathi Highlands"] .. "\n" .. BZ["Desolace"] }, + { 40, "Atteindre 40: " .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Desolace"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 43, "Atteindre 43: " .. BZ["Tanaris"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 45, "Atteindre 45: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] }, + { 48, "Atteindre 48: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] .. "\n" .. BZ["Searing Gorge"] }, + { 51, "Atteindre 51: " .. BZ["Tanaris"] .. "\n" .. BZ["Azshara"] .. "\n" .. BZ["Blasted Lands"] + .. "\n" .. BZ["Searing Gorge"] .. "\n" .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] }, + { 55, "Atteindre 55: " .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] .. "\n" .. BZ["Burning Steppes"] + .. "\n" .. BZ["Blasted Lands"] .. "\n" .. BZ["Western Plaguelands"] }, + { 58, "Atteindre 58: " .. BZ["Winterspring"] .. "\n" .. BZ["Burning Steppes"] .. "\n" .. BZ["Western Plaguelands"] + .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 60, "Atteindre 60: " .. BZ["Winterspring"] .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 62, "Atteindre 62: " .. BZ["Hellfire Peninsula"] }, + { 64, "Atteindre 64: " .. BZ["Zangarmarsh"] .. "\n" .. BZ["Terokkar Forest"]}, + { 65, "Atteindre 65: " .. BZ["Terokkar Forest"] }, + { 66, "Atteindre 66: " .. BZ["Terokkar Forest"] .. "\n" .. BZ["Nagrand"]}, + { 67, "Atteindre 67: " .. BZ["Nagrand"]}, + { 68, "Atteindre 68: " .. BZ["Blade's Edge Mountains"]}, + { 70, "Atteindre 70: " .. BZ["Blade's Edge Mountains"] .. "\n" .. BZ["Netherstorm"] .. "\n" .. BZ["Shadowmoon Valley"]}, + { 72, "Atteindre 72: " .. BZ["Howling Fjord"] .. "\n" .. BZ["Borean Tundra"]}, + { 74, "Atteindre 74: " .. BZ["Grizzly Hills"] .. "\n" .. BZ["Dragonblight"]}, + { 76, "Atteindre 76: " .. BZ["Dragonblight"] .. "\n" .. BZ["Zul'Drak"]}, + { 78, "Atteindre 78: " .. BZ["Zul'Drak"] .. "\n" .. BZ["Sholazar Basin"]}, + { 80, "Atteindre 80: " .. BZ["The Storm Peaks"] .. "\n" .. BZ["Icecrown"]}, + }, + + + -- Reputation levels + -- -42000 = "Haï" + -- -6000 = "Hostile" + -- -3000 = "Inamical" + -- 0 = "Neutre" + -- 3000 = "Amical" + -- 9000 = "Honor\195\169" + -- 21000 = "R\195\169v\195\169r\195\169" + -- 42000 = "Exalt\195\169" + + -- Outland factions: source: http://www.mmo-champion.com/ + [BF["The Aldor"]] = { + { 0, "Atteindre Neutre:\n" .. WHITE .. "[Glande \195\160 venin de croc-d'effroi]|r +250 rep\n\n" + .. YELLOW .. "R\195\180deuse croc-d'effroi,\nVeuve croc-d'effroi\n" + .. WHITE .. "(For\195\170t de Terrokar)" }, + { 9000, "Atteindre Honor\195\169:\n" .. WHITE .. "[Marque de Kil'jaeden]|r\n+25 rep" }, + { 42000, "Atteindre Exalt\195\169:\n" .. WHITE .. "[Marque de Sargeras]|r +25 rep par marque\n" + .. GREEN .. "[Arme gangren\195\169e]|r +350 rep (+1 [Poussi\195\168re sacr\195\169e])" } + }, + [BF["The Scryers"]] = { + { 0, "Atteindre Neutral:\n" .. WHITE .. "[Oeil de basilic tremp\195\169caille]|r +250 rep\n\n" + .. YELLOW .. "P\195\169trificateur Echine-de-fer,\nD\195\169voreur Tremp\195\169caille,\nBasilic Tremp\195\169caille\n" + .. WHITE .. "(For\195\170t de Terrokar)" }, + { 9000, "Atteindre Honor\195\169:\n" .. WHITE .. "[Chevali\195\168re Aile-de-feu]|r\n+25 rep" }, + { 42000, "Atteindre Exalt\195\169:\n" .. WHITE .. "[Chevali\195\168re Solfurie]|r +25 rep par chevali\195\168re\n" + .. GREEN .. "[Tome des arcanes]|r +350 rep (+1 [Rune des arcanes])" } + }, + [BF["Netherwing"]] = { + { 3000, "Atteindre Amical, r\195\169p\195\169ter ces qu\195\170tes:\n\n" + .. YELLOW .. "Une mort lente (Journali\195\168re)|r 250 rep\n" + .. YELLOW .. "Du pollen de pruin\195\169ante (Journali\195\168re)|r 250 rep\n" + .. YELLOW .. "Les cristaux de l'Aile-du-N\195\169ant (Journali\195\168re)|r 250 rep\n" + .. YELLOW .. "Les cieux pas si cl\195\169ments... (Journali\195\168re)\n" + .. YELLOW .. "La ru\195\169e vers les oeufs de l'Aile-du-N\195\169ant (R\195\169p\195\169table)|r 250 rep" }, + { 9000, "Atteindre Honor\195\169, r\195\169p\195\169ter ces qu\195\170tes:\n\n" + .. YELLOW .. "\195\170tre surveillant : savoir faire les bons choix|r 350 rep\n" + .. YELLOW .. "Le botterang : un traitement pour les p\195\169ons bons \195\160 rien (Journali\195\168re)|r 350 rep\n" + .. YELLOW .. "Ramasser les morceaux... (Journali\195\168re)|r 350 rep\n" + .. YELLOW .. "Les dragons sont les derniers de nos soucis (Journali\195\168re)|r 350 rep\n" + .. YELLOW .. "Affol\195\169s et perturb\195\169s|r 350 rep\n" }, + { 21000, "Atteindre R\195\169v\195\169r\195\169, r\195\169p\195\169ter ces qu\195\170tes:\n\n" + .. YELLOW .. "Dominer le Dominateur|r 500 rep\n" + .. YELLOW .. "Perturber la Porte du cr\195\169puscule (Journali\195\168re)|r 500 rep\n" + .. YELLOW .. "Qu\195\170tes de course de drake: 500 chacune \navec 5 pour la 1\195\168re , et 1000 pour la 6\195\168me" }, + { 42000, "Atteindre Exalt\195\169, r\195\169p\195\169ter cette qu\195\170te:\n\n" + .. YELLOW .. "Le plus mortel des pi\195\168ges (Journali\195\168re) (groupe de 3)|r 500 rep" } + }, + [BF["Honor Hold"]] = { + { 9000, "Atteindre Honor\195\169:\n\n" + .. YELLOW .. "Qu\195\170tes de la p\195\169ninsule des flammes infernales\n" + .. GREEN .. "Faire l'instance : Remparts des flammes infernales |r(Normal)\n" + .. GREEN .. "Faire l'instance : La fournaise du sang |r(Normal)" }, + { 42000, "Atteindre Exalt\195\169:\n\n" + .. GREEN .. "Faire l'instance : Les salles bris\195\169es |r(Normal et H\195\169roïque)\n" + .. GREEN .. "Faire l'instance : Remparts des flammes infernales |r(H\195\169roïque)\n" + .. GREEN .. "Faire l'instance : La fournaise du sang |r(H\195\169roïque)" } + }, + [BF["Thrallmar"]] = { + { 9000, "Atteindre Honor\195\169:\n\n" + .. YELLOW .. "Qu\195\170tes de la p\195\169ninsule des flammes infernales\n" + .. GREEN .. "Faire l'instance : Remparts des flammes infernales |r(Normal)\n" + .. GREEN .. "Faire l'instance : La fournaise du sang |r(Normal)" }, + { 42000, "Atteindre Exalt\195\169:\n\n" + .. GREEN .. "Faire l'instance : Les salles bris\195\169es |r(Normal et H\195\169roïque)\n" + .. GREEN .. "Faire l'instance : Remparts des flammes infernales |r(H\195\169roïque)\n" + .. GREEN .. "Faire l'instance : La fournaise du sang |r(H\195\169roïque)" } + }, + + [BF["Cenarion Expedition"]] = { + { 3000, "Atteindre Amical:\n\n" + .. WHITE .. "Tuer les Nagas Sombrecr\195\170te et Ecaille-sanglante (+5 rep)\n" + .. YELLOW .. "Qu\195\170tes dans le Mar\195\169cage de Zangar\n" + .. "Faire n'importe quelle instance du " .. GREEN .. "R\195\169servoir de Glissecroc|r\n\n" + .. WHITE .. "Garder les [Morceaux de plantes non identifi\195\169es] pour passer honor\195\169" }, + { 9000, "Atteindre Honor\195\169:\n\n" + .. WHITE .. "Rendre les [Morceaux de plantes non identifi\195\169es] x240\n" + .. YELLOW .. "Qu\195\170tes dans le Mar\195\169cage de Zangar\n" + .. "Faire n'importe quelle instance du " .. GREEN .. "R\195\169servoir de Glissecroc|r" }, + { 42000, "Atteindre Exalt\195\169:\n\n" + .. WHITE .. "Rendre les [Armes de Glissecroc] +75 rep\n\n" + .. GREEN .. "Faire l'instance : Les enclos aux esclaves |r(Normal)\n" + .. "Faire n'importe quelle instance du " .. GREEN .. "R\195\169servoir de Glissecroc|r (H\195\169roïque)" } + }, + [BF["Keepers of Time"]] = { + { 42000, "Atteindre Exalt\195\169:\n\n" + .. "|rFaire les instances " .. GREEN .. "Les Contreforts d'Hautebrande d'antan|r et " .. GREEN .. "Le noir mar\195\169cage\n\n" + .. YELLOW .. "Garder les qu\195\170tes pour le plus tard possible:\n s\195\169rie de qu\195\170tes du Hautebrande d'antan = 5000 rep\ns\195\169rie de qu\195\170tes du noir mar\195\169cage = 8000 rep" } + }, + [BF["The Sha'tar"]] = { + { 42000, "Atteindre Exalt\195\169:\n\n" + .. GREEN .. "Faire l'instance : La Botanica |r(Normal et H\195\169roïque)\n" + .. GREEN .. "Faire l'instance : Le Mechanar |r(Normal et H\195\169roïque)\n" + .. GREEN .. "Faire l'instance : L'Arcatraz |r(Normal et H\195\169roïque)\n" } + }, + [BF["Lower City"]] = { + { 9000, "Atteindre Honor\195\169:\n\n" + .. WHITE .. "Rendre les [Plume d'Arakkoa] x30 (+250 rep)\n" + .. GREEN .. "Faire l'instance : Labyrinthe des ombres |r(Normal)\n" + .. GREEN .. "Faire l'instance : Cryptes Auchenai |r(Normal)\n" + .. GREEN .. "Faire l'instance : Les salles de Sethekk |r(Normal)" }, + { 42000, "Atteindre Exalt\195\169:\n\n" + .. GREEN .. "Faire l'instance : Labyrinthe des ombres |r(Normal et H\195\169roïque)\n" + .. GREEN .. "Faire l'instance : Cryptes Auchenai |r(H\195\169roïque)\n" + .. GREEN .. "Faire l'instance : Les salles de Sethekk |r(H\195\169roïque)" } + }, + [BF["The Consortium"]] = { + { 3000, "Atteindre Amical:\n\n" + .. "|rRendre les [Fragment de cristal d'Oshu'gun] +250 rep\n" + .. "Rendre les [Paire de d\195\169fenses d'ivoire] +250 rep\n\n" + .. GREEN .. "Faire l'instance : Tombes-mana |r(Normal)" }, + { 9000, "Atteindre Honor\195\169:\n\n" + .. "|rRendre les [Perles de guerre d'obsidienne] +250 rep\n\n" + .. GREEN .. "Faire l'instance : Tombes-mana |r(Normal)" }, + { 42000, "Atteindre Exalt\195\169:\n\n" + .. "|rRendre les [Insigne de Zaxxis] +250 rep\n" + .. "|rRendre les [Perles de guerre d'obsidienne] +250 rep\n\n" + .. GREEN .. "Faire l'instance : Tombes-mana |r(H\195\169roïque)" } + } + +} diff --git a/Altoholic-Addon/Altoholic/Suggestions_koKR.lua b/Altoholic-Addon/Altoholic/Suggestions_koKR.lua new file mode 100644 index 0000000..9f739b8 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Suggestions_koKR.lua @@ -0,0 +1,582 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() +local BF = LibStub("LibBabble-Faction-3.0"):GetLookupTable() + +if GetLocale() ~= "koKR" then return end + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +-- This table contains a list of suggestions to get to the next level of reputation, craft or skill +addon.Suggestions = { + [L["Riding"]] = { + { 75, "수습 탈것 타기 기술 (30 레벨): |cFFFFFFFF35골\n|cFFFFD700수도 도시 안이나 근처에 있는 기본 탈것: |cFFFFFFFF10골" }, + { 150, "중급 탈것 타기 기술 (60 레벨): |cFFFFFFFF600골\n|cFFFFD700수도 도시 안이나 근처에 있는 에픽 탈것: |cFFFFFFFF100골" }, + { 225, "숙련 탈것 타기 기술 (70 레벨): |cFFFFFFFF800골\n|cFFFFD700어둠달 골짜기에 있는 나는 탈것: |cFFFFFFFF100골" }, + { 300, "Artisan riding skill (70 레벨): |cFFFFFFFF5000골\n|cFFFFD700어둠달 골짜기에 있는 에픽 나는 탈것: |cFFFFFFFF200골" } + }, + + -- source : http://forums.worldofwarcraft.com/thread.html?topicId=102789457&sid=1 + -- ** Primary professions ** + [BI["Tailoring"]] = { + { 50, "50 까지: 리넨 두루마리" }, + { 70, "70 까지: 리넨 가방" }, + { 75, "75 까지: 질긴 리넨 단망토" }, + { 105, "105 까지: 양모 두루마리" }, + { 110, "110 까지: 회색 양모 셔츠"}, + { 125, "125 까지: 이중 양모 어깨보호구" }, + { 145, "145 까지: 비단 두루마리" }, + { 160, "160 까지: 감청색 비단 두건" }, + { 170, "170 까지: 비단 머리띠" }, + { 175, "175 까지: 흰색 정장 셔츠" }, + { 185, "185 까지: 마법 두루마리" }, + { 205, "205 까지: 심홍색 비단 조끼" }, + { 215, "215 까지: 심홍색 비단 바지" }, + { 220, "220 까지: 검은 마법매듭 다리보호구\n또는 검은 마법매듭 조끼" }, + { 230, "230 까지: 검은 마법매듭 장갑" }, + { 250, "250 까지: 검은 마법매듭 머리띠\n또는 검은 마법매듭 어깨보호구" }, + { 260, "260 까지: 룬무늬 두루마리" }, + { 275, "275 까지: 룬무늬 허리띠" }, + { 280, "280 까지: 룬매듭 가방" }, + { 300, "300 까지: 룬매듭 장갑" }, + { 325, "325 까지: 황천매듭 두루마리\n|cFFFFD700팔지 말 것, 향후 사용" }, + { 340, "340 까지: 마력 깃든 황천매듭 두루마리\n|cFFFFD700팔지 말 것, 향후 사용" }, + { 350, "350 까지: 황천매듭 장화\n|cFFFFD700마력 추출해서 신비한 수정 가루" }, + { 375, "375 까지: 서리매듭 두루마리" }, + { 380, "380 까지: 서리장식 장화" }, + { 395, "395 까지: 서리장식 두건" }, + { 405, "405 까지: 그늘매듭 두건" }, + { 410, "410 까지: 그늘매듭 손목보호구" }, + { 415, "415 까지: 그늘매듭 장갑" }, + { 425, "425 까지: 황천매듭, 마력 깃든 황천매듭, 태초의 달빛매듭,\n서리매듭 가방" }, + { 450, "450 까지: 필요한 것 위주로\n점수 얻을 수 있는 모든 것" } + }, + [BI["Leatherworking"]] = { + { 35, "35 까지: 작은 방어구 키트" }, + { 55, "55 까지: 얇은 경화 가죽" }, + { 85, "85 까지: 새김무늬 가죽 장갑" }, + { 100, "100 까지: 고급 가죽 허리띠" }, + { 120, "120 까지: 일반 경화 가죽" }, + { 125, "125 까지: 고급 가죽 허리띠" }, + { 150, "150 까지: 암색 가죽 허리띠" }, + { 160, "160 까지: 질긴 경화 가죽" }, + { 170, "170 까지: 고급 방어구 키트" }, + { 180, "180 까지: 거무스름한 가죽 다리보호구\n또는 수호 바지" }, + { 195, "195 까지: 야만전사의 어깨보호구" }, + { 205, "205 까지: 거무스름한 팔보호구" }, + { 220, "220 까지: 두꺼운 방어구 키트" }, + { 225, "225 까지: 밤하늘 머리띠" }, + { 250, "250 까지: 선택한 전문화에 따라\n(원소)밤하늘 머리띠/튜닉/바지\n(용비늘)단단한 전갈 흉갑/장갑\n(전통)거북 껍질 세트" }, + { 260, "260 까지: 밤하늘 장화" }, + { 270, "270 까지: 악의의 가죽 건틀릿" }, + { 285, "285 까지: 악의의 가죽 팔보호구" }, + { 300, "300 까지: 악의의 가죽 머리띠" }, + { 310, "310 까지: 톱니매듭 가죽" }, + { 320, "320 까지: 야생의 드레나이 장갑" }, + { 325, "325 까지: 두꺼운 드레나이 장화" }, + { 335, "335 까지: 질긴톱니매듭가죽\n|cFFFFD700팔지 말 것, 향후 사용" }, + { 340, "340 까지: 두꺼운 드레나이 조끼" }, + { 350, "350 까지: 지옥껍질 흉갑" }, + { 375, "375 까지: 북풍 방어구 키트" }, + { 385, "385 까지: 북극의 장화" }, + { 395, "395 까지: 북극의 허리띠" }, + { 400, "400 까지: 북극의 손목보호구" }, + { 405, "405 까지: 네루비안 다리 방어구 키트" }, + { 410, "410 까지: 어두운 여러가지 흉갑 또는 다리보호구들" }, + { 425, "425 까지: 여러가지 모피 안감\n전문기술 가방들" }, + { 450, "450 까지: 필요한 것 위주로\n점수 얻을 수 있는 모든 것" } + }, + [BI["Engineering"]] = { + { 40, "40 까지: 천연 화약" }, + { 50, "50 까지: 구리 나사 한 줌" }, + { 51, "만능 스패너 하나 제작" }, + { 65, "65 까지: 구리관" }, + { 75, "75 까지: 조잡한 붐스틱" }, + { 95, "95 까지: 굵은 화약" }, + { 105, "105 까지: 은 접지" }, + { 120, "120 까지: 청동관" }, + { 125, "125 까지: 소형 청동 폭탄" }, + { 145, "145 까지: 강한 화약" }, + { 150, "150 까지: 대형 청동 폭탄" }, + { 175, "175 까지: 푸른, 녹색, 또는 붉은 폭죽" }, + { 176, "자동회전 초정밀조율기 하나 제작" }, + { 190, "190 까지: 조밀한 화약" }, + { 195, "195 까지: 대형 철제 폭탄" }, + { 205, "205 까지: 미스릴관" }, + { 210, "210 까지: 유동성 제동장치" }, + { 225, "225 까지: 고강도 미스릴 산탄" }, + { 235, "235 까지: 미스릴 형틀" }, + { 245, "245 까지: 고폭탄" }, + { 250, "250 까지: 미스릴 회전탄" }, + { 260, "260 까지: 강도 높은 화약" }, + { 290, "290 까지: 토륨 부품" }, + { 300, "300 까지: 토륨관\n또는 토륨 탄환 (더 저렴)" }, + { 310, "310 까지: 지옥무쇠 형틀,\n지옥무쇠 나사 한 줌,\n 그리고 원소 화약\n향후 제작을 위해 모두 보관" }, + { 320, "320 까지: 지옥무쇠 폭탄" }, + { 335, "335 까지: 지옥무쇠 머스킷총" }, + { 350, "350 까지: 백색 조명탄" }, + { 375, "375 까지: 코발트 파편 폭탄" }, + { 430, "430 까지: 마나, 치유 주사 도구\n오랫동안 필요하게 될 것임" }, + { 435, "435 까지: 마나 주사 도구" }, + { 450, "450 까지: 필요한 것 위주로,\n점수 얻을 수 있는 모든 것" } + }, + [BI["Jewelcrafting"]] = { + { 20, "20 까지: 가느다른 구리 철사" }, + { 30, "30 까지: 조잡한 돌 조각상" }, + { 50, "50 까지: 호안석 고리" }, + { 75, "75 까지: 청동 장식" }, + { 80, "80 까지: 순 청동 반지" }, + { 90, "90 까지: 세련된 은 반지" }, + { 110, "110 까지: 힘의 은 반지" }, + { 120, "120 까지: 단단한 돌 조각상" }, + { 150, "150 까지: 보호의 태마노 팬던트\n또는 황금 용 반지" }, + { 180, "180 까지: 미스릴 장식" }, + { 200, "200 까지: 글자가 새겨진 진은 반지" }, + { 210, "210 까지: 신속한 치유의 황수정 반지" }, + { 225, "225 까지: 남옥 인장 반지" }, + { 250, "250 까지: 토륨 장식" }, + { 255, "255 까지: 파괴의 붉은 반지" }, + { 265, "265 까지: 치유의 진은 반지" }, + { 275, "275 까지: 간결한 오팔 반지" }, + { 285, "285 까지: 사파이어 인장 반지" }, + { 290, "290 까지: 다이아몬드 정신집중 반지" }, + { 300, "300 까지: 에메랄드 사자 반지" }, + { 310, "310 까지: 각종 녹색 등급 보석" }, + { 315, "315 까지: 피의 지옥무쇠 반지\n또는 각종 녹색 등급 보석" }, + { 320, "320 까지: 각종 녹색 등급 보석" }, + { 325, "325 까지: 하늘월장석 반지" }, + { 335, "335 까지: 수은 아다만타이트 (향후 필요)\n또는 각종 녹색 등급 보석" }, + { 350, "350 까지: 무거운 아다만타이트 반지" }, + { 355, "355 까지: 각종 파란색 등급 보석" }, + { 360, "360 까지: 각종 월드 드랍 제조법, 예:\n생명의 루비 펜던트\n또는 두꺼운 지옥강철 목걸이" }, + { 365, "365 까지: 비전 보호의 반지\n샤타르 평판 - 우호적" }, + { 375, "375 까지: 다이아몬드들 변환\n월드 드랍 (파란색 등급)\n샤타르 - 매우 우호, 스랄마 - 우호적" }, + { 400, "400 까지: 각종 녹색 등급 보석" }, + { 420, "420 까지: 암흑력의 반지" }, + }, + [BI["Enchanting"]] = { + { 2, "2 까지: 룬문자 구리마법막대" }, + { 75, "75 까지: 손목보호구 마법부여 - 최하급 생명력" }, + { 85, "85 까지: 손목보호구 마법부여 - 최하급 회피" }, + { 100, "100 까지: 손목보호구 마법부여 - 최하급 체력" }, + { 101, "룬문자 은마법막대 하나 제작" }, + { 105, "105 까지: 손목보호구 마법부여 - 최하급 체력" }, + { 120, "120 까지: 상급 마술봉" }, + { 130, "130 까지: 방패 마법부여 - 최하급 체력" }, + { 150, "150 까지: 손목보호구 마법부여 - 하급 체력" }, + { 151, "룬문자 금마법막대 하나 제작" }, + { 160, "160 까지: 손목보호구 마법부여 - 하급 체력" }, + { 165, "165 까지: 방패 마법부여 - 하급 체력" }, + { 180, "180 까지: 손목보호구 마법부여 - 정신력" }, + { 200, "200 까지: 손목보호구 마법부여 - 힘" }, + { 201, "룬문자 진은마법막대 하나 제작" }, + { 205, "205 까지: 손목보호구 마법부여 - 힘" }, + { 225, "225 까지: 망토 마법부여 - 상급 보호" }, + { 235, "235 까지: 장갑 마법부여 - 민첩성" }, + { 245, "245 까지: 가슴보호구 마법부여 - 최상급 생명력" }, + { 250, "250 까지: 손목보호구 마법부여 - 상급 힘" }, + { 270, "270 까지: 하급 마나 오일\n주문식은 실리더스에서 판매" }, + { 290, "290 까지: 방패 마법부여 - 상급 체력\n또는 장화 마법부여 - 상급 체력" }, + { 291, "룬문자 아케이나이트막대 하나 제작" }, + { 300, "300 까지: 망토 마법부여 - 최상급 보호" }, + { 301, "룬문자 지옥무쇠막대 하나 제작" }, + { 305, "305 까지: 망토 마법부여 - 최상급 보호" }, + { 315, "315 까지: 손목보호구 마법부여 - 맹공" }, + { 325, "325 까지: 망토 마법부여 - 일급 방어도\nor 장갑 마법부여 - 맹공" }, + { 335, "335 까지: 가슴보호구 마법부여 - 일급 정신력" }, + { 340, "340 까지: 방패 마법부여 - 일급 체력" }, + { 345, "345 까지: 최상급 마술사 오일\n재료가 있다면 350 까지" }, + { 350, "350 까지: 장갑 마법부여 - 일급 힘" }, + { 351, "룬문자 아다만다이트 막대 하나 제작" }, + { 360, "360 까지: 장갑 마법부여 - 일급 힘" }, + { 370, "370 까지: 장갑 마법부여 - 주문 적중\n세나리온 원정대 - 매우 우호적" }, + { 375, "375 까지: 반지 마법부여 - 치유 마법 강화\n샤타르 - 매우 우호적" }, + { 376, "룬문자 이터늄 마법막대 하나 제작" }, + { 380, "380 까지: 가슴보호구 마법부여 - 최상급 능력치" }, + { 390, "390 까지: 무기 마법부여 - 상급 근력" }, + }, + [BI["Blacksmithing"]] = { + { 25, "25 까지: 조잡한 숫돌" }, + { 45, "45 까지: 조잡한 연마석" }, + { 75, "75 까지: 구리 사슬 허리띠" }, + { 80, "80 까지: 일반 연마석" }, + { 100, "100 까지: 구리 룬문자 허리띠" }, + { 105, "105 까지: 은마법막대" }, + { 125, "125 까지: 청동 다리보호구" }, + { 150, "150 까지: 단단한 연마석" }, + { 155, "155 까지: 금마법막대" }, + { 165, "165 까지: 녹색 철제 다리보호구" }, + { 185, "185 까지: 녹색 철제 팔보호구" }, + { 200, "200 까지: 황금 미늘 팔보호구" }, + { 210, "210 까지: 견고한 연마석" }, + { 215, "215 까지: 황금 미늘 팔보호구" }, + { 235, "235 까지: 강철 판금 투구\n또는 미스릴 미늘 팔보호구 (더 저렴)\n제조법은 맹금의 봉우리(얼) 또는 스토나드(호)" }, + { 250, "250 까지: 미스릴 코이프\n또는 미스릴 박차 (더 저렴)" }, + { 260, "260 까지: 강도 톺은 숫돌" }, + { 270, "270 까지: 토륨 허리띠 또는 팔보호구 (더 저렴)\n대지로 벼려낸 다리보호구(갑옷전문)\n대지로 벼려낸 검(검전문)\n불꽃으로 벼려낸 망치(둔기전문)\n하늘로 벼려낸 도끼(도끼전문)" }, + { 295, "295 까지: 황제의 판금 팔보호구" }, + { 300, "300 까지: 황제의 판금 장화" }, + { 305, "305 까지: 지옥의 숫돌" }, + { 320, "320 까지: 지옥무쇠 허리띠" }, + { 325, "325 까지: 지옥무쇠 장화" }, + { 330, "330 까지: 하급 수호의 룬" }, + { 335, "335 까지: 지옥무쇠 흉갑" }, + { 340, "340 까지: 아다만타이트 클레버\n샤트라, 실버문, 엑소다르에서 판매" }, + { 345, "345 까지: 하급 수호의 보호막\n와일드해머 성채와 스랄마에서 판매" }, + { 350, "350 까지: 아다만타이트 클레버" }, + { 360, "360 까지: 아다만타이트 무게추\n세나리온 원정대 - 우호적 필요" }, + { 370, "370 까지: 지옥강철 장갑 (아키나이 납골당)\n화염파멸 장갑 (알도르 사제회 - 우호적 필요)\n마력 깃든 아다만타이트 허리띠 (점술가 길드 - 약간 우호적)" }, + { 375, "375 까지: 지옥강철 장갑 (아키나이 납골당)\n화염파멸 흉갑 (알도르 사제회 - 매우 우호 필요)\n마력 깃든 아다만타이트 허리띠 (점술가 길드 - 약간 우호적)" }, + { 385, "385 까지: 코발트 건틀럿" }, + { 393, "393 까지: 가시 박힌 코발트 어깨보호구\n또는 흉갑" }, + { 395, "395 까지: 가시 박힌 코발트 건틀럿" }, + { 400, "400 까지: 가시 박힌 코발트 허리띠" }, + { 410, "410 까지: 가시 박힌 코발트 팔보호구" }, + { 415, "415 까지: 달궈진 사로나이트 어깨보호구" }, + { 420, "420 까지: 달궈진 사로나이트 팔보호구" }, + { 430, "430 까지: 위압의 손보호대" }, + { 445, "445 까지: 위압의 다리보호구" }, + { 450, "450 까지: 각종 에픽" }, + }, + [BI["Alchemy"]] = { + { 60, "60 까지: 최하급 치유 물약" }, + { 110, "110 까지: 하급 치유 물약" }, + { 140, "140 까지: 치유 물약" }, + { 155, "155 까지: 하급 마나 물약" }, + { 185, "185 까지: 상급 치유 물약" }, + { 210, "210 까지: 민첩의 비약" }, + { 215, "215 까지: 상급 방어의 비약" }, + { 230, "230 까지: 최상급 치유 물약" }, + { 250, "250 까지: 언데드 감지의 비약" }, + { 265, "265 까지: 상급 민첩의 비약" }, + { 285, "285 까지: 최상급 마나 물약" }, + { 300, "300 까지: 일급 치유 물약" }, + { 315, "315 까지: 신속 치유 물약\n또는 일급 마나 물약" }, + { 350, "350 까지: Mad Alchemists's 물약\nTurns yellow at 335, but cheap to make" }, + { 375, "375 까지: 일급 Dreamless Sleep 물약\nSold in Allerian Stronghold (A)\nor Thunderlord Stronghold (H)" } + }, + [L["Mining"]] = { + { 65, "65 까지: 구리 채굴\n모든 시작 지역에서 가능" }, + { 125, "125 까지: Mine Tin, Silver, Incendicite and 하급 Bloodstone\n\nMine Incendicite at Thelgen Rock (Wetlands)\nEasy leveling up to 125" }, + { 175, "175 까지: Mine Iron and Gold\nDesolace, Ashenvale, Badlands, Arathi Highlands,\nAlterac Mountains, Stranglethorn Vale, Swamp of Sorrows" }, + { 250, "250 까지: Mine Mithril and Truesilver\nBlasted Lands, Searing Gorge, Badlands, The Hinterlands,\nWestern Plaguelands, Azshara, Winterspring, Felwood, Stonetalon Mountains, Tanaris" }, + { 300, "300 까지: Mine Thorium \nUn’goro Crater, Azshara, Winterspring, Blasted Lands\nSearing Gorge, Burning Steppes, Eastern Plaguelands, Western Plaguelands" }, + { 330, "330 까지: Mine Fel Iron\nHellfire Peninsula, Zangarmarsh" }, + { 375, "375 까지: Mine Fel Iron and Adamantite\nTerrokar Forest, Nagrand\nBasically everywhere in Outland" } + }, + [L["Herbalism"]] = { + { 50, "50 까지: Collect Silverleaf and Peacebloom\nAvailable in all starting zones" }, + { 70, "70 까지: Collect Mageroyal and Earthroot\nThe Barrens, Westfall, Silverpine Forest, Loch Modan" }, + { 100, "100 까지: Collect Briarthorn\nSilverpine Forest, Duskwood, Darkshore,\nLoch Modan, Redridge Mountains" }, + { 115, "115 까지: Collect Bruiseweed\nAshenvale, Stonetalon Mountains, Southern Barrens\nLoch Modan, Redridge Mountains" }, + { 125, "125 까지: Collect Wild Steelbloom\nStonetalon Mountains, Arathi Highlands, Stranglethorn Vale\nSouthern Barrens, Thousand Needles" }, + { 160, "160 까지: Collect Kingsblood\nAshenvale, Stonetalon Mountains, Wetlands,\nHillsbrad Foothills, Swamp of Sorrows" }, + { 185, "185 까지: Collect Fadeleaf\nSwamp of Sorrows" }, + { 205, "205 까지: Collect Khadgar's Whisker\nThe Hinterlands, Arathi Highlands, Swamp of Sorrows" }, + { 230, "230 까지: Collect Firebloom\nSearing Gorge, Blasted Lands, Tanaris" }, + { 250, "250 까지: Collect Sungrass\nFelwood, Feralas, Azshara\nThe Hinterlands" }, + { 270, "270 까지: Collect Gromsblood\nFelwood, Blasted Lands,\nMannoroc Coven in Desolace" }, + { 285, "285 까지: Collect Dreamfoil\nUn'goro Crater, Azshara" }, + { 300, "300 까지: Collect Plagueblooms\nEastern & Western Plaguelands, Felwood\nor Icecaps in Winterspring" }, + { 330, "330 까지: Collect Felweed\nHellfire Peninsula, Zangarmarsh" }, + { 375, "375 까지: Any flower available in Outland\nFocus on Zangarmarsh & Terrokar Forest" } + }, + [L["Skinning"]] = { + { 375, "375 까지: Divide your current skill level by 5,\nand skin mobs of that level" } + }, + + -- source: http://www.elsprofessions.com/inscription/leveling.html + [L["Inscription"]] = { + { 18, "18 까지: Ivory Ink" }, + { 35, "35 까지: Scroll of Intellect, 정신력 or 체력" }, + { 50, "50 까지: Moonglow Ink\nSave if for 최하급 Inscription Research" }, + { 75, "75 까지: Scroll of Recall, Armor Vellum" }, + { 79, "79 까지: Midnight Ink" }, + { 80, "80 까지: 최하급 Inscription Research" }, + { 85, "85 까지: Glyph of Backstab, Frost Nova\nRejuvenation, ..." }, + { 87, "87 까지: Hunter's Ink" }, + { 90, "90 까지: Glyph of Corruption, Flame Shock\nRapid Charge, Wrath" }, + { 100, "100 까지: Glyph of Ice Armor, Maul\nSerpent Sting" }, + { 104, "104 까지: Lion's Ink" }, + { 105, "105 까지: Glyph of Arcane Shot, Arcane Explosion" }, + { 110, "110 까지: Glyph of Eviscerate, Holy Light, Fade" }, + { 115, "115 까지: Glyph of Fire Nova Totem\n생명력 Funel, Rending" }, + { 120, "120 까지: Glyph of Arcane Missiles, Healing Touch" }, + { 125, "125 까지: Glyph of Expose Armor\nFlash Heal, Judgment" }, + { 130, "130 까지: Dawnstar Ink" }, + { 135, "135 까지: Glyph of Blink\nImmolation, Moonfire" }, + { 140, "140 까지: Glyph of Lay on Hands\nGarrote, Inner Fire" }, + { 142, "142 까지: Glyph of Sunder Armor\nImp, Lightning Bolt" }, + { 150, "150 까지: Strange Tarot" }, + { 155, "155 까지: Jadefire Ink" }, + { 160, "160 까지: Scroll of 체력 III" }, + { 165, "165 까지: Glyph of Gouge, Renew" }, + { 170, "170 까지: Glyph of Shadow Bolt\nStrength of Earth Totem" }, + { 175, "175 까지: Glyph of Overpower" }, + { 177, "177 까지: Royal Ink" }, + { 183, "183 까지: Scroll of 민첩성 III" }, + { 185, "185 까지: Glyph of Cleansing\nShadow Word: Pain" }, + { 190, "190 까지: Glyph of Insect Swarm\nFrost Shock, Sap" }, + { 192, "192 까지: Glyph of Revenge\nVoidwalker" }, + { 200, "200 까지: Arcane Tarot" }, + { 204, "204 까지: Celestial Ink" }, + { 210, "210 까지: Armor Vellum II" }, + { 215, "215 까지: Glyph of Smite, Sinister Strike" }, + { 220, "220 까지: Glyph of Searing Pain\nHealing Stream Totem" }, + { 225, "225 까지: Glyph of Starfire\nBarbaric Insults" }, + { 227, "227 까지: Fiery Ink" }, + { 230, "230 까지: Scroll of 민첩성 IV" }, + { 235, "235 까지: Glyph of Dispel Magic" }, + { 250, "250 까지: Weapon Vellum II" }, + { 255, "255 까지: Scroll of 체력 V" }, + { 260, "260 까지: Scroll of 정신력 V" }, + { 265, "265 까지: Glyph of Freezing Trap, Shred" }, + { 270, "270 까지: Glyph of Exorcism, Bone Shield" }, + { 275, "275 까지: Glyph of Fear Ward, Frost Strike" }, + { 285, "285 까지: Ink of the Sky" }, + { 295, "295 까지: Glyph of Execution\nSprint, Death Grip" }, + { 300, "300 까지: Scroll of 정신력 VI" }, + { 304, "304 까지: Ethereal Ink" }, + { 305, "305 까지: Glyph of Plague Strike\nEarthliving Weapon, Flash of Light" }, + { 310, "310 까지: Glyph of Feint" }, + { 315, "315 까지: Glyph of Rake, Rune Tap" }, + { 320, "320 까지: Glyph of Holy Nova, Rapid Fire" }, + { 325, "325 까지: Glyph of Blood Strike, Sweeping Strikes" }, + { 327, "327 까지: Darkflame Ink" }, + { 330, "330 까지: Glyph of Mage Armor, Succubus" }, + { 335, "335 까지: Glyph of Scourge Strike, Windfury Weapon" }, + { 340, "340 까지: Glyph of Arcane Power, Seal of Command" }, + { 345, "345 까지: Glyph of Ambush, Death Strike" }, + { 350, "350 까지: Glyph of Whirlwind" }, + { 360, "360 까지: Glyph of Mind Flay, Banish" }, + { 365, "365 까지: Scroll of Intellect VII" }, + { 370, "370 까지: Scroll of 힘 VII" }, + { 375, "375 까지: Scroll of 민첩성 VII" }, + { 380, "380 까지: Glyph of Focus, Strangulate" }, + { 400, "400 까지: Northrend Inscription Research" }, + + { 450, "450 까지: Not yet implemented" } + }, + + -- source: http://www.almostgaming.com/wowguides/world-of-warcraft-lockpicking-guide + [L["Lockpicking"]] = { + { 85, "85 까지: Thieves Training\nAtler Mill, Redridge Moutains (A)\nShip near Ratchet (H)" }, + { 150, "150 까지: Chest near the boss of the poison quest\nWestfall (A) or The Barrens (H)" }, + { 185, "185 까지: Murloc camps (Wetlands)" }, + { 225, "225 까지: Sar'Theris Strand (Desolace)\n" }, + { 250, "250 까지: Angor Fortress (Badlands)" }, + { 275, "275 까지: Slag Pit (Searing Gorge)" }, + { 300, "300 까지: Lost Rigger Cove (Tanaris)\nBay of Storms (Azshara)" }, + { 325, "325 까지: Feralfen Village (Zangarmarsh)" }, + { 350, "350 까지: Kil'sorrow Fortress (Nagrand)\nPickpocket the Boulderfists in Nagrand" } + }, + + -- ** Secondary professions ** + [BI["First Aid"]] = { + { 40, "40 까지: 리넨 붕대" }, + { 80, "80 까지: 두꺼운 리넨 붕대\n50에 중급" }, + { 115, "115 까지: 양모 붕대" }, + { 150, "150 까지: 두꺼운 양모 붕대\n125에 숙련 응급치료 책\nBuy the 2 manuals in Stromguarde (A) or Brackenwall Village (H)" }, + { 180, "180 까지: 비단 붕대" }, + { 210, "210 까지: 두꺼운 비단 붕대" }, + { 240, "240 까지: 마법 붕대\n레벨 35에 응급치료 퀘스트\n테라모어 섬 (얼) 또는 헤머폴 (호)" }, + { 260, "260 까지: 두꺼운 마법 붕대" }, + { 290, "290 까지: 룬매듭 붕대" }, + { 330, "330 까지: 두꺼운 룬매듭 붕대\nBuy Master First Aid book\nTemple of Telhamat (A) or Falcon Watch (H)" }, + { 360, "360 까지: 황천매듭 붕대\nBuy the book in the Temple of Telhamat (A) or in Falcon Watch (H)" }, + { 375, "375 까지: 두꺼운 황천매듭 붕대\nBuy the book in the Temple of Telhamat (A) or in Falcon Watch (H)" } + }, + [BI["Cooking"]] = { + { 40, "40 까지: 매콤한 빵" }, + { 85, "85 까지: 곰고기 숯불구이, 게살 케이크" }, + { 100, "100 까지: 집게발 요리 (얼)\n들쥐 스튜 (호)" }, + { 125, "125 까지: 들쥐 스튜 (호)\n양념 늑대 케밥 (얼)" }, + { 175, "175 까지: 진기한 맛의 오믈렛 (얼)\n매운 사자 고기 (호)" }, + { 200, "200 까지: 랩터 숯불구이" }, + { 225, "225 까지: 거미 소시지\n\n|cFFFFFFFF요리 퀘스트:\n|cFFFFD70012 거대한 알,\n10 Zesty Clam Meat,\n20 알터렉 스위스 " }, + { 275, "275 까지: 괴물 오믈렛\n또는 연한 늑대 스테이크" }, + { 285, "285 까지: 룬툼 줄기 별미\nDire Maul (Pusillin)" }, + { 300, "300 까지: 훈제 사막 경단\n실리더스에서 퀘스트" }, + { 325, "325 까지: Ravager Dogs, Buzzard Bites" }, + { 350, "350 까지: 갈래발굽 숯불구이\n차원의 버거, 탈부크 스테이크" }, + { 375, "375 까지: Crunchy Serpent\nMok'nathal Treats" } + }, + -- source: http://www.wowguideonline.com/fishing.html + [BI["Fishing"]] = { + { 50, "50 까지: 모든 시작 지역" }, + { 75, "75 까지:\n스톰윈드 안 운하\n오그리마 안 연못The Pond in Orgrimmar" }, + { 150, "150 까지: 힐스블래드 Foothills' river" }, + { 225, "225 까지: 숙련 낚시 기술 책 구입 in Booty Bay\nFish in Desolace 또는 아라시 고원" }, + { 250, "250 까지: Hinterlands, 타나리스\n\n|cFFFFFFFFFishing quest in Dustwallow Marsh\n|cFFFFD700Savage Coast Blue Sailfin (Stranglethorn Vale)\nFeralas Ahi (Verdantis River, Feralas)\nSer'theris Striker (Northern Sartheris Strand, Desolace)\nMisty Reed Mahi Mahi (Swamp of Sorrows coastline)" }, + { 260, "260 까지: Felwood" }, + { 300, "300 까지: 아즈라샤" }, + { 330, "330 까지: 장가르 습지대 동부에 있는 물고기\n세나리온 원정대에 전문 낚시책" }, + { 345, "345 까지: 장가르 습지대 서부" }, + { 360, "360 까지: Terrokar Forest" }, + { 375, "375 까지: Terrokar Forest, in altitude\nFlying mount required" } + }, + + -- suggested leveling zones, compiled by Thaoky, based on too many sources to list + my own leveling experience on Alliance side + ["Leveling"] = { + { 10, "10 까지: 모든 시작 지역" }, + { 20, "20 까지: " .. BZ["Loch Modan"] .. "\n" .. BZ["Westfall"] .. "\n" .. BZ["Darkshore"] .. "\n" .. BZ["Bloodmyst Isle"] + .. "\n" .. BZ["Silverpine Forest"] .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Ghostlands"]}, + { 25, "25 까지: " .. BZ["Wetlands"] .. "\n" .. BZ["Redridge Mountains"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Hillsbrad Foothills"] }, + { 28, "28 까지: " .. BZ["Duskwood"] .. "\n" .. BZ["Wetlands"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Thousand Needles"] }, + { 31, "31 까지: " .. BZ["Duskwood"] .. "\n" .. BZ["Thousand Needles"] .. "\n" .. BZ["Ashenvale"] }, + { 35, "35 까지: " .. BZ["Thousand Needles"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Alterac Mountains"] + .. "\n" .. BZ["Arathi Highlands"] .. "\n" .. BZ["Desolace"] }, + { 40, "40 까지: " .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Desolace"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 43, "43 까지: " .. BZ["Tanaris"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 45, "45 까지: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] }, + { 48, "48 까지: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] .. "\n" .. BZ["Searing Gorge"] }, + { 51, "51 까지: " .. BZ["Tanaris"] .. "\n" .. BZ["Azshara"] .. "\n" .. BZ["Blasted Lands"] + .. "\n" .. BZ["Searing Gorge"] .. "\n" .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] }, + { 55, "55 까지: " .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] .. "\n" .. BZ["Burning Steppes"] + .. "\n" .. BZ["Blasted Lands"] .. "\n" .. BZ["Western Plaguelands"] }, + { 58, "58 까지: " .. BZ["Winterspring"] .. "\n" .. BZ["Burning Steppes"] .. "\n" .. BZ["Western Plaguelands"] + .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 60, "60 까지: " .. BZ["Winterspring"] .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 62, "62 까지: " .. BZ["Hellfire Peninsula"] }, + { 64, "64 까지: " .. BZ["Zangarmarsh"] .. "\n" .. BZ["Terokkar Forest"]}, + { 65, "65 까지: " .. BZ["Terokkar Forest"] }, + { 66, "66 까지: " .. BZ["Terokkar Forest"] .. "\n" .. BZ["Nagrand"]}, + { 67, "67 까지: " .. BZ["Nagrand"]}, + { 68, "68 까지: " .. BZ["Blade's Edge Mountains"]}, + { 70, "70 까지: " .. BZ["Blade's Edge Mountains"] .. "\n" .. BZ["Netherstorm"] .. "\n" .. BZ["Shadowmoon Valley"]}, + { 72, "72 까지: " .. BZ["Howling Fjord"] .. "\n" .. BZ["Borean Tundra"]}, + { 74, "74 까지: " .. BZ["Grizzly Hills"] .. "\n" .. BZ["Dragonblight"]}, + { 76, "76 까지: " .. BZ["Dragonblight"] .. "\n" .. BZ["Zul'Drak"]}, + { 78, "78 까지: " .. BZ["Zul'Drak"] .. "\n" .. BZ["Sholazar Basin"]}, + { 80, "80 까지: " .. BZ["The Storm Peaks"] .. "\n" .. BZ["Icecrown"]}, + }, + + -- Reputation levels + -- -42000 = "Hated", "매우 적대적" + -- -6000 = "Hostile", "적대적" + -- -3000 = "Unfriendly", "약간 적대적" + -- 0 = "Neutral", "중립적" + -- 3000 = "Friendly", "약간 우호적" + -- 9000 = "Honored", "우호적" + -- 21000 = "Revered", "매우 우호적" + -- 42000 = "Exalted", "확고한 동맹" + + -- Outland factions: source: http://www.mmo-champion.com/ + [BF["The Aldor"]] = { + { 0, "중립적 까지:\n" .. WHITE .. "[Dreadfang Venom Sac]|r +250 rep\n\n" + .. YELLOW .. "Dreadfang Lurker,\nDreadfang Widow\n" + .. WHITE .. "(Terrokar Forest)" }, + { 9000, "우호적 까지:\n" .. WHITE .. "[Mark of Kil'jaeden]|r\n+25 rep" }, + { 42000, "확고한 까지:\n" .. WHITE .. "[Mark of Sargeras]|r +25 rep per mark\n" + .. GREEN .. "[Fel Armament]|r +350 rep (+1 Holy Dust)" } + }, + [BF["The Scryers"]] = { + { 0, "중립적 까지:\n" .. WHITE .. "[Dampscale Basilisk Eye]|r +250 rep\n\n" + .. YELLOW .. "Ironspine Petrifier,\nDampscale Devourer,\nDampscale Basilisk\n" + .. WHITE .. "(Terrokar Forest)" }, + { 9000, "우호적 까지:\n" .. WHITE .. "[Firewing Signet]|r\n+25 rep" }, + { 42000, "확고한 까지:\n" .. WHITE .. "[Sunfury Signet]|r +25 rep per mark\n" + .. GREEN .. "[Arcane Tome]|r +350 rep (+1 Arcane Rune)" } + }, + [BF["Netherwing"]] = { + { 3000, "약간 우호적 까지, repeat these quests:\n\n" + .. YELLOW .. "A Slow Death (Daily)|r 250 rep\n" + .. YELLOW.. "Netherdust Pollen (Daily)|r 250 rep\n" + .. YELLOW.. "Netherwing crystal (Daily)|r 250 rep\n" + .. YELLOW.. "Not so friendly skies (Daily)\n" + .. YELLOW.. "Great Netherwing egg hunt (Repeatable)|r 250 rep" }, + { 9000, "우호적 까지, repeat these quests:\n\n" + .. YELLOW .. "Overseeing and you: making the right choices|r 350 rep\n" + .. YELLOW .. "The Booterang: A Cure ... (Daily)|r 350 rep\n" + .. YELLOW .. "Picking up the pieces (Daily)|r 350 rep\n" + .. YELLOW .. "Dragons are the least of our problems (Daily)|r 350 rep\n" + .. YELLOW .. "Crazed & confused|r 350 rep\n" }, + { 21000, "매우 우호적 까지, repeat these quests:\n\n" + .. YELLOW .. "Subduing the Subduer|r 500 rep\n" + .. YELLOW .. "Disrupting the Twiligth Generator (Daily)|r 500 rep\n" + .. YELLOW .. "Race quests 500 each for first 5, 1000 for 6th\n" }, + { 42000, "확고한 까지, repeat this quest:\n\n" + .. YELLOW .. "The greatest trap ever (Daily) (3 man group)|r 500 rep" } + }, + [BF["Honor Hold"]] = { + { 9000, "우호적 까지:\n\n" + .. YELLOW .. "Quest in Hellfire Peninsula\n" + .. GREEN .. "Hellfire Remparts |r(Normal)\n" + .. GREEN .. "Blood Furnace |r(Normal)" }, + { 42000, "확고한 까지:\n\n" + .. GREEN .. "Shattered Halls |r(Normal & Heroic)\n" + .. GREEN .. "Hellfire Remparts |r(Heroic)\n" + .. GREEN .. "Blood Furnace |r(Heroic)" } + }, + [BF["Thrallmar"]] = { + { 9000, "우호적 까지:\n\n" + .. YELLOW .. "Quest in Hellfire Peninsula\n" + .. GREEN .. "Hellfire Remparts |r(Normal)\n" + .. GREEN .. "Blood Furnace |r(Normal)" }, + { 42000, "확고한 까지:\n\n" + .. GREEN .. "Shattered Halls |r(Normal & Heroic)\n" + .. GREEN .. "Hellfire Remparts |r(Heroic)\n" + .. GREEN .. "Blood Furnace |r(Heroic)" } + }, + [BF["Cenarion Expedition"]] = { + { 3000, "약간 우호적 까지:\n\n" + .. WHITE .. "Darkcrest & Bloodscale Nagas (+5 rep)\n" + .. YELLOW .. "Quest in Zangarmarsh\n" + .. "|rRun any " .. GREEN .. "Coilfang|r instance\n\n" + .. WHITE .. "Keep [Unidentified Plant Parts] for later" }, + { 9000, "우호적 까지:\n\n" + .. WHITE .. "Turn in [Unidentified Plant Parts] x240\n" + .. YELLOW .. "Quest in Zangarmarsh\n" + .. "|rRun any " .. GREEN .. "Coilfang|r instance" }, + { 42000, "확고한 까지:\n\n" + .. WHITE .. "Turn in [Coilfang Armaments] +75 rep\n\n" + .. GREEN .. "Steamvault |r(Normal)\n" + .. GREEN .. "Any Coilfang instance |r(Heroic)" } + }, + [BF["Keepers of Time"]] = { + { 42000, "확고한 까지:\n\n" + .. "|rRun the " .. GREEN .. "Old Hillsbrad Foothills|r & " .. GREEN .. "The Black Morass\n\n" + .. YELLOW .. "Keep quests for later:\nOld Hillsbrad quesline = 5000 rep\nBlack Morass questline = 8000 rep" } + }, + [BF["The Sha'tar"]] = { + { 42000, "확고한 까지:\n\n" + .. GREEN .. "The Botanica |r(Normal & Heroic)\n" + .. GREEN .. "The Mechanar |r(Normal & Heroic)\n" + .. GREEN .. "The Arcatraz |r(Normal & Heroic)\n" } + }, + [BF["Lower City"]] = { + { 9000, "우호적 까지:\n\n" + .. WHITE .. "Turn in [Arrakoa Feather] x30 (+250 rep)\n" + .. GREEN .. "Shadow Labyrinth |r(Normal)\n" + .. GREEN .. "Auchenai Crypts |r(Normal)\n" + .. GREEN .. "Sethekk Halls |r(Normal)" }, + { 42000, "확고한 까지:\n\n" + .. GREEN .. "Shadow Labyrinth |r(Normal & Heroic)\n" + .. GREEN .. "Auchenai Crypts |r(Heroic)\n" + .. GREEN .. "Sethekk Halls |r(Heroic)" } + }, + [BF["The Consortium"]] = { + { 3000, "약간 우호적 까지:\n\n" + .. "|rTurn in [Oshu'gun Crystal Fragment] +250 rep\n" + .. "Turn in [Pair of Ivory Tusks] +250 rep\n\n" + .. GREEN .. "Mana-Tombs |r(Normal)" }, + { 9000, "우호적 까지:\n\n" + .. "|rTurn in [Obsidian Warbeads] +250 rep\n\n" + .. GREEN .. "Mana-Tombs |r(Normal)" }, + { 42000, "확고한 까지:\n\n" + .. "|rTurn in [Zaxxis Insignia] +250 rep\n" + .. "|rTurn in [Obsidian Warbeads] +250 rep\n\n" + .. GREEN .. "Mana-Tombs |r(Heroic)" } + } + + -- Northrend factions +} diff --git a/Altoholic-Addon/Altoholic/Suggestions_ruRU.lua b/Altoholic-Addon/Altoholic/Suggestions_ruRU.lua new file mode 100644 index 0000000..b4ea0c2 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Suggestions_ruRU.lua @@ -0,0 +1,567 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() +local BF = LibStub("LibBabble-Faction-3.0"):GetLookupTable() + +if GetLocale() ~= "ruRU" then return end + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +-- This table contains a list of suggestions to get to the next level of reputation, craft or skill +addon.Suggestions = { + [L["Riding"]] = { + { 75, "Ученик в деле верховой езды (20 урв): |cFFFFFFFF4g\n|cFFFFD700Стандартные верховые животные/nобучаются в столицах: |cFFFFFFFF1з" }, + { 150, "Подмастерьем в деле верховой езды (40 урв): |cFFFFFFFF50g\n|cFFFFD700Эпические верховые животные/nобучаются в столицах: |cFFFFFFFF10з" }, + { 225, "Умельцем в деле верховой езды (60 урв): |cFFFFFFFF600g\n|cFFFFD700Летающие верховые животные в Долине Призрачной Луны: |cFFFFFFFF50з" }, + { 300, "Профессионалом в деле верховой езды (70 урв): |cFFFFFFFF5000g\n|cFFFFD700Эпические летающие верховые животные в Долине Призрачной Луны: |cFFFFFFFF200з" } + }, + + -- source : http://forums.worldofwarcraft.com/thread.html?topicId=102789457&sid=1 + -- ** Primary professions ** + [BI["Tailoring"]] = { + { 50, "До 50: Рулон льняной ткани" }, + { 70, "До 70: Льняная сумка" }, + { 75, "До 75: Усиленная льняная накидка" }, + { 105, "До 105: Рулон шерсти" }, + { 110, "До 110: Серая шерстяная рубашка"}, + { 125, "До 125: Шерстяные наплечники с двойным швом" }, + { 145, "До 145: Рулон шелка" }, + { 160, "До 160: Лазурный шелковый капюшон" }, + { 170, "До 170: Шелковая головная повязка" }, + { 175, "До 175: Церемониальная белая рубашка" }, + { 185, "До 185: Рулон магической ткани" }, + { 205, "До 205: Багровый шелковый жилет" }, + { 215, "До 215: Багровые шелковые кюлоты" }, + { 220, "До 220: Черные поножи из магической ткани\nили Черный жилет из магической ткани" }, + { 230, "До 230: Черные перчатки из магической ткани" }, + { 250, "До 250: Черная повязка из магической ткани\nили Черные наплечники из магической ткани" }, + { 260, "До 260: Рулон рунической ткани" }, + { 275, "До 275: Пояс из рунической ткани" }, + { 280, "До 280: Сумка из рунической ткани" }, + { 300, "До 300: Перчатки из рунической ткани" }, + { 325, "До 325: Рулоны ткани Пустоты\n|cFFFFD700Не продовайте их, пожже они вам понадобятся|r" }, + { 340, "До 340: Рулоны прочной ткани Пустоты\n|cFFFFD700Не продовайте их, пожже они вам понадобятся|r" }, + { 350, "До 350: Сапоги из ткани Пустоты\n|cFFFFD700Распылите их на Чародейскую пыль|r" }, + { 375, "До 375: Рулоны ледяной ткани" }, + { 380, "До 380: Ледотканые сапоги" }, + { 395, "До 395: Ледотканый шлем" }, + { 405, "До 405: Клобук из сумеречной ткани" }, + { 410, "До 410: Напульсники из сумеречной ткани" }, + { 415, "До 415: Перчатки из сумеречной ткани" }, + { 425, "До 425: Иссиня-черная ткань, Лунный тюль, или Чароткань\nСумка из ледяной ткани" }, + { 450, "До 450: Изготовьте любую вещь для получения очка,\nв зависимости от ваших потребностей" } + }, + [BI["Leatherworking"]] = { + { 35, "До 35: Накладки из тонкой кожи" }, + { 55, "До 55: Обработанная легкая шкура" }, + { 85, "До 85: Тисненые кожаные перчатки" }, + { 100, "До 100: Тонкий кожаный пояс" }, + { 120, "До 120: Обработанная средняя шкура" }, + { 125, "До 125: Тонкий кожаный пояс" }, + { 150, "До 150: Темный кожаный пояс" }, + { 160, "До 160: Обработанная тяжелая шкура" }, + { 170, "До 170: Накладки из толстой кожи" }, + { 180, "До 180: Мглистые кожаные поножи\nили Штаны стража" }, + { 195, "До 195: Варварские наплечники" }, + { 205, "До 205: Мглистые наручи" }, + { 220, "До 220: Накладки из плотной кожи" }, + { 225, "До 225: Ночная головная повязка" }, + { 250, "До 250: Зависит от вашей специализации\nНочная головная повязка/мундир/штаны (сила стихий)\nЖесткая кираса из чешуи скорпида/перчатки (чешуя дракона)\nКомплект из Черепашьего панциря (традиции предков)" }, + { 260, "До 260: Ночные сапоги" }, + { 270, "До 270: Гибельные кожаные рукавицы" }, + { 285, "До 285: Гибельные кожаные наручи" }, + { 300, "До 300: Гибельная кожаная головная повязка" }, + { 310, "До 310: Узловатая кожа" }, + { 320, "До 320: Перчатки дренейского дикаря" }, + { 325, "До 325: Утолщенные дренейские сапоги" }, + { 335, "До 335: Толстая узловатая кожа\n|cFFFFD700Не продовайте их, пожже они вам понадобятся" }, + { 340, "До 340: Утолщенная дренейская безрукавка" }, + { 350, "До 350: Скверночешуйчатая кираса" }, + { 375, "До 375: Накладки из борейской кожи" }, + { 385, "До 385: Арктические сапоги" }, + { 395, "До 395: Арктический пояс" }, + { 400, "До 400: Арктические накулачники" }, + { 405, "До 405: Нерубские накладки для поножей" }, + { 410, "До 410: Any Черный нагрудник или поножи" }, + { 425, "До 425: Любую Меховую подкладку\nСумки для профессий" }, + { 450, "До 450: Изготовте любую вещь для получения очка,\nв зависимости от ваших потребностей" } + }, + [BI["Engineering"]] = { + { 40, "До 40: Грубое взрывчатое вещество" }, + { 50, "До 50: Горсть медных винтов" }, + { 51, "Изготовьте один Тангенциальный вращатель" }, + { 65, "До 65: Медные трубы" }, + { 75, "До 75: Грубый огнестрел" }, + { 95, "До 95: Низкосортное взрывчатое вещество" }, + { 105, "До 105: Серебряные контакты" }, + { 120, "До 120: Бронзовые трубкы" }, + { 125, "До 125: Небольшие бронзовые бомбы" }, + { 145, "До 145: Тяжелое взрывчатое вещество" }, + { 150, "До 150: Большие бронзовые бомбы" }, + { 175, "До 175: Синие, Зеленые или Красные петарды" }, + { 176, "Изготовьте один Шлицевой гироинструмент" }, + { 190, "До 190: Твердое взрывчатое вещество" }, + { 195, "До 195: Большие железные бомбы" }, + { 205, "До 205: Мифриловые трубы" }, + { 210, "До 210: Нестабильные пусковые устройства" }, + { 225, "До 225: Бронебойные мифриловые пули" }, + { 235, "До 235: Мифриловую обшивку" }, + { 245, "До 245: Фугасные бомбы" }, + { 250, "До 250: Мифриловый гиро-патрон" }, + { 260, "До 260: Концентрированное взрывчатое вещество" }, + { 290, "До 290: Ториевое устройство" }, + { 300, "До 300: Ториевые трубы\nили Ториевые патроны (дешевле)" }, + { 310, "До 310: Обшивка из оскверненного железа,\nГорсть винтов из оскверненного железа,\n и Взрывчатое вещество стихий\n|cFFFFD700Не продовайте их, пожже они вам понадобятся|r" }, + { 320, "До 320: Бомбы из оскверненного железа" }, + { 335, "До 335: Мушкеты из оскверненного железа" }, + { 350, "До 350: Белые дымовые сигнальные ракеты" }, + { 375, "До 375: Кобальтовые осколочные бомбы" }, + { 430, "До 430: Детали для набора лечебных(маны) инъекций\nВы будете в них нуждается долгое время" }, + { 435, "До 435: Детали для набора инъекций маны" }, + { 450, "До 450: Изготовьте любую вещь для получения очка,\nв зависимости от ваших потребностей" } + }, + [BI["Jewelcrafting"]] = { + { 20, "До 20: Delicate Copper Wire" }, + { 30, "До 30: Rough Stone Statue" }, + { 50, "До 50: Tigerseye Band" }, + { 75, "До 75: Bronze Setting" }, + { 80, "До 80: Solid Bronze Ring" }, + { 90, "До 90: Elegant Silver Ring" }, + { 110, "До 110: Ring of Silver Might" }, + { 120, "До 120: Heavy Stone Statue" }, + { 150, "До 150: Pendant of the Agate Shield\nor Golden Dragon Ring" }, + { 180, "До 180: Mithril Filigree" }, + { 200, "До 200: Engraved Truesilver Ring" }, + { 210, "До 210: Citrine Ring of Rapid Healing" }, + { 225, "До 225: Aquamarine Signet" }, + { 250, "До 250: Thorium Setting" }, + { 255, "До 255: Red Ring of Destruction" }, + { 265, "До 265: Truesilver Healing Ring" }, + { 275, "До 275: Simple Opal Ring" }, + { 285, "До 285: Sapphire Signet" }, + { 290, "До 290: Diamond Focus Ring" }, + { 300, "До 300: Emerald Lion Ring" }, + { 310, "До 310: Any green quality gem" }, + { 315, "До 315: Fel Iron Blood Ring\nor any green quality gem" }, + { 320, "До 320: Any green quality gem" }, + { 325, "До 325: Azure Moonstone Ring" }, + { 335, "До 335: Mercurial Adamantite (required later)\nor any green quality gem" }, + { 350, "До 350: Heavy Adamantite Ring" }, + { 355, "До 355: Any blue quality gem" }, + { 360, "До 360: World drop recipes like:\nLiving Ruby Pendant\nor Thick Felsteel Necklace" }, + { 365, "До 365: Ring of Arcane Shielding\nThe Sha'tar - Уважение" }, + { 375, "До 375: Transmute diamonds\nWorld drops (blue quality)\nПочтение с Sha'tar, Honor Hold, Thrallmar" } + }, + [BI["Enchanting"]] = { + { 2, "До 2: Рунический медный жезл" }, + { 75, "До 75: Чары для наручей - здоровье I" }, + { 85, "До 85: Чары для наручей - отражение I" }, + { 100, "До 100: Чары для наручей - выносливость I" }, + { 101, "Изготовьте один Рунический серебряный жезл" }, + { 105, "До 105: Чары для наручей - выносливость I" }, + { 120, "До 120: Большой магический жезл" }, + { 130, "До 130: Чары для щита - выносливость I" }, + { 150, "До 150: Чары для наручей - выносливость II" }, + { 151, "Изготовьте один Рунический золотой жезл" }, + { 160, "До 160: Чары для наручей - выносливость II" }, + { 165, "До 165: Чары для щита - выносливость II" }, + { 180, "До 180: Чары для наручей - дух III" }, + { 200, "До 200: Чары для наручей - сила III" }, + { 201, "Изготовьте один Рунический жезл истинного серебра" }, + { 205, "До 205: Чары для наручей - сила III" }, + { 225, "До 225: Чары для плаща - защита II" }, + { 235, "До 235: Чары для перчаток - ловкость I" }, + { 245, "До 245: Чары для нагрудника - здоровье V" }, + { 250, "До 250: Чары для наручей - сила IV" }, + { 270, "До 270: Простое масло маны\nРецепт продается в Силитусе" }, + { 290, "До 290: Чары для щита - выносливость IV\nили Чары для обуви - выносливость IV" }, + { 291, "Изготовьте один Рунический арканитовый жезл" }, + { 300, "До 300: Чары для плаща - защита III" }, + { 301, "Изготовьте один Рунический жезл из оскверненного железа" }, + { 305, "До 305: Чары для плаща - защита III" }, + { 315, "До 315: Чары для наручей - штурм II" }, + { 325, "До 325: Чары для плаща - броня III\nили Чары для перчаток - штурм I" }, + { 335, "До 335: Чары для нагрудника - дух" }, + { 340, "До 340: Чары для щита - выносливость V" }, + { 345, "До 345: Превосходное волшебное масло\nИзготавливайте до 350, если у вас есть достаточно матерьяла" }, + { 350, "До 350: Чары для перчаток - сила III" }, + { 351, "Изготовьте один Рунический адамантитовый жезл" }, + { 360, "До 360: Чары для перчаток - сила III" }, + { 370, "До 370: Чары для перчаток - точные удары\nТребуется Почтение с Кенарийской экспедицией" }, + { 375, "До 375: Чары для кольца - целительная сила\nТребуется Почтение с Ша'таром" } + }, + [BI["Blacksmithing"]] = { + { 25, "До 25: Rough Sharpening Stones" }, + { 45, "До 45: Rough Grinding Stones" }, + { 75, "До 75: Copper Chain Belt" }, + { 80, "До 80: Coarse Grinding Stones" }, + { 100, "До 100: Runed Copper Belt" }, + { 105, "До 105: Silver Rod" }, + { 125, "До 125: Rough Bronze Leggings" }, + { 150, "До 150: Heavy Grinding Stone" }, + { 155, "До 155: Golden Rod" }, + { 165, "До 165: Green Iron Leggings" }, + { 185, "До 185: Green Iron Bracers" }, + { 200, "До 200: Golden Scale Bracers" }, + { 210, "До 210: Solid Grinding Stone" }, + { 215, "До 215: Golden Scale Bracers" }, + { 235, "До 235: Steel Plate Helm\nor Mithril Scale Bracers (cheaper)\nRecipe in Aerie Peak (A) or Stonard (H)" }, + { 250, "До 250: Mithril Coif\nor Mothril Spurs (cheaper)" }, + { 260, "До 260: Dense Sharpening Stones" }, + { 270, "До 270: Thorium Belt or Bracers (cheaper)\nEarthforged Leggings (Armorsmith)\nLight Earthforged Blade (Swordsmith)\nLight Emberforged Hammer (Hammersmith)\nLight Skyforged Axe (Axesmith)" }, + { 295, "До 295: Imperial Plate Bracers" }, + { 300, "До 300: Imperial Plate Boots" }, + { 305, "До 305: Fel Weightstone" }, + { 320, "До 320: Fel Iron Plate Belt" }, + { 325, "До 325: Fel Iron Plate Boots" }, + { 330, "До 330: Lesser Rune of Warding" }, + { 335, "До 335: Fel Iron Breastplate" }, + { 340, "До 340: Adamantite Cleaver\nSold in Shattrah, Silvermoon, Exodar" }, + { 345, "До 345: Lesser Rune of Shielding\nSold in Wildhammer Stronghold and Thrallmar" }, + { 350, "До 350: Adamantite Cleaver" }, + { 360, "До 360: Adamantite Weightstone\nRequires Cenarion Expedition - Уважение" }, + { 370, "До 370: Felsteel Gloves (Auchenai Crypts)\nFlamebane Gloves (Aldor - Уважение)\nEnchanted Adamantite Belt (Scryer - Дружелюбие)" }, + { 375, "До 375: Felsteel Gloves (Auchenai Crypts)\nFlamebane Breastplate (Aldor - Почтение)\nEnchanted Adamantite Belt (Scryer - Дружелюбие)" }, + { 385, "До 385: Cobalt Gauntlets" }, + { 393, "До 393: Spiked Cobalt Shoulders\nor Chestpiece" }, + { 395, "До 395: Spiked Cobalt Gauntlets" }, + { 400, "До 400: Spiked Cobalt Belt" }, + { 410, "До 410: Spiked Cobalt Bracers" }, + }, + [BI["Alchemy"]] = { + { 60, "До 60: Minor Healing Potion" }, + { 110, "До 110: Lesser Healing Potion" }, + { 140, "До 140: Healing Potion" }, + { 155, "До 155: Lesser Mana Potion" }, + { 185, "До 185: Greater Healing Potion" }, + { 210, "До 210: Elixir of Agility" }, + { 215, "До 215: Elixir of Greater Defense" }, + { 230, "До 230: Superior Healing Potion" }, + { 250, "До 250: Elixir of Detect Undead" }, + { 265, "До 265: Elixir of Greater Agility" }, + { 285, "До 285: Superior Mana Potion" }, + { 300, "До 300: Major Healing Potion" }, + { 315, "До 315: Volatile Healing Potion\nor Major Mana Potion" }, + { 350, "До 350: Mad Alchemists's Potion\nTurns yellow at 335, but cheap to make" }, + { 375, "До 375: Major Dreamless Sleep Potion\nSold in Allerian Stronghold (A)\nor Thunderlord Stronghold (H)" } + }, + [L["Mining"]] = { + { 65, "До 65: Mine Copper\nAvailable in all starting zones" }, + { 125, "До 125: Mine Tin, Silver, Incendicite and Lesser Bloodstone\n\nMine Incendicite at Thelgen Rock (Wetlands)\nEasy leveling up to 125" }, + { 175, "До 175: Mine Iron and Gold\nDesolace, Ashenvale, Badlands, Arathi Highlands,\nAlterac Mountains, Stranglethorn Vale, Swamp of Sorrows" }, + { 250, "До 250: Mine Mithril and Truesilver\nBlasted Lands, Searing Gorge, Badlands, The Hinterlands,\nWestern Plaguelands, Azshara, Winterspring, Felwood, Stonetalon Mountains, Tanaris" }, + { 300, "До 300: Mine Thorium \nUn’goro Crater, Azshara, Winterspring, Blasted Lands\nSearing Gorge, Burning Steppes, Eastern Plaguelands, Western Plaguelands" }, + { 330, "До 330: Mine Fel Iron\nHellfire Peninsula, Zangarmarsh" }, + { 375, "До 375: Mine Fel Iron and Adamantite\nTerrokar Forest, Nagrand\nBasically everywhere in Outland" } + }, + [L["Herbalism"]] = { + { 50, "До 50: Собираем Сребролист и Мироцвет\nДоступны в начальных зонах" }, + { 70, "До 70: Собираем Магороза и Земляной корень\nСтепи, Западный Край, Серебряный бор, Лок Модан" }, + { 100, "До 100: Собираем Остротерн\nСеребряный бор, Сумеречный лес, Темные берега,\nЛок Модан, Красногорье" }, + { 115, "До 115: Собираем Синячник\nЯсеневый лес, Когтистые горы, Южные степи\nЛок Модан, Красногорье" }, + { 125, "До 125: Собираем Дикий сталецвет\nКогтистые горы, Нагорье Арати, Тернистая долина\nЮжные степи, Тысяча Игл" }, + { 160, "До 160: Собираем Королевская кровь\nЯсеневый лес, Когтистые горы, Болотина,\nПредгорья Хилсбрада, Болото Печали" }, + { 185, "До 185: Собираем Бледнолист\nБолото Печали" }, + { 205, "До 205: Собираем Кадгаров ус\nВнутренние земли, Нагорье Арати, Болото Печали" }, + { 230, "До 230: Собираем Огнецвет\nТлеющее ущелье, Выжженные земли, Танарис" }, + { 250, "До 250: Собираем Солнечник\nОскверненный лес, Фералас, Азшара\nВнутренние земли" }, + { 270, "До 270: Собираем Кровь Грома\nОскверненный лес, Выжженные земли,\nMannoroc Coven in Пустоши" }, + { 285, "До 285: Собираем Снолист\nКратер Ун'Горо, Азшара" }, + { 300, "До 300: Собираем Чумоцвет\nВосточные и Западные Чумные земли, Оскверненный лес\nили Ледяной зев в Зимних Ключах" }, + { 330, "До 330: Собираем Сквернопля\nПолуостров Адского Пламени, Зангартопь" }, + { 375, "До 375: Все остальные цветы доступные в запределье\nВ основном в Зангартопе и в Лесу Тероккар" } + }, + [L["Skinning"]] = { + { 375, "До 375: Разделите ваш текущий уровень на 5,\nи снемайте шкуру с животных полученного уровня" } + }, + + -- source: http://www.elsprofessions.com/inscription/leveling.html + [L["Inscription"]] = { + { 18, "До 18: Ivory Ink" }, + { 35, "До 35: Scroll of Intellect, Spirit or Stamina" }, + { 50, "До 50: Moonglow Ink\nSave if for Minor Inscription Research" }, + { 75, "До 75: Scroll of Recall, Armor Vellum" }, + { 79, "До 79: Midnight Ink" }, + { 80, "До 80: Minor Inscription Research" }, + { 85, "До 85: Glyph of Backstab, Frost Nova\nRejuvenation, ..." }, + { 87, "До 87: Hunter's Ink" }, + { 90, "До 90: Glyph of Corruption, Flame Shock\nRapid Charge, Wrath" }, + { 100, "До 100: Glyph of Ice Armor, Maul\nSerpent Sting" }, + { 104, "До 104: Lion's Ink" }, + { 105, "До 105: Glyph of Arcane Shot, Arcane Explosion" }, + { 110, "До 110: Glyph of Eviscerate, Holy Light, Fade" }, + { 115, "До 115: Glyph of Fire Nova Totem\nHealth Funel, Rending" }, + { 120, "До 120: Glyph of Arcane Missiles, Healing Touch" }, + { 125, "До 125: Glyph of Expose Armor\nFlash Heal, Judgment" }, + { 130, "До 130: Dawnstar Ink" }, + { 135, "До 135: Glyph of Blink\nImmolation, Moonfire" }, + { 140, "До 140: Glyph of Lay on Hands\nGarrote, Inner Fire" }, + { 142, "До 142: Glyph of Sunder Armor\nImp, Lightning Bolt" }, + { 150, "До 150: Strange Tarot" }, + { 155, "До 155: Jadefire Ink" }, + { 160, "До 160: Scroll of Stamina III" }, + { 165, "До 165: Glyph of Gouge, Renew" }, + { 170, "До 170: Glyph of Shadow Bolt\nStrength of Earth Totem" }, + { 175, "До 175: Glyph of Overpower" }, + { 177, "До 177: Royal Ink" }, + { 183, "До 183: Scroll of Agility III" }, + { 185, "До 185: Glyph of Cleansing\nShadow Word: Pain" }, + { 190, "До 190: Glyph of Insect Swarm\nFrost Shock, Sap" }, + { 192, "До 192: Glyph of Revenge\nVoidwalker" }, + { 200, "До 200: Arcane Tarot" }, + { 204, "До 204: Celestial Ink" }, + { 210, "До 210: Armor Vellum II" }, + { 215, "До 215: Glyph of Smite, Sinister Strike" }, + { 220, "До 220: Glyph of Searing Pain\nHealing Stream Totem" }, + { 225, "До 225: Glyph of Starfire\nBarbaric Insults" }, + { 227, "До 227: Fiery Ink" }, + { 230, "До 230: Scroll of Agility IV" }, + { 235, "До 235: Glyph of Dispel Magic" }, + { 250, "До 250: Weapon Vellum II" }, + { 255, "До 255: Scroll of Stamina V" }, + { 260, "До 260: Scroll of Spirit V" }, + { 265, "До 265: Glyph of Freezing Trap, Shred" }, + { 270, "До 270: Glyph of Exorcism, Bone Shield" }, + { 275, "До 275: Glyph of Fear Ward, Frost Strike" }, + { 285, "До 285: Ink of the Sky" }, + { 295, "До 295: Glyph of Execution\nSprint, Death Grip" }, + { 300, "До 300: Scroll of Spirit VI" }, + { 304, "До 304: Ethereal Ink" }, + { 305, "До 305: Glyph of Plague Strike\nEarthliving Weapon, Flash of Light" }, + { 310, "До 310: Glyph of Feint" }, + { 315, "До 315: Glyph of Rake, Rune Tap" }, + { 320, "До 320: Glyph of Holy Nova, Rapid Fire" }, + { 325, "До 325: Glyph of Blood Strike, Sweeping Strikes" }, + { 327, "До 327: Darkflame Ink" }, + { 330, "До 330: Glyph of Mage Armor, Succubus" }, + { 335, "До 335: Glyph of Scourge Strike, Windfury Weapon" }, + { 340, "До 340: Glyph of Arcane Power, Seal of Command" }, + { 345, "До 345: Glyph of Ambush, Death Strike" }, + { 350, "До 350: Glyph of Whirlwind" }, + { 350, "До 350: Glyph of Mind Flay, Banish" }, + + { 450, "До 450: Not yet implemented" } + }, + + -- source: http://www.almostgaming.com/wowguides/world-of-warcraft-lockpicking-guide + [L["Lockpicking"]] = { + { 85, "До 85: Thieves Training\nAtler Mill, Redridge Moutains (A)\nShip near Ratchet (H)" }, + { 150, "До 150: Chest near the boss of the poison quest\nWestfall (A) or The Barrens (H)" }, + { 185, "До 185: Murloc camps (Wetlands)" }, + { 225, "До 225: Sar'Theris Strand (Desolace)\n" }, + { 250, "До 250: Angor Fortress (Badlands)" }, + { 275, "До 275: Slag Pit (Searing Gorge)" }, + { 300, "До 300: Lost Rigger Cove (Tanaris)\nBay of Storms (Azshara)" }, + { 325, "До 325: Feralfen Village (Zangarmarsh)" }, + { 350, "До 350: Kil'sorrow Fortress (Nagrand)\nPickpocket the Boulderfists in Nagrand" } + }, + + -- ** Secondary professions ** + [BI["First Aid"]] = { + { 40, "До 40: Linen Bandages" }, + { 80, "До 80: Heavy Linen Bandages\nBecome Journeyman at 50" }, + { 115, "До 115: Wool Bandages" }, + { 150, "До 150: Heavy Wool Bandages\nGet Expert First Aid book at 125\nBuy the 2 manuals in Stromguarde (A) or Brackenwall Village (H)" }, + { 180, "До 180: Silk Bandages" }, + { 210, "До 210: Heavy Silk Bandages" }, + { 240, "До 240: Mageweave Bandages\nFirst Aid quest at level 35\nTheramore Isle (A) or Hammerfall (H)" }, + { 260, "До 260: Heavy Mageweave Bandages" }, + { 290, "До 290: Runecloth Bandages" }, + { 330, "До 330: Heavy Runecloth Bandages\nBuy Master First Aid book\nTemple of Telhamat (A) or Falcon Watch (H)" }, + { 360, "До 360: Netherweave Bandages\nBuy the book in the Temple of Telhamat (A) or in Falcon Watch (H)" }, + { 375, "До 375: Heavy Netherweave Bandages\nBuy the book in the Temple of Telhamat (A) or in Falcon Watch (H)" } + }, + [BI["Cooking"]] = { + { 40, "До 40: Хлеб с пряностями" }, + { 85, "До 85: Копченая медвежатина, Пирожок с мясом краба" }, + { 100, "До 100: Cooked Crab Claw (A)\nDig Rat Stew (H)" }, + { 125, "До 125: Dig Rat Stew (H)\nSeasoned Wolf Kabob (A)" }, + { 175, "До 175: Curiously Tasty Omelet (A)\nHot Lion Chops (H)" }, + { 200, "До 200: Roast Raptor" }, + { 225, "До 225: Spider Sausage\n\n|cFFFFFFFFCooking quest:\n|cFFFFD70012 Giant Eggs,\n10 Zesty Clam Meat,\n20 Alterac Swiss " }, + { 275, "До 275: Monster Omelet\nor Tender Wolf Steaks" }, + { 285, "До 285: Runn Tum Tuber Surprise\nDire Maul (Pusillin)" }, + { 300, "До 300: Smoked Desert Dumplings\nQuest in Silithus" }, + { 325, "До 325: Ravager Dogs, Buzzard Bites" }, + { 350, "До 350: Roasted Clefthoof\nWarp Burger, Talbuk Steak" }, + { 375, "До 375: Crunchy Serpent\nMok'nathal Treats" } + }, + -- source: http://www.wowguideonline.com/fishing.html + [BI["Fishing"]] = { + { 50, "До 50: Любая начальная зона" }, + { 75, "До 75:\nВ каналах Штормграда\nВ прудах Оргриммара" }, + { 150, "До 150: В реке Предгорья Хилсбрада" }, + { 225, "До 225: Книга Рыболов-умелец продается в Пиратской бухте\nРыбачьте в Пустоши или Нагорьях Арати" }, + { 250, "До 250: Внутренние земли, Танарис\n\n|cFFFFFFFFРыболовное задание в Пылевых топях\n|cFFFFD700Синий плавник Гибельного берега (Тернистая долина)\nФералас-ахи (Река Вердантис, Фералас)\nУдарник Сартериса (Северное побережье Сар'Терис, Пустоши)\nМахи-махи с Тростникового берега (Береговая линия Болот Печали)" }, + { 260, "До 260: Оскверненный лес" }, + { 300, "До 300: Азшара" }, + { 330, "До 330: Рыбачьте на востоке Зангартопи\nКнига Рыболов-мастер у Кенарийской экспедиция" }, + { 345, "До 345: Рыбачьте на западе Зангартопи" }, + { 360, "До 360: Лес Тероккар" }, + { 375, "До 375: Лесу Тероккар, в Скеттисе\nНужено летающее верховое животное" } + }, + + -- suggested leveling zones, compiled by Thaoky, based on too many sources to list + my own leveling experience on Alliance side + ["Leveling"] = { + { 10, "До 10: Любая начальная зона" }, + { 20, "До 20: " .. BZ["Loch Modan"] .. "\n" .. BZ["Westfall"] .. "\n" .. BZ["Darkshore"] .. "\n" .. BZ["Bloodmyst Isle"] + .. "\n" .. BZ["Silverpine Forest"] .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Ghostlands"]}, + { 25, "До 25: " .. BZ["Wetlands"] .. "\n" .. BZ["Redridge Mountains"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Hillsbrad Foothills"] }, + { 28, "До 28: " .. BZ["Duskwood"] .. "\n" .. BZ["Wetlands"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Thousand Needles"] }, + { 31, "До 31: " .. BZ["Duskwood"] .. "\n" .. BZ["Thousand Needles"] .. "\n" .. BZ["Ashenvale"] }, + { 35, "До 35: " .. BZ["Thousand Needles"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Alterac Mountains"] + .. "\n" .. BZ["Arathi Highlands"] .. "\n" .. BZ["Desolace"] }, + { 40, "До 40: " .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Desolace"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 43, "До 43: " .. BZ["Tanaris"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 45, "До 45: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] }, + { 48, "До 48: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] .. "\n" .. BZ["Searing Gorge"] }, + { 51, "До 51: " .. BZ["Tanaris"] .. "\n" .. BZ["Azshara"] .. "\n" .. BZ["Blasted Lands"] + .. "\n" .. BZ["Searing Gorge"] .. "\n" .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] }, + { 55, "До 55: " .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] .. "\n" .. BZ["Burning Steppes"] + .. "\n" .. BZ["Blasted Lands"] .. "\n" .. BZ["Western Plaguelands"] }, + { 58, "До 58: " .. BZ["Winterspring"] .. "\n" .. BZ["Burning Steppes"] .. "\n" .. BZ["Western Plaguelands"] + .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 60, "До 60: " .. BZ["Winterspring"] .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 62, "До 62: " .. BZ["Hellfire Peninsula"] }, + { 64, "До 64: " .. BZ["Zangarmarsh"] .. "\n" .. BZ["Terokkar Forest"]}, + { 65, "До 65: " .. BZ["Terokkar Forest"] }, + { 66, "До 66: " .. BZ["Terokkar Forest"] .. "\n" .. BZ["Nagrand"]}, + { 67, "До 67: " .. BZ["Nagrand"]}, + { 68, "До 68: " .. BZ["Blade's Edge Mountains"]}, + { 70, "До 70: " .. BZ["Blade's Edge Mountains"] .. "\n" .. BZ["Netherstorm"] .. "\n" .. BZ["Shadowmoon Valley"]}, + { 72, "До 72: " .. BZ["Howling Fjord"] .. "\n" .. BZ["Borean Tundra"]}, + { 74, "До 74: " .. BZ["Grizzly Hills"] .. "\n" .. BZ["Dragonblight"]}, + { 76, "До 76: " .. BZ["Dragonblight"] .. "\n" .. BZ["Zul'Drak"]}, + { 78, "До 78: " .. BZ["Zul'Drak"] .. "\n" .. BZ["Sholazar Basin"]}, + { 80, "До 80: " .. BZ["The Storm Peaks"] .. "\n" .. BZ["Icecrown"]}, + }, + + -- Reputation levels + -- -42000 = "Hated" + -- -6000 = "Hostile" + -- -3000 = "Unfriendly" + -- 0 = "Neutral" + -- 3000 = "Friendly" + -- 9000 = "Honored" + -- 21000 = "Revered" + -- 42000 = "Exalted" + + -- Outland factions: source: http://www.mmo-champion.com/ + [BF["The Aldor"]] = { + { 0, "До Равнодушия:\n" .. WHITE .. "[Ядовитая железа Смертеплета]|r +250 реп\n\n" + .. YELLOW .. "Жуткопалый скрытень,\nЖуткопалая черная вдова\n" + .. WHITE .. "(Лес Тероккар)" }, + { 9000, "До Уважения:\n" .. WHITE .. "[Знак Кил'джедена]|r\n+25 реп" }, + { 42000, "До Превознесения:\n" .. WHITE .. "[Знак Саргераса]|r +25 реп за знак\n" + .. GREEN .. "[Латные перчатки Скверны]|r +350 реп (+1 Святая пыль)" } + }, + [BF["The Scryers"]] = { + { 0, "До Равнодушия:\n" .. WHITE .. "[Глаз гладкоспинного василиска]|r +250 реп\n\n" + .. YELLOW .. "Стальноспинный окаменитель,\nВлажночешуйчатый пожиратель,\nГладкоспинный василиск\n" + .. WHITE .. "(Лес Тероккар)" }, + { 9000, "До Уважения:\n" .. WHITE .. "[Перстень Огнекрылов]|r\n+25 реп" }, + { 42000, "До Превознесения:\n" .. WHITE .. "[Перстень Ярости Солнца]|r +25 реп за перстень\n" + .. GREEN .. "[Чародейский фолиант]|r +350 реп (+1 Чародейская руна)" } + }, + [BF["Netherwing"]] = { + { 3000, "До Дружелюбие, повторяйте слудующие задания:\n\n" + .. YELLOW .. "Медленная смерть (Ежедневный)|r 250 реп\n" + .. YELLOW.. "Пыльца хаотического пыльника (Ежедневный)|r 250 реп\n" + .. YELLOW.. "Кристаллы Крыльев Пустоты (Ежедневный)|r 250 реп\n" + .. YELLOW.. "Недружелюбные небеса (Ежедневный)|r 250 реп\n" + .. YELLOW.. "Большая Охота (Повторяемый)|r 250 реп" }, + { 9000, "До Уважения, повторяйте слудующие задания:\n\n" + .. YELLOW .. "Ты – инспектор: как делать все правильно|r 350 реп\n" + .. YELLOW .. "Ботиранг: Лекарство для ... (Ежедневный)|r 350 реп\n" + .. YELLOW .. "Собрать по кусочкам... (Ежедневный)|r 350 реп\n" + .. YELLOW .. "Драконы – это не самое страшное (Ежедневный)|r 350 реп\n" + .. YELLOW .. "Спятившие и очень опасные...|r 350 реп\n" }, + { 21000, "До Почтения, повторяйте слудующие задания:\n\n" + .. YELLOW .. "Покорить Покорителя|r 500 реп\n" + .. YELLOW .. "Разрушение Сумеречного Портала (Ежедневный)|r 500 реп\n" + .. YELLOW .. "Race quests 500 each for first 5, 1000 for 6th\n" }, + { 42000, "До Превознесения, повторяйте слудующие задания:\n\n" + .. YELLOW .. "Самая Опасная Ловушка (Ежедневный) (группа на 3)|r 500 реп" } + }, + [BF["Honor Hold"]] = { + { 9000, "До Уважения:\n\n" + .. YELLOW .. "Задания на Полуострове Адского Пламени\n" + .. GREEN .. "Бастионы Адского Пламени |r(Обычный)\n" + .. GREEN .. "Кузня Крови |r(Обычный)" }, + { 42000, "До Превознесения:\n\n" + .. GREEN .. "Разрушенные залы |r(Обычный & Героический)\n" + .. GREEN .. "Бастионы Адского Пламени |r(Героический)\n" + .. GREEN .. "Кузня Крови |r(Героический)" } + }, + [BF["Thrallmar"]] = { + { 9000, "До Уважения:\n\n" + .. YELLOW .. "Задания на Полуострове Адского Пламени\n" + .. GREEN .. "Бастионы Адского Пламени |r(Обычный)\n" + .. GREEN .. "Кузня Крови |r(Обычный)" }, + { 42000, "До Превознесения:\n\n" + .. GREEN .. "Разрушенные залы |r(Обычный & Героический)\n" + .. GREEN .. "Бастионы Адского Пламени |r(Героический)\n" + .. GREEN .. "Кузня Крови |r(Героический)" } + }, + [BF["Cenarion Expedition"]] = { + { 3000, "До Дружелюбия:\n\n" + .. WHITE .. "Наги из клана Темного Гребня и Кровавой Чешуи (+5 реп)\n" + .. YELLOW .. "Задания в Зангартопе\n" + .. "|rПройдите любое подземелье " .. GREEN .. "Резервуара|r\n\n" + .. WHITE .. "Храните [Неопознанные части растений] на потом" }, + { 9000, "До Уважения:\n\n" + .. WHITE .. "Сдайте [Неопознанные части растений] x240\n" + .. YELLOW .. "Задания в Зангартопе\n" + .. "|rПройдите любое подземелье " .. GREEN .. "Резервуара|r" }, + { 42000, "До Превознесения:\n\n" + .. WHITE .. "Сдавайте [Оружие Змеиного Зуба] +75 реп\n\n" + .. GREEN .. "Паровое подземелье |r(Обычное)\n" + .. GREEN .. "Любое подземелье Резервуара |r(Героическое)" } + }, + [BF["Keepers of Time"]] = { + { 42000, "До Превознесения:\n\n" + .. "|rПройдите " .. GREEN .. "Старые предгорья Хилсбрада|r и " .. GREEN .. "Черные топи|r\n\n" + .. YELLOW .. "Храните задания на потом:\nЦепь заданий в Старые предгорья Хилсбрада = 5000 реп\nв Черные топи = 8000 реп" } + }, + [BF["The Sha'tar"]] = { + { 42000, "До Превознесения:\n\n" + .. GREEN .. "Ботаника |r(Обычный & Героический)\n" + .. GREEN .. "Механар |r(Обычный & Героический)\n" + .. GREEN .. "Аркатрац |r(Обычный & Героический)\n" } + }, + [BF["Lower City"]] = { + { 9000, "До Уважения:\n\n" + .. WHITE .. "Сдавайте [Перо араккоа] x30 (+250 реп)\n" + .. GREEN .. "Темный лабиринт |r(Обычный)\n" + .. GREEN .. "Аукенайские гробницы |r(Обычный)\n" + .. GREEN .. "Сетеккские залы |r(Обычный)" }, + { 42000, "До Превознесения:\n\n" + .. GREEN .. "Темный лабиринт |r(Обычный & Героический)\n" + .. GREEN .. "Аукенайские гробницы |r(Героический)\n" + .. GREEN .. "Сетеккские залы |r(Героический)" } + }, + [BF["The Consortium"]] = { + { 3000, "До Дружелюбия:\n\n" + .. "|rСдавайте [Осколок кристалла Ошу'гуна] +250 реп\n" + .. "Сдавайте [Пара бивней] +250 реп\n\n" + .. GREEN .. "Гробницы Маны |r(Обычный)" }, + { 9000, "До Уважения:\n\n" + .. "|rСдавайте [Обсидиановые боевые бусы] +250 реп\n\n" + .. GREEN .. "Гробницы Маны |r(Обычный)" }, + { 42000, "До Превознесения:\n\n" + .. "|rСдавайте [Знак отличия братства Заксис] +250 реп\n" + .. "|rСдавайте [Обсидиановые боевые бусы] +250 реп\n\n" + .. GREEN .. "Гробницы Маны |r(Героический)" } + } + + -- Northrend factions +} diff --git a/Altoholic-Addon/Altoholic/Suggestions_zhCN.lua b/Altoholic-Addon/Altoholic/Suggestions_zhCN.lua new file mode 100644 index 0000000..4c68b3f --- /dev/null +++ b/Altoholic-Addon/Altoholic/Suggestions_zhCN.lua @@ -0,0 +1,535 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() +local BF = LibStub("LibBabble-Faction-3.0"):GetLookupTable() + +if GetLocale() ~= "zhCN" then return end + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +-- 以下为声望值、等级、技能等的建议 +addon.Suggestions = { + [L["Riding"]] = { + { 75, "初级骑术(20级): |cFFFFFFFF4g\n|cFFFFD700主城附近的的普通坐骑:|cFFFFFFFF1g" }, + { 150, "中级骑术(40级): |cFFFFFFFF50g\n|cFFFFD700主城附近的史诗级坐骑:|cFFFFFFFF10g" }, + { 225, "高级骑术(60级): |cFFFFFFFF600g\n|cFFFFD700影月谷附近的普通飞行坐骑:|cFFFFFFFF50g" }, + { 300, "专家级骑乘(70级): |cFFFFFFFF5000g\n|cFFFFD700影月谷附近的史诗级飞行坐骑:|cFFFFFFFF200g" } + }, + + -- 来源 : http://forums.worldofwarcraft.com/thread.html?topicId=102789457&sid=1(英文) + -- ** 主专业技能 ** + [BI["Tailoring"]] = { + { 50, "1~50: 亚麻布卷\n(2×亚麻布)×80" }, + { 70, "51~70: 亚麻包\n(3×亚麻布卷|3×粗线)×20" }, + { 75, "71~75: 强化亚麻斗篷\n(2×亚麻布卷|3×粗线)×5" }, + { 105, "76~105: 毛布卷\n(3×毛料)×60" }, + { 110, "106~110: 灰色毛纺衬衣\n(2×毛布卷|1×细线|1×灰色染料)×5"}, + { 125, "111~125: 双线毛纺护肩\n(3×毛布卷|2×细线)×15" }, + { 145, "126~145: 丝绸卷\n(4×丝绸)×190" }, + { 160, "146~160: 碧蓝丝质头巾\n(2×丝绸卷|2×蓝色染料|1×细线)×15" }, + { 170, "161~170: 丝质头带\n(3×丝绸卷|2×细线)×10" }, + { 175, "171~175: 体面的白衬衣\n(3×丝绸卷|2×漂白液|1×细线)×5" }, + { 185, "176~185: 魔纹布卷\n(5×魔纹布)×100" }, + { 205, "186~205: 深红丝质外衣\n(4×丝绸卷|2×红色染料|2×细线)×15" }, + { 215, "206~215: 深红丝质马裤(4×丝绸卷|2×红色染料|2×丝线)×15" }, + { 220, "216~220: 黑色魔纹短裤\n黑色魔纹外衣\n(2×魔纹布卷|3×丝线)×5" }, + { 230, "221~230: 黑色魔纹手套\n(2×魔纹布卷|2×粗丝线)×10" }, + { 250, "231~250: 黑色魔纹头带\n黑色魔纹护肩\n(3×魔纹布卷|2×粗丝线)×20" }, + { 260, "251~260: 符文布卷\n(5×符文布)×180" }, + { 275, "261~275: 符文布腰带\n(3×符文布卷|1×符文线)×15" }, + { 280, "276~280: 符文布背包\n(5×符文布卷|2×硬甲皮|1×符文线)×5" }, + { 300, "281~300: 符文布手套\n(4×符文布卷|4×硬甲皮|1×符文线)×20" }, + { 325, "301~325: 灵纹布卷\n(6×灵纹布)×25\n|cFFFFD700千万别卖掉,你用来继续升级的!" }, + { 340, "326~340: 魔化灵纹布卷\n(3×灵纹布卷|2×奥法之尘)×15\n|cFFFFD700千万别卖掉,你用来继续升级的!" }, + { 350, "341~350: 灵纹长靴\n(6×灵纹布卷|2×结缔皮|1×符文线)×10\n|cFFFFD700可分解为奥法之尘。" }, + { 360, "351~360: 灵纹外套\n(8×灵纹布卷|2×符文线)×10\n|cFFFFD700可分解为奥法之尘。" }, + { 375, "361~375: 魔化灵纹外套\n(6×魔化灵纹布卷|2×灵网蜘蛛丝|1×符文线)×15\n期间可以选择分支并作专业套装。" } + }, + [BI["Leatherworking"]] = { + { 35, "1~35: 轻型护甲片\n(1×轻皮)×35" }, + { 55, "36~55: 熟化轻毛皮\n(1×轻毛皮|1×盐)×20" }, + { 80, "56~80: 雕花皮靴\n(8×轻皮|5×粗线)×15" }, + { 85, "81~85: 优质皮带\n(6×轻皮|2×粗线)×5" }, + { 90, "86~90: 优质皮外套\n(3×熟化轻毛皮|6×轻皮|4×粗线)×5" }, + { 100, "91~100: 优质皮带\n(6×轻皮|2×粗线)×10" }, + { 120, "101~120: 熟化中毛皮\n(1×中毛皮|1×盐)×20" }, + { 125, "121~125: 优质皮带\n(6×轻皮|2×粗线)×5" }, + { 150, "126~150: 黑皮腰带\n(1×优质皮带|1×熟化中毛皮|2×细线|1×灰色染料)×25" }, + { 160, "151~160: 熟化重毛皮\n(1×重毛皮|3×盐)×10" }, + { 170, "161~170: 重型护甲片\n(5×重皮|1×细线)×10" }, + { 180, "171~180: 暗色皮护腿\n(10×重皮|1×黑色染料|2×细线)×10\n守护短裤\n(12×重皮|2×丝绸卷|2×细线)×10" }, + { 195, "181~195: 野人护肩\n(8×重皮|1×熟化重毛皮|2×细线)×15" }, + { 205, "196~205: 暗色护腕\n(16×重皮|1×黑色染料|2×丝线)×10" }, + { 220, "206~220: 厚重护甲片\n(5×厚皮|1×丝线)×15" }, + { 225, "221~225: 夜色头带\n(5×厚皮|2×丝线)×5" }, + { 250, "226~250: 根据你的专精可以为:\n 元素制皮:\n夜色头带\n(5×厚皮|2×丝线)×25\n夜色外套\n(7×厚皮|2×丝线)×25\n夜色短裤(14×厚皮|4×丝线)×20\n 龙鳞制皮:\n硬化蝎壳胸甲(12×厚皮|12×蝎壳|4×丝线)×25\n硬化蝎壳手套(6×厚皮|8×蝎壳|2×丝线)×25\n部族制皮: \n龟壳头盔(14×厚皮|24×龟壳|1×粗丝线)×20\n龟壳护腿(14×厚皮|28×龟壳|1×粗丝线)×15\n龟壳胸甲(6×厚皮|12×龟壳|1×粗丝线)×25\n龟壳手套(6×厚皮|8×龟壳|1×粗丝线)×25\n龟壳护腕(8×厚皮|12×龟壳|1×粗丝线)×25\n" }, + { 260, "251~260: 夜色长靴\n(16×厚皮|2×粗丝线)×10" }, + { 270, "261~270: 邪恶皮甲护手\n(8×硬甲皮|1×黑色染料|1×符文线)×10" }, + { 285, "271~285: 邪恶皮甲护腕\n(8×硬甲皮|1×黑色染料|1×符文线)×10" }, + { 300, "286~300: 邪恶皮甲头环\n(12×硬甲皮|1×黑色染料|1×符文线)×15" }, + { 310, "301~310: 结缔皮\n(5×结缔皮碎片)×10" }, + { 320, "311~320: 野性德莱尼手套\n(9×结缔皮|3×符文线)×10" }, + { 325, "3212~325: 厚重德莱尼长靴\n(10×结缔皮|3×符文线)×5" }, + { 335, "326~335: 重结缔皮\n(5×结缔皮)×10\n|cFFFFD700千万别卖掉,你用来继续升级的!" }, + { 340, "336~340: 厚重德莱尼外套\n(14×结缔皮|3×符文线)×5" }, + { 355, "341~355: 魔鳞胸甲\n(14×结缔皮|3×魔鳞|3×符文线)×15" }, + { 365, "356~365: 厚重裂蹄长靴\n(4×重结缔皮|20×厚裂蹄牛皮|4×源生之土|2×符文线)×10\n配方购于:\n芬德雷·迅矛:赞加沼泽<79,63>\n|cFFFFD700需要塞纳里奥远征队 - 友善\n|cFFFFD700厚裂蹄牛皮在纳格兰获取" }, + { 375, "366~375: 战斗之鼓\n(6×重结缔皮|4×厚裂蹄牛皮)×10\n配方购于:\n奥玛多尔:沙塔斯城<51,41>\n|cFFFFD700需要沙塔尔 - 尊敬" } + }, + [BI["Engineering"]] = { + { 40, "1~40: 劣质火药\n(1×劣质的石头)×40" }, + { 50, "41~50: 一把螺栓\n(1×铜锭)×10" }, + { 51, "51: 扳手\n(6×铜锭)×1" }, + { 65, "52~65: 铜管\n(2×铜锭|1×弱效助熔剂)×14" }, + { 75, "66~75: 劣质火枪\n(1×铜管|1×一把螺栓|1×木柴)×10" }, + { 95, "76~95: 粗制火药粉\n(1×粗糙的石头)×20" }, + { 105, "96~105: 银触媒\n(1×银锭)×10" }, + { 120, "106~120: 青铜管\n(2×青铜锭|1×弱效助熔剂)×15" }, + { 125, "121~125: 小型青铜炸弹\n(4×粗制火药粉|2×青铜锭|1×银触媒|1×毛料)×5" }, + { 145, "126~145: 烈性火药\n(1×沉重的石头)×20" }, + { 150, "146~150: 重磅青铜炸弹\n(2×烈性火药|3×青铜锭|1×银触媒)×5" }, + { 175, "151~175: 蓝色焰火|红色焰火|绿色焰火\n(1×烈性火药|1×重皮)×25" }, + { 176, "176: 侏儒微调器\n(4×钢锭)×1" }, + { 190, "177~190: 实心炸药\n(2×坚固的石头)×14" }, + { 195, "191~195: 重磅铁制炸弹\n(3×烈性火药|3×铁锭|1×银触媒)×5" }, + { 205, "196~205: 秘银管\n(3×秘银锭)×10" }, + { 210, "206~210: 不牢固的扳机\n(1×秘银锭|1×魔纹布|1×实心炸药)×5" }, + { 225, "211~225: 高速秘银弹头\n(1×秘银锭|1×实心炸药)×15" }, + { 235, "226~235: 秘银外壳\n(3×秘银锭)×10" }, + { 245, "236~245: 高爆炸弹\n(2×秘银外壳|1×不牢固的扳机|2×实心炸药)×10" }, + { 250, "246~250: 秘银螺旋弹\n(2×秘银锭|2×实心炸药)×5" }, + { 260, "251~260: 致密炸药粉\n(2×厚重的石头)×10" }, + { 290, "261~290: 瑟银零件\n(3×瑟银锭|1×符文布)×30" }, + { 300, "291~300: 瑟银管\n(3×瑟银锭)×10\n瑟银弹\n(2×瑟银锭|1×致密炸药粉)×10" }, + { 310, "301~310: 魔铁外壳\n(3×魔铁锭)×10\n魔铁螺丝\n(1×魔铁锭)×10\n元素炸药粉\n(1×火焰微粒|2×土之微粒)×10\n保留这些东西,为了下一步使用!" }, + { 320, "311~320: 魔铁炸弹\n(1×魔铁外壳|2×魔铁螺丝|1×元素炸药粉)×10" }, + { 335, "321~335: 魔铁步枪\n(1×沉重的树干|3×魔铁外壳|6×魔铁螺丝)×15" }, + { 350, "336~350: 白色烟幕弹\n(1×元素炸药粉|1×灵纹布)×15" }, + { 360, "351~360: 氪金能量核心\n(3×氪金锭|1×源生火焰)×10\n最好做20个,下一步要用到" }, + { 375, "361~375: 战地修理机器人110G\n(8×精金锭|8×魔铁螺丝|1×氪金能量核心)×15\n掉落:甘尔葛分析师 刀锋山" } + }, + [BI["Jewelcrafting"]] = { + { 20, "1~20: 精巧的铜线\n(2×铜锭)×20" }, + { 30, "21~30: 劣质石像\n(8×劣质的石头)×10" }, + { 50, "31~50: 虎眼指环\n(1×虎眼石|1×精巧的铜线)×20" }, + { 75, "51~75: 青铜底座\n(2×青铜锭)×25" }, + { 80, "76~80: 结实的青铜戒指\n(4×青铜锭)×5" }, + { 90, "81~90: 优雅的银戒指\n(1×银锭)×10" }, + { 110, "91~110: 银色力量之戒\n(2×银锭)×20" }, + { 120, "111~120: 沉重石像\n(8×沉重的石头)×10" }, + { 150, "121~150: 玛瑙护盾坠饰\n(1×绿玛瑙|1×青铜底座)×30\n金色巨龙戒指\n(1×翡翠|2×金锭|2×精巧的铜线)×30" }, + { 180, "151~180: 秘银丝\n(2×秘银锭)×30" }, + { 200, "181~200: 蚀刻真银戒指\n(1×真银锭|2×秘银丝)×20" }, + { 210, "201~210: 迅疾治疗之黄水晶戒指\n(1×黄水晶|2×元素之水|2×秘银锭)×10" }, + { 225, "211~225: 青绿石徽记\n(3×青绿石|4×魔精)×15" }, + { 250, "226~250: 瑟银底座\n(1×瑟银锭)×25" }, + { 255, "251~255: 红色毁灭指环\n(1×红宝石|1×瑟银底座)×5" }, + { 265, "256~265: 真银治疗戒指\n(2×真银锭|2×野性之心)×10" }, + { 275, "266~275: 朴素的猫眼石戒指\n(1×大猫眼石|1×瑟银底座)×10" }, + { 285, "276~285: 蓝宝石徽记\n(4×蓝宝石|2×真银锭|1×瑟银底座)×10" }, + { 290, "286~290: 钻石专注戒指\n(1×艾泽拉斯钻石|1×瑟银底座)×5" }, + { 300, "291~300: 翡翠狮王戒指\n(2×巨型绿宝石|1×瑟银底座)×10" }, + { 310, "301~310: 任何优秀品质的宝石(绿色)×10" }, + { 315, "311~315: 魔铁血戒\n(1×魔铁锭|2×血榴石)×5\n任何优秀品质的宝石(绿色)×5" }, + { 320, "316~320: 任何优秀品质的宝石(绿色)×10" }, + { 325, "321~325: 碧月石指环\n(1×魔铁锭|2×碧月石|1×翠榄石)×5" }, + { 335, "326~335: 水银精金(升级用到)\n(4×精金粉|1×源生之土)×10\n任何优秀品质的宝石(绿色)×10" }, + { 350, "336~350: 重型精金戒指\n(1×精金锭|1×水银精金)×15" }, + { 355, "351~355: 任何精良品质的宝石(蓝色)×5" }, + { 360, "356~360: 世界掉落配方,例如:\n红曜石坠饰\n(4×氪金锭|1×水银精金|1×红曜石)×5\n厚重魔钢项链\n(2×魔钢锭|3×水银精金)×5" }, + { 365, "361~365: 奥术护盾指环\n(2×恒金锭|8×源生法力)×5\n配方购于:\n奥玛多尔:沙塔斯城<51,41>\n|cFFFFD700需要沙塔尔 - 尊敬" }, + { 375, "366~375: 大地风暴钻石或天火钻石系列\n世界掉落(精良品质)\n部分可购买,需要沙塔尔/萨尔玛/荣耀堡/破碎残阳 - 崇敬" } + }, + [BI["Enchanting"]] = { + { 2, "1~2: 符文铜棒\n(1×铜棒|1×奇异之尘|1×次级魔法精华)×1" }, + { 75, "3~75: 附魔护腕 - 初级生命\n(1×奇异之尘)×73" }, + { 85, "76~85: 附魔护腕 - 初级偏斜\n(1×次级魔法精华|1×奇异之尘)×20" }, + { 100, "86~100: 附魔护腕 - 初级耐力\n(3×奇异之尘)×15" }, + { 101, "101: 符文银棒\n(1×银棒|6×奇异之尘|3×强效魔法精华|1×符文铜棒)×1" }, + { 105, "102~105: 附魔护腕 - 初级耐力\n(3×奇异之尘)×4" }, + { 120, "106~120: 强效魔法杖\n(1×普通木柴|1×强效魔法精华)×15" }, + { 130, "121~130: 附魔盾牌 - 初级耐力\n(1×次级星界精华|2×奇异之尘)×10" }, + { 150, "131~150: 附魔护腕 - 次级耐力\n(2×灵魂之尘)×20" }, + { 151, "151: 符文金棒\n(1×金棒|1×彩色珍珠|2×强效星界精华|2×灵魂之尘|1×符文银棒)×1" }, + { 160, "152~160: 附魔护腕 - 次级耐力\n(2×灵魂之尘)×9" }, + { 165, "161~165: 附魔盾牌 - 次级耐力\n(1×次级秘法精华|1×灵魂之尘)×5" }, + { 180, "166~180: 附魔护腕 - 精神\n(1×次级秘法精华)×15" }, + { 200, "181~200: 附魔护腕 - 力量\n(1×幻象之尘)×20" }, + { 201, "201: 符文真银棒\n(1×真银棒|1×黑珍珠|2×强效秘法精华|2×幻象之尘|1×符文金棒)×1" }, + { 205, "202~205: 附魔护腕 - 力量\n(1×幻象之尘)×4" }, + { 225, "206~225: 附魔披风 - 强效防御\n(3×幻象之尘)×20" }, + { 235, "226~235: 附魔手套 - 敏捷\n(1×次级虚空精华|1×幻象之尘)×10" }, + { 245, "236~245: 附魔胸甲 - 超强生命\n(6×幻象之尘)×10" }, + { 250, "246~250: 附魔护腕 - 强效力量\n(2×梦境之尘|1×强效虚空精华)×5" }, + { 270, "251~270: 次级法力之油\n(3×梦境之尘|2×紫莲花|1×水晶瓶)×20\n配方购于:\n卡妮亚:希利苏斯<51,39>" }, + { 290, "271~290: 附魔盾牌 - 强效耐力\n(10×梦境之尘)×20\n附魔靴子 - 强效耐力\n(10×梦境之尘)×20" }, + { 291, "291: 符文奥金棒\n(1×奥金棒|1×金珍珠|10×幻影之尘|4×强效不灭精华|1×符文真银棒|2×大块魔光碎片)×1" }, + { 300, "292~300: 附魔披风 - 超强防御\n(8×幻影之尘)×9" }, + { 301, "301: 符文魔铁棒\n(1×魔铁棒|4×强效不灭精华|6×大块魔光碎片|1×符文奥金棒)×1" }, + { 305, "302~305: 附魔披风 - 超强防御\n(8×幻影之尘)×4" }, + { 315, "306~315: 附魔护腕 - 突袭\n(6×奥法之尘)×10" }, + { 325, "316~325: 附魔披风 - 特效护甲\n(8×奥法之尘)×10\n附魔护腕 - 突袭\n(6×奥法之尘)×10" }, + { 335, "326~335: 附魔胸甲 - 特效精神\n(2×强效位面精华)×10" }, + { 340, "336~340: 附魔盾牌 - 特效耐力\n(15×奥法之尘)×5" }, + { 345, "341~345: 超级巫师之油\n(3×奥法之尘|1×噩梦藤|1×灌魔之瓶)×5\n配方购于:\n卢比夫人:沙塔斯城<63,70>\n琳娜:银月城<69,24>\n艾苟米斯:埃索达<39,39>\n如果有足够的噩梦藤最好冲到350,这个材料便宜" }, + { 350, "346~350: 附魔手套 - 特效力量\n(12×奥法之尘|1×强效位面精华)×5" }, + { 351, "351: 符文精金棒\n(1×精金棒|8×强效位面精华|8×大块棱光碎片|1×源生之能|1×符文魔铁棒)×1\n配方购于:\n沃德辛:地狱火半岛<24,38>\n伦格尔:泰罗卡森林<48,46>" }, + { 360, "352~360: 附魔手套 - 特效力量\n(12×奥法之尘|1×强效位面精华)×9" }, + { 370, "361~370: 附魔手套 - 法术打击\n(8×强效位面精华|2×奥法之尘|2×大块棱光碎片)×10\n配方购于:\n芬德雷·迅矛:赞加沼泽<79,63>\n|cFFFFD700需要塞纳里奥远征队 - 崇敬" }, + { 375, "371~375: 附魔戒指 - 治疗能量\n(2×大块棱光碎片|3×强效位面精华|5×奥法之尘)×5\n配方购于:\n奥玛多尔:沙塔斯城<51,41>\n|cFFFFD700需要沙塔尔 - 崇敬" } + }, + [BI["Blacksmithing"]] = { + { 25, "1~25: 劣质磨刀石\n(1×劣质的石头)×25" }, + { 45, "26~45: 劣质砂轮\n(2×劣质的石头)×20" }, + { 75, "46~75: 铜质链甲腰带\n(6×铜锭)×30" }, + { 80, "76~80: 粗制砂轮\n(2×粗糙的石头)×5" }, + { 100, "81~100: 铜质符文腰带\n(10×铜锭)×20" }, + { 105, "101~105: 银棒\n(1×银锭|2×劣质砂轮)×5" }, + { 125, "106~125: 劣质青铜护腿\n(6×青铜锭)×20" }, + { 150, "126~150: 重砂轮\n(3×沉重的石头)×25" }, + { 155, "151~155: 金棒\n(1×金锭|2×粗制砂轮)×5" }, + { 165, "156~165: 绿铁护腿\n(8×铁锭|1×重砂轮|1×绿色染料)×10" }, + { 185, "166~185: 绿铁护腕\n(6×铁锭|1×绿色染料)×20" }, + { 200, "186~200: 金鳞护腕\n(5×钢锭|2×重砂轮)×15" }, + { 210, "201~210: 坚固的砂轮\n(4×坚固的石头)×10" }, + { 215, "211~215: 金鳞护腕\n(5×钢锭|2×重砂轮)×5" }, + { 235, "216~235: 钢质头盔\n(14×钢锭|1×坚固的砂轮)×20\n秘银鳞片护腕(成本低)\n(8×秘银锭)×20\n配方购于:\n哈尔甘:辛特兰,鹰巢山<13,44>\n卡尔拉什:悲伤沼泽,斯通纳德<45,51>" }, + { 250, "236~250: 秘银罩帽\n(10×秘银锭|6×魔纹布)×15\n秘银马刺(成本低)\n(4×秘银锭|3×坚固的砂轮)×15\n配方世界掉落" }, + { 260, "251~260: 致密磨刀石\n(1×厚重的石头)×10" }, + { 270, "261~270: 瑟银腰带(成本低)\n(12×瑟银锭|4×红色能量水晶)×10\n瑟银护腕(成本低)\n(12×瑟银锭|4×蓝色能量水晶)×10\n以上两种配方世界掉落\n地铸护腿 (防具锻造)\n(16×秘银锭|2×大地之核)×10\n风铸护腿(防具锻造)\n((16×秘银锭|2×风之气息))×10\n轻型地铸利刃(宗师级铸剑)\n(12×秘银锭|4×大地之核)×10\n轻型灰烬铸锤(宗师级铸锤)\n(12×秘银锭|4×火焰之心)×10\n轻型天铸战斧(宗师级铸斧)\n(12×秘银锭|4×风之气息)×10" }, + { 295, "271~295: 君王板甲护腕\n(12×瑟银锭)×25\n配方任务取得" }, + { 300, "296~300: 君王板甲战靴\n(18×瑟银锭)×5\n配方任务取得" }, + { 305, "301~305: 魔能平衡石\n(1×魔铁锭|1×灵纹布)×5" }, + { 320, "306~320: 魔铁板甲腰带\n(4×魔铁锭)×15" }, + { 325, "321~325: 魔铁板甲战靴\n(6×魔铁锭)×5" }, + { 330, "326~330: 次级结界符文\n(1×精金锭)×5" }, + { 335, "331~335: 魔铁胸甲\n(10×魔铁锭)×5" }, + { 340, "336~340: 精金利斧\n(8×精金锭)×5\n配方购于:\n埃隆·霍尔曼:沙塔斯城<64,71>\n恩里德:银月城<80,36>\n阿尔拉斯:埃索达<61,89>" }, + { 345, "341~345: 次级护盾结界\n(1×精金锭)×5\n配方购于:玛里·石拳:影月谷,蛮锤要塞<36,55>|罗霍克:地狱火半岛,萨尔玛<53,38>" }, + { 350, "346~350: 精金利斧\n(8×精金锭)×5\n配方购于:\n埃隆·霍尔曼:沙塔斯城<64,71>\n恩里德:银月城<80,36>\n阿尔拉斯:埃索达<61,89>" }, + { 360, "351~360: 精金平衡石\n(1×精金锭|2×灵纹布)×10\n配方购于:\n芬德雷·迅矛:赞加沼泽<79,63>\n|cFFFFD700需要塞纳里奥远征队 - 尊敬" }, + { 370, "361~370: 魔钢手套\n(6×魔钢锭)×10\n奥金尼地穴掉落\n灭焰手套\n(8×魔铁锭|4×源生之水|4×源生火焰)×10\n配方购于:\n军需官恩达尔林:沙塔斯城<47,25>\n|cFFFFD700需要奥尔多 - 尊敬\n魔化精金腰带\n(2×硬化精金锭|8×奥法之尘|2×大块棱光碎片)×10\n配方购于:\n军需官恩努利尔:沙塔斯城<60,64>\n|cFFFFD700需要占星者 - 友善" }, + { 375, "371~375: 魔钢手套\n(6×魔钢锭)×5\n奥金尼地穴掉落\n灭焰胸甲\n配方购于:\n军需官恩达尔林:沙塔斯城<47,25>\n(16×魔铁锭|6×源生之水|4×源生火焰)×5\n|cFFFFD700需要奥尔多 - 尊敬\n魔化精金腰带\n(2×硬化精金锭|8×奥法之尘|2×大块棱光碎片)×5\n配方购于:\n军需官恩努利尔:沙塔斯城<60,64>\n|cFFFFD700需要占星者 - 友善" } + }, + [BI["Alchemy"]] = { + { 60, "1~60: 初级治疗药水\n(1×宁神花|1×银叶草|1×空瓶)×60" }, + { 110, "61~110: 次级治疗药水\n(1×初级治疗药水|1×石南草)×50" }, + { 140, "111~140: 治疗药水\n(1×跌打草|1×石南草|1×铅瓶)×30" }, + { 155, "141~155: 次级法力药水\n(1×魔皇草|1×荆棘藻|1×空瓶)×15" }, + { 185, "156~185: 强效治疗药水\n(1×活根草|1×皇血草|1×铅瓶)×30" }, + { 210, "186~210: 敏捷药剂\n(1×荆棘藻|1×金棘草|1×铅瓶)×25" }, + { 215, "211~215: 强效防御药剂\n(1×野钢花|1×金棘草|1×铅瓶)×5" }, + { 230, "216~230: 优质治疗药水\n(1×太阳草|1×卡德加的胡须|1×水晶瓶)×15" }, + { 250, "231~250: 侦测亡灵药剂\n(1×阿尔萨斯之泪|1×水晶瓶)×20" }, + { 265, "251~265: 强效敏捷药剂\n(1×太阳草|1×金棘草|1×水晶瓶)×15" }, + { 285, "266~285: 优质法力药水\n(2×太阳草|2×盲目草|1×水晶瓶)×20" }, + { 300, "286~300: 特效治疗药水\n(2×黄金参|1×山鼠草|1×水晶瓶)×15" }, + { 315, "301~315: 不稳定的治疗药水\n(1×黄金参|1×魔草|1×灌魔之瓶)×15\n特效法力药水\n(3×梦叶草|2×冰盖草|1×水晶瓶)×15" }, + { 350, "316~350: 疯狂炼金师药水\n(1×水晶瓶|2×邪雾草)×35+\n在335的时候会变黄,但是该配方成本低" }, + { 375, "351~375: 特效无梦睡眠药水\n(1×梦露花|1×噩梦藤|1×灌魔之瓶)×25\n配方购于:莉莉·朗哈格:泰罗卡森林,奥蕾莉亚要塞<57,53>\n联达加·拉姆巴:刀锋山,雷神要塞<51,57>" } + }, + [L["Mining"]] = { + { 65, "1~65: 铜矿\n所有起始地区" }, + { 125, "66~125: 锡矿|银矿|火岩矿|次级血石矿\n\n火岩矿分布于瑟根石(湿地)\n很容易升到125" }, + { 175, "126~175: 铁矿|金矿\n凄凉之地|灰谷|荒芜之地|阿拉希高地\n奥特兰克山脉|荆棘谷|悲伤沼泽" }, + { 250, "176~250: 秘银矿|真银矿\n诅咒之地|灼热峡谷|荒芜之地|辛特兰\n西瘟疫之地|艾萨拉|冬泉谷|费伍德森林|石爪山脉|塔纳利斯" }, + { 300, "251~300: 瑟银矿\n安戈洛环形山|冬泉谷|诅咒之地|灼热峡谷\n燃烧平原|东瘟疫之地|西瘟疫之地" }, + { 330, "301~330: 魔铁矿\n地狱火半岛|赞加沼泽" }, + { 375, "331~375: 魔铁矿|精金矿\n泰罗卡森林|纳格兰\n所有外域地区均有" } + }, + [L["Herbalism"]] = { + { 50, "1~50: 银叶草|宁神花\n所有起始地区" }, + { 70, "51~70: 魔皇草|地根草\n贫瘠之地|西部荒野|银松森林|洛克莫丹|黑海岸" }, + { 100, "71~100: 石南草\n银松森林|暮色森林|黑海岸|洛克莫丹|赤脊山" }, + { 115, "101~115: 跌打草\n灰谷|石爪山脉|南贫瘠之地|洛克莫丹|赤脊山" }, + { 125, "116~125: 野钢花\n石爪山脉|阿拉希高地|荆棘谷|南贫瘠之地|千针石林" }, + { 160, "126~160: 皇血草\n灰谷|石爪山脉|湿地|希尔斯布莱德丘陵|悲伤沼泽" }, + { 185, "161~185: 枯叶草\n悲伤沼泽" }, + { 205, "186~205: 卡德加的胡须\n辛特兰|阿拉希高地|悲伤沼泽" }, + { 230, "206~230: 火焰花\n灼热峡谷|诅咒之地|塔纳利斯" }, + { 250, "231~250: 太阳草\n费伍德森林|菲拉斯|艾萨拉|辛特兰" }, + { 270, "251~270: 格罗姆之血\n费伍德森林|诅咒之地|玛诺洛克集会所(凄凉之地)" }, + { 285, "271~285: 梦叶草\n安戈洛环形山|艾萨拉" }, + { 300, "286~300: 瘟疫花\n东瘟疫之地|西瘟疫之地|费伍德森林|\n冰盖草\n冬泉谷" }, + { 330, "301~330: 魔草\n地狱火半岛|赞加沼泽" }, + { 375, "331~375: 任何外域植物\n赞加沼泽和泰罗卡森林较集中" } + }, + [L["Skinning"]] = { + { 375, "1~375: 技能等级处以5,\n所获值对应的可剥皮怪物" } + }, + -- 来源: http://www.almostgaming.com/wowguides/world-of-warcraft-lockpicking-guide + [L["Lockpicking"]] = { + { 85, "1~85: 开锁练习\n奥瑟尔伐木场,赤脊山(联盟)\n棘齿城附近的海盗船(部落)" }, + { 150, "86~150: 制毒任务目标怪附近的箱子\n西部荒野(联盟)|贫瘠之地(部落)" }, + { 185, "151~185: 鱼人营地(湿地)" }, + { 225, "186~225: 萨瑟里斯海岸(凄凉之地)\n" }, + { 250, "226~250: 苦痛堡垒(荒芜之地)" }, + { 275, "251~275: 熔渣之池(灼热峡谷)" }, + { 300, "276~300: 落帆海湾(塔纳利斯)\n风暴海湾(艾萨拉)" }, + { 325, "301~325: 蛮沼村(赞加沼泽)" }, + { 350, "326~350: 基尔索罗堡垒(纳格兰)\n偷取石拳系食人魔(纳格兰)" } + }, + + -- ** 辅助技能 ** + [BI["First Aid"]] = { + { 40, "1~40: 亚麻绷带" }, + { 80, "41~80: 厚亚麻绷带\n50的时候学急救(中级)" }, + { 115, "81~115: 绒线绷带" }, + { 150, "116~150: 厚绒线绷带\n125的时候去买教材<中级急救教材 - 绷带缚体>和2个配方\n配方购于:\n德尼布·沃克:阿拉希高地,激流堡<27,58>\n格鲁克卡恩:尘泥沼泽,蕨墙村<35,30>\n巴莱·洛克维:尘泥沼泽,蕨墙村<36,30>" }, + { 180, "151~180: 丝质绷带" }, + { 210, "181~210: 厚丝质绷带\n200的时候满35级,做任务学会急救(专家级)\n地点:塞拉摩岛(联盟)|落锤镇(部落)" }, + { 240, "211~240: 魔纹绷带\n" }, + { 260, "241~260: 厚魔纹绷带" }, + { 290, "261~290: 符文布绷带" }, + { 330, "291~330: 厚符文布绷带\n300的时候去买教材<大师级急救手册 - 私人医生>\n配方购于:\n阿蕾瑟拉:地狱火半岛,塔哈玛特神殿<26,62>\n布尔库:地狱火半岛,猎鹰岗哨<22,39>" }, + { 360, "331~360: 灵纹布绷带\n购买<手册:灵纹布绷带>\n配方购于:\n阿蕾瑟拉:地狱火半岛,塔哈玛特神殿<26,62>\n布尔库:地狱火半岛,猎鹰岗哨<22,39>" }, + { 375, "361~375: 厚灵纹布绷带\n购买<手册:厚灵纹布绷带>\n配方购于:\n阿蕾瑟拉:地狱火半岛,塔哈玛特神殿<26,62>\n布尔库:地狱火半岛,猎鹰岗哨<22,39>" } + }, + [BI["Cooking"]] = { + { 40, "1~40: 香料面包\n(1×面粉|1×甜香料)×70" }, + { 75, "41~75: 熏熊肉\n(1×熊肉)×30\n配方购于:\n德拉克·卷刃:洛克莫丹<35,49>\n安德鲁·希尔伯特:银松森林<43,40>" }, + { 85, "76~85: 蟹肉蛋糕(联盟)\n(1×蟹肉, 1×甜香料)×10\n熏熊肉(部落)\n(1×熊肉)×20\n配方购于:\n德拉克·卷刃:洛克莫丹<35,49>\n安德鲁·希尔伯特:银松森林<43,40>" }, + { 90, "86~90: 煮蟹爪(联盟)\n(1×蟹爪, 1×甜香料)×5\n配方购于:\n肯多尔·卡邦卡:暴风城<74,36>\n熏熊肉(部落)\n(1×熊肉)×10\n配方购于:\n德拉克·卷刃:洛克莫丹<35,49>\n安德鲁·希尔伯特:银松森林<43,40>" }, + { 100, "91~100: 煮蟹爪(联盟)\n(1×蟹爪|1×甜香料)×15\n配方购于:\n肯多尔·卡邦卡:暴风城<74,36>\n掘地鼠炖肉(部落)\n(1×掘地鼠)×10\n配方任务获取:[23]掘地鼠炖肉" }, + { 125, "101~125: 掘地鼠炖肉(部落)\n(1×掘地鼠)×30\n配方任务获取:[23]掘地鼠炖肉\n干烤狼肉串(联盟)\n(2×狼肋排|1×暴风城特产调料)×25\n配方购于:\n肯多尔·卡邦卡:暴风城<74,36>" }, + { 130, "126~130: 烤狮排(部落)\n(1×狮肉|1×辣椒)×5\n配方购于:\n扎尔夫:贫瘠之地<52,29>\n干烤狼肉串(联盟)\n(2×狼肋排|1×暴风城特产调料)×25\n配方购于:\n肯多尔·卡邦卡:暴风城<74,36>" }, + { 175, "131~175: 美味煎蛋卷(联盟)\n(1×迅猛龙蛋|1×辣椒)×50\n配方购于:\n肯多尔·卡邦卡:暴风城<74,36>\n烤狮排(部落)\n(1×狮肉|1×辣椒)×55\n配方购于:\n扎尔夫:贫瘠之地<52,29>" }, + { 200, "176~200: 烤迅猛龙肉\n(1×迅猛龙肉|1×辣椒)×30\n配方购于:\n耐里斯特:荆棘谷,格罗姆高营地<32,29>\n布鲁斯下士:荆棘谷,反抗军营地<37,3>" }, + { 225, "201~225: 蜘蛛肉肠\n(2×白蜘蛛肉)×30\n\n|cFFFFFFFF225接到烹饪大师任务: 迪尔格·奎克里弗:加基森<51,27>给予\n|cFFFFD700需要12个巨蛋|10个美味的蚌肉|20个奥特兰克冷酪" }, + { 275, "226~275: 超级煎蛋卷\n(1×巨蛋|2×舒心草)×80\n配方购于:\n琦亚:冬泉谷,永望镇<61,37>\n西米克:冬泉谷,永望镇<61,39>\n拜尔:费伍德森林,血毒岗哨<34,53>\n玛里甘:费伍德森林,刺枝林地<62,25>\n嫩狼肉排\n(1×嫩狼肉|1×舒心草)×80\n配方购于:\n迪尔格·奎克里弗:塔纳利斯,加基森<52,28>\n特鲁克·蛮鬃:辛特兰,鹰巢山<14,42>" }, + { 285, "276~285: 洛恩塔姆薯块\n(1×洛恩塔姆地薯|1×舒心草)×10\n掉落:普希林 厄运之槌" }, + { 300, "286~300: 沙漠肉丸子\n(1×沙虫的肉|1×舒心草)×20\n希利苏斯任务(旅店老板)" }, + { 325, "301~325: 掠食者热狗\n(1×掠食者的肉)×40\n配方购于:\n独眼曲奇:地狱火半岛,萨尔玛<54,41>\n希德·利巴迪:地狱火半岛,荣耀堡<54,63>\n美味秃鹫\n(1×秃鹰肉)×40\n来源:任务 [61]万无一失" }, + { 350, "326~350: 烧烤裂蹄牛\n(1×裂蹄牛肉)×40\n配方购于:\n屠夫努尔拉:纳格兰,加拉达尔<58,35>\n乌利库:纳格兰,塔拉<56,73>\n迁跃兽汉堡\n(1×迁跃兽肉)×40\n配方购于:\n屠夫努尔拉:纳格兰,加拉达尔<58,35>\n乌利库:纳格兰,塔拉<56,73>\n旅店老板格里尔卡:泰罗卡森林,裂石堡<48,45>\n供给官米尔斯:泰罗卡森林,奥蕾莉亚要塞<55,53>\n塔布肉排\n(1×塔布羊肉)×40\n配方购于:\n屠夫努尔拉:纳格兰,加拉达尔<58,35>\n乌利库:纳格兰,塔拉<56,73>" }, + { 375, "351~375: 香辣小龙虾\n(1×狂暴龙虾)×25\n配方购于:\n旅店老板贝莉比:泰罗卡森林,奥蕾莉亚要塞<56,53>\n伦格尔:泰罗卡森林,裂石堡<48,46>\n此处建议和钓鱼一起练\n莫克纳萨肋排\n(1×迅猛龙肋排)×60\n香脆蛇\n(1×蛇肉)×60c\n以上两个配方来源:\n任务 [67]莫克纳萨的美味(部落)\n购买:萨莎·焊井:刀锋山,托雷斯营地<61,68>" } + }, + -- 来源: http://www.wowguideonline.com/fishing.html + [BI["Fishing"]] = { + { 50, "1~50: 任何起始地点" }, + { 75, "51~75:\n暴风城的河里\n奥格瑞玛的池塘里" }, + { 150, "76~150: 希尔斯布莱德丘陵的河里" }, + { 225, "151~225: 凄凉之地|阿拉希高地\n150的时候购买<中级钓鱼教材 - 鲈鱼与你>\n配方购于:\n老人海明威:藏宝海湾<27,77>" }, + { 250, "226~250: 辛特兰|塔纳利斯\n\n|cFFFFFFFF225开始高级钓鱼任务\n起始于各个主城,均到纳特·帕格:尘泥沼泽<59,61>\n|cFFFFD700野人海岸蓝色叉牙鱼(荆棘谷<34,35>)\n菲拉斯草鱼(沃丹提斯河, 菲拉斯)\n萨瑟里斯虎鱼(萨瑟里斯海岸北部, 葬影村附近, 凄凉之地)\n芦苇海岸大马哈鱼(芦苇海岸, 悲伤沼泽)" }, + { 260, "251~260: 费伍德森林" }, + { 300, "261~300: 艾萨拉" }, + { 330, "301~330: 赞加沼泽东部\n300的时候购买<顶级钓鱼教材 - 下钩的艺术>\n配方购于:\n乔诺·杜伏恩:塞那里奥避难所<78,66>" }, + { 345, "331~345: 赞加沼泽西部" }, + { 360, "346~360: 泰罗卡森林" }, + { 375, "361~375: 泰罗卡森林,高地上:\n尤鲁恩湖, 裂石堡西北方\n艾雷诺湖, 奥蕾莉亚要塞东南方\n黑风湖, 斯克提斯地区\n需要飞行坐骑" } + }, + + -- 建议升级地区,来源众多,不一一列举了 + ["Leveling"] = { + { 10, "1~10级: 所有起始地区" }, + { 20, "11~20级: " .. BZ["Loch Modan"] .. "\n" .. BZ["Westfall"] .. "\n" .. BZ["Darkshore"] .. "\n" .. BZ["Bloodmyst Isle"] + .. "\n" .. BZ["Silverpine Forest"] .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Ghostlands"]}, + { 25, "21~25级: " .. BZ["Wetlands"] .. "\n" .. BZ["Redridge Mountains"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Hillsbrad Foothills"] }, + { 28, "26~28级: " .. BZ["Duskwood"] .. "\n" .. BZ["Wetlands"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Thousand Needles"] }, + { 31, "29~31级: " .. BZ["Duskwood"] .. "\n" .. BZ["Thousand Needles"] .. "\n" .. BZ["Ashenvale"] }, + { 35, "32~35级: " .. BZ["Thousand Needles"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Alterac Mountains"] + .. "\n" .. BZ["Arathi Highlands"] .. "\n" .. BZ["Desolace"] }, + { 40, "36~40级: " .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Desolace"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 43, "41~43级: " .. BZ["Tanaris"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 45, "44~45级: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] }, + { 48, "46~48级: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] .. "\n" .. BZ["Searing Gorge"] }, + { 51, "49~51级: " .. BZ["Tanaris"] .. "\n" .. BZ["Azshara"] .. "\n" .. BZ["Blasted Lands"] + .. "\n" .. BZ["Searing Gorge"] .. "\n" .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] }, + { 55, "54~55级: " .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] .. "\n" .. BZ["Burning Steppes"] + .. "\n" .. BZ["Blasted Lands"] .. "\n" .. BZ["Western Plaguelands"] }, + { 58, "56~58级: " .. BZ["Winterspring"] .. "\n" .. BZ["Burning Steppes"] .. "\n" .. BZ["Western Plaguelands"] + .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 60, "59~60级: " .. BZ["Winterspring"] .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 62, "61~62级: " .. BZ["Hellfire Peninsula"] }, + { 64, "63~64级: " .. BZ["Zangarmarsh"] .. "\n" .. BZ["Terokkar Forest"]}, + { 65, "65级: " .. BZ["Terokkar Forest"] }, + { 66, "66级: " .. BZ["Terokkar Forest"] .. "\n" .. BZ["Nagrand"]}, + { 67, "67级: " .. BZ["Nagrand"]}, + { 68, "68级: " .. BZ["Blade's Edge Mountains"]}, + { 70, "69~70级: " .. BZ["Blade's Edge Mountains"] .. "\n" .. BZ["Netherstorm"] .. "\n" .. BZ["Shadowmoon Valley"]}, + { 72, "72级: " .. BZ["Howling Fjord"] .. "\n" .. BZ["Borean Tundra"]}, + { 74, "74级: " .. BZ["Grizzly Hills"] .. "\n" .. BZ["Dragonblight"]}, + { 76, "76级: " .. BZ["Dragonblight"] .. "\n" .. BZ["Zul'Drak"]}, + { 78, "78级: " .. BZ["Zul'Drak"] .. "\n" .. BZ["Sholazar Basin"]}, + { 80, "80级: " .. BZ["The Storm Peaks"] .. "\n" .. BZ["Icecrown"]}, + }, + + -- 声望值级别 + -- -42000 = "仇恨" + -- -6000 = "敌对" + -- -3000 = "冷淡" + -- 0 = "中立" + -- 3000 = "友善" + -- 9000 = "尊敬" + -- 21000 = "崇敬" + -- 42000 = "崇拜" + + -- Outland factions: source: http://www.mmo-champion.com/ + [BF["The Aldor"]] = { + { 0, "升到中立:\n" .. WHITE .. "[巨牙毒囊]|r +250 声望值\n\n" + .. YELLOW .. "巨牙潜伏者,\n巨牙寡妇蛛\n" + .. WHITE .. "(泰罗卡森林)" }, + { 9000, "升到尊敬:\n" .. WHITE .. "[基尔加丹印记]|r\n+25 声望值" }, + { 42000, "升到崇拜:\n" .. WHITE .. "[萨格拉斯印记]|r +25 声望值/每枚\n" + .. GREEN .. "[邪能装备]|r +350 声望值 (+1 神圣之尘)" } + }, + [BF["The Scryers"]] = { + { 0, "升到中立:\n" .. WHITE .. "[湿鳞蜥蜴的眼睛]|r +250 声望值\n\n" + .. YELLOW .. "铁脊石化者,\n湿鳞吞噬者,\n湿鳞蜥蜴\n" + .. WHITE .. "(泰罗卡森林)" }, + { 9000, "升到尊敬:\n" .. WHITE .. "[火翼徽记]|r\n+25 声望值" }, + { 42000, "升到崇拜:\n" .. WHITE .. "[日怒徽记]|r +25 声望值 per mark\n" + .. GREEN .. "[奥法宝典]|r +350 声望值 (+1 奥术符文)" } + }, + [BF["Netherwing"]] = { + { 3000, "升到友善, 重复以下任务:\n\n" + .. YELLOW .. "缓慢的死亡 (日常)|r +250 声望值\n" + .. YELLOW.. "灵尘花粉 (日常)|r +250 声望值\n" + .. YELLOW.. "灵翼水晶 (日常)|r +250 声望值\n" + .. YELLOW.. "危险的天空 (日常)|r +250 声望值\n" + .. YELLOW.. "寻找灵翼龙卵 (可重复提交)|r +250 声望值" }, + { 9000, "升到尊敬, 重复以下任务:\n\n" + .. YELLOW .. "新的监工:正确的选择|r +350 声望值\n" + .. YELLOW .. "训诫靴:懒惰苦工的惩戒 (日常)|r +350 声望值\n" + .. YELLOW .. "回收货物 (日常)|r +350 声望值\n" + .. YELLOW .. "龙?不是问题 (日常)|r +350 声望值\n" + .. YELLOW .. "疯狂与困惑|r +350 声望值\n" }, + { 21000, "升到崇敬, 重复以下任务:\n\n" + .. YELLOW .. "征服者雷萨赫尔顿|r +500 声望值\n" + .. YELLOW .. "暮光岭的传送门 (日常)|r +500 声望值\n" + .. YELLOW .. "你的双翼 +500 声望值(1~5号), +1000 声望值(6号)\n" }, + { 42000, "升到崇拜, 重复以下任务:\n\n" + .. YELLOW .. "最致命的陷阱 (日常) (3+)|r +500 声望值" } + }, + [BF["Honor Hold"]] = { + { 9000, "升到尊敬:\n\n" + .. YELLOW .. "地狱火半岛的任务\n" + .. GREEN .. "地狱火城墙 |r(普通)\n" + .. GREEN .. "鲜血熔炉 |r(普通)" }, + { 42000, "升到崇拜:\n\n" + .. GREEN .. "破碎大厅 |r(普通或英雄)\n" + .. GREEN .. "地狱火城墙 |r(英雄)\n" + .. GREEN .. "鲜血熔炉 |r(英雄)" } + }, + [BF["Thrallmar"]] = { + { 9000, "升到尊敬:\n\n" + .. YELLOW .. "地狱火半岛的任务\n" + .. GREEN .. "地狱火城墙 |r(普通)\n" + .. GREEN .. "鲜血熔炉 |r(普通)" }, + { 42000, "升到崇拜:\n\n" + .. GREEN .. "破碎大厅 |r(普通或英雄)\n" + .. GREEN .. "地狱火城墙 |r(英雄)\n" + .. GREEN .. "鲜血熔炉 |r(英雄)" } + }, + [BF["Cenarion Expedition"]] = { + { 3000, "升到友善:\n\n" + .. WHITE .. "暗潮纳迦或者血鳞纳迦 (+5 声望值)\n" + .. YELLOW .. "赞加沼泽的任务\n" + .. "|r杀入任意 " .. GREEN .. "盘牙水库|r 的副本\n\n" + .. WHITE .. "保存 [未鉴定过的植物] 为稍后上缴" }, + { 9000, "升到尊敬:\n\n" + .. WHITE .. "上缴 [未鉴定过的植物] x240\n" + .. YELLOW .. "赞加沼泽的任务\n" + .. "|r杀入任意 " .. GREEN .. "盘牙水库|r 的副本" }, + { 42000, "升到崇拜:\n\n" + .. WHITE .. "上缴 [盘牙武器] +75 声望值\n\n" + .. GREEN .. "蒸汽地窟 |r(普通)\n" + .. GREEN .. "任何盘牙水库的副本 |r(英雄)" } + }, + [BF["Keepers of Time"]] = { + { 42000, "升到崇拜:\n\n" + .. "|r杀入 " .. GREEN .. "旧希尔斯布莱德丘陵|r 和 " .. GREEN .. "黑色沼泽|r 副本\n\n" + .. YELLOW .. "最后交任务:\n“旧希尔斯布莱德丘陵”任务线共计 5000 声望值\n“黑色沼泽”任务线共计 8000 声望值" } + }, + [BF["The Sha'tar"]] = { + { 42000, "升到崇拜:\n\n" + .. GREEN .. "生态船 |r(普通或英雄)\n" + .. GREEN .. "能源舰 |r(普通或英雄)\n" + .. GREEN .. "禁魔监狱 |r(普通或英雄)\n" } + }, + [BF["Lower City"]] = { + { 9000, "升到尊敬:\n\n" + .. WHITE .. "上缴 [鸦人的羽毛]×30 (+250 声望值)\n" + .. GREEN .. "暗影迷宫 |r(普通)\n" + .. GREEN .. "奥金尼地穴 |r(普通)\n" + .. GREEN .. "塞泰克大厅 |r(普通)" }, + { 42000, "升到崇拜:\n\n" + .. GREEN .. "暗影迷宫 |r(普通或英雄)\n" + .. GREEN .. "奥金尼地穴 |r(英雄)\n" + .. GREEN .. "塞泰克大厅 |r(英雄)" } + }, + [BF["The Consortium"]] = { + { 3000, "升到友善:\n\n" + .. "|r上缴 [沃舒古水晶碎片] +250 声望值\n" + .. "上缴 [象牙] +250 声望值\n\n" + .. GREEN .. "法力坟墓 |r(普通)" }, + { 9000, "升到尊敬:\n\n" + .. "|r上缴 [黑曜石作战念珠] +250 声望值\n\n" + .. GREEN .. "法力坟墓 |r(普通)" }, + { 42000, "升到崇拜:\n\n" + .. "|r上缴 [萨克希斯徽记] +250 声望值\n" + .. "|r上缴 [黑曜石作战念珠] +250 声望值\n\n" + .. GREEN .. "法力坟墓 |r(英雄)" } + }, + [BF["Shattered Sun Offensive"]] = { + { 42000, "升到崇拜:\n\n" + .. YELLOW .. "完成奎尔丹纳斯岛和沙塔斯城的相关日常任务" } + }, + [BF["The Mag'har"]] = { + { 42000, "升到崇拜:\n\n" + .. "|r上缴 [黑曜石作战念珠] +250 声望值\n\n" + .. WHITE .. "纳格兰和泰罗卡森林的任何食人魔 (+5~11 声望值)\n" + .. YELLOW .. "完成纳格兰的任务" } + }, + [BF["Kurenai"]] = { + { 42000, "升到崇拜:\n\n" + .. "|r上缴 [黑曜石作战念珠] +250 声望值\n\n" + .. WHITE .. "纳格兰和泰罗卡森林的任何食人魔 (+5~11 声望值)\n" + .. YELLOW .. "完成纳格兰的任务" } + }, + [BF["Sporeggar"]] = { + { 0, "升到中立:\n\n" + .. "上缴 [成熟的孢子] 或者 [沼泽领主的卷须] +250 声望值\n\n" + .. YELLOW .. "沼泽领主,\n打开[孢子囊]\n" + .. WHITE .. "(赞加沼泽)" }, + { 3000, "升到友善:\n\n" + .. "上缴 [亮顶蘑菇] +250 声望值\n\n" + .. "上缴 [成熟的孢子] 或者 [沼泽领主的卷须] +250 声望值\n\n" + .. YELLOW .. "沼泽领主,\n打开[孢子囊]\n" + .. WHITE .. "(赞加沼泽)" }, + { 42000, "升到崇拜:\n\n" + .. WHITE .. "上缴 [红色木槿] +250 声望值\n\n" + .. GREEN .. "幽暗沼泽 |r(普通或者英雄)\n" + .. "上缴 [成熟的孢子] +250 声望值\n\n" + .. YELLOW .. "现在 我们是朋友了… (可重复)|r +250 声望值\n" } + }, + [BF["Sha'tari Skyguard"]] = { + { 42000, "升到崇拜, 重复以下任务:\n\n" + .. YELLOW .. "轰炸斯克提斯 (日常)|r +350 声望值\n" + .. YELLOW.. "逃离斯克提斯 (日常)|r +350 声望值\n" + .. YELLOW.. "仇敌的血脉 (可重复)|r +350 声望值\n" + .. YELLOW.. "召唤泰罗克 (可重复)|r +350 声望值\n" + .. WHITE .. "(斯克提斯)" + .. YELLOW.. "继续轰炸! (日常)|r +500 声望值\n" + .. YELLOW.. "捕捉更多以太鳐! (日常)|r +350 声望值\n" + .. YELLOW.. "埃匹希斯的顿悟 (日常)|r +350 声望值\n" + .. YELLOW.. "放逐更多恶魔 (日常)|r +350 声望值\n" + .. WHITE .. "(刀锋山)"}, + }, + [BF["Ogri'la"]] = { + { 42000, "升到崇拜, 重复以下任务:\n\n" + .. YELLOW.. "继续轰炸! (日常)|r +500 声望值\n" + .. YELLOW.. "捕捉更多以太鳐! (日常)|r +350 声望值\n" + .. YELLOW.. "埃匹希斯的顿悟 (日常)|r +350 声望值\n" + .. YELLOW.. "放逐更多恶魔 (日常)|r +350 声望值\n" + .. WHITE .. "(刀锋山)"}, + } +} diff --git a/Altoholic-Addon/Altoholic/Suggestions_zhTW.lua b/Altoholic-Addon/Altoholic/Suggestions_zhTW.lua new file mode 100644 index 0000000..d9a03d9 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Suggestions_zhTW.lua @@ -0,0 +1,536 @@ +local addonName = ... +local addon = _G[addonName] + +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() +local BZ = LibStub("LibBabble-Zone-3.0"):GetLookupTable() +local BF = LibStub("LibBabble-Faction-3.0"):GetLookupTable() + +if GetLocale() ~= "zhTW" then return end + +local WHITE = "|cFFFFFFFF" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" + +-- 以下為聲望值、等級、技能等的建議 +addon.Suggestions = { + [L["Riding"]] = { + { 75, "初級騎術(20級): |cFFFFFFFF4g\n|cFFFFD700主城附近的的普通坐騎:|cFFFFFFFF1g" }, + { 150, "中級騎術(40級): |cFFFFFFFF50g\n|cFFFFD700主城附近的史詩級坐騎:|cFFFFFFFF10g" }, + { 225, "高級騎術(60級): |cFFFFFFFF600g\n|cFFFFD700影月谷附近的普通飛行坐騎:|cFFFFFFFF50g" }, + { 300, "專家級騎乘(70級): |cFFFFFFFF5000g\n|cFFFFD700影月谷附近的史詩級飛行坐騎:|cFFFFFFFF200g" } + }, + + -- 來源 : http://forums.worldofwarcraft.com/thread.html?topicId=102789457&sid=1(英文) + -- ** 主專業技能 ** + [BI["Tailoring"]] = { + { 50, "1-50: 亞麻布卷\n(2x亞麻布)x80" }, + { 70, "51-70: 亞麻包\n(3x亞麻布卷/3x粗線)x20" }, + { 75, "71-75: 強化亞麻斗篷\n(2x亞麻布卷/3x粗線)x5" }, + { 105, "76-105: 毛布卷\n(3x毛料)x60" }, + { 110, "106-110: 灰色毛紡襯衣\n(2x毛布卷/1x細線/1x灰色染料)x5"}, + { 125, "111-125: 雙線毛紡護肩\n(3x毛布卷/2x細線)x15" }, + { 145, "126-145: 絲綢卷\n(4x絲綢)x190" }, + { 160, "146-160: 碧藍絲質頭巾\n(2x絲綢卷/2x藍色染料/1x細線)x15" }, + { 170, "161-170: 絲質頭帶\n(3x絲綢卷/2x細線)x10" }, + { 175, "171-175: 體面的白襯衣\n(3x絲綢卷/2x漂白液/1x細線)x5" }, + { 185, "176-185: 魔紋布卷\n(5x魔紋布)x100" }, + { 205, "186-205: 深紅絲質外衣\n(4x絲綢卷/2x紅色染料/2x細線)x15" }, + { 215, "206-215: 深紅絲質馬褲\n(4x絲綢卷/2x紅色染料/2x絲線)x15" }, + { 220, "216-220: 黑色魔紋短褲\n黑色魔紋外衣\n(2x魔紋布卷/3x絲線)x5" }, + { 230, "221-230: 黑色魔紋手套\n(2x魔紋布卷/2x粗絲線)x10" }, + { 250, "231-250: 黑色魔紋頭帶\n黑色魔紋護肩\n(3x魔紋布卷/2x粗絲線)x20" }, + { 260, "251-260: 符文布卷\n(5x符文布)x180" }, + { 275, "261-275: 符文布腰帶\n(3x符文布卷/1x符文線)x15" }, + { 280, "276-280: 符文布背包\n(5x符文布卷/2x硬甲皮/1x符文線)x5" }, + { 300, "281-300: 符文布手套\n(4x符文布卷/4x硬甲皮/1x符文線)x20" }, + { 325, "301-325: 幽紋布卷\n(6x幽紋布)x25\n|cFFFFD700千萬別賣掉,你用來繼續升級的!" }, + { 340, "326-340: 魔染幽紋布卷\n(3x幽紋布卷/2x魔塵)x15\n|cFFFFD700千萬別賣掉,你用來繼續升級的!" }, + { 350, "341-350: 幽紋長靴\n(6x幽紋布卷/2x境外皮革/1x符文線)x10\n|cFFFFD700可分解為魔塵." }, + { 360, "351-360: 幽紋外套\n(8x幽紋布卷/2x符文線)x10\n|cFFFFD700可分解為魔塵." }, + { 375, "361-375: 魔染幽紋外套\n(6x魔染幽紋布卷/2x幽網蜘蛛絲/1x符文線)x15\n期間可以選擇分支並作專業套裝." } + }, + [BI["Leatherworking"]] = { + { 35, "1-35: 輕型護甲片\n(1x輕皮)x35" }, + { 55, "36-55: 熟化輕毛皮\n(1x輕毛皮/1x鹽)x20" }, + { 80, "56-80: 雕花皮靴\n(8x輕皮/5x粗線)x15" }, + { 85, "81-85: 優質皮帶\n(6x輕皮/2x粗線)x5" }, + { 90, "86-90: 優質皮外套\n(3x熟化輕毛皮/6x輕皮/4x粗線)x5" }, + { 100, "91-100: 優質皮帶\n(6x輕皮/2x粗線)x10" }, + { 120, "101-120: 熟化中毛皮\n(1x中毛皮/1x鹽)x20" }, + { 125, "121-125: 優質皮帶\n(6x輕皮/2x粗線)x5" }, + { 150, "126-150: 黑皮腰帶\n(1x優質皮帶/1x熟化中毛皮/2x細線/1x灰色染料)x25" }, + { 160, "151-160: 熟化重毛皮\n(1x重毛皮/3x鹽)x10" }, + { 170, "161-170: 重型護甲片\n(5x重皮/1x細線)x10" }, + { 180, "171-180: 暗色皮護腿\n(10x重皮/1x黑色染料/2x細線)x10\n守護短褲\n(12x重皮/2x絲綢卷/2x細線)x10" }, + { 195, "181-195: 野人護肩\n(8x重皮/1x熟化重毛皮/2x細線)x15" }, + { 205, "196-205: 暗色護腕\n(16x重皮/1x黑色染料/2x絲線)x10" }, + { 220, "206-220: 厚重護甲片\n(5x厚皮/1x絲線)x15" }, + { 225, "221-225: 夜色頭帶\n(5x厚皮/2x絲線)x5" }, + { 250, "226-250: 根據你的專精可以為:\n元素制皮:\n夜色頭帶\n(5x厚皮/2x絲線)x25\n夜色外套\n(7x厚皮/2x絲線)x25\n夜色短褲(14x厚皮/4x絲線)x20\n龍鱗制皮:\n硬化蠍殼胸甲(12x厚皮/12x蠍殼/4x絲線)x25\n硬化蠍殼手套(6x厚皮/8x蠍殼/2x絲線)x25\n部族制皮:\n龜殼頭盔(14x厚皮/24x龜殼/1x粗絲線)x20\n龜殼護腿(14x厚皮/28x龜殼/1x粗絲線)x15\n龜殼胸甲(6x厚皮/12x龜殼/1x粗絲線)x25\n龜殼手套(6x厚皮/8x龜殼/1x粗絲線)x25\n龜殼護腕(8x厚皮/12x龜殼/1x粗絲線)x25\n"}, + { 260, "251-260: 夜色長靴\n(16x厚皮/2x粗絲線)x10" }, + { 270, "261-270: 邪惡皮甲護手\n(8x硬甲皮/1x黑色染料/1x符文線)x10" }, + { 285, "271-285: 邪惡皮甲護腕\n(8x硬甲皮/1x黑色染料/1x符文線)x10" }, + { 300, "286-300: 邪惡皮甲頭環\n(12x硬甲皮/1x黑色染料/1x符文線)x15" }, + { 310, "301-310: 境外皮革\n(5x境外皮革碎片)x10" }, + { 320, "311-320: 野性德萊尼手套\n(9x境外皮革/3x符文線)x10" }, + { 325, "3212-325: 厚重德萊尼長靴\n(10x境外皮革/3x符文線)x5" }, + { 335, "326-335: 厚境外皮革\n(5x境外皮革)x10\n|cFFFFD700千萬別賣掉,你用來繼續升級的!" }, + { 340, "336-340: 厚重德萊尼外套\n(14x境外皮革/3x符文線)x5" }, + { 355, "341-355: 魔化鱗片胸甲\n(14x境外皮革/3x魔化鱗片/3x符文線)x15" }, + { 365, "356-365: 厚重裂蹄長靴\n(4x厚裂締皮/20x厚裂蹄牛皮/4x原始大地/2x符文線)x10\n配方購於:\n芬德雷迅矛:贊格沼澤<79,63>\n|cFFFFD700需要塞納裏奧遠征隊 - 友善\n|cFFFFD700厚裂蹄牛皮在納葛蘭獲取" }, + { 375, "366-375: 戰鬥之鼓\n(6x厚境外皮革/4x厚裂蹄牛皮)x10\n配方購於:\n奧瑪多爾:薩塔斯城<51,41>\n|cFFFFD700需要薩塔 - 尊敬" } + }, + [BI["Engineering"]] = { + { 40, "1-40: 劣質火藥\n(1x劣質的石頭)x40" }, + { 50, "41-50: 一把螺栓\n(1x銅錠)x10" }, + { 51, "51: 扳手\n(6x銅錠)x1" }, + { 65, "52-65: 銅管\n(2x銅錠/1x弱效助熔劑)x14" }, + { 75, "66-75: 劣質火槍\n(1x銅管/1x一把螺栓/1x木柴)x10" }, + { 95, "76-95: 粗制火藥粉\n(1x粗糙的石頭)x20" }, + { 105, "96-105: 銀觸媒\n(1x銀錠)x10" }, + { 120, "106-120: 青銅管\n(2x青銅錠/1x弱效助熔劑)x15" }, + { 125, "121-125: 小型青銅炸彈\n(4x粗制火藥粉/2x青銅錠/1x銀觸媒/1x毛料)x5" }, + { 145, "126-145: 烈性火藥\n(1x沉重的石頭)x20" }, + { 150, "146-150: 重磅青銅炸彈\n(2x烈性火藥/3x青銅錠/1x銀觸媒)x5" }, + { 175, "151-175: 藍色焰火/紅色焰火/綠色焰火\n(1x烈性火藥/1x重皮)x25" }, + { 176, "176: 地精微調器\n(4x鋼錠)x1" }, + { 190, "177-190: 實心炸藥\n(2x堅固的石頭)x14" }, + { 195, "191-195: 重磅鐵制炸彈\n(3x烈性火藥/3x鐵錠/1x銀觸媒)x5" }, + { 205, "196-205: 秘銀管\n(3x秘銀錠)x10" }, + { 210, "206-210: 不牢固的扳機\n(1x秘銀錠/1x魔紋布/1x實心炸藥)x5" }, + { 225, "211-225: 高速秘銀彈頭\n(1x秘銀錠/1x實心炸藥)x15" }, + { 235, "226-235: 秘銀外殼\n(3x秘銀錠)x10" }, + { 245, "236-245: 高爆炸彈\n(2x秘銀外殼/1x不牢固的扳機/2x實心炸藥)x10" }, + { 250, "246-250: 秘銀螺旋彈\n(2x秘銀錠/2x實心炸藥)x5" }, + { 260, "251-260: 緻密炸藥粉\n(2x厚重的石頭)x10" }, + { 290, "261-290: 瑟銀零件\n(3x瑟銀錠/1x符文布)x30" }, + { 300, "291-300: 瑟銀管\n(3x瑟銀錠)x10\n瑟銀彈\n(2x瑟銀錠/1x緻密炸藥粉)x10" }, + { 310, "301-310: 魔鐵外殼\n(3x魔鐵錠)x10\n一把魔鐵螺栓\n(1x魔鐵錠)x10\n元素炸藥粉\n(1x火焰微粒/2x大地微粒)x10\n保留這些東西,為了下一步使用!" }, + { 320, "311-320: 魔鐵炸彈\n(1x魔鐵外殼/2x一把魔鐵螺栓/1x元素炸藥粉)x10" }, + { 335, "321-335: 魔鐵步槍\n(1x沉重的樹幹/3x魔鐵外殼/6x一把魔鐵螺栓)x15" }, + { 350, "336-350: 白色煙幕彈\n(1x元素炸藥粉/1x幽紋布)x15" }, + { 360, "351-360: 克銀能量核心\n(3x克銀錠/1x原始之火)x10\n最好做20個,下一步要用到" }, + { 375, "361-375: 修理機器人110G型\n(8x堅鋼錠/8x一把魔鐵螺栓/1x克銀能量核心)x15\n掉落:甘納格分解者 劍刃山脈" } + }, + [BI["Jewelcrafting"]] = { + { 20, "1-20: 精緻的銅絲\n(2x銅錠)x20" }, + { 30, "21-30: 劣質石像\n(8x劣質的石頭)x10" }, + { 50, "31-50: 虎眼指環\n(1x虎眼石/1x精緻的銅絲)x20" }, + { 75, "51-75: 青銅底座\n(2x青銅錠)x25" }, + { 80, "76-80: 結實的青銅戒指\n(4x青銅錠)x5" }, + { 90, "81-90: 優雅的銀戒指\n(1x銀錠)x10" }, + { 110, "91-110: 銀色力量之戒\n(2x銀錠)x20" }, + { 120, "111-120: 沉重石像\n(8x沉重的石頭)x10" }, + { 150, "121-150: 瑪瑙護盾墜飾\n(1x綠瑪瑙/1x青銅底座)x30\n金色巨龍戒指\n(1x翡翠/2x金錠/2x精緻的銅絲)x30" }, + { 180, "151-180: 秘銀絲邊\n(2x秘銀錠)x30" }, + { 200, "181-200: 蝕刻真銀戒指\n(1x真銀錠/2x秘銀絲邊)x20" }, + { 210, "201-210: 迅疾治療之黃水晶戒指\n(1x黃水晶/2x元素之水/2x秘銀錠)x10" }, + { 225, "211-225: 青綠石徽記\n(3x青綠石/4x魔精)x15" }, + { 250, "226-250: 瑟銀底座\n(1x瑟銀錠)x25" }, + { 255, "251-255: 紅色毀滅指環\n(1x紅寶石/1x瑟銀底座)x5" }, + { 265, "256-265: 真銀治療戒指\n(2x真銀錠/2x野性之心)x10" }, + { 275, "266-275: 樸素的貓眼石戒指\n(1x大貓眼石/1x瑟銀底座)x10" }, + { 285, "276-285: 藍寶石徽記\n(4x藍寶石/2x真銀錠/1x瑟銀底座)x10" }, + { 290, "286-290: 鑽石專注戒指\n(1x艾澤拉斯鑽石/1x瑟銀底座)x5" }, + { 300, "291-300: 翡翠獅王戒指\n(2x巨型綠寶石/1x瑟銀底座)x10" }, + { 310, "301-310: 任何優秀品質的寶石(綠色)x10" }, + { 315, "311-315: 魔鐵血戒\n(1x魔鐵錠/2x血石榴石)x5\n任何優秀品質的寶石(綠色)x5" }, + { 320, "316-320: 任何優秀品質的寶石(綠色)x10" }, + { 325, "321-325: 藍月石指環\n(1x魔鐵錠/2x藍月石/1x翠綠橄欖石)x5" }, + { 335, "326-335: 水銀堅鋼石(升級用到)\n(4x堅鋼粉未/1x原始大地)x10\n任何優秀品質的寶石(綠色)x10" }, + { 350, "336-350: 重型堅鋼戒指\n(1x堅鋼錠/1x水銀堅鋼石)x15" }, + { 355, "351-355: 任何精良品質的寶石(藍色)x5" }, + { 360, "356-360: 世界掉落配方,例如:\n生命紅寶石墜飾\n(4x克銀錠/1x水銀堅鋼石/1x生命紅寶石)x5\n厚重魔鋼項鏈\n(2x魔鋼錠/3x水銀堅鋼石)x5" }, + { 365, "361-365: 秘法護盾指環\n(2x堅鋼錠/8x原始法力)x5\n配方購於:\n奧瑪多爾:薩塔斯城<51,41>\n|cFFFFD700需要薩塔 - 尊敬" }, + { 375, "366-375: 大地風暴鑽石或天火鑽石系列\n世界掉落(精良品質)\n部分可購買,需要薩塔/薩爾瑪/榮譽堡/破碎之日 - 崇敬" } + }, + [BI["Enchanting"]] = { + { 2, "1-2: 符文銅棒\n(1x銅棒/1x奇異之塵/1x次級魔法精華)x1" }, + { 75, "3-75: 附魔護腕 - 初級生命\n(1x奇異之塵)x73" }, + { 85, "76-85: 附魔護腕 - 初級偏斜\n(1x次級魔法精華/1x奇異之塵)x20" }, + { 100, "86-100: 附魔護腕 - 初級耐力\n(3x奇異之塵)x15" }, + { 101, "101: 符文銀棒\n(1x銀棒/6x奇異之塵/3x強效魔法精華/1x符文銅棒)x1" }, + { 105, "102-105: 附魔護腕 - 初級耐力\n(3x奇異之塵)x4" }, + { 120, "106-120: 強效魔法杖\n(1x普通木柴/1x強效魔法精華)x15" }, + { 130, "121-130: 附魔盾牌 - 初級耐力\n(1x次級星界精華/2x奇異之塵)x10" }, + { 150, "131-150: 附魔護腕 - 次級耐力\n(2x靈魂之塵)x20" }, + { 151, "151: 符文金棒\n(1x金棒/1x彩色珍珠/2x強效星界精華/2x靈魂之塵/1x符文銀棒)x1" }, + { 160, "152-160: 附魔護腕 - 次級耐力\n(2x靈魂之塵)x9" }, + { 165, "161-165: 附魔盾牌 - 次級耐力\n(1x次級秘法精華/1x靈魂之塵)x5" }, + { 180, "166-180: 附魔護腕 - 精神\n(1x次級秘法精華)x15" }, + { 200, "181-200: 附魔護腕 - 力量\n(1x幻象之塵)x20" }, + { 201, "201: 符文真銀棒\n(1x真銀棒/1x黑珍珠/2x強效秘法精華/2x幻象之塵/1x符文金棒)x1" }, + { 205, "202-205: 附魔護腕 - 力量\n(1x幻象之塵)x4" }, + { 225, "206-225: 附魔披風 - 強效防禦\n(3x幻象之塵)x20" }, + { 235, "226-235: 附魔手套 - 敏捷\n(1x次級虛空精華/1x幻象之塵)x10" }, + { 245, "236-245: 附魔胸甲 - 超強生命\n(6x幻象之塵)x10" }, + { 250, "246-250: 附魔護腕 - 強效力量\n(2x夢境之塵/1x強效虛空精華)x5" }, + { 270, "251-270: 次級法力之油\n(3x夢境之塵/2x紫蓮花/1x水晶瓶)x20\n配方購於:\n卡妮亞:希利蘇斯<51,39>" }, + { 290, "271-290: 附魔盾牌 - 強效耐力\n(10x夢境之塵)x20\n附魔靴子 - 強效耐力\n(10x夢境之塵)x20" }, + { 291, "291: 符文奧金棒\n(1x奧金棒/1x金珍珠/10x幻影之塵/4x強效不滅精華/1x符文真銀棒/2x大塊魔光碎片)x1" }, + { 300, "292-300: 附魔披風 - 超強防禦\n(8x幻影之塵)x9" }, + { 301, "301: 符文魔鐵棒\n(1x魔鐵棒/4x強效不滅精華/6x大塊魔光碎片/1x符文奧金棒)x1" }, + { 305, "302-305: 附魔披風 - 超強防禦\n(8x幻影之塵)x4" }, + { 315, "306-315: 附魔護腕 - 攻擊\n(6x魔塵)x10" }, + { 325, "316-325: 附魔披風 - 特效護甲\n(8x魔塵)x10\n附魔護腕 - 攻擊\n(6x魔塵)x10" }, + { 335, "326-335: 附魔胸甲 - 特效精神\n(2x強效異界精華)x10" }, + { 340, "336-340: 附魔盾牌 - 特效耐力\n(15x魔塵)x5" }, + { 345, "341-345: 超級巫師之油\n(3x魔塵/1x夢魘根/1x灌魔之瓶)x5\n配方購於:\n盧比夫人:薩塔斯城<63,70>\n琳娜:銀月城<69,24>\n艾苟米斯:埃索達<39,39>\n如果有足夠的夢魘根最好沖到350,這個材料便宜" }, + { 350, "346-350: 附魔手套 - 極效力量\n(12x魔塵/1x強效異界精華)x5" }, + { 351, "351: 符文堅鋼棒\n(1x堅鋼棒/8x強效異界精華/8x大塊棱光碎片/1x原始力量/1x符文魔鐵棒)x1\n配方購於:\n沃德辛:地獄火半島<24,38>\n倫格爾:泰洛卡森林<48,46>" }, + { 360, "352-360: 附魔手套 - 極效力量\n(12x魔塵/1x強效異界精華)x9" }, + { 370, "361-370: 附魔手套 - 法術打擊\n(8x強效異界精華/2x魔塵/2x大塊棱光碎片)x10\n配方購於:\n芬德雷迅矛:贊格沼澤<79,63>\n|cFFFFD700需要塞納裏奧遠征隊 - 崇敬" }, + { 375, "371-375: 附魔戒指 - 治療能量\n(2x大塊棱光碎片/3x強效異界精華/5x魔塵)x5\n配方購於:\n奧瑪多爾:薩塔斯城<51,41>\n|cFFFFD700需要薩塔 - 崇敬" } + }, + [BI["Blacksmithing"]] = { + { 25, "1-25: 劣質磨刀石\n(1x劣質的石頭)x25" }, + { 45, "26-45: 劣質砂輪\n(2x劣質的石頭)x20" }, + { 75, "46-75: 銅質鎖甲腰帶\n(6x銅錠)x30" }, + { 80, "76-80: 粗制砂輪\n(2x粗糙的石頭)x5" }, + { 100, "81-100: 銅質符文腰帶\n(10x銅錠)x20" }, + { 105, "101-105: 銀棒\n(1x銀錠/2x劣質砂輪)x5" }, + { 125, "106-125: 劣質青銅護腿\n(6x青銅錠)x20" }, + { 150, "126-150: 重砂輪\n(3x沉重的石頭)x25" }, + { 155, "151-155: 金棒\n(1x金錠/2x粗制砂輪)x5" }, + { 165, "156-165: 綠鐵護腿\n(8x鐵錠/1x重砂輪/1x綠色染料)x10" }, + { 185, "166-185: 綠鐵護腕\n(6x鐵錠/1x綠色染料)x20" }, + { 200, "186-200: 金鱗護腕\n(5x鋼錠/2x重砂輪)x15" }, + { 210, "201-210: 堅固的砂輪\n(4x堅固的石頭)x10" }, + { 215, "211-215: 金鱗護腕\n(5x鋼錠/2x重砂輪)x5" }, + { 235, "216-235: 鋼質頭盔\n(14x鋼錠/1x堅固的砂輪)x20\n秘銀鱗片護腕(成本低)\n(8x秘銀錠)x20\n配方購於:\n哈爾甘:辛特蘭,鷹巢山<13,44>\n卡爾拉什:悲傷沼澤,斯通納德<45,51>" }, + { 250, "236-250: 秘銀罩帽\n(10x秘銀錠/6x魔紋布)x15\n秘銀馬刺(成本低)\n(4x秘銀錠/3x堅固的砂輪)x15\n配方世界掉落" }, + { 260, "251-260: 緻密磨刀石\n(1x厚重的石頭)x10" }, + { 270, "261-270: 瑟銀腰帶(成本低)\n(12x瑟銀錠/4x紅色能量水晶)x10\n瑟銀護腕(成本低)\n(12x瑟銀錠/4x藍色能量水晶)x10\n以上兩種配方世界掉落\n地鑄護腿 (防具鍛造)\n(16x秘銀錠/2x大地之核)x10\n風鑄護腿(防具鍛造)\n((16x秘銀錠/2x風之氣息))x10\n輕型地鑄利刃(鑄劍大師)\n(12x秘銀錠/4x大地之核)x10\n輕型灰燼鑄錘(鑄錘大師)\n(12x秘銀錠/4x火焰之心)x10\n輕型天鑄戰斧(大師鑄斧)\n(12x秘銀錠/4x風之氣息)x10" }, + { 295, "271-295: 君王鎧甲護腕\n(12x瑟銀錠)x25\n配方任務取得" }, + { 300, "296-300: 君王鎧甲戰靴\n(18x瑟銀錠)x5\n配方任務取得" }, + { 305, "301-305: 魔能平衡石\n(1x魔鐵錠/1x幽紋布)x5" }, + { 320, "306-320: 魔鐵鎧甲腰帶\n(4x魔鐵錠)x15" }, + { 325, "321-325: 魔鐵鎧甲戰靴\n(6x魔鐵錠)x5" }, + { 330, "326-330: 次級結界符文\n(1x堅鋼錠)x5" }, + { 335, "331-335: 魔鐵胸甲\n(10x魔鐵錠)x5" }, + { 340, "336-340: 堅鋼利斧\n(8x堅鋼錠)x5\n配方購於:\n埃隆霍爾曼:薩塔斯城<64,71>\n恩裏德:銀月城<80,36>\n阿爾拉斯:埃索達<61,89>" }, + { 345, "341-345: 次級護盾結界\n(1x堅鋼錠)x5\n配方購於:瑪裏石拳:影月谷,蠻錘要塞<36,55>/羅霍克:地獄火半島,薩爾瑪<53,38>" }, + { 350, "346-350: 堅鋼利斧\n(8x堅鋼錠)x5\n配方購於:\n埃隆霍爾曼:薩塔斯城<64,71>\n恩裏德:銀月城<80,36>\n阿爾拉斯:埃索達<61,89>" }, + { 360, "351-360: 堅鋼平衡石\n(1x堅鋼錠/2x幽紋布)x10\n配方購於:\n芬德雷迅矛:贊格沼澤<79,63>\n|cFFFFD700需要塞納裏奧遠征隊 - 尊敬" }, + { 370, "361-370: 魔鋼手套\n(6x魔鋼錠)x10\n奧奇奈地穴掉落\n烈焰毀滅手套\n(8x魔鐵錠/4x原始之水/4x原始之火)x10\n配方購於:\n軍需官恩達爾林:薩塔斯城<47,25>\n|cFFFFD700需要奧多爾 - 尊敬\n魔化堅鋼腰帶\n(2x特堅鋼錠/8x魔塵/2x大塊棱光碎片)x10\n配方購於:\n軍需官恩努利爾:薩塔斯城<60,64>\n|cFFFFD700需要占星者 - 友善" }, + { 375, "371-375: 魔鋼手套\n(6x魔鋼錠)x5\n奧奇奈地穴掉落\n烈焰毀滅胸甲\n配方購於:\n軍需官恩達爾林:薩塔斯城<47,25>\n(16x魔鐵錠/6x原始之水/4x原始之火)x5\n|cFFFFD700需要奧多爾 - 尊敬\n魔化堅鋼腰帶\n(2x特堅鋼錠/8x魔塵/2x大塊棱光碎片)x5\n配方購於:\n軍需官恩努利爾:薩塔斯城<60,64>\n|cFFFFD700需要占星者 - 友善" } + }, + [BI["Alchemy"]] = { + { 60, "1-60: 初級治療藥水\n(1x寧神花/1x銀葉草/1x空瓶)x60" }, + { 110, "61-110: 次級治療藥水\n(1x初級治療藥水/1x石南草)x50" }, + { 140, "111-140: 治療藥水\n(1x跌打草/1x石南草/1x鉛瓶)x30" }, + { 155, "141-155: 次級法力藥水\n(1x魔皇草/1x荊棘藻/1x空瓶)x15" }, + { 185, "156-185: 強效治療藥水\n(1x活根草/1x皇血草/1x鉛瓶)x30" }, + { 210, "186-210: 敏捷藥劑\n(1x荊棘藻/1x金棘草/1x鉛瓶)x25" }, + { 215, "211-215: 強效防禦藥劑\n(1x野鋼花/1x金棘草/1x鉛瓶)x5" }, + { 230, "216-230: 優質治療藥水\n(1x太陽草/1x卡德加的鬍鬚/1x水晶瓶)x15" }, + { 250, "231-250: 偵測不死生物藥劑\n(1x阿爾薩斯之淚/1x水晶瓶)x20" }, + { 265, "251-265: 強效敏捷藥劑\n(1x太陽草/1x金棘草/1x水晶瓶)x15" }, + { 285, "266-285: 超強法力藥水\n(2x太陽草/2x盲目草/1x水晶瓶)x20" }, + { 300, "286-300: 極效治療藥水\n(2x黃金參/1x山鼠草/1x水晶瓶)x15" }, + { 315, "301-315: 強烈治療藥水\n(1x黃金參/1x魔獄草/1x灌魔之瓶)x15\n極效法力藥水\n(3x夢葉草/2x冰蓋草/1x水晶瓶)x15" }, + { 350, "316-350: 瘋狂煉金師藥水\n(1x水晶瓶/2x拉格維花)x35+\n在335的時候會變黃,但是該配方成本低" }, + { 375, "351-375: 極效昏睡藥水\n(1x譽夢草/1x夢魘根/1x灌魔之瓶)x25\n配方購於:莉莉朗哈格:泰洛卡森林,艾蘭里堡疊<57,53>\n聯達加拉姆巴:劍刃山脈,雷神要塞<51,57>" } + }, + [L["Mining"]] = { + { 65, "1-65: 銅礦\n所有起始地區" }, + { 125, "66-125: 錫礦/銀礦/火岩礦/次級血石礦\n\n火岩礦分佈于瑟根石(濕地)\n很容易升到125" }, + { 175, "126-175: 鐵礦/金礦\n淒涼之地/灰谷/荒蕪之地/阿拉希高地\n奧特蘭克山脈/荊棘谷/悲傷沼澤" }, + { 250, "176-250: 秘銀礦/真銀礦\n詛咒之地/灼熱峽谷/荒蕪之地/辛特蘭\n西瘟疫之地/艾薩拉/冬泉谷/費伍德森林/石爪山脈/塔納利斯" }, + { 300, "251-300: 瑟銀礦\n安戈洛環形山/冬泉谷/詛咒之地/灼熱峽谷\n燃燒平原/東瘟疫之地/西瘟疫之地" }, + { 330, "301-330: 魔鐵礦\n地獄火半島/贊格沼澤" }, + { 375, "331-375: 魔鐵礦/堅鋼礦\n泰洛卡森林/納葛蘭\n所有外域地區均有" } + }, + [L["Herbalism"]] = { + { 50, "1-50: 銀葉草/寧神花\n所有起始地區" }, + { 70, "51-70: 魔皇草/地根草\n貧瘠之地/西部荒野/銀松森林/洛克莫丹/黑海岸" }, + { 100, "71-100: 石南草\n銀松森林/暮色森林/黑海岸/洛克莫丹/赤脊山" }, + { 115, "101-115: 跌打草\n灰谷/石爪山脈/南貧瘠之地/洛克莫丹/赤脊山" }, + { 125, "116-125: 野鋼花\n石爪山脈/阿拉希高地/荊棘谷/南貧瘠之地/千針石林" }, + { 160, "126-160: 皇血草\n灰谷/石爪山脈/濕地/希爾斯布萊德丘陵/悲傷沼澤" }, + { 185, "161-185: 枯葉草\n悲傷沼澤" }, + { 205, "186-205: 卡德加的鬍鬚\n辛特蘭/阿拉希高地/悲傷沼澤" }, + { 230, "206-230: 火焰花\n灼熱峽谷/詛咒之地/塔納利斯" }, + { 250, "231-250: 太陽草\n費伍德森林/菲拉斯/艾薩拉/辛特蘭" }, + { 270, "251-270: 格羅姆之血\n費伍德森林/詛咒之地/瑪諾洛克集會所(淒涼之地)" }, + { 285, "271-285: 夢葉草\n安戈洛環形山/艾薩拉" }, + { 300, "286-300: 瘟疫花\n東瘟疫之地/西瘟疫之地/費伍德森林/\n冰蓋草\n冬泉谷" }, + { 330, "301-330: 魔獄草\n地獄火半島/贊格沼澤" }, + { 375, "331-375: 任何外域植物\n贊格沼澤和泰洛卡森林較集中" } + }, + [L["Skinning"]] = { + { 375, "1-375: 技能等級處以5,\n所獲值對應的可剝皮怪物" } + }, + -- 來源: http://www.almostgaming.com/wowguides/world-of-warcraft-lockpicking-guide + [L["Lockpicking"]] = { + { 85, "1-85: 開鎖練習\n奧瑟爾伐木場,赤脊山(聯盟)\n棘齒城附近的海盜船(部落)" }, + { 150, "86-150: 制毒任務目標怪附近的箱子\n西部荒野(聯盟)/貧瘠之地(部落)" }, + { 185, "151-185: 魚人營地(濕地)" }, + { 225, "186-225: 薩瑟裏斯海岸(淒涼之地)\n" }, + { 250, "226-250: 苦痛堡壘(荒蕪之地)" }, + { 275, "251-275: 熔渣之池(灼熱峽谷)" }, + { 300, "276-300: 落帆海灣(塔納利斯)\n風暴海灣(艾薩拉)" }, + { 325, "301-325: 蠻沼村(贊格沼澤)" }, + { 350, "326-350: 基爾索羅堡壘(納葛蘭)\n偷取石拳系巨魔(納葛蘭)" } + }, + + -- ** 輔助技能 ** + [BI["First Aid"]] = { + { 40, "1-40: 亞麻繃帶" }, + { 80, "41-80: 厚亞麻繃帶\n50的時候學急救(中級)" }, + { 115, "81-115: 絨線繃帶" }, + { 150, "116-150: 厚絨線繃帶\n125的時候去買教材<中級急救教材 - 繃帶縛體>和2個配方\n配方購於:\n德尼布沃克:阿拉希高地,激流堡<27,58>\n格魯克卡恩:塵泥沼澤,蕨牆村<35,30>\n巴萊洛克維:塵泥沼澤,蕨牆村<36,30>" }, + { 180, "151-180: 絲質繃帶" }, + { 210, "181-210: 厚絲質繃帶\n200的時候滿35級,做任務學會急救(專家級)\n地點:塞拉摩島(聯盟)/落錘鎮(部落)" }, + { 240, "211-240: 魔紋繃帶\n" }, + { 260, "241-260: 厚魔紋繃帶" }, + { 290, "261-290: 符文布繃帶" }, + { 330, "291-330: 厚符文布繃帶\n300的時候去買教材<大師級急救手冊 - 私人醫生>\n配方購於:\n阿蕾瑟拉:地獄火半島,塔哈瑪特神殿<26,62>\n布林庫:地獄火半島,獵鷹崗哨<22,39>" }, + { 360, "331-360: 幽紋布繃帶\n購買<手冊:幽紋布繃帶>\n配方購於:\n阿蕾瑟拉:地獄火半島,塔哈瑪特神殿<26,62>\n布林庫:地獄火半島,獵鷹崗哨<22,39>" }, + { 375, "361-375: 厚幽紋布繃帶\n購買<手冊:厚幽紋布繃帶>\n配方購於:\n阿蕾瑟拉:地獄火半島,塔哈瑪特神殿<26,62>\n布林庫:地獄火半島,獵鷹崗哨<22,39>" } + }, + [BI["Cooking"]] = { + { 40, "1-40: 香料麵包\n(1x麵粉/1x甜香料)x70" }, + { 75, "41-75: 熏熊肉\n(1x熊肉)x30\n配方購於:\n德拉克卷刃:洛克莫丹<35,49>\n安德魯希爾伯特:銀松森林<43,40>" }, + { 85, "76-85: 蟹肉蛋糕(聯盟)\n(1x蟹肉, 1x甜香料)x10\n熏熊肉(部落)\n(1x熊肉)x20\n配方購於:\n德拉克卷刃:洛克莫丹<35,49>\n安德魯希爾伯特:銀松森林<43,40>" }, + { 90, "86-90: 煮蟹爪(聯盟)\n(1x蟹爪, 1x甜香料)x5\n配方購於:\n肯多爾卡邦卡:暴風城<74,36>\n熏熊肉(部落)\n(1x熊肉)x10\n配方購於:\n德拉克卷刃:洛克莫丹<35,49>\n安德魯希爾伯特:銀松森林<43,40>" }, + { 100, "91-100: 煮蟹爪(聯盟)\n(1x蟹爪/1x甜香料)x15\n配方購於:\n肯多爾卡邦卡:暴風城<74,36>\n掘地鼠燉肉(部落)\n(1x掘地鼠)x10\n配方任務獲取:[23]掘地鼠燉肉" }, + { 125, "101-125: 掘地鼠燉肉(部落)\n(1x掘地鼠)x30\n配方任務獲取:[23]掘地鼠燉肉\n幹烤狼肉串(聯盟)\n(2x狼肋排/1x暴風城特產調料)x25\n配方購於:\n肯多爾卡邦卡:暴風城<74,36>" }, + { 130, "126-130: 烤獅排(部落)\n(1x獅肉/1x辣椒)x5\n配方購於:\n紮爾夫:貧瘠之地<52,29>\n幹烤狼肉串(聯盟)\n(2x狼肋排/1x暴風城特產調料)x25\n配方購於:\n肯多爾卡邦卡:暴風城<74,36>" }, + { 175, "131-175: 美味煎蛋捲(聯盟)\n(1x迅猛龍蛋/1x辣椒)x50\n配方購於:\n肯多爾卡邦卡:暴風城<74,36>\n烤獅排(部落)\n(1x獅肉/1x辣椒)x55\n配方購於:\n紮爾夫:貧瘠之地<52,29>" }, + { 200, "176-200: 烤迅猛龍肉\n(1x迅猛龍肉/1x辣椒)x30\n配方購於:\n耐裏斯特:荊棘谷,格羅姆高營地<32,29>\n布魯斯下士:荊棘谷,反抗軍營地<37,3>" }, + { 225, "201-225: 蜘蛛肉腸\n(2x白蜘蛛肉)x30\n\n|cFFFFFFFF225接到烹飪大師任務: 迪爾格奎克裏弗:加基森<51,27>給予\n|cFFFFD700需要12個巨蛋/10個美味的蚌肉/20個奧特蘭克冷酪" }, + { 275, "226-275: 超級煎蛋捲\n(1x巨蛋/2x舒心草)x80\n配方購於:\n琦亞:冬泉谷,永望鎮<61,37>\n西米克:冬泉谷,永望鎮<61,39>\n拜爾:費伍德森林,血毒崗哨<34,53>\n瑪裏甘:費伍德森林,刺枝林地<62,25>\n嫩狼肉排\n(1x嫩狼肉/1x舒心草)x80\n配方購於:\n迪爾格奎克裏弗:塔納利斯,加基森<52,28>\n特魯克蠻鬃:辛特蘭,鷹巢山<14,42>" }, + { 285, "276-285: 洛恩塔姆薯塊\n(1x洛恩塔姆地薯/1x舒心草)x10\n掉落:普希林 厄運之槌" }, + { 300, "286-300: 沙漠肉丸子\n(1x沙蟲的肉/1x舒心草)x20\n希利蘇斯任務(旅店老闆)" }, + { 325, "301-325: 掠食者熱狗\n(1x掠食者的肉)x40\n配方購於:\n獨眼曲奇:地獄火半島,薩爾瑪<54,41>\n希德利巴迪:地獄火半島,榮譽堡<54,63>\n美味禿鷲\n(1x禿鷹肉)x40\n來源:任務 [61]萬無一失" }, + { 350, "326-350: 燒烤裂蹄牛\n(1x裂蹄牛肉)x40\n配方購於:\n屠夫努爾拉:納葛蘭,加拉達爾<58,35>\n烏利庫:納葛蘭,泰拉<56,73>\n扭曲漢堡\n(1x扭曲肉塊)x40\n配方購於:\n屠夫努爾拉:納葛蘭,加拉達爾<58,35>\n烏利庫:納葛蘭,泰拉<56,73>\n旅店老闆格裏爾卡:泰洛卡森林,裂石堡<48,45>\n供給官米爾斯:泰洛卡森林,艾蘭里堡疊<55,53>\n塔布肉排\n(1x塔布羊肉)x40\n配方購於:\n屠夫努爾拉:納葛蘭,加拉達爾<58,35>\n烏利庫:納葛蘭,泰拉<56,73>" }, + { 375, "351-375: 香辣小龍蝦\n(1x狂暴龍蝦)x25\n配方購於:\n旅店老闆貝莉比:泰洛卡森林,艾蘭里堡疊<56,53>\n倫格爾:泰洛卡森林,裂石堡<48,46>\n此處建議和釣魚一起練\n莫克納薩肋排\n(1x迅猛龍肋排)x60\n香脆蛇\n(1x蛇肉)x60c\n以上兩個配方來源:\n任務 [67]莫克納薩的美味(部落)\n購買:薩莎焊井:劍刃山脈,托雷斯營地<61,68>" } + }, + -- 來源: http://www.wowguideonline.com/fishing.html + [BI["Fishing"]] = { + { 50, "1-50: 任何起始地點" }, + { 75, "51-75:\n暴風城的河裏\n奧格瑞瑪的池塘裏" }, + { 150, "76-150: 希爾斯布萊德丘陵的河裏" }, + { 225, "151-225: 淒涼之地/阿拉希高地\n150的時候購買<中級釣魚教材 - 鱸魚與你>\n配方購於:\n老人海明威:藏寶海灣<27,77>" }, + { 250, "226-250: 辛特蘭/塔納利斯\n\n|cFFFFFFFF225開始高級釣魚任務\n起始於各個主城,均到納特帕格:塵泥沼澤<59,61>\n|cFFFFD700野人海岸藍色叉牙魚(荊棘谷<34,35>)\n菲拉斯草魚(沃丹提斯河, 菲拉斯)\n薩瑟裏斯虎魚(薩瑟裏斯海岸北部, 葬影村附近, 淒涼之地)\n蘆葦海岸大馬哈魚(蘆葦海岸, 悲傷沼澤)" }, + { 260, "251-260: 費伍德森林" }, + { 300, "261-300: 艾薩拉" }, + { 330, "301-330: 贊格沼澤東部\n300的時候購買<頂級釣魚教材 - 下鉤的藝術>\n配方購於:\n喬諾杜伏恩:塞納裏奧避難所<78,66>" }, + { 345, "331-345: 贊格沼澤西部" }, + { 360, "346-360: 泰洛卡森林" }, + { 375, "361-375: 泰洛卡森林,高地上:\n尤魯恩湖, 裂石堡西北方\n艾雷諾湖, 艾蘭里堡疊東南方\n黑風湖, 司凱堤斯地區\n需要飛行坐騎" } + }, + + -- 建議升級地區,來源眾多,不一一列舉了 + ["Leveling"] = { + { 10, "1-10級: 所有起始地區" }, + { 20, "11-20級: " .. BZ["Loch Modan"] .. "\n" .. BZ["Westfall"] .. "\n" .. BZ["Darkshore"] .. "\n" .. BZ["Bloodmyst Isle"] + .. "\n" .. BZ["Silverpine Forest"] .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Ghostlands"]}, + { 25, "21-25級: " .. BZ["Wetlands"] .. "\n" .. BZ["Redridge Mountains"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["The Barrens"] .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Hillsbrad Foothills"] }, + { 28, "26-28級: " .. BZ["Duskwood"] .. "\n" .. BZ["Wetlands"] .. "\n" .. BZ["Ashenvale"] + .. "\n" .. BZ["Stonetalon Mountains"] .. "\n" .. BZ["Thousand Needles"] }, + { 31, "29-31級: " .. BZ["Duskwood"] .. "\n" .. BZ["Thousand Needles"] .. "\n" .. BZ["Ashenvale"] }, + { 35, "32-35級: " .. BZ["Thousand Needles"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Alterac Mountains"] + .. "\n" .. BZ["Arathi Highlands"] .. "\n" .. BZ["Desolace"] }, + { 40, "36-40級: " .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Desolace"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 43, "41-43級: " .. BZ["Tanaris"] .. "\n" .. BZ["Stranglethorn Vale"] .. "\n" .. BZ["Badlands"] + .. "\n" .. BZ["Dustwallow Marsh"] .. "\n" .. BZ["Swamp of Sorrows"] }, + { 45, "44-45級: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] }, + { 48, "46-48級: " .. BZ["Tanaris"] .. "\n" .. BZ["Feralas"] .. "\n" .. BZ["The Hinterlands"] .. "\n" .. BZ["Searing Gorge"] }, + { 51, "49-51級: " .. BZ["Tanaris"] .. "\n" .. BZ["Azshara"] .. "\n" .. BZ["Blasted Lands"] + .. "\n" .. BZ["Searing Gorge"] .. "\n" .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] }, + { 55, "54-55級: " .. BZ["Un'Goro Crater"] .. "\n" .. BZ["Felwood"] .. "\n" .. BZ["Burning Steppes"] + .. "\n" .. BZ["Blasted Lands"] .. "\n" .. BZ["Western Plaguelands"] }, + { 58, "56-58級: " .. BZ["Winterspring"] .. "\n" .. BZ["Burning Steppes"] .. "\n" .. BZ["Western Plaguelands"] + .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 60, "59-60級: " .. BZ["Winterspring"] .. "\n" .. BZ["Eastern Plaguelands"] .. "\n" .. BZ["Silithus"] }, + { 62, "61-62級: " .. BZ["Hellfire Peninsula"] }, + { 64, "63-64級: " .. BZ["Zangarmarsh"] .. "\n" .. BZ["Terokkar Forest"]}, + { 65, "65級: " .. BZ["Terokkar Forest"] }, + { 66, "66級: " .. BZ["Terokkar Forest"] .. "\n" .. BZ["Nagrand"]}, + { 67, "67級: " .. BZ["Nagrand"]}, + { 68, "68級: " .. BZ["Blade's Edge Mountains"]}, + { 70, "69-70級: " .. BZ["Blade's Edge Mountains"] .. "\n" .. BZ["Netherstorm"] .. "\n" .. BZ["Shadowmoon Valley"]}, + { 72, "72級: " .. BZ["Howling Fjord"] .. "\n" .. BZ["Borean Tundra"]}, + { 74, "74級: " .. BZ["Grizzly Hills"] .. "\n" .. BZ["Dragonblight"]}, + { 76, "76級: " .. BZ["Dragonblight"] .. "\n" .. BZ["Zul'Drak"]}, + { 78, "78級: " .. BZ["Zul'Drak"] .. "\n" .. BZ["Sholazar Basin"]}, + { 80, "80級: " .. BZ["The Storm Peaks"] .. "\n" .. BZ["Icecrown"]}, + }, + + -- 聲望值級別 + -- -42000 = "仇恨" + -- -6000 = "敵對" + -- -3000 = "冷淡" + -- 0 = "中立" + -- 3000 = "友善" + -- 9000 = "尊敬" + -- 21000 = "崇敬" + -- 42000 = "崇拜" + + -- Outland factions: source: http://www.mmo-champion.com/ + [BF["The Aldor"]] = { + { 0, "升到中立:\n" .. WHITE .. "[懼牙毒囊]|r +250 聲望值\n\n" + .. YELLOW .. "懼牙潛伏者,\n懼牙寡婦蛛\n" + .. WHITE .. "(泰洛卡森林)" }, + { 9000, "升到尊敬:\n" .. WHITE .. "[基爾加丹印記]|r\n+25 聲望值" }, + { 42000, "升到崇拜:\n" .. WHITE .. "[薩格拉斯印記]|r +25 聲望值/每枚\n" + .. GREEN .. "[魔化武器]|r +350 聲望值 (+1 神聖之塵)" } + }, + [BF["The Scryers"]] = { + { 0, "升到中立:\n" .. WHITE .. "[濕鱗蜥蜴的眼睛]|r +250 聲望值\n\n" + .. YELLOW .. "鐵脊石化者,\n濕鱗吞噬者,\n濕鱗蜥蜴\n" + .. WHITE .. "(泰洛卡森林)" }, + { 9000, "升到尊敬:\n" .. WHITE .. "[火翼徽記]|r\n+25 聲望值" }, + { 42000, "升到崇拜:\n" .. WHITE .. "[日怒徽記]|r +25 聲望值 per mark\n" + .. GREEN .. "[秘法寶典]|r +350 聲望值 (+1 秘法符文)" } + }, + [BF["Netherwing"]] = { + { 3000, "升到友善, 重複以下任務:\n\n" + .. YELLOW .. "慢速死亡 (每日)|r +250 聲望值\n" + .. YELLOW.. "虛空之塵花粉 (每日)|r +250 聲望值\n" + .. YELLOW.. "虛空之翼水晶 (每日)|r +250 聲望值\n" + .. YELLOW.. "不太友善的航線 (每日)|r +250 聲望值\n" + .. YELLOW.. "尋找虛空之翼龍卵 (可重複提交)|r +250 聲望值" }, + { 9000, "升到尊敬, 重複以下任務:\n\n" + .. YELLOW .. "新的監工:正確的選擇|r +350 聲望值\n" + .. YELLOW .. "迴力靴:專治沒用的苦工 (每日)|r +350 聲望值\n" + .. YELLOW .. "拾起貨品 (每日)|r +350 聲望值\n" + .. YELLOW .. "龍的問題不算什麼 (每日)|r +350 聲望值\n" + .. YELLOW .. "瘋狂與困惑|r +350 聲望值\n" }, + { 21000, "升到崇敬, 重複以下任務:\n\n" + .. YELLOW .. "征服者雷薩赫爾頓|r +500 聲望值\n" + .. YELLOW .. "瓦解暮光傳送門 (每日)|r +500 聲望值\n" + .. YELLOW .. "你的雙翼 +500 聲望值(1-5號), +1000 聲望值(6號)\n" }, + { 42000, "升到崇拜, 重複以下任務:\n\n" + .. YELLOW .. "史上最致命的陷阱 (每日) (3+)|r +500 聲望值" } + }, + [BF["Honor Hold"]] = { + { 9000, "升到尊敬:\n\n" + .. YELLOW .. "地獄火半島的任務\n" + .. GREEN .. "地獄火壁壘 |r(普通)\n" + .. GREEN .. "血熔爐 |r(普通)" }, + { 42000, "升到崇拜:\n\n" + .. GREEN .. "破碎大廳 |r(普通或英雄)\n" + .. GREEN .. "地獄火壁壘 |r(英雄)\n" + .. GREEN .. "血熔爐 |r(英雄)" } + }, + [BF["Thrallmar"]] = { + { 9000, "升到尊敬:\n\n" + .. YELLOW .. "地獄火半島的任務\n" + .. GREEN .. "地獄火壁壘 |r(普通)\n" + .. GREEN .. "血熔爐 |r(普通)" }, + { 42000, "升到崇拜:\n\n" + .. GREEN .. "破碎大廳 |r(普通或英雄)\n" + .. GREEN .. "地獄火壁壘 |r(英雄)\n" + .. GREEN .. "血熔爐 |r(英雄)" } + }, + [BF["Cenarion Expedition"]] = { + { 3000, "升到友善:\n\n" + .. WHITE .. "暗潮納迦或者血鱗納迦 (+5 聲望值)\n" + .. YELLOW .. "贊格沼澤的任務\n" + .. "|r殺入任意 " .. GREEN .. "盤牙洞穴|r 的副本\n\n" + .. WHITE .. "保存 [未鑒定過的植物] 為稍後上繳" }, + { 9000, "升到尊敬:\n\n" + .. WHITE .. "上繳 [未鑒定過的植物] x240\n" + .. YELLOW .. "贊格沼澤的任務\n" + .. "|r殺入任意 " .. GREEN .. "盤牙洞穴|r 的副本" }, + { 42000, "升到崇拜:\n\n" + .. WHITE .. "上繳 [盤牙裝備] +75 聲望值\n\n" + .. GREEN .. "蒸汽洞窟 |r(普通)\n" + .. GREEN .. "任何盤牙洞穴的副本 |r(英雄)" } + }, + [BF["Keepers of Time"]] = { + { 42000, "升到崇拜:\n\n" + .. "|r殺入 " .. GREEN .. "舊希爾斯布萊德丘陵|r 和 " .. GREEN .. "黑色沼澤|r 副本\n\n" + .. YELLOW .. "最後交任務:\n'舊希爾斯布萊德丘陵'任務線共計 5000 聲望值\n'黑色沼澤'任務線共計 8000 聲望值" } + }, + [BF["The Sha'tar"]] = { + { 42000, "升到崇拜:\n\n" + .. GREEN .. "波塔尼卡 |r(普通或英雄)\n" + .. GREEN .. "麥克那爾 |r(普通或英雄)\n" + .. GREEN .. "亞克崔茲 |r(普通或英雄)\n" } + }, + [BF["Lower City"]] = { + { 9000, "升到尊敬:\n\n" + .. WHITE .. "上繳 [阿拉卡羽毛]x30 (+250 聲望值)\n" + .. GREEN .. "暗影迷宮 |r(普通)\n" + .. GREEN .. "奧奇奈地穴 |r(普通)\n" + .. GREEN .. "塞司克大廳 |r(普通)" }, + { 42000, "升到崇拜:\n\n" + .. GREEN .. "暗影迷宮 |r(普通或英雄)\n" + .. GREEN .. "奧奇奈地穴 |r(英雄)\n" + .. GREEN .. "塞司克大廳 |r(英雄)" } + }, + [BF["The Consortium"]] = { + { 3000, "升到友善:\n\n" + .. "|r上繳 [沃舒古水晶碎片] +250 聲望值\n" + .. "上繳 [象牙] +250 聲望值\n\n" + .. GREEN .. "法力墓地 |r(普通)" }, + { 9000, "升到尊敬:\n\n" + .. "|r上繳 [黑曜石戰爭珠串] +250 聲望值\n\n" + .. GREEN .. "法力墓地 |r(普通)" }, + { 42000, "升到崇拜:\n\n" + .. "|r上繳 [薩克希斯徽記] +250 聲望值\n" + .. "|r上繳 [黑曜石戰爭珠串] +250 聲望值\n\n" + .. GREEN .. "法力墓地 |r(英雄)" } + }, + [BF["Shattered Sun Offensive"]] = { + { 42000, "升到崇拜:\n\n" + .. YELLOW .. "完成奎爾達納斯島和薩塔斯城的相關每日任務" } + }, + [BF["The Mag'har"]] = { + { 42000, "升到崇拜:\n\n" + .. "|r上繳 [黑曜石戰爭珠串] +250 聲望值\n\n" + .. WHITE .. "納葛蘭和泰洛卡森林的任何巨魔 (+5-11 聲望值)\n" + .. YELLOW .. "完成納葛蘭的任務" } + }, + [BF["Kurenai"]] = { + { 42000, "升到崇拜:\n\n" + .. "|r上繳 [黑曜石戰爭珠串] +250 聲望值\n\n" + .. WHITE .. "納葛蘭和泰洛卡森林的任何巨魔 (+5-11 聲望值)\n" + .. YELLOW .. "完成納葛蘭的任務" } + }, + [BF["Sporeggar"]] = { + { 0, "升到中立:\n\n" + .. "上繳 [成熟的孢子] 或者 [沼澤領主觸鬚] +250 聲望值\n\n" + .. YELLOW .. "沼澤領主,\n打開[孢子囊]\n" + .. WHITE .. "(贊格沼澤)" }, + { 3000, "升到友善:\n\n" + .. "上繳 [白閃菇] +250 聲望值\n\n" + .. "上繳 [成熟的孢子] 或者 [沼澤領主觸鬚] +250 聲望值\n\n" + .. YELLOW .. "沼澤領主,\n打開[孢子囊]\n" + .. WHITE .. "(贊格沼澤)" }, + { 42000, "升到崇拜:\n\n" + .. WHITE .. "上繳 [紅色木槿] +250 聲望值\n\n" + .. GREEN .. "深幽泥澤 |r(普通或者英雄)\n" + .. "上繳 [成熟的孢子] +250 聲望值\n\n" + .. YELLOW .. "現在 我們是朋友了… (可重複)|r +250 聲望值\n" } + }, + [BF["Sha'tari Skyguard"]] = { + { 42000, "升到崇拜, 重複以下任務:\n\n" + .. YELLOW.. "轟炸司凱堤斯 (每日)|r +350 聲望值\n" + .. YELLOW.. "逃離司凱堤斯 (每日)|r +350 聲望值\n" + .. YELLOW.. "敵人的血 (可重複)|r +350 聲望值\n" + .. YELLOW.. "召喚泰洛卡 (可重複)|r +350 聲望值\n" + .. WHITE .. "(司凱堤斯)" + .. YELLOW.. "再度轟炸 (每日)|r +500 聲望值\n" + .. YELLOW.. "捆綁更多蒼穹鰭刺 (每日)|r +500 聲望值\n" + .. YELLOW.. "聖物的增益 (每日)|r +350 聲望值\n" + .. YELLOW.. "放逐更多惡魔 (每日)|r +350 聲望值\n" + .. WHITE .. "(劍刃山脈)"}, + }, + [BF["Ogri'la"]] = { + { 42000, "升到崇拜, 重複以下任務:\n\n" + .. YELLOW.. "再度轟炸 (每日)|r +500 聲望值\n" + .. YELLOW.. "捆綁更多蒼穹鰭刺 (每日)|r +500 聲望值\n" + .. YELLOW.. "聖物的增益 (每日)|r +350 聲望值\n" + .. YELLOW.. "放逐更多惡魔 (每日)|r +350 聲望值\n" + .. WHITE .. "(劍刃山脈)"}, + } +} + diff --git a/Altoholic-Addon/Altoholic/Tasks.lua b/Altoholic-Addon/Altoholic/Tasks.lua new file mode 100644 index 0000000..dd1d4dd --- /dev/null +++ b/Altoholic-Addon/Altoholic/Tasks.lua @@ -0,0 +1,57 @@ +-- Simple task manager +-- Written by : Thaoky, EU-Marécages de Zangar + +local addon = Altoholic +addon.Tasks = {} + +function addon.Tasks:Init() + self.List = self.List or {} + wipe(self.List) +end + +function addon.Tasks:OnUpdate(elapsed) + for name, task in pairs(self.List) do + task.delay = task.delay - elapsed + if task.delay <= 0 then + if task.func then + if not task.func(task.owner, elapsed) then + -- execute the task, if it doesn't return anything, delete it. + -- if it does, keep it in the list, and execute it in every pass (set a delay of 0). + -- if necessary, reschedule by updating the delay + -- The function is responsible for returning the right value + self:Remove(name) + end + end + end + end +end + +function addon.Tasks:Add(name, delay, func, owner) + if not self.List[name] then + self.List[name] = {} + end + + local p = self.List[name] + p.delay = delay -- time before executing the task + p.func = func -- function pointer to the task + p.owner = owner -- owner (table or frame) +end + +function addon.Tasks:Remove(name) + local p = self.List[name] + if p then + wipe(p) + self.List[name] = nil + end +end + +function addon.Tasks:Get(name) + return self.List[name] +end + +function addon.Tasks:Reschedule(name, delay) + local p = self.List[name] + if p then + p.delay = delay -- time before executing the task + end +end diff --git a/Altoholic-Addon/Altoholic/Tooltip.lua b/Altoholic-Addon/Altoholic/Tooltip.lua new file mode 100644 index 0000000..f8d9f22 --- /dev/null +++ b/Altoholic-Addon/Altoholic/Tooltip.lua @@ -0,0 +1,636 @@ +local addonName = ... +local addon = _G[addonName] +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() + +local WHITE = "|cFFFFFFFF" +local RED = "|cFFFF0000" +local GREEN = "|cFF00FF00" +local YELLOW = "|cFFFFFF00" +local ORANGE = "|cFFFF7F00" +local TEAL = "|cFF00FF9A" +local GOLD = "|cFFFFD700" + +local THIS_ACCOUNT = "Default" + +local Orig_GameTooltip_OnShow +local Orig_GameTooltip_SetItem +local Orig_GameTooltip_ClearItem +-- local Orig_GameTooltip_SetSpell + +local Orig_ItemRefTooltip_OnShow +local Orig_ItemRefTooltip_SetItem +local Orig_ItemRefTooltip_ClearItem +-- local Orig_ItemRefTooltip_SetSpell + +local GatheringNodes = { -- Add herb/ore possession info to Plants/Mines, thanks to Tempus on wowace for gathering this. + + -- Mining nodes + [L["Adamantite Deposit"]] = 23425, -- Adamantite Ore + [L["Copper Vein"]] = 2770, -- Copper Ore + [L["Dark Iron Deposit"]] = 11370, -- Dark Iron Ore + [L["Fel Iron Deposit"]] = 23424, -- Fel Iron Ore + [L["Gold Vein"]] = 2776, -- Gold Ore + [L["Hakkari Thorium Vein"]] = 10620, -- Thorium Ore + [L["Iron Deposit"]] = 2772, -- Iron Ore + [L["Khorium Vein"]] = 23426, -- Khorium Ore + [L["Mithril Deposit"]] = 3858, -- Mithril Ore + [L["Ooze Covered Gold Vein"]] = 2776, -- Gold Ore + [L["Ooze Covered Mithril Deposit"]] = 3858, -- Mithril Ore + [L["Ooze Covered Rich Thorium Vein"]] = 10620, -- Thorium Ore + [L["Ooze Covered Silver Vein"]] = 2775, -- Silver Ore + [L["Ooze Covered Thorium Vein"]] = 10620, -- Thorium Ore + [L["Ooze Covered Truesilver Deposit"]] = 7911, -- Truesilver Ore + [L["Rich Adamantite Deposit"]] = 23425, -- Adamantite Ore + [L["Rich Thorium Vein"]] = 10620, -- Thorium Ore + [L["Silver Vein"]] = 2775, -- Silver Ore + [L["Small Thorium Vein"]] = 10620, -- Thorium Ore + [L["Tin Vein"]] = 2771, -- Tin Ore + [L["Truesilver Deposit"]] = 7911, -- Truesilver Ore + + [L["Lesser Bloodstone Deposit"]] = 4278, -- Lesser Bloodstone Ore + [L["Incendicite Mineral Vein"]] = 3340, -- Incendicite Ore + [L["Indurium Mineral Vein"]] = 5833, -- Indurium Ore + [L["Nethercite Deposit"]] = 32464, -- Nethercite Ore + [L["Large Obsidian Chunk"]] = 22203, -- Large Obsidian Shard Both drop on both nodes.. + [L["Small Obsidian Chunk"]] = 22202, -- Small Obsidian Shard + + -- wotlk + ["Cobalt Deposit"] = 36909, -- Cobalt Ore + ["Rich Cobalt Deposit"] = 36909, -- Cobalt Ore + ["Saronite Deposit"] = 36912, -- Saronite Ore + ["Rich Saronite Deposit"] = 36912, -- Saronite Ore + ["Titanium Vein"] = 36910, -- Titanium Ore + + -- Herbs + [L["Ancient Lichen"]] = 22790, + [L["Arthas' Tears"]] = 8836, + [L["Black Lotus"]] = 13468, + [L["Blindweed"]] = 8839, + [L["Bloodthistle"]] = 22710, + [L["Briarthorn"]] = 2450, + [L["Bruiseweed"]] = 2453, + [L["Dreamfoil"]] = 13463, + [L["Dreaming Glory"]] = 22786, + [L["Earthroot"]] = 2449, + [L["Fadeleaf"]] = 3818, + [L["Felweed"]] = 22785, + [L["Firebloom"]] = 4625, + [L["Flame Cap"]] = 22788, + [L["Ghost Mushroom"]] = 8845, + [L["Golden Sansam"]] = 13464, + [L["Goldthorn"]] = 3821, + [L["Grave Moss"]] = 3369, + [L["Gromsblood"]] = 8846, + [L["Icecap"]] = 13467, + [L["Khadgar's Whisker"]] = 3358, + [L["Kingsblood"]] = 3356, + [L["Liferoot"]] = 3357, + [L["Mageroyal"]] = 785, + [L["Mana Thistle"]] = 22793, + [L["Mountain Silversage"]] = 13465, + [L["Netherbloom"]] = 22791, + [L["Nightmare Vine"]] = 22792, + [L["Peacebloom"]] = 2447, + [L["Plaguebloom"]] = 13466, + [L["Purple Lotus"]] = 8831, + [L["Ragveil"]] = 22787, + [L["Silverleaf"]] = 765, + [L["Stranglekelp"]] = 3820, + [L["Sungrass"]] = 8838, + [L["Terocone"]] = 22789, + [L["Wild Steelbloom"]] = 3355, + [L["Wintersbite"]] = 3819, + + [L["Glowcap"]] = 24245, + [L["Netherdust Bush"]] = 32468, -- Netherdust Pollen + [L["Sanguine Hibiscus"]] = 24246, + + ["Fel Lotus"] = 22794, + ["Goldclover"] = 36901, + ["Adder's Tongue"] = 36903, + ["Tiger Lily"] = 36904, + ["Lichbloom"] = 36905, + ["Icethorn"] = 36906, + ["Talandra's Rose"] = 36907, + ["Frost Lotus"] = 36908, + ["Firethorn"] = 39970, +} + +-- *** Utility functions *** +local function IsGatheringNode(name) + if name then + for k, v in pairs(GatheringNodes) do + if name == k then -- returns the itemID if "name" is a known type of gathering node (mines & herbs) + return v + end + end + end +end + +local function GetCraftNameFromRecipeLink(link) + -- get the craft name from the itemlink (strsplit on | to get the 4th value, then split again on ":" ) + local recipeName = select(4, strsplit("|", link)) + local craftName + + -- try to determine if it's a transmute (has 2 colons in the string --> Alchemy: Transmute: blablabla) + local pos = string.find(recipeName, L["Transmute"]) + if pos then -- it's a transmute + return string.sub(recipeName, pos, -2) + else + craftName = select(2, strsplit(":", recipeName)) + end + + if craftName == nil then -- will be nil for enchants + return string.sub(recipeName, 3, -2) -- ex: "Enchant Weapon - Striking" + end + + return string.sub(craftName, 2, -2) -- at this point, get rid of the leading space and trailing square bracket +end + +local isTooltipDone, isNodeDone -- for informant +local cachedItemID, cachedCount, cachedTotal, cachedSource +local cachedRecipeOwners + +local itemCounts = {} +local itemCountsLabels = { L["Bags"], L["Bank"], L["AH"], L["Equipped"], L["Mail"], CURRENCY } +local counterLines = {} -- list of lines containing a counter to display in the tooltip + +local function AddCounterLine(owner, counters) + table.insert(counterLines, { ["owner"] = owner, ["info"] = counters } ) +end + +local function WriteCounterLines(tooltip) + if #counterLines == 0 then return end + + if (addon.Options:Get("TooltipCount") == 1) then -- add count per character/guild + tooltip:AddLine(" ",1,1,1); + for _, line in ipairs (counterLines) do + tooltip:AddDoubleLine(line.owner, TEAL .. line.info); + end + end +end + +local function WriteTotal(tooltip) + if (addon.Options:Get("TooltipTotal") == 1) and cachedTotal then + tooltip:AddLine(cachedTotal,1,1,1); + end +end + +local function GetCharacterItemCount(character, searchedID) + itemCounts[1], itemCounts[2] = DataStore:GetContainerItemCount(character, searchedID) + itemCounts[3] = DataStore:GetAuctionHouseItemCount(character, searchedID) + itemCounts[4] = DataStore:GetInventoryItemCount(character, searchedID) + itemCounts[5] = DataStore:GetMailItemCount(character, searchedID) + itemCounts[6] = DataStore:GetCurrencyItemCount(character, searchedID) + + local charCount = 0 + for _, v in pairs(itemCounts) do + charCount = charCount + v + end + + if charCount > 0 then + local account, _, char = strsplit(".", character) + local name = DataStore:GetColoredCharacterName(character) or char -- if for any reason this char isn't in DS_Characters.. use the name part of the key + if account ~= THIS_ACCOUNT then + name = name .. YELLOW .. " (" .. account .. ")" + end + + local t = {} + for k, v in pairs(itemCounts) do + if v > 0 then -- if there are more than 0 items in this container + table.insert(t, WHITE .. itemCountsLabels[k] .. ": " .. TEAL .. v) + end + end + + -- charInfo should look like (Bags: 4, Bank: 8, Equipped: 1, Mail: 7), table concat takes care of this + AddCounterLine(name, format("%s (%s%s)", ORANGE .. charCount .. WHITE, table.concat(t, WHITE..", "), WHITE)) + end + + return charCount +end + +local function GetAccountItemCount(account, searchedID) + local realm = GetRealmName() -- implicit: this realm only + local count = 0 + + for _, character in pairs(DataStore:GetCharacters(realm, account)) do + if addon.Options:Get("TooltipCrossFaction") == 1 then + count = count + GetCharacterItemCount(character, searchedID) + else + if DataStore:GetCharacterFaction(character) == UnitFactionGroup("player") then + count = count + GetCharacterItemCount(character, searchedID) + end + end + end + return count +end + +local function GetItemCount(searchedID) + -- Return the total amount of times an item is present on this realm, and prepares the counterLines table for later display by the tooltip + wipe(counterLines) + + local count = 0 + if addon.Options:Get("TooltipMultiAccount") == 1 and not addon.Comm.Sharing.SharingInProgress then + for account in pairs(DataStore:GetAccounts()) do + count = count + GetAccountItemCount(account, searchedID) + end + else + count = GetAccountItemCount(THIS_ACCOUNT, searchedID) + end + + if addon.Options:Get("TooltipGuildBank") == 1 then + for guildName, guildKey in pairs(DataStore:GetGuilds(GetRealmName())) do -- this realm only + local altoGuild = addon:GetGuild(guildName) + if not altoGuild or (altoGuild and not altoGuild.hideInTooltip) then + local guildCount = 0 + + if addon.Options:Get("TooltipGuildBankCountPerTab") == 1 then + local tabCounters = {} + + for tabID = 1, 6 do + local tabCount = DataStore:GetGuildBankTabItemCount(guildKey, tabID, searchedID) + if tabCount > 0 then + table.insert(tabCounters, format("%s: %s", WHITE .. DataStore:GetGuildBankTabName(guildKey, tabID), TEAL..tabCount)) + end + end + + if #tabCounters > 0 then + guildCount = DataStore:GetGuildBankItemCount(guildKey, searchedID) + AddCounterLine(GREEN..guildName, format("%s %s(%s%s)", ORANGE .. guildCount, WHITE, table.concat(tabCounters, ","), WHITE)) + end + else + guildCount = DataStore:GetGuildBankItemCount(guildKey, searchedID) + if guildCount > 0 then + AddCounterLine(GREEN..guildName, format("%s(%s: %s%s)", WHITE, GUILD_BANK, TEAL..guildCount, WHITE)) + end + end + + if addon.Options:Get("TooltipGuildBankCount") == 1 then + count = count + guildCount + end + end + end + end + + return count +end + +local function GetRecipeOwners(professionName, link, recipeLevel) + local craftName + local spellID = addon:GetSpellIDFromRecipeLink(link) + + if not spellID then -- spell id unknown ? let's parse the tooltip + craftName = GetCraftNameFromRecipeLink(link) + if not craftName then return end -- still nothing usable ? then exit + end + + local know = {} -- list of alts who know this recipe + local couldLearn = {} -- list of alts who could learn it + local willLearn = {} -- list of alts who will be able to learn it later + + local profession, isKnownByChar + for characterName, character in pairs(DataStore:GetCharacters()) do + profession = DataStore:GetProfession(character, professionName) + + if profession then + if spellID then -- if spell id is known, just find its equivalent in the professions + isKnownByChar = DataStore:IsCraftKnown(profession, spellID) + else + for i = 1, DataStore:GetNumCraftLines(profession) do + local isHeader, _, info = DataStore:GetCraftLineInfo(profession, i) + + if not isHeader then + local skillName = GetSpellInfo(info) or "" + + if string.lower(skillName) == string.lower(craftName) then + isKnownByChar = true + break + end + end + end + end + + local coloredName = DataStore:GetColoredCharacterName(character) + + if isKnownByChar then + table.insert(know, coloredName) + else + local currentLevel = DataStore:GetSkillInfo(character, professionName) + if currentLevel > 0 then + if currentLevel < recipeLevel then + table.insert(willLearn, format("%s |r(%d)", coloredName, currentLevel)) + else + table.insert(couldLearn, format("%s |r(%d)", coloredName, currentLevel)) + end + end + end + end + end + + local lines = {} + if #know > 0 then + table.insert(lines, TEAL .. L["Already known by "] ..": ".. WHITE.. table.concat(know, ", ") .."\n") + end + + if #couldLearn > 0 then + table.insert(lines, YELLOW .. L["Could be learned by "] ..": ".. WHITE.. table.concat(couldLearn, ", ") .."\n") + end + + if #willLearn > 0 then + table.insert(lines, RED .. L["Will be learnable by "] ..": ".. WHITE.. table.concat(willLearn, ", ")) + end + + return table.concat(lines, "\n") +end + +local function AddPetOwners(companionSpellID, companionType, tooltip) + local know = {} -- list of alts who know this pet + local couldLearn = {} -- list of alts who could learn it + + for characterName, character in pairs(DataStore:GetCharacters()) do + if DataStore:IsPetKnown(character, companionType, companionSpellID) then + table.insert(know, characterName) + else + table.insert(couldLearn, characterName) + end + end + + if #know > 0 then + tooltip:AddLine(TEAL .. L["Already known by "] ..": ".. WHITE.. table.concat(know, ", "), 1, 1, 1, 1); + end + + if #couldLearn > 0 then + tooltip:AddLine(YELLOW .. L["Could be learned by "] ..": ".. WHITE.. table.concat(couldLearn, ", "), 1, 1, 1, 1); + end +end + +local function ShowGatheringNodeCounters() + -- exit if player does not want counters for known gathering nodes + if addon.Options:Get("TooltipGatheringNode") == 0 then return end + + local itemID = IsGatheringNode( _G["GameTooltipTextLeft1"]:GetText() ) + if not itemID or (itemID == cachedItemID) then return end -- is the item in the tooltip a known type of gathering node ? + + if Informant then + isNodeDone = true + end + + -- check player bags to see how many times he owns this item, and where + if addon.Options:Get("TooltipCount") == 1 or addon.Options:Get("TooltipTotal") == 1 then + cachedCount = GetItemCount(itemID) -- if one of the 2 options is active, do the count + cachedTotal = (cachedCount > 0) and format("%s: %s", GOLD..L["Total owned"], TEAL..cachedCount) or nil + end + + WriteCounterLines(GameTooltip) + WriteTotal(GameTooltip) +end + +local function ProcessTooltip(tooltip, name, link) + if Informant and isNodeDone then + return + end + + local itemID = addon:GetIDFromLink(link) + + -- if there's no cached item id OR if it's different from the previous one .. + if (not cachedItemID) or + (cachedItemID and (itemID ~= cachedItemID)) then + + cachedRecipeOwners = nil + + -- these are the cpu intensive parts of the update .. so do them only if necessary + cachedSource = nil + if addon.Options:Get("TooltipSource") == 1 then + local Instance, Boss = addon.Loots:GetSource(itemID) + + cachedItemID = itemID -- we have searched this ID .. + if Instance then + cachedSource = format("%s: %s, %s", GOLD..L["Source"], TEAL..Instance, Boss) + end + end + + -- .. then check player bags to see how many times he owns this item, and where + if addon.Options:Get("TooltipCount") == 1 or addon.Options:Get("TooltipTotal") == 1 then + cachedCount = GetItemCount(itemID) -- if one of the 2 options is active, do the count + cachedTotal = (cachedCount > 0) and format("%s: %s", GOLD..L["Total owned"], TEAL..cachedCount) or nil + end + end + + -- add item cooldown text + local owner = tooltip:GetOwner() + if owner and owner.startTime then + tooltip:AddLine(format(ITEM_COOLDOWN_TIME, SecondsToTime(owner.duration - (GetTime() - owner.startTime))),1,1,1); + end + + WriteCounterLines(tooltip) + WriteTotal(tooltip) + + if cachedSource then -- add item source + tooltip:AddLine(" ",1,1,1); + tooltip:AddLine(cachedSource,1,1,1); + end + + -- addon:CheckMaterialUtility(itemID) + + if addon.Options:Get("TooltipItemID") == 1 then + local iLevel = select(4, GetItemInfo(itemID)) + + if iLevel then + tooltip:AddLine(" ",1,1,1); + tooltip:AddDoubleLine("Item ID: " .. GREEN .. itemID, "iLvl: " .. GREEN .. iLevel); +-- tooltip:AddLine(TEAL .. select(10, GetItemInfo(itemID))); -- texture path + end + end + + if DataStore:IsModuleEnabled("DataStore_Pets") and addon.Options:Get("TooltipPetInfo") == 1 then + local companionID = DataStore:GetCompanionSpellID(itemID) + if companionID then + tooltip:AddLine(" ",1,1,1); + AddPetOwners(companionID, "CRITTER", tooltip) + return -- it's certainly not a recipe if we passed here + end + + local mountID = DataStore:GetMountSpellID(itemID) + if mountID then + tooltip:AddLine(" ",1,1,1); + AddPetOwners(mountID, "MOUNT", tooltip) + return -- it's certainly not a recipe if we passed here + end + end + + if addon.Options:Get("TooltipRecipeInfo") == 0 then return end -- exit if recipe information is not wanted + + local _, _, _, _, _, itemType, itemSubType = GetItemInfo(itemID) + if itemType ~= BI["Recipe"] then return end -- exit if not a recipe + if itemSubType == BI["Book"] then return end -- exit if it's a book + + if not cachedRecipeOwners then + local tooltipName = tooltip:GetName() + local reqLevel + for i = 2, tooltip:NumLines() do -- parse all tooltip lines, one by one + local tooltipText = _G[tooltipName .. "TextLeft" .. i]:GetText() + if tooltipText then + if string.find(tooltipText, "%d+") then -- try to find a numeric value .. + reqLevel = tonumber(string.sub(tooltipText, string.find(tooltipText, "%d+"))) + break + end + end + end + cachedRecipeOwners = GetRecipeOwners(itemSubType, link, reqLevel) + end + + if cachedRecipeOwners then + tooltip:AddLine(" ",1,1,1); + tooltip:AddLine(cachedRecipeOwners, 1, 1, 1, 1); + end +end + +local function Hook_LinkWrangler(frame) + local name, link = frame:GetItem() + if name and link then + ProcessTooltip(frame, name, link) + end +end + +-- ** GameTooltip hooks ** +local function OnGameTooltipShow(tooltip, ...) + if Orig_GameTooltip_OnShow then + Orig_GameTooltip_OnShow(tooltip, ...) + end + + ShowGatheringNodeCounters() + GameTooltip:Show() +end + +local function OnGameTooltipSetItem(tooltip, ...) + if Orig_GameTooltip_SetItem then + Orig_GameTooltip_SetItem(tooltip, ...) + end + + if (not isTooltipDone) and tooltip then + local name, link = tooltip:GetItem() + isTooltipDone = true + if link then + ProcessTooltip(tooltip, name, link) + end + end +end + +local function OnGameTooltipCleared(tooltip, ...) + isTooltipDone = nil + isNodeDone = nil -- for informant + return Orig_GameTooltip_ClearItem(tooltip, ...) +end + +-- ** ItemRefTooltip hooks ** +local function OnItemRefTooltipShow(tooltip, ...) + if Orig_ItemRefTooltip_OnShow then + Orig_ItemRefTooltip_OnShow(tooltip, ...) + end + + addon.Quests:ListCharsOnQuest( _G["ItemRefTooltipTextLeft1"]:GetText(), UnitName("player"), ItemRefTooltip) + ItemRefTooltip:Show() +end + +local function OnItemRefTooltipSetItem(tooltip, ...) + if Orig_ItemRefTooltip_SetItem then + Orig_ItemRefTooltip_SetItem(tooltip, ...) + end + + if (not isTooltipDone) and tooltip then + local name, link = tooltip:GetItem() + isTooltipDone = true + if link then + ProcessTooltip(tooltip, name, link) + end + end +end + +local function OnItemRefTooltipCleared(tooltip, ...) + isTooltipDone = nil + return Orig_ItemRefTooltip_ClearItem(tooltip, ...) +end + +function addon:InitTooltip() + -- save all function pointers + Orig_GameTooltip_OnShow = GameTooltip:GetScript("OnShow") + Orig_GameTooltip_SetItem = GameTooltip:GetScript("OnTooltipSetItem") + Orig_GameTooltip_ClearItem = GameTooltip:GetScript("OnTooltipCleared") + -- Orig_GameTooltip_SetSpell = GameTooltip:GetScript("OnTooltipSetSpell") + + Orig_ItemRefTooltip_OnShow = ItemRefTooltip:GetScript("OnShow") + Orig_ItemRefTooltip_SetItem = ItemRefTooltip:GetScript("OnTooltipSetItem") + Orig_ItemRefTooltip_ClearItem = ItemRefTooltip:GetScript("OnTooltipCleared") + -- Orig_ItemRefTooltip_SetSpell = ItemRefTooltip:GetScript("OnTooltipSetSpell") + + -- set new function pointers + GameTooltip:SetScript("OnShow", OnGameTooltipShow) + GameTooltip:SetScript("OnTooltipSetItem", OnGameTooltipSetItem) + GameTooltip:SetScript("OnTooltipCleared", OnGameTooltipCleared) + -- GameTooltip:SetScript("OnTooltipSetSpell", OnGameTooltipSetSpell) + + ItemRefTooltip:SetScript("OnShow", OnItemRefTooltipShow) + ItemRefTooltip:SetScript("OnTooltipSetItem", OnItemRefTooltipSetItem) + ItemRefTooltip:SetScript("OnTooltipCleared", OnItemRefTooltipCleared) + -- ItemRefTooltip:SetScript("OnTooltipSetSpell", OnItemRefTooltipSetSpell) + + -- LinkWrangler supoprt + if LinkWrangler then + LinkWrangler.RegisterCallback ("Altoholic", Hook_LinkWrangler, "refresh") + end +end + +function addon:RefreshTooltip() + cachedItemID = nil -- putting this at NIL will force a tooltip refresh in self:ProcessToolTip +end + +function addon:GetItemCount(searchedID) + -- "public" for other addons using it + return GetItemCount(searchedID) +end + +-- not yet implemented, still needs testing, basic stuff works, but far from being optimized. +-- function addon.Tooltip.OnGameTooltipSetSpell(tooltip, ...) + -- local self = addon.Tooltip + + -- if self.Orig_GameTooltip_SetSpell then + -- self.Orig_GameTooltip_SetSpell(tooltip, ...) + -- end + + -- local _, _, spellID = tooltip:GetSpell() + -- if spellID then + -- local DS = DataStore + -- for characterName, character in pairs(DataStore:GetCharacters(realm)) do + -- for _, profession in pairs(DataStore:GetProfessions(character)) do + -- if DataStore:IsCraftKnown(profession, spellID) then + -- tooltip:AddLine(TEAL .. L["Already known by "] ..": ".. WHITE.. characterName, 1, 1, 1, 1); + -- end + -- end + -- end + -- self:AddPetOwners(spellID, "CRITTER", tooltip) + -- self:AddPetOwners(spellID, "MOUNT", tooltip) + -- end +-- end + +-- function addon.Tooltip.OnItemRefTooltipSetSpell(tooltip, ...) + -- local self = addon.Tooltip + + -- if self.Orig_ItemRefTooltip_SetSpell then + -- self.Orig_ItemRefTooltip_SetSpell(tooltip, ...) + -- end + + -- local _, _, spellID = tooltip:GetSpell() + -- if spellID then + -- local DS = DataStore + -- for characterName, character in pairs(DataStore:GetCharacters(realm)) do + -- for _, profession in pairs(DataStore:GetProfessions(character)) do + -- if DataStore:IsCraftKnown(profession, spellID) then + -- tooltip:AddLine(TEAL .. L["Already known by "] ..": ".. WHITE.. characterName, 1, 1, 1, 1); + -- end + -- end + -- end + -- self:AddPetOwners(spellID, "CRITTER", tooltip) + -- self:AddPetOwners(spellID, "MOUNT", tooltip) + -- end +-- end diff --git a/Altoholic-Addon/Altoholic/changelog.txt b/Altoholic-Addon/Altoholic/changelog.txt new file mode 100644 index 0000000..31690dd --- /dev/null +++ b/Altoholic-Addon/Altoholic/changelog.txt @@ -0,0 +1,713 @@ +Altoholic Changelog (dates in dd/mm/yyyy) +=================== + +Join the #altoholic IRC channel on Freenode : irc://irc.freenode.net:6667/ + +3.3.002b + +- Fixed linking items/quests/etc.. to chat. +- Several minor bugfixes. + +Note: due to several real life constraints, progress is likely to remain slow, and the fact that Cataclysm is getting closer means I will not update the addon for a while. +Chances are that once addons are allowed on the beta servers and I get access, I will spend my time making changes there directly. +Adding functionalities now and having to rewrite them in a month wouldn't make sense. + +3.3.002 + +- Added an information tooltip when mousing over the number of mails in the Activity pane. +- Search is now cancelled if there is no value in the search edit box, except if you're using the categories in the search tab. +- Reworked item filtering during searches. All types of searches now use the same code path. Also fixed a few filters that were not working properly. +- Changed the location drop down in the Summary tab, you can now select more combinations of realms/accounts. +- Added an option to clamp the addon's window to the screen. +- Fixed skill tooltip displaying "no data" when mousing over skinning or herbalism. +- The achievement UI is now a module on its own and is loaded-on-demand. This slightly decreases resource usage if you don't use that part of the UI. +- You can now fully disable DataStore_Achievements and Altoholic_Achievements if you do not wish to track achievements at all. +- Winter code cleanup is almost over, almost everything has been reviewed. Next reviews: Calendar & Account Sharing (too big/touchy to review in this pass). + +Note: I have released an alpha version of my new addon on CurseForge. It's definitely not final, but it's stable and fully usable. +Those of you who like to hunt quests you may have missed should like it, it's called Odyssey, and you can find it here: + +http://wow.curseforge.com/addons/odyssey/ + +The quest database is still WIP, so don't bash if there are a few mistakes here & there. I will also be looking for people who can help me maintaining the list of quests & filters. + +No "official" support will be given at this point, please use the email thaoky.altoholic@yahoo.com if you have questions or if you are willing to help. I can also be reached on IRC. + + +3.3.001d (28/01/2010) + +- Fixed several issues with the guild bank tab: deleting a guild, guilds that still appeared in the drop down, etc.. +Note: guild bank money is reset to zero in the process, please visit your guild bank to update it. +- Improved the source's description when searching for items located in the guild bank. +- Fixed an error when changing alt in the 'Characters' tab. + +3.3.001c (27/01/2010) + +- Added back 'text' field in LDB (conditional, for Broker2FuBar) +- Fixed LinkWrangler hook. +- Added support for faction specific achievements. They are now displayed on the same line if a given realm contains characters of the two factions. This used to be a bug/limitation of the system in earlier versions. +- Guild bank counters from other realms are no longer displayed in the tooltip. +- Fixed a Lua error in the 'Guild Skills' pane. +- Added "Offline Members" to the 'Guild Members' pane. The AiL of an offline member can still be clicked, and if a players' equipment has been checked earlier, it will be displayed. +- Fixed a few Lua errors. +- Added an option to show/hide pets already known/could be learned by xx. (Thanks bsmorgan !) +- Pets/mounts can now be shift-clicked and linked. +- Expiries that are supposed to be shown in a dialog box will now be printed to the chat frame instead if player is in combat. +- Changed dependencies in the .toc file, to help the Curse Client with DataStore & its modules. +- Updated the recipe DB. +- Updated loot tables (ICC). + + +3.3.001b (26/12/2009) + +Two Year Anniversary Edition + +In a few days, Altoholic will turn two, and I would like to take some time to thank you all for the continuous support you have given me :) +Quite often, I have received warm "thank you" messages from many of you, and apart from the traditional "you're welcome", or "glad you like the addon", I never had the opportunity to tell you how much this keeps me going. +So here I am, thanking you for being patient when bugfixes do not come in fast enough, for taking the time to dig into the issues yourselves because I cannot reproduce a bug, and for sometimes fixing bugs in my place too. +For all these little things you have done to help, know that I am extremely grateful, and that what started as a small personal project now binds a small community, thanks to all of you. + +I wish you all the very best for 2010! + +/kisses +/hugs +/love +x1000 + +Thaoky + +On to the changelog: +- Fixed a Lua error in DataStore_Auctions. +- Fixed missing currencies count to the tooltip. +- Added a sorted list of achievements in the category "Dungeons & Raids". +- Fixed a tooltip bug where only one of two guilds with the same name would be listed. +- Added The Ashen Verdict faction. + + +3.3.001 (09/12/2009) + +2 reminders : + +1) In the previous version, all options have been moved to Blizzard's option panel, under 2 categories : Altoholic & DataStore (click on '+'). No options has been removed. +2) Help topics have been added in both categories, make sure to read them, they contain a lot of frequently asked questions. + +- Added two new options in DataStore_Mails to check mail expiries for all accounts and/or all realms +- Slightly modified the options panels to better fit all resolutions/UI scales. +- The "Shared Content" scroll frame now has its own panel, right under "Account Sharing". This will change in the future when the entire account sharing feature gets an upgrade and becomes entirely managed by DataStore. +- Added an option to automatically clear expired auctions and bids (DataStore_Auctions). +- Fixed a bug where mail counters were not always displayed in the tooltip. (Thanks Quagm1re !) +- Added currencies count to the tooltip. +- Added 4 missing pets. +- Added mandatory dependencies on DataStore_Characters & DataStore_Containers. The other modules are optional, and the addon will be updated to reflect that soon. Until you read a note about this in the changelog, keep all modules activated. +- Manually updated the loot tables of Onyxia's Lair & ToC, since they are not yet in LPT. + +3.2.003b (25/11/2009) + +- Fixed a Lua error in the when sorting the activity pane by auctions or bids, this happened if one of the alts had never visited the AH. +- Fixed a Lua error in the search pane. +- Fixed a Lua error when mousing over the skill level of an unscanned profession in the Skills pane. +- The options tab has been removed, all options are now available in the Blizzard Options panel. A button has been added at the top of the summary tab, for faster access. +- Added an help topic in the options panel. More topics will be added along the way, don't hesitate to ask if you want to see a particular topic. +- Added a "what's new" topic in the options panel. +- Added an option to turn off the broadcast of profession links to the guild channel into DataStore_Crafts. This is what consumes the most bandwidth, so disable it if you/your guild considers this as critical. + + +3.2.003 (16/11/2009) + +- Fixed a compatibility issue with MrTrader (DataStore_Crafts) +- Added the character skill level in the recipe tooltip (in "Could be learned by ..") +- Fixed a Lua error in when trying to get the item count of a missing character. +- Fixed invalid reporting of the number of free bank slots. +- Added a counter in the achievements tooltip to show the amount of completed criterias, this is particulary useful for achievements like "Northrend Gourmet" +- Some achievement categories are now sorted in a custom fashion, rather than alphabetically, in order to show progressive achievements side by side. +- Achievements can now be linked into chat frames. (You will need to relog your alts at least once for this to work). +- Moved the option that manages the mail expiry threshold to DataStore_Mails. It is thus reset to 5 days for everyone, make sure to change it back to whatever you like in the options pane. +- Guild communication has been entirely rewritten. + The bad news is that backwards compatibility is not maintained (way too much work), meaning that you will not see your guild mates' data in the guild panes unless they upgrade to this version. + The good news is that the amount of data put on the guild channel has been decreased by around 30-35%, and as guild comm is now mostly managed by datastore, this will open doors for new features. +- Improved the "Guild Bank Tabs" pane: + - if you're playing in a guild where players use different localizations of Altoholic, you will now see all timestamps in the same format. + - Players who have more recent data than yours are now shown in yellow (the colour may change if I find something more suitable). +- Improved return mail support. If a guildmate returns a mail to one of your alts, you will be notified immediately. +- Mail expiries are now checked 5 seconds after login, to slightly decrease the processing load at startup. +- Your alts' professions are now sent 5 seconds after login at a pace of 1 per 0.5 seconds, this also decreases the amount of info put on the network at startup. Same thing when you reply to someone else's login. +- Guild member professions will now automatically be cleaned after a patch, to make sure your database only contains usable links. +- Most money amounts are now displayed using money icons, some of them will remain as they were due to graphic inconsistencies. +- DataStore_Talents now scans talent tree reference only once per game patch, this saves some cpu cycles at loading. +- Fixed a lot of small bugs in a lot of places. + + +3.2.002b (28/09/2009) + +- Removed the "Method missing" error message in DataStore, it now fails silently (it's mostly a debug feature). +- Added an option to display detailed guild bank counters (per tab). Disabled by default. +- Fixed a Lua error in the Auctions/bids panes. +- Updated the list of Feats of Strength. +- Added 3.2 pets. +- Changed the mysterious egg/disgusting jar timers from 7 days to 6 days 20 hours. +- Fixed a bug where the message "No player named xx is currently playing." could be spammed if a guildmate logged in & out too quickly. + +3.2.002 (14/09/2009) + +- Added early support for returned mails. +- Fixed a Lua error when trying to delete a guild bank. +- Changed the calendar warning options, you can now set different warning thresholds per event type. +- Added an option to disable name auto-complete when writing a mail (to prevent conflicts with other addons offering the same feature). +- The reputations pane has been redone. I'm still playing a bit with the icon colors, feel free to make suggestions/tests by changing the values in Frames\Reputations.lua +- Added a new pane for the currencies. They are still visible per character in the activity pane. + +3.2.001d (24/08/2009) + +More bugfixes. +- Removed an unnecessary blank line that sometimes appeared in the tooltip. +- Fixed mining ore/herbs counters being displayed twice when Informant is present (finally :D). +- Fixed the detection of goblin AH (DataStore_Auctions). +- Fixed a Lua error when receiving a mail from a guildmate (DataStore_Mails). +- Fixed a Lua error when searching guild members professions. This was caused by LibTradeLinks expiry after a patch. +- Updated LibTradeLinks to the most recent version. +- Slightly modified the way calendar events are managed, in order to prevent a wall of text when multiple alchemy transmutes expire simultaneously. +- Several bugfixes in the calendar too. +- koKR partial localization (thanks Seashop !) +- Fixed realm deletion in the account summary. +- Declined invitations are now filtered out. + +3.2.001c (14/08/2009) + +- Moved mail expiry check back in OnEnable() +- Fixed 2 Lua errors when doing a search. +- Fixed a minor bug when viewing guild bank tabs on an unguilded alt. +- Fixed invalid counters when taking an attachment (DataStore_Mails). +- [frFR] Fixed an error when viewing certain talent trees (DataStore_Talents). +- Fixed a lua error when visiting the AH (DataStore_Auctions). +- [deDE] Fixed a lua error when scanning skills (DataStore_Skills). +- Fixed sorting alts by rest XP rate. + + +3.2.001b (11/08/2009) + +- Fixed a Lua error in the quest log (DataStore_Quests). +- Fixed the option that scans the body of a mail or not (DataStore_Mails) +- Removed debug code when mousing over a talent. +- Gathered Ace & LPT libraries used by DataStore_* modules under DataStore (thanks AnrDaemon). +- Removed Ace libraries already provided by DataStore +- Fixed localization issues. + +3.2.001 (10/08/2009) + +YOU MUST DELETE your altoholic.lua in SavedVariables before using this version! + +As of this version, Altoholic will be using the DataStore series of addons. +These small addons are responsible for scanning, storing and providing data to client addons. +Although I wrote them, they must be seen as independent projects which will offer numerous benefits, such as: + +- Other client addons can use them, in order to save memory and processing time. +- Data is scanned and stored only once. +- Each module has its own saved variables file (DataStore_Containers, DataStore_Crafts, etc..), so a change in one DB will not impact the other. +- Scanning has been fine tuned in many places, ex: you can say goodbye to messages like "Recipes could not be read, please rescan" :) +- This will strongly ease the implementation of account sharing related features. + +Other changes: + +- Added the possibility to search guild members recipe (enabled by default). Ex: simply type "glacial bag" to see which guild members can craft it. +- Fixed the calendar to use server time instead of local time. Note that in order to determine the difference between these, the addon waits until time rolls over to the next minute, so in the first minute, values shown in the calendar will not take this offset into account. Warnings are now also triggered after this happened, rather than right after login. +- Added a small test to prevent a wall of text being displayed when a profession cooldown is available again. +- A lot of lua errors have been fixed. + + +3.1.003b (14/06/2009) + +- Fixed FuBar icon issues introduced in the previous release. +- Fixed a lua error in the calendar pane when mousing over a day. +- Fixed a bug when scanning the talents of a low level alt (under lv 10). 10 mottled boars were rageously slain to fix this bug. + +3.1.003 (12/06/2009) + +- Finalized a massive code update started several versions ago, the goal is to facilitate the implementation of new features, so the effort was definitely worth it, even if it caused a small delay in my schedule. +- Brought a few changes that should address the issue of empty Account Summary/Bag Usage/Skills/Activity. Please let me know if this is still happening ! +- Fixed a rare refresh bug that could trigger a Lua error in the recipes pane. +- Added an option to change the UI transparency. +- Added an option to change the UI scale. +- Fixed a bug when sorting alts on rest xp in the account summary (Thanks Dreamsmith !). +- Fixed invalid tooltip counters when mousing over an item in the mailbox. +- Updated zhCN localization (thanks ALADDINN). +- Updated zhTW localization (thanks NightOwl). +- Updated ruRU localization (thanks StingerSoft). +- Added ruRU suggestions (thanks StingerSoft). +- Added a calendar pane to track the following events: standard calendar events, profession cooldowns, raid timers, mysterious egg/disgusting jar. +- Localization update in order to comply with the CurseForge localization tool. A few large strings may need review in ruRU, zhCN & zhTW (those that are used as option tooltips). +- Fixed a bug with the option "Include guild bank count in the total count". + +3.1.002b (05/05/2009) + +- Better tracking of raid id's, they should hopefully no longer be reset at login. +- Added a workaround to the database conversion failing due to a partial DB corruption. +- Added a missing mount. +- Updated loot tables (mostly Ulduar). +- The tradeskill scanning code has been rewritten, it should no longer miss cooldowns or get wrong colors for recipes. Filters are no longer lost during the scan either. If it doesn't work perfectly now, I think I'll start crying like a baby :) +- Fixed a bug where some equipped items might not appear in the search results. + +3.1.002 (29/04/2009) + +- Changed the way pets & craft recipes are stored, thereby considerably reducing the amount of memory used and decreasing the duration of the account sharing process. To give you an idea, my own database (10 alts) went from 4.15 Mb down to 3.34 Mb. Transferring an alt now takes around 40k down from 80k. +- Fixed an error in the all-in-one pets/mounts pane. +- Added a small check to automatically remove players who have left the guild from "Offline Members" in the guild professions pane. +- Fixed quest log headers being continuously expanded when the quest log was updated. +- Fixed reputation log headers being continuously expanded when the reputation log was updated. +- Fixed a lua error due to a line inversion in the account sharing process. (/target Thaoky, /bonk, *ouch*) +- The guild skills pane now display profession icons (when available) + skill level instead of profession link, the button can still be clicked or shift-clicked. +- The 3 column header of the guild skills pane can now be used to sort the view by skill level. +- Added 3 drop down menus in the recipe list to filter recipes on color, class, or inventory slot. +- Updated the list of achievements (thanks shad0h). +- Updated zhTW localization (thanks NightOwl). + +3.1.001b (17/04/2009) + +- Added several missing pets/mounts (Thanks Poco !) +- Fixed a minor issue when counting equipped items. +- Added a temporary workaround to help Bean Counter users (mail function hook). +- Slightly reworked the "Already known by.." tooltip information to make it use less space, both for recipes and pets/mounts. + +3.1.001 (16/04/2009) + +- Added "Already know/Could be learned by" information to the tooltip for both pets & mounts. Database might not be complete, please let me know if you find missing entries. +- Fixed a bug when searching items with a variable enchant name (ex: ".. of the bandit", ".. of the monkey", etc..) +- Fixed a data refresh issue after updating a guild bank tab from another player. This used to be a potential cause of Lua errors in the 3 guild panes. +- Talent & Glyph information has been removed from the character tooltip in the account summary. +- Added a pane for full talent trees. You don't need to clean your DB, but you obviously need to reload alts at least once to scan the trees. Hunter pets are not in yet. +- Glyphs have been moved to the talent tree pane. +- Dual specs are now supported for both talent trees & glyphs. +- Bank visit timestamps are now broadcasted and updated when leaving the guild bank. +- Fixed a few issues that occured while sharing data between two accounts. +- Added a right-click menu option to update a realm imported through account sharing. +- Item cooldowns are now tracked. +- Fixed a very nasty bug in the achievements pane that caused issues in several places, although the most visible was the "GetItemCount" one. (Thaoky wins ! \o/) +- Added/changed search locations in the search pane ("This character" / "This realm, this faction" / "This realm, both factions") +- Fixed linking a craft recipe to a chat channel when Altoholic is visible. +- Added a name auto-complete feature when sending a mail, the addon will lookup your alts of the same faction. (Thanks Omegasnow for the code !) +- Added an option to include the guild bank count or not in the total count. Enabled by default. +- Updated Ace 3 libraries to r803 (15/04/2009). +- Updated LibBabble libs to 3.0-release15 (15/04/2009). +- Updated loot tables with AtlasLoot 5.04.00. +- Updated zhCN localization (thanks ALADDINN). +- Updated esES localization (thanks PatoDaia). +- zhCN: Fixed the translation of "Professions" + +3.0.008b (06/03/2009) + +Minor bugfix release +- Added a right-click menu on the realm name in the account summary. Currently, the only option is to delete the entire realm (current realm can't be deleted). More will come later. +- Added an information tooltip when mousing over a name in the "Guild Members" pane, it contains the guild rank, zone, public & officer notes. +- Updated zhTW localization (thanks NightOwl). +- Updated zhCN localization (thanks ALADDINN). +- Fixed "Lockpicking" in esES. +- Fixed a Lua error in the containers pane when loading a new character. +- Fixed a Lua error in the skills pane. +- Fixed a rare issue with the pets pane. + +Note: Most open issues have been fixed, this is thus most likely the last release until patch 3.1 goes live. + +3.0.008 (04/03/2009) + +- Added a few tests to prevent the risk of displaying an empty frame when opening the addon. +- Changed the "Guild Bank Tabs" slightly, the top level is now the tab name instead of the player. It now shows your own timestamps on the same line as the tab name, and your guildmates in the children lines. It feels more natural than the original implementation. +- Added support for profession links of offline members in the "Guild Skills" pane. +- Added profession icons in the skill pane. Cold Weather Flying in now tracked. +- Added a tooltip to the "Totals" line of the account summary, it contains per faction totals of that realms' data (levels/money/played). +- The mail expiry warning has been reworked, you will now see a popup frame at login that will inform you that mail is about to expire, and offer you the possibility to view the Activity pane directly. This check can be disabled in the options if you don't want to see it. +- Added a new feature to the mail system: when a guildmate sends a mail to one of your alts, the content is directly saved into your alt's mailbox and is immediately visible in Altoholic, without having to reconnect the alt! +- Fixed several Lua errors introduced in the previous version. + +3.0.007b (20/02/2009) + +Minor bugfix release +- Fixed 2 lua errors in the Pets frame. +- Fixed an option stored at the wrong place in the DB, causing lua errors when viewing bags. +- Added few more suggestions for professions in frFR (Thanks to Laumac !) + +3.0.007 (18/02/2009) + +- Updated zhTW localization (thanks NightOwl). +- Updated the containers view. You can now view either bank+bags, or bags only, or bank only in normal or all-in-one mode. +- Added a rarity filter to the containers view that allows you to highlight items with the specified rarity, while greying out other items. +- Changed the "View" DropDownMenu in the "Characters" tab into buttons, for faster browsing. Thanks AnrDaemon for the suggestion. +- Colour legend for reputations moved from the characters' frame to the tooltip. +- Mail & auction house have been slightly reworked, they now use more readable timestamps and also have column headers. +- Added two "All-in-one" views for pets & mounts, to compare your pets/mount across your alts, and also to see which ones you're missing. +- Added a small database of spell ID's taught by recipes. This will prevent the tooltip from reporting that a recipe "Could be learned by x" when it's actually already known. +Note: If a recipe is not in the database, the addon will try to use the old method (parsing the tooltip) to find a match. Both practices should lead to a much better level of accuracy. If you still spot mistakes, make sure to report them and to specify which recipe is impacted. + + +3.0.006c (7/02/2009) + +You DO NOT have to clean your saved variables if you're upgrading from 3.0.006 or 3.0.006b. You MUST still do it if upgrading from a lower version though. + +- Changed the grand totals at the bottom right of the main Altoholic frame, they now change based on how realms/accounts are filtered. +- Fixed a lua error when mousing over an item during an account sharing phase, until this phase is completed, the tooltip will only show the counters of the current realm. +- Message Type MSG_GUILD_ANNOUNCELOGOUT deprecated. Guild logouts are no-longer communicated to other members, they are now detected with CHAT_MSG_SYSTEM. +- You can now Shift-click any profession link from "Guild Skills" to copy it into the chat frame. +- Improved sorting columns in the "Guild Members" pane. Alts are now sorted too. +- Added sorting abilities to the "Guild Professions" pane (first 3 columns only). +- Added the "AH" location in the item tooltip. +- Added an icon for the resulting item of a tradeskill in the recipes pane. It can be be linked to chat, as well as each material. +- Removed the restriction to link a full profession from another account, my original tests had failed, but this seems to work well anyway! Link from another realm remains impossible though. (Thanks g3gg0 for your input on this!) +- The date/time at which an account sharing was performed is now saved and displayed next to the account/realm into the 4 main panes (account summary/activity/etc..). +- Progressive achievements are now tracked. You have to log your characters once to gather the missing data, but cleaning the DB first is NOT required, missing data will simply be completed when you relog. +- Achievements are now listed alphabetically in their respective categories. +- Reference tables have been added in order to support progressive achievements, which means that you will see more achievements than offered by the default achievement UI. For instance, all feats of strength are visible. +- The achievements frame has been slightly reworked, *HUGE* thanks to 0xdeadc0de for the suggestion & the code behind this. +- Updated LibBabble libs (7/02/2009). + +Security Note: Added an option to automatically authorize guild bank updates. +This option is DISABLED by default, this will prevent unauthorized users to query information about a tab on which they do not have view rights. +Unfortunately, the API is extremely limited with regards to security, and this is the best solution I could come up with. +For instance: the API does not allow me to determine whether user x with guild rank y can access bank tab z. +Make sure that if Blizzard provides more API functions to manage such things, I will update this feature and make it automatic (ie: no rights = auto reject). +Until then, security is in your hands. + +To other users, make sure you ENABLE this option if everyone can see everything in your guild, so that you do not get bothered by requests. + + +3.0.006b (01/02/2009) + +You DO NOT have to clean your saved variables if you're upgrading from 3.0.006. You MUST still do it if upgrading from a lower version though. + +- Added an option to include both factions in the tooltip counters (for PVE realms). +- Added an option to include all accounts in the tooltip counters. +- Fixed a Lua error when clicking on an empty profession in the Guild Skills pane. +- Fixed a Lua error in the Auctions pane. +- Fixed 3 Lua errors in the companions/mounts panes when viewing characters from another account. +- Improved the detection of guild login/logout. +- Added a few hints/buttons/tooltips to make the account sharing process more explicit for both sides. +- The account name in the "Account Sharing" frame can no longer be empty, it was never intended to. +- Updated zhTW localization (thanks NightOwl). + +Note: most bugs introduced in 3.0.006 have been fixed. I'm still working on a refresh issue in the guild panes, I expect this to be an easy fix, but it is hard to reproduce the problem, so the fix will be in a future release. + +3.0.006 (26/01/2009) + +3.0.005 was an internal release number, it was not available outside of my guild. + +YOU MUST DELETE your altoholic.lua in SavedVariables before using this version! + +- Support for multiple accounts has been added. Please refer to the appropriate section of readme.txt for details. +- Added 3 new panes in the Summary tab: + - Guild Members: a list of your connected guildmates, along with their alts (if they're using Altoholic too), and their average item level. Clicking their AiL will also allow you to "remotely" inspect their equipment. + - Guild Skills: a list of altoholic users in your guild, along with their alts and direct profession links. All professions are available in one click. + - Guild Bank tabs: a list of altoholic users and the time at which they last visited the guild bank. If you haven't visited the guild bank for a few days, you can remotely update your local data without going to a capital city. + +- A button to expand/collapse realms has been added to the "Summary" tab. +- A filter to select "This realm / All realms / All accounts" has been added to the "Summary" tab. +- An option to select "All accounts" has been added in one of the search filters. +- Horde and Alliance characters on the same PVE realm are now displayed together in the addon, they are no longer displayed in separate realms. +- Fixed a bug in the quest log when abandonning a quest. (Thanks Squeet !) +- Fixed yet another bug related to filters in the tradeskill window, scanning should hopefully be flawless now. +- Added a button to link an entire tradeskill in chat. Only works with alts on the same realm, same account. Does not work for runeforging either. +- Winter code cleanup, won't change your life, but will definitely change mine :D +- Guild bank timestamps are now tracked separately for each tab. +- Raid timers are now updated when PLAYER_ENTERING_WORLD is triggered (entering or leaving an instance). +- Updated loot tables with AtlasLoot 5.03.02 (wotlk crafts missing, coming soon). +- Updated LibBabble libs (26/01/2009). +- A lot of small changes. + +Note: +- In order to support multiple accounts, a lot of code changes have taken place at the core of the addon, and although the addon has been thoroughly tested since last release, this addition plus the guild features that rely on communication may mean that some new bugs were added. +Problems that did not arise in my guild may arise in yours, so let me know if you spot anything. + + +3.0.004b (17/12/2008) + +- Minor localization (frFR) fixes. +- Updated LibBabble libs. +- When searching bags with an active filter on rarity or equipment slot, searching known recipes will no longer happen, as this was inconsistent. + +3.0.004 (15/12/2008) + +- Fixed/added leveling suggestions in all languages for wotlk zones. +- Updated the loot tables to be on par with the AtlasLoot 5.02.03. +- Added support for esES. Thanks IrregularByte. +- WotLK factions have been triggered, please let me know if I missed any, as I do not have a high level horde character. +- Fixed a couple of bugs related to profession cooldowns. +- Fixed a potential incompatibility issue between Auctioneer and Altoholic's auction pane. +- Fixed a rare bug related to rest xp (rest status not correctly reported). +- Added a tooltip above the average item level in the account summary, with a few references. +- Fixed an issue with raid id's of instances like Naxx 10 & 25 overlapping one another. +- Removed specific parsing for enchanting in the recipe tooltip. +- Added 2 options (in Options -> General) to show/hide the fubar icon & text. + +Here's some information about tests I have made regarding a few bug reports: + +- Quest Log: a bug had been reported when a quest is abandonned, the "cursor" seems to go back to the beginning of the log. After extensive tests (without altoholic, with altoholic but all QL scanning code commented, etc..), it appears that this is not a bug. Abandonning quest #10 brings you back to the beginning of the list, seems new since 3.0. +- FuBar: There's a minor issue with the FuBar options that were added. +FuBar does not seem to accept that both the text & icon are hidden, so if you're trying to hide both, one will always come back. As a side note, I have spent way too much time on FuBar issues already, and these two buttons should meet the needs of most FuBar users, so I will not do anything about FuBar anymore. +Also, FuBar saves the status of icon/text per user, not per account, and I won't spend time working around that either. +If you're not happy with the result, use LibDataBroker instead of FuBar. + +3.0.003 (12/11/2008) + +- Fixed mistakes in deDE leveling suggestions, invalid translations (causing Lua errors). +- Fixed LinkWrangler support. (moved Hook_LinkWrangler). +- Added a launcher for LDB. Tested with ButtonBin & MakeRocketGoNow, working ok, let me know if by any chance you have problems with other LDB displays (which I really doubt given how simple it was to implement it). +- Updated zhTW localization (thanks NightOwl). +- Changed libraries directory from "Libs" to "libs" in embeds.xml, to avoid problems on non-windows platforms. +- Fixed a Lua error when clearing AH entries from the list. +- Added support for glyphs, they are visible in the character tooltip of the account summary. Their location is likely to change whenever I have time to implement better support. +- Suggestions to level inscription have been updated, they are now more complete and go up to 350. +- [zhTW]: Fixed translations for "Secondary Skills" and "Riding" that prevented data from being displayed in the skills pane. +- [deDE]: Fixed "Klasse: xx" to "Klassen: xx" & "Restores %d+ mana per", and ITEM_MOD_SPELL_POWER (Thanks ckaotik) +- Fixed the name of the alt who last visited the guild bank. It was correctly saved, but not correctly refreshed. +- Number of achievements earned + points have been added in the class icon tooltip, on top of the achievements frame. +- Fixed a Lua error when trying to find an equipment upgrade based on item level. +- Tradeskill cap raised to 450. +- Level cap raised to 80. + +Note: v3.0.004 should be released rather quickly, and will contain an updated faction list as well as updated loot tables. + +3.0.002b (18/10/2008) Bugfix release. + +- Fixed a bug with the PLAYER_LEVEL_UP event. +- Fixed the issue where earning an achievement updated all of them (it was actually intended to be a temporary solution). Earning an achievement now only updates the information of that specific achievement. (Thanks Syzgyn) +- Fixed a few typos in deDE suggestions. +- Updated all LibBabble libraries to the latest version, as the ones included with 3.0.002 seemed to be causing issues. + +Important notes: + If you didn't face any problems with 3.0.002, you can (and you should) install 3.0.002b without deleting your saved variables database. Simply update the addon, and you'll be fine. + + If you did face problems with 3.0.002, the most annoying bug was that the level of one of your alts has been saved as an incorrect value (the addon expects a number, and gets a string, this is the bug I've fixed). + How did this happen? + A wow event has changed, and I wasn't aware of it. You have only been impacted by this problem if one of your alts actually leveled up since you installed 3.0.002, otherwise, you have not been affected. + + How can I fix it? + If you know exactly which alts leveled up, you can simply update the addon to 3.0.002b, and relog them all once, this will update the invalid value to a valid one. You should NOT toggle the UI before you have logged the incriminated characters at least once. + There is a chance that if you kept playing with this problem, the addon did not operate properly and corrupted certain data (like professions, etc..), so if you're in doubt, you should totally delete your saved variables file. + + My sincere apologies for this inconvenience. + +3.0.002 (12/10/2008) + +Known issues: +- There is a known issue with refreshing achievements information, currently data is updated whenever an achievement is completed, but not when its partially completed. This is being addressed in a future patch. +- Only achievements are implemented at this point, statistics will come later. +- Glyphs are not in yet, but definitely planned. +- Tokens/currencies are visible when mousing over a character in the activity tab, this will likely change in a future release. + +IMPORTANT NOTES - PLEASE READ BEFORE INSTALLING !! + +1) Do not install this version before patch 3.0.2 is applied to live realms. +2) YOU MUST DELETE your previous Altoholic directory, as lot of libraries have changed, it is highly recommended to start with a clean installation. +3) YOU MUST DELETE your altoholic.lua in SavedVariables. + +- Added an activity pane: you can now see in one pane how many mails, auctions or bids your alts have, including the time at which they were last checked. +- The addon now detects when a profession is abandonned. All data related to this profession will automatically be removed from the database. +- Fixed the update of faction data, keyring and bank bags. +- deDe localization (almost complete) + suggestions (complete), thanks to sLiz3r. +- Slightly modified the skill pane to display the riding skill level in the right color. The color legend is now a bit different. + +3.0.001b (WotLK beta) +- Fixed feats of strength +- The "color" of recipes is now being tracked, you can now see how many recipes are still green/yellow/orange for any profession. +- Added a button in the tradeskill pane to expand/collapse all sections at once. +- Fixed a few small bugs here and there. +- Tokens are now tracked. +- Rock libraries removed, they had been temporarily included in the previous version to make a few tests with FuBar. Since I could not reach convincing results, they've been dropped. +- Key binding is now supported, you can configure any key to toggle the UI rapidly. + +3.0.001 (WotLK beta) +- Way too much to list :) +- ruRU localization added, thanks to Hellbot. +- frFR suggestions added, thanks to Laumac. +- Support for pets, mounts and achievements. +- Changed the categories in the search tab, they're now the same as at the AH, except all categories have a "Any" subcategory. +- Fixed the bug related to scanning recipes introduced in an earlier release. Recipes are no longer scanned every time a tradeskill window is opened if the database is already well populated. +- The options that were moved to the option pane in 2.4.016 are now permanent. + +2.4.016 (not officially released) +- The UI now uses tabs, like at the real AH, this will leave room to add new features and simplifies navigation. Don't worry if some frames feel a bit empty, this will change over time as new features are added. +- Added the possibility to see bag contents as one large bag. +- Loot table updated with AtlasLoot 4.06.00 +- Fixed trade skills being partially wiped when a filter was active in a tradeskill window. +- Fixed a bug that sometimes caused the counters to be displayed twice in the tooltip for certain gathering nodes. +- Fixed a rare bug when reporting the rest xp of a character that has never entered an inn. +- Fixed Fubar icon not being draggable. +- Added current xp + xp rate in the character tooltip +- Improved the search window by adding column headers to sort results. +- Improved the "find upgrade" feature by adding column headers as well to sort results based on a specific stat. +- Fixed a few other bugs to prevent lua errors when an item link is unknow (especially after a patch). + +- A few checkboxes that were at the top of the search pane have been moved to the options pane. They ARE NOT YET permanent options, but they will be soon. (ex: include guild bank, include mails, etc..) + + +Note to translators: expect some strings to be updated soon, I used to concatenate strings without using %s, which is a bad practice, I'll need your help in future releases :) + + +2.4.015 (22/06/2008) +- NOTE: To those who are facing the issue of options not saving properly, please note that cleaning your Altoholic.lua in WTF/.../SavedVariables will fix the problem. +- Added a count of ores/herbs when mousing over a known type of mining/herbalism node. +- When a quest is linked in chat, clicking on it now tells you which alts are also on the quest (excluding current player). +- Fixed incorrect reporting that mail is about to expire in x days. +- Replaced usage of GameTooltip by Altoholic's own tooltip in order to avoid unnecessary hooks from other addons, thereby preventing potential lockups. +- Quest log is now updated a bit more often, to ensure data validity. +- FuBar: it's now possible to show/hide icon/text. +- Added Auction House support. You can now view a list of auctions & bids you've done with any character. This works like the mail or the bank, you have to be at the AH to read/refresh the data. There's unfortunately no way to provide more accurate info than what I provide, like letting the addon react to an outbid/sale/auction expiry. If that ever becomes possible, make sure Altoholic will take advantage of it :) +Note about the AH information: The AH entries visible in the addon WILL NOT be deleted automatically upon expiry. Reasoning behind this is that you might want to see in which auctions/bids you have to track at login, even if it expired two hours ago. +You can right-click any entry to get a contextual menu thanks to which you can delete AH entries from either your faction's AH, goblin's AH, or both. +- Disabled data refresh on exit, no longer necessary. +- Added advanced filters to find upgrades in the equipment pane. Right-click an item to get the options. Please refer to readme.txt for the details. +Note about the filters: at the moment, they work quite well on armor slots, but I need to improve filtering for rings/trinkets/etc.. expect more fine-tuning. + +2.4.014 (28/05/2008) +- Fixed a bug related to "First Aid" frFR translation being changed without notice. +- Fixed tradeskill levels not always being properly saved on exit. +- Fixed a lua error when mousing over equipment from another realm than the current. +- Updated the loot table to AtlasLoot 4.05.00. +- Added the possibility to find an upgrade for an item in the Equipment pane. Simply right-click the item. The items listed are the ones with a higher item level for a specific slot, so it's possible that searching for a DPS cloth upgrade returns healing stuff. +- Addon uploaded on wowace svn. You can now get it via WowAceUpdater or on files.wowace.com. There will be more frequent updates there, but keep in mind that those version will always be work-in-progress, even though I'll strive to upload stable versions only. +- Added support for profession cooldowns. The profession tooltip in the "Skills" pane now shows the list of items that are currently in cooldown. +- Added support for command line searches, please refer to readme.txt for details. +- /altoholic no longer toggles the ui. You can now use '/alto show', '/alto hide' or '/alto toggle' to act on the UI. +- /alto is now a valid slash command, it does the same as /altoholic. +- Massive localization effort in this version. *HUGE* thanks to NightOwl (wowace) for zhTW, and to AYiNaFA/Wang for zhCN. +- The addon is getting close to be 100% localized for enUS, frFR, zhTW, zhCN. If you notice mistakes, thanks to report them. +Note: deDE still defaults to enUS for many entries, help will be gladly welcome to finish this localization. +I'm also looking for help to translate the suggestions in frFR, deDE. + +2.4.013 (13/05/2008) +- Fixed incorrect counters in the tooltip when viewing mailbox content. +- Fixed a bug after a /gquit. +- Fixed a localization bug in the recipe tooltip. +- Fixed a bug displaying or linking guild bank tooltips on realm other than the current. +- Fixed a bug processing recipe tooltips in frFR (and potentially deDE too). +- Fixed a few typos in deDE. +- Fixed a small typo that prevented the Factions table from being cleared. +- Raid id's are now tracked and visible in the character tooltip (Account Summary). Simply relog your characters to get this info. +- Added suggestions to the following factions: Honor Hold, Thrallmar, Cenarion Exp., Keepers of Time, Sha'tar, Lower City, Consortium. More will come later. +- Right-clicking an alt's level now opens a contextual menu for faster access to bags, mail & questlog. Left clicking still directly opens his bags. +- Added LinkWrangler support. Thanks Brykrys for the help. +- Added basic PVP info (arena, honor, hk, dk) to the character tooltip. +- Added the possibility to delete an alt by right clicking on its level in "Account Summary->Characters" and selecting "Delete this Alt". +Note: The addon will NOT let you delete the character with which you're currently logged in, this is the desired behaviour and will not be changed. +- Added support for an AutoQuery of the loot tables, this is disabled by default of the serious risk of disconnection. Please check readme.txt for an explanation on how this works. + +2.4.012b (05/05/2008) Bugfix release. +- Fixed a bug introduced in .012 that reported all recipes as "Could be learned by". +- Click an alt's name in the Account Summary now opens its containers. +- Changed the colours in the reputation frame. I'm using WoWwiki's colour scheme, but I could not use it for button textures as the colours were too bright. +I thus opted for a more neutral background (dark gray), and used the colours for the text. The result is not too bad, and I feel it's less aggressive to the eye now. +However, depending on the feedback this may still change, and there will probably be more colour sets in the future (if there's demand). +- Added an option to show/hide "Already known by", "Will be learnable by ", etc .. in the tooltip. +- Fixed a bug when linking a stacked item causing the "split stack" to popup all the time. + +2.4.012 (04/05/2008) +- Fixed enchanting recipes not being listed when searching known recipes. +- Fixed a bug when searching transmutes. +- Fixed known recipes being listed as search results when searching via the menu. +- Fixed the FuBar icon bug for good. If FuBar is not installed, the icon will appear for a split second at login and will be hidden by the addon. Will stay like this until I know FuBar a bit better. +- Fixed a bug when scanning professions. +- Fixed a bug when mousing over a character icon in the reputation frame. +- Fixed a bug introduced in .010 in the multiple realm support for the guild bank. +- Added the list of characters already on a quest in the tooltip. +- Registered ZONE_CHANGED_NEW_AREA & ZONE_CHANGED_INDOORS to better track player location. +- Added support for "Will be learnable by " in the recipe tooltip. +- The reputation pane has been redone, factions are now grouped like in the genuine reputation windows. +A few notes on this: +1) Only the current realm is supported at this point, but multiple-realm support is in the works. +2) Suggestions on how to level each faction will be provided. Aldor, Scryers & Netherwing are already in, to give you a taste of what you can expect :) +3) The frFR & deDE localization have been done by myself, thanks to the WoW-EU Armory, if you find any mistake in the name of a reputation, please let me know. +4) Given how the reputations are now grouped, the need for an "inactive" sub-group is not necessary. This may still happen in the future though. +5) I am not satisfied with the colour scheme of the reputation frame, I'm open to suggestions to make this look better! + +2.4.011 (28/04/2008) +- Fixed a small bug when closing the guild bank after purchasing a new slot. +- Fixed the bug where 2 Altoholic icons were drawn around the minimap when fubar was not running. +- Fixed an invalid item count in the tooltip when moving items from the main bank slots to the bags. +- Prevented the profession from being messed up by opening a craft window with an active filter (have material, subclass, etc..). +The assumption is that the number of crafts will never decrease, so if the number displayed is lower than what is in the DB, scanning is skipped. +- The previous fix will prevent incorrect reporting of "already known" or "could be used by" in a recipe tooltip. +- Now displays item count in the tooltip if it's equal to 1 (was previously considered implicit). +- Various fixes to handle nil pointers. +- Added leveling suggestions when mousing over character level in the character list. +- Fixed a bug due to which rest xp was not correctly updated on logout. + +2.4.010 (26/04/2008) +- YOU MUST DELETE these files: /wtf/your_account/SavedVariables/Altoholic.lua & Altoholic.lua.bak +- The database has been reworked in order to use much less lua tables than before, thereby reducing memory consumption (by around 20%). +- Source files have been re-arranged to be more manageable, you should completely delete your previous Altoholic directory before installing this version. +- German localization ! Thanks Ayindi :D +- It is now possible to search for known recipes, as if you were searching for items. +- The amount of money available at the guild bank is now tracked. +- Added an option to automatically sort loots in descending order (still based on item level). +- Added an option to display the maximum rest xp as 150% instead of 100%. +- Removed the "scan successful" message when scanning a profession went ok. No use for an option. +- Added an option to scan the body of a mail, enabled by default. Disabling this will prevent mails from being marked as read. +- Fixed a bug where a recipe known by an alt was reported as "could be learned". +- Fixed a bug when there were two characters with the same name on 2 different realms. +- Added multiple realms support to the equipment frame. +- Added multiple realms support to the guild bank frame. +- Note: multiple realms support for reputations is NOT YET implemented, but is definitely planned. + +2.4.009 (20/04/2008) +- Added Suggestions for all professions (except skinning, will come once I find meaningful information to provide ..) +- Removed a unnecessary bag update when leaving the bank, which I suspect to be causing a bug. +- Slightly decreased memory usage. +- Mousing over a rogue class in the "skills" frame now shows lockpicking & poisons. +- Quests can now be shift-linked in chat windows +- Added support for professions. You MUST open each profession windows one by one so that the addon can learn them. +This is mandatory, professions can't be queried unless their window is opened, just like the bank. +A message will let you know if professions were properly loaded, which under certain conditions might not be the case. +I'm not sure there's a way to work around this issue, but at least I can detect it, so if you get the error message, just close the window and reopen it. + +2.4.008 (13/04/2008) +- Improved multilingual support for female class names, currently frFR & deDE. I don't know if it's necessary in other languages. +- Fixed the estimation of rest xp, and support for disconnections out of an inn. +- Fixed missing enchant information in item links, relog your alts to update the info. +- Added "Suggestions" to the first aid, tailoring & riding skills tooltip, the concept will be extended to other professions and reputations. + +2.4.007 (10/04/2008) +- Added a "Quests" frame. Suggestions to enhance it are welcome. +- Fixed a bug that prevented bank bags from being correctly read. Make sure to visit the banks of the alts that were affected by this. You DO NOT have to clean the .lua database in the WTF folder. +- Updated most inventory terms to use LibBabble-Inventory 3.0. +- Fixed a bug (that could not be reproduced) with the tooltip parameter being nil in hooked functions (can't happen anymore) +- Updated loot table to AtlasLoot 4.04.01 + +2.4.006 (07/04/2008) +- /Altoholic now toggles the UI +- Fixed a bug with the item count being invalid after equiping/unequiping an item. +- Added early FuBar support. +- Added an option to show/hide the minimap button + +2.4.005 (05/04/2008) +- Improved the method that clears tables. +- Added additional details to the item tooltip. +- Added a new drop down to filter searches by equipment slot. +- The BAG_UPDATE event is now registered later, to prevent inconsistencies after logout. +- Completed the loot table with: Sha'tar faction, Heroic mode badge rewards, and various sets. Now fully on par with AtlasLoot 4.04 +- Fixed a bug in the "Bag Usage" tooltips, the total amount of free slots didn't take the first bag into account. +- The item tooltip is now refreshed automatically when the quantity of the item varies. + +2.4.004 (04/04/2008) +- Fixed a bug when trying to update a bag with a wrong id. +- Added support of LibBabble 3.0 libraries: Boss, Faction, Inventory & Zone, this will add support for additional languages. +Please let me know if you face particular problems related to localization. +The core of the addon still only supports enUS & frFR, but I intend to integrate LibBabble-Class shortly, to make the addon entirely open to other languages. + +2.4.003 (01/04/2008) +- (frFR) Fixed a typo for 2H maces, swords & axes. +- Added the "SetsAndPVP" part of AtlasLoot 4.04 to the loot tables, only a few sets remain to be added (but PVP & T4, T5, T6 are in) +- Fixed a bug with the item tooltip causing a Lua error due to a nil itemLink. +- Fixed a bug that caused the source to be displayed twice on certain recipes. +- Fixed a bug with the item count in the tooltip, this was due to me being too conservative about bag updates. The tooltip will now display the correct value. There is only a small inconsistency that will not be corrected. If for instance you own 3 copies of an item, and you want to purchase one more, you'll see "3" right before the purchase, and to update it to "4" in the tooltip, you'll have to mouse over an another item first. + +This is because I do not want to be constantly counting the bags (as the function "OnTooltipSetItem" is being triggered continuously by the game when your cursor is over the item). +I thus save the last item ID, and do not recount until a new item ID is found. + +Note that the count isn't displayed if you only own 1 copy of the item. + +2.4.002 (30/03/2008) +- Added the "Crafting" part of AtlasLoot 4.04 to the loot tables +- Added the "WorldLoot" part of AtlasLoot 4.04 to the loot tables +- Added support for item count on the item tooltip, similar to Bagnon_tooltip (configurable) +- Added support for item source location on the item tooltip, similar to Mendeleev (configurable) +- Fixed a bug with the bag usage tooltip. +- Fixed a bug with the female class names introduced since 2.4 in the frFR version. + +2.4.001 (29/03/2008) +- Initial Release \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic/embedded.xml b/Altoholic-Addon/Altoholic/embedded.xml new file mode 100644 index 0000000..fb49319 --- /dev/null +++ b/Altoholic-Addon/Altoholic/embedded.xml @@ -0,0 +1,10 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 41, Altoholic.Achievements.Update) + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/Altoholic_Achievements/Altoholic_Achievements.toc b/Altoholic-Addon/Altoholic_Achievements/Altoholic_Achievements.toc new file mode 100644 index 0000000..b0a5613 --- /dev/null +++ b/Altoholic-Addon/Altoholic_Achievements/Altoholic_Achievements.toc @@ -0,0 +1,15 @@ +## Interface: 30300 +## Title: Altoholic_Achievements +## Notes: Altoholic's Achievements UI +## Author: Thaoky (EU-Marécages de Zangar) +## Version: 3.3.002 +## Dependencies: Altoholic, DataStore, DataStore_Achievements, DataStore_Characters +## LoadOnDemand: 1 +## X-Category: Interface Enhancements +## X-Curse-Packaged-Version: r90 +## X-Curse-Project-Name: Altoholic +## X-Curse-Project-ID: altoholic +## X-Curse-Repository-ID: wow/altoholic/mainline + +TabAchievements.xml +Achievements.xml diff --git a/Altoholic-Addon/Altoholic_Achievements/TabAchievements.lua b/Altoholic-Addon/Altoholic_Achievements/TabAchievements.lua new file mode 100644 index 0000000..06fe8d4 --- /dev/null +++ b/Altoholic-Addon/Altoholic_Achievements/TabAchievements.lua @@ -0,0 +1,131 @@ +local addonName = "Altoholic" +local addon = _G[addonName] + +local WHITE = "|cFFFFFFFF" + +local view +local highlightIndex + +addon.Tabs.Achievements = {} + +local ns = addon.Tabs.Achievements -- ns = namespace + +local function BuildView() + view = view or {} + wipe(view) + + local cats = GetCategoryList() + for _, categoryID in ipairs(cats) do + local _, parentID = GetCategoryInfo(categoryID) + + if parentID == -1 then -- add categories, followed by their respective sub-categories + table.insert(view, { id = categoryID, isCollapsed = true } ) + + for _, subCatID in ipairs(cats) do + local _, subCatParentID = GetCategoryInfo(subCatID) + if subCatParentID == categoryID then + table.insert(view, subCatID ) + end + end + end + end +end + +local function Header_OnClick(frame) + highlightIndex = frame.categoryIndex + local header = view[highlightIndex] + header.isCollapsed = not header.isCollapsed + + ns:Update(); + AltoholicFrameAchievements:Show() + addon.Achievements:SetCategory(header.id) + addon.Achievements:Update() +end + +local function Item_OnClick(frame) + highlightIndex = frame.subCategoryIndex + local item = view[highlightIndex] + + ns:Update(); + AltoholicFrameAchievements:Show() + addon.Achievements:SetCategory(item) + addon.Achievements:Update() +end + +function ns:Update() + if not view then + BuildView() + end + + local VisibleLines = 15 + + local categoryIndex -- index of the category in the menu table + local categoryCacheIndex -- index of the category in the cache table + local MenuCache = {} + + for k, v in pairs (view) do -- rebuild the cache + if type(v) == "table" then -- header + categoryIndex = k + table.insert(MenuCache, { linetype=1, nameIndex=k } ) + categoryCacheIndex = #MenuCache + + if (highlightIndex) and (highlightIndex == k) then + MenuCache[#MenuCache].needsHighlight = true + end + else + if view[categoryIndex].isCollapsed == false then + table.insert(MenuCache, { linetype=2, nameIndex=k, parentIndex=categoryIndex } ) + + if (highlightIndex) and (highlightIndex == k) then + MenuCache[#MenuCache].needsHighlight = true + MenuCache[categoryCacheIndex].needsHighlight = true + end + end + end + end + + local buttonWidth = 156 + if #MenuCache > 15 then + buttonWidth = 136 + end + + local scrollFrame = AltoholicAchievementsMenuScrollFrame + local offset = FauxScrollFrame_GetOffset( scrollFrame ); + local itemButtom = "AltoholicTabAchievementsMenuItem" + for i=1, VisibleLines do + local line = i + offset + + if line > #MenuCache then + _G[itemButtom..i]:Hide() + else + local p = MenuCache[line] + + _G[itemButtom..i]:SetWidth(buttonWidth) + _G[itemButtom..i.."NormalText"]:SetWidth(buttonWidth - 21) + if p.needsHighlight then + _G[itemButtom..i]:LockHighlight() + else + _G[itemButtom..i]:UnlockHighlight() + end + + if p.linetype == 1 then + local catName = GetCategoryInfo(view[p.nameIndex].id) + + _G[itemButtom..i.."NormalText"]:SetText(WHITE .. catName) + _G[itemButtom..i]:SetScript("OnClick", Header_OnClick) + _G[itemButtom..i].categoryIndex = p.nameIndex + elseif p.linetype == 2 then + local catName = GetCategoryInfo(view[p.nameIndex]) + + _G[itemButtom..i.."NormalText"]:SetText("|cFFBBFFBB " .. catName) + _G[itemButtom..i]:SetScript("OnClick", Item_OnClick) + _G[itemButtom..i].categoryIndex = p.parentIndex + _G[itemButtom..i].subCategoryIndex = p.nameIndex + end + + _G[itemButtom..i]:Show() + end + end + + FauxScrollFrame_Update( scrollFrame, #MenuCache, VisibleLines, 20); +end diff --git a/Altoholic-Addon/Altoholic_Achievements/TabAchievements.xml b/Altoholic-Addon/Altoholic_Achievements/TabAchievements.xml new file mode 100644 index 0000000..69fbe3d --- /dev/null +++ b/Altoholic-Addon/Altoholic_Achievements/TabAchievements.xml @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FauxScrollFrame_OnVerticalScroll(self, offset, 20, Altoholic.Tabs.Achievements.Update) + + + Altoholic.Tabs.Achievements:Update(); + + + + + + + AltoholicFrameClasses:Show() + Altoholic.Tabs.Achievements:Update() + + + AltoholicFrameClasses:Hide() + + + + \ No newline at end of file diff --git a/Altoholic-Addon/DataStore/Changelog-DataStore-r26.txt b/Altoholic-Addon/DataStore/Changelog-DataStore-r26.txt new file mode 100644 index 0000000..655ad84 --- /dev/null +++ b/Altoholic-Addon/DataStore/Changelog-DataStore-r26.txt @@ -0,0 +1,15 @@ +------------------------------------------------------------------------ +r26 | Thaoky | 2010-07-06 17:21:38 +0000 (Tue, 06 Jul 2010) | 1 line +Changed paths: + M /trunk/DataStore.lua + +Minor update to prepare the migration of the account sharing process from Altoholic to DataStore. +------------------------------------------------------------------------ +r25 | thaoky | 2010-03-17 11:50:20 +0000 (Wed, 17 Mar 2010) | 1 line +Changed paths: + A /trunk/Export + A /trunk/Export/DataStore.xsl + A /trunk/Export/ExportToXML.lua + +Added an external script to export databases to XML. +------------------------------------------------------------------------ diff --git a/Altoholic-Addon/DataStore/DataStore.lua b/Altoholic-Addon/DataStore/DataStore.lua new file mode 100644 index 0000000..aa2f77b --- /dev/null +++ b/Altoholic-Addon/DataStore/DataStore.lua @@ -0,0 +1,636 @@ +--[[ *** DataStore *** +Written by : Thaoky, EU-Marécages de Zangar +July 15th, 2009 + +This is the main DataStore module, its purpose is to be a single point of contact for common operations between client addons and other DataStore modules. +For instance, it prevents client addons from calling a different :GetCharacter() in each module, as the value returned by the main module can be passed to the other ones. + +Other services offered by DataStore: + - DataStore Events ; possibility to trigger and respond to DataStore's own events (see the respective modules for details) + - Tracks guild members status in a slightly more accurate way than with GUILD_ROSTER_UPDATE alone. + - Guild member info can be requested by character name (DataStore:GetGuildMemberInfo(member)) rather than by index (GetGuildRosterInfo) + - Tracks online guild members' alts, used mostly by other DataStore modules, but can also be used by client addons. + Note: a "main" is the currently connected player, "alts" are all his other characters in the same guild. The notions of "main" & "alts" are thus only valid for live data, nothing else. +--]] +DataStore = LibStub("AceAddon-3.0"):NewAddon("DataStore", "AceConsole-3.0", "AceEvent-3.0", "AceComm-3.0", "AceSerializer-3.0") + +local addon = DataStore +addon.Version = "v3.3.001" + +local THIS_ACCOUNT = "Default" +local commPrefix = "DataStore" +local Characters, Guilds -- pointers to the parts of the DB that contain character, guild data + +local RegisteredModules = {} +local RegisteredMethods = {} + +local guildMembersIndexes = {} -- hash table containing guild member info +local onlineMembers = {} -- simple hash table to track online members: ["member"] = true (or nil) +local onlineMembersAlts = {} -- simple hash table to track online members' alts: ["member"] = "alt1|alt2|alt3..." + +-- Message types +local MSG_ANNOUNCELOGIN = 1 -- broacast at login +local MSG_LOGINREPLY = 2 -- reply to MSG_ANNOUNCELOGIN + +local AddonDB_Defaults = { + global = { + Guilds = { + ['*'] = { -- ["Account.Realm.Name"] + faction = nil, + } + }, + Characters = { + ['*'] = { -- ["Account.Realm.Name"] + faction = nil, + guildName = nil, -- nil = not in a guild, as returned by GetGuildInfo("player") + } + }, + SharedContent = { -- lists the shared content + -- ["Account.Realm.Name"] = true means the char is shared, + -- ["Account.Realm.Name.Module"] = true means the module is shared for that char + }, + } +} + +local function GetKey(name, realm, account) + -- default values + name = name or UnitName("player") + realm = realm or GetRealmName() + account = account or THIS_ACCOUNT + + return format("%s.%s.%s", account, realm, name) +end + +local function GetDBVersion() + return addon.db.global.Version or 0 +end + +local function SetDBVersion(version) + addon.db.global.Version = version +end + +local DBUpdaters = { + -- Table of functions, each one updates to its index's version + -- ex: [3] = the function that upgrades from v2 to v3 + [1] = function(self) + -- This function moves character keys from the "global" level to the "Characters" sub-table + -- keys are also changed from a simple boolean (previously set to true) to a table. Only faction & guildname are tracked (for later use) + for k, v in pairs(addon.db.global) do + if type(v) == "boolean" then + if not addon.db.global.Characters[k].faction then -- for characters other than the current one .. + addon.db.global.Characters[k].faction = "" -- set the faction field to create the table. + end + addon.db.global[k] = nil -- kill the key at the old location + end + end + end, +} + +local function UpdateDB() + local version = GetDBVersion() + + for i = (version+1), #DBUpdaters do -- start from latest version +1 to the very last + DBUpdaters[i]() + SetDBVersion(i) + end + + DBUpdaters = nil + GetDBVersion = nil + SetDBVersion = nil +end + +local function GetAlts(guild) + -- returns a | delimited string containing the list of alts in the same guild + guild = guild or GetGuildInfo("player") + if not guild then return end + + local out = {} + for k, v in pairs(Characters) do + local accountKey, realmKey, charKey = strsplit(".", k) + + if accountKey and accountKey == THIS_ACCOUNT then -- same account + if realmKey and realmKey == GetRealmName() then -- same realm + if charKey and charKey ~= UnitName("player") then -- skip current char + if v.guildName and v.guildName == guild then -- same guild (to send only guilded alts, privacy concern, do not change this) + table.insert(out, charKey) + end + end + end + end + end + + return table.concat(out, "|") +end + +local function SaveAlts(sender, alts) + if alts then + if strlen(alts) > 0 then -- sender has no alts + onlineMembersAlts[sender] = alts -- "alt1|alt2|alt3..." + end + addon:SendMessage("DATASTORE_GUILD_ALTS_RECEIVED", sender, alts) + end +end + +local function GuildBroadcast(messageType, ...) + local serializedData = addon:Serialize(messageType, ...) + addon:SendCommMessage(commPrefix, serializedData, "GUILD") +end + +local function GuildWhisper(player, messageType, ...) + if addon:IsGuildMemberOnline(player) then + local serializedData = addon:Serialize(messageType, ...) + addon:SendCommMessage(commPrefix, serializedData, "WHISPER", player) + end +end + +local function CopyTable(src, dest) + for k, v in pairs (src) do + if type(v) == "table" then + dest[k] = {} + CopyTable(v, dest[k]) + else + dest[k] = v + end + end +end + +-- *** Event Handlers *** +local currentGuildName + +local function OnPlayerGuildUpdate() + -- at login this event is called between OnEnable and PLAYER_ALIVE, where GetGuildInfo returns a wrong value + -- however, the value returned here is correct + if IsInGuild() and not currentGuildName then -- the event may be triggered multiple times, and GetGuildInfo may return incoherent values in subsequent calls, so only save if we have no value. + currentGuildName = GetGuildInfo("player") + if currentGuildName then + Guilds[GetKey(currentGuildName)].faction = UnitFactionGroup("player") + -- the first time a valid value is found, broadcast to guild, it must happen here for a standard login, but won't work here after a reloadui since this event is not triggered + GuildBroadcast(MSG_ANNOUNCELOGIN, GetAlts(currentGuildName)) + addon:SendMessage("DATASTORE_ANNOUNCELOGIN", currentGuildName) + end + end + Characters[GetKey()].guildName = currentGuildName +end + +local function OnPlayerAlive() + Characters[GetKey()].faction = UnitFactionGroup("player") + OnPlayerGuildUpdate() +end + +local function OnGuildRosterUpdate() + wipe(guildMembersIndexes) + for i=1, GetNumGuildMembers(true) do -- browse all players (online & offline) + local name, _, _, _, _, _, _, _, onlineStatus = GetGuildRosterInfo(i) + if name then + guildMembersIndexes[name] = i + + if onlineMembers[name] and not onlineStatus then -- if a player was online but has now gone offline, trigger a message + addon:SendMessage("DATASTORE_GUILD_MEMBER_OFFLINE", name) + end + onlineMembers[name] = onlineStatus + end + end +end + +local msgOffline = gsub(ERR_FRIEND_OFFLINE_S, "%%s", "(.+)") -- this turns "%s has gone offline." into "(.+) has gone offline." + +local function OnChatMsgSystem(event, arg) + if arg then + local member = arg:match(msgOffline) + if member then + -- guild roster update can be triggered every 10 secs max, so if a players logs in & out right after, sending him message will result in "No player named xx" + -- marking him as offline prevents this + onlineMembers[member] = nil + onlineMembersAlts[member] = nil + addon:SendMessage("DATASTORE_GUILD_MEMBER_OFFLINE", member) + end + end +end + +-- *** Guild Comm *** +local GuildCommCallbacks = { + [commPrefix] = { + [MSG_ANNOUNCELOGIN] = function(sender, alts) + onlineMembers[sender] = true -- sender is obviously online + if sender ~= UnitName("player") then -- don't send back to self + GuildWhisper(sender, MSG_LOGINREPLY, GetAlts()) -- reply by sending my own alts .. + end + SaveAlts(sender, alts) -- .. and save received data + end, + [MSG_LOGINREPLY] = function(sender, alts) + SaveAlts(sender, alts) + end, + }, +} + +local function GuildCommHandler(prefix, message, distribution, sender) + -- This handler will be used by other modules as well + local success, msgType, arg1, arg2, arg3 = addon:Deserialize(message) + + if success and msgType and GuildCommCallbacks[prefix] then + local func = GuildCommCallbacks[prefix][msgType] + + if func then + func(sender, arg1, arg2, arg3) + end + end +end + +-- Explanation of this piece of code +-- Whenever DataStore:MethodXXX(arg1, arg2, etc..) is called, this attempts to find the method in the registered list +-- If this method is character related, we intercept the string (ex: ["Default.RealmZZZ.CharYYY") and get the associated character table in the module that owns these data +-- since we actually pass a table to registered methods, the "conversion" is done here. + +--[[ *** Sample code *** + local character = DataStore:GetCharacter() + + -- while the implementation of GetNumSpells in DataStore_Spells expects a table as first parameter, the string value returned by GetCharacter is converted on the fly + -- this service prevents having to maintain a separate pointer to each character table in the respective DataStore_* modules. + local n = DataStore:GetNumSpells(character, "Fire") + print(n) +--]] + +local lookupMethods = { __index = function(self, key) + return function(self, arg1, ...) + if not RegisteredMethods[key] then +-- print(format("DataStore : method <%s> is missing.", key)) -- enable this in Debug only, there's a risk that this function gets called unexpectedly + return + end + + if RegisteredMethods[key].isCharBased then -- if this method is character related, the first expected parameter is the character + local owner = RegisteredMethods[key].owner + arg1 = owner.Characters[arg1] -- turns a "string" parameter into a table, fully intended. + if not arg1.lastUpdate then return end -- lastUpdate must be present in the Character part of a db, if not, data is unavailable + + elseif RegisteredMethods[key].isGuildBased then -- if this method is guild related, the first expected parameter is the guild + local owner = RegisteredMethods[key].owner + arg1 = owner.Guilds[arg1] -- turns a "string" parameter into a table, fully intended. + if not arg1 then return end + + end + return RegisteredMethods[key].func(arg1, ...) + end +end } + +function addon:OnInitialize() + addon.db = LibStub("AceDB-3.0"):New("DataStoreDB", AddonDB_Defaults) + + Characters = addon.db.global.Characters + Guilds = addon.db.global.Guilds + UpdateDB() + + setmetatable(addon, lookupMethods) + + addon:SetupOptions() -- See Options.lua +end + +function addon:OnEnable() + addon:RegisterEvent("PLAYER_ALIVE", OnPlayerAlive) + addon:RegisterEvent("PLAYER_GUILD_UPDATE", OnPlayerGuildUpdate) -- for gkick, gquit, etc.. + + if IsInGuild() then + addon:RegisterEvent("GUILD_ROSTER_UPDATE", OnGuildRosterUpdate) + -- we only care about "%s has come online" or "%s has gone offline", so register only if player is in a guild + addon:RegisterEvent("CHAT_MSG_SYSTEM", OnChatMsgSystem) + addon:RegisterComm(commPrefix, GuildCommHandler) + + local guild = GetGuildInfo("player") -- will be nil in a standard login (called too soon), but ok for a reloadui. + if guild then + GuildBroadcast(MSG_ANNOUNCELOGIN, GetAlts(guild)) + addon:SendMessage("DATASTORE_ANNOUNCELOGIN", guild) + end + end +end + +function addon:OnDisable() + addon:UnregisterEvent("PLAYER_ALIVE") + addon:UnregisterEvent("PLAYER_GUILD_UPDATE") + addon:UnregisterEvent("GUILD_ROSTER_UPDATE") + addon:UnregisterEvent("CHAT_MSG_SYSTEM") +end + +-- *** DB functions *** +function addon:RegisterModule(moduleName, module, publicMethods) + assert(type(moduleName) == "string") + assert(type(module) == "table") + + if not RegisteredModules[moduleName] then -- add the module's database address (addon.db.global) to the list of known modules + RegisteredModules[moduleName] = module + local db = module.db.global + + -- simplifies the life of child modules, and prepares a few pointers for them + module.ThisCharacter = db.Characters[GetKey()] + module.Characters = db.Characters + module.Guilds = db.Guilds + + -- register module's public method + for methodName, method in pairs(publicMethods) do + if RegisteredMethods[methodName] then + print(format("DataStore:RegisterMethod() : adding method for module <%s> failed.", moduleName)) + print(format("DataStore:RegisterMethod() : method <%s> already exists !", methodName)) + return + end + + RegisteredMethods[methodName] = { + func = method, + owner = module, -- module that owns this method & associated data + } + end + end +end + +function addon:SetCharacterBasedMethod(methodName) + -- flags a given method as character based + if RegisteredMethods[methodName] then + -- this will take care of error checking before calling the registered method, and pass the appropriate character table as argument + RegisteredMethods[methodName].isCharBased = true + end +end + +function addon:SetGuildBasedMethod(methodName) + if RegisteredMethods[methodName] then + RegisteredMethods[methodName].isGuildBased = true -- same as above for guilds + end +end + +function addon:GetGuildCommHandler() + return GuildCommHandler +end + +function addon:SetGuildCommCallbacks(prefix, callbacks) + GuildCommCallbacks[prefix] = callbacks -- no need to create a new table, it exists already as a local table in the calling module +end + +function addon:IsModuleEnabled(name) + assert(type(name) == "string") + + if RegisteredModules[name] then + return true + end +end + +function addon:GetCharacter(name, realm, account) + local key = GetKey(name, realm, account) + if Characters[key] then -- if the key is known, return it to caller, it can be passed to other modules + return key + end +end + +function addon:GetCharacters(realm, account) + -- get a list of characters on a given realm/account + realm = realm or GetRealmName() + account = account or THIS_ACCOUNT + + local out = {} + local accountKey, realmKey, charKey + for k, v in pairs(Characters) do + if v.faction and v.faction == "" then -- this is an integrity check, may happen after a failed account sync. + Characters[k] = nil -- kill the key, don't add it to the list. + else + accountKey, realmKey, charKey = strsplit(".", k) + + if accountKey and realmKey then + if accountKey == account and realmKey == realm then + out[charKey] = k + -- allows this kind of iteration: + -- for characterName, character in pairs(DS:GetCharacters(realm, account)) do + -- do stuff with characterName only + -- or do stuff with the "character" key to pass to other DataStore functions + -- end + end + end + end + end + + return out +end + +function addon:DeleteCharacter(name, realm, account) + local key = GetKey(name, realm, account) + if not Characters[key] then return end + + -- delete the character in all modules + for moduleName, moduleDB in pairs(RegisteredModules) do + if moduleDB.Characters then + moduleDB.Characters[key] = nil + end + end + + -- delete the key in DataStore + Characters[key] = nil +end + +function addon:GetNumCharactersInDB() + -- a simple count of the number of character entries in the db + + local count = 0 + for _, _ in pairs(Characters) do + count = count + 1 + end + return count +end + +function addon:GetGuild(name, realm, account) + name = name or GetGuildInfo("player") + local key = GetKey(name, realm, account) + + if Guilds[key] then -- if the key is known, return it to caller, it can be passed to other modules + return key + end +end + +function addon:GetGuilds(realm, account) + -- get a list of guilds on a given realm/account + realm = realm or GetRealmName() + account = account or THIS_ACCOUNT + + local out = {} + local accountKey, realmKey, guildKey + for k, _ in pairs(Guilds) do + accountKey, realmKey, guildKey = strsplit(".", k) + + if accountKey and realmKey then + if accountKey == account and realmKey == realm then + out[guildKey] = k + -- this allows to iterate with this kind of loop: + -- for guildName, guild in pairs(DS:GetGuilds(realm, account)) do + -- do stuff with guildName only + -- or do stuff with the "guild" key to pass to other DataStore functions + -- end + end + end + end + + return out +end + +function addon:DeleteRealm(realm, account) + for name, _ in pairs(addon:GetCharacters(realm, account)) do + addon:DeleteCharacter(name, realm, account) + end +end + +function addon:GetRealms(account) + account = account or THIS_ACCOUNT + + local out = {} + local accountKey, realmKey + for k, _ in pairs(Characters) do + accountKey, realmKey = strsplit(".", k) + + if accountKey and realmKey then + if accountKey == account then + out[realmKey] = true + -- allows this kind of iteration: + -- for realmName in pairs(DS:GetRealms( account)) do + -- end + end + end + end + return out +end + +function addon:GetAccounts() + local out = {} + local accountKey + for k, _ in pairs(Characters) do + accountKey = strsplit(".", k) + + if accountKey then + out[accountKey] = true + -- allows this kind of iteration: + -- for accountName in pairs(DS:GetAccounts()) do + -- end + end + end + return out +end + +function addon:GetModules() + return RegisteredModules + -- for moduleName, module in pairs(DS:GetModules()) do + -- end +end + +function addon:GetCharacterTable(module, name, realm, account) + -- module can be either the module name (string) or the module table + -- ex: DS:GetCharacterTable("DataStore_Containers", ...) or DS:GetCharacterTable(DataStore_Containers, ...) + if type(module) == "string" then + module = RegisteredModules[module] + end + + assert(type(module) == "table") + return module.Characters[GetKey(name, realm, account)] +end + +function addon:GetModuleLastUpdate(module, name, realm, account) + -- module can be either the module name (string) or the module table + -- ex: DS:GetModuleLastUpdate("DataStore_Containers", ...) or DS:GetModuleLastUpdate(DataStore_Containers, ...) + if type(module) == "string" then + module = RegisteredModules[module] + end + + assert(type(module) == "table") + + local key = GetKey(name, realm, account) + + return module.Characters[key].lastUpdate +end + +function addon:ImportData(module, data, name, realm, account) + -- module can be either the module name (string) or the module table + -- ex: DS:ImportData("DataStore_Containers", ...) or DS:ImportData(DataStore_Containers, ...) + if type(module) == "string" then + module = RegisteredModules[module] + end + + assert(type(module) == "table") + -- change this, it shoudl be a COPYTABLE instead of an assignation, otherwise, ace DB wildcards are not applied + -- module.Characters[GetKey(name, realm, account)] = data + CopyTable(data, module.Characters[GetKey(name, realm, account)]) + +end + +function addon:ImportCharacter(key, faction, guild) + -- after data has been imported, add a player entry to the DB, so that it becomes "visible" to the outside world. + -- in other words, the correct sequence of operations should be something like: + -- DataStore:ImportData(DataStore_Talents) + -- DataStore:ImportData(DataStore_Spells) + -- DataStore:ImportCharacter(key, faction, guild) + + Characters[key].faction = faction + Characters[key].guildName = guild +end + +function addon:SetOption(module, option, value) + -- module can be either the module name (string) or the module table + -- ex: DS:SetOption("DataStore_Containers", ...) or DS:SetOption(DataStore_Containers, ...) + if type(module) == "string" then + module = RegisteredModules[module] + end + + if type(module) == "table" then + if module.db.global.Options then + module.db.global.Options[option] = value + end + end +end + +function addon:GetOption(module, option) + -- module can be either the module name (string) or the module table + -- ex: DS:GetOption("DataStore_Containers", ...) or DS:GetOption(DataStore_Containers, ...) + if type(module) == "string" then + module = RegisteredModules[module] + end + + if type(module) == "table" then + if module.db.global.Options then + return module.db.global.Options[option] + end + end +end + +-- *** Guild stuff *** +function addon:GetGuildMemberInfo(member) + -- returns the same info as the genuine GetGuildRosterInfo(), but it can be called by character name instead of by index. + local index = guildMembersIndexes[member] + if index then + -- name, rank, rankIndex, level, class, zone, note, officernote, online, status, englishClass = GetGuildRosterInfo(index) + return GetGuildRosterInfo(index) + end +end + +function addon:GetGuildMemberAlts(member) + local index = onlineMembersAlts[member] + if index then + return onlineMembersAlts[member] + end +end + +function addon:GetOnlineGuildMembers() + return onlineMembers +end + +function addon:IsGuildMemberOnline(member) + if member == UnitName("player") then -- if self, always return true, may happen if login broadcast hasn't come back yet + return true + end + return onlineMembers[member] +end + +function addon:GetNameOfMain(player) + -- returns the name of the guild mate to whom an alt belongs + + -- ex, player x has alts a, b, c + if onlineMembers[player] then -- if x is passed ..it's the main + return player -- return it + end + + for member, alts in pairs(onlineMembersAlts) do --if b is passed, browse all online players who sent their alts + for _, alt in pairs( { strsplit("|", alts) }) do -- browse the list of alts + if alt == player then -- alt found ? + return member -- return the name of his main (currently connected) + end + end + end +end diff --git a/Altoholic-Addon/DataStore/DataStore.toc b/Altoholic-Addon/DataStore/DataStore.toc new file mode 100644 index 0000000..197896b --- /dev/null +++ b/Altoholic-Addon/DataStore/DataStore.toc @@ -0,0 +1,24 @@ +## Interface: 30300 +## Title: DataStore +## Notes: Main DataStore Module +## Author: Thaoky (EU-Marécages de Zangar) +## Version: 3.3.001 +## OptionalDeps: Ace3, LibAboutPanel +## SavedVariables: DataStoreDB +## X-Embeds: Ace3 +## X-Category: Interface Enhancements +## X-Localizations: enUS, frFR, zhCN, zhTW, deDE, koKR, esES, esMX, ruRU +## X-Website: http://wow.curse.com/downloads/wow-addons/details/datastore.aspx +## X-eMail: thaoky.altoholic@yahoo.com +## X-Donate: http://wow.curse.com/downloads/wow-addons/details/altoholic.aspx +## X-Credits: My guild (Odysseüs), all translators, the wowace community, and all users for their invaluable suggestions ! +## X-Curse-Packaged-Version: r26 +## X-Curse-Project-Name: DataStore +## X-Curse-Project-ID: datastore +## X-Curse-Repository-ID: wow/datastore/mainline + +embeds.xml +locale.xml + +DataStore.lua +Options.xml \ No newline at end of file diff --git a/Altoholic-Addon/DataStore/Export/DataStore.xsl b/Altoholic-Addon/DataStore/Export/DataStore.xsl new file mode 100644 index 0000000..0028c2f --- /dev/null +++ b/Altoholic-Addon/DataStore/Export/DataStore.xsl @@ -0,0 +1,438 @@ + + + + + + + + + <xsl:value-of select="@Title" /> + + + + + + + + + + + + + :
+
+ + + + :
+
+ + + + + + + + + + + + x + +
+
+ + + + + Achievement + Status : + + + Completed on + + + + + +
+
+ + + + + + + + + +
+ +
+ +
+
+ + + + + + Item + Count : , + + Highest Bidder : , + + + Owner : , + + + Starting Price : , + + + Bid Price : , + + Buyout Price : , + Time Left : + + + + + + + + + + +
+ +
+
+ + + + + + + + + +
+ + + +
+ + + + + + + +
+ +
+
+ + + + + Spell
+
+ + +
+ +
+ + +
+ +
+ + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + + + + + + + + + +
+ +
+ +
+
+ + + + + + + + + + + + + + + + + +
+ +
+
+ + + +
+
+ + + + + + + + + +
+ +
+ +
+
+ + + + + + + + + + + + +
+
+ + + + + + + + + +
+ Quest Log +
+ +
+
+ + + + : (/) + +
+
+ + + + + + + + + +
+ Factions +
+ +
+
+ + + + + +
+ + +
+ + + + + + + + + +
+ Skills +
+
+ + + + Spell +
+
+ + + + +
+ + +
+ + + + + + + + + +
+ Spellbook +
+
+ + + + : +
+
+ + + :
+ +
+ + + + Glyph + Spec: , Slot: , Type: +
+
+ + + + + + + + + +
+ +
+ +
+
+ + + [] : /
+
+ + + + () +
+ + +
+ + + + + + + + + +
Talent Trees
+
+ + + +
+ / / +
+ +
+
+
+ + + +
+ +
+ +
\ No newline at end of file diff --git a/Altoholic-Addon/DataStore/Export/ExportToXML.lua b/Altoholic-Addon/DataStore/Export/ExportToXML.lua new file mode 100644 index 0000000..c748bcf --- /dev/null +++ b/Altoholic-Addon/DataStore/Export/ExportToXML.lua @@ -0,0 +1,670 @@ +--[[ *** DataStore Export Script *** +Written by : Thaoky, EU-Marecages de Zangar +Date: 10-03-2010 + +READ THIS FIRST !!! + +1) Prerequisites + +You must have a Lua environment installed on your machine. I suggest getting LuaSocket from this address : http://luaforge.net/projects/luasocket/ +Even though this script does not use any network function, LuaSocket is a useful and neat package, and other scripts I may release in the future are likely to use those features :) +Make sure to install it & configure it properly. + +2) Setup a small .bat + +Create a file called go.bat in this directory +Copy this line into the file : + d:\Lua\lua5.1.exe export.lua + +.. where d:\Lua is the directory where your Lua environment is installed + +3) Set INPUT_DIR & OUTPUT_DIR to valid directories (don't forget the double backslashes !!) + +INPUT_DIR must be set to the directory that contains your DataStore Saved Variables. +OUTPUT_DIR is any directory of your choice. + +4) run go.bat + +5) After you've ran the .bat, make sure to copy/move the .xsl that comes with the script into the OUTPUT_DIR, for your own convenience. + +--]] + +print("** DataStore Export **") + +-- local INPUT_DIR = "" +local INPUT_DIR = "D:\\World of Warcraft\\WTF\\Account\\YOUR_ACCOUNT\\SavedVariables" +local OUTPUT_DIR = "E:\\Wow\\Export DataStore" + +local USE_XSL = true -- adds a line that refers to a basic .xsl file to display exported content, comment this line if you don't want an xsl reference. + +local format = string.format + +function strsplit(delimiter, text) + -- source : http://lua-users.org/wiki/SplitJoin + local list = {} + local pos = 1 + if string.find("", delimiter, 1) then -- this would result in endless loops + error("delimiter matches empty string!") + end + + if delimiter == "." then + delimiter = "%." + end + + while 1 do + local first, last = string.find(text, delimiter, pos) + if first then -- found? + table.insert(list, string.sub(text, pos, first-1)) + pos = last+1 + else + table.insert(list, string.sub(text, pos)) + break + end + end + + return unpack(list) +end + +function CreateDir(name) + os.execute("mkdir " .. name) +end + +function ChangeDir(name) + os.execute("chdir " .. name) +end + +local rarityColors = { + ["9d9d9d"] = 0, -- grey + ["ffffff"] = 1, -- white + ["1eff00"] = 2, -- green + ["0070dd"] = 3, -- blue + ["a335ee"] = 4, -- purple + ["ff8000"] = 5, -- orange + ["e5cc80"] = 7, -- heirloom +} + +function GetRarityFromLink(link) + local color = link:sub(5, 10) + if color then + return rarityColors[color] + end +end + +-- ** xml utility ** +function CreateXMLFile(fileName) + local f = assert(io.open(OUTPUT_DIR .. "\\" .. fileName, "w")) + f:write("\n") + if USE_XSL then + f:write("\n") + end + return f +end + +function WriteXMLLine(file, level, text) + file:write(format("%s%s\n", string.rep("\t", level), text:gsub("&", "&"))) +end + +function OpenXMLTag(file, level, tag, attributes) + if attributes then + WriteXMLLine(file, level, format("<%s %s>", tag, attributes)) + else + WriteXMLLine(file, level, format("<%s>", tag)) + end +end + +function CloseXMLTag(file, level, tag) + WriteXMLLine(file, level, format("", tag)) +end + +function SingleLineTag(file, level, tag, value, attributes) + if attributes then + WriteXMLLine(file, level, format("<%s %s>%s", tag, attributes, value, tag)) + else + WriteXMLLine(file, level, format("<%s>%s", tag, value, tag)) + end +end + +local timeFields = { + ["lastUpdate"] = true, + ["ClientTime"] = true, + ["lastLogoutTimestamp"] = true, + ["lastCheck"] = true, + ["HistoryLastUpdate"] = true, +} + +local BottomLevels = { + [-42000] = "Hated", + [-6000] = "Hostile", + [-3000] = "Unfriendly", + [0] = "Neutral", + [3000] = "Friendly", + [9000] = "Honored", + [21000] = "Revered", + [42000] = "Exalted", +} + +-- ** Module specific export functions ** +local specificExport = { + ["DataStore_Achievements"] = { + ["Achievements"] = function(file, level, source, character) + OpenXMLTag(file, level, "Achievements") + for index, data in pairs(source) do + local attrib = format("id=\"%s\"", index) + + if type(data) == "boolean" and data == true then + data = "true" -- achievement has been completed + local month, day, year = character.CompletionDates[index]:match("(%d+):(%d+):(%d+)") + year = tonumber(year) + 2000 + + attrib = format("%s completionDate=\"%s/%s/%s\"", attrib, month, day, year) + end + SingleLineTag(file, level+1, "Achievement", data, attrib) + end + CloseXMLTag(file, level, "Achievements") + end, + }, + ["DataStore_Auctions"] = { + ["Auctions"] = function(file, level, source) + OpenXMLTag(file, level, "Auctions") + for index, data in pairs(source) do + local isGoblin, itemID, count, highBidder, startPrice, buyoutPrice, timeLeft = strsplit("|", data) + + local attrib = format("count=\"%s\" highBidder=\"%s\" startPrice=\"%s\" buyoutPrice=\"%s\" timeLeft=\"%s\"", count, highBidder, startPrice, buyoutPrice, timeLeft) + if isGoblin == "1" then + attrib = format("%s GoblinAH=\"true\"", attrib) + end + SingleLineTag(file, level+1, "Auction", itemID, attrib) + end + CloseXMLTag(file, level, "Auctions") + end, + ["Bids"] = function(file, level, source) + OpenXMLTag(file, level, "Bids") + for index, data in pairs(source) do + local isGoblin, itemID, count, ownerName, bidPrice, buyoutPrice, timeLeft = strsplit("|", data) + + local attrib = format("count=\"%s\" ownerName=\"%s\" bidPrice=\"%s\" buyoutPrice=\"%s\" timeLeft=\"%s\"", count, ownerName, bidPrice, buyoutPrice, timeLeft) + if isGoblin == "1" then + attrib = format("%s GoblinAH=\"true\"", attrib) + end + SingleLineTag(file, level+1, "Auction", itemID, attrib) + end + CloseXMLTag(file, level, "Bids") + end, + }, + ["DataStore_Containers"] = { + ["Containers"] = function(file, level, source) + OpenXMLTag(file, level, "Containers") + for bagIndex, bag in pairs(source) do + local bagID = tonumber(bagIndex:sub(4)) + OpenXMLTag(file, level+1, "Bag", format("id=\"%s\"", bagID)) + + for key, value in pairs(bag) do + if type(value) == "number" then + SingleLineTag(file, level+2, key, value) + elseif type(value) == "string" then + SingleLineTag(file, level+2, key, value) + elseif type(value) == "boolean" then + SingleLineTag(file, level+2, key, (value) and "true" or "false") + elseif type(value) == "table" then + if key == "ids" then -- ids is the main table, the two others (links & counts) are complement + OpenXMLTag(file, level+2, "Content") + for slotID, itemID in pairs(value) do + + local text = format("Item %d", itemID) + local count = 1 + if bag.counts and bag.counts[slotID] then + count = bag.counts[slotID] + end + + local attrib = format("slot=\"%s\" count=\"%s\" id=\"%s\"", slotID, count, itemID) + if bag.links and bag.links[slotID] then + local link = bag.links[slotID] + text = link:match("%[(.+)%]") -- this gets the itemName + local rarity = GetRarityFromLink(link) + + attrib = format("%s rarity=\"%s\" link=\"%s\"", attrib, rarity, link) + end + + SingleLineTag(file, level+3, "Item", text, attrib) + end + CloseXMLTag(file, level+2, "Content") + end + end + end + CloseXMLTag(file, level+1, "Bag") + end + CloseXMLTag(file, level, "Containers") + end, + ["Tabs"] = function(file, level, source) + OpenXMLTag(file, level, "Tabs") + for tabID, tab in pairs(source) do + OpenXMLTag(file, level+1, "Tab", format("id=\"%s\"", tabID)) + + for key, value in pairs(tab) do + if type(value) == "number" then + if timeFields[key] then + SingleLineTag(file, level+2, key, os.date("%m/%d/%Y %X", value)) + else + SingleLineTag(file, level+2, key, value) + end + elseif type(value) == "string" then + SingleLineTag(file, level+2, key, value) + elseif type(value) == "boolean" then + SingleLineTag(file, level+2, key, (value) and "true" or "false") + elseif type(value) == "table" then + if key == "ids" then -- ids is the main table, the two others (links & counts) are complement + OpenXMLTag(file, level+2, "Content") + for slotID, itemID in pairs(value) do + + local text = format("Item %d", itemID) + local count = 1 + if tab.counts and tab.counts[slotID] then + count = tab.counts[slotID] + end + + local attrib = format("slot=\"%s\" count=\"%s\" id=\"%s\"", slotID, count, itemID) + if tab.links and tab.links[slotID] then + local link = tab.links[slotID] + text = link:match("%[(.+)%]") -- this gets the itemName + local rarity = GetRarityFromLink(link) + + attrib = format("%s rarity=\"%s\" link=\"%s\"", attrib, rarity, link) + end + + SingleLineTag(file, level+3, "Item", itemID, attrib) + end + CloseXMLTag(file, level+2, "Content") + end + end + end + CloseXMLTag(file, level+1, "Tab") + end + CloseXMLTag(file, level, "Tabs") + end, + }, + ["DataStore_Crafts"] = { + ["Professions"] = function(file, level, source) + OpenXMLTag(file, level, "Professions") + for professionName, profession in pairs(source) do + OpenXMLTag(file, level+1, "Profession", format("name=\"%s\"", professionName)) + + for key, value in pairs(profession) do + if type(value) == "number" then + SingleLineTag(file, level+2, key, value) + elseif type(value) == "string" then + SingleLineTag(file, level+2, key, value) + elseif type(value) == "boolean" then + SingleLineTag(file, level+2, key, (value) and "true" or "false") + elseif type(value) == "table" then + if key == "Crafts" then -- there shouldn't be any other + OpenXMLTag(file, level+2, "Crafts") + + local currentHeader + for index, craft in ipairs(value) do + local color, info = strsplit("|", craft) + + if color == "0" then + if currentHeader then + CloseXMLTag(file, level+3, "Category") + end + OpenXMLTag(file, level+3, "Category", format("name=\"%s\"", info)) + currentHeader = info + else + SingleLineTag(file, level+4, "Spell", info) + end + end + + if currentHeader then + CloseXMLTag(file, level+3, "Category") + end + CloseXMLTag(file, level+2, "Crafts") + end + end + end + CloseXMLTag(file, level+1, "Profession") + end + CloseXMLTag(file, level, "Professions") + end, + }, + ["DataStore_Currencies"] = { + ["Currencies"] = function(file, level, source) + OpenXMLTag(file, level, "Currencies") + + local currentCategory + for index, data in ipairs(source) do + local isHeader, name, count, itemID = strsplit("|", data) + isHeader = (isHeader == "0" and true or nil) + + if isHeader then + if currentCategory then + CloseXMLTag(file, level+1, "Category") + end + OpenXMLTag(file, level+1, "Category", format("name=\"%s\"", name)) + currentCategory = name + else + SingleLineTag(file, level+2, "Currency", name, format("count=\"%s\" itemID=\"%s\"", count, itemID)) + end + end + if currentCategory then + CloseXMLTag(file, level+1, "Category") + end + CloseXMLTag(file, level, "Currencies") + end, + }, + ["DataStore_Inventory"] = { + ["Inventory"] = function(file, level, source) + OpenXMLTag(file, level, "Inventory") + for index, item in pairs(source) do + local attrib = format("index=\"%s\"", index) + local text, itemID + + if type(item) == "number" then + itemID = item + text = format("Item %d", itemID) + else + itemID = tonumber(item:match("item:(%d+)")) + text = item:match("%[(.+)%]") -- this gets the itemName + local rarity = GetRarityFromLink(item) + + attrib = format("%s rarity=\"%s\" link=\"%s\"", attrib, rarity, item) + end + + attrib = format("%s id=\"%s\"", attrib, itemID) + SingleLineTag(file, level+1, "Item", text, attrib) + end + CloseXMLTag(file, level, "Inventory") + end, + }, + ["DataStore_Mails"] = { + ["Mails"] = function(file, level, source) + OpenXMLTag(file, level, "Mails") + for index, mail in pairs(source) do + OpenXMLTag(file, level+1, "Mail") + + for key, value in pairs(mail) do + if timeFields[key] then + SingleLineTag(file, level+2, key, os.date("%m/%d/%Y %X", value)) + else + SingleLineTag(file, level+2, key, value) + end + end + CloseXMLTag(file, level+1, "Mail") + end + CloseXMLTag(file, level, "Mails") + end, + }, + ["DataStore_Pets"] = { + ["CRITTER"] = function(file, level, source) + OpenXMLTag(file, level, "Companions") + for _, data in pairs(source) do + local modelID, name, spellID, icon = strsplit("|", data) + local attrib = format("name=\"%s\" modelID=\"%s\" icon=\"%s\"", name, modelID, icon) + + SingleLineTag(file, level+1, "Spell", spellID, attrib) + end + CloseXMLTag(file, level, "Companions") + end, + ["MOUNT"] = function(file, level, source) + OpenXMLTag(file, level, "Mounts") + for _, data in pairs(source) do + local modelID, name, spellID, icon = strsplit("|", data) + local attrib = format("name=\"%s\" modelID=\"%s\" icon=\"%s\"", name, modelID, icon) + + SingleLineTag(file, level+1, "Spell", spellID, attrib) + end + CloseXMLTag(file, level, "Mounts") + end, + }, + ["DataStore_Quests"] = { + ["History"] = function(file, level, source) + OpenXMLTag(file, level, "History") + for index, data in pairs(source) do + SingleLineTag(file, level+1, "ID", index) + end + CloseXMLTag(file, level, "History") + end, + ["Quests"] = function(file, level, source, character) + OpenXMLTag(file, level, "QuestLog") + for index, data in pairs(source) do + local attrib = format("index=\"%s\"", index) + local text + + local isHeader, questTag, groupSize, money = strsplit("|", data) + groupSize = tonumber(groupSize) + money = tonumber(money) + + if isHeader == "0" then + text = questTag -- catagory name + attrib = format("%s isHeader=\"true\"", attrib) + else + if questTag ~= "" then + attrib = format("%s tag=\"%s\"", attrib, questTag) + end + end + + if groupSize and groupSize > 0 then + attrib = format("%s groupSize=\"%s\"", attrib, groupSize) + end + if money and money > 0 then + attrib = format("%s money=\"%s\"", attrib, money) + end + + -- Fully functional, uncomment if there's demand. + local link = character.QuestLinks[index] + if link then + local questID, questLevel = link:match("quest:(%d+):(-?%d+)") + text = link:match("%[(.+)%]") -- this gets the questName + attrib = format("%s id=\"%s\" level=\"%s\"", attrib, questID, questLevel) + end + + local rewards = character.Rewards[index] + if rewards then + attrib = format("%s rewards=\"%s\"", attrib, rewards) + end + + SingleLineTag(file, level+1, "Quest", text, attrib) + end + CloseXMLTag(file, level, "QuestLog") + end, + }, + ["DataStore_Reputations"] = { + ["Factions"] = function(file, level, source) + OpenXMLTag(file, level, "Factions") + for name, data in pairs(source) do + local bottom, top, earned = strsplit("|", data) + bottom = tonumber(bottom) + top = tonumber(top) + earned = tonumber(earned) + + SingleLineTag(file, level+1, "Faction", name, format("rank=\"%s\" numPoints=\"%s\" maxPoints=\"%s\"", BottomLevels[bottom], (earned - bottom), (top - bottom))) + end + CloseXMLTag(file, level, "Factions") + end, + }, + ["DataStore_Spells"] = { + ["Spells"] = function(file, level, source) + OpenXMLTag(file, level, "Spells") + for schoolName, school in pairs(source) do + OpenXMLTag(file, level+1, "School", format("name=\"%s\"", schoolName)) + + local attrib + for index, value in ipairs(school) do + local id, rank = strsplit("|", value) + + attrib = format("index=\"%s\"", index) + + if rank ~= "" then + attrib = format("%s rank=\"%s\"", attrib, rank) + end + + SingleLineTag(file, level+2, "Spell", id, attrib) + end + CloseXMLTag(file, level+1, "School") + end + CloseXMLTag(file, level, "Spells") + end, + }, + ["DataStore_Skills"] = { + ["Skills"] = function(file, level, source) + OpenXMLTag(file, level, "Skills") + for categoryName, category in pairs(source) do + OpenXMLTag(file, level+1, "Category", format("name=\"%s\"", categoryName)) + + for skillName, skillData in pairs(category) do + SingleLineTag(file, level+2, "Skill", skillData, format("name=\"%s\"", skillName)) + end + CloseXMLTag(file, level+1, "Category") + end + CloseXMLTag(file, level, "Skills") + end, + }, + ["DataStore_Stats"] = { + ["Stats"] = function(file, level, source) + -- to do : improve this, needs some specific code per stat type (if there's demand) + OpenXMLTag(file, level, "Stats") + for name, data in pairs(source) do + SingleLineTag(file, level+1, name, data) + end + CloseXMLTag(file, level, "Stats") + end, + }, + ["DataStore_Talents"] = { + ["Glyphs"] = function(file, level, source) + OpenXMLTag(file, level, "Glyphs") + for index, data in pairs(source) do + local enabled, glyphType, spell, icon, glyphID = strsplit("|", data) + + if enabled == "1" and spell ~= "" then + glyphType = (glyphType == "1") and "major" or "minor" + + local spec = (index <= 6) and "primary" or "secondary" + local slot = (index > 6) and index - 6 or index + + SingleLineTag(file, level+1, "Glyph", glyphID, format("spec=\"%s\" slot=\"%s\" glyphType=\"%s\" spellID=\"%s\" icon=\"%s\"", spec, slot, glyphType, spell, icon)) + end + end + CloseXMLTag(file, level, "Glyphs") + end, + ["TalentTrees"] = function(file, level, source, character) + OpenXMLTag(file, level, "TalentTrees") + + + for treeIndex, data in pairs(source) do + local treeName, spec = strsplit("|", treeIndex) + spec = (spec == "1") and "primary" or "secondary" + local talentRef = DataStore_TalentsRefDB.global[character.Class].Trees[treeName].talents -- this points to talent info from the ref table + + OpenXMLTag(file, level+1, "TalentTree", format("name=\"%s\" spec=\"%s\"", treeName, spec)) + for key, value in pairs(data) do + local id, name, _, _, _, maximumRank = strsplit("|", talentRef[key]) + + SingleLineTag(file, level+2, "Talent", name, format("index=\"%s\" id=\"%s\" pointsSpent=\"%s\" maximumRank=\"%s\"", key, id, value, maximumRank)) + end + CloseXMLTag(file, level+1, "TalentTree") + end + CloseXMLTag(file, level, "TalentTrees") + end, + }, +} + +function ExportCharacters(moduleName, file) + OpenXMLTag(file, 1, "Characters") + + local db = _G[moduleName .."DB"] + local level = 2 + + for characterKey, character in pairs(db.global.Characters) do + local account, realm, characterName = strsplit(".", characterKey) + OpenXMLTag(file, level, format("Character name=\"%s\" realm=\"%s\" account=\"%s\"", characterName, realm, account)) + + for key, value in pairs(character) do + if type(value) == "number" then + if timeFields[key] then + SingleLineTag(file, level+1, key, os.date("%m/%d/%Y %X", value)) + else + SingleLineTag(file, level+1, key, value) + end + elseif type(value) == "string" then + SingleLineTag(file, level+1, key, value) + elseif type(value) == "table" then + if specificExport[moduleName] and specificExport[moduleName][key] then -- ex: if specificExport["DataStore_Reputations"]["Factions"] exists, call it + + specificExport[moduleName][key](file, level+1, value, character) + end + end + end + + CloseXMLTag(file, level, "Character") + end + CloseXMLTag(file, 1, "Characters") +end + +function ExportGuilds(moduleName, file) + OpenXMLTag(file, 1, "Guilds") + + local db = _G[moduleName .."DB"] + local level = 2 + + for guildKey, guild in pairs(db.global.Guilds) do + local account, realm, guildName = strsplit(".", guildKey) + OpenXMLTag(file, level, format("Guild name=\"%s\" realm=\"%s\" account=\"%s\"", guildName, realm, account)) + + for key, value in pairs(guild) do + if type(value) == "number" then + SingleLineTag(file, level+1, key, value) + elseif type(value) == "string" then + SingleLineTag(file, level+1, key, value) + elseif type(value) == "table" then + if specificExport[moduleName] and specificExport[moduleName][key] then -- ex: if specificExport["DataStore_Reputations"]["Factions"] exists, call it + + specificExport[moduleName][key](file, level+1, value) + end + end + end + + CloseXMLTag(file, level, "Guild") + end + + CloseXMLTag(file, 1, "Guilds") +end + +function ExportModule(moduleName) + dofile(INPUT_DIR .. "\\"..moduleName .. ".lua") + + print(format("Exporting %s ...", moduleName)) + local f = CreateXMLFile(moduleName..".xml") + OpenXMLTag(f, 0, format("DataStorePage Title=\"%s\"", moduleName)) + ExportCharacters(moduleName, f) + + if moduleName == "DataStore" or moduleName == "DataStore_Containers" then + ExportGuilds(moduleName, f) + end + + CloseXMLTag(f, 0, "DataStorePage") + f:close() +end + +local modules = { + "DataStore", + "DataStore_Achievements", + "DataStore_Auctions", + "DataStore_Characters", + "DataStore_Containers", + "DataStore_Crafts", + "DataStore_Currencies", + "DataStore_Inventory", + "DataStore_Mails", + "DataStore_Pets", + "DataStore_Quests", + "DataStore_Reputations", + "DataStore_Skills", + "DataStore_Spells", + "DataStore_Stats", + "DataStore_Talents", +} + +for _, moduleName in pairs(modules) do + ExportModule(moduleName) +end + +print("Export complete !") diff --git a/Altoholic-Addon/DataStore/LICENSE.txt b/Altoholic-Addon/DataStore/LICENSE.txt new file mode 100644 index 0000000..4301cb1 --- /dev/null +++ b/Altoholic-Addon/DataStore/LICENSE.txt @@ -0,0 +1,2 @@ + +All Rights Reserved unless otherwise explicitly stated. \ No newline at end of file diff --git a/Altoholic-Addon/DataStore/Locales/deDE.lua b/Altoholic-Addon/DataStore/Locales/deDE.lua new file mode 100644 index 0000000..49caf0a --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/deDE.lua @@ -0,0 +1,8 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore", "deDE" ) + +if not L then return end + +L["Disabled"] = "Deaktiviert" +L["Enabled"] = "Aktiviert" +L["Memory used for %d |4character:characters;:"] = "Verwendeter Speicher für %d |4charakter:charaktere;:" + diff --git a/Altoholic-Addon/DataStore/Locales/enUS.lua b/Altoholic-Addon/DataStore/Locales/enUS.lua new file mode 100644 index 0000000..d15daa1 --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/enUS.lua @@ -0,0 +1,11 @@ +local debug = false +--[===[@debug@ +debug = true +--@end-debug@]===] + +local L = LibStub("AceLocale-3.0"):NewLocale("DataStore", "enUS", true, debug) + +L["Disabled"] = true +L["Enabled"] = true +L["Memory used for %d |4character:characters;:"] = true + diff --git a/Altoholic-Addon/DataStore/Locales/esES.lua b/Altoholic-Addon/DataStore/Locales/esES.lua new file mode 100644 index 0000000..01215b4 --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/esES.lua @@ -0,0 +1,8 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore", "esES" ) + +if not L then return end + +L["Disabled"] = "Desactivado" +L["Enabled"] = "Activado" +L["Memory used for %d |4character:characters;:"] = "Memoria utilizada para %d |4personaje:personajes;:" + diff --git a/Altoholic-Addon/DataStore/Locales/esMX.lua b/Altoholic-Addon/DataStore/Locales/esMX.lua new file mode 100644 index 0000000..0935efb --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/esMX.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore", "esMX" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore/Locales/frFR.lua b/Altoholic-Addon/DataStore/Locales/frFR.lua new file mode 100644 index 0000000..363dd5f --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/frFR.lua @@ -0,0 +1,8 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore", "frFR" ) + +if not L then return end + +L["Disabled"] = "Désactivée" +L["Enabled"] = "Activée" +L["Memory used for %d |4character:characters;:"] = "Mémoire utilisée pour %d |4personnage:personnages;:" + diff --git a/Altoholic-Addon/DataStore/Locales/koKR.lua b/Altoholic-Addon/DataStore/Locales/koKR.lua new file mode 100644 index 0000000..1aef9a7 --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/koKR.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore", "koKR" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore/Locales/repoenUS.lua b/Altoholic-Addon/DataStore/Locales/repoenUS.lua new file mode 100644 index 0000000..2a49de2 --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/repoenUS.lua @@ -0,0 +1,7 @@ +local L = LibStub("AceLocale-3.0"):NewLocale("DataStore", "enUS", true, true) + +if not L then return end + +L["Enabled"] = true +L["Disabled"] = true +L["Memory used for %d |4character:characters;:"] = true diff --git a/Altoholic-Addon/DataStore/Locales/ruRU.lua b/Altoholic-Addon/DataStore/Locales/ruRU.lua new file mode 100644 index 0000000..4fa5aec --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/ruRU.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore", "ruRU" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore/Locales/zhCN.lua b/Altoholic-Addon/DataStore/Locales/zhCN.lua new file mode 100644 index 0000000..cb6c06e --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/zhCN.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore", "zhCN" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore/Locales/zhTW.lua b/Altoholic-Addon/DataStore/Locales/zhTW.lua new file mode 100644 index 0000000..6291bb3 --- /dev/null +++ b/Altoholic-Addon/DataStore/Locales/zhTW.lua @@ -0,0 +1,8 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore", "zhTW" ) + +if not L then return end + +L["Disabled"] = "禁用" +L["Enabled"] = "啟用" +L["Memory used for %d |4character:characters;:"] = "記憶容量已使用 %d |4角色:角色;:" + diff --git a/Altoholic-Addon/DataStore/Options.lua b/Altoholic-Addon/DataStore/Options.lua new file mode 100644 index 0000000..22075b9 --- /dev/null +++ b/Altoholic-Addon/DataStore/Options.lua @@ -0,0 +1,233 @@ +if not DataStore then return end + +local addonName = ... +local addon = _G[addonName] +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +local addonList = { + "DataStore", + "DataStore_Achievements", + "DataStore_Auctions", + "DataStore_Characters", + "DataStore_Containers", + "DataStore_Crafts", + "DataStore_Currencies", + "DataStore_Inventory", + "DataStore_Mails", + "DataStore_Pets", + "DataStore_Quests", + "DataStore_Reputations", + "DataStore_Skills", + "DataStore_Spells", + "DataStore_Stats", + "DataStore_Talents", +} + + +local WHITE = "|cFFFFFFFF" +local TEAL = "|cFF00FF9A" +local ORANGE = "|cFFFF8400" +local GREEN = "|cFF00FF00" +local RED = "|cFFFF0000" + +-- *** DataStore's own help topics *** +local help = { + { name = "General", + questions = { + "What is DataStore?", + "What are the advantages of this approach?", + "What do all these modules do? Do I need to enable them all?", + "How should I update DataStore and its modules?", + }, + answers = { + "DataStore is the main component of a series of addons that serve as data repositories in game. Their respective purpose is to offer scanning and storing services to other addons.", + format("%s\n\n%s\n%s\n%s\n%s", + "There are multiple advantages, for both players and developers:", + "- Data is scanned only once for all client addons (performance gain).", + "- Data is stored only once for all client addons (memory gain).", + "- Add-on authors can spend more time coding higher level features.", + "- Each module is an independant add-on, and therefore has its own SavedVariables file, meaning that you could clean a module's data without disturbing other modules." + ), + format("%s\n\n%s", + "'DataStore' is the main module, client add-ons should have a dependency on it, it should therefore remain enabled all the time, as it is the interface used to access data from the various modules.", + "The other modules are technically all optional, and could be enabled/disabled according to your needs. However, for the time being, Altoholic has not yet been modified to fully support this approach. It will happen soon(tm)!" + ), + format("%s\n\n%s", + "Altoholic is always packaged with the latest versions, most users should upgrade using this method.", + "If you really can't wait, refer to the add-on's homepage in the 'About' panel. The homepage contains links to all the modules' projects on CurseForge. Alphas are available there for advanced users who are courageous enough to test new bu.. I mean new features!" + ) + } + }, + { name = "Clearing data", + questions = { + "How do I clear data from DataStore?", + "What if I want to get rid of Saved Variables?", + }, + answers = { + "At this point, characters and guilds can be erased from Altoholic's UI.", + format("%s\n\n%s", + "Databases are located in |cFFFFFFFFWTF \\ Account \\ \\ SavedVariables|r.", + format("If you deem it necessary, you can delete %sDataStore.lua|r and all %sDataStore_*.lua|r", GREEN, GREEN) + ), + } + }, +} + + +-- *** Utility functions *** +local infoText + +-- very basic support for info panes (FAQ, sections, text.. ), improve later if necessary, see if a lib exists to do that, etc.. +local function AddHelpLine(str) + infoText = format("%s%s\n", infoText, str) +end + +local function AddSection(section) + AddHelpLine(format("%s|r\n", ORANGE..section)) +end + +local function AddQuestion(question) + AddHelpLine(format("%s) %s", WHITE.."Q", TEAL..question)) +end + +local function AddAnswer(answer) + AddHelpLine(format("%s) |r%s\n", WHITE.."A", answer)) +end + +local function AddBulletedText(text) + AddHelpLine(format("%s-|r %s\n", WHITE, text)) +end + +function addon:SetupInfoPanel(info, helpFrame) + infoText = "" + + for _, section in ipairs(info) do + AddSection(section.name) + + if section.questions then + for i = 1, #section.questions do + AddQuestion(section.questions[i]) + AddAnswer(section.answers[i]) + end + + elseif section.bulletedList then + for _, text in ipairs(section.bulletedList) do + AddBulletedText(text) + end + + elseif section.textLines then + for _, text in ipairs(section.textLines) do + AddHelpLine(text) + end + end + end + + helpFrame:SetText(infoText) + infoText = nil +end + +function addon:AddOptionCategory(frame, name, parent) + -- tiny wrapper to add categories in Blizzard's options panel + frame.name = name + frame.parent = parent + InterfaceOptions_AddCategory(frame) +end + +function addon:SetupOptions() + addon:AddOptionCategory(DataStoreGeneralOptions, addonName) + LibStub("LibAboutPanel").new(addonName, addonName); + addon:AddOptionCategory(DataStoreHelp, HELP_LABEL, addonName) -- more categories will be added as the various modules' OnEnable() get called. + + addon:SetupInfoPanel(help, DataStoreHelp_Text) + + DataStoreGeneralOptions_Title:SetText(TEAL..format("DataStore %s", DataStore.Version)) + + -- manually adjust the width of a few panes, as resolution/scale may have an impact on the layout + local width = InterfaceOptionsFramePanelContainer:GetWidth() - 45 + DataStoreHelp:SetWidth(width) + DataStoreHelp_ScrollFrame:SetWidth(width) + DataStoreHelp_Text:SetWidth(width-35) +end + +function addon:ToggleOption(frame, module, option) + if frame:GetChecked() then + addon:SetOption(module, option, 1) + else + addon:SetOption(module, option, 0) + end +end + +function addon:UpdateMyMemoryUsage() + collectgarbage() + addon:UpdateMemoryUsage(addonList, DataStoreGeneralOptions, format(L["Memory used for %d |4character:characters;:"], addon:GetNumCharactersInDB())) +end + +function addon:UpdateMemoryUsage(addons, parent, totalText) + UpdateAddOnMemoryUsage() + + local memInKb + local totalMem = 0 + local text + local list = "" + local name = parent:GetName() + + -- title + _G[name .. "_AddonsText"]:SetText(ORANGE..ADDONS) + + -- headers + for index, dsModule in ipairs(addons) do + list = format("%s%s:\n", list, dsModule) + end + + list = format("%s\n%s", list, totalText) + _G[name .. "_AddonsList"]:SetText(list) + + -- memory used + list = "" + for index, module in ipairs(addons) do + if IsAddOnLoaded(module) then -- module is enabled + memInKb = GetAddOnMemoryUsage(module) + totalMem = totalMem + memInKb + + if memInKb < 1024 then + text = format("%s%.0f %sKB", GREEN, memInKb, WHITE) + else + text = format("%s%.2f %sMB", GREEN, memInKb/1024, WHITE) + end + else -- module is disabled + text = RED..ADDON_DISABLED + end + + list = format("%s%s\n", list, text) + end + + list = format("%s\n%s", list, format("%s%.2f %sMB", GREEN, totalMem/1024, WHITE)) + _G[name .. "_AddonsMem"]:SetText(list) +end + +function addon:SetCheckBoxTooltip(frame, title, whenEnabled, whenDisabled) + frame.tooltipText = title + frame.tooltipRequirement = format("%s|r:\n%s\n\n%s|r:\n%s", GREEN..L["Enabled"], whenEnabled, RED..L["Disabled"], whenDisabled) +end + +local OptionsPanelWidth, OptionsPanelHeight +local lastOptionsPanelWidth = 0 +local lastOptionsPanelHeight = 0 + +function addon:OnUpdate(self, mandatoryResize) + OptionsPanelWidth = InterfaceOptionsFramePanelContainer:GetWidth() + OptionsPanelHeight = InterfaceOptionsFramePanelContainer:GetHeight() + + if not mandatoryResize then -- if resize is not mandatory, allow exit + if OptionsPanelWidth == lastOptionsPanelWidth and OptionsPanelHeight == lastOptionsPanelHeight then return end -- no size change ? exit + end + + lastOptionsPanelWidth = OptionsPanelWidth + lastOptionsPanelHeight = OptionsPanelHeight + + DataStoreHelp:SetWidth(OptionsPanelWidth-45) + DataStoreHelp_ScrollFrame:SetWidth(OptionsPanelWidth-45) + DataStoreHelp:SetHeight(OptionsPanelHeight-30) + DataStoreHelp_ScrollFrame:SetHeight(OptionsPanelHeight-30) + DataStoreHelp_Text:SetWidth(OptionsPanelWidth-80) +end diff --git a/Altoholic-Addon/DataStore/Options.xml b/Altoholic-Addon/DataStore/Options.xml new file mode 100644 index 0000000..33dbc07 --- /dev/null +++ b/Altoholic-Addon/DataStore/Options.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DataStore:UpdateMyMemoryUsage() + + + + + + + + + + + + + + DataStore:OnUpdate(self) + + + DataStore:OnUpdate(self, true) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Altoholic-Addon/DataStore/embeds.xml b/Altoholic-Addon/DataStore/embeds.xml new file mode 100644 index 0000000..5cd9048 --- /dev/null +++ b/Altoholic-Addon/DataStore/embeds.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Auctions", "AutoClearExpiredItems") + + + + + + + diff --git a/Altoholic-Addon/DataStore_Auctions/locale.xml b/Altoholic-Addon/DataStore_Auctions/locale.xml new file mode 100644 index 0000000..3eb054f --- /dev/null +++ b/Altoholic-Addon/DataStore_Auctions/locale.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/DataStore_Characters/Changelog-DataStore_Characters-r11.txt b/Altoholic-Addon/DataStore_Characters/Changelog-DataStore_Characters-r11.txt new file mode 100644 index 0000000..adb05bd --- /dev/null +++ b/Altoholic-Addon/DataStore_Characters/Changelog-DataStore_Characters-r11.txt @@ -0,0 +1,13 @@ +------------------------------------------------------------------------ +r11 | Thaoky | 2010-07-06 16:43:08 +0000 (Tue, 06 Jul 2010) | 1 line +Changed paths: + M /trunk/DataStore_Characters.lua + +Code cleanup. Event handlers reorganized. +------------------------------------------------------------------------ +r10 | thaoky | 2010-02-08 14:22:12 +0000 (Mon, 08 Feb 2010) | 1 line +Changed paths: + M /trunk/DataStore_Characters.lua + +Now tracking englishRace, returned by UnitRace(). +------------------------------------------------------------------------ diff --git a/Altoholic-Addon/DataStore_Characters/DataStore_Characters.lua b/Altoholic-Addon/DataStore_Characters/DataStore_Characters.lua new file mode 100644 index 0000000..afa783e --- /dev/null +++ b/Altoholic-Addon/DataStore_Characters/DataStore_Characters.lua @@ -0,0 +1,329 @@ +--[[ *** DataStore_Characters *** +Written by : Thaoky, EU-Marécages de Zangar +July 18th, 2009 +--]] +if not DataStore then return end + +local addonName = "DataStore_Characters" + +_G[addonName] = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceConsole-3.0", "AceEvent-3.0") + +local addon = _G[addonName] + +local THIS_ACCOUNT = "Default" + +local AddonDB_Defaults = { + global = { + Characters = { + ['*'] = { -- ["Account.Realm.Name"] + -- ** General Stuff ** + lastUpdate = nil, -- last time this char was updated. Set at logon & logout + name = nil, -- to simplify processing a bit, the name is saved in the table too, in addition to being part of the key + level = nil, + race = nil, + englishRace = nil, + class = nil, + englishClass = nil, -- "WARRIOR", "DRUID" .. english & caps, regardless of locale + faction = nil, + gender = nil, -- UnitSex + lastLogoutTimestamp = nil, + money = nil, + played = 0, -- /played, in seconds + zone = nil, -- character location + subZone = nil, + + -- ** XP ** + XP = nil, -- current level xp + XPMax = nil, -- max xp at current level + RestXP = nil, + isResting = nil, -- nil = out of an inn + + -- ** Guild ** + guildName = nil, -- nil = not in a guild, as returned by GetGuildInfo("player") + guildRankName = nil, + guildRankIndex = nil, + } + } + } +} + +-- *** Scanning functions *** +local function ScanPlayerLocation() + local character = addon.ThisCharacter + character.zone = GetRealZoneText() + character.subZone = GetSubZoneText() +end + +-- *** Event Handlers *** +local function OnPlayerGuildUpdate() + -- at login this event is called between OnEnable and PLAYER_ALIVE, where GetGuildInfo returns a wrong value + -- however, the value returned here is correct + if IsInGuild() then + -- find a way to improve this, it's minor, but it's called too often at login + local name, rank, index = GetGuildInfo("player") + if name and rank and index then + local character = addon.ThisCharacter + character.guildName = name + character.guildRankName = rank + character.guildRankIndex = index + end + end +end + +local function OnPlayerUpdateResting() + addon.ThisCharacter.isResting = IsResting(); +end + +local function OnPlayerXPUpdate() + local character = addon.ThisCharacter + + character.XP = UnitXP("player") + character.XPMax = UnitXPMax("player") + character.RestXP = GetXPExhaustion() or 0 +end + +local function OnPlayerMoney() + addon.ThisCharacter.money = GetMoney(); +end + +local function OnPlayerAlive() + local character = addon.ThisCharacter + + character.name = UnitName("player") -- to simplify processing a bit, the name is saved in the table too, in addition to being part of the key + character.level = UnitLevel("player") + character.race, character.englishRace = UnitRace("player") + character.class, character.englishClass = UnitClass("player") + character.gender = UnitSex("player") + character.faction = UnitFactionGroup("player") + character.lastLogoutTimestamp = 0 + character.lastUpdate = time() + + OnPlayerMoney() + OnPlayerXPUpdate() + OnPlayerUpdateResting() + OnPlayerGuildUpdate() +end + +local function OnPlayerLogout() + addon.ThisCharacter.lastLogoutTimestamp = time() + addon.ThisCharacter.lastUpdate = time() +end + +-- ** Mixins ** +local function _GetCharacterName(character) + return character.name +end + +local function _GetCharacterLevel(character) + return character.level or 0 +end + +local function _GetCharacterRace(character) + return character.race or "", character.englishRace or "" +end + +local function _GetCharacterClass(character) + return character.class or "", character.englishClass or "" +end + +local ClassColors = { + ["MAGE"] = "|cFF69CCF0", + ["WARRIOR"] = "|cFFC79C6E", + ["HUNTER"] = "|cFFABD473", + ["ROGUE"] = "|cFFFFF569", + ["WARLOCK"] = "|cFF9482CA", + ["DRUID"] = "|cFFFF7D0A", + ["SHAMAN"] = "|cFF2459FF", + ["PALADIN"] = "|cFFF58CBA", + ["PRIEST"] = "|cFFFFFFFF", + ["DEATHKNIGHT"] = "|cFFC41F3B" +} + +local function _GetColoredCharacterName(character) + return ClassColors[character.englishClass] .. character.name +end + +local function _GetClassColor(character) + -- return just the color of this character's class + return ClassColors[character.englishClass] +end + +local function _GetCharacterFaction(character) + return character.faction or "" +end + +local function _GetColoredCharacterFaction(character) + if character.faction == "Alliance" then + return "|cFF2459FF" .. FACTION_ALLIANCE + else + return "|cFFFF0000" .. FACTION_HORDE + end +end + +local function _GetCharacterGender(character) + return character.gender or "" +end + +local function _GetLastLogout(character) + return character.lastLogoutTimestamp or 0 +end + +local function _GetMoney(character) + return character.money or 0 +end + +local function _GetXP(character) + return character.XP or 0 +end + +local function _GetXPRate(character) + return floor((character.XP / character.XPMax) * 100) +end + +local function _GetXPMax(character) + return character.XPMax or 0 +end + +local function _GetRestXP(character) + return character.RestXP or 0 +end + +local function _GetRestXPRate(character) + -- after extensive tests, it seems that the known formula to calculate rest xp is incorrect. + -- I believed that the maximum rest xp was exactly 1.5 level, and since 8 hours of rest = 5% of a level + -- being 100% rested would mean having 150% xp .. but there's a trick... + -- One would expect that 150% of rest xp would be split over the following levels, and that calculating the exact amount of rest + -- would require taking into account that 30% are over the current level, 100% over lv+1, and the remaining 20% over lv+2 .. + + -- .. But that is not the case.Blizzard only takes into account 150% of rest xp AT THE CURRENT LEVEL RATE. + -- ex: at level 15, it takes 13600 xp to go to 16, therefore the maximum attainable rest xp is: + -- 136 (1% of the level) * 150 = 20400 + + -- thus, to calculate the exact rate (ex at level 15): + -- divide xptonext by 100 : 13600 / 100 = 136 ==> 1% of the level + -- multiply by 1.5 136 * 1.5 = 204 + -- divide rest xp by this value 20400 / 204 = 100 ==> rest xp rate + + local rate = 0 + if character.RestXP then + rate = (character.RestXP / ((character.XPMax / 100) * 1.5)) + end + + -- get the known rate of rest xp (the one saved at last logout) + the rate represented by the elapsed time since last logout + -- (elapsed time / 3600) * 0.625 * (2/3) simplifies to elapsed time / 8640 + -- 0.625 comes from 8 hours rested = 5% of a level, *2/3 because 100% rested = 150% of xp (1.5 level) + + if character.lastLogoutTimestamp ~= 0 then -- time since last logout, 0 for current char, <> for all others + if character.isResting then + rate = rate + ((time() - character.lastLogoutTimestamp) / 8640) + else + rate = rate + ((time() - character.lastLogoutTimestamp) / 34560) -- 4 times less if not at an inn + end + end + return rate +end + +local function _IsResting(character) + return character.isResting +end + +local function _GetGuildInfo(character) + return character.guildName, character.guildRankName, character.guildRankIndex +end + +local function _GetPlayTime(character) + return character.played +end + +local function _GetLocation(character) + return character.zone, character.subZone +end + +local PublicMethods = { + GetCharacterName = _GetCharacterName, + GetCharacterLevel = _GetCharacterLevel, + GetCharacterRace = _GetCharacterRace, + GetCharacterClass = _GetCharacterClass, + GetColoredCharacterName = _GetColoredCharacterName, + GetClassColor = _GetClassColor, + GetCharacterFaction = _GetCharacterFaction, + GetColoredCharacterFaction = _GetColoredCharacterFaction, + GetCharacterGender = _GetCharacterGender, + GetLastLogout = _GetLastLogout, + GetMoney = _GetMoney, + GetXP = _GetXP, + GetXPRate = _GetXPRate, + GetXPMax = _GetXPMax, + GetRestXP = _GetRestXP, + GetRestXPRate = _GetRestXPRate, + IsResting = _IsResting, + GetGuildInfo = _GetGuildInfo, + GetPlayTime = _GetPlayTime, + GetLocation = _GetLocation, +} + +function addon:OnInitialize() + addon.db = LibStub("AceDB-3.0"):New(addonName .. "DB", AddonDB_Defaults) + + DataStore:RegisterModule(addonName, addon, PublicMethods) + DataStore:SetCharacterBasedMethod("GetCharacterName") + DataStore:SetCharacterBasedMethod("GetCharacterLevel") + DataStore:SetCharacterBasedMethod("GetCharacterRace") + DataStore:SetCharacterBasedMethod("GetCharacterClass") + DataStore:SetCharacterBasedMethod("GetColoredCharacterName") + DataStore:SetCharacterBasedMethod("GetClassColor") + DataStore:SetCharacterBasedMethod("GetCharacterFaction") + DataStore:SetCharacterBasedMethod("GetColoredCharacterFaction") + DataStore:SetCharacterBasedMethod("GetCharacterGender") + DataStore:SetCharacterBasedMethod("GetLastLogout") + DataStore:SetCharacterBasedMethod("GetMoney") + DataStore:SetCharacterBasedMethod("GetXP") + DataStore:SetCharacterBasedMethod("GetXPRate") + DataStore:SetCharacterBasedMethod("GetXPMax") + DataStore:SetCharacterBasedMethod("GetRestXP") + DataStore:SetCharacterBasedMethod("GetRestXPRate") + DataStore:SetCharacterBasedMethod("IsResting") + DataStore:SetCharacterBasedMethod("GetGuildInfo") + DataStore:SetCharacterBasedMethod("GetPlayTime") + DataStore:SetCharacterBasedMethod("GetLocation") +end + +function addon:OnEnable() + addon:RegisterEvent("PLAYER_ALIVE", OnPlayerAlive) + addon:RegisterEvent("PLAYER_LOGOUT", OnPlayerLogout) + addon:RegisterEvent("PLAYER_LEVEL_UP") + addon:RegisterEvent("PLAYER_MONEY", OnPlayerMoney) + addon:RegisterEvent("PLAYER_XP_UPDATE", OnPlayerXPUpdate) + addon:RegisterEvent("PLAYER_UPDATE_RESTING", OnPlayerUpdateResting) + addon:RegisterEvent("PLAYER_GUILD_UPDATE", OnPlayerGuildUpdate) -- for gkick, gquit, etc.. + addon:RegisterEvent("ZONE_CHANGED", ScanPlayerLocation) + addon:RegisterEvent("ZONE_CHANGED_NEW_AREA", ScanPlayerLocation) + addon:RegisterEvent("ZONE_CHANGED_INDOORS", ScanPlayerLocation) + addon:RegisterEvent("TIME_PLAYED_MSG") + + RequestTimePlayed() -- trigger a TIME_PLAYED_MSG event +end + +function addon:OnDisable() + addon:UnregisterEvent("PLAYER_ALIVE") + addon:UnregisterEvent("PLAYER_LOGOUT") + addon:UnregisterEvent("PLAYER_LEVEL_UP") + addon:UnregisterEvent("PLAYER_MONEY") + addon:UnregisterEvent("PLAYER_XP_UPDATE") + addon:UnregisterEvent("PLAYER_UPDATE_RESTING") + addon:UnregisterEvent("PLAYER_GUILD_UPDATE") + addon:UnregisterEvent("ZONE_CHANGED") + addon:UnregisterEvent("ZONE_CHANGED_NEW_AREA") + addon:UnregisterEvent("ZONE_CHANGED_INDOORS") + addon:UnregisterEvent("TIME_PLAYED_MSG") +end + +-- *** EVENT HANDLERS *** + +function addon:PLAYER_LEVEL_UP(event, newLevel) + addon.ThisCharacter.level = newLevel +end + +function addon:TIME_PLAYED_MSG(event, TotalTime, CurrentLevelTime) + addon.ThisCharacter.played = TotalTime +end diff --git a/Altoholic-Addon/DataStore_Characters/DataStore_Characters.toc b/Altoholic-Addon/DataStore_Characters/DataStore_Characters.toc new file mode 100644 index 0000000..2be9e21 --- /dev/null +++ b/Altoholic-Addon/DataStore_Characters/DataStore_Characters.toc @@ -0,0 +1,16 @@ +## Interface: 30300 +## Title: DataStore_Characters +## Notes: Stores information about characters (race, level, etc..) +## Author: Thaoky (EU-Marécages de Zangar) +## Version: 3.3.001 +## Dependencies: DataStore +## OptionalDeps: Ace3 +## SavedVariables: DataStore_CharactersDB +## X-Category: Interface Enhancements +## X-Embeds: Ace3 +## X-Curse-Packaged-Version: r11 +## X-Curse-Project-Name: DataStore_Characters +## X-Curse-Project-ID: datastore_characters +## X-Curse-Repository-ID: wow/datastore_characters/mainline + +DataStore_Characters.lua diff --git a/Altoholic-Addon/DataStore_Characters/LICENSE.txt b/Altoholic-Addon/DataStore_Characters/LICENSE.txt new file mode 100644 index 0000000..4301cb1 --- /dev/null +++ b/Altoholic-Addon/DataStore_Characters/LICENSE.txt @@ -0,0 +1,2 @@ + +All Rights Reserved unless otherwise explicitly stated. \ No newline at end of file diff --git a/Altoholic-Addon/DataStore_Containers/Changelog-DataStore_Containers-r22.txt b/Altoholic-Addon/DataStore_Containers/Changelog-DataStore_Containers-r22.txt new file mode 100644 index 0000000..6e4d702 --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/Changelog-DataStore_Containers-r22.txt @@ -0,0 +1,13 @@ +------------------------------------------------------------------------ +r22 | Thaoky | 2010-07-06 16:44:09 +0000 (Tue, 06 Jul 2010) | 1 line +Changed paths: + M /trunk/DataStore_Containers.lua + +Minor code cleanup. +------------------------------------------------------------------------ +r21 | thaoky | 2010-03-09 10:22:10 +0000 (Tue, 09 Mar 2010) | 1 line +Changed paths: + M /trunk/DataStore_Containers.lua + +Added GetGuildBankTabIcon() +------------------------------------------------------------------------ diff --git a/Altoholic-Addon/DataStore_Containers/DataStore_Containers.lua b/Altoholic-Addon/DataStore_Containers/DataStore_Containers.lua new file mode 100644 index 0000000..aa2159a --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/DataStore_Containers.lua @@ -0,0 +1,818 @@ +--[[ *** DataStore_Containers *** +Written by : Thaoky, EU-Marécages de Zangar +June 21st, 2009 + +This modules takes care of scanning & storing player bags, bank, & guild banks + +Extended services: + - guild communication: at logon, sends guild bank tab info (last visit) to guildmates + - triggers events to manage transfers of guild bank tabs +--]] +if not DataStore then return end + +local addonName = "DataStore_Containers" + +_G[addonName] = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceConsole-3.0", "AceEvent-3.0", "AceComm-3.0", "AceSerializer-3.0") + +local addon = _G[addonName] + +local THIS_ACCOUNT = "Default" +local commPrefix = "DS_Cont" -- let's keep it a bit shorter than the addon name, this goes on a comm channel, a byte is a byte ffs :p +local BI = LibStub("LibBabble-Inventory-3.0"):GetLookupTable() + +local guildMembers = {} -- hash table containing guild member info (tab timestamps) + +-- Message types +local MSG_SEND_BANK_TIMESTAMPS = 1 -- broacast at login +local MSG_BANK_TIMESTAMPS_REPLY = 2 -- reply to someone else's login +local MSG_BANKTAB_REQUEST = 3 -- request bank tab data .. +local MSG_BANKTAB_REQUEST_ACK = 4 -- .. ack the request, tell the requester to wait +local MSG_BANKTAB_REQUEST_REJECTED = 5 -- .. refuse the request +local MSG_BANKTAB_TRANSFER = 6 -- .. or send the data + +local AddonDB_Defaults = { + global = { + Guilds = { + ['*'] = { -- ["Account.Realm.Name"] + money = nil, + faction = nil, + Tabs = { + ['*'] = { -- tabID = table index [1] to [6] + name = nil, + icon = nil, + visitedBy = "", + ClientTime = 0, -- since epoch + ClientDate = nil, + ClientHour = nil, + ClientMinute = nil, + ServerHour = nil, + ServerMinute = nil, + ids = {}, + links = {}, + counts = {} + } + }, + } + }, + Characters = { + ['*'] = { -- ["Account.Realm.Name"] + lastUpdate = nil, + numBagSlots = 0, + numFreeBagSlots = 0, + numBankSlots = 0, + numFreeBankSlots = 0, + Containers = { + ['*'] = { -- Containers["Bag0"] + icon = nil, -- Containers's texture + link = nil, -- Containers's itemlink + size = 0, + freeslots = 0, + bagtype = 0, + ids = {}, + links = {}, + counts = {}, + cooldowns = {} + } + } + } + } + } +} + +local function GetDBVersion() + return addon.db.global.Version or 0 +end + +local function SetDBVersion(version) + addon.db.global.Version = version +end + +local DBUpdaters = { + -- Table of functions, each one updates to its index's version + -- ex: [3] = the function that upgrades from v2 to v3 + [1] = function(self) + + local function CopyTable(src, dest) + for k, v in pairs (src) do + if type(v) == "table" then + dest[k] = {} + CopyTable(v, dest[k]) + else + dest[k] = v + end + end + end + + -- This function moves guild bank tabs from the "Guilds/Guildkey" level to the "Guilds/Guildkey/Tabs" sub-table + for guildKey, guildTable in pairs(addon.db.global.Guilds) do + for tabID = 1, 6 do -- convert the 6 tabs + if type(guildTable[tabID]) == "table" then + CopyTable(guildTable[tabID], guildTable.Tabs[tabID]) + wipe(guildTable[tabID]) + guildTable[tabID] = nil + end + end + guildTable.money = 0 + end + end, +} + +local function UpdateDB() + local version = GetDBVersion() + + for i = (version+1), #DBUpdaters do -- start from latest version +1 to the very last + DBUpdaters[i]() + SetDBVersion(i) + end + + DBUpdaters = nil + GetDBVersion = nil + SetDBVersion = nil +end + +-- *** Utility functions *** +local function GetThisGuild() + local guild = GetGuildInfo("player") + if guild then + local key = format("%s.%s.%s", THIS_ACCOUNT, GetRealmName(), guild) + return addon.db.global.Guilds[key] + end +end + +local function GetBankTimestamps(guild) + -- returns a | delimited string containing the list of alts in the same guild + guild = guild or GetGuildInfo("player") + if not guild then return end + + local thisGuild = GetThisGuild() + if not thisGuild then return end + + local out = {} + for tabID, tab in pairs(thisGuild.Tabs) do + if tab.name then + table.insert(out, format("%d:%s:%d:%d:%d", tabID, tab.name, tab.ClientTime, tab.ServerHour, tab.ServerMinute)) + end + end + + return table.concat(out, "|") +end + +local function SaveBankTimestamps(sender, timestamps) + if strlen(timestamps) == 0 then return end -- sender has no tabs + + guildMembers[sender] = guildMembers[sender] or {} + wipe(guildMembers[sender]) + + for _, v in pairs( { strsplit("|", timestamps) }) do + local id, name, clientTime, serverHour, serverMinute = strsplit(":", v) + + -- ex: guildMembers["Thaoky"]["RaidFood"] = { clientTime = 123, serverHour = ... } + guildMembers[sender][name] = {} + local tab = guildMembers[sender][name] + tab.id = tonumber(id) + tab.clientTime = tonumber(clientTime) + tab.serverHour = tonumber(serverHour) + tab.serverMinute = tonumber(serverMinute) + end + addon:SendMessage("DATASTORE_GUILD_BANKTABS_UPDATED", sender) +end + +local function GuildBroadcast(messageType, ...) + local serializedData = addon:Serialize(messageType, ...) + addon:SendCommMessage(commPrefix, serializedData, "GUILD") +end + +local function GuildWhisper(player, messageType, ...) + if DataStore:IsGuildMemberOnline(player) then + local serializedData = addon:Serialize(messageType, ...) + addon:SendCommMessage(commPrefix, serializedData, "WHISPER", player) + end +end + +local function IsEnchanted(link) + if not link then return end + + if not string.find(link, "0:0:0:0:0:0:0") then + -- enchants/jewels store values instead of zeroes in the link, if this string can't be found, there's at least one enchant/jewel + return true + end +end + +local BAGS = 1 -- All bags, 0 to 11, and keyring ( id -2 ) +local BANK = 2 -- 28 main slots +local GUILDBANK = 3 -- 98 main slots + +local ContainerTypes = { + [BAGS] = { + GetSize = function(self, bagID) + return GetContainerNumSlots(bagID) + end, + GetFreeSlots = function(self, bagID) + local freeSlots, bagType = GetContainerNumFreeSlots(bagID) + return freeSlots, bagType + end, + GetLink = function(self, slotID, bagID) + return GetContainerItemLink(bagID, slotID) + end, + GetCount = function(self, slotID, bagID) + local _, count = GetContainerItemInfo(bagID, slotID) + return count + end, + GetCooldown = function(self, slotID, bagID) + local startTime, duration, isEnabled = GetContainerItemCooldown(bagID, slotID) + return startTime, duration, isEnabled + end, + }, + [BANK] = { + GetSize = function(self) + return NUM_BANKGENERIC_SLOTS or 28 -- hardcoded in case the constant is not set + end, + GetFreeSlots = function(self) + local freeSlots, bagType = GetContainerNumFreeSlots(-1) -- -1 = player bank + return freeSlots, bagType + end, + GetLink = function(self, slotID) + return GetInventoryItemLink("player", slotID) + end, + GetCount = function(self, slotID) + return GetInventoryItemCount("player", slotID) + end, + GetCooldown = function(self, slotID) + local startTime, duration, isEnabled = GetInventoryItemCooldown("player", slotID) + return startTime, duration, isEnabled + end, + }, + [GUILDBANK] = { + GetSize = function(self) + return MAX_GUILDBANK_SLOTS_PER_TAB or 98 -- hardcoded in case the constant is not set + end, + GetFreeSlots = function(self) + return nil, nil + end, + GetLink = function(self, slotID, tabID) + return GetGuildBankItemLink(tabID, slotID) + end, + GetCount = function(self, slotID, tabID) + local _, count = GetGuildBankItemInfo(tabID, slotID) + return count + end, + GetCooldown = function(self, slotID) + return nil + end, + } +} + +-- *** Scanning functions *** +local function ScanContainer(bagID, containerType) + local Container = ContainerTypes[containerType] + + local bag + if containerType == GUILDBANK then + local thisGuild = GetThisGuild() + if not thisGuild then return end + + bag = thisGuild.Tabs[bagID] -- bag is actually the current tab + else + bag = addon.ThisCharacter.Containers["Bag" .. bagID] + wipe(bag.cooldowns) -- does not exist for a guild bank + end + + wipe(bag.ids) -- clean existing bag data + wipe(bag.counts) + wipe(bag.links) + + local link, count + local startTime, duration, isEnabled + + bag.size = Container:GetSize(bagID) + bag.freeslots, bag.bagtype = Container:GetFreeSlots(bagID) + + -- Scan from 1 to bagsize for normal bags or guild bank tabs, but from 40 to 67 for main bank slots + local baseIndex = (containerType == BANK) and 39 or 0 + local index + + for slotID = baseIndex + 1, baseIndex + bag.size do + index = slotID - baseIndex + link = Container:GetLink(slotID, bagID) + if link then + bag.ids[index] = tonumber(link:match("item:(%d+)")) + + if IsEnchanted(link) then + bag.links[index] = link + end + + count = Container:GetCount(slotID, bagID) + if count and count > 1 then + bag.counts[index] = count -- only save the count if it's > 1 (to save some space since a count of 1 is extremely redundant) + end + end + + startTime, duration, isEnabled = Container:GetCooldown(slotID, bagID) + if startTime and startTime > 0 then + bag.cooldowns[index] = startTime .."|".. duration .. "|" .. 1 + end + end + + addon.ThisCharacter.lastUpdate = time() +end + +local function ScanBagSlotsInfo() + local char = addon.ThisCharacter + + local numBagSlots = 0 + local numFreeBagSlots = 0 + + for bagID = 0, NUM_BAG_SLOTS do + local bag = char.Containers["Bag" .. bagID] + numBagSlots = numBagSlots + bag.size + numFreeBagSlots = numFreeBagSlots + bag.freeslots + end + + char.numBagSlots = numBagSlots + char.numFreeBagSlots = numFreeBagSlots +end + +local function ScanBankSlotsInfo() + local char = addon.ThisCharacter + + local numBankSlots = NUM_BANKGENERIC_SLOTS + local numFreeBankSlots = char.Containers["Bag100"].freeslots + + for bagID = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do -- 5 to 11 + local bag = char.Containers["Bag" .. bagID] + + numBankSlots = numBankSlots + bag.size + numFreeBankSlots = numFreeBankSlots + bag.freeslots + end + + char.numBankSlots = numBankSlots + char.numFreeBankSlots = numFreeBankSlots +end + +local function ScanGuildBankInfo() + -- only the current tab can be updated + local thisGuild = GetThisGuild() + local tabID = GetCurrentGuildBankTab() + local t = thisGuild.Tabs[tabID] -- t = current tab + + t.name, t.icon = GetGuildBankTabInfo(tabID) + t.visitedBy = UnitName("player") + t.ClientTime = time() + if GetLocale() == "enUS" then -- adjust this test if there's demand + t.ClientDate = date("%m/%d/%Y") + else + t.ClientDate = date("%d/%m/%Y") + end + t.ClientHour = tonumber(date("%H")) + t.ClientMinute = tonumber(date("%M")) + t.ServerHour, t.ServerMinute = GetGameTime() +end + +local function ScanBag(bagID) + if bagID < 0 then return end + + local char = addon.ThisCharacter + local bag = char.Containers["Bag" .. bagID] + + if bagID == 0 then -- Bag 0 + bag.icon = "Interface\\Buttons\\Button-Backpack-Up"; + bag.link = nil; + else -- Bags 1 through 11 + bag.icon = GetInventoryItemTexture("player", ContainerIDToInventoryID(bagID)) + bag.link = GetInventoryItemLink("player", ContainerIDToInventoryID(bagID)) + end + ScanContainer(bagID, BAGS) + ScanBagSlotsInfo() +end + +local function ScanKeyRing() + local char = addon.ThisCharacter + local bag = char.Containers["Bag" .. KEYRING_CONTAINER] + + bag.icon = "Interface\\Icons\\INV_Misc_Key_14"; + bag.link = nil + ScanContainer(KEYRING_CONTAINER, BAGS) +end + +-- *** Event Handlers *** +local function OnBagUpdate(event, bag) + if bag < 0 then + return + end + + if (bag >= 5) and (bag <= 11) and not addon.isBankOpen then + return + end + + if bag == 0 then -- bag is 0 for both the keyring and the original backpack + ScanKeyRing() + end + ScanBag(bag) +end + +local function OnBankFrameClosed() + addon.isBankOpen = nil + addon:UnregisterEvent("BANKFRAME_CLOSED") + addon:UnregisterEvent("PLAYERBANKSLOTS_CHANGED") +end + +local function OnPlayerBankSlotsChanged(event, slotID) + -- from top left to bottom right, slotID = 1 to 28for main slots, and 29 to 35 for the additional bags + if (slotID >= 29) and (slotID <= 35) then + ScanBag(slotID - 24) -- bagID for bank bags goes from 5 to 11, so slotID - 24 + else + ScanContainer(100, BANK) + ScanBankSlotsInfo() + end +end + +local function OnBankFrameOpened() + addon.isBankOpen = true + for bagID = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do -- 5 to 11 + ScanBag(bagID) + end + ScanContainer(100, BANK) + ScanBankSlotsInfo() + addon:RegisterEvent("BANKFRAME_CLOSED", OnBankFrameClosed) + addon:RegisterEvent("PLAYERBANKSLOTS_CHANGED", OnPlayerBankSlotsChanged) +end + +local function OnGuildBankFrameClosed() + addon:UnregisterEvent("GUILDBANKFRAME_CLOSED") + addon:UnregisterEvent("GUILDBANKBAGSLOTS_CHANGED") + + local guildName = GetGuildInfo("player") + if guildName then + GuildBroadcast(MSG_SEND_BANK_TIMESTAMPS, GetBankTimestamps(guildName)) + end +end + +local function OnGuildBankBagSlotsChanged() + ScanContainer(GetCurrentGuildBankTab(), GUILDBANK) + ScanGuildBankInfo() +end + +local function OnGuildBankFrameOpened() + addon:RegisterEvent("GUILDBANKFRAME_CLOSED", OnGuildBankFrameClosed) + addon:RegisterEvent("GUILDBANKBAGSLOTS_CHANGED", OnGuildBankBagSlotsChanged) + + local thisGuild = GetThisGuild() + if thisGuild then + thisGuild.money = GetGuildBankMoney() + thisGuild.faction = UnitFactionGroup("player") + end +end + +-- ** Mixins ** +local function _GetContainer(character, containerID) + -- containerID can be number or string + return character.Containers["Bag" .. containerID] +end + +local function _GetContainers(character) + return character.Containers +end + +local BagTypeStrings = { + [1] = BI["Quiver"], + [2] = BI["Ammo Pouch"], + [4] = BI["Soul Bag"], + [8] = BI["Leatherworking Bag"], + [16] = BI["Inscription Bag"], + [32] = BI["Herb Bag"], + [64] = BI["Enchanting Bag"], + [128] = BI["Engineering Bag"], + [512] = BI["Gem Bag"], + [1024] = BI["Mining Bag"], +} + +local function _GetContainerInfo(character, containerID) + local bag = _GetContainer(character, containerID) + return bag.icon, bag.link, bag.size, bag.freeslots, BagTypeStrings[bag.bagtype] +end + +local function _GetContainerSize(character, containerID) + -- containerID can be number or string + return character.Containers["Bag" .. containerID].size +end + +local function _GetSlotInfo(bag, slotID) + assert(type(bag) == "table") -- this is the pointer to a bag table, obtained through addon:GetContainer() + assert(type(slotID) == "number") + + -- return itemID, itemLink, itemCount + return bag.ids[slotID], bag.links[slotID], bag.counts[slotID] or 1 +end + +local function _GetContainerCooldownInfo(bag, slotID) + assert(type(bag) == "table") -- this is the pointer to a bag table, obtained through addon:GetContainer() + assert(type(slotID) == "number") + + local cd = bag.cooldowns[slotID] + if cd then + local startTime, duration, isEnabled = strsplit("|", bag.cooldowns[slotID]) + local remaining = duration - (GetTime() - startTime) + + if remaining > 0 then -- valid cd ? return it + return tonumber(startTime), tonumber(duration), tonumber(isEnabled) + end + -- cooldown expired ? clean it from the db + bag.cooldowns[slotID] = nil + end +end + +local function _GetContainerItemCount(character, searchedID) + local bagCount = 0 + local bankCount = 0 + local id + + for containerName, container in pairs(character.Containers) do + for slotID=1, container.size do + id = container.ids[slotID] + + if (id) and (id == searchedID) then + local itemCount = container.counts[slotID] or 1 + + if (containerName == "Bag100") then + bankCount = bankCount + itemCount + elseif (containerName == "Bag-2") then + bagCount = bagCount + itemCount + else + local bagNum = tonumber(string.sub(containerName, 4)) + if (bagNum >= 0) and (bagNum <= 4) then + bagCount = bagCount + itemCount + else + bankCount = bankCount + itemCount + end + end + end + end + end + + return bagCount, bankCount +end + +local function _GetNumBagSlots(character) + return character.numBagSlots +end + +local function _GetNumFreeBagSlots(character) + return character.numFreeBagSlots +end + +local function _GetNumBankSlots(character) + return character.numBankSlots +end + +local function _GetNumFreeBankSlots(character) + return character.numFreeBankSlots +end + +local function _DeleteGuild(name, realm, account) + realm = realm or GetRealmName() + account = account or THIS_ACCOUNT + + local key = format("%s.%s.%s", account, realm, name) + addon.db.global.Guilds[key] = nil +end + +local function _GetGuildBankItemCount(guild, searchedID) + local count = 0 + for _, container in pairs(guild.Tabs) do + for slotID, id in pairs(container.ids) do + if (id == searchedID) then + count = count + (container.counts[slotID] or 1) + end + end + end + return count +end + +local function _GetGuildBankTab(guild, tabID) + return guild.Tabs[tabID] +end + +local function _GetGuildBankTabName(guild, tabID) + return guild.Tabs[tabID].name +end + +local function _GetGuildBankTabIcon(guild, tabID) + return guild.Tabs[tabID].icon +end + +local function _GetGuildBankTabItemCount(guild, tabID, searchedID) + local count = 0 + local container = guild.Tabs[tabID] + + for slotID, id in pairs(container.ids) do + if (id == searchedID) then + count = count + (container.counts[slotID] or 1) + end + end + return count +end + +local function _GetGuildBankTabLastUpdate(guild, tabID) + return guild.Tabs[tabID].ClientTime +end + +local function _GetGuildBankMoney(guild) + return guild.money +end + +local function _GetGuildBankFaction(guild) + return guild.faction +end + +local function _ImportGuildBankTab(guild, tabID, data) + wipe(guild.Tabs[tabID]) -- clear existing data + guild.Tabs[tabID] = data +end + +local function _GetGuildBankTabSuppliers() + return guildMembers +end + +local function _GetGuildMemberBankTabInfo(member, tabName) + -- for the current guild, return the guild member's data about a given tab + if guildMembers[member] then + if guildMembers[member][tabName] then + local tab = guildMembers[member][tabName] + return tab.clientTime, tab.serverHour, tab.serverMinute + end + end +end + +local function _RequestGuildMemberBankTab(member, tabName) + GuildWhisper(member, MSG_BANKTAB_REQUEST, tabName) +end + +local function _RejectBankTabRequest(member) + GuildWhisper(member, MSG_BANKTAB_REQUEST_REJECTED) +end + +local function _SendBankTabToGuildMember(member, tabName) + -- send the actual content of a bank tab to a guild member + local thisGuild = GetThisGuild() + if thisGuild then + local tabID + if guildMembers[member] then + if guildMembers[member][tabName] then + tabID = guildMembers[member][tabName].id + end + end + + if tabID then + GuildWhisper(member, MSG_BANKTAB_TRANSFER, thisGuild.Tabs[tabID]) + end + end +end + +local PublicMethods = { + GetContainer = _GetContainer, + GetContainers = _GetContainers, + GetContainerInfo = _GetContainerInfo, + GetContainerSize = _GetContainerSize, + GetSlotInfo = _GetSlotInfo, + GetContainerCooldownInfo = _GetContainerCooldownInfo, + GetContainerItemCount = _GetContainerItemCount, + GetNumBagSlots = _GetNumBagSlots, + GetNumFreeBagSlots = _GetNumFreeBagSlots, + GetNumBankSlots = _GetNumBankSlots, + GetNumFreeBankSlots = _GetNumFreeBankSlots, + DeleteGuild = _DeleteGuild, + GetGuildBankItemCount = _GetGuildBankItemCount, + GetGuildBankTab = _GetGuildBankTab, + GetGuildBankTabName = _GetGuildBankTabName, + GetGuildBankTabIcon = _GetGuildBankTabIcon, + GetGuildBankTabItemCount = _GetGuildBankTabItemCount, + GetGuildBankTabLastUpdate = _GetGuildBankTabLastUpdate, + GetGuildBankMoney = _GetGuildBankMoney, + GetGuildBankFaction = _GetGuildBankFaction, + ImportGuildBankTab = _ImportGuildBankTab, + GetGuildMemberBankTabInfo = _GetGuildMemberBankTabInfo, + RequestGuildMemberBankTab = _RequestGuildMemberBankTab, + RejectBankTabRequest = _RejectBankTabRequest, + SendBankTabToGuildMember = _SendBankTabToGuildMember, + GetGuildBankTabSuppliers = _GetGuildBankTabSuppliers, +} + +-- *** Guild Comm *** +--[[ *** Protocol *** + +At login: + Broadcast of guild bank timers on the guild channel +After the guild bank frame is closed: + Broadcast of guild bank timers on the guild channel + +Client addon calls: DataStore:RequestGuildMemberBankTab() + Client Server + + ==> MSG_BANKTAB_REQUEST + <== MSG_BANKTAB_REQUEST_ACK (immediate ack) + + <== MSG_BANKTAB_REQUEST_REJECTED (stop) + or + <== MSG_BANKTAB_TRANSFER (actual data transfer) +--]] + +local function OnAnnounceLogin(self, guildName) + -- when the main DataStore module sends its login info, share the guild bank last visit time across guild members + local timestamps = GetBankTimestamps(guildName) + if timestamps then -- nil if guild bank hasn't been visited yet, so don't broadcast anything + GuildBroadcast(MSG_SEND_BANK_TIMESTAMPS, timestamps) + end +end + +local function OnGuildMemberOffline(self, member) + guildMembers[member] = nil + addon:SendMessage("DATASTORE_GUILD_BANKTABS_UPDATED", member) +end + +local GuildCommCallbacks = { + [MSG_SEND_BANK_TIMESTAMPS] = function(sender, timestamps) + if sender ~= UnitName("player") then -- don't send back to self + local timestamps = GetBankTimestamps() + if timestamps then + GuildWhisper(sender, MSG_BANK_TIMESTAMPS_REPLY, timestamps) -- reply by sending my own data.. + end + end + SaveBankTimestamps(sender, timestamps) + end, + [MSG_BANK_TIMESTAMPS_REPLY] = function(sender, timestamps) + SaveBankTimestamps(sender, timestamps) + end, + [MSG_BANKTAB_REQUEST] = function(sender, tabName) + -- trigger the event only, actual response (ack or not) must be handled by client addons + GuildWhisper(sender, MSG_BANKTAB_REQUEST_ACK) -- confirm that the request has been received + addon:SendMessage("DATASTORE_BANKTAB_REQUESTED", sender, tabName) + end, + [MSG_BANKTAB_REQUEST_ACK] = function(sender) + addon:SendMessage("DATASTORE_BANKTAB_REQUEST_ACK", sender) + end, + [MSG_BANKTAB_REQUEST_REJECTED] = function(sender) + addon:SendMessage("DATASTORE_BANKTAB_REQUEST_REJECTED", sender) + end, + [MSG_BANKTAB_TRANSFER] = function(sender, data) + local guildName = GetGuildInfo("player") + local guild = GetThisGuild() + + for tabID, tab in pairs(guild.Tabs) do + if tab.name == data.name then -- this is the tab being updated + _ImportGuildBankTab(guild, tabID, data) + addon:SendMessage("DATASTORE_BANKTAB_UPDATE_SUCCESS", sender, guildName, data.name, tabID) + GuildBroadcast(MSG_SEND_BANK_TIMESTAMPS, GetBankTimestamps(guildName)) + end + end + end, +} + +function addon:OnInitialize() + addon.db = LibStub("AceDB-3.0"):New(addonName .. "DB", AddonDB_Defaults) + UpdateDB() + + DataStore:RegisterModule(addonName, addon, PublicMethods) + DataStore:SetGuildCommCallbacks(commPrefix, GuildCommCallbacks) + + DataStore:SetCharacterBasedMethod("GetContainer") + DataStore:SetCharacterBasedMethod("GetContainers") + DataStore:SetCharacterBasedMethod("GetContainerInfo") + DataStore:SetCharacterBasedMethod("GetContainerSize") + DataStore:SetCharacterBasedMethod("GetContainerItemCount") + DataStore:SetCharacterBasedMethod("GetNumBagSlots") + DataStore:SetCharacterBasedMethod("GetNumFreeBagSlots") + DataStore:SetCharacterBasedMethod("GetNumBankSlots") + DataStore:SetCharacterBasedMethod("GetNumFreeBankSlots") + + DataStore:SetGuildBasedMethod("GetGuildBankItemCount") + DataStore:SetGuildBasedMethod("GetGuildBankTab") + DataStore:SetGuildBasedMethod("GetGuildBankTabName") + DataStore:SetGuildBasedMethod("GetGuildBankTabIcon") + DataStore:SetGuildBasedMethod("GetGuildBankTabItemCount") + DataStore:SetGuildBasedMethod("GetGuildBankTabLastUpdate") + DataStore:SetGuildBasedMethod("GetGuildBankMoney") + DataStore:SetGuildBasedMethod("GetGuildBankFaction") + DataStore:SetGuildBasedMethod("ImportGuildBankTab") + + addon:RegisterMessage("DATASTORE_ANNOUNCELOGIN", OnAnnounceLogin) + addon:RegisterMessage("DATASTORE_GUILD_MEMBER_OFFLINE", OnGuildMemberOffline) + addon:RegisterComm(commPrefix, DataStore:GetGuildCommHandler()) +end + +function addon:OnEnable() + -- manually update bags 0 to 4, then register the event, this avoids reacting to the flood of BAG_UPDATE events at login + for bagID = 0, NUM_BAG_SLOTS do + ScanBag(bagID) + end + ScanKeyRing() + + addon:RegisterEvent("BAG_UPDATE", OnBagUpdate) + addon:RegisterEvent("BANKFRAME_OPENED", OnBankFrameOpened) + addon:RegisterEvent("GUILDBANKFRAME_OPENED", OnGuildBankFrameOpened) +end + +function addon:OnDisable() + addon:UnregisterEvent("BAG_UPDATE") + addon:UnregisterEvent("BANKFRAME_OPENED") + addon:UnregisterEvent("GUILDBANKFRAME_OPENED") +end diff --git a/Altoholic-Addon/DataStore_Containers/DataStore_Containers.toc b/Altoholic-Addon/DataStore_Containers/DataStore_Containers.toc new file mode 100644 index 0000000..e5ed9f0 --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/DataStore_Containers.toc @@ -0,0 +1,18 @@ +## Interface: 30300 +## Title: DataStore_Containers +## Notes: Stores information about character bags, bank, and guild banks +## Author: Thaoky (EU-Marécages de Zangar) +## Version: 3.3.001 +## Dependencies: DataStore +## OptionalDeps: Ace3 +## SavedVariables: DataStore_ContainersDB +## X-Category: Interface Enhancements +## X-Embeds: Ace3 +## X-Curse-Packaged-Version: r22 +## X-Curse-Project-Name: DataStore_Containers +## X-Curse-Project-ID: datastore_containers +## X-Curse-Repository-ID: wow/datastore_containers/mainline + +embeds.xml + +DataStore_Containers.lua diff --git a/Altoholic-Addon/DataStore_Containers/LICENSE.txt b/Altoholic-Addon/DataStore_Containers/LICENSE.txt new file mode 100644 index 0000000..4301cb1 --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/LICENSE.txt @@ -0,0 +1,2 @@ + +All Rights Reserved unless otherwise explicitly stated. \ No newline at end of file diff --git a/Altoholic-Addon/DataStore_Containers/embeds.xml b/Altoholic-Addon/DataStore_Containers/embeds.xml new file mode 100644 index 0000000..f53a20a --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/embeds.xml @@ -0,0 +1,5 @@ + + + + diff --git a/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibBabble-3.0.lua b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibBabble-3.0.lua new file mode 100644 index 0000000..fc4a012 --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibBabble-3.0.lua @@ -0,0 +1,292 @@ +-- LibBabble-3.0 is hereby placed in the Public Domain +-- Credits: ckknight +local LIBBABBLE_MAJOR, LIBBABBLE_MINOR = "LibBabble-3.0", 2 + +local LibBabble = LibStub:NewLibrary(LIBBABBLE_MAJOR, LIBBABBLE_MINOR) +if not LibBabble then + return +end + +local data = LibBabble.data or {} +for k,v in pairs(LibBabble) do + LibBabble[k] = nil +end +LibBabble.data = data + +local tablesToDB = {} +for namespace, db in pairs(data) do + for k,v in pairs(db) do + tablesToDB[v] = db + end +end + +local function warn(message) + local _, ret = pcall(error, message, 3) + geterrorhandler()(ret) +end + +local lookup_mt = { __index = function(self, key) + local db = tablesToDB[self] + local current_key = db.current[key] + if current_key then + self[key] = current_key + return current_key + end + local base_key = db.base[key] + local real_MAJOR_VERSION + for k,v in pairs(data) do + if v == db then + real_MAJOR_VERSION = k + break + end + end + if not real_MAJOR_VERSION then + real_MAJOR_VERSION = LIBBABBLE_MAJOR + end + if base_key then + warn(("%s: Translation %q not found for locale %q"):format(real_MAJOR_VERSION, key, GetLocale())) + rawset(self, key, base_key) + return base_key + end + warn(("%s: Translation %q not found."):format(real_MAJOR_VERSION, key)) + rawset(self, key, key) + return key +end } + +local function initLookup(module, lookup) + local db = tablesToDB[module] + for k in pairs(lookup) do + lookup[k] = nil + end + setmetatable(lookup, lookup_mt) + tablesToDB[lookup] = db + db.lookup = lookup + return lookup +end + +local function initReverse(module, reverse) + local db = tablesToDB[module] + for k in pairs(reverse) do + reverse[k] = nil + end + for k,v in pairs(db.current) do + reverse[v] = k + end + tablesToDB[reverse] = db + db.reverse = reverse + db.reverseIterators = nil + return reverse +end + +local prototype = {} +local prototype_mt = {__index = prototype} + +--[[--------------------------------------------------------------------------- +Notes: + * If you try to access a nonexistent key, it will warn but allow the code to pass through. +Returns: + A lookup table for english to localized words. +Example: + local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want. + local BL = B:GetLookupTable() + assert(BL["Some english word"] == "Some localized word") + DoSomething(BL["Some english word that doesn't exist"]) -- warning! +-----------------------------------------------------------------------------]] +function prototype:GetLookupTable() + local db = tablesToDB[self] + + local lookup = db.lookup + if lookup then + return lookup + end + return initLookup(self, {}) +end +--[[--------------------------------------------------------------------------- +Notes: + * If you try to access a nonexistent key, it will return nil. +Returns: + A lookup table for english to localized words. +Example: + local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want. + local B_has = B:GetUnstrictLookupTable() + assert(B_has["Some english word"] == "Some localized word") + assert(B_has["Some english word that doesn't exist"] == nil) +-----------------------------------------------------------------------------]] +function prototype:GetUnstrictLookupTable() + local db = tablesToDB[self] + + return db.current +end +--[[--------------------------------------------------------------------------- +Notes: + * If you try to access a nonexistent key, it will return nil. + * This is useful for checking if the base (English) table has a key, even if the localized one does not have it registered. +Returns: + A lookup table for english to localized words. +Example: + local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want. + local B_hasBase = B:GetBaseLookupTable() + assert(B_hasBase["Some english word"] == "Some english word") + assert(B_hasBase["Some english word that doesn't exist"] == nil) +-----------------------------------------------------------------------------]] +function prototype:GetBaseLookupTable() + local db = tablesToDB[self] + + return db.base +end +--[[--------------------------------------------------------------------------- +Notes: + * If you try to access a nonexistent key, it will return nil. + * This will return only one English word that it maps to, if there are more than one to check, see :GetReverseIterator("word") +Returns: + A lookup table for localized to english words. +Example: + local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want. + local BR = B:GetReverseLookupTable() + assert(BR["Some localized word"] == "Some english word") + assert(BR["Some localized word that doesn't exist"] == nil) +-----------------------------------------------------------------------------]] +function prototype:GetReverseLookupTable() + local db = tablesToDB[self] + + local reverse = db.reverse + if reverse then + return reverse + end + return initReverse(self, {}) +end +local blank = {} +local weakVal = {__mode='v'} +--[[--------------------------------------------------------------------------- +Arguments: + string - the localized word to chek for. +Returns: + An iterator to traverse all English words that map to the given key +Example: + local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want. + for word in B:GetReverseIterator("Some localized word") do + DoSomething(word) + end +-----------------------------------------------------------------------------]] +function prototype:GetReverseIterator(key) + local db = tablesToDB[self] + local reverseIterators = db.reverseIterators + if not reverseIterators then + reverseIterators = setmetatable({}, weakVal) + db.reverseIterators = reverseIterators + elseif reverseIterators[key] then + return pairs(reverseIterators[key]) + end + local t + for k,v in pairs(db.current) do + if v == key then + if not t then + t = {} + end + t[k] = true + end + end + reverseIterators[key] = t or blank + return pairs(reverseIterators[key]) +end +--[[--------------------------------------------------------------------------- +Returns: + An iterator to traverse all translations English to localized. +Example: + local B = LibStub("LibBabble-Module-3.0") -- where Module is what you want. + for english, localized in B:Iterate() do + DoSomething(english, localized) + end +-----------------------------------------------------------------------------]] +function prototype:Iterate() + local db = tablesToDB[self] + + return pairs(db.current) +end + +-- #NODOC +-- modules need to call this to set the base table +function prototype:SetBaseTranslations(base) + local db = tablesToDB[self] + local oldBase = db.base + if oldBase then + for k in pairs(oldBase) do + oldBase[k] = nil + end + for k, v in pairs(base) do + oldBase[k] = v + end + base = oldBase + else + db.base = base + end + for k,v in pairs(base) do + if v == true then + base[k] = k + end + end +end + +local function init(module) + local db = tablesToDB[module] + if db.lookup then + initLookup(module, db.lookup) + end + if db.reverse then + initReverse(module, db.reverse) + end + db.reverseIterators = nil +end + +-- #NODOC +-- modules need to call this to set the current table. if current is true, use the base table. +function prototype:SetCurrentTranslations(current) + local db = tablesToDB[self] + if current == true then + db.current = db.base + else + local oldCurrent = db.current + if oldCurrent then + for k in pairs(oldCurrent) do + oldCurrent[k] = nil + end + for k, v in pairs(current) do + oldCurrent[k] = v + end + current = oldCurrent + else + db.current = current + end + end + init(self) +end + +for namespace, db in pairs(data) do + setmetatable(db.module, prototype_mt) + init(db.module) +end + +-- #NODOC +-- modules need to call this to create a new namespace. +function LibBabble:New(namespace, minor) + local module, oldminor = LibStub:NewLibrary(namespace, minor) + if not module then + return + end + + if not oldminor then + local db = { + module = module, + } + data[namespace] = db + tablesToDB[module] = db + else + for k,v in pairs(module) do + module[k] = nil + end + end + + setmetatable(module, prototype_mt) + + return module +end diff --git a/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibBabble-Inventory-3.0.lua b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibBabble-Inventory-3.0.lua new file mode 100644 index 0000000..bbb5ef4 --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibBabble-Inventory-3.0.lua @@ -0,0 +1,1330 @@ +--[[ +Name: LibBabble-Inventory-3.0 +Revision: $Rev: 101 $ +Maintainers: ckknight, nevcairiel, Ackis +Website: http://www.wowace.com/projects/libbabble-inventory-3-0/ +Dependencies: None +License: MIT +]] + +local MAJOR_VERSION = "LibBabble-Inventory-3.0" +local MINOR_VERSION = 90000 + tonumber(("$Rev: 101 $"):match("%d+")) + +if not LibStub then error(MAJOR_VERSION .. " requires LibStub.") end +local lib = LibStub("LibBabble-3.0"):New(MAJOR_VERSION, MINOR_VERSION) +if not lib then return end + +local GAME_LOCALE = GetLocale() + +lib:SetBaseTranslations { + Alchemy = "Alchemy", + ["Ammo Pouch"] = "Ammo Pouch", + Armor = "Armor", + ["Armor Enchantment"] = "Armor Enchantment", + Arrow = "Arrow", + Axe = "Axe", + Back = "Back", + Bag = "Bag", + Bandage = "Bandage", + Blacksmithing = "Blacksmithing", + Blue = "Blue", + Book = "Book", + Bow = "Bow", + Bows = "Bows", + Bullet = "Bullet", + Chest = "Chest", + Cloth = "Cloth", + Consumable = "Consumable", + Container = "Container", + Cooking = "Cooking", + Crossbow = "Crossbow", + Crossbows = "Crossbows", + Dagger = "Dagger", + Daggers = "Daggers", + ["Death Knight"] = "Death Knight", + Devices = "Devices", + Drink = "Drink", + Druid = "Druid", + Elemental = "Elemental", + Elixir = "Elixir", + Enchanting = "Enchanting", + ["Enchanting Bag"] = "Enchanting Bag", + Engineering = "Engineering", + ["Engineering Bag"] = "Engineering Bag", + Explosives = "Explosives", + Feet = "Feet", + ["First Aid"] = "First Aid", + Fishing = "Fishing", + ["Fishing Pole"] = "Fishing Pole", + ["Fishing Poles"] = "Fishing Poles", + ["Fist Weapon"] = "Fist Weapon", + ["Fist Weapons"] = "Fist Weapons", + Flask = "Flask", + Food = "Food", + ["Food & Drink"] = "Food & Drink", + Gem = "Gem", + ["Gem Bag"] = "Gem Bag", + Glyph = "Glyph", + Green = "Green", + Gun = "Gun", + Guns = "Guns", + Hands = "Hands", + Head = "Head", + ["Held in Off-Hand"] = "Held in Off-Hand", + Herb = "Herb", + ["Herb Bag"] = "Herb Bag", + Holiday = "Holiday", + Hunter = "Hunter", + Idol = "Idol", + Idols = "Idols", + ["Inscription Bag"] = "Inscription Bag", + ["Item Enhancement"] = "Item Enhancement", + Jewelcrafting = "Jewelcrafting", + Junk = "Junk", + Key = "Key", + Leather = "Leather", + Leatherworking = "Leatherworking", + ["Leatherworking Bag"] = "Leatherworking Bag", + Legs = "Legs", + Libram = "Libram", + Librams = "Librams", + Mace = "Mace", + Mage = "Mage", + Mail = "Mail", + ["Main Hand"] = "Main Hand", + Materials = "Materials", + Meat = "Meat", + Meta = "Meta", + ["Metal & Stone"] = "Metal & Stone", + ["Mining Bag"] = "Mining Bag", + Miscellaneous = "Miscellaneous", + Mount = "Mount", + Neck = "Neck", + ["Off Hand"] = "Off Hand", + ["One-Hand"] = "One-Hand", + ["One-Handed Axes"] = "One-Handed Axes", + ["One-Handed Maces"] = "One-Handed Maces", + ["One-Handed Swords"] = "One-Handed Swords", + Orange = "Orange", + Other = "Other", + Paladin = "Paladin", + Parts = "Parts", + Pet = "Pet", + Plate = "Plate", + Polearm = "Polearm", + Polearms = "Polearms", + Potion = "Potion", + Priest = "Priest", + Prismatic = "Prismatic", + Projectile = "Projectile", + Purple = "Purple", + Quest = "Quest", + Quiver = "Quiver", + Ranged = "Ranged", + Reagent = "Reagent", + Recipe = "Recipe", + Red = "Red", + Relic = "Relic", + Ring = "Ring", + Rogue = "Rogue", + Scroll = "Scroll", + Shaman = "Shaman", + Shield = "Shield", + Shields = "Shields", + Shirt = "Shirt", + Shoulder = "Shoulder", + Sigils = "Sigils", + Simple = "Simple", + ["Soul Bag"] = "Soul Bag", + Staff = "Staff", + Staves = "Staves", + Sword = "Sword", + Tabard = "Tabard", + Tailoring = "Tailoring", + Thrown = "Thrown", + Totem = "Totem", + Totems = "Totems", + ["Trade Goods"] = "Trade Goods", + Trinket = "Trinket", + ["Two-Hand"] = "Two-Hand", + ["Two-Handed Axes"] = "Two-Handed Axes", + ["Two-Handed Maces"] = "Two-Handed Maces", + ["Two-Handed Swords"] = "Two-Handed Swords", + Waist = "Waist", + Wand = "Wand", + Wands = "Wands", + Warlock = "Warlock", + Warrior = "Warrior", + Weapon = "Weapon", + ["Weapon Enchantment"] = "Weapon Enchantment", + Wrist = "Wrist", + Yellow = "Yellow", +} + + +if GAME_LOCALE == "enUS" then + lib:SetCurrentTranslations(true) +elseif GAME_LOCALE == "deDE" then + lib:SetCurrentTranslations { + Alchemy = "Alchemie", + ["Ammo Pouch"] = "Munitionsbeutel", + Armor = "Rüstung", + ["Armor Enchantment"] = "Rüstungsverzauberung", + Arrow = "Pfeil", + Axe = "Axt", + Back = "Rücken", + Bag = "Behälter", + Bandage = "Verband", + Blacksmithing = "Schmiedekunst", + Blue = "Blau", + Book = "Buch", + Bow = "Bogen", + Bows = "Bögen", + Bullet = "Kugel", + Chest = "Brust", + Cloth = "Stoff", + Consumable = "Verbrauchbar", + Container = "Behälter", + Cooking = "Kochkunst", + Crossbow = "Armbrust", + Crossbows = "Armbrüste", + Dagger = "Dolch", + Daggers = "Dolche", + ["Death Knight"] = "Todesritter", + Devices = "Geräte", + Drink = "Getränk", + Druid = "Druide", + Elemental = "Elementar", + Elixir = "Elixier", + Enchanting = "Verzauberkunst", + ["Enchanting Bag"] = "Verzauberertasche", + Engineering = "Ingenieurskunst", + ["Engineering Bag"] = "Ingenieurstasche", + Explosives = "Sprengstoff", + Feet = "Füße", + ["First Aid"] = "Erste Hilfe", + Fishing = "Angeln", + ["Fishing Pole"] = "Angelrute", + ["Fishing Poles"] = "Angelruten", + ["Fist Weapon"] = "Faustwaffe", + ["Fist Weapons"] = "Faustwaffen", + Flask = "Fläschchen", + Food = "Essen", + ["Food & Drink"] = "Essen & Trinken", + Gem = "Edelstein", + ["Gem Bag"] = "Edelsteintasche", + Glyph = "Glyphe", + Green = "Grün", + Gun = "Schusswaffe", + Guns = "Schusswaffen", + Hands = "Hände", + Head = "Kopf", + ["Held in Off-Hand"] = "In Schildhand geführt", + Herb = "Kräuter", + ["Herb Bag"] = "Kräutertasche", + Holiday = "Festtag", + Hunter = "Jäger", + Idol = "Götze", + Idols = "Götzen", + ["Inscription Bag"] = "Schreibertasche", + ["Item Enhancement"] = "Gegenstandsverbesserung", + Jewelcrafting = "Juwelenschleifen", + Junk = "Plunder", + Key = "Schlüssel", + Leather = "Leder", + Leatherworking = "Lederverarbeitung", + ["Leatherworking Bag"] = "Lederertasche", + Legs = "Beine", + Libram = "Buchband", + Librams = "Buchbände", + Mace = "Streitkolben", + Mage = "Magier", + Mail = "Schwere Rüstung", + ["Main Hand"] = "Waffenhand", + Materials = "Materialien", + Meat = "Fleisch", + Meta = "Meta", + ["Metal & Stone"] = "Metall & Stein", + ["Mining Bag"] = "Bergbautasche", + Miscellaneous = "Verschiedenes", + Mount = "Reittier", + Neck = "Hals", + ["Off Hand"] = "Schildhand", + ["One-Hand"] = "Einhändig", + ["One-Handed Axes"] = "Einhandäxte", + ["One-Handed Maces"] = "Einhandstreitkolben", + ["One-Handed Swords"] = "Einhandschwerter", + Orange = "Orange", + Other = "Sonstige", + Paladin = "Paladin", + Parts = "Teile", + Pet = "Begleiter", + Plate = "Platte", + Polearm = "Stangenwaffe", + Polearms = "Stangenwaffen", + Potion = "Trank", + Priest = "Priester", + Prismatic = "Prismatisch", + Projectile = "Projektil", + Purple = "Violett", + Quest = "Quest", + Quiver = "Köcher", + Ranged = "Distanz", + Reagent = "Reagenz", + Recipe = "Rezept", + Red = "Rot", + Relic = "Relikt", + Ring = "Finger", + Rogue = "Schurke", + Scroll = "Rolle", + Shaman = "Schamane", + Shield = "Schild", + Shields = "Schilde", + Shirt = "Hemd", + Shoulder = "Schulter", + Sigils = "Siegel", + Simple = "Einfach", + ["Soul Bag"] = "Seelentasche", + Staff = "Stab", + Staves = "Stäbe", + Sword = "Schwert", + Tabard = "Wappenrock", + Tailoring = "Schneiderei", + Thrown = "Wurfwaffen", + Totem = "Totem", + Totems = "Totems", + ["Trade Goods"] = "Handwerkswaren", + Trinket = "Schmuck", + ["Two-Hand"] = "Zweihändig", + ["Two-Handed Axes"] = "Zweihandäxte", + ["Two-Handed Maces"] = "Zweihandstreitkolben", + ["Two-Handed Swords"] = "Zweihandschwerter", + Waist = "Taille", + Wand = "Zauberstab", + Wands = "Zauberstäbe", + Warlock = "Hexenmeister", + Warrior = "Krieger", + Weapon = "Waffe", + ["Weapon Enchantment"] = "Waffenverzauberung", + Wrist = "Handgelenke", + Yellow = "Gelb", +} +elseif GAME_LOCALE == "frFR" then + lib:SetCurrentTranslations { + Alchemy = "Alchimie", + ["Ammo Pouch"] = "Giberne", + Armor = "Armure", + ["Armor Enchantment"] = "Enchantements d'armure", + Arrow = "Flèche", + Axe = "Hache", + Back = "Dos", + Bag = "Sac", + Bandage = "Bandage", + Blacksmithing = "Forge", + Blue = "Bleu", + Book = "Livre", + Bow = "Arc", + Bows = "Arcs", + Bullet = "Balle", + Chest = "Torse", + Cloth = "Tissu", + Consumable = "Consommable", + Container = "Conteneur", + Cooking = "Cuisine", + Crossbow = "Arbalète", + Crossbows = "Arbalètes", + Dagger = "Dague", + Daggers = "Dagues", + ["Death Knight"] = "Chevalier de la mort", + Devices = "Élémentaire", + Drink = "Breuvage", + Druid = "Druide", + Elemental = "Élémentaire", + Elixir = "Élixir", + Enchanting = "Enchantement", + ["Enchanting Bag"] = "Sac d'enchantement", + Engineering = "Ingénierie", + ["Engineering Bag"] = "Sac d'ingéniérie", + Explosives = "Explosifs", + Feet = "Pieds", + ["First Aid"] = "Secourisme", + Fishing = "Pêche", + ["Fishing Pole"] = "Canne à pêche", + ["Fishing Poles"] = "Cannes à pêche", + ["Fist Weapon"] = "Arme de pugilat", + ["Fist Weapons"] = "Armes de pugilat", + Flask = "Flacon", + Food = "Ration", + ["Food & Drink"] = "Nourriture & boissons", + Gem = "Gemme", + ["Gem Bag"] = "Sac de gemmes", + Glyph = "Glyphe", + Green = "Verte", + Gun = "Arme à feu", + Guns = "Fusils", + Hands = "Mains", + Head = "Tête", + ["Held in Off-Hand"] = "Tenu(e) en main gauche", + Herb = "Herbes", + ["Herb Bag"] = "Sac d'herbes", + Holiday = "Vacances", + Hunter = "Chasseur", + Idol = "Idole", + Idols = "Idoles", + ["Inscription Bag"] = "Sac de calligraphie", + ["Item Enhancement"] = "Amélioration d'objet", + Jewelcrafting = "Joaillerie", + Junk = "Camelote", + Key = "Clé", + Leather = "Cuir", + Leatherworking = "Travail du cuir", + ["Leatherworking Bag"] = "Sac de travailleur du cuir", + Legs = "Jambes", + Libram = "Libram", + Librams = "Librams", + Mace = "Masse", + Mage = "Mage", + Mail = "Mailles", + ["Main Hand"] = "Main droite", + Materials = "Matériaux", + Meat = "Viande", + Meta = "Méta", + ["Metal & Stone"] = "Métal & pierre", + ["Mining Bag"] = "Sac de mineur", + Miscellaneous = "Divers", + Mount = "Monture", + Neck = "Cou", + ["Off Hand"] = "Main gauche", + ["One-Hand"] = "A une main", + ["One-Handed Axes"] = "Haches à une main", + ["One-Handed Maces"] = "Masses à une main", + ["One-Handed Swords"] = "Epées à une main", + Orange = "Orange", + Other = "Autre", + Paladin = "Paladin", + Parts = "Eléments", + Pet = "Familier", + Plate = "Plaques", + Polearm = "Arme d'hast", + Polearms = "Armes d'hast", + Potion = "Potion", + Priest = "Prêtre", + Prismatic = "Prismatique", + Projectile = "Projectile", + Purple = "Violette", + Quest = "Quête", + Quiver = "Carquois", + Ranged = "À distance", + Reagent = "Réactif", + Recipe = "Recette", + Red = "Rouge", + Relic = "Relique", + Ring = "Anneau", + Rogue = "Voleur", + Scroll = "Parchemin", + Shaman = "Chaman", + Shield = "Bouclier", + Shields = "Boucliers", + Shirt = "Chemise", + Shoulder = "Epaule", + Sigils = "Glyphes", + Simple = "Simple", + ["Soul Bag"] = "Sac d'âme", + Staff = "Bâton", + Staves = "Bâtons", + Sword = "Epée", + Tabard = "Tabard", + Tailoring = "Couture", + Thrown = "Armes de jets", + Totem = "Totem", + Totems = "Totems", + ["Trade Goods"] = "Artisanat", + Trinket = "Bijou", + ["Two-Hand"] = "Deux mains", + ["Two-Handed Axes"] = "Haches à deux mains", + ["Two-Handed Maces"] = "Masses à deux mains", + ["Two-Handed Swords"] = "Epées à deux mains", + Waist = "Taille", + Wand = "Baguette", + Wands = "Baguettes", + Warlock = "Démoniste", + Warrior = "Guerrier", + Weapon = "Arme", + ["Weapon Enchantment"] = "Enchantements d'arme", + Wrist = "Poignets", + Yellow = "Jaune", +} +elseif GAME_LOCALE == "koKR" then + lib:SetCurrentTranslations { + Alchemy = "연금술", + ["Ammo Pouch"] = "탄약 주머니", + Armor = "방어구", + ["Armor Enchantment"] = "방어구 마부", + Arrow = "화살", + Axe = "도끼", + Back = "등", + Bag = "가방", + Bandage = "붕대", + Blacksmithing = "대장기술", + Blue = "푸른색", + Book = "책", + Bow = "활", + Bows = "활류", + Bullet = "탄환", + Chest = "가슴", + Cloth = "천", + Consumable = "소비용품", + Container = "보관함", + Cooking = "요리", + Crossbow = "석궁", + Crossbows = "석궁류", + Dagger = "단검", + Daggers = "단검류", + ["Death Knight"] = "죽음의 기사", + Devices = "기계 장치", + Drink = "음료", + Druid = "드루이드", + Elemental = "원소", + Elixir = "비약", + Enchanting = "마법부여", + ["Enchanting Bag"] = "마법부여 가방", + Engineering = "기계공학", + ["Engineering Bag"] = "기계공학 가방", + Explosives = "폭발물", + Feet = "발", + ["First Aid"] = "응급치료", + Fishing = "낚시", + ["Fishing Pole"] = "낚싯대", + ["Fishing Poles"] = "낚싯대", + ["Fist Weapon"] = "장착 무기", + ["Fist Weapons"] = "장착 무기류", + Flask = "영약", + Food = "음식", + ["Food & Drink"] = "음식과 음료", + Gem = "보석", + ["Gem Bag"] = "보석 가방", + Glyph = "문양", + Green = "녹색", + Gun = "총기", + Guns = "총기류", + Hands = "손", + Head = "머리", + ["Held in Off-Hand"] = "보조장비", + Herb = "약초", + ["Herb Bag"] = "약초 가방", + Holiday = "축제용품", + Hunter = "사냥꾼", + Idol = "우상", + Idols = "우상", + ["Inscription Bag"] = "주문각인사의 가방", + ["Item Enhancement"] = "아이템 강화", + Jewelcrafting = "보석세공", + Junk = "잡동사니", + Key = "열쇠", + Leather = "가죽", + Leatherworking = "가죽세공", + ["Leatherworking Bag"] = "가죽세공 가방", + Legs = "다리", + Libram = "성서", + Librams = "성서", + Mace = "둔기", + Mage = "마법사", + Mail = "사슬", + ["Main Hand"] = "주장비", + Materials = "재료", + Meat = "고기", + Meta = "얼개", + ["Metal & Stone"] = "광물", + ["Mining Bag"] = "채광 가방", + Miscellaneous = "기타", + Mount = "탈것", + Neck = "목", + ["Off Hand"] = "보조장비", + ["One-Hand"] = "한손", + ["One-Handed Axes"] = "한손 도끼류", + ["One-Handed Maces"] = "한손 둔기류", + ["One-Handed Swords"] = "한손 도검류", + Orange = "주황색", + Other = "기타", + Paladin = "성기사", + Parts = "부품", + Pet = "애완동물", + Plate = "판금", + Polearm = "장창", + Polearms = "장창류", + Potion = "물약", + Priest = "사제", + Prismatic = "다색", + Projectile = "투사체", + Purple = "보라색", + Quest = "퀘스트", + Quiver = "화살통", + Ranged = "원거리 장비", + Reagent = "재료", + Recipe = "제조법", + Red = "붉은색", + Relic = "유물", + Ring = "손가락", + Rogue = "도적", + Scroll = "두루마리", + Shaman = "주술사", + Shield = "방패", + Shields = "방패", + Shirt = "속옷", + Shoulder = "어깨", + Sigils = "인장", + Simple = "일반", + ["Soul Bag"] = "영혼의 가방", + Staff = "지팡이", + Staves = "지팡이류", + Sword = "도검", + Tabard = "휘장", + Tailoring = "재봉술", + Thrown = "투척 무기", + Totem = "토템", + Totems = "토템", + ["Trade Goods"] = "직업용품", + Trinket = "장신구", + ["Two-Hand"] = "양손", + ["Two-Handed Axes"] = "양손 도끼류", + ["Two-Handed Maces"] = "양손 둔기류", + ["Two-Handed Swords"] = "양손 도검류", + Waist = "허리", + Wand = "마법봉", + Wands = "마법봉류", + Warlock = "흑마법사", + Warrior = "전사", + Weapon = "무기", + ["Weapon Enchantment"] = "무기 마부", + Wrist = "손목", + Yellow = "노란색", +} +elseif GAME_LOCALE == "esES" then + lib:SetCurrentTranslations { + Alchemy = "Alquimia", + ["Ammo Pouch"] = "Bolsa de Munición", + Armor = "Armadura", + ["Armor Enchantment"] = "Encantamiento de Armadura", + Arrow = "Flecha", + Axe = "Hacha", + Back = "Espalda", + Bag = "Bolsa", + Bandage = "Venda", + Blacksmithing = "Herrería", + Blue = "Azul", + Book = "Libro", + Bow = "Arco", + Bows = "Arcos", + Bullet = "Bala", + Chest = "Torso", + Cloth = "Tela", + Consumable = "Consumible", + Container = "Contenedor", + Cooking = "Cocina", + Crossbow = "Ballesta", + Crossbows = "Ballestas", + Dagger = "Daga", + Daggers = "Dagas", + ["Death Knight"] = "Caballero de la Muerte", + Devices = "Dispositivos", + Drink = "Bebida", + Druid = "Druída", + Elemental = "Elemental", + Elixir = "Elixir", + Enchanting = "Encantamiento", + ["Enchanting Bag"] = "Bolsa de Encantamiento", + Engineering = "Ingeniería", + ["Engineering Bag"] = "Bolsa de Ingeniería", + Explosives = "Explosivos", + Feet = "Pies", + ["First Aid"] = "Primeros auxilios", + Fishing = "Pesca", + ["Fishing Pole"] = "Caña de pescar", + ["Fishing Poles"] = "Cañas de pescar", + ["Fist Weapon"] = "Arma de Puño", + ["Fist Weapons"] = "Armas de Puño", + Flask = "Frasco", + Food = "Comida", + ["Food & Drink"] = "Comida y bebida", + Gem = "Gema", + ["Gem Bag"] = "Bolsa de Gemas", + Glyph = "Glifo", + Green = "Verde", + Gun = "Pistola", + Guns = "Pistolas", + Hands = "Manos", + Head = "Cabeza", + ["Held in Off-Hand"] = "Sostener con la mano izquierda", + Herb = "Herbalísmo", + ["Herb Bag"] = "Bolsa de Hierbas", + Holiday = "Festivo", + Hunter = "Cazador", + Idol = "Ídolo", + Idols = "Ídolos", + ["Inscription Bag"] = "Bolsa de Inscripción", + ["Item Enhancement"] = "Mejora de Objeto", + Jewelcrafting = "Joyería", + Junk = "Basura", + Key = "Llave", + Leather = "Cuero", + Leatherworking = "Peletería", + ["Leatherworking Bag"] = "Bolsa de Peletería", + Legs = "Piernas", + Libram = "Tratado", + Librams = "Tratados", + Mace = "Maza", + Mage = "Mago", + Mail = "Mallas", + ["Main Hand"] = "Mano Derecha", + Materials = "Materiales", + Meat = "Carne", + Meta = "Meta", + ["Metal & Stone"] = "Metal y Piedra", + ["Mining Bag"] = "Bolsa de Minería", + Miscellaneous = "Miscelánea", + Mount = "Montura", + Neck = "Cuello", + ["Off Hand"] = "Mano Izquierda", + ["One-Hand"] = "Una Mano", + ["One-Handed Axes"] = "Hachas de Una Mano", + ["One-Handed Maces"] = "Mazas de Una Mano", + ["One-Handed Swords"] = "Espadas de Una Mano", + Orange = "Naranja", + Other = "Otro", + Paladin = "Paladín", + Parts = "Partes", + Pet = "Mascota", + Plate = "Placas", + Polearm = "Arma de asta", + Polearms = "Armas de asta", + Potion = "Poción", + Priest = "Sacerdote", + Prismatic = "Prismático", + Projectile = "Proyectil", + Purple = "Morado", + Quest = "Misión", + Quiver = "Carcaj", + Ranged = "Rango", + Reagent = "Reactivo", + Recipe = "Receta", + Red = "Rojo", + Relic = "Reliquia", + Ring = "Anillo", + Rogue = "Pícaro", + Scroll = "Pergamino", + Shaman = "Chamán", + Shield = "Escudo", + Shields = "Escudos", + Shirt = "Camisa", + Shoulder = "Hombros", + Sigils = "Sigilos", + Simple = "Simple", + ["Soul Bag"] = "Bolsa de Almas", + Staff = "Bastón", + Staves = "Bastones", + Sword = "Espada", + Tabard = "Tabardo", + Tailoring = "Sastrería", + Thrown = "Arrojadiza", + Totem = "Tótem", + Totems = "Tótems", + ["Trade Goods"] = "Objeto comerciable", + Trinket = "Abalorio", + ["Two-Hand"] = "Dos Manos", + ["Two-Handed Axes"] = "Hachas a Dos Manos", + ["Two-Handed Maces"] = "Mazas a Dos Manos", + ["Two-Handed Swords"] = "Espadas a Dos Manos", + Waist = "Cintura", + Wand = "Varita", + Wands = "Varitas", + Warlock = "Brujo", + Warrior = "Guerrero", + Weapon = "Arma", + ["Weapon Enchantment"] = "Encantamiento de Armas", + Wrist = "Muñeca", + Yellow = "Amarillo", +} +elseif GAME_LOCALE == "esMX" then + lib:SetCurrentTranslations { + Alchemy = "Alquimia", + ["Ammo Pouch"] = "Bolsa de Munición", + Armor = "Armadura", + ["Armor Enchantment"] = "Encantamiento de Armadura", + Arrow = "Flecha", + Axe = "Hacha", + Back = "Espalda", + Bag = "Bolsa", + Bandage = "Venda", + Blacksmithing = "Herrería", + Blue = "Azul", + Book = "Libro", + Bow = "Arco", + Bows = "Arcos", + Bullet = "Bala", + Chest = "Torso", + Cloth = "Tela", + Consumable = "Consumible", + Container = "Contenedor", + Cooking = "Cocina", + Crossbow = "Ballesta", + Crossbows = "Ballestas", + Dagger = "Daga", + Daggers = "Dagas", + ["Death Knight"] = "Caballero de la Muerte", + Devices = "Dispositivos", + Drink = "Bebida", + Druid = "Druída", + Elemental = "Elemental", + Elixir = "Elixir", + Enchanting = "Encantamiento", + ["Enchanting Bag"] = "Bolsa de Encantamiento", + Engineering = "Ingeniería", + ["Engineering Bag"] = "Bolsa de Ingeniería", + Explosives = "Explosivos", + Feet = "Pies", + ["First Aid"] = "Primeros auxilios", + Fishing = "Pesca", + ["Fishing Pole"] = "Caña de pescar", + ["Fishing Poles"] = "Cañas de pescar", + ["Fist Weapon"] = "Arma de Puño", + ["Fist Weapons"] = "Armas de Puño", + Flask = "Frasco", + Food = "Comida", + ["Food & Drink"] = "Comida y bebida", + Gem = "Gema", + ["Gem Bag"] = "Bolsa de Gemas", + Glyph = "Glifo", + Green = "Verde", + Gun = "Pistola", + Guns = "Pistolas", + Hands = "Manos", + Head = "Cabeza", + ["Held in Off-Hand"] = "Sostener con la mano izquierda", + Herb = "Herbalísmo", + ["Herb Bag"] = "Bolsa de Hierbas", + Holiday = "Festivo", + Hunter = "Cazador", + Idol = "Ídolo", + Idols = "Ídolos", + ["Inscription Bag"] = "Bolsa de Inscripción", + ["Item Enhancement"] = "Mejora de Objeto", + Jewelcrafting = "Joyería", + Junk = "Basura", + Key = "Llave", + Leather = "Cuero", + Leatherworking = "Peletería", + ["Leatherworking Bag"] = "Bolsa de Peletería", + Legs = "Piernas", + Libram = "Tratado", + Librams = "Tratados", + Mace = "Maza", + Mage = "Mago", + Mail = "Mallas", + ["Main Hand"] = "Mano Derecha", + Materials = "Materiales", + Meat = "Carne", + Meta = "Meta", + ["Metal & Stone"] = "Metal y Piedra", + ["Mining Bag"] = "Bolsa de Minería", + Miscellaneous = "Miscelánea", + Mount = "Montura", + Neck = "Cuello", + ["Off Hand"] = "Mano Izquierda", + ["One-Hand"] = "Una Mano", + ["One-Handed Axes"] = "Hachas de Una Mano", + ["One-Handed Maces"] = "Mazas de Una Mano", + ["One-Handed Swords"] = "Espadas de Una Mano", + Orange = "Naranja", + Other = "Otro", + Paladin = "Paladín", + Parts = "Partes", + Pet = "Mascota", + Plate = "Placas", + Polearm = "Arma de asta", + Polearms = "Armas de asta", + Potion = "Poción", + Priest = "Sacerdote", + Prismatic = "Prismático", + Projectile = "Proyectil", + Purple = "Morado", + Quest = "Misión", + Quiver = "Carcaj", + Ranged = "Rango", + Reagent = "Reactivo", + Recipe = "Receta", + Red = "Rojo", + Relic = "Reliquia", + Ring = "Anillo", + Rogue = "Pícaro", + Scroll = "Pergamino", + Shaman = "Chamán", + Shield = "Escudo", + Shields = "Escudos", + Shirt = "Camisa", + Shoulder = "Hombros", + Sigils = "Sigilos", + Simple = "Simple", + ["Soul Bag"] = "Bolsa de Almas", + Staff = "Bastón", + Staves = "Bastones", + Sword = "Espada", + Tabard = "Tabardo", + Tailoring = "Sastrería", + Thrown = "Arrojadiza", + Totem = "Tótem", + Totems = "Tótems", + ["Trade Goods"] = "Objeto comerciable", + Trinket = "Abalorio", + ["Two-Hand"] = "Dos Manos", + ["Two-Handed Axes"] = "Hachas a Dos Manos", + ["Two-Handed Maces"] = "Mazas a Dos Manos", + ["Two-Handed Swords"] = "Espadas a Dos Manos", + Waist = "Cintura", + Wand = "Varita", + Wands = "Varitas", + Warlock = "Brujo", + Warrior = "Guerrero", + Weapon = "Arma", + ["Weapon Enchantment"] = "Encantamiento de Armas", + Wrist = "Muñeca", + Yellow = "Amarillo", +} +elseif GAME_LOCALE == "ruRU" then + lib:SetCurrentTranslations { + Alchemy = "Алхимия", + ["Ammo Pouch"] = "Подсумок", + Armor = "Доспехи", + ["Armor Enchantment"] = "Чары для доспехов", + Arrow = "Стрела", + Axe = "Топор", + Back = "Спина", + Bag = "Сумка", + Bandage = "Бинты", + Blacksmithing = "Кузнечное дело", + Blue = "Синий", + Book = "Книга", + Bow = "Лук", + Bows = "Луки", + Bullet = "Пуля", + Chest = "Грудь", + Cloth = "Ткань", + Consumable = "Потребляемые", + Container = "Сумки", + Cooking = "Кулинария", + Crossbow = "Арбалет", + Crossbows = "Арбалеты", + Dagger = "Кинжал", + Daggers = "Кинжалы", + ["Death Knight"] = "Рыцарь смерти", + Devices = "Устройства", + Drink = "Питье", + Druid = "Друид", + Elemental = "Стихии", + Elixir = "Эликсир", + Enchanting = "Наложение чар", + ["Enchanting Bag"] = "Сумка зачаровывателя", + Engineering = "Механика", + ["Engineering Bag"] = "Сумка механика", + Explosives = "Взрывчатка", + Feet = "Ступни", + ["First Aid"] = "Первая помощь", + Fishing = "Рыбная ловля", + ["Fishing Pole"] = "Удочка", + ["Fishing Poles"] = "Удочки", + ["Fist Weapon"] = "Кистевое", + ["Fist Weapons"] = "Кистевое", + Flask = "Фляга", + Food = "Еда", + ["Food & Drink"] = "Еда и напитки", + Gem = "Самоцветы", + ["Gem Bag"] = "Сумка ювелира", + Glyph = "Символ", + Green = "Зеленый", + Gun = "Огнестрельное", + Guns = "Огнестрельное", + Hands = "Кисти рук", + Head = "Голова", + ["Held in Off-Hand"] = "Левая рука", + Herb = "Трава", + ["Herb Bag"] = "Сумка травника", + Holiday = "Праздник", + Hunter = "Охотник", + Idol = "Идол", + Idols = "Идолы", + ["Inscription Bag"] = "Сумка начертателя", + ["Item Enhancement"] = "Улучшение", + Jewelcrafting = "Ювелирное дело", + Junk = "Мусор", + Key = "Ключ", + Leather = "Кожа", + Leatherworking = "Кожевничество", + ["Leatherworking Bag"] = "Сумка кожевника", + Legs = "Ноги", + Libram = "Манускрипт", + Librams = "Манускрипты", + Mace = "Дробящее", + Mage = "Маг", + Mail = "Кольчуга", + ["Main Hand"] = "Правая рука", + Materials = "Материалы", + Meat = "Мясо", + Meta = "Особый", + ["Metal & Stone"] = "Металл и камень", + ["Mining Bag"] = "Шахтерская сумка", + Miscellaneous = "Разное", + Mount = "Верховые животные", + Neck = "Шея", + ["Off Hand"] = "Левая рука", + ["One-Hand"] = "Одноручное", + ["One-Handed Axes"] = "Одноручные топоры", + ["One-Handed Maces"] = "Одноручное дробящее", + ["One-Handed Swords"] = "Одноручные мечи", + Orange = "Оранжевый", + Other = "Другое", + Paladin = "Паладин", + Parts = "Детали", + Pet = "Питомец", + Plate = "Латы", + Polearm = "Древковое", + Polearms = "Древковое", + Potion = "Зелье", + Priest = "Жрец", + Prismatic = "Радужный", + Projectile = "Боеприпасы", + Purple = "Фиолетовый", + Quest = "Задания", + Quiver = "Колчан", + Ranged = "Для оружия дальнего боя", + Reagent = "Реагент", + Recipe = "Рецепты", + Red = "Красный", + Relic = "Реликвия", + Ring = "Палец", + Rogue = "Разбойник", + Scroll = "Свиток", + Shaman = "Шаман", + Shield = "Щит", + Shields = "Щиты", + Shirt = "Рубашка", + Shoulder = "Плечо", + Sigils = "Печати", + Simple = "Простой", + ["Soul Bag"] = "Сумка душ", + Staff = "Посох", + Staves = "Посохи", + Sword = "Меч", + Tabard = "Гербовая накидка", + Tailoring = "Портняжное дело", + Thrown = "Метательное", + Totem = "Тотем", + Totems = "Тотемы", + ["Trade Goods"] = "Хозяйственные товары", + Trinket = "Аксессуар", + ["Two-Hand"] = "Двуручное", + ["Two-Handed Axes"] = "Двуручные топоры", + ["Two-Handed Maces"] = "Двуручное дробящее", + ["Two-Handed Swords"] = "Двуручные мечи", + Waist = "Пояс", + Wand = "Жезл", + Wands = "Жезлы", + Warlock = "Чернокнижник", + Warrior = "Воин", + Weapon = "Оружие", + ["Weapon Enchantment"] = "Чары для оружия\009", + Wrist = "Запястья", + Yellow = "Желтый", +} +elseif GAME_LOCALE == "zhCN" then + lib:SetCurrentTranslations { + Alchemy = "炼金术", + ["Ammo Pouch"] = "弹药袋", + Armor = "护甲", + ["Armor Enchantment"] = "护甲强化", + Arrow = "箭", + Axe = "斧", + Back = "背部", + Bag = "容器", + Bandage = "绷带", + Blacksmithing = "锻造", + Blue = "蓝色", + Book = "书籍", + Bow = "弓", + Bows = "弓", + Bullet = "子弹", + Chest = "胸部", + Cloth = "布甲", + Consumable = "消耗品", + Container = "容器", + Cooking = "烹饪", + Crossbow = "弩", + Crossbows = "弩", + Dagger = "匕首", + Daggers = "匕首", + ["Death Knight"] = "死亡骑士", + Devices = "装置", + Drink = "饮料", + Druid = "德鲁伊", + Elemental = "元素", + Elixir = "药剂", + Enchanting = "附魔", + ["Enchanting Bag"] = "附魔材料袋", + Engineering = "工程学", + ["Engineering Bag"] = "工程学材料袋", + Explosives = "爆炸物", + Feet = "脚", + ["First Aid"] = "急救", + Fishing = "钓鱼", + ["Fishing Pole"] = "鱼竿", + ["Fishing Poles"] = "鱼竿", + ["Fist Weapon"] = "拳套", + ["Fist Weapons"] = "拳套", + Flask = "合剂", + Food = "食物", + ["Food & Drink"] = "食物和饮料", + Gem = "宝石", + ["Gem Bag"] = "宝石袋", + Glyph = "雕文", + Green = "绿色", + Gun = "枪械", + Guns = "枪械", + Hands = "手", + Head = "头部", + ["Held in Off-Hand"] = "副手物品", + Herb = "草药", + ["Herb Bag"] = "草药袋", + Holiday = "节日", + Hunter = "猎人", + Idol = "神像", + Idols = "神像", + ["Inscription Bag"] = "铭文包", + ["Item Enhancement"] = "物品强化", + Jewelcrafting = "珠宝加工", + Junk = "垃圾", + Key = "钥匙", + Leather = "皮甲", + Leatherworking = "制皮", + ["Leatherworking Bag"] = "制皮材料袋", + Legs = "腿部", + Libram = "圣契", + Librams = "圣契", + Mace = "锤", + Mage = "法师", + Mail = "锁甲", + ["Main Hand"] = "主手", + Materials = "原料", + Meat = "肉类", + Meta = "多彩", + ["Metal & Stone"] = "金属和矿石", + ["Mining Bag"] = "矿石袋", + Miscellaneous = "其他", + Mount = "坐骑", + Neck = "颈部", + ["Off Hand"] = "副手", + ["One-Hand"] = "单手", + ["One-Handed Axes"] = "单手斧", + ["One-Handed Maces"] = "单手锤", + ["One-Handed Swords"] = "单手剑", + Orange = "橙色", + Other = "其它", + Paladin = "圣骑士", + Parts = "零件", + Pet = "宠物", + Plate = "板甲", + Polearm = "长柄武器", + Polearms = "长柄武器", + Potion = "药水", + Priest = "牧师", + Prismatic = "棱彩", + Projectile = "弹药", + Purple = "紫色", + Quest = "任务", + Quiver = "箭袋", + Ranged = "远程", + Reagent = "材料", + Recipe = "配方", + Red = "红色", + Relic = "圣物", + Ring = "手指", + Rogue = "潜行者", + Scroll = "卷轴", + Shaman = "萨满祭司", + Shield = "盾牌", + Shields = "盾牌", + Shirt = "衬衫", + Shoulder = "肩部", + Sigils = "魔印", + Simple = "简易", + ["Soul Bag"] = "灵魂袋", + Staff = "法杖", + Staves = "法杖", + Sword = "剑", + Tabard = "战袍", + Tailoring = "裁缝", + Thrown = "投掷武器", + Totem = "图腾", + Totems = "图腾", + ["Trade Goods"] = "商品", + Trinket = "饰品", + ["Two-Hand"] = "双手", + ["Two-Handed Axes"] = "双手斧", + ["Two-Handed Maces"] = "双手锤", + ["Two-Handed Swords"] = "双手剑", + Waist = "腰部", + Wand = "魔杖", + Wands = "魔杖", + Warlock = "术士", + Warrior = "战士", + Weapon = "武器", + ["Weapon Enchantment"] = "武器强化", + Wrist = "手腕", + Yellow = "黄色", +} +elseif GAME_LOCALE == "zhTW" then + lib:SetCurrentTranslations { + Alchemy = "鍊金術", + ["Ammo Pouch"] = "彈藥袋", + Armor = "護甲", + ["Armor Enchantment"] = "護甲附魔", + Arrow = "箭", + Axe = "斧", + Back = "背部", + Bag = "容器", + Bandage = "繃帶", + Blacksmithing = "鍛造", + Blue = "藍色", + Book = "書籍", + Bow = "弓", + Bows = "弓", + Bullet = "子彈", + Chest = "胸部", + Cloth = "布甲", + Consumable = "消耗品", + Container = "容器", + Cooking = "烹飪", + Crossbow = "弩", + Crossbows = "弩", + Dagger = "匕首", + Daggers = "匕首", + ["Death Knight"] = "死亡騎士", + Devices = "裝置", + Drink = "飲料", + Druid = "德魯伊", + Elemental = "元素材料", + Elixir = "藥劑", + Enchanting = "附魔", + ["Enchanting Bag"] = "附魔包", + Engineering = "工程學", + ["Engineering Bag"] = "工程包", + Explosives = "爆裂物", + Feet = "腳", + ["First Aid"] = "急救", + Fishing = "釣魚", + ["Fishing Pole"] = "魚竿", + ["Fishing Poles"] = "魚竿", + ["Fist Weapon"] = "拳套", + ["Fist Weapons"] = "拳套", + Flask = "精煉藥劑", + Food = "食物", + ["Food & Drink"] = "食物和飲料", + Gem = "寶石", + ["Gem Bag"] = "寶石背包", + Glyph = "雕紋", + Green = "綠色", + Gun = "槍械", + Guns = "槍械", + Hands = "手", + Head = "頭部", + ["Held in Off-Hand"] = "副手物品", + Herb = "草藥", + ["Herb Bag"] = "草藥包", + Holiday = "節慶用品", + Hunter = "獵人", + Idol = "塑像", + Idols = "塑像", + ["Inscription Bag"] = "銘文包", + ["Item Enhancement"] = "物品強化", + Jewelcrafting = "珠寶設計", + Junk = "垃圾", + Key = "鑰匙", + Leather = "皮甲", + Leatherworking = "製皮", + ["Leatherworking Bag"] = "製皮包", + Legs = "腿部", + Libram = "聖契", + Librams = "聖契", + Mace = "錘", + Mage = "法師", + Mail = "鎖甲", + ["Main Hand"] = "主手", + Materials = "原料", + Meat = "肉類", + Meta = "變換", + ["Metal & Stone"] = "金屬和石頭", + ["Mining Bag"] = "礦石包", + Miscellaneous = "其他", + Mount = "坐騎", + Neck = "頸部", + ["Off Hand"] = "副手", + ["One-Hand"] = "單手", + ["One-Handed Axes"] = "單手斧", + ["One-Handed Maces"] = "單手錘", + ["One-Handed Swords"] = "單手劍", + Orange = "橘色", + Other = "其他", + Paladin = "聖騎士", + Parts = "零件", + Pet = "寵物", + Plate = "鎧甲", + Polearm = "長柄武器", + Polearms = "長柄武器", + Potion = "藥水", + Priest = "牧師", + Prismatic = "稜彩", + Projectile = "彈藥", + Purple = "紫色", + Quest = "任務", + Quiver = "箭袋", + Ranged = "遠程", + Reagent = "施法材料", + Recipe = "配方", + Red = "紅色", + Relic = "聖物", + Ring = "手指", + Rogue = "盜賊", + Scroll = "卷軸", + Shaman = "薩滿", + Shield = "盾牌", + Shields = "盾牌", + Shirt = "襯衣", + Shoulder = "肩部", + Sigils = "符印", + Simple = "簡單", + ["Soul Bag"] = "靈魂裂片包", + Staff = "法杖", + Staves = "法杖", + Sword = "劍", + Tabard = "外袍", + Tailoring = "裁縫", + Thrown = "投擲武器", + Totem = "圖騰", + Totems = "圖騰", + ["Trade Goods"] = "商品", + Trinket = "飾品", + ["Two-Hand"] = "雙手", + ["Two-Handed Axes"] = "雙手斧", + ["Two-Handed Maces"] = "雙手錘", + ["Two-Handed Swords"] = "雙手劍", + Waist = "腰部", + Wand = "魔杖", + Wands = "魔杖", + Warlock = "術士", + Warrior = "戰士", + Weapon = "武器", + ["Weapon Enchantment"] = "武器附魔", + Wrist = "手腕", + Yellow = "黃色", +} + +else + error(("%s: Locale %q not supported"):format(MAJOR_VERSION, GAME_LOCALE)) +end diff --git a/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibBabble-Inventory-3.0.toc b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibBabble-Inventory-3.0.toc new file mode 100644 index 0000000..25cae1a --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibBabble-Inventory-3.0.toc @@ -0,0 +1,16 @@ +## Interface: 30300 +## LoadOnDemand: 1 +## Title: Lib: Babble-Inventory-3.0 +## Notes: A library to help with localization of item types and subtypes. +## Notes-esES: Una libreria para ayudar con la traduccion de tipos y subtipos de objetos. +## Author: ckknight +## X-eMail: ckknight@gmail.com +## X-Category: Library +## X-License: MIT +## X-Curse-Packaged-Version: r101 +## X-Curse-Project-Name: LibBabble-Inventory-3.0 +## X-Curse-Project-ID: libbabble-inventory-3-0 +## X-Curse-Repository-ID: wow/libbabble-inventory-3-0/mainline + +LibStub\LibStub.lua +lib.xml diff --git a/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibStub/LibStub.lua b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibStub/LibStub.lua new file mode 100644 index 0000000..0a41ac0 --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/LibStub/LibStub.lua @@ -0,0 +1,30 @@ +-- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info +-- LibStub is hereby placed in the Public Domain Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke +local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub", 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS! +local LibStub = _G[LIBSTUB_MAJOR] + +if not LibStub or LibStub.minor < LIBSTUB_MINOR then + LibStub = LibStub or {libs = {}, minors = {} } + _G[LIBSTUB_MAJOR] = LibStub + LibStub.minor = LIBSTUB_MINOR + + function LibStub:NewLibrary(major, minor) + assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)") + minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.") + + local oldminor = self.minors[major] + if oldminor and oldminor >= minor then return nil end + self.minors[major], self.libs[major] = minor, self.libs[major] or {} + return self.libs[major], oldminor + end + + function LibStub:GetLibrary(major, silent) + if not self.libs[major] and not silent then + error(("Cannot find a library instance of %q."):format(tostring(major)), 2) + end + return self.libs[major], self.minors[major] + end + + function LibStub:IterateLibraries() return pairs(self.libs) end + setmetatable(LibStub, { __call = LibStub.GetLibrary }) +end diff --git a/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/lib.xml b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/lib.xml new file mode 100644 index 0000000..b9f9904 --- /dev/null +++ b/Altoholic-Addon/DataStore_Containers/libs/LibBabble-Inventory-3.0/lib.xml @@ -0,0 +1,5 @@ + + + + + + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Crafts", "BroadcastProfs") + + + + + + + diff --git a/Altoholic-Addon/DataStore_Crafts/embeds.xml b/Altoholic-Addon/DataStore_Crafts/embeds.xml new file mode 100644 index 0000000..7173eb4 --- /dev/null +++ b/Altoholic-Addon/DataStore_Crafts/embeds.xml @@ -0,0 +1,8 @@ + + + + + + + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Inventory", "AutoClearGuildInventory") + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Inventory", "BroadcastAiL") + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Inventory", "EquipmentRequestNotification") + + + + + + + diff --git a/Altoholic-Addon/DataStore_Inventory/embeds.xml b/Altoholic-Addon/DataStore_Inventory/embeds.xml new file mode 100644 index 0000000..d4dcbc4 --- /dev/null +++ b/Altoholic-Addon/DataStore_Inventory/embeds.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + local L = LibStub("AceLocale-3.0"):GetLocale("DataStore_Mails") + + local name = self:GetName() + _G[name .. "Text"]:SetText(L["Mail Expiry Warning"] .. " (" .. self:GetValue() ..")"); + DataStore:SetOption("DataStore_Mails", "MailWarningThreshold", self:GetValue()) + + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Mails", "CheckMailExpiry") + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Mails", "ScanMailBody") + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Mails", "CheckMailExpiryAllAccounts") + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Mails", "CheckMailExpiryAllRealms") + + + + + + + diff --git a/Altoholic-Addon/DataStore_Mails/locale.xml b/Altoholic-Addon/DataStore_Mails/locale.xml new file mode 100644 index 0000000..3eb054f --- /dev/null +++ b/Altoholic-Addon/DataStore_Mails/locale.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/DataStore_Pets/Changelog-DataStore_Pets-r18.txt b/Altoholic-Addon/DataStore_Pets/Changelog-DataStore_Pets-r18.txt new file mode 100644 index 0000000..7e09d99 --- /dev/null +++ b/Altoholic-Addon/DataStore_Pets/Changelog-DataStore_Pets-r18.txt @@ -0,0 +1,13 @@ +------------------------------------------------------------------------ +r18 | Thaoky | 2010-07-06 17:14:26 +0000 (Tue, 06 Jul 2010) | 1 line +Changed paths: + M /trunk/Data/CompanionList.lua + +Minor fixes in the companion list. +------------------------------------------------------------------------ +r17 | thaoky | 2010-03-09 10:26:17 +0000 (Tue, 09 Mar 2010) | 1 line +Changed paths: + M /trunk/DataStore_Pets.lua + +Now registering event COMPANION_LEARNED instead of COMPANION_UPDATE. +------------------------------------------------------------------------ diff --git a/Altoholic-Addon/DataStore_Pets/Data/CompanionList.lua b/Altoholic-Addon/DataStore_Pets/Data/CompanionList.lua new file mode 100644 index 0000000..80d673b --- /dev/null +++ b/Altoholic-Addon/DataStore_Pets/Data/CompanionList.lua @@ -0,0 +1,194 @@ +local addonName = "DataStore_Pets" +local addon = _G[addonName] + +-- these are spellID's +addon.CompanionList = { + 4055, + 10673, + 10674, + 10675, + 10676, + 10677, + 10678, + 10679, + 10680, + 10681, + 10682, + 10683, + 10684, + 10685, + 10686, + 10687, + 10688, + 10695, + 10696, + 10697, + 10698, + 10699, + 10700, + 10701, + 10702, + 10703, + 10704, + 10705, + 10706, + 10707, + 10708, + 10709, + 10710, + 10711, + 10712, + 10713, + 10714, + 10715, + 10716, + 10717, + 10718, + 10719, + 10720, + 10721, + 12243, + 13548, + 15048, + 15049, + 15067, + 15648, + 15999, + 16450, + 17468, + 17469, + 17567, + 17707, + 17708, + 17709, + 19363, + 19772, + 23428, + 23429, + 23430, + 23431, + 23432, + 23530, + 23531, + 23811, + 24696, + 24985, + 24986, + 24987, + 24988, + 24989, + 24990, + 25018, + 25162, + 25849, + 26010, + 26045, + 26067, + 26391, + 26529, + 26533, + 26541, + 27241, + 27570, + 28487, + 28505, + 28738, + 28739, + 28740, + 28871, + 30152, + 30156, + 32298, + 33050, + 33057, + 35156, + 35157, + 35239, + 35907, + 35909, + 35910, + 35911, + 36027, + 36028, + 36029, + 36031, + 36034, + 39181, + 39709, + 40319, + 40405, + 40549, + 40613, + 40614, + 40634, + 40990, + 42609, + 43697, + 43698, + 43918, + 44369, + 45082, + 45125, + 45127, + 45174, + 45175, + 45890, + 46425, + 46426, + 46599, + 48406, + 48408, + 49964, + 51716, + 51851, + 52615, + 53082, + 53316, + 53768, + 54187, + 55068, + 59250, + 61348, + 61349, + 61350, + 61351, + 61357, + 61472, + 61725, + 61773, + 61855, + 61991, + 62491, + 62508, + 62510, + 62513, + 62514, + 62516, + 62542, + 62561, + 62562, + 62564, + 62609, + 62674, + 62746, + 63318, + 63712, + 64351, + 65381, + 65382, + 65682, + 66030, + 66096, + 66520, + 67413, + 67414, + 67415, + 67416, + 67417, + 67418, + 67419, + 67420, + 69541, + 69677, + 69002, +} diff --git a/Altoholic-Addon/DataStore_Pets/Data/CompanionToSpellID.lua b/Altoholic-Addon/DataStore_Pets/Data/CompanionToSpellID.lua new file mode 100644 index 0000000..bd859f6 --- /dev/null +++ b/Altoholic-Addon/DataStore_Pets/Data/CompanionToSpellID.lua @@ -0,0 +1,153 @@ +local addonName = "DataStore_Pets" +local addon = _G[addonName] + +-- [itemID] = spellID +addon.CompanionToSpellID = { + [4401] = 4055, + [8485] = 10673, + [8486] = 10674, + [8487] = 10676, + [8488] = 10678, + [8489] = 10679, + [8490] = 10677, + [8491] = 10675, + [8492] = 10683, + [8494] = 10682, + [8495] = 10684, + [8496] = 10680, + [8497] = 10711, + [8498] = 10698, + [8499] = 10697, + [8500] = 10707, + [8501] = 10706, + [10360] = 10714, + [10361] = 10716, + [10392] = 10717, + [10393] = 10688, + [10394] = 10709, + [10398] = 12243, + [10822] = 10695, + [11023] = 10685, + [11026] = 10704, + [11027] = 10703, + [11110] = 13548, + [11474] = 15067, + [11825] = 15048, + [11826] = 15049, + [12185] = 17567, + [12264] = 15999, + [12529] = 16450, + [13582] = 17709, + [13583] = 17707, + [13584] = 17708, + [15778] = 19363, + [15996] = 19772, + [21305] = 26541, + [21308] = 26529, + [21301] = 26533, + [21309] = 26045, + [18964] = 23429, + [19450] = 23811, + [20371] = 24696, + [20769] = 25162, + [21168] = 25849, + [21277] = 26010, + [21325] = 26067, + [21579] = 26391, + [22114] = 27241, + [22235] = 27570, + [23002] = 28738, + [23007] = 28739, + [23015] = 28740, + [23083] = 28871, + [23713] = 30156, + [25535] = 32298, + [27445] = 33050, + [29363] = 35156, + [29364] = 35239, + [29901] = 35907, + [29902] = 35909, + [29903] = 35910, + [29904] = 35911, + [29953] = 36027, + [29956] = 36028, + [29957] = 36029, + [29958] = 36031, + [29960] = 36034, + [30360] = 24988, + [31760] = 39181, + [32233] = 39709, + [32498] = 40405, + [32588] = 40549, + [32616] = 40614, + [32617] = 40613, + [32622] = 40634, + [33154] = 42609, + [33816] = 43697, + [33818] = 43698, + [33993] = 43918, + [34425] = 54187, + [34478] = 45082, + [34492] = 45125, + [34493] = 45127, + [34535] = 10696, + [34955] = 45890, + [35349] = 46425, + [35350] = 46426, + [35504] = 46599, + [37297] = 48406, + [38050] = 49964, + [38628] = 51716, + [38658] = 51851, + [39286] = 52615, + [39656] = 53082, + [39896] = 61348, + [39898] = 61351, + [39899] = 61349, + [39973] = 53316, + [40110] = 53768, + [40653] = 40990, + [43517] = 58636, + [43698] = 59250, + [44721] = 61350, + [44723] = 61357, + [44738] = 61472, + [44794] = 61725, + [44819] = 61855, + [44822] = 10716, + [44841] = 61991, + [44965] = 62491, + [44970] = 62508, + [44971] = 62510, + [44973] = 62513, + [44974] = 62516, + [44980] = 62542, + [44982] = 62564, + [44983] = 62561, + [44984] = 62562, + [44998] = 62609, + [45002] = 62674, + [45022] = 62746, + [45180] = 63318, + [45606] = 63712, + [45942] = 64351, + [46544] = 65382, + [46545] = 65381, + [46707] = 44369, + [46767] = 65682, + [46802] = 66030, + [46820] = 66096, + [46821] = 66096, + [48112] = 67413, + [48114] = 67414, + [48116] = 67415, + [48118] = 67416, + [48120] = 67417, + [48122] = 67418, + [48124] = 67419, + [48126] = 67420, + [49665] = 69541, + [49693] = 69677, + [49362] = 69002, + [41133] = 55068, +} diff --git a/Altoholic-Addon/DataStore_Pets/Data/MountList.lua b/Altoholic-Addon/DataStore_Pets/Data/MountList.lua new file mode 100644 index 0000000..1aa83df --- /dev/null +++ b/Altoholic-Addon/DataStore_Pets/Data/MountList.lua @@ -0,0 +1,282 @@ +local addonName = "DataStore_Pets" +local addon = _G[addonName] + +-- these are spellID's +addon.MountList = { + 458, + 459, + 468, + 470, + 471, + 472, + 578, + 579, + 580, + 581, + 3363, + 6648, + 6653, + 6654, + 6777, + 6896, + 6897, + 6898, + 6899, + 8394, + 8395, + 8980, + 10789, + 10793, + 10795, + 10796, + 10798, + 10799, + 10873, + 10969, + 15779, + 15780, + 15781, + 16055, + 16056, + 16058, + 16059, + 16060, + 16080, + 16081, + 16082, + 16083, + 16084, + 17229, + 17450, + 17453, + 17454, + 17455, + 17456, + 17458, + 17459, + 17460, + 17461, + 17462, + 17463, + 17464, + 17465, + 17481, + 18363, + 18989, + 18990, + 18991, + 18992, + 22717, + 22718, + 22719, + 22720, + 22721, + 22722, + 22723, + 22724, + 23219, + 23220, + 23221, + 23222, + 23223, + 23225, + 23227, + 23228, + 23229, + 23238, + 23239, + 23240, + 23241, + 23242, + 23243, + 23246, + 23247, + 23248, + 23249, + 23250, + 23251, + 23252, + 23338, + 23509, + 23510, + 24242, + 24252, + 25953, + 26054, + 26055, + 26056, + 26656, + 28828, + 29059, + 30174, + 32235, + 32239, + 32240, + 32242, + 32243, + 32244, + 32245, + 32246, + 32289, + 32290, + 32292, + 32295, + 32296, + 32297, + 32345, + 33630, + 33660, + 34406, + 34407, + 34790, + 34795, + 34896, + 34897, + 34898, + 34899, + 35018, + 35020, + 35022, + 35025, + 35027, + 35028, + 35710, + 35711, + 35712, + 35713, + 35714, + 36702, + 37015, + 39315, + 39316, + 39317, + 39318, + 39319, + 39798, + 39800, + 39801, + 39802, + 39803, + 40192, + 41252, + 41513, + 41514, + 41515, + 41516, + 41517, + 41518, + 42776, + 42777, + 42781, + 43688, + 43810, + 43899, + 43900, + 43927, + 44151, + 44153, + 44317, + 44744, + 46197, + 46199, + 46628, + 47037, + 48025, + 48027, + 48954, + 49193, + 49322, + 49378, + 49379, + 50869, + 50870, + 51412, + 51960, + 54729, + 54753, + 55531, + 58615, + 58983, + 59567, + 59568, + 59569, + 59570, + 59571, + 59572, + 59573, + 59650, + 59785, + 59788, + 59791, + 59793, + 59797, + 59799, + 59802, + 59804, + 59961, + 59976, + 59996, + 60002, + 60021, + 60024, + 60025, + 60114, + 60116, + 60118, + 60119, + 60136, + 60140, + 60424, + 61229, + 61230, + 61294, + 61309, + 61425, + 61442, + 61444, + 61446, + 61447, + 61451, + 61465, + 61467, + 61469, + 61470, + 61996, + 61997, + 62048, + 63232, + 63635, + 63636, + 63637, + 63638, + 63639, + 63640, + 63641, + 63642, + 63643, + 63796, + 63844, + 63956, + 63963, + 64656, + 64657, + 64658, + 64659, + 64731, + 64927, + 64977, + 65637, + 65638, + 65639, + 65640, + 65641, + 65642, + 65643, + 65644, + 65645, + 65646, + 65917, + 66122, + 66123, + 66124, +} diff --git a/Altoholic-Addon/DataStore_Pets/Data/MountToSpellID.lua b/Altoholic-Addon/DataStore_Pets/Data/MountToSpellID.lua new file mode 100644 index 0000000..18f8f86 --- /dev/null +++ b/Altoholic-Addon/DataStore_Pets/Data/MountToSpellID.lua @@ -0,0 +1,247 @@ +local addonName = "DataStore_Pets" +local addon = _G[addonName] + +-- [itemID] = spellID +addon.MountToSpellID = { + [1132] = 580, + [2411] = 470, + [2414] = 472, + [5655] = 6648, + [5656] = 458, + [5665] = 6653, + [5668] = 6654, + [5864] = 6777, + [5872] = 6899, + [5873] = 6898, + [8563] = 10873, + [8586] = 16084, + [8588] = 8395, + [8591] = 10796, + [8592] = 10799, + [8595] = 10969, + [8629] = 10793, + [8631] = 8394, + [8632] = 10789, + [12302] = 16056, + [12303] = 16055, + [12330] = 16080, + [12351] = 16081, + [12353] = 16083, + [12354] = 16082, + [13086] = 17229, + [13317] = 17450, + [13321] = 17453, + [13322] = 17454, + [13326] = 15779, + [13327] = 17459, + [13328] = 17461, + [13329] = 17460, + [13331] = 17462, + [13332] = 17463, + [13333] = 17464, + [13334] = 17465, + [13335] = 17481, + [15277] = 18989, + [15290] = 18990, + [15292] = 18991, + [15293] = 18992, + [16339] = 16082, + [18241] = 22717, + [18242] = 22723, + [18243] = 22719, + [18244] = 22720, + [18245] = 22724, + [18246] = 22721, + [18247] = 22718, + [18248] = 22722, + [18766] = 23221, + [18767] = 23219, + [18772] = 23225, + [18773] = 23223, + [18774] = 23222, + [18776] = 23227, + [18777] = 23229, + [18778] = 23228, + [18785] = 23240, + [18786] = 23238, + [18787] = 23239, + [18788] = 23241, + [18789] = 23242, + [18790] = 23243, + [18791] = 23246, + [18793] = 23247, + [18794] = 23249, + [18795] = 23248, + [18796] = 23250, + [18797] = 23251, + [18798] = 23252, + [18902] = 23338, + [19029] = 23509, + [19030] = 23510, + [19872] = 24242, + [19902] = 24252, + [21176] = 26656, + [21218] = 25953, + [21321] = 26054, + [21323] = 26056, + [21324] = 26055, + [23720] = 30174, + [25470] = 32235, + [25471] = 32239, + [25472] = 32240, + [25473] = 32242, + [25474] = 32243, + [25475] = 32244, + [25476] = 32245, + [25477] = 32246, + [25527] = 32289, + [25528] = 32290, + [25529] = 32292, + [25531] = 32295, + [25532] = 32296, + [25533] = 32297, + [25596] = 32345, + [28481] = 34406, + [28915] = 39316, + [28927] = 34795, + [28936] = 33660, + [29102] = 34896, + [29103] = 34897, + [29104] = 34898, + [29105] = 34899, + [29220] = 35020, + [29221] = 35022, + [29222] = 35018, + [29223] = 35025, + [29224] = 35027, + [29227] = 34896, + [29228] = 34790, + [29229] = 34898, + [29230] = 34899, + [29231] = 34897, + [29465] = 22719, + [29466] = 22718, + [29467] = 22720, + [29468] = 22717, + [29469] = 22724, + [29470] = 22722, + [29471] = 22723, + [29472] = 22721, + [29743] = 35711, + [29744] = 35710, + [29745] = 35713, + [29746] = 35712, + [29747] = 35714, + [30480] = 36702, + [30609] = 37015, + [31829] = 39315, + [31830] = 39315, + [31831] = 39317, + [31832] = 39317, + [31833] = 39318, + [31834] = 39318, + [31835] = 39319, + [31836] = 39319, + [32314] = 39798, + [32316] = 39801, + [32317] = 39800, + [32318] = 39802, + [32319] = 39803, + [32458] = 40192, + [32768] = 41252, + [32857] = 41513, + [32858] = 41514, + [32859] = 41515, + [32860] = 41516, + [32861] = 41517, + [32862] = 41518, + [33224] = 42776, + [33225] = 42777, + [33809] = 43688, + [33976] = 43899, + [33977] = 43900, + [33999] = 43927, + [34060] = 44153, + [34061] = 44151, + [34092] = 44744, + [34129] = 35028, + [35225] = 46197, + [35226] = 46199, + [35513] = 46628, + [35906] = 48027, + [37012] = 48025, + [37676] = 49193, + [37719] = 49322, + [37828] = 49379, + [38576] = 51412, + [40775] = 54729, + [41508] = 55531, + [43516] = 58615, + [43599] = 58983, + [43951] = 59569, + [43952] = 59567, + [43953] = 59568, + [43954] = 59571, + [43955] = 59570, + [43956] = 59785, + [43958] = 59799, + [43959] = 61465, + [43961] = 61470, + [43962] = 54753, + [43986] = 59650, + [44077] = 59788, + [44080] = 59797, + [44083] = 61467, + [44086] = 61469, + [44151] = 59996, + [44160] = 59961, + [44164] = 59976, + [44168] = 60002, + [44175] = 60021, + [44178] = 60025, + [44223] = 60118, + [44224] = 60119, + [44225] = 60114, + [44226] = 60116, + [44230] = 59791, + [44231] = 59793, + [44234] = 61447, + [44235] = 61425, + [44413] = 60424, + [44554] = 61451, + [44558] = 61309, + [44689] = 61229, + [44690] = 61230, + [44707] = 61294, + [44842] = 61997, + [44843] = 61996, + [45125] = 63232, + [45586] = 63636, + [45589] = 63638, + [45590] = 63639, + [45591] = 63637, + [45592] = 63641, + [45593] = 63635, + [45595] = 63640, + [45596] = 63642, + [45597] = 63643, + [45725] = 63844, + [45801] = 63956, + [45802] = 63963, + [46099] = 64658, + [46100] = 64657, + [46101] = 64656, + [46109] = 64731, + [46171] = 64927, + [46308] = 64977, + [46743] = 65644, + [46744] = 65638, + [46745] = 65637, + [46746] = 65645, + [46747] = 65642, + [46748] = 65643, + [46749] = 65646, + [46750] = 65641, + [46751] = 65639, + [46752] = 65640, +} diff --git a/Altoholic-Addon/DataStore_Pets/DataStore_Pets.lua b/Altoholic-Addon/DataStore_Pets/DataStore_Pets.lua new file mode 100644 index 0000000..d771ef0 --- /dev/null +++ b/Altoholic-Addon/DataStore_Pets/DataStore_Pets.lua @@ -0,0 +1,145 @@ +--[[ *** DataStore_Pets *** +Written by : Thaoky, EU-Marécages de Zangar +June 22st, 2009 +--]] +if not DataStore then return end + +local addonName = "DataStore_Pets" + +_G[addonName] = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceConsole-3.0", "AceEvent-3.0") + +local addon = _G[addonName] + +local THIS_ACCOUNT = "Default" + +local AddonDB_Defaults = { + global = { + Characters = { + ['*'] = { -- ["Account.Realm.Name"] + lastUpdate = nil, + CRITTER = {}, -- companion types are used as table names + MOUNT = {}, + } + } + } +} + +-- *** Scanning functions *** +local COMPANION_ICON_PATH = "Interface\\Icons\\" + +local function ScanCompanions(companionType) + local list = addon.ThisCharacter[companionType] + + wipe(list) + + for i = 1, GetNumCompanions(companionType) do + local modelID, name, spellID, icon = GetCompanionInfo(companionType, i); + if modelID and name and spellID and icon then + -- trim icon path to save memory + list[i] = modelID .. "|" .. name .. "|" .. spellID .. "|" .. string.gsub(icon, COMPANION_ICON_PATH, "") + end + end + + addon.ThisCharacter.lastUpdate = time() +end + +-- *** Event Handlers *** +local function OnPlayerAlive() + ScanCompanions("CRITTER") + ScanCompanions("MOUNT") +end + +local function OnCompanionUpdate() + -- COMPANION_UPDATE is triggered very often, but after the very first call, pets & mounts can be scanned automatically. After that, we only need to track COMPANION_LEARNED + addon:UnregisterEvent("COMPANION_UPDATE") + ScanCompanions("CRITTER") + ScanCompanions("MOUNT") +end + +local function OnCompanionLearned() + ScanCompanions("CRITTER") + ScanCompanions("MOUNT") +end + +-- ** Mixins ** +local function _GetPets(character, companionType) + return character[companionType] +end + +local function _GetNumPets(pets) + assert(type(pets) == "table") -- this is the pointer to a pet table, obtained through GetPets() + return #pets +end + +local function _GetPetInfo(pets, index) + local pet = pets[index] + + if pet then + local modelID, name, spellID, icon = strsplit("|", pet) + return tonumber(modelID), name, tonumber(spellID), "Interface\\Icons\\" .. icon + end +end + +local function _IsPetKnown(character, companionType, spellID) + local pets = _GetPets(character, companionType) + for i = 1, #pets do + local _, _, id = _GetPetInfo(pets, i) + if id == spellID then + return true -- returns true if a given spell ID is a known pet or mount + end + end +end + +local function _GetMountList() + return addon.MountList +end + +local function _GetMountSpellID(itemID) + -- returns nil if id is not in the DB, returns the spellID otherwise + return addon.MountToSpellID[itemID] +end + +local function _GetCompanionList() + return addon.CompanionList +end + +local function _GetCompanionSpellID(itemID) + -- returns nil if id is not in the DB, returns the spellID otherwise + return addon.CompanionToSpellID[itemID] +end + +local function _GetCompanionLink(spellID) + local name = GetSpellInfo(spellID) + return format("|cff71d5ff|Hspell:%s|h[%s]|h|r", spellID, name) +end + +local PublicMethods = { + GetPets = _GetPets, + GetNumPets = _GetNumPets, + GetPetInfo = _GetPetInfo, + IsPetKnown = _IsPetKnown, + GetMountList = _GetMountList, + GetMountSpellID = _GetMountSpellID, + GetCompanionList = _GetCompanionList, + GetCompanionSpellID = _GetCompanionSpellID, + GetCompanionLink = _GetCompanionLink, +} + +function addon:OnInitialize() + addon.db = LibStub("AceDB-3.0"):New(addonName .. "DB", AddonDB_Defaults) + + DataStore:RegisterModule(addonName, addon, PublicMethods) + DataStore:SetCharacterBasedMethod("GetPets") + DataStore:SetCharacterBasedMethod("IsPetKnown") +end + +function addon:OnEnable() + addon:RegisterEvent("PLAYER_ALIVE", OnPlayerAlive) + addon:RegisterEvent("COMPANION_UPDATE", OnCompanionUpdate) + addon:RegisterEvent("COMPANION_LEARNED", OnCompanionLearned) +end + +function addon:OnDisable() + addon:UnregisterEvent("PLAYER_ALIVE") + addon:UnregisterEvent("COMPANION_LEARNED") +end diff --git a/Altoholic-Addon/DataStore_Pets/DataStore_Pets.toc b/Altoholic-Addon/DataStore_Pets/DataStore_Pets.toc new file mode 100644 index 0000000..d872846 --- /dev/null +++ b/Altoholic-Addon/DataStore_Pets/DataStore_Pets.toc @@ -0,0 +1,20 @@ +## Interface: 30300 +## Title: DataStore_Pets +## Notes: Stores information about character pets and mounts +## Author: Thaoky (EU-Marécages de Zangar) +## Version: 3.3.001 +## Dependencies: DataStore +## OptionalDeps: Ace3 +## SavedVariables: DataStore_PetsDB +## X-Category: Interface Enhancements +## X-Embeds: Ace3 +## X-Curse-Packaged-Version: r18 +## X-Curse-Project-Name: DataStore_Pets +## X-Curse-Project-ID: datastore_pets +## X-Curse-Repository-ID: wow/datastore_pets/mainline + +DataStore_Pets.lua +Data\MountList.lua +Data\MountToSpellID.lua +Data\CompanionList.lua +Data\CompanionToSpellID.lua diff --git a/Altoholic-Addon/DataStore_Pets/LICENSE.txt b/Altoholic-Addon/DataStore_Pets/LICENSE.txt new file mode 100644 index 0000000..4301cb1 --- /dev/null +++ b/Altoholic-Addon/DataStore_Pets/LICENSE.txt @@ -0,0 +1,2 @@ + +All Rights Reserved unless otherwise explicitly stated. \ No newline at end of file diff --git a/Altoholic-Addon/DataStore_Quests/Changelog-DataStore_Quests-r12.txt b/Altoholic-Addon/DataStore_Quests/Changelog-DataStore_Quests-r12.txt new file mode 100644 index 0000000..808f6ac --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Changelog-DataStore_Quests-r12.txt @@ -0,0 +1,55 @@ +------------------------------------------------------------------------ +r12 | pompachomp | 2010-02-19 18:58:04 +0000 (Fri, 19 Feb 2010) | 2 lines +Changed paths: + M /trunk/DataStore_Quests.toc + D /trunk/local.xml + A /trunk/locale.xml (from /trunk/local.xml:11) + +local.xml->locale.xml + +------------------------------------------------------------------------ +r11 | thaoky | 2010-02-17 19:04:05 +0000 (Wed, 17 Feb 2010) | 1 line +Changed paths: + M /trunk/DataStore_Quests.lua + M /trunk/DataStore_Quests.toc + A /trunk/Locales + A /trunk/Locales/deDE.lua + A /trunk/Locales/enUS.lua + A /trunk/Locales/esES.lua + A /trunk/Locales/esMX.lua + A /trunk/Locales/frFR.lua + A /trunk/Locales/koKR.lua + A /trunk/Locales/repoenUS.lua + A /trunk/Locales/ruRU.lua + A /trunk/Locales/zhCN.lua + A /trunk/Locales/zhTW.lua + A /trunk/Options.lua + A /trunk/Options.xml + A /trunk/local.xml + +Added 2 options to manage quest turn-ins & history auto-update. +------------------------------------------------------------------------ +r10 | thaoky | 2010-02-15 18:12:05 +0000 (Mon, 15 Feb 2010) | 1 line +Changed paths: + M /trunk/DataStore_Quests.lua + +Quest turn-ins are now detected and update the history DB. +------------------------------------------------------------------------ +r9 | thaoky | 2010-02-03 19:00:55 +0000 (Wed, 03 Feb 2010) | 1 line +Changed paths: + M /trunk/DataStore_Quests.lua + +Improved quest history support. +------------------------------------------------------------------------ +r8 | thaoky | 2010-01-24 17:40:19 +0000 (Sun, 24 Jan 2010) | 1 line +Changed paths: + M /trunk/DataStore_Quests.lua + +Added early support to manage quest history. +------------------------------------------------------------------------ +r7 | thaoky | 2009-12-09 12:35:09 +0000 (Wed, 09 Dec 2009) | 1 line +Changed paths: + M /trunk/DataStore_Quests.toc + +ToC Update +------------------------------------------------------------------------ diff --git a/Altoholic-Addon/DataStore_Quests/DataStore_Quests.lua b/Altoholic-Addon/DataStore_Quests/DataStore_Quests.lua new file mode 100644 index 0000000..132fc24 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/DataStore_Quests.lua @@ -0,0 +1,361 @@ +--[[ *** DataStore_Quests *** +Written by : Thaoky, EU-Marécages de Zangar +July 8th, 2009 +--]] +if not DataStore then return end + +local addonName = "DataStore_Quests" + +_G[addonName] = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceConsole-3.0", "AceEvent-3.0", "AceTimer-3.0") + +local addon = _G[addonName] + +local THIS_ACCOUNT = "Default" + +local AddonDB_Defaults = { + global = { + Options = { + TrackTurnIns = 1, -- by default, save the ids of completed quests in the history + AutoUpdateHistory = 1, -- if history has been queried at least once, auto update it at logon (fast operation - already in the game's cache) + }, + Characters = { + ['*'] = { -- ["Account.Realm.Name"] + lastUpdate = nil, + Quests = {}, + QuestLinks = {}, + Rewards = {}, + History = {}, -- a list of completed quests, hash table ( [questID] = true ) + HistoryBuild = nil, -- build version under which the history has been saved + HistorySize = 0, + HistoryLastUpdate = nil, + } + } + } +} + +-- *** Utility functions *** +local function GetOption(option) + return addon.db.global.Options[option] +end + +local function GetQuestLogIndexByName(name) + -- helper function taken from QuestGuru + for i = 1, GetNumQuestLogEntries() do + local title = GetQuestLogTitle(i); + if title == strtrim(name) then + return i + end + end +end + +-- *** Scanning functions *** +local headersState = {} + +local function SaveHeaders() + local headerCount = 0 -- use a counter to avoid being bound to header names, which might not be unique. + + for i = GetNumQuestLogEntries(), 1, -1 do -- 1st pass, expand all categories + local _, _, _, _, isHeader, isCollapsed = GetQuestLogTitle(i) + if isHeader then + headerCount = headerCount + 1 + if isCollapsed then + ExpandQuestHeader(i) + headersState[headerCount] = true + end + end + end +end + +local function RestoreHeaders() + local headerCount = 0 + for i = GetNumQuestLogEntries(), 1, -1 do + local _, _, _, _, isHeader = GetQuestLogTitle(i) + if isHeader then + headerCount = headerCount + 1 + if headersState[headerCount] then + CollapseQuestHeader(i) + end + end + end + wipe(headersState) +end + +local REWARD_TYPE_CHOICE = "c" +local REWARD_TYPE_REWARD = "r" +local REWARD_TYPE_SPELL = "s" + +local function ScanQuests() + local char = addon.ThisCharacter + local quests = char.Quests + local links = char.QuestLinks + local rewards = char.Rewards + + wipe(quests) + wipe(links) + wipe(rewards) + + local currentSelection = GetQuestLogSelection() -- save the currently selected quest + SaveHeaders() + + local RewardsCache = {} + for i = 1, GetNumQuestLogEntries() do + local title, _, questTag, groupSize, isHeader, _, isComplete = GetQuestLogTitle(i); + + if isHeader then + quests[i] = "0|" .. (title or "") + else + SelectQuestLogEntry(i) + local money = GetQuestLogRewardMoney() + quests[i] = format("1|%s|%d|%d|%d", questTag or "", groupSize, money, isComplete or 0) + links[i] = GetQuestLink(i) + + wipe(RewardsCache) + local num = GetNumQuestLogChoices() -- these are the actual item choices proposed to the player + if num > 0 then + for i = 1, num do + local _, _, numItems, _, isUsable = GetQuestLogChoiceInfo(i) + local link = GetQuestLogItemLink("choice", i) + if link then + local id = tonumber(link:match("item:(%d+)")) + if id then + table.insert(RewardsCache, REWARD_TYPE_CHOICE .."|"..id.."|"..numItems.."|"..(isUsable or 0)) + end + end + end + end + + num = GetNumQuestLogRewards() -- these are the rewards given anyway + if num > 0 then + for i = 1, num do + local _, _, numItems, _, isUsable = GetQuestLogRewardInfo(i) + local link = GetQuestLogItemLink("reward", i) + if link then + local id = tonumber(link:match("item:(%d+)")) + if id then + table.insert(RewardsCache, REWARD_TYPE_REWARD .. "|"..id.."|"..numItems.."|"..(isUsable or 0)) + end + end + end + end + + if GetQuestLogRewardSpell() then -- apparently, there is only one spell as reward + local _, _, isTradeskillSpell, isSpellLearned = GetQuestLogRewardSpell() + if isTradeskillSpell or isSpellLearned then + local link = GetQuestLogSpellLink() + if link then + local id = tonumber(link:match("spell:(%d+)")) + if id then + table.insert(RewardsCache, REWARD_TYPE_SPELL .. "|"..id) + end + end + end + end + + if #RewardsCache > 0 then + rewards[i] = table.concat(RewardsCache, ",") + end + end + end + + RestoreHeaders() + SelectQuestLogEntry(currentSelection) -- restore the selection to match the cursor, must be properly set if a user abandons a quest + + addon.ThisCharacter.lastUpdate = time() +end + +local function RefreshQuestHistory() + -- called 5 seconds after login, if the current character already has an history, one that was saved in the same build, then it's safe to refresh it automatically + local thisChar = addon.ThisCharacter + if not thisChar.HistoryLastUpdate then return end -- never scanned the history before ? exit + + local _, version = GetBuildInfo() + if version and thisChar.HistoryBuild and version == thisChar.HistoryBuild then -- proceed if version is the same as the one saved in the db + QueryQuestsCompleted() + end +end + +-- *** Event Handlers *** +local function OnPlayerAlive() + ScanQuests() +end + +local function OnQuestLogUpdate() + addon:UnregisterEvent("QUEST_LOG_UPDATE") -- .. and unregister it right away, since we only want it to be processed once (and it's triggered way too often otherwise) + ScanQuests() +end + +local function OnUnitQuestLogChanged() -- triggered when accepting/validating a quest .. but too soon to refresh data + addon:RegisterEvent("QUEST_LOG_UPDATE", OnQuestLogUpdate) -- so register for this one .. +end + +local lastCompleteQuestLink + +local function OnQuestComplete() + if GetOption("TrackTurnIns") ~= 1 then return end + + -- "QUEST_COMPLETE" is triggered when the UI reaches the page where a player can click on the "Complete" Button. + -- At this point, only detect which quest we're dealing with, and save its link + local num = GetQuestLogIndexByName(GetTitleText()); + if num then + lastCompleteQuestLink = GetQuestLink(num) -- or save quest id + end +end + +local queryVerbose + +local function OnQuestQueryComplete() + local thisChar = addon.ThisCharacter + local history = thisChar.History + local quests = {} + GetQuestsCompleted(quests) + + local count = 0 + for questID in pairs(quests) do + history[questID] = true + count = count + 1 + end + + local _, version = GetBuildInfo() -- save the current build, to know if we can requery and expect immediate execution + thisChar.HistoryBuild = version + thisChar.HistorySize = count + thisChar.HistoryLastUpdate = time() + + if queryVerbose then + addon:Print("Quest history successfully retrieved!") + queryVerbose = nil + end +end + +-- ** Mixins ** +local function _GetQuestLogSize(character) + return #character.Quests +end + +local function _GetQuestLogInfo(character, index) + local quest = character.Quests[index] + local link = character.QuestLinks[index] + local isHeader, questTag, groupSize, money, isComplete = strsplit("|", quest) + + if isHeader == "0" then + return true, questTag -- questTag contains the title in a header line + end + + isComplete = tonumber(isComplete) + return nil, link, questTag, tonumber(groupSize), tonumber(money), tonumber(isComplete) +end + +local function _GetQuestLogNumRewards(character, index) + local reward = character.Rewards[index] + if reward then + return select(2, gsub(reward, ",", ",")) + 1 -- returns the number of rewards (=count of ^ +1) + end + return 0 +end + +local function _GetQuestLogRewardInfo(character, index, rewardIndex) + local reward = character.Rewards[index] + if not reward then return end + + local i = 1 + for v in reward:gmatch("([^,]+)") do + if rewardIndex == i then + local rewardType, id, numItems, isUsable = strsplit("|", v) + + numItems = tonumber(numItems) or 0 + isUsable = (isUsable and isUsable == 1) and true or nil + + return rewardType, tonumber(id), numItems, isUsable + end + i = i + 1 + end +end + +local function _GetQuestInfo(link) + assert(type(link) == "string") + + local questID, questLevel = link:match("quest:(%d+):(-?%d+)") + local questName = link:match("%[(.+)%]") + + return questName, tonumber(questID), tonumber(questLevel) +end + +local function _QueryQuestHistory() + QueryQuestsCompleted() -- this call triggers "QUEST_QUERY_COMPLETE" + queryVerbose = true +end + +local function _GetQuestHistory(character) + return character.History +end + +local function _GetQuestHistoryInfo(character) + -- return the size of the history, the timestamp, and the build under which it was saved + return character.HistorySize, character.HistoryLastUpdate, character.HistoryBuild +end + +local function _IsQuestCompletedBy(character, questID) + return character.History[questID] -- nil = not completed (not in the table), true = completed +end + +local PublicMethods = { + GetQuestLogSize = _GetQuestLogSize, + GetQuestLogInfo = _GetQuestLogInfo, + GetQuestLogNumRewards = _GetQuestLogNumRewards, + GetQuestLogRewardInfo = _GetQuestLogRewardInfo, + GetQuestInfo = _GetQuestInfo, + QueryQuestHistory = _QueryQuestHistory, + GetQuestHistory = _GetQuestHistory, + GetQuestHistoryInfo = _GetQuestHistoryInfo, + IsQuestCompletedBy = _IsQuestCompletedBy, +} + +function addon:OnInitialize() + addon.db = LibStub("AceDB-3.0"):New(addonName .. "DB", AddonDB_Defaults) + + DataStore:RegisterModule(addonName, addon, PublicMethods) + DataStore:SetCharacterBasedMethod("GetQuestLogSize") + DataStore:SetCharacterBasedMethod("GetQuestLogInfo") + DataStore:SetCharacterBasedMethod("GetQuestLogNumRewards") + DataStore:SetCharacterBasedMethod("GetQuestLogRewardInfo") + DataStore:SetCharacterBasedMethod("GetQuestHistory") + DataStore:SetCharacterBasedMethod("GetQuestHistoryInfo") + DataStore:SetCharacterBasedMethod("IsQuestCompletedBy") +end + +function addon:OnEnable() + addon:RegisterEvent("PLAYER_ALIVE", OnPlayerAlive) + addon:RegisterEvent("UNIT_QUEST_LOG_CHANGED", OnUnitQuestLogChanged) + addon:RegisterEvent("QUEST_COMPLETE", OnQuestComplete) + addon:RegisterEvent("QUEST_QUERY_COMPLETE", OnQuestQueryComplete) + + addon:SetupOptions() + + if GetOption("AutoUpdateHistory") == 1 then -- if history has been queried at least once, auto update it at logon (fast operation - already in the game's cache) + addon:ScheduleTimer(RefreshQuestHistory, 5) -- refresh quest history 5 seconds later, to decrease the load at startup + end +end + +function addon:OnDisable() + addon:UnregisterEvent("PLAYER_ALIVE") + addon:UnregisterEvent("UNIT_QUEST_LOG_CHANGED") + addon:UnregisterEvent("QUEST_QUERY_COMPLETE") +end + +-- *** Hooks *** + +local Orig_QuestRewardCompleteButton_OnClick = QuestRewardCompleteButton_OnClick; + +function QuestRewardCompleteButton_OnClick() + if lastCompleteQuestLink then -- if there's a valid link + local questID = lastCompleteQuestLink:match("quest:(%d+):") + questID = tonumber(questID) + if questID then + addon.ThisCharacter.History[questID] = true -- mark the current quest ID as completed + addon:SendMessage("DATASTORE_QUEST_TURNED_IN", questID) -- trigger the DS event + end + lastCompleteQuestLink = nil + end + Orig_QuestRewardCompleteButton_OnClick(); +end + +QuestFrameCompleteQuestButton:SetScript("OnClick", QuestRewardCompleteButton_OnClick); diff --git a/Altoholic-Addon/DataStore_Quests/DataStore_Quests.toc b/Altoholic-Addon/DataStore_Quests/DataStore_Quests.toc new file mode 100644 index 0000000..1cd3470 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/DataStore_Quests.toc @@ -0,0 +1,19 @@ +## Interface: 30300 +## Title: DataStore_Quests +## Notes: Stores information about character quests +## Author: Thaoky (EU-Marécages de Zangar) +## Version: 3.3.001 +## Dependencies: DataStore +## OptionalDeps: Ace3 +## SavedVariables: DataStore_QuestsDB +## X-Category: Interface Enhancements +## X-Embeds: Ace3 +## X-Curse-Packaged-Version: r12 +## X-Curse-Project-Name: DataStore_Quests +## X-Curse-Project-ID: datastore_quests +## X-Curse-Repository-ID: wow/datastore_quests/mainline + +locale.xml + +DataStore_Quests.lua +Options.xml diff --git a/Altoholic-Addon/DataStore_Quests/LICENSE.txt b/Altoholic-Addon/DataStore_Quests/LICENSE.txt new file mode 100644 index 0000000..4301cb1 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/LICENSE.txt @@ -0,0 +1,2 @@ + +All Rights Reserved unless otherwise explicitly stated. \ No newline at end of file diff --git a/Altoholic-Addon/DataStore_Quests/Locales/deDE.lua b/Altoholic-Addon/DataStore_Quests/Locales/deDE.lua new file mode 100644 index 0000000..8336a17 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/deDE.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore_Quests", "deDE" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore_Quests/Locales/enUS.lua b/Altoholic-Addon/DataStore_Quests/Locales/enUS.lua new file mode 100644 index 0000000..e737a54 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/enUS.lua @@ -0,0 +1,16 @@ +local debug = false +--[===[@debug@ +debug = true +--@end-debug@]===] + +local L = LibStub("AceLocale-3.0"):NewLocale("DataStore_Quests", "enUS", true, debug) + +L["AUTO_UPDATE_DISABLED"] = "The quest history will remain in its current state, either empty or outdated." +L["AUTO_UPDATE_ENABLED"] = "A character's quest history will be refreshed every time you login with that character." +L["Auto-update History"] = true +L["AUTO_UPDATE_TITLE"] = "Auto-Update Quest History" +L["Track Quest Turn-ins"] = true +L["TRACK_TURNINS_DISABLED"] = "The quest history will remain in its current state, either empty or outdated." +L["TRACK_TURNINS_ENABLED"] = "Turned-in quests are saved into the history, to make sure it remains constantly valid." +L["TRACK_TURNINS_TITLE"] = "Track Quest Turn-ins" + diff --git a/Altoholic-Addon/DataStore_Quests/Locales/esES.lua b/Altoholic-Addon/DataStore_Quests/Locales/esES.lua new file mode 100644 index 0000000..e43cc77 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/esES.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore_Quests", "esES" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore_Quests/Locales/esMX.lua b/Altoholic-Addon/DataStore_Quests/Locales/esMX.lua new file mode 100644 index 0000000..4a7e8ba --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/esMX.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore_Quests", "esMX" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore_Quests/Locales/frFR.lua b/Altoholic-Addon/DataStore_Quests/Locales/frFR.lua new file mode 100644 index 0000000..9f21c66 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/frFR.lua @@ -0,0 +1,13 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore_Quests", "frFR" ) + +if not L then return end + +L["AUTO_UPDATE_DISABLED"] = "L'historique de quêtes restera dans son état actuel, soit vide ou obsolète." +L["AUTO_UPDATE_ENABLED"] = "L'historique de quêtes d'un personnage sera rafraîchi à chaque connexion de ce personnage." +L["Auto-update History"] = "Mise à jour automatique de l'historique" +L["AUTO_UPDATE_TITLE"] = "Mise à jour automatique de l'historique de quêtes" +L["Track Quest Turn-ins"] = "Suivre les validations de quêtes" +L["TRACK_TURNINS_DISABLED"] = "L'historique de quêtes restera dans son état actuel, soit vide ou obsolète." +L["TRACK_TURNINS_ENABLED"] = "Les validations de quêtes sont sauvées dans l'historique, afin d'assurer qu'il soit toujours valide." +L["TRACK_TURNINS_TITLE"] = "Suivre les validations de quêtes" + diff --git a/Altoholic-Addon/DataStore_Quests/Locales/koKR.lua b/Altoholic-Addon/DataStore_Quests/Locales/koKR.lua new file mode 100644 index 0000000..eb4515d --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/koKR.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore_Quests", "koKR" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore_Quests/Locales/repoenUS.lua b/Altoholic-Addon/DataStore_Quests/Locales/repoenUS.lua new file mode 100644 index 0000000..ceebff8 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/repoenUS.lua @@ -0,0 +1,12 @@ +local L = LibStub("AceLocale-3.0"):NewLocale("DataStore_Quests", "enUS", true, true) + +if not L then return end + +L["Track Quest Turn-ins"] = true +L["Auto-update History"] = true +L["TRACK_TURNINS_DISABLED"] = "The quest history will remain in its current state, either empty or outdated." +L["TRACK_TURNINS_ENABLED"] = "Turned-in quests are saved into the history, to make sure it remains constantly valid." +L["TRACK_TURNINS_TITLE"] = "Track Quest Turn-ins" +L["AUTO_UPDATE_DISABLED"] = "The quest history will remain in its current state, either empty or outdated." +L["AUTO_UPDATE_ENABLED"] = "A character's quest history will be refreshed every time you login with that character." +L["AUTO_UPDATE_TITLE"] = "Auto-Update Quest History" diff --git a/Altoholic-Addon/DataStore_Quests/Locales/ruRU.lua b/Altoholic-Addon/DataStore_Quests/Locales/ruRU.lua new file mode 100644 index 0000000..ee288b0 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/ruRU.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore_Quests", "ruRU" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore_Quests/Locales/zhCN.lua b/Altoholic-Addon/DataStore_Quests/Locales/zhCN.lua new file mode 100644 index 0000000..5e5e83f --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/zhCN.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore_Quests", "zhCN" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore_Quests/Locales/zhTW.lua b/Altoholic-Addon/DataStore_Quests/Locales/zhTW.lua new file mode 100644 index 0000000..4c285e9 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Locales/zhTW.lua @@ -0,0 +1,5 @@ +local L = LibStub("AceLocale-3.0"):NewLocale( "DataStore_Quests", "zhTW" ) + +if not L then return end + + diff --git a/Altoholic-Addon/DataStore_Quests/Options.lua b/Altoholic-Addon/DataStore_Quests/Options.lua new file mode 100644 index 0000000..6b9c39c --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Options.lua @@ -0,0 +1,20 @@ +if not DataStore then return end + +local addonName = "DataStore_Quests" +local addon = _G[addonName] +local L = LibStub("AceLocale-3.0"):GetLocale(addonName) + +function addon:SetupOptions() + DataStore:AddOptionCategory(DataStoreQuestsOptions, addonName, "DataStore") + + -- localize options + DataStoreQuestsOptions_TrackTurnInsText:SetText(L["Track Quest Turn-ins"]) + DataStoreQuestsOptions_AutoUpdateHistoryText:SetText(L["Auto-update History"]) + + DataStore:SetCheckBoxTooltip(DataStoreQuestsOptions_TrackTurnIns, L["TRACK_TURNINS_TITLE"], L["TRACK_TURNINS_ENABLED"], L["TRACK_TURNINS_DISABLED"]) + DataStore:SetCheckBoxTooltip(DataStoreQuestsOptions_AutoUpdateHistory, L["AUTO_UPDATE_TITLE"], L["AUTO_UPDATE_ENABLED"], L["AUTO_UPDATE_DISABLED"]) + + -- restore saved options to gui + DataStoreQuestsOptions_TrackTurnIns:SetChecked(DataStore:GetOption(addonName, "TrackTurnIns")) + DataStoreQuestsOptions_AutoUpdateHistory:SetChecked(DataStore:GetOption(addonName, "AutoUpdateHistory")) +end diff --git a/Altoholic-Addon/DataStore_Quests/Options.xml b/Altoholic-Addon/DataStore_Quests/Options.xml new file mode 100644 index 0000000..0e18552 --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/Options.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Quests", "TrackTurnIns") + + + + + + + + + + + + + + + + + DataStore:ToggleOption(self, "DataStore_Quests", "AutoUpdateHistory") + + + + + + + + diff --git a/Altoholic-Addon/DataStore_Quests/locale.xml b/Altoholic-Addon/DataStore_Quests/locale.xml new file mode 100644 index 0000000..3eb054f --- /dev/null +++ b/Altoholic-Addon/DataStore_Quests/locale.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Altoholic-Addon/DataStore_Reputations/Changelog-DataStore_Reputations-r10.txt b/Altoholic-Addon/DataStore_Reputations/Changelog-DataStore_Reputations-r10.txt new file mode 100644 index 0000000..8db82a1 --- /dev/null +++ b/Altoholic-Addon/DataStore_Reputations/Changelog-DataStore_Reputations-r10.txt @@ -0,0 +1,19 @@ +------------------------------------------------------------------------ +r10 | thaoky | 2009-12-09 12:35:19 +0000 (Wed, 09 Dec 2009) | 1 line +Changed paths: + M /trunk/DataStore_Reputations.toc + +ToC Update +------------------------------------------------------------------------ +r9 | thaoky | 2009-11-15 14:30:45 +0000 (Sun, 15 Nov 2009) | 1 line +Changed paths: + M /trunk/DataStore_Reputations.toc + +TOC update. +------------------------------------------------------------------------ +r8 | thaoky | 2009-09-13 15:15:23 +0000 (Sun, 13 Sep 2009) | 1 line +Changed paths: + M /trunk/DataStore_Reputations.toc + +TOC update +------------------------------------------------------------------------ diff --git a/Altoholic-Addon/DataStore_Reputations/DataStore_Reputations.lua b/Altoholic-Addon/DataStore_Reputations/DataStore_Reputations.lua new file mode 100644 index 0000000..cdd5505 --- /dev/null +++ b/Altoholic-Addon/DataStore_Reputations/DataStore_Reputations.lua @@ -0,0 +1,191 @@ +--[[ *** DataStore_Reputations *** +Written by : Thaoky, EU-Marécages de Zangar +June 22st, 2009 +--]] +if not DataStore then return end + +local addonName = "DataStore_Reputations" + +_G[addonName] = LibStub("AceAddon-3.0"):NewAddon(addonName, "AceConsole-3.0", "AceEvent-3.0") + +local addon = _G[addonName] + +local THIS_ACCOUNT = "Default" + +local AddonDB_Defaults = { + global = { + Characters = { + ['*'] = { -- ["Account.Realm.Name"] + lastUpdate = nil, + Factions = {}, + } + } + } +} + +local BottomLevels = { + [-42000] = FACTION_STANDING_LABEL1, -- "Hated" + [-6000] = FACTION_STANDING_LABEL2, -- "Hostile" + [-3000] = FACTION_STANDING_LABEL3, -- "Unfriendly" + [0] = FACTION_STANDING_LABEL4, -- "Neutral" + [3000] = FACTION_STANDING_LABEL5, -- "Friendly" + [9000] = FACTION_STANDING_LABEL6, -- "Honored" + [21000] = FACTION_STANDING_LABEL7, -- "Revered" + [42000] = FACTION_STANDING_LABEL8, -- "Exalted" +} + +-- ** Mixins ** +local function _GetReputationInfo(character, faction) + local reputationData = character.Factions[faction] -- Ex "3000|9000|7680" + if not reputationData then return end + + local bottom, top, earned = strsplit("|", reputationData) + bottom = tonumber(bottom) + top = tonumber(top) + earned = tonumber(earned) + local rate = (earned - bottom) / (top - bottom) * 100 + + -- ex: "Revered", 15400, 21000, 73% + return BottomLevels[bottom], (earned - bottom), (top - bottom), rate +end + +local function _GetRawReputationInfo(character, faction) + -- same as GetReputationInfo, but returns raw values + local reputationData = character.Factions[faction] -- Ex "3000|9000|7680" + if not reputationData then return end + + local bottom, top, earned = strsplit("|", reputationData) + return tonumber(bottom), tonumber(top), tonumber(earned) +end + +local function _GetReputations(character) + return character.Factions +end + +local PublicMethods = { + GetReputationInfo = _GetReputationInfo, + GetRawReputationInfo = _GetRawReputationInfo, + GetReputations = _GetReputations, +} + +function addon:OnInitialize() + addon.db = LibStub("AceDB-3.0"):New(addonName .. "DB", AddonDB_Defaults) + + DataStore:RegisterModule(addonName, addon, PublicMethods) + DataStore:SetCharacterBasedMethod("GetReputationInfo") + DataStore:SetCharacterBasedMethod("GetRawReputationInfo") + DataStore:SetCharacterBasedMethod("GetReputations") +end + +function addon:OnEnable() + addon:RegisterEvent("PLAYER_ALIVE") + addon:RegisterEvent("CHAT_MSG_COMBAT_FACTION_CHANGE") +end + +function addon:OnDisable() + addon:UnregisterEvent("PLAYER_ALIVE") + addon:UnregisterEvent("CHAT_MSG_COMBAT_FACTION_CHANGE") +end + +-- *** Utility functions *** + +-- *** Scanning functions *** +local headersState = {} + +local function SaveHeaders() + local headerCount = 0 -- use a counter to avoid being bound to header names, which might not be unique. + + for i = GetNumFactions(), 1, -1 do -- 1st pass, expand all categories + local _, _, _, _, _, _, _, _, isHeader, isCollapsed = GetFactionInfo(i) + if isHeader then + headerCount = headerCount + 1 + if isCollapsed then + ExpandFactionHeader(i) + headersState[headerCount] = true + end + end + end +end + +local function RestoreHeaders() + local headerCount = 0 + for i = GetNumFactions(), 1, -1 do + local _, _, _, _, _, _, _, _, isHeader = GetFactionInfo(i) + if isHeader then + headerCount = headerCount + 1 + if headersState[headerCount] then + CollapseFactionHeader(i) + end + end + end + wipe(headersState) +end + +local function ScanReputations() + SaveHeaders() + + local factions = addon.ThisCharacter.Factions + wipe(factions) + + for i = 1, GetNumFactions() do -- 2nd pass, data collection + local name, _, _, bottom, top, earned, _, _, isHeader, _, hasRep = GetFactionInfo(i) + if (not isHeader) or (isHeader and hasRep) then + -- new in 3.0.2, headers may have rep, ex: alliance vanguard + horde expedition + factions[name] = bottom .. "|" .. top .. "|" .. earned + end + end + + RestoreHeaders() + + addon.ThisCharacter.lastUpdate = time() +end + +local PT = LibStub("LibPeriodicTable-3.1") +local BF = LibStub("LibBabble-Faction-3.0"):GetUnstrictLookupTable() + +function addon:GetSource(searchedID) + -- returns the faction where a given item ID can be obtained, as well as the level + local level, repData = PT:ItemInSet(searchedID, "Reputation.Reward") + if level and repData then + local _, _, faction = strsplit(".", repData) -- ex: "Reputation.Reward.Sporeggar" + faction = BF[faction] or faction -- localize faction name if possible + + -- level = 7, 29150:7 where 7 means revered + return faction, _G["FACTION_STANDING_LABEL"..level] + end +end + +-- *** EVENT HANDLERS *** +function addon:PLAYER_ALIVE() + ScanReputations() +end + +-- this turns +-- "Reputation with %s increased by %d." +-- into +-- "Reputation with (.+) increased by (%d+)." +local repUpMsg = gsub(FACTION_STANDING_INCREASED, "%%s", "(.+)") +repUpMsg = gsub(repUpMsg, "%%d", "(%%d+)") + +function addon:CHAT_MSG_COMBAT_FACTION_CHANGE(event, text) + -- This code is a bit more complex than calling ScanReputations again. + -- The purpose is to avoid triggering UPDATE_FACTION, as this may result in heavy processing in other addons + if not text then return end + + local faction, value = text:match(repUpMsg) + if faction and value then + local bottom, top, earned = DataStore:GetRawReputationInfo(DataStore:GetCharacter(), faction) + + if earned then + local newValue = earned + tonumber(value) + if newValue >= top then -- rep status increases (to revered, etc..) + ScanReputations() -- so scan all + else + addon.ThisCharacter.Factions[faction] = bottom .. "|" .. top .. "|" .. newValue + addon.ThisCharacter.lastUpdate = time() + end + else -- faction not in the db, scan all + ScanReputations() + end + end +end diff --git a/Altoholic-Addon/DataStore_Reputations/DataStore_Reputations.toc b/Altoholic-Addon/DataStore_Reputations/DataStore_Reputations.toc new file mode 100644 index 0000000..7e73be5 --- /dev/null +++ b/Altoholic-Addon/DataStore_Reputations/DataStore_Reputations.toc @@ -0,0 +1,18 @@ +## Interface: 30300 +## Title: DataStore_Reputations +## Notes: Stores information about character reputation levels +## Author: Thaoky (EU-Marécages de Zangar) +## Version: 3.3.001 +## Dependencies: DataStore +## OptionalDeps: Ace3 +## SavedVariables: DataStore_ReputationsDB +## X-Category: Interface Enhancements +## X-Embeds: Ace3 +## X-Curse-Packaged-Version: r10 +## X-Curse-Project-Name: DataStore_Reputations +## X-Curse-Project-ID: datastore_reputations +## X-Curse-Repository-ID: wow/datastore_reputations/mainline + +embeds.xml + +DataStore_Reputations.lua diff --git a/Altoholic-Addon/DataStore_Reputations/LICENSE.txt b/Altoholic-Addon/DataStore_Reputations/LICENSE.txt new file mode 100644 index 0000000..4301cb1 --- /dev/null +++ b/Altoholic-Addon/DataStore_Reputations/LICENSE.txt @@ -0,0 +1,2 @@ + +All Rights Reserved unless otherwise explicitly stated. \ No newline at end of file diff --git a/Altoholic-Addon/DataStore_Reputations/embeds.xml b/Altoholic-Addon/DataStore_Reputations/embeds.xml new file mode 100644 index 0000000..89bc8ba --- /dev/null +++ b/Altoholic-Addon/DataStore_Reputations/embeds.xml @@ -0,0 +1,8 @@ + + + + +