diff --git a/.env.example b/.env.example index d6042d0..a045bcc 100644 --- a/.env.example +++ b/.env.example @@ -6,3 +6,7 @@ AWS_DEFAULT_REGION= AWS_BUCKET= AWS_ENDPOINT= AWS_USE_PATH_STYLE_ENDPOINT= + +PRODUCTION_REALMLIST= +PTR_REALMLIST= +LOCAL_REALMLIST= diff --git a/modules/moonwell/src/MoonWell.cpp b/modules/moonwell/src/MoonWell.cpp index f8d2e86..3adcfbb 100644 --- a/modules/moonwell/src/MoonWell.cpp +++ b/modules/moonwell/src/MoonWell.cpp @@ -6,6 +6,7 @@ // boot phase, before GlueXML is loaded. #include "core/Logger.hpp" +#include "core/Hook.hpp" #include "core/Mem.hpp" #include "runtime/LuaBindings.hpp" #include "runtime/ModuleInstall.hpp" @@ -28,6 +29,88 @@ namespace moonwell using GxSetProjectionFn = wxl::offsets::engine::gx::GxSetProjectionFn; GxSetProjectionFn g_nextSetProjection = nullptr; + // FrameXML's stock SetCreature only accepts a creature entry and waits + // for its client cache record. Encounter Journal already has the exact + // CreatureDisplayInfo ID, so accept it as an optional second argument. + constexpr uintptr_t kSetCreature = 0x00597960; + constexpr uintptr_t kGetCurrentModelFrame = 0x004A81B0; + constexpr uintptr_t kModelFrameTypeToken = 0x00C0E4D4; + constexpr uintptr_t kApplyCreatureCacheRecord = 0x00597700; + + using SetCreatureFn = int(__cdecl*)(void* state); + using ApplyCreatureCacheRecordFn = void(__fastcall*)(void* frame, void* edx, + const void* cacheRecord); + SetCreatureFn g_nextSetCreature = nullptr; + alignas(4) std::array g_encounterJournalCreatureRecord{}; + + void* GetCurrentModelFrame(void* state, uint32_t typeToken) + { + // FrameScript_GetObject takes the type token on the stack, but the + // 3.3.5 client also expects lua_State in ESI (an internal calling + // convention not expressible with a regular C function pointer). + void* frame = nullptr; + __asm + { + mov esi, state + push typeToken + mov eax, kGetCurrentModelFrame + call eax + add esp, 4 + mov frame, eax + } + return frame; + } + + int __cdecl SetCreatureDisplayInfoHook(void* state) + { + const int result = g_nextSetCreature ? g_nextSetCreature(state) : 0; + if (!state || !wxl::runtime::lua::IsNumber(state, 3)) + return result; + + const double requestedDisplayInfo = wxl::runtime::lua::ToNumber(state, 3); + if (requestedDisplayInfo <= 0.0 || requestedDisplayInfo > 4294967295.0) + return result; + + const auto displayInfo = static_cast(requestedDisplayInfo); + __try + { + const uint32_t typeToken = *reinterpret_cast(kModelFrameTypeToken); + if (!typeToken) + return result; + + void* frame = GetCurrentModelFrame(state, typeToken); + if (!frame) + return result; + + // Both the initial loader and the later character-appearance + // pass read displayInfo at +0x24. Keep this record alive and + // attach it to the frame: character models use it asynchronously + // to resolve CreatureDisplayInfoExtra, baked skin and equipment. + g_encounterJournalCreatureRecord.fill(0); + g_encounterJournalCreatureRecord[9] = displayInfo; + *reinterpret_cast(static_cast(frame) + 0x378) = + g_encounterJournalCreatureRecord.data(); + reinterpret_cast(kApplyCreatureCacheRecord)( + frame, nullptr, g_encounterJournalCreatureRecord.data()); + } + __except (EXCEPTION_EXECUTE_HANDLER) + { + WLOG_ERROR("moonwell: SetCreature displayInfo bridge failed for %u", displayInfo); + } + return result; + } + + void InstallEncounterJournalModelPreview() + { + if (!wxl::core::hook::Install("MoonWellSetCreatureDisplayInfo", kSetCreature, + &SetCreatureDisplayInfoHook, &g_nextSetCreature)) + { + WLOG_ERROR("moonwell: encounter journal model hook installation failed"); + return; + } + WLOG_INFO("moonwell: encounter journal displayInfo model bridge installed"); + } + struct CameraTransition { float zoom = 1.0f; @@ -60,7 +143,6 @@ namespace moonwell return; } - // Smoothstep avoids a visible jerk at both ends of the move. t = t * t * (3.0f - 2.0f * t); camera.zoom = camera.startZoom + (camera.targetZoom - camera.startZoom) * t; camera.verticalOffset = camera.startVerticalOffset diff --git a/run.ps1 b/run.ps1 index e645090..38be751 100644 --- a/run.ps1 +++ b/run.ps1 @@ -1,3 +1,9 @@ +param( + [Parameter(Mandatory=$false)] + [ValidateSet("production", "ptr", "local")] + [string]$Env = "local" +) + # Stop on errors $ErrorActionPreference = "Stop" @@ -81,6 +87,21 @@ if ($LASTEXITCODE -ge 8) { Write-Host "MPQ archives deployed to $WOW_HOME" +# --- Write realmlist.wtf based on selected environment +$realmlist = switch ($Env) { + "production" { $env:PRODUCTION_REALMLIST } + "ptr" { $env:PTR_REALMLIST } + "local" { $env:LOCAL_REALMLIST } +} + +if ($realmlist) { + $realmlistPath = Join-Path $WOW_HOME "Data\ruRU\realmlist.wtf" + Set-Content -Path $realmlistPath -Value "set realmlist $realmlist" -Encoding ASCII + Write-Host "Realmlist ($Env): $realmlist" +} else { + Write-Warning "REALMLIST for '$Env' is not set in .env -- skipping realmlist.wtf" +} + # --- Run WoW reload script Write-Host "Launching WoW..." cmd /c $RELOAD_SCRIPT diff --git a/src/Data/ruRU/patch-ruRU-4/Interface/GlueXML/CharacterCreate.lua b/src/Data/ruRU/patch-ruRU-4/Interface/GlueXML/CharacterCreate.lua index e96a332..c333fbe 100644 --- a/src/Data/ruRU/patch-ruRU-4/Interface/GlueXML/CharacterCreate.lua +++ b/src/Data/ruRU/patch-ruRU-4/Interface/GlueXML/CharacterCreate.lua @@ -23,7 +23,7 @@ FACTION_BACKDROP_COLOR_TABLE = { ["Alliance"] = {0.5, 0.5, 0.5, 0.09, 0.09, 0.19}, ["Horde"] = {0.5, 0.2, 0.2, 0.19, 0.05, 0.05}, }; -FRAMES_TO_BACKDROP_COLOR = { +FRAMES_TO_BACKDROP_COLOR = { "CharacterCreateCharacterRace", "CharacterCreateCharacterClass", -- "CharacterCreateCharacterFaction", @@ -36,11 +36,11 @@ RACE_ICON_TCOORDS = { ["NIGHTELF_MALE"] = {0.126953125, 0.189453125, 0.000000000, 0.125953125}, ["DRAENEI_MALE"] = {0.255859375, 0.318359375, 0.000000000, 0.125953125}, - ["HUMAN_FEMALE"] = {0.000000000, 0.062500000, 0.128906250, 0.253906250}, - ["DWARF_FEMALE"] = {0.063476563, 0.125976563, 0.128906250, 0.253906250}, - ["GNOME_FEMALE"] = {0.192382813, 0.254882813, 0.128906250, 0.253906250}, - ["NIGHTELF_FEMALE"] = {0.127441406, 0.189941406, 0.128906250, 0.253906250}, - ["DRAENEI_FEMALE"] = {0.256347656, 0.318359375, 0.128906250, 0.253906250}, + ["HUMAN_FEMALE"] = {0.000000000, 0.062500000, 0.128906250, 0.253906250}, + ["DWARF_FEMALE"] = {0.063476563, 0.125976563, 0.128906250, 0.253906250}, + ["GNOME_FEMALE"] = {0.192382813, 0.254882813, 0.128906250, 0.253906250}, + ["NIGHTELF_FEMALE"] = {0.127441406, 0.189941406, 0.128906250, 0.253906250}, + ["DRAENEI_FEMALE"] = {0.256347656, 0.318359375, 0.128906250, 0.253906250}, ["ORC_MALE"] = {0.062011719, 0.000000000, 0.262695313, 0.384765625}, ["SCOURGE_MALE"] = {0.125976563, 0.063964844, 0.262695313, 0.384765625}, @@ -48,10 +48,10 @@ RACE_ICON_TCOORDS = { ["TROLL_MALE"] = {0.253906250, 0.192382813, 0.262695313, 0.384765625}, ["BLOODELF_MALE"] = {0.317871094, 0.256835938, 0.262695313, 0.384765625}, - ["ORC_FEMALE"] = {0.060546875, 0.000000000, 0.391601563, 0.512695313}, - ["SCOURGE_FEMALE"] = {0.124023438, 0.063476563, 0.391601563, 0.512695313}, - ["TAUREN_FEMALE"] = {0.187988281, 0.127441406, 0.391601563, 0.512695313}, - ["TROLL_FEMALE"] = {0.252441406, 0.191894531, 0.391601563, 0.512695313}, + ["ORC_FEMALE"] = {0.060546875, 0.000000000, 0.391601563, 0.512695313}, + ["SCOURGE_FEMALE"] = {0.124023438, 0.063476563, 0.391601563, 0.512695313}, + ["TAUREN_FEMALE"] = {0.187988281, 0.127441406, 0.391601563, 0.512695313}, + ["TROLL_FEMALE"] = {0.252441406, 0.191894531, 0.391601563, 0.512695313}, ["BLOODELF_FEMALE"] = {0.316894531, 0.256835938, 0.391601563, 0.512695313}, }; CLASS_ICON_TCOORDS = { @@ -137,23 +137,23 @@ local function HideAllTooltips() if AllianceTooltip then AllianceTooltip:Hide() end - + if HordeTooltip then HordeTooltip:Hide() end end local backdrop = { - bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", - edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", - tile = true, tileSize = 16, edgeSize = 16, + bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", + edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", + tile = true, tileSize = 16, edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4 } }; local Backdrop2 = { - bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", - edgeFile = "Interface\\Tooltips\\ui-tooltip-border-maw", - tile = true, tileSize = 16, edgeSize = 16, + bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", + edgeFile = "Interface\\Tooltips\\ui-tooltip-border-maw", + tile = true, tileSize = 16, edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4 } }; @@ -164,10 +164,10 @@ local function GetOrCreateRaceTooltip(button) tooltip:SetSize(280, 150) tooltip:SetFrameStrata("TOOLTIP") tooltip:SetBackdropColor(0, 0, 0, 1) - + local raceID = button:GetID() local faction = _G.GetFactionForRaceID(raceID) - + if faction == "Alliance" then tooltip:SetPoint("LEFT", CharacterCreateFrame, "LEFT", 160, 50) elseif faction == "Horde" then @@ -194,7 +194,7 @@ local function GetOrCreateRaceTooltip(button) tooltip.rightClickText:SetPoint("TOP", tooltip.detailsText, "BOTTOM", 0, -10) tooltip.rightClickText:SetTextColor(0.8, 0.8, 0.8) tooltip.rightClickText:SetJustifyH("CENTER") - + raceTooltips[button] = tooltip end return raceTooltips[button] @@ -217,7 +217,7 @@ local function UpdateRaceTooltip(button, toggleDetails) tooltip.text:ClearAllPoints() tooltip.text:SetPoint("TOPLEFT", tooltip, "TOPLEFT", 10, -5) - + tooltip.detailsText:ClearAllPoints() tooltip.detailsText:SetPoint("TOPLEFT", tooltip.text, "BOTTOMLEFT", 0, -5) @@ -271,7 +271,7 @@ local function UpdateRaceTooltip(button, toggleDetails) local containerHeight = tooltip["spellIcon"..i]:GetHeight() + tooltip["spellDesc"..i]:GetHeight() + 3 tooltip["spellContainer"..i]:SetHeight(containerHeight) - + lastElement = tooltip["spellContainer"..i] end end @@ -308,10 +308,10 @@ local function UpdateRaceTooltip(button, toggleDetails) end end - local baseHeight = tooltip.text:GetHeight() + - tooltip.detailsText:GetHeight() + + local baseHeight = tooltip.text:GetHeight() + + tooltip.detailsText:GetHeight() + tooltip.rightClickText:GetHeight() + 25 - + tooltip:SetHeight(baseHeight + heightToAdd) detailedRaceTooltips[button] = toggleDetails tooltip:ClearAllPoints() @@ -346,7 +346,7 @@ local function GetOrCreateClassTooltip(button) tooltip.Roles:SetWidth(284) tooltip.Roles:SetWordWrap(true) tooltip.Roles:SetJustifyH("LEFT") - + classTooltips[button] = tooltip end @@ -370,7 +370,7 @@ local function GetValidRacesForClass(classID) table.insert(hordeRaces, raceName) end end - + return allianceRaces, hordeRaces end local function UpdateClassTooltip(button) @@ -382,7 +382,7 @@ local function UpdateClassTooltip(button) local buttonX, buttonY = button:GetCenter() local parentX, parentY = CharacterCreateFrame:GetCenter() - + if buttonX > parentX then tooltip:SetPoint("BOTTOMRIGHT", button, "TOPRIGHT", 0, 10) else @@ -394,7 +394,7 @@ local function UpdateClassTooltip(button) tooltip.text:ClearAllPoints() tooltip.text:SetPoint("TOPLEFT", tooltip, "TOPLEFT", 8, -8) - + tooltip.detailsText:ClearAllPoints() tooltip.detailsText:SetPoint("TOPLEFT", tooltip.text, "BOTTOMLEFT", 0, -5) @@ -405,7 +405,7 @@ local function UpdateClassTooltip(button) tooltip.RestrictionText = tooltip.RestrictionText or tooltip:CreateFontString(nil, "OVERLAY") tooltip.RestrictionText:SetFont("Fonts\\FRIZQT__.TTF", 12, "OUTLINE") tooltip.RestrictionText:SetJustifyH("LEFT") - + tooltip.FactionText = tooltip.FactionText or tooltip:CreateFontString(nil, "OVERLAY") tooltip.FactionText:SetFont("Fonts\\FRIZQT__.TTF", 11) tooltip.FactionText:SetWordWrap(true) @@ -416,12 +416,12 @@ local function UpdateClassTooltip(button) coloredRoles = string.gsub(coloredRoles, "Дальний бой", "|cffff2020Дальний бой|r") coloredRoles = string.gsub(coloredRoles, "Танк", "|cff0070ddТанк|r") coloredRoles = string.gsub(coloredRoles, "Лекарь", "|cff20c000Лекарь|r") - + if not tooltip.Roles then tooltip.Roles = tooltip:CreateFontString(nil, "OVERLAY") tooltip.Roles:SetFont("Fonts\\FRIZQT__.TTF", 11) end - + tooltip.Roles:SetText("|cFFFFFFFF"..FUNTION_INF.."|r\n\n "..coloredRoles) if showRestriction then @@ -435,20 +435,20 @@ local function UpdateClassTooltip(button) tooltip.RestrictionText:Show() local allianceRaces, hordeRaces = GetValidRacesForClass(classID) - + local factionText = "" - + if #allianceRaces > 0 then factionText = ALLIANCE_RACE .. " |cFFFFFFFF" .. table.concat(allianceRaces, ", ") .. "|r" end - + if #hordeRaces > 0 then if factionText ~= "" then factionText = factionText .. "\n\n" end factionText = factionText .. "\n" .. HORDE_RACE .. " |cFFFFFFFF" .. table.concat(hordeRaces, ", ") .. "|r" end - + tooltip.FactionText:SetPoint("TOPLEFT", tooltip.RestrictionText, "BOTTOMLEFT", 0, -15) tooltip.FactionText:SetTextColor(1, 0.82, 0) tooltip.FactionText:SetText(factionText) @@ -459,18 +459,18 @@ local function UpdateClassTooltip(button) maxWidth = math.max(maxWidth, tooltip.RestrictionText:GetWidth()) maxWidth = math.max(maxWidth, tooltip.FactionText:GetWidth()) maxWidth = math.max(280, math.min(maxWidth + 16, 400)) - + tooltip:SetWidth(maxWidth) tooltip.FactionText:SetWidth(maxWidth - 16) - - local restrictionHeight = tooltip.text:GetHeight() + - tooltip.detailsText:GetHeight() + + + local restrictionHeight = tooltip.text:GetHeight() + + tooltip.detailsText:GetHeight() + tooltip.Roles:GetHeight() + - tooltip.RestrictionText:GetHeight() + + tooltip.RestrictionText:GetHeight() + tooltip.FactionText:GetHeight() + 80 - + tooltip:SetHeight(restrictionHeight) - + else tooltip.RestrictionText:Hide() tooltip.FactionText:Hide() @@ -484,10 +484,10 @@ local function UpdateClassTooltip(button) maxWidth = math.max(280, math.min(maxWidth + 16, 400)) tooltip:SetWidth(maxWidth) - local baseHeight = tooltip.text:GetHeight() + - tooltip.detailsText:GetHeight() + + local baseHeight = tooltip.text:GetHeight() + + tooltip.detailsText:GetHeight() + tooltip.Roles:GetHeight() + 30 - + tooltip:SetHeight(baseHeight) end end @@ -498,7 +498,7 @@ function CharacterCreate_MoveTexturesToBackground() if button then local normalTex = _G[button:GetName().."NormalTexture"] local pushedTex = _G[button:GetName().."PushedTexture"] - + if normalTex then normalTex:SetDrawLayer("BACKGROUND") end @@ -513,7 +513,7 @@ function CharacterCreate_MoveTexturesToBackground() if button then local normalTex = _G[button:GetName().."NormalTexture"] local pushedTex = _G[button:GetName().."PushedTexture"] - + if normalTex then normalTex:SetDrawLayer("BACKGROUND") end @@ -525,12 +525,12 @@ function CharacterCreate_MoveTexturesToBackground() local maleButton = CharacterCreateGenderButtonMale local femaleButton = CharacterCreateGenderButtonFemale - + if maleButton then _G[maleButton:GetName().."NormalTexture"]:SetDrawLayer("BACKGROUND") _G[maleButton:GetName().."PushedTexture"]:SetDrawLayer("BACKGROUND") end - + if femaleButton then _G[femaleButton:GetName().."NormalTexture"]:SetDrawLayer("BACKGROUND") _G[femaleButton:GetName().."PushedTexture"]:SetDrawLayer("BACKGROUND") @@ -558,7 +558,7 @@ local function CreateFactionTooltip(parent, factionName) tooltip.description:SetWordWrap(true) tooltip.description:SetJustifyH("LEFT") tooltip.description:SetTextColor(0.9, 0.9, 0.9) - + return tooltip end @@ -566,7 +566,7 @@ local function UpdateTooltipSize(tooltip) local titleHeight = tooltip.title:GetHeight() local descHeight = tooltip.description:GetHeight() local totalHeight = titleHeight + descHeight + 30 - + tooltip:SetHeight(totalHeight) tooltip:SetWidth(300) end @@ -580,7 +580,7 @@ function CharacterCreate_PositionRaceButtons() local button = _G["CharacterCreateRaceButton"..i] if button then button:ClearAllPoints() - + if i == 1 then button:SetPoint("TOP", AllianceLogoFrame, "BOTTOM", -horizontalOffset, verticalStart) else @@ -594,7 +594,7 @@ function CharacterCreate_PositionRaceButtons() local button = _G["CharacterCreateRaceButton"..i] if button then button:ClearAllPoints() - + if i == 6 then button:SetPoint("TOP", HordeLogoFrame, "BOTTOM", horizontalOffset, verticalStart) else @@ -607,12 +607,12 @@ end function CharacterCreate_PositionClassButtons() local buttonSpacing = 80 - + for i = 1, MAX_CLASSES_PER_RACE do local button = _G["CharacterCreateClassButton"..i] if button then button:ClearAllPoints() - + if i == 1 then button:SetPoint("CENTER", CharacterCreateFrame, "BOTTOM", -360, 80) else @@ -624,16 +624,16 @@ function CharacterCreate_PositionClassButtons() end function CharacterCreate_PositionGenderButtons() - local genderSpacing = 310 - + local genderSpacing = 310 + local maleButton = CharacterCreateGenderButtonMale local femaleButton = CharacterCreateGenderButtonFemale - + if maleButton then maleButton:ClearAllPoints() maleButton:SetPoint("CENTER", CharacterCreateFrame, "CENTER", -(genderSpacing/2), -250) end - + if femaleButton then femaleButton:ClearAllPoints() femaleButton:SetPoint("CENTER", CharacterCreateFrame, "CENTER", (genderSpacing/2), -250) @@ -714,6 +714,44 @@ local function CharacterCreate_UpdateCamera(immediate) end end +-- The stock creation scene frames each race at a different height. Projection +-- zoom therefore needs a per-race vertical target to keep the face in frame. +-- Values are indexed by GetSelectedSex(): 2 male, 3 female. +local CHARACTER_CREATE_CAMERA_PROFILES = { + HUMAN = { [2] = -0.28, [3] = -0.20 }, + ORC = { [2] = -0.50, [3] = -0.30 }, + DWARF = { [2] = 0.30, [3] = 0.38 }, + NIGHTELF = { [2] = -0.65, [3] = -0.65 }, + SCOURGE = { [2] = 0.18, [3] = 0.27 }, + TAUREN = { [2] = -0.78, [3] = -0.62 }, + GNOME = { [2] = 0.64, [3] = 0.72 }, + TROLL = { [2] = -0.70, [3] = -0.55 }, + BLOODELF = { [2] = -0.30, [3] = -0.22 }, + DRAENEI = { [2] = -0.62, [3] = -0.55 }, +}; + +local function CharacterCreate_GetCameraProfile() + local _, raceFile = GetNameForRace(); + local raceProfile = raceFile and CHARACTER_CREATE_CAMERA_PROFILES[strupper(raceFile)]; + local sex = GetSelectedSex(); + return 2.0, raceProfile and raceProfile[sex] or -0.20; +end + +local function CharacterCreate_UpdateCamera(immediate) + local showFace = CharacterCreate.personalizationMode and not CharacterCreate.gameModeSelectionMode; + local mode = showFace and 1 or 0; + if CharacterCreate.cameraMode == mode and not immediate then + return; + end + + CharacterCreate.cameraMode = mode; + CharacterCreate:SetCamera(0); + if MoonWellSetCharacterCreateCamera then + local zoom, verticalOffset = CharacterCreate_GetCameraProfile(); + MoonWellSetCharacterCreateCamera(mode, zoom, verticalOffset, immediate and 0 or 500); + end +end + local function CharacterCreate_GetEnteredName() local text = ""; @@ -818,7 +856,7 @@ function CharacterCreate_OnLoad(self) self:SetSequence(0) self:SetCamera(0) SetCharCustomizeFrame("CharacterCreate") - + CharacterCreate.numRaces = 0 CharacterCreate.selectedRace = 0 CharacterCreate.numClasses = 0 @@ -860,7 +898,7 @@ function CharacterCreate_OnLoad(self) AllianceLogoFrame:SetSize(100, 100) AllianceLogoFrame:SetPoint("TOPLEFT", -16, 16) AllianceLogoFrame:EnableMouse(true) - + AllianceLogoFrame:SetScript("OnEnter", function(self) AllianceTooltip.title:SetText(ALLIANCE) AllianceTooltip.description:SetText(FACTION_ALLIANCE_DESCRIPTION) @@ -869,7 +907,7 @@ function CharacterCreate_OnLoad(self) AllianceTooltip:SetPoint("TOPLEFT", self, "BOTTOMLEFT", 90, 60) AllianceTooltip:Show() end) - + AllianceLogoFrame:SetScript("OnLeave", function(self) AllianceTooltip:Hide() end) @@ -890,7 +928,7 @@ function CharacterCreate_OnLoad(self) HordeLogoFrame:SetSize(100, 100) HordeLogoFrame:SetPoint("TOPRIGHT", 16, 16) HordeLogoFrame:EnableMouse(true) - + HordeLogoFrame:SetScript("OnEnter", function(self) HordeTooltip.title:SetText(HORDE) HordeTooltip.description:SetText(FACTION_HORDE_DESCRIPTION) @@ -899,7 +937,7 @@ function CharacterCreate_OnLoad(self) HordeTooltip:SetPoint("TOPRIGHT", self, "BOTTOMRIGHT", -90, 60) HordeTooltip:Show() end) - + HordeLogoFrame:SetScript("OnLeave", function(self) HordeTooltip:Hide() end) @@ -913,7 +951,7 @@ function CharacterCreate_SetupCustomButtons() {button = CharCreateRandomizeButton, width = 36, height = 36}, {button = CharacterCreateRandomName, width = 30, height = 30} } - + local texturePath = "Interface\\Glues\\CharacterCreate\\charactercreate" for _, btnInfo in ipairs(buttons) do @@ -1002,7 +1040,7 @@ end) function CharacterCreate_OnShow() CharacterCreate.personalizationMode = false; - + for i=1, MAX_CLASSES_PER_RACE, 1 do local button = _G["CharacterCreateClassButton"..i]; button:Enable(); @@ -1026,7 +1064,7 @@ function CharacterCreate_OnShow() CharacterCreate.personalizationMode = false; CharacterCreate.gameModeSelectionMode = false; CharCreateOkayButton:Hide(); - + for i=1, NUM_CHAR_CUSTOMIZATIONS do _G["CharacterCustomizationButtonFrame"..i]:Hide(); end @@ -1113,11 +1151,11 @@ function CharacterCreateEnumerateRaces(...) local raceID = index local faction = _G.GetFactionForRaceID(raceID) local borderColor - + if faction == "Alliance" then borderColor = {0.0, 0.4, 1.0} else - borderColor = {1.0, 0.0, 0.0} + borderColor = {1.0, 0.0, 0.0} end if not button.staticTexture then @@ -1155,10 +1193,10 @@ function CharacterCreateEnumerateRaces(...) if not button.texturesMoved then button:SetScript("OnMouseDown", nil); button:SetScript("OnMouseUp", nil); - + button.texturesMoved = true; end - + button:Show(); if ( select(i+2, ...) == 1 ) then button.enable = true; @@ -1180,7 +1218,7 @@ function CharacterCreateEnumerateRaces(...) tooltip:Hide() end end) - + button:SetScript("OnMouseDown", function(self, clickedButton) if self:IsEnabled() and clickedButton == "RightButton" then local tooltip = GetOrCreateRaceTooltip(self) @@ -1246,7 +1284,7 @@ function CharacterCreateEnumerateClasses(...) button.nameFrame = CreateFrame("Frame", nil, button); button.nameFrame:SetSize(112, 40); button.nameFrame:SetPoint("TOP", button, "BOTTOM", 0, -5); - + button.nameFrame.text = button.nameFrame:CreateFontString(nil, "OVERLAY"); button.nameFrame.text:SetFont("Fonts\\FRIZQT__.TTF", 10, "OUTLINE"); button.nameFrame.text:SetPoint("CENTER", 0, 0); @@ -1261,10 +1299,10 @@ function CharacterCreateEnumerateClasses(...) if not button.texturesMoved then button:SetScript("OnMouseDown", nil); button:SetScript("OnMouseUp", nil); - + button.texturesMoved = true; end - + button:Show(); local className = select(i, ...); @@ -1311,7 +1349,7 @@ function CharacterCreateEnumerateClasses(...) tooltip:Hide() end end) - + button:SetScript("OnMouseDown", function(self, clickedButton) if self:IsEnabled() and clickedButton == "RightButton" then local tooltip = GetOrCreateClassTooltip(self) @@ -1356,14 +1394,14 @@ function CharacterCreate_CreateGenderButtonTextures() maleButton.staticTexture:SetTexture("Interface\\Glues\\CharacterCreate\\IconBorder_F1"); maleButton.staticTexture:SetSize(86, 86); maleButton.staticTexture:SetPoint("CENTER", 0, 0); - + maleButton.highlightTexture = maleButton:CreateTexture(maleButton:GetName().."HighlightTexture", "HIGHLIGHT"); maleButton.highlightTexture:SetTexture("Interface\\Glues\\CharacterCreate\\IconBorder_F1"); maleButton.highlightTexture:SetAlpha(0.5); maleButton.highlightTexture:SetBlendMode("ADD"); maleButton.highlightTexture:SetSize(86, 86); maleButton.highlightTexture:SetPoint("CENTER", 0, 0); - + maleButton.checkedTexture = maleButton:CreateTexture(maleButton:GetName().."CheckedTexture", "OVERLAY"); maleButton.checkedTexture:SetDrawLayer("OVERLAY", 7); maleButton.checkedTexture:SetTexture("Interface\\Glues\\CharacterCreate\\IconBorderRace_H"); @@ -1382,14 +1420,14 @@ function CharacterCreate_CreateGenderButtonTextures() femaleButton.staticTexture:SetTexture("Interface\\Glues\\CharacterCreate\\IconBorder_F1"); femaleButton.staticTexture:SetSize(86, 86); femaleButton.staticTexture:SetPoint("CENTER", 0, 0); - + femaleButton.highlightTexture = femaleButton:CreateTexture(femaleButton:GetName().."HighlightTexture", "HIGHLIGHT"); femaleButton.highlightTexture:SetTexture("Interface\\Glues\\CharacterCreate\\IconBorder_F1"); femaleButton.highlightTexture:SetAlpha(0.5); femaleButton.highlightTexture:SetBlendMode("ADD"); femaleButton.highlightTexture:SetSize(86, 86); femaleButton.highlightTexture:SetPoint("CENTER", 0, 0); - + femaleButton.checkedTexture = femaleButton:CreateTexture(femaleButton:GetName().."CheckedTexture", "OVERLAY"); femaleButton.checkedTexture:SetDrawLayer("OVERLAY", 7); femaleButton.checkedTexture:SetTexture("Interface\\Glues\\CharacterCreate\\IconBorderRace_H"); @@ -1480,7 +1518,7 @@ function SetCharacterClass(id) end CharacterCreate_UpdateButtonCheckedStates(); - + local className, classFileName, _, tank, healer, damage = GetSelectedClass(); local abilityIndex = 0; local tempText = _G["CLASS_INFO_"..classFileName..abilityIndex]; @@ -1493,7 +1531,7 @@ function SetCharacterClass(id) local coords = CLASS_ICON_TCOORDS[classFileName]; CharacterCreateClassIcon:SetTexCoord(coords[1], coords[2], coords[3], coords[4]); CharacterCreateClassLabel:SetText(className); - CharacterCreateClassRolesText:SetText(abilityText); + CharacterCreateClassRolesText:SetText(abilityText); CharacterCreateClassText:SetText(GetFlavorText("CLASS_"..strupper(classFileName), GetSelectedSex()).."|n|n"); CharacterCreateClassScrollFrameScrollBar:SetValue(0); end @@ -1529,7 +1567,7 @@ function CharacterCreate_UpdateButtonCheckedStates() local maleButton = CharacterCreateGenderButtonMale; local femaleButton = CharacterCreateGenderButtonFemale; - + if maleButton and maleButton.checkedTexture then if maleButton:GetChecked() then maleButton.checkedTexture:Show(); @@ -1537,7 +1575,7 @@ function CharacterCreate_UpdateButtonCheckedStates() maleButton.checkedTexture:Hide(); end end - + if femaleButton and femaleButton.checkedTexture then if femaleButton:GetChecked() then femaleButton.checkedTexture:Show(); @@ -1641,7 +1679,7 @@ function CharacterRace_OnClick(self, id) SetCharacterClass(classIndex); CharacterCreate_UpdateHairCustomization(); - + CharacterChangeFixup(); CharacterCreate_UpdateButtonCheckedStates(); @@ -1666,7 +1704,7 @@ function SetCharacterGender(sex) CharacterCreateEnumerateRaces(GetAvailableRaces()); CharacterCreateEnumerateClasses(GetAvailableClasses()); SetCharacterRace(GetSelectedRace()); - + local _,_,classIndex = GetSelectedClass(); if ( PAID_SERVICE_TYPE ) then classIndex = PaidChange_GetCurrentClassIndex(); @@ -1680,7 +1718,7 @@ function SetCharacterGender(sex) fileString = strupper(fileString); local coords = RACE_ICON_TCOORDS[fileString.."_"..gender]; CharacterCreateRaceIcon:SetTexCoord(coords[1], coords[2], coords[3], coords[4]); - + CharacterChangeFixup(); CharacterCreate_UpdateButtonCheckedStates(); @@ -1707,7 +1745,7 @@ function CharacterCreate_ResetState(immediate) CharCreatePersonalizeButton:Show(); CharCreateOkayButton:Hide(); CharacterCreate_UpdateGameModeVisibility(); - + for i=1, NUM_CHAR_CUSTOMIZATIONS do _G["CharacterCustomizationButtonFrame"..i]:Hide(); end @@ -1753,7 +1791,7 @@ end function CharacterCreate_UpdateHairCustomization() CharacterCustomizationButtonFrame3Text:SetText(_G["HAIR_"..GetHairCustomization().."_STYLE"]); CharacterCustomizationButtonFrame4Text:SetText(_G["HAIR_"..GetHairCustomization().."_COLOR"]); - CharacterCustomizationButtonFrame5Text:SetText(_G["FACIAL_HAIR_"..GetFacialHairCustomization()]); + CharacterCustomizationButtonFrame5Text:SetText(_G["FACIAL_HAIR_"..GetFacialHairCustomization()]); end function SetButtonDesaturated(button, desaturated, r, g, b) @@ -1775,7 +1813,7 @@ function SetButtonDesaturated(button, desaturated, r, g, b) g = 0.5; b = 0.5; end - + icon:SetVertexColor(r, g, b); end diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AchievementFrame/UI-Achievement-ProgressBar-Border.blp b/src/Data/ruRU/patch-ruRU-5/Interface/AchievementFrame/UI-Achievement-ProgressBar-Border.blp new file mode 100644 index 0000000..f94e8c3 Binary files /dev/null and b/src/Data/ruRU/patch-ruRU-5/Interface/AchievementFrame/UI-Achievement-ProgressBar-Border.blp differ diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI/modules/micromenu.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI/modules/micromenu.lua index e8631c0..da7919f 100644 --- a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI/modules/micromenu.lua +++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/DragonUI/modules/micromenu.lua @@ -69,25 +69,26 @@ local MainMenuBarBackpackButton = _G.MainMenuBarBackpackButton; local HelpMicroButton = _G.HelpMicroButton; local KeyRingButton = _G.KeyRingButton; --- Button collections (dynamically set based on server) -local MICRO_BUTTONS +-- Button collections (rebuilt after addons create optional custom buttons). +local function BuildMicroButtonList() + if isAscensionServer then + return { + _G.CharacterMicroButton, + _G.SpellbookMicroButton, + _G.TalentMicroButton, + _G.AchievementMicroButton, + _G.QuestLogMicroButton, + _G.SocialsMicroButton, + _G.LFDMicroButton, + _G.EncounterJournalMicroButton, + _G.PathToAscensionMicroButton, + _G.ChallengesMicroButton, + _G.MainMenuMicroButton, + _G.HelpMicroButton + } + end -if isAscensionServer then - MICRO_BUTTONS = { - _G.CharacterMicroButton, - _G.SpellbookMicroButton, - _G.TalentMicroButton, - _G.AchievementMicroButton, - _G.QuestLogMicroButton, - _G.SocialsMicroButton, - _G.LFDMicroButton, - _G.PathToAscensionMicroButton, - _G.ChallengesMicroButton, - _G.MainMenuMicroButton, - _G.HelpMicroButton - } -else - MICRO_BUTTONS = { + return { _G.CharacterMicroButton, _G.SpellbookMicroButton, _G.TalentMicroButton, @@ -95,6 +96,7 @@ else _G.QuestLogMicroButton, _G.SocialsMicroButton, _G.LFDMicroButton, + _G.EncounterJournalMicroButton, _G.CollectionsMicroButton, _G.PVPMicroButton, _G.MainMenuMicroButton, @@ -102,6 +104,7 @@ else } end +local MICRO_BUTTONS = BuildMicroButtonList() local bagslots = {_G.CharacterBag0Slot, _G.CharacterBag1Slot, _G.CharacterBag2Slot, _G.CharacterBag3Slot}; @@ -783,6 +786,8 @@ local function ApplyMicromenuSystem() return end + MICRO_BUTTONS = BuildMicroButtonList() + -- Store original states first StoreOriginalMicroButtonStates() @@ -911,6 +916,8 @@ local function ApplyMicromenuSystem() or (_G.PVPParentFrame and _G.PVPParentFrame:IsVisible() and true or false) or (_G.BattlefieldFrame and _G.BattlefieldFrame:IsVisible() and true or false) or (_G.HonorFrame and _G.HonorFrame:IsVisible() and true or false) + elseif buttonName == "EncounterJournal" then + return (_G.EncounterJournal and _G.EncounterJournal:IsVisible() and true or false) end return pressed @@ -919,6 +926,152 @@ local function ApplyMicromenuSystem() -- ============================================================================ -- SECTION 5: SPECIALIZED BUTTON SETUP -- ============================================================================ + local function SetupEncounterJournalButton(button) + local iconTexture = 'Interface\\EncounterJournal\\UI-EJ-PortraitIcon' + local backgroundTexture = 'Interface\\AddOns\\DragonUI\\Textures\\Micromenu\\uimicromenu2x' + local buttonWidth, buttonHeight = button:GetSize() + local dx, dy = -1, 1 + local offX, offY = button:GetPushedTextOffset() + + if not button.DragonUIEncounterJournalIcon then + button.DragonUIEncounterJournalIcon = button:CreateTexture(nil, 'ARTWORK') + end + + local icon = button.DragonUIEncounterJournalIcon + icon:SetTexture(iconTexture) + icon:SetTexCoord(0, 1, 0, 1) + icon:ClearAllPoints() + icon:SetPoint('CENTER', button, 'CENTER', 0, 0) + icon:SetSize(buttonWidth - 8, buttonWidth - 8) + icon:SetAlpha(1) + icon:Show() + + local highlightTexture = button:GetHighlightTexture() + if highlightTexture then + highlightTexture:SetTexture(iconTexture) + highlightTexture:SetTexCoord(0, 1, 0, 1) + highlightTexture:ClearAllPoints() + highlightTexture:SetAllPoints(icon) + highlightTexture:SetBlendMode('ADD') + highlightTexture:SetAlpha(0.55) + end + + if not button.DragonUIBackground then + local bg = button:CreateTexture(nil, 'BACKGROUND') + bg:SetTexture(backgroundTexture) + bg:SetSize(buttonWidth, buttonHeight + 1) + bg:SetTexCoord(0.0654297, 0.12793, 0.330078, 0.490234) + bg:SetPoint('CENTER', dx, dy) + button.DragonUIBackground = bg + + local bgPushed = button:CreateTexture(nil, 'BACKGROUND') + bgPushed:SetTexture(backgroundTexture) + bgPushed:SetSize(buttonWidth, buttonHeight + 1) + bgPushed:SetTexCoord(0.0654297, 0.12793, 0.494141, 0.654297) + bgPushed:SetPoint('CENTER', dx + offX, dy + offY) + bgPushed:Hide() + button.DragonUIBackgroundPushed = bgPushed + else + button.DragonUIBackground:SetTexture(backgroundTexture) + button.DragonUIBackground:SetTexCoord(0.0654297, 0.12793, 0.330078, 0.490234) + button.DragonUIBackground:ClearAllPoints() + button.DragonUIBackground:SetPoint('CENTER', dx, dy) + button.DragonUIBackground:SetSize(buttonWidth, buttonHeight + 1) + + if button.DragonUIBackgroundPushed then + button.DragonUIBackgroundPushed:SetTexture(backgroundTexture) + button.DragonUIBackgroundPushed:SetTexCoord(0.0654297, 0.12793, 0.494141, 0.654297) + button.DragonUIBackgroundPushed:ClearAllPoints() + button.DragonUIBackgroundPushed:SetPoint('CENTER', dx + offX, dy + offY) + button.DragonUIBackgroundPushed:SetSize(buttonWidth, buttonHeight + 1) + end + end + + button.dragonUIState = button.dragonUIState or {} + button.dragonUIState.pushed = IsSpecialMicroButtonActive(button, "EncounterJournal") + button.dragonUILastState = button.dragonUIState.pushed + button.dragonUITimer = button.dragonUITimer or 0 + + button.HandleDragonUIState = function() + local state = button.dragonUIState + local hlTex = button:GetHighlightTexture() + if state and state.pushed then + if icon then + icon:ClearAllPoints() + icon:SetPoint('CENTER', button, 'CENTER', offX, offY) + icon:SetAlpha(0.7) + end + if button.DragonUIBackground then + button.DragonUIBackground:Hide() + end + if button.DragonUIBackgroundPushed then + button.DragonUIBackgroundPushed:Show() + end + if hlTex then + hlTex:ClearAllPoints() + hlTex:SetPoint('TOPLEFT', icon, 'TOPLEFT', 0, 0) + hlTex:SetPoint('BOTTOMRIGHT', icon, 'BOTTOMRIGHT', 0, 0) + end + else + if icon then + icon:ClearAllPoints() + icon:SetPoint('CENTER', button, 'CENTER', 0, 0) + icon:SetAlpha(1) + end + if button.DragonUIBackground then + button.DragonUIBackground:Show() + end + if button.DragonUIBackgroundPushed then + button.DragonUIBackgroundPushed:Hide() + end + if hlTex then + hlTex:ClearAllPoints() + hlTex:SetAllPoints(icon) + end + end + end + + button:SetScript('OnUpdate', function(self, elapsed) + self.dragonUITimer = (self.dragonUITimer or 0) + elapsed + if self.dragonUITimer >= 0.1 then + self.dragonUITimer = 0 + local currentState = IsSpecialMicroButtonActive(self, "EncounterJournal") + if currentState ~= self.dragonUILastState then + self.dragonUILastState = currentState + if self.dragonUIState then + self.dragonUIState.pushed = currentState + end + if self.HandleDragonUIState then + self.HandleDragonUIState() + end + end + end + end) + + if not button.DragonUIStateHooks then + button:HookScript('OnMouseDown', function(self) + if self.dragonUIState then + self.dragonUIState.pushed = true + end + if self.HandleDragonUIState then + self.HandleDragonUIState() + end + end) + button:HookScript('OnMouseUp', function(self) + local currentState = IsSpecialMicroButtonActive(self, "EncounterJournal") + if self.dragonUIState then + self.dragonUIState.pushed = currentState + end + if self.HandleDragonUIState then + self.HandleDragonUIState() + end + end) + button.DragonUIStateHooks = true + end + + button.HandleDragonUIState() + end + local function SetupPVPButton(button) -- Mirror the Character button pattern: -- Instead of fighting WoW's internal NormalTexture alpha management, @@ -1582,6 +1735,8 @@ local function ApplyMicromenuSystem() end local function setupMicroButtons(xOffset) + MICRO_BUTTONS = BuildMicroButtonList() + local buttonxOffset = 0 local useGrayscale = addon.db.profile.micromenu.grayscale_icons @@ -1705,9 +1860,11 @@ local function ApplyMicromenuSystem() local isCharacterButton = (buttonName == "Character") local isPVPButton = (buttonName == "PVP") + local isEncounterJournalButton = (buttonName == "EncounterJournal") - local upCoords = not isCharacterButton and not isPVPButton and GetColoredTextureCoords(name, "Up") or nil - local shouldUseGrayscale = useGrayscale or (not isPVPButton and not upCoords and not isCharacterButton) + local upCoords = not isCharacterButton and not isPVPButton and not isEncounterJournalButton and GetColoredTextureCoords(name, "Up") or nil + local shouldUseGrayscale = (useGrayscale and not isEncounterJournalButton) or + (not isPVPButton and not isEncounterJournalButton and not upCoords and not isCharacterButton) if shouldUseGrayscale then -- Grayscale icons @@ -1741,6 +1898,8 @@ local function ApplyMicromenuSystem() end elseif isPVPButton then SetupPVPButton(button) + elseif isEncounterJournalButton then + SetupEncounterJournalButton(button) elseif isCharacterButton then SetupCharacterButton(button) else @@ -2245,6 +2404,8 @@ end return end + MICRO_BUTTONS = BuildMicroButtonList() + local useGrayscale = addon.db.profile.micromenu.grayscale_icons local configMode = useGrayscale and "grayscale" or "normal" local config = addon.db.profile.micromenu[configMode] diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/Custom_EncounterJournal/Custom_EncounterJournal.lua b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/Custom_EncounterJournal/Custom_EncounterJournal.lua new file mode 100644 index 0000000..5dd52be --- /dev/null +++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/Custom_EncounterJournal/Custom_EncounterJournal.lua @@ -0,0 +1,4172 @@ +UIPanelWindows["EncounterJournal"] = { area = "left", pushable = 0, whileDead = 1, width = 830, xOffset = "15", yOffset = +"-10" } + +--FILE CONSTANTS +local HEADER_INDENT = 15; +local MAX_CREATURES_PER_ENCOUNTER = 9; + +local SECTION_BUTTON_OFFSET = 6; +local SECTION_DESCRIPTION_OFFSET = 27; + +local EJ_STYPE_ITEM = 0; +local EJ_STYPE_ENCOUNTER = 1; +local EJ_STYPE_CREATURE = 2; +local EJ_STYPE_SECTION = 3; +local EJ_STYPE_INSTANCE = 4; + +local EJ_HTYPE_OVERVIEW = 3; + +local EJ_NUM_INSTANCE_PER_ROW = 4; + +local EJ_LORE_MAX_HEIGHT = 97; +local EJ_MAX_SECTION_MOVE = 320; + +local EJ_NUM_SEARCH_PREVIEWS = 5; +local EJ_SHOW_ALL_SEARCH_RESULTS_INDEX = EJ_NUM_SEARCH_PREVIEWS + 1; + +local NO_CLASS_FILTER = 0 +local NO_INV_TYPE_FILTER = 0 + +AJ_MAX_NUM_SUGGESTIONS = 3; + +-- Priority list for *not my spec* +local overviewPriorities = { + [1] = "DAMAGER", + [2] = "HEALER", + [3] = "TANK", +} + +local flagsByRole = { + ["DAMAGER"] = 1, + ["HEALER"] = 2, + ["TANK"] = 0, +} + +local rolesByFlag = { + [0] = "TANK", + [1] = "DAMAGER", + [2] = "HEALER" +} + +local EJ_Tabs = {}; +local EJ_BROKEN_BAKED_MODEL = {}; +local EJ_MODEL_CAMERA = { + -- Avatar of Hakkar is unusually small and anchored too low. + [8053] = { scale = 2.0, x = 0, y = 0.16, z = 0 }, + -- Gahz'rilla's native UI camera is an extreme facial close-up. + [7271] = { scale = 0.42, x = 0, y = 0.04, z = 0 }, +}; +local EJ_MODEL_USER_SCALE = {}; + +EJ_Tabs[1] = { frame = "overviewScroll", button = "overviewTab" }; +EJ_Tabs[2] = { frame = "lootScroll", button = "lootTab" }; +EJ_Tabs[3] = { frame = "detailsScroll", button = "bossTab" }; +EJ_Tabs[4] = { frame = "model", button = "modelTab" }; + + +local EJ_section_openTable = {}; + + +local EJ_LINK_INSTANCE = 0; +local EJ_LINK_ENCOUNTER = 1; +local EJ_LINK_SECTION = 3; + +local EJ_DIFFICULTIES = { + { size = "5", prefix = PLAYER_DIFFICULTY1, difficultyID = 1, difficultyMask = 1 }, + { size = "5", prefix = PLAYER_DIFFICULTY2, difficultyID = 2, difficultyMask = 2 }, + { size = "5", prefix = PLAYER_DIFFICULTY3, difficultyID = 3, difficultyMask = 4 }, + { size = "10", prefix = PLAYER_DIFFICULTY1, difficultyID = 1, difficultyMask = 1 }, + { size = "25", prefix = PLAYER_DIFFICULTY1, difficultyID = 2, difficultyMask = 2 }, + { size = "10", prefix = PLAYER_DIFFICULTY2, difficultyID = 3, difficultyMask = 4 }, + { size = "25", prefix = PLAYER_DIFFICULTY2, difficultyID = 4, difficultyMask = 8 }, +} + +local EJ_TIER_DATA = +{ + [1] = { backgroundAtlas = "UI-EJ-Classic", r = 1.0, g = 0.8, b = 0.0 }, + [2] = { backgroundAtlas = "UI-EJ-BurningCrusade", r = 0.6, g = 0.8, b = 0.0 }, + [3] = { backgroundAtlas = "UI-EJ-WrathoftheLichKing", r = 0.2, g = 0.8, b = 1.0 }, + [4] = { backgroundAtlas = "UI-EJ-Cataclysm", r = 1.0, g = 0.4, b = 0.0 }, + [5] = { backgroundAtlas = "UI-EJ-MistsofPandaria", r = 0.0, g = 0.6, b = 0.2 }, + [6] = { backgroundAtlas = "UI-EJ-WarlordsofDraenor", r = 0.82, g = 0.55, b = 0.1 }, + [7] = { backgroundAtlas = "UI-EJ-Legion", r = 1.0, g = 0.8, b = 0.0 }, + [8] = { backgroundAtlas = "UI-EJ-BattleforAzeroth", expansionLevel = LE_EXPANSION_BATTLE_FOR_AZEROTH }, + [9] = { backgroundAtlas = "UI-EJ-Shadowlands", expansionLevel = LE_EXPANSION_SHADOWLANDS }, + [10] = { backgroundAtlas = "UI-EJ-Dragonflight", expansionLevel = LE_EXPANSION_DRAGONFLIGHT }, + [11] = { backgroundAtlas = "UI-EJ-TheWarWithin", expansionLevel = LE_EXPANSION_WAR_WITHIN }, + [12] = { backgroundAtlas = "UI-EJ-Midnight", expansionLevel = LE_EXPANSION_MIDNIGHT }, +} + +EJButtonMixin = {} + +function EJButtonMixin:OnLoad() + local l, t, _, b, r = self.UpLeft:GetTexCoord(); + self.UpLeft:SetTexCoord(l, l + (r - l) / 2, t, b); + l, t, _, b, r = self.UpRight:GetTexCoord(); + self.UpRight:SetTexCoord(l + (r - l) / 2, r, t, b); + + l, t, _, b, r = self.DownLeft:GetTexCoord(); + self.DownLeft:SetTexCoord(l, l + (r - l) / 2, t, b); + l, t, _, b, r = self.DownRight:GetTexCoord(); + self.DownRight:SetTexCoord(l + (r - l) / 2, r, t, b); + + l, t, _, b, r = self.HighLeft:GetTexCoord(); + self.HighLeft:SetTexCoord(l, l + (r - l) / 2, t, b); + l, t, _, b, r = self.HighRight:GetTexCoord(); + self.HighRight:SetTexCoord(l + (r - l) / 2, r, t, b); +end + +function EJButtonMixin:OnMouseDown(button) + self.UpLeft:Hide(); + self.UpRight:Hide(); + + self.DownLeft:Show(); + self.DownRight:Show(); +end + +function EJButtonMixin:OnMouseUp(button) + self.UpLeft:Show(); + self.UpRight:Show(); + + self.DownLeft:Hide(); + self.DownRight:Hide(); +end + +function GetEJTierData(tier) + if C_EncounterJournal.IsTierSeasonal(tier) then + return EJ_TIER_DATA[11] + end + if tier > #EJ_TIER_DATA then + tier = C_EncounterJournal.GetServerTier() + end + return EJ_TIER_DATA[tier] or EJ_TIER_DATA[1]; +end + +ExpansionEnumToEJTierDataTableId = { + [LE_EXPANSION_CLASSIC] = 1, + [LE_EXPANSION_BURNING_CRUSADE] = 2, + [LE_EXPANSION_WRATH_OF_THE_LICH_KING] = 3, + [LE_EXPANSION_CATACLYSM] = 4, + [LE_EXPANSION_MISTS_OF_PANDARIA] = 5, + [LE_EXPANSION_WARLORDS_OF_DRAENOR] = 6, + [LE_EXPANSION_LEGION] = 7, + [LE_EXPANSION_BATTLE_FOR_AZEROTH] = 8, + [LE_EXPANSION_SHADOWLANDS] = 9, + [LE_EXPANSION_DRAGONFLIGHT] = 10, + [LE_EXPANSION_WAR_WITHIN] = 11, + [LE_EXPANSION_MIDNIGHT] = 12, +} + +function GetEJTierDataTableID(expansion) + local data = ExpansionEnumToEJTierDataTableId[expansion]; + if data then + return data; + end + + return ExpansionEnumToEJTierDataTableId[LE_EXPANSION_CLASSIC]; +end + +local BOSS_LOOT_BUTTON_HEIGHT = 45; +local INSTANCE_LOOT_BUTTON_HEIGHT = 64; + +local BOSS_BUTTON_FIRST_OFFSET = 10; +local BOSS_BUTTON_SECOND_OFFSET = 15; +local BOSS_BUTTON_HEIGHT = 55; + +function EncounterJournal_InitTab(self) + if not C_Service.IsRenegadeRealm() then + PanelTemplates_HideTab(self, 2) + EncounterJournalTab3:SetPoint("LEFT", EncounterJournalTab1, "RIGHT", -16, 0); + end + if not C_Service.IsHardcoreEnabledOnRealm() then + PanelTemplates_HideTab(self, 3) + end + if not C_Service.IsGMAccount() and not IsInterfaceDevClient() then + PanelTemplates_HideTab(self, 4) + end +end + +local function EncounterJournal_ScrollFrame_OnMouseWheel(scrollFrame, delta, isHybrid) + if not scrollFrame then + return false; + end + + if isHybrid and HybridScrollFrame_OnMouseWheel then + HybridScrollFrame_OnMouseWheel(scrollFrame, delta); + return true; + end + + if ScrollFrameTemplate_OnMouseWheel then + ScrollFrameTemplate_OnMouseWheel(scrollFrame, delta); + return true; + end + + local scrollBar = scrollFrame.ScrollBar or scrollFrame.scrollBar or _G[scrollFrame:GetName() .. "ScrollBar"]; + if scrollBar then + local minValue, maxValue = scrollBar:GetMinMaxValues(); + local step = scrollBar:GetValueStep() or 20; + scrollBar:SetValue(math.min(maxValue, math.max(minValue, scrollBar:GetValue() - delta * step))); + return true; + end + + return false; +end + +function EncounterJournal_OnMouseWheel(self, delta) + if PlayerGuideFrame and PlayerGuideFrame:IsVisible() and PlayerGuideFrame.BodyScroll and PlayerGuideFrame.BodyScroll:IsShown() then + return EncounterJournal_ScrollFrame_OnMouseWheel(PlayerGuideFrame.BodyScroll, delta); + end + + if self.searchResults and self.searchResults:IsVisible() and self.searchResults.scrollFrame and self.searchResults.scrollFrame:IsShown() then + return EncounterJournal_ScrollFrame_OnMouseWheel(self.searchResults.scrollFrame, delta, true); + end + + if self.suggestFrame and self.suggestFrame:IsVisible() then + EJSuggestFrame_OnMouseWheel(self.suggestFrame, delta); + return true; + end + + local instanceSelect = self.instanceSelect; + if instanceSelect and instanceSelect:IsVisible() and instanceSelect.scroll and instanceSelect.scroll:IsShown() then + return EncounterJournal_ScrollFrame_OnMouseWheel(instanceSelect.scroll, delta); + end + + local info = self.encounter and self.encounter.info; + if info and info:IsVisible() then + if info.lootScroll and info.lootScroll:IsShown() then + return EncounterJournal_ScrollFrame_OnMouseWheel(info.lootScroll, delta, true); + elseif info.detailsScroll and info.detailsScroll:IsShown() then + return EncounterJournal_ScrollFrame_OnMouseWheel(info.detailsScroll, delta); + elseif info.overviewScroll and info.overviewScroll:IsShown() then + return EncounterJournal_ScrollFrame_OnMouseWheel(info.overviewScroll, delta); + elseif info.bossesScroll and info.bossesScroll:IsShown() then + return EncounterJournal_ScrollFrame_OnMouseWheel(info.bossesScroll, delta); + end + end + + return false; +end + +function EncounterJournal_OnLoad(self) + EncounterJournalTitleText:SetText(ADVENTURE_JOURNAL); + SetPortraitToTexture(EncounterJournalPortrait, "Interface\\EncounterJournal\\UI-EJ-PortraitIcon"); + self:RegisterCustomEvent("EJ_LOOT_DATA_RECIEVED"); + self:RegisterCustomEvent("EJ_DIFFICULTY_UPDATE"); + self:RegisterCustomEvent("SEARCH_DB_LOADED"); + self:EnableMouseWheel(true); + self:SetScript("OnMouseWheel", EncounterJournal_OnMouseWheel); + + do + SetParentFrameLevel(self.inset) + SetParentFrameLevel(self.instanceSelect) + SetParentFrameLevel(self.encounter) + SetParentFrameLevel(self.encounter.info) + + self.instanceSelect.guideTab.id = self.instanceSelect.guideTab:GetID() + self.instanceSelect.guideTab:SetText(MW_PLAYER_GUIDE) + self.instanceSelect.suggestTab.id = self.instanceSelect.suggestTab:GetID() + self.instanceSelect.dungeonsTab.id = self.instanceSelect.dungeonsTab:GetID() + self.instanceSelect.raidsTab.id = self.instanceSelect.raidsTab:GetID() + self.instanceSelect.LootJournalTab.id = self.instanceSelect.LootJournalTab:GetID() + self.instanceSelect.suggestTab:SetText(AJ_SUGGESTED_CONTENT_TAB) + self.instanceSelect.dungeonsTab:SetText(INSTANCES) + self.instanceSelect.raidsTab:SetText(RAIDS) + self.instanceSelect.LootJournalTab:SetText(LOOT_JOURNAL_ITEM_SETS) + + local info = EncounterJournal.encounter.info; + for index, data in ipairs(EJ_Tabs) do + local tabButton = info[data.button]; + SetParentFrameLevel(tabButton, 10) + end + + if self.instanceSelect.Tabs then + for _, tab in ipairs(self.instanceSelect.Tabs) do + tab:SetWidth(max(tab:GetTextWidth() + 20, 70)) + tab.selectedGlow:Hide() + end + end + end + + self.encounter.freeHeaders = {}; + self.encounter.usedHeaders = {}; + + self.encounter.overviewFrame = self.encounter.info.overviewScroll.child; + self.encounter.overviewFrame.isOverview = true; + self.encounter.overviewFrame.overviews = {}; + self.encounter.info.overviewScroll.ScrollBar.scrollStep = 30; + + self.encounter.infoFrame = self.encounter.info.detailsScroll.child; + self.encounter.info.detailsScroll.ScrollBar.scrollStep = 30; + + self.encounter.bossesFrame = self.encounter.info.bossesScroll.child; + self.encounter.info.bossesScroll.ScrollBar.scrollStep = 30; + + self.encounter.info.overviewTab:Click(); + + self.encounter.info.lootScroll.update = EncounterJournal_LootUpdate; + self.encounter.info.lootScroll.scrollBar.doNotHide = true; + self.encounter.info.lootScroll.dynamic = EncounterJournal_LootCalcScroll; + HybridScrollFrame_CreateButtons(self.encounter.info.lootScroll, "EncounterItemTemplate", 0, 0); + + self.searchResults.scrollFrame.update = EncounterJournal_SearchUpdate; + self.searchResults.scrollFrame.scrollBar.doNotHide = true; + HybridScrollFrame_CreateButtons(self.searchResults.scrollFrame, "EncounterSearchLGTemplate", 0, 0); + + local homeData = { + name = ENCOUNTER_JOURNAL_NAVIGATION_HOME or NAVIGATIONBAR_HOME, + OnClick = function() + if self.instanceSelect.selectedTab then + EJ_ContentTab_Select(self.instanceSelect.selectedTab); + NavBar_Reset(self.navBar) + else + EJPlayerGuide_OpenFrame(); + end + end, + } + NavBar_Initialize(self.navBar, "NavButtonTemplate", homeData, self.navBar.home, self.navBar.overflow); + UIDropDownMenu_Initialize(self.encounter.info.lootScroll.lootFilter, EncounterJournal_InitLootFilter, "MENU"); + UIDropDownMenu_Initialize(self.encounter.info.lootScroll.lootSlotFilter, EncounterJournal_InitLootSlotFilter, "MENU"); + + self.encounter.instance.FindGroupButton:SetShown(C_LFGList.IsPremadeGroupFinderEnabled()) + + -- initialize tabs + local instanceSelect = EncounterJournal.instanceSelect; + local tierName = EJ_GetTierInfo(EJ_GetCurrentTier()); + UIDropDownMenu_SetText(instanceSelect.tierDropDown, tierName); + + -- check if tabs are active + local dungeonInstanceID = EJ_GetInstanceByIndex(1, false); + if (not dungeonInstanceID) then + instanceSelect.dungeonsTab.grayBox:Show(); + end + local raidInstanceID = EJ_GetInstanceByIndex(1, true); + if (not raidInstanceID) then + instanceSelect.raidsTab.grayBox:Show(); + end + -- open the player guide by default + EJPlayerGuide_OpenFrame(); + + self.tab1:SetFrameLevel(1) + self.tab2:SetFrameLevel(1) + self.tab3:SetFrameLevel(1) + self.tab4:SetFrameLevel(1) + + self.maxTabWidth = (self:GetWidth() - 19) / 4 + + PanelTemplates_SetNumTabs(self, 4) + + self:RegisterCustomEvent("SERVICE_DATA_UPDATE") + self:RegisterCustomEvent("CUSTOM_CHALLENGE_DEACTIVATED") + self:RegisterCustomEvent("AJ_ACTION_EJ_DUNGEON") + + self.helpPlate = { + FramePos = { x = 0, y = -24 }, + FrameSize = { width = 800, height = 468 }, + [1] = { ButtonPos = { x = 95, y = -26 }, HighLightBox = { x = 17, y = -49, width = 202, height = 36 }, ToolTipDir = "RIGHT", ToolTipText = HEPLPLATE_ENCOUNTER_JOURNAL_TUTORIAL_1 }, + [2] = { ButtonPos = { x = 269, y = -26 }, HighLightBox = { x = 232, y = -49, width = 121, height = 36 }, ToolTipDir = "RIGHT", ToolTipText = HEPLPLATE_ENCOUNTER_JOURNAL_TUTORIAL_2 }, + [3] = { ButtonPos = { x = 389, y = -26 }, HighLightBox = { x = 366, y = -49, width = 92, height = 36 }, ToolTipDir = "RIGHT", ToolTipText = HEPLPLATE_ENCOUNTER_JOURNAL_TUTORIAL_3 }, + [4] = { ButtonPos = { x = 504, y = -26 }, HighLightBox = { x = 471, y = -49, width = 112, height = 36 }, ToolTipDir = "RIGHT", ToolTipText = HEPLPLATE_ENCOUNTER_JOURNAL_TUTORIAL_4 }, + [5] = { ButtonPos = { x = 758, y = -39 }, HighLightBox = { x = 600, y = -45, width = 181, height = 34 }, ToolTipDir = "RIGHT", ToolTipText = HEPLPLATE_ENCOUNTER_JOURNAL_TUTORIAL_5 }, + [6] = { ButtonPos = { x = 773, y = 5 }, HighLightBox = { x = 568, y = -2, width = 228, height = 32 }, ToolTipDir = "RIGHT", ToolTipText = HEPLPLATE_ENCOUNTER_JOURNAL_TUTORIAL_6 }, + } +end + +function EncounterJournal_GetLootJournalView() + return EncounterJournal.lootJournalView; +end + +function EncounterJournal_SetLootJournalView(view) + local self = EncounterJournal; + local activeViewPanel, inactiveViewPanel = EncounterJournal_GetLootJournalPanels(view); + self.LootJournalViewDropDown:SetParent(activeViewPanel); + self.LootJournalViewDropDown:SetPoint("TOPLEFT", 15, -9); + UIDropDownMenu_SetText(self.LootJournalViewDropDown, view); + + -- if no previous view then it's the init, no need to change which frame is shown + if self.lootJournalView then + activeViewPanel:Show(); + inactiveViewPanel:Hide(); + end + + self.lootJournalView = view; +end + +function EncounterJournal_GetLootJournalPanels(view) + local self = EncounterJournal; + if not view then + view = self.lootJournalView; + end + return self.LootJournalItems, self.LootJournal; +end + +function EncounterJournal_EnableTierDropDown() + local tierName = EJ_GetTierInfo(EJ_GetCurrentTier()); + UIDropDownMenu_SetText(EncounterJournal.instanceSelect.tierDropDown, tierName); + UIDropDownMenu_EnableDropDown(EncounterJournal.instanceSelect.tierDropDown); +end + +function EncounterJournal_DisableTierDropDown(removeText) + UIDropDownMenu_DisableDropDown(EncounterJournal.instanceSelect.tierDropDown); + if (removeText) then + UIDropDownMenu_SetText(EncounterJournal.instanceSelect.tierDropDown, nil); + else + local tierName = EJ_GetTierInfo(EJ_GetCurrentTier()); + UIDropDownMenu_SetText(EncounterJournal.instanceSelect.tierDropDown, tierName); + end +end + +function EncounterJournal_HasChangedContext(instanceID, instanceType, difficultyID) + if (instanceType == "none") then + -- we've gone from a dungeon to the open world + return EncounterJournal.lastInstance ~= nil; + elseif (instanceID ~= 0 and (instanceID ~= EncounterJournal.lastInstance or EncounterJournal.lastDifficulty ~= difficultyID)) then + -- dungeon or difficulty has changed + return true; + end + return false; +end + +function EncounterJournal_ResetDisplay(instanceID, instanceType, difficultyID) + if (instanceType == "none") then + EncounterJournal.lastInstance = nil; + EncounterJournal.lastDifficulty = nil; + EJPlayerGuide_OpenFrame(); + else + EJ_ContentTab_SelectAppropriateInstanceTab(instanceID); + + EncounterJournal_DisplayInstance(instanceID); + EncounterJournal.lastInstance = instanceID; + -- try to set difficulty to current instance difficulty + if (EJ_IsValidInstanceDifficulty(difficultyID)) then + EJ_SetDifficulty(difficultyID); + end + EncounterJournal.lastDifficulty = difficultyID; + end +end + +function EncounterJournal_OnShow(self) + C_EncounterJournal.OnOpen(); + PanelTemplates_SetTab(self, 1) + + -- MainMenuMicroButton_HideAlert(EncounterJournalMicroButton); + MicroButtonPulseStop(EncounterJournalMicroButton); + + UpdateMicroButtons(); + PlaySound("igCharacterInfoOpen"); + EncounterJournal_LootUpdate(); + + local instanceSelect = EncounterJournal.instanceSelect; + + --automatically navigate to the current dungeon if you are in one; + local instanceID = EJ_GetCurrentInstance(); + local _, instanceType, difficultyID = GetInstanceInfo(); + if (instanceID and EncounterJournal_HasChangedContext(instanceID, instanceType, difficultyID)) then + EncounterJournal_ResetDisplay(instanceID, instanceType, difficultyID); + end + + local tierData = GetEJTierData(EJ_GetCurrentTier()); + if (instanceSelect.suggestTab:IsEnabled() ~= 1 or EncounterJournal.suggestFrame:IsShown()) then + tierData = GetEJTierData(EJSuggestTab_GetPlayerTierIndex()); + end + instanceSelect.bg:SetAtlas(tierData.backgroundAtlas, true); + instanceSelect.raidsTab.selectedGlow:SetVertexColor(tierData.r, tierData.g, tierData.b); + instanceSelect.dungeonsTab.selectedGlow:SetVertexColor(tierData.r, tierData.g, tierData.b); + + local success = EncounterJournal_CheckAndDisplayEncounter() + if not success then + if instanceSelect:IsShown() then + EJ_ContentTab_Select(instanceSelect.selectedTab); + EncounterJournal_ListInstances() + end + end + + EncounterJournal_UpdateScrollPos(EncounterJournal.encounter.info.lootScroll, 1) + C_EncounterJournal.ResetSlotFilter() + + EventRegistry:TriggerEvent("EncounterJournal.OnShow") +end + +function EncounterJournal_OnHide(self) + C_EncounterJournal.OnClose(); + UpdateMicroButtons(); + PlaySound("igCharacterInfoClose"); + self.searchBox:SetText("") + EJ_EndSearch(); + + HelpPlate_Hide(false) + EventRegistry:TriggerEvent("EncounterJournal.OnHide") +end + +function EncounterJournal_CheckAndDisplayEncounter() + local instanceID, encounterID = C_EncounterJournal.GetClosestEncounter() + if instanceID then + NavBar_Reset(EncounterJournal.navBar) + EncounterJournal_DisplayInstance(instanceID) + EncounterJournal_DisplayEncounter(encounterID) + return true + end + return false +end + +local function EncounterJournal_GetRootAfterOverviews(rootSectionID) + local nextSectionID = rootSectionID; + + local headerType, siblingID, _; + + repeat + _, _, headerType, _, _, siblingID = EJ_GetSectionInfo(nextSectionID); + if (headerType == EJ_HTYPE_OVERVIEW) then + nextSectionID = siblingID; + end + until headerType ~= EJ_HTYPE_OVERVIEW; + + return nextSectionID; +end + +local function EncounterJournal_CheckForOverview(rootSectionID) + return select(3, EJ_GetSectionInfo(rootSectionID)) == EJ_HTYPE_OVERVIEW; +end + +local function EncounterJournal_SearchForOverview(instanceID) + local bossIndex = 1; + local _, _, bossID = EJ_GetEncounterInfoByIndex(bossIndex); + while bossID do + local _, _, _, rootSectionID = EJ_GetEncounterInfo(bossID); + + if (EncounterJournal_CheckForOverview(rootSectionID)) then + return true; + end + + bossIndex = bossIndex + 1; + _, _, bossID = EJ_GetEncounterInfoByIndex(bossIndex); + end + + return false; +end + +function EncounterJournal_OnEvent(self, event, ...) + if event == "SERVICE_DATA_UPDATE" + or (event == "CUSTOM_CHALLENGE_DEACTIVATED" and select(2, ...) == Enum.HardcoreDeathReason.RESTORE) + then + EncounterJournal_InitTab(self) + elseif event == "EJ_LOOT_DATA_RECIEVED" then + local itemID = ... + if itemID and not EJ_IsLootListOutOfDate() then + EncounterJournal_LootCallback(itemID); + + if EncounterJournal.searchResults:IsShown() then + EncounterJournal_SearchUpdate(); + elseif EncounterJouranl_IsSearchPreviewShown() then + EncounterJournal_UpdateSearchPreview(); + end + else + EncounterJournal_LootUpdate(); + end + elseif event == "EJ_DIFFICULTY_UPDATE" then + --fix the difficulty buttons + EncounterJournal_UpdateDifficulty(...); + elseif event == "SEARCH_DB_LOADED" then + EncounterJournal_RestartSearchTracking(); + elseif event == "AJ_ACTION_EJ_DUNGEON" then + local dungeonID, difficultyID = ... + + if not self:IsShown() then + ShowUIPanel(self) + end + + if dungeonID ~= 0 then + EncounterJournal_OpenJournal(difficultyID, dungeonID) + end + end +end + +function EncounterJournal_UpdateDifficulty(newDifficultyID, noRefresh) + local selectedEntry; + for i = 1, #EJ_DIFFICULTIES do + local entry = EJ_DIFFICULTIES[i] + if entry.difficultyID == newDifficultyID then + if EJ_IsValidInstanceDifficulty(entry.difficultyID) and (entry.size ~= "5" == EJ_InstanceIsRaidByID(EncounterJournal.instanceID)) then + selectedEntry = entry; + break; + end + end + end + + if not selectedEntry then + for i = 1, #EJ_DIFFICULTIES do + local entry = EJ_DIFFICULTIES[i] + if EJ_IsValidInstanceDifficulty(entry.difficultyID) and (entry.size ~= "5" == EJ_InstanceIsRaidByID(EncounterJournal.instanceID)) then + selectedEntry = entry; + break; + end + end + end + + if selectedEntry then + if selectedEntry.size ~= "5" then + EncounterJournal.encounter.info.difficulty:SetFormattedText("(%s) %s", selectedEntry.size, + selectedEntry.prefix); + else + EncounterJournal.encounter.info.difficulty:SetText(selectedEntry.prefix); + end + if not noRefresh then + EncounterJournal_Refresh(); + end + end +end + +function EncounterJournal_GetCreatureButton(index) + if index > MAX_CREATURES_PER_ENCOUNTER then + return nil; + end + + local self = EncounterJournal.encounter.info; + local button = self.creatureButtons[index]; + if (not button) then + button = CreateFrame("BUTTON", nil, self, "EncounterCreatureButtonTemplate"); + button:SetPoint("TOPLEFT", self.creatureButtons[index - 1], "BOTTOMLEFT", 0, 8); + self.creatureButtons[index] = button; + end + return button; +end + +local infiniteLoopPolice = false; --design might make a tier that has no instances at all sigh +local function EncounterJournal_UpdateInstanceListScrollRange(instanceCount) + local scrollFrame = EncounterJournal.instanceSelect.scroll; + local scrollChild = scrollFrame.child; + local scrollBar = scrollFrame.ScrollBar or _G[scrollFrame:GetName() .. "ScrollBar"]; + local rows = math.ceil((instanceCount or 0) / EJ_NUM_INSTANCE_PER_ROW); + local childHeight = 375; + + if rows > 0 then + childHeight = math.max(childHeight, 20 + rows * 96 + math.max(rows - 1, 0) * 15); + end + + scrollChild:SetHeight(childHeight); + if scrollFrame.UpdateScrollChildRect then + scrollFrame:UpdateScrollChildRect(); + end + if ScrollFrame_OnScrollRangeChanged then + ScrollFrame_OnScrollRangeChanged(scrollFrame, 0, math.max(0, childHeight - scrollFrame:GetHeight())); + end + if scrollBar then + scrollBar:SetValue(math.min(scrollBar:GetValue(), math.max(0, childHeight - scrollFrame:GetHeight()))); + end +end + +function EncounterJournal_BossList_OnMouseWheel(self, delta) + local scrollFrame = EncounterJournal.encounter.info.bossesScroll; + if ScrollFrameTemplate_OnMouseWheel then + ScrollFrameTemplate_OnMouseWheel(scrollFrame, delta); + end +end + +local function EncounterJournal_ConfigureBossButtonScroll(button) + if not button or button.__MoonWellBossScrollConfigured then + return; + end + + if button.EnableMouseWheel then + button:EnableMouseWheel(true); + end + button:SetScript("OnMouseWheel", EncounterJournal_BossList_OnMouseWheel); + button.__MoonWellBossScrollConfigured = true; +end + +local function EncounterJournal_UpdateBossListScrollRange(bossCount) + local scrollFrame = EncounterJournal.encounter.info.bossesScroll; + local scrollChild = scrollFrame.child; + local scrollBar = scrollFrame.ScrollBar or _G[scrollFrame:GetName() .. "ScrollBar"]; + local baseHeight = scrollFrame:GetHeight() or 382; + local contentHeight = baseHeight; + + if bossCount and bossCount > 0 then + contentHeight = math.max(baseHeight, + BOSS_BUTTON_FIRST_OFFSET + bossCount * BOSS_BUTTON_HEIGHT + + math.max(bossCount - 1, 0) * BOSS_BUTTON_SECOND_OFFSET + 8); + end + + scrollChild:SetHeight(contentHeight); + if scrollFrame.UpdateScrollChildRect then + scrollFrame:UpdateScrollChildRect(); + end + if scrollFrame.EnableMouseWheel then + scrollFrame:EnableMouseWheel(true); + end + if scrollFrame.SetScript then + scrollFrame:SetScript("OnMouseWheel", EncounterJournal_BossList_OnMouseWheel); + end + if ScrollFrame_OnScrollRangeChanged then + ScrollFrame_OnScrollRangeChanged(scrollFrame, 0, math.max(0, contentHeight - baseHeight)); + end + if scrollBar then + scrollBar:SetValue(math.min(scrollBar:GetValue(), math.max(0, contentHeight - baseHeight))); + end +end + +function EncounterJournal_ListInstances() + local instanceSelect = EncounterJournal.instanceSelect; + + local tierName = EJ_GetTierInfo(EJ_GetCurrentTier()); + UIDropDownMenu_SetText(instanceSelect.tierDropDown, tierName); + NavBar_Reset(EncounterJournal.navBar); + EncounterJournal.encounter:Hide(); + instanceSelect:Show(); + local showRaid = instanceSelect.raidsTab:IsEnabled() ~= 1; + + local scrollFrame = instanceSelect.scroll.child; + local index = 1; + local instanceID, name, description, _, buttonImage, _, _, _, link, _, mapID = EJ_GetInstanceByIndex(index, showRaid); + + --No instances in this tab + if not instanceID and not infiniteLoopPolice then + --disable this tab and select the other one. + infiniteLoopPolice = true; + if (showRaid) then + instanceSelect.raidsTab.grayBox:Show(); + EJ_ContentTab_Select(instanceSelect.dungeonsTab.id); + else + instanceSelect.dungeonsTab.grayBox:Show(); + EJ_ContentTab_Select(instanceSelect.raidsTab.id); + end + return; + end + infiniteLoopPolice = false; + + while instanceID do + local instanceButton = scrollFrame["instance" .. index]; + if not instanceButton then -- create button + instanceButton = CreateFrame("BUTTON", scrollFrame:GetParent():GetName() .. "instance" .. index, scrollFrame, + "EncounterInstanceButtonTemplate"); + if (EncounterJournal.localizeInstanceButton) then + EncounterJournal.localizeInstanceButton(instanceButton); + end + scrollFrame["instance" .. index] = instanceButton; + if mod(index - 1, EJ_NUM_INSTANCE_PER_ROW) == 0 then + instanceButton:SetPoint("TOP", scrollFrame["instance" .. (index - EJ_NUM_INSTANCE_PER_ROW)], "BOTTOM", 0, + -15); + else + instanceButton:SetPoint("LEFT", scrollFrame["instance" .. (index - 1)], "RIGHT", 15, 0); + end + end + + local isOpen, isActual, minItemLevel, maxItemLevel = C_EncounterJournal.GetInstanceInfoEx(instanceID) + local hasRequirements, requirements = C_EncounterJournal.GetInstanceRequirementsEx(instanceID) + + instanceButton.name:SetText(name); + instanceButton.bgImage:SetTexture(buttonImage); + instanceButton.instanceID = instanceID; + instanceButton.tooltipTitle = name; + instanceButton.tooltipText = description; + instanceButton.link = link; + instanceButton.mapID = mapID; + instanceButton:Show(); + + if minItemLevel ~= 0 and isOpen then + if minItemLevel == maxItemLevel then + instanceButton.DropInfo.ItemLevel:SetText(minItemLevel) + else + instanceButton.DropInfo.ItemLevel:SetFormattedText("%d - %d", minItemLevel, maxItemLevel) + end + + if isActual then + instanceButton.DropInfo.ItemLevel:SetTextColor(1, 0.82, 0) + else + instanceButton.DropInfo.ItemLevel:SetTextColor(0.5, 0.5, 0.5) + end + + local currencyItemID = C_EncounterJournal.GetInstanceCurrencyReward(instanceID) + if currencyItemID then + local currencyName, itemLink, quality, _, _, _, _, _, _, currencyIcon = C_Item.GetItemInfo( + currencyItemID, nil, nil, true) + SetItemButtonQuality(instanceButton.DropInfo.CurrencyItemButton, quality) + instanceButton.DropInfo.CurrencyItemButton.Icon:SetTexture(currencyIcon or + [[Interface\Icons\INV_Misc_QuestionMark]]) + instanceButton.DropInfo.CurrencyItemButton.itemLink = itemLink + instanceButton.DropInfo.CurrencyItemButton:Show() + else + instanceButton.DropInfo.CurrencyItemButton:Hide() + end + + instanceButton.DropInfo:Show() + else + instanceButton.DropInfo:Hide() + end + + if hasRequirements then + instanceButton.Requirements.requirements = requirements + instanceButton.Requirements.Icon:SetAtlas("PKBT-Icon-Notification") + else + instanceButton.Requirements.requirements = nil + instanceButton.Requirements.Icon:SetAtlas("PKBT-Icon-Notification-White") + end + instanceButton.Requirements.isRaid = showRaid + instanceButton.Requirements:SetShown(showRaid) + instanceButton.Unavailable:SetShown(not isOpen) + + index = index + 1; + instanceID, name, description, _, buttonImage, _, _, _, link, _, mapID = EJ_GetInstanceByIndex(index, showRaid); + end + + EJ_HideInstances(index); + EncounterJournal_UpdateInstanceListScrollRange(index - 1); + + --check if the other tab is empty + local instanceText = EJ_GetInstanceByIndex(1, not showRaid); + --No instances in the other tab + if not instanceText then + --disable the other tab. + if (showRaid) then + instanceSelect.dungeonsTab.grayBox:Show(); + else + instanceSelect.raidsTab.grayBox:Show(); + end + end +end + +function EncounterJournalInstanceButton_OnClick(self) + NavBar_Reset(EncounterJournal.navBar); + EncounterJournal_DisplayInstance(self.instanceID or EncounterJournal.instanceID); +end + +local function UpdateDifficultyAnchoring(difficultyFrame) + local infoFrame = difficultyFrame:GetParent(); + infoFrame.reset:ClearAllPoints(); + + if difficultyFrame:IsShown() then + infoFrame.reset:SetPoint("RIGHT", difficultyFrame, "LEFT", -10, 0); + else + infoFrame.reset:SetPoint("TOPRIGHT", infoFrame, "TOPRIGHT", -19, -13); + end +end + +local function UpdateDifficultyVisibility() + local shouldDisplayDifficulty = select(9, EJ_GetInstanceInfo()); + + -- As long as the current tab isn't the model tab, which always suppresses the difficulty, then update the shown state. + local info = EncounterJournal.encounter.info; + info.difficulty:SetShown(shouldDisplayDifficulty --[[ and (info.tab ~= 4)]]); + + UpdateDifficultyAnchoring(info.difficulty); +end + +function EncounterJournal_DisplayInstance(instanceID, noButton) + EncounterJournal_UpdateScrollPos(EncounterJournal.encounter.info.lootScroll, 1) + EJ_ResetLootFilter() + C_EncounterJournal.ResetSlotFilter() + EncounterJournal_UpdateFilterString() + EncounterJournal_RefreshSlotFilterText() + + EJ_HideNonInstancePanels(); + + local self = EncounterJournal.encounter; + EncounterJournal.instanceSelect:Hide(); + EncounterJournal.encounter:Show(); + EncounterJournal.creatureDisplayID = 0; + + EncounterJournal.instanceID = instanceID; + EncounterJournal.encounterID = nil; + + EJ_SelectInstance(instanceID); + EncounterJournal_LootUpdate(); + EncounterJournal_ClearDetails(); + + local instanceName, description, bgImage, _, loreImage, buttonImage, dungeonAreaMapID = EJ_GetInstanceInfo(); + self.instance.title:SetText(instanceName); + self.instance.titleBG:SetWidth(self.instance.title:GetStringWidth() + 80); + self.instance.loreBG:SetTexture(loreImage); + self.info.TitleFrame.instanceTitle:SetText(instanceName); + self.instance.mapButton:SetShown(dungeonAreaMapID and dungeonAreaMapID > 0); + + self.instance.loreScroll.ScrollBar:Hide(); + self.instance.loreScroll.child.lore:SetWidth(335); + self.instance.loreScroll.child.lore:SetText(description); + + local loreHeight = self.instance.loreScroll.child.lore:GetHeight(); + self.instance.loreScroll.ScrollBar:SetValue(0); + if loreHeight > EJ_LORE_MAX_HEIGHT then + self.instance.loreScroll.ScrollBar:Show(); + self.instance.loreScroll.child.lore:SetWidth(313); + end + + self.instance.FindGroupButton.Text:SetText(EJ_InstanceIsRaid() and ENCOUNTER_JOURNAL_FIND_RAID or + ENCOUNTER_JOURNAL_FIND_GROUP) + + self.info.instanceButton.instanceID = instanceID; + -- self.info.instanceButton.icon:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask"); + -- self.info.instanceButton.icon:SetTexture(buttonImage); + + buttonImage = buttonImage:lower():gsub("%.blp$", ""):gsub("(\\lfgframe)", "%1\\LFGIcon64") + local res = self.info.instanceButton.icon:SetTexture(buttonImage) + if res then + SetPortraitToTexture(self.info.instanceButton.icon, buttonImage) + else + SetPortraitToTexture(self.info.instanceButton.icon, "Interface\\EncounterJournal\\UI-EJ-Home-Icon") + end + + self.info.model.dungeonBG:SetTexture(bgImage); + + UpdateDifficultyVisibility(); + EncounterJournal_UpdateDifficulty(EJ_GetDifficulty(), true); + + local bossIndex = 1; + local name, description, bossID, rootSectionID, link = EJ_GetEncounterInfoByIndex(bossIndex); + local bossButton; + + local hasBossAbilities = false; + while bossID do + bossButton = _G["EncounterJournalBossButton" .. bossIndex]; + if not bossButton then -- create a new header; + bossButton = CreateFrame("BUTTON", "EncounterJournalBossButton" .. bossIndex, + EncounterJournal.encounter.bossesFrame, "EncounterBossButtonTemplate"); + if bossIndex > 1 then + bossButton:SetPoint("TOPLEFT", _G["EncounterJournalBossButton" .. (bossIndex - 1)], "BOTTOMLEFT", 0, + -BOSS_BUTTON_SECOND_OFFSET); + else + bossButton:SetPoint("TOPLEFT", EncounterJournal.encounter.bossesFrame, "TOPLEFT", 0, + -BOSS_BUTTON_FIRST_OFFSET); + end + end + EncounterJournal_ConfigureBossButtonScroll(bossButton); + + bossButton.link = link; + if IsGMAccount() then + local _, _, _, _, _, creatureID, encounterID = EJ_GetCreatureInfo(1, bossID) + bossButton:SetFormattedText("[%d][%d] %s", encounterID or 0, creatureID or 0, name) + else + bossButton:SetText(name); + end + bossButton:Show(); + bossButton.encounterID = bossID; + --Use the boss' first creature as the button icon + local _, _, _, _, bossImage = EJ_GetCreatureInfo(1, bossID); + bossImage = bossImage or "Interface\\EncounterJournal\\UI-EJ-BOSS-Default"; + bossButton.creature:SetTexture(bossImage); + bossButton:UnlockHighlight(); + + if (not hasBossAbilities) then + hasBossAbilities = rootSectionID > 0; + end + + bossIndex = bossIndex + 1; + name, description, bossID, rootSectionID, link = EJ_GetEncounterInfoByIndex(bossIndex); + end + EncounterJournal_UpdateBossListScrollRange(bossIndex - 1); + + EncounterJournal_SetTabEnabled(EncounterJournal.encounter.info.overviewTab, true); + --disable abilities tab, no boss selected + EncounterJournal_SetTabEnabled(EncounterJournal.encounter.info.bossTab, false); + + if (EncounterJournal_SearchForOverview(instanceID)) then + EJ_Tabs[1].frame = "overviewScroll"; + EJ_Tabs[3].frame = "detailsScroll"; -- flip them back + self.info[EJ_Tabs[1].button].tooltip = OVERVIEW; + self.info[EJ_Tabs[3].button]:Show(); + self.info.overviewFound = true; + else + EJ_Tabs[1].frame = "detailsScroll"; + EJ_Tabs[3].frame = "overviewScroll"; -- flip these so detailsScroll won't get hidden, overview will never be shown here + if (hasBossAbilities) then + self.info[EJ_Tabs[1].button].tooltip = ABILITIES; + else + self.info[EJ_Tabs[1].button].tooltip = OVERVIEW; + end + self.info[EJ_Tabs[3].button]:Hide(); + self.info.overviewFound = false; + end + + self.instance:Show(); + self.info.overviewScroll:Hide(); + self.info.detailsScroll:Hide(); + self.info.lootScroll:Hide(); + self.info.rightShadow:Hide(); + + if (self.info.tab and self.info.tab < 3) then + self.info[EJ_Tabs[self.info.tab].button]:Click() + else + self.info.overviewTab:Click(); + end + + if not noButton then + local buttonData = { + id = instanceID, + name = instanceName, + OnClick = EJNAV_RefreshInstance, + listFunc = EJNAV_ListInstance, + } + NavBar_AddButton(EncounterJournal.navBar, buttonData); + end +end + +function EncounterJournal_DisplayEncounter(encounterID, noButton, scrollToEncounter) + if encounterID == -1 then + return + end + + local self = EncounterJournal.encounter; + local ename, description, _, rootSectionID, link, instanceID = EJ_GetEncounterInfo(encounterID); + if not ename then + return; + end + + if instanceID and EncounterJournal.instanceID ~= instanceID then + EncounterJournal_DisplayInstance(instanceID, true); + end + + if EncounterJournal.encounterID == encounterID or EncounterJournal.instanceID == instanceID then + EncounterJournal_SetTab(EncounterJournal.encounter.info.tab) + else + EncounterJournal_ValidateSelectedTab() + end + + if rootSectionID == 0 then + -- EncounterJournal_SetTab(EncounterJournal.encounter.info.lootTab:GetID()) + end + + if (EncounterJournal.encounterID == encounterID) then + --navbar is already set to the right button, don't add another + noButton = true; + elseif (EncounterJournal.encounterID) then + --make sure the previous navbar button is the instance button + NavBar_OpenTo(EncounterJournal.navBar, EncounterJournal.instanceID); + end + + EncounterJournal.encounterID = encounterID; + EJ_SelectEncounter(encounterID); + EncounterJournal_LootUpdate(); + --need to clear details, but don't want to scroll to top of bosses list + local bossListScrollValue = self.info.bossesScroll.ScrollBar:GetValue() + EncounterJournal_ClearDetails(); + EncounterJournal.encounter.info.bossesScroll.ScrollBar:SetValue(bossListScrollValue); + + self.info.TitleFrame.encounterTitle:SetText(ename); + + EncounterJournal_SetTabEnabled(EncounterJournal.encounter.info.overviewTab, (rootSectionID > 0)); + + local overviewFound; + if (EncounterJournal_CheckForOverview(rootSectionID)) then + local _, overviewDescription = EJ_GetSectionInfo(rootSectionID) + self.overviewFrame.loreDescription:SetHeight(0); + self.overviewFrame.loreDescription:SetWidth(self.overviewFrame:GetWidth() - 5); + self.overviewFrame.loreDescription:SetText(description); + self.overviewFrame.overviewDescription:SetWidth(self.overviewFrame:GetWidth() - 5); + self.overviewFrame.overviewDescription.Text:SetWidth(self.overviewFrame:GetWidth() - 5); + EncounterJournal_SetBullets(self.overviewFrame.overviewDescription, overviewDescription, false); + local bulletHeight = 0; + if (self.overviewFrame.Bullets and #self.overviewFrame.Bullets > 0) then + for i = 1, #self.overviewFrame.Bullets do + bulletHeight = bulletHeight + self.overviewFrame.Bullets[i]:GetHeight(); + end + local bullet = self.overviewFrame.Bullets[1]; + bullet:ClearAllPoints(); + bullet:SetPoint("TOPLEFT", self.overviewFrame.overviewDescription, "BOTTOMLEFT", 0, -9); + end + self.overviewFrame.descriptionHeight = self.overviewFrame.loreDescription:GetHeight() + + self.overviewFrame.overviewDescription:GetHeight() + bulletHeight + 42; + self.overviewFrame.rootOverviewSectionID = rootSectionID; + rootSectionID = EncounterJournal_GetRootAfterOverviews(rootSectionID); + overviewFound = true; + end + + self.infoFrame.description:SetWidth(self.infoFrame:GetWidth() - 5); + self.infoFrame.description:SetText(description); + self.infoFrame.descriptionHeight = self.infoFrame.description:GetHeight(); + + self.infoFrame.encounterID = encounterID; + self.infoFrame.rootSectionID = rootSectionID; + self.infoFrame.expanded = false; + + local selectedEncounterIndex; + + local bossIndex = 1; + local name, description, bossID, _, link = EJ_GetEncounterInfoByIndex(bossIndex); + local bossButton; + while bossID do + bossButton = _G["EncounterJournalBossButton" .. bossIndex]; + if not bossButton then -- create a new header; + bossButton = CreateFrame("BUTTON", "EncounterJournalBossButton" .. bossIndex, + EncounterJournal.encounter.bossesFrame, "EncounterBossButtonTemplate"); + if bossIndex > 1 then + bossButton:SetPoint("TOPLEFT", _G["EncounterJournalBossButton" .. (bossIndex - 1)], "BOTTOMLEFT", 0, + -BOSS_BUTTON_SECOND_OFFSET); + else + bossButton:SetPoint("TOPLEFT", EncounterJournal.encounter.bossesFrame, "TOPLEFT", 0, + -BOSS_BUTTON_FIRST_OFFSET); + end + end + EncounterJournal_ConfigureBossButtonScroll(bossButton); + + bossButton.link = link; + if IsGMAccount() then + local _, _, _, _, _, creatureID, encounterID = EJ_GetCreatureInfo(1, bossID) + bossButton:SetFormattedText("[%d][%d] %s", encounterID or 0, creatureID or 0, name) + else + bossButton:SetText(name); + end + bossButton:Show(); + bossButton.encounterID = bossID; + --Use the boss' first creature as the button icon + local _, _, _, _, bossImage = EJ_GetCreatureInfo(1, bossID); + bossImage = bossImage or "Interface\\EncounterJournal\\UI-EJ-BOSS-Default"; + bossButton.creature:SetTexture(bossImage); + + if (encounterID == bossID) then + bossButton:LockHighlight(); + selectedEncounterIndex = bossIndex; + else + bossButton:UnlockHighlight(); + end + + bossIndex = bossIndex + 1; + name, description, bossID, _, link = EJ_GetEncounterInfoByIndex(bossIndex); + end + EncounterJournal_UpdateBossListScrollRange(bossIndex - 1); + + if selectedEncounterIndex and scrollToEncounter then + bossIndex = bossIndex - 1; + + local value, maxScrollRange = ScrollFrame_GetScrollValueForIndex(EncounterJournal.encounter.info.bossesScroll, + selectedEncounterIndex, bossIndex, BOSS_BUTTON_HEIGHT, BOSS_BUTTON_SECOND_OFFSET) + ScrollFrame_OnScrollRangeChanged(EncounterJournal.encounter.info.bossesScroll, 0, maxScrollRange); + EncounterJournal.encounter.info.bossesScroll.ScrollBar:SetValue(value); + end + + -- Setup Creatures + local id, name, description, displayInfo, iconImage, creatureID; + local hasCreatureModel = false; + for i = 1, MAX_CREATURES_PER_ENCOUNTER do + id, name, description, displayInfo, iconImage, creatureID = EJ_GetCreatureInfo(i); + if id then + local button = EncounterJournal_GetCreatureButton(i); + -- SetPortraitTexture(button.creature, displayInfo); + button.creature:SetPortrait(displayInfo) + button.name = name; + button.id = id; + button.description = description; + button.displayInfo = displayInfo; + button.iconImage = iconImage; + button.creatureID = creatureID; + if creatureID and creatureID > 0 then + hasCreatureModel = true; + end + end + end + + --enable abilities tab + EncounterJournal_SetTabEnabled(EncounterJournal.encounter.info.bossTab, true); + EncounterJournal_SetTabEnabled(EncounterJournal.encounter.info.modelTab, hasCreatureModel); + + if (overviewFound) then + EncounterJournal_ToggleHeaders(self.overviewFrame); + self.overviewFrame:Show(); + else + self.overviewFrame:Hide(); + end + + EncounterJournal_ToggleHeaders(self.infoFrame); + + self:Show(); + + --make sure we stay on the tab we were on + self.info[EJ_Tabs[self.info.tab].button]:Click() + + if not noButton then + local buttonData = { + id = encounterID, + name = ename, + OnClick = EJNAV_RefreshEncounter, + listFunc = EJNAV_ListEncounter, + } + NavBar_AddButton(EncounterJournal.navBar, buttonData); + end +end + +function EncounterJournal_DisplayCreature(self) + if EncounterJournal.encounter.info.shownCreatureButton then + EncounterJournal.encounter.info.shownCreatureButton:Enable(); + end + + local model = EncounterJournal.encounter.info.model; + local displayInfo = self.displayInfo; + if model.ClearModel then + model:ClearModel(); + end + EncounterJournal.creatureDisplayID = displayInfo; + model.displayInfo = displayInfo; + local useStaticPortrait = EJ_BROKEN_BAKED_MODEL[displayInfo]; + if model.fallbackPortrait then + if useStaticPortrait then + model.fallbackPortrait:SetTexture(self.iconImage or + (MoonWellEncounterPortraitByDisplayInfo and MoonWellEncounterPortraitByDisplayInfo[displayInfo]) or + QUESTION_MARK_ICON); + model.fallbackPortrait:Show(); + else + model.fallbackPortrait:Hide(); + end + end + + -- WarcraftXL accepts displayInfo as an optional second argument and can + -- therefore render entries which are not present in the creature cache. + -- Stock 3.3.5 safely ignores the extra argument and keeps its old fallback. + if not useStaticPortrait and self.creatureID and self.creatureID > 0 and model.SetCreature then + model:SetCreature(self.creatureID, displayInfo); + EncounterJournal_Model_ApplyCamera(model); + end + + model.imageTitle:SetText(self.name) + + self:Disable(); + EncounterJournal.encounter.info.shownCreatureButton = self; +end + +function EncounterJournal_ShowCreatures() + for index, creatureButton in ipairs(EncounterJournal.encounter.info.creatureButtons) do + if (creatureButton.displayInfo) then + creatureButton:Show(); + if index == 1 then + EncounterJournal_DisplayCreature(creatureButton); + end + end + end +end + +function EncounterJournal_Model_OnLoad(self) + self.rotation = 0; + self:SetRotation(self.rotation); + self:EnableMouse(true); + self:EnableMouseWheel(true); +end + +function EncounterJournal_Model_ApplyCamera(self) + if not self or not self.displayInfo or EJ_BROKEN_BAKED_MODEL[self.displayInfo] then + return; + end + + local camera = EJ_MODEL_CAMERA[self.displayInfo]; + local scale = EJ_MODEL_USER_SCALE[self.displayInfo] or (camera and camera.scale) or 1; + if self.SetModelScale then + self:SetModelScale(scale); + end + if self.SetPosition then + self:SetPosition(camera and camera.x or 0, camera and camera.y or 0, camera and camera.z or 0); + end +end + +function EncounterJournal_Model_OnMouseWheel(self, delta) + if not self.displayInfo or EJ_BROKEN_BAKED_MODEL[self.displayInfo] then + return; + end + + local camera = EJ_MODEL_CAMERA[self.displayInfo]; + local scale = EJ_MODEL_USER_SCALE[self.displayInfo] or (camera and camera.scale) or 1; + if delta > 0 then + scale = scale * 1.12; + else + scale = scale / 1.12; + end + scale = math.max(0.15, math.min(4, scale)); + EJ_MODEL_USER_SCALE[self.displayInfo] = scale; + EncounterJournal_Model_ApplyCamera(self); +end + +function EncounterJournal_Model_OnUpdateModel(self) + EncounterJournal_Model_ApplyCamera(self); +end + +function EncounterJournal_Model_OnMouseDown(self, button) + if button == "LeftButton" then + self.dragCursorX = GetCursorPosition(); + elseif button == "RightButton" and self.displayInfo then + EJ_MODEL_USER_SCALE[self.displayInfo] = nil; + EncounterJournal_Model_ApplyCamera(self); + end +end + +function EncounterJournal_Model_OnMouseUp(self) + self.dragCursorX = nil; +end + +function EncounterJournal_Model_OnUpdate(self) + if not self.dragCursorX then + return; + end + + local cursorX = GetCursorPosition(); + local delta = cursorX - self.dragCursorX; + self.dragCursorX = cursorX; + self.rotation = (self.rotation or 0) + delta * 0.01; + self:SetRotation(self.rotation); +end + +function EncounterJournal_HideCreatures(clearDisplayInfo) + for index, creatureButton in ipairs(EncounterJournal.encounter.info.creatureButtons) do + creatureButton:Hide(); + + if clearDisplayInfo then + creatureButton.displayInfo = nil; + creatureButton.creatureID = nil; + end + end +end + +local toggleTempList = {}; +local headerCount = 0; +local loopedSections = {}; + +local function EncounterJournal_GetHeaderWidth(sourceFrame) + local width = sourceFrame and sourceFrame:GetWidth() or 0; + if width and width > 20 then + return width; + end + + local info = EncounterJournal and EncounterJournal.encounter and EncounterJournal.encounter.info; + local scrollFrame = info and ((info.detailsScroll and info.detailsScroll:IsShown() and info.detailsScroll) or + (info.overviewScroll and info.overviewScroll:IsShown() and info.overviewScroll) or info.detailsScroll or info.overviewScroll); + local child = scrollFrame and (scrollFrame.child or scrollFrame.ScrollChild); + + width = child and child:GetWidth() or 0; + if width and width > 20 then + return width; + end + + width = scrollFrame and scrollFrame:GetWidth() or 0; + if width and width > 20 then + return math.max(1, width - 30); + end + + return 320; +end + +function EncounterJournal_UpdateButtonState(self) + local oldtex = self.textures.expanded; + if self:GetParent().expanded then + self.tex = self.textures.expanded; + oldtex = self.textures.collapsed; + self.expandedIcon:SetTextColor(0.929, 0.788, 0.620); + self.title:SetTextColor(0.929, 0.788, 0.620); + else + self.tex = self.textures.collapsed; + self.expandedIcon:SetTextColor(0.827, 0.659, 0.463); + self.title:SetTextColor(0.827, 0.659, 0.463); + end + + oldtex.up[1]:Hide(); + oldtex.up[2]:Hide(); + oldtex.up[3]:Hide(); + oldtex.down[1]:Hide(); + oldtex.down[2]:Hide(); + oldtex.down[3]:Hide(); + + + self.tex.up[1]:Show(); + self.tex.up[2]:Show(); + self.tex.up[3]:Show(); + self.tex.down[1]:Hide(); + self.tex.down[2]:Hide(); + self.tex.down[3]:Hide(); +end + +local function EncounterJournal_NormalizeHeaderButton(infoHeader, width) + if not infoHeader or not infoHeader.button then + return; + end + + width = width or EncounterJournal_GetHeaderWidth(infoHeader); + infoHeader:SetWidth(width); + infoHeader.button:SetWidth(width); + + if infoHeader.button:GetButtonState() ~= "NORMAL" then + infoHeader.button:SetButtonState("NORMAL"); + end + + EncounterJournal_UpdateButtonState(infoHeader.button); +end + +function EncounterJournal_OnClick(self) + if IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow() then + if self.link then + ChatEdit_InsertLink(self.link); + end + return; + end + + EncounterJournal_ToggleHeaders(self:GetParent()) + self:GetScript("OnShow")(self); + PlaySound("igMainMenuOptionCheckBoxOn"); +end + +function EncounterJournal_OnHyperlinkEnter(self, link, text) + local linkType = string.split(":", link, 2) + + if linkType == "kbase" then + GameTooltip:SetOwner(self, "ANCHOR_CURSOR_RIGHT") + GameTooltip:AddLine(KNOWLEDGE_BASE, 1, 1, 1) + GameTooltip:Show() + else + GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); + GameTooltip:SetHyperlink(link); + end +end + +function EncounterJournal_CleanBullets(self, start, keep) + if (not self.Bullets) then return end + start = start or 1; + for i = start, #self.Bullets do + self.Bullets[i]:Hide(); + if (not keep) then + if (not self.BulletCache) then + self.BulletCache = {}; + end + self.Bullets[i]:ClearAllPoints(); + tinsert(self.BulletCache, self.Bullets[i]); + self.Bullets[i] = nil; + end + end +end + +local function EncounterJournal_UpdateSimpleHTMLHeight(frame) + if not frame then + return 0; + end + + local height = 0; + if frame.GetContentHeight then + height = frame:GetContentHeight() or 0; + end + if height <= 0 and frame.GetStringHeight then + height = frame:GetStringHeight() or 0; + end + if height <= 0 and frame.GetRegions then + local region = frame:GetRegions(); + if region and region.GetStringHeight then + height = region:GetStringHeight() or 0; + elseif region and region.GetHeight then + height = region:GetHeight() or 0; + end + end + + height = math.max(math.ceil(height), 10); + frame:SetHeight(height); + return height; +end + +local function EncounterJournal_SetHeaderDescription(header, description) + if not header or not header.description then + return; + end + + header.description:SetWidth(math.max((header:GetWidth() or 0) - 20, 1)); + header.description:SetText(description or ""); + EncounterJournal_UpdateSimpleHTMLHeight(header.description); +end + +local function EncounterJournal_UpdateDetailsScrollRange() + local encounter = EncounterJournal and EncounterJournal.encounter; + local info = encounter and encounter.info; + local scrollFrame = info and info.detailsScroll; + local child = scrollFrame and (scrollFrame.child or scrollFrame.ScrollChild); + if not scrollFrame or not child then + return; + end + + local contentHeight = math.max(scrollFrame:GetHeight() or 0, child.descriptionHeight or 0); + local usedHeaders = encounter.usedHeaders or {}; + for i = 1, #usedHeaders do + local header = usedHeaders[i]; + if header and header:IsShown() then + local _, _, _, _, anchorY = header:GetPoint(); + local bottom = math.abs(anchorY or 0) + (header:GetHeight() or 0); + if header.description and header.description:IsShown() then + bottom = bottom + EncounterJournal_UpdateSimpleHTMLHeight(header.description) + + SECTION_DESCRIPTION_OFFSET; + else + bottom = bottom + SECTION_BUTTON_OFFSET; + end + contentHeight = math.max(contentHeight, bottom + 16); + end + end + + child:SetHeight(contentHeight); + if scrollFrame.UpdateScrollChildRect then + scrollFrame:UpdateScrollChildRect(); + end + if ScrollFrame_OnScrollRangeChanged then + ScrollFrame_OnScrollRangeChanged(scrollFrame, 0, math.max(0, contentHeight - (scrollFrame:GetHeight() or 0))); + end +end + +function EncounterJournal_InfoScrollFrame_OnMouseWheel(self, delta) + local info = EncounterJournal and EncounterJournal.encounter and EncounterJournal.encounter.info; + local scrollFrame = info and info.detailsScroll; + if scrollFrame and scrollFrame:IsShown() then + ScrollFrameTemplate_OnMouseWheel(scrollFrame, delta); + end +end + +function EncounterJournal_SetBullets(object, description, hideBullets) + local parent = object:GetParent(); + local parentWidth = 60 + local characterHeight = 16 + + if (not string.find(description, "%$bullet;")) then + object.Text:SetText(description); + object.textString = description; + local height = (strlenutf8(description) / parentWidth) * characterHeight + object:SetHeight(height) + -- object:SetHeight(object.Text:GetContentHeight()); + EncounterJournal_CleanBullets(parent); + return; + end + + local desc = string.match(description, "(.-)%$bullet;"); + + if (desc) then + object.Text:SetText(desc); + object.textString = desc; + local height = (strlenutf8(desc) / parentWidth) * characterHeight + object:SetHeight(height) + -- object:SetHeight(object.Text:GetContentHeight()); + end + + local bullets = {} + for v in string.gmatch(description, "%$bullet;([^$]+)") do + tinsert(bullets, v); + end + + local k = 1; + local skipped = 0; + for j = 1, #bullets do + local text = bullets[j]; + if (text and text ~= "") then + local bullet; + bullet = parent.Bullets and parent.Bullets[k]; + if (not bullet) then + if (parent.BulletCache and #parent.BulletCache > 0) then + -- We only need to check for BulletCache because the BulletCache is created when we clean the bullets, so the BulletCache existing also means the Bullets exist. + parent.Bullets[k] = tremove(parent.BulletCache); + bullet = parent.Bullets[k]; + else + bullet = CreateFrame("Frame", nil, parent, "EncounterOverviewBulletTemplate"); + end + bullet:SetWidth(307) + bullet.Text:SetWidth(300 - 26) + -- bullet:SetWidth(parent:GetWidth() - 13); + -- bullet.Text:SetWidth(parentWidth - 26); + end + bullet:ClearAllPoints(); + if (k == 1) then + if (parent.button) then + bullet:SetPoint("TOPLEFT", parent.button, "BOTTOMLEFT", 13, -9 - object:GetHeight()); + else + bullet:SetPoint("TOPLEFT", parent, "TOPLEFT", 13, -9 - object:GetHeight()); + end + else + bullet:SetPoint("TOP", parent.Bullets[k - 1], "BOTTOM", 0, -8); + end + bullet.Text:SetText(text); + + local height = (strlenutf8(text) / parentWidth) * characterHeight + if (height ~= 0) then + bullet:SetHeight(height); + end + --[[ + if (bullet.Text:GetContentHeight() ~= 0) then + bullet:SetHeight(bullet.Text:GetContentHeight()); + end +--]] + if (hideBullets) then + bullet:Hide(); + else + bullet:Show(); + end + k = k + 1; + else + skipped = skipped + 1; + end + end + + EncounterJournal_CleanBullets(parent, (#bullets - skipped) + 1); +end + +function EncounterJournal_SetDescriptionWithBullets(infoHeader, description) + EncounterJournal_SetBullets(infoHeader.overviewDescription, description, true); + + infoHeader.descriptionBG:ClearAllPoints(); + infoHeader.descriptionBG:SetPoint("TOPLEFT", infoHeader.button, "BOTTOMLEFT", 1, 0); + if (infoHeader.Bullets and #infoHeader.Bullets > 0) then + infoHeader.descriptionBG:SetPoint("BOTTOMRIGHT", infoHeader.Bullets[#infoHeader.Bullets], -1, -11); + else + infoHeader.descriptionBG:SetPoint("BOTTOMRIGHT", infoHeader.overviewDescription, 9, -11); + end + infoHeader.descriptionBG:Hide(); + infoHeader.descriptionBGBottom:Hide(); +end + +function EncounterJournal_SetUpOverview(self, role, index) + local infoHeader; + if not self.overviews[index] then -- create a new header; + infoHeader = CreateFrame("FRAME", "EncounterJournalOverviewInfoHeader" .. index, + EncounterJournal.encounter.overviewFrame, "EncounterInfoTemplate"); + infoHeader.description:Hide(); + infoHeader.overviewDescription:Hide(); + infoHeader.descriptionBG:Hide(); + infoHeader.descriptionBGBottom:Hide(); + infoHeader.button.abilityIcon:Hide(); + infoHeader.button.portrait:Hide(); + infoHeader.button.portrait.name = nil; + infoHeader.button.portrait.displayInfo = nil; + infoHeader.button.icon2:Hide(); + infoHeader.button.icon3:Hide(); + infoHeader.button.icon4:Hide(); + infoHeader.overviewIndex = index; + infoHeader.isOverview = true; + + local textLeftAnchor = infoHeader.button.expandedIcon; + local textRightAnchor = infoHeader.button.icon1; + infoHeader.button.title:SetPoint("LEFT", textLeftAnchor, "RIGHT", 5, 0); + infoHeader.button.title:SetPoint("RIGHT", textRightAnchor, "LEFT", -5, 0); + + self.overviews[index] = infoHeader; + else + infoHeader = self.overviews[index]; + end + + infoHeader.button.expandedIcon:SetText("+"); + infoHeader.expanded = false; + + infoHeader:ClearAllPoints(); + if (index == 1) then + infoHeader:SetPoint("TOPLEFT", 0, -15 - self.descriptionHeight - SECTION_BUTTON_OFFSET); + infoHeader:SetPoint("TOPRIGHT", 0, -15 - self.descriptionHeight - SECTION_BUTTON_OFFSET); + else + infoHeader:SetPoint("TOPLEFT", self.overviews[index - 1], "BOTTOMLEFT", 0, -9); + infoHeader:SetPoint("TOPRIGHT", self.overviews[index - 1], "BOTTOMRIGHT", 0, -9); + end + + infoHeader.description:Hide(); + + for i = 1, #infoHeader.Bullets do + infoHeader.Bullets[i]:Hide(); + end + + wipe(infoHeader.Bullets); + local title, description, siblingID, link, filteredByDifficulty, flag1 + + local _, _, _, _, _, _, nextSectionID = EJ_GetSectionInfo(self.rootOverviewSectionID) + + while nextSectionID do + title, description, _, _, _, siblingID, _, filteredByDifficulty, link, _, _, flag1 = EJ_GetSectionInfo( + nextSectionID) + if (role == rolesByFlag[flag1] and not filteredByDifficulty) then + break + end + nextSectionID = siblingID + end + + if (not title) then + infoHeader:Hide(); + return; + end + + infoHeader.button.icon1:Show() + EncounterJournal_SetFlagIcon(infoHeader.button.icon1.icon, flag1) + + infoHeader.button.title:SetText(title) + infoHeader.button.link = link; + infoHeader.sectionID = nextSectionID; + + EncounterJournal_NormalizeHeaderButton(infoHeader, EncounterJournal_GetHeaderWidth(self)); + infoHeader.overviewDescription:SetWidth(infoHeader:GetWidth() - 20); + EncounterJournal_SetDescriptionWithBullets(infoHeader, description); + infoHeader:Show(); +end + +function EncounterJournal_ToggleHeaders(self, doNotShift) + local numAdded = 0; + local infoHeader, parentID, _; + local hWidth = EncounterJournal_GetHeaderWidth(self); + local nextSectionID; + local topLevelSection = false; + + local isOverview = self.isOverview; + + local hideHeaders; + if (not self.isOverview or (self.isOverview and self.overviewIndex)) then + self.expanded = not self.expanded; + hideHeaders = not self.expanded; + end + + if hideHeaders then + self.button.expandedIcon:SetText("+"); + self.description:Hide(); + if (self.overviewDescription) then + self.overviewDescription:Hide(); + end + self.descriptionBG:Hide(); + self.descriptionBGBottom:Hide(); + + EncounterJournal_CleanBullets(self, nil, true); + + if (self.overviewIndex) then + local overview = EncounterJournal.encounter.overviewFrame.overviews[self.overviewIndex + 1]; + + if (overview) then + overview:SetPoint("TOPLEFT", self, "BOTTOMLEFT", 0, -9); + end + else + EncounterJournal_ClearChildHeaders(self); + end + else + if (not isOverview) then + if strlen(self.description:GetText() or "") > 2 then + EncounterJournal_UpdateSimpleHTMLHeight(self.description); + self.description:Show(); + if (self.overviewDescription) then + self.overviewDescription:Hide(); + end + if self.button then + self.descriptionBG:Show(); + self.descriptionBGBottom:Show(); + self.button.expandedIcon:SetText("-"); + end + elseif self.button then + self.description:Hide(); + if (self.overviewDescription) then + self.overviewDescription:Hide(); + end + self.descriptionBG:Hide(); + self.descriptionBGBottom:Hide(); + self.button.expandedIcon:SetText("-"); + end + else + if (self.overviewIndex) then + self.button.expandedIcon:SetText("-"); + for i = 1, #self.Bullets do + self.Bullets[i]:Show(); + end + self.description:Hide(); + self.overviewDescription:Show(); + self.descriptionBG:Show(); + self.descriptionBGBottom:Show(); + + local overview = EncounterJournal.encounter.overviewFrame.overviews[self.overviewIndex + 1]; + + if (overview) then + if (self.Bullets and #self.Bullets > 0) then + overview:SetPoint("TOPLEFT", self.Bullets[#self.Bullets], "BOTTOMLEFT", -13, -18); + else + local yoffset = -18 - self:GetHeight(); + overview:SetPoint("TOPLEFT", self, "BOTTOMLEFT", 0, yoffset); + end + end + EncounterJournal_UpdateButtonState(self.button); + end + end + + -- Get Section Info + if (not isOverview) then + local freeHeaders = EncounterJournal.encounter.freeHeaders; + local usedHeaders = EncounterJournal.encounter.usedHeaders; + + local listEnd = #usedHeaders; + + if self.myID then -- this is from a button click + _, _, _, _, _, _, nextSectionID = EJ_GetSectionInfo(self.myID); + parentID = self.myID; + self.description:SetWidth(self:GetWidth() - 20); + EncounterJournal_UpdateSimpleHTMLHeight(self.description); + hWidth = hWidth - HEADER_INDENT; + else + --This sets the base encounter header + parentID = self.encounterID; + nextSectionID = self.rootSectionID; + topLevelSection = true; + end + + local pass + while nextSectionID do + local title, description, headerType, abilityIcon, displayInfo, siblingID, nextNextSectionID, fileredByDifficulty, link, startsOpen, creatureEntry, flag1, flag2, flag3, flag4 = + EJ_GetSectionInfo(nextSectionID) + + if nextNextSectionID and nextNextSectionID ~= 0 then + local _, childSectionID = EJ_GetSectionPath(nextSectionID) + if childSectionID == nextNextSectionID then + loopedSections[#loopedSections + 1] = nextSectionID + pass = true + end + end + + if pass then + pass = nil + elseif not title then + break + elseif not fileredByDifficulty then + if #freeHeaders == 0 then -- create a new header; + headerCount = headerCount + 1; -- the is a file local + infoHeader = CreateFrame("FRAME", "EncounterJournalInfoHeader" .. headerCount, + EncounterJournal.encounter.infoFrame, "EncounterInfoTemplate"); + infoHeader:Hide(); + else + infoHeader = freeHeaders[#freeHeaders]; + freeHeaders[#freeHeaders] = nil; + end + + numAdded = numAdded + 1; + toggleTempList[#toggleTempList + 1] = infoHeader; + + infoHeader.button.link = link; + infoHeader.parentID = parentID; + infoHeader.myID = nextSectionID; + + -- Spell names can show up in white, which clashes with the parchment, strip out white color codes. + description = (description or ""):gsub("|cffffffff(.-)|r", "%1"); + + infoHeader.button.title:SetText(title) + if topLevelSection then + infoHeader.button.title:SetFontObject("GameFontNormalMed3"); + else + infoHeader.button.title:SetFontObject("GameFontNormal"); + end + + --All headers start collapsed + infoHeader.expanded = false + infoHeader.description:Hide(); + infoHeader.descriptionBG:Hide(); + infoHeader.descriptionBGBottom:Hide(); + infoHeader.button.expandedIcon:SetText("+"); + + for i = 1, #infoHeader.Bullets do + infoHeader.Bullets[i]:Hide(); + end + + local textLeftAnchor = infoHeader.button.expandedIcon; + --Show ability Icon + if abilityIcon then + infoHeader.button.abilityIcon:SetTexture(abilityIcon); + infoHeader.button.abilityIcon:Show(); + textLeftAnchor = infoHeader.button.abilityIcon; + else + infoHeader.button.abilityIcon:Hide(); + end + + --Show Creature Portrait + if displayInfo ~= 0 then + -- SetPortraitTexture(infoHeader.button.portrait.icon, displayInfo) + infoHeader.button.portrait.icon:SetPortrait(displayInfo) + infoHeader.button.portrait.name = title; + infoHeader.button.portrait.displayInfo = creatureEntry; + infoHeader.button.portrait:Show(); + textLeftAnchor = infoHeader.button.portrait; + infoHeader.button.abilityIcon:Hide(); + else + infoHeader.button.portrait:Hide(); + infoHeader.button.portrait.name = nil; + infoHeader.button.portrait.displayInfo = nil; + end + infoHeader.button.title:SetPoint("LEFT", textLeftAnchor, "RIGHT", 5, 0); + + local textRightAnchor = nil + infoHeader.button.icon1:Hide() + infoHeader.button.icon2:Hide() + infoHeader.button.icon3:Hide() + infoHeader.button.icon4:Hide() + if flag1 then + textRightAnchor = infoHeader.button.icon1 + infoHeader.button.icon1:Show() + infoHeader.button.icon1.tooltipTitle = _G["ENCOUNTER_JOURNAL_SECTION_FLAG" .. flag1] + infoHeader.button.icon1.tooltipText = _G["ENCOUNTER_JOURNAL_SECTION_FLAG_DESCRIPTION" .. flag1] + EncounterJournal_SetFlagIcon(infoHeader.button.icon1.icon, flag1) + if flag2 then + textRightAnchor = infoHeader.button.icon2 + infoHeader.button.icon2:Show() + EncounterJournal_SetFlagIcon(infoHeader.button.icon2.icon, flag2) + infoHeader.button.icon2.tooltipTitle = _G["ENCOUNTER_JOURNAL_SECTION_FLAG" .. flag2] + infoHeader.button.icon2.tooltipText = _G + ["ENCOUNTER_JOURNAL_SECTION_FLAG_DESCRIPTION" .. flag2] + if flag3 then + textRightAnchor = infoHeader.button.icon3 + infoHeader.button.icon3:Show() + EncounterJournal_SetFlagIcon(infoHeader.button.icon3.icon, flag3) + infoHeader.button.icon3.tooltipTitle = _G["ENCOUNTER_JOURNAL_SECTION_FLAG" .. flag3] + infoHeader.button.icon3.tooltipText = _G + ["ENCOUNTER_JOURNAL_SECTION_FLAG_DESCRIPTION" .. flag3] + if flag4 then + textRightAnchor = infoHeader.button.icon4 + infoHeader.button.icon4:Show() + EncounterJournal_SetFlagIcon(infoHeader.button.icon4.icon, flag4) + infoHeader.button.icon4.tooltipTitle = _G["ENCOUNTER_JOURNAL_SECTION_FLAG" .. flag4] + infoHeader.button.icon4.tooltipText = _G + ["ENCOUNTER_JOURNAL_SECTION_FLAG_DESCRIPTION" .. flag4] + end + end + end + end + if textRightAnchor then + infoHeader.button.title:SetPoint("RIGHT", textRightAnchor, "LEFT", -5, 0) + else + infoHeader.button.title:SetPoint("RIGHT", infoHeader.button, "RIGHT", -5, 0) + end + + infoHeader.index = nil; + EncounterJournal_NormalizeHeaderButton(infoHeader, hWidth); + EncounterJournal_SetHeaderDescription(infoHeader, description); + + -- If this section has not be seen and should start open + if EJ_section_openTable[infoHeader.myID] == nil and startsOpen then + EJ_section_openTable[infoHeader.myID] = true; + end + + --toggleNested? + if EJ_section_openTable[infoHeader.myID] then + infoHeader.expanded = false; -- setting false to expand it in EncounterJournal_ToggleHeaders + numAdded = numAdded + EncounterJournal_ToggleHeaders(infoHeader, true); + end + + EncounterJournal_NormalizeHeaderButton(infoHeader, hWidth); + infoHeader:Show(); + end -- if not filteredByDifficulty + + nextSectionID = siblingID; + end + + if not doNotShift and numAdded > 0 then + --fix the usedlist + local startIndex = self.index or 0; + for i = listEnd, startIndex + 1, -1 do + usedHeaders[i + numAdded] = usedHeaders[i]; + usedHeaders[i + numAdded].index = i + numAdded; + usedHeaders[i] = nil + end + for i = 1, numAdded do + usedHeaders[startIndex + i] = toggleTempList[i]; + usedHeaders[startIndex + i].index = startIndex + i; + toggleTempList[i] = nil; + end + end + + if topLevelSection and usedHeaders[1] then + usedHeaders[1]:SetPoint("TOPRIGHT", 0, + -8 - EncounterJournal.encounter.infoFrame.descriptionHeight - SECTION_BUTTON_OFFSET); + end + + if not doNotShift and #loopedSections ~= 0 then + StaticPopup_Show("ENCOUNTER_JOURNAL_SECTION_LOOP_ERROR_DIALOG", table.concat(loopedSections, ", ")) + table.wipe(loopedSections) + end + elseif (not self.overviewIndex) then + for i = 1, #self.overviews do + self.overviews[i]:Hide(); + end + + EncounterJournal.overviewDefaultRole = nil; + + if (not self.rootOverviewSectionID) then + return; + end + + local spec, role; + --[[ + spec = GetSpecialization(); + if (spec) then + role = GetSpecializationRole(spec); + else + role = "DAMAGER"; + end +--]] + + role = "DAMAGER" + + EncounterJournal_SetUpOverview(self, role, 1) + + local k = 2 + for i = 1, 3 do + local otherRole = overviewPriorities[i] + if (otherRole ~= role) then + EncounterJournal_SetUpOverview(self, otherRole, k) + k = k + 1 + end + end + + if (self.linkSection) then + for i = 1, 3 do + local overview = self.overviews[i]; + if (overview.sectionID == self.linkSection) then + overview.expanded = false; + EncounterJournal_ToggleHeaders(overview); + overview.cbCount = 0; + overview.button.glow.flashAnim:Play(); + overview:SetScript("OnUpdate", EncounterJournal_FocusSectionCallback); + else + overview.expanded = true; + EncounterJournal_ToggleHeaders(overview); + overview.button.glow.flashAnim:Stop(); + overview:SetScript("OnUpdate", nil); + end + end + self.linkSection = nil; + elseif self.overviews and self.overviews[1] then + self.overviews[1].expanded = false; + EncounterJournal.overviewDefaultRole = role; + EncounterJournal_ToggleHeaders(self.overviews[1]); + end + end + end + + if (not isOverview) then + if self.myID then + EJ_section_openTable[self.myID] = self.expanded; + end + + if not doNotShift then + EncounterJournal_ShiftHeaders(self.index or 1); + EncounterJournal_UpdateDetailsScrollRange(); + + --check to see if it is offscreen + if self.index then + local scrollValue = EncounterJournal.encounter.info.detailsScroll.ScrollBar:GetValue(); + local cutoff = EncounterJournal.encounter.info.detailsScroll:GetHeight() + scrollValue; + + local _, _, _, _, anchorY = self:GetPoint(); + anchorY = anchorY - self:GetHeight(); + if self.description:IsShown() then + anchorY = anchorY - self.description:GetHeight() - SECTION_DESCRIPTION_OFFSET; + end + + if cutoff < abs(anchorY) then + self.frameCount = 0; + self:SetScript("OnUpdate", EncounterJournal_MoveSectionUpdate); + end + end + end + return numAdded; + else + return 0; + end +end + +function EncounterJournal_ShiftHeaders(index) + local usedHeaders = EncounterJournal.encounter.usedHeaders; + if not usedHeaders[index] then + return; + end + + local _, _, _, _, anchorY = usedHeaders[index]:GetPoint(); + for i = index, #usedHeaders - 1 do + anchorY = anchorY - usedHeaders[i]:GetHeight(); + if usedHeaders[i].description:IsShown() then + anchorY = anchorY - EncounterJournal_UpdateSimpleHTMLHeight(usedHeaders[i].description) - + SECTION_DESCRIPTION_OFFSET; + else + anchorY = anchorY - SECTION_BUTTON_OFFSET; + end + + usedHeaders[i + 1]:SetPoint("TOPRIGHT", 0, anchorY); + end +end + +function EncounterJournal_ResetHeaders() + for key, _ in pairs(EJ_section_openTable) do + EJ_section_openTable[key] = nil; + end + + PlaySound("igMainMenuOptionCheckBoxOn"); + EncounterJournal_UpdateScrollPos(EncounterJournal.encounter.info.lootScroll, 1) + EJ_SetValidationDifficulty(1) + EJ_ResetLootFilter() + EncounterJournal_UpdateFilterString() + EncounterJournal_Refresh(); +end + +function EncounterJournal_FocusSection(sectionID) + if (not EncounterJournal_CheckForOverview(sectionID)) then + local usedHeaders = EncounterJournal.encounter.usedHeaders; + for _, section in pairs(usedHeaders) do + if section.myID == sectionID then + section.cbCount = 0; + section.button.glow.flashAnim:Play(); + section:SetScript("OnUpdate", EncounterJournal_FocusSectionCallback); + else + section.button.glow.flashAnim:Stop(); + section:SetScript("OnUpdate", nil); + end + end + end +end + +function EncounterJournal_FocusSectionCallback(self) + if self.cbCount > 0 then + local _, _, _, _, anchorY = self:GetPoint(); + anchorY = abs(anchorY); + anchorY = anchorY - EncounterJournal.encounter.info.detailsScroll:GetHeight() / 2 + EncounterJournal.encounter.info.detailsScroll.ScrollBar:SetValue(anchorY) + self:SetScript("OnUpdate", nil); + end + self.cbCount = self.cbCount + 1; +end + +function EncounterJournal_MoveSectionUpdate(self) + if self.frameCount > 0 then + local _, _, _, _, anchorY = self:GetPoint(); + local height = min(EJ_MAX_SECTION_MOVE, + self:GetHeight() + self.description:GetHeight() + SECTION_DESCRIPTION_OFFSET); + local scrollValue = abs(anchorY) - (EncounterJournal.encounter.info.detailsScroll:GetHeight() - height); + EncounterJournal.encounter.info.detailsScroll.ScrollBar:SetValue(scrollValue); + self:SetScript("OnUpdate", nil); + end + self.frameCount = self.frameCount + 1; +end + +function EncounterJournal_ClearChildHeaders(self, doNotShift) + local usedHeaders = EncounterJournal.encounter.usedHeaders; + local freeHeaders = EncounterJournal.encounter.freeHeaders; + local numCleared = 0 + for key, header in pairs(usedHeaders) do + if header.parentID == self.myID then + if header.expanded then + numCleared = numCleared + EncounterJournal_ClearChildHeaders(header, true) + end + header:Hide(); + usedHeaders[key] = nil; + freeHeaders[#freeHeaders + 1] = header; + numCleared = numCleared + 1; + end + end + + if numCleared > 0 and not doNotShift then + local placeIndex = self.index + 1; + local shiftHeader = usedHeaders[placeIndex + numCleared]; + while shiftHeader do + usedHeaders[placeIndex] = shiftHeader; + usedHeaders[placeIndex].index = placeIndex; + usedHeaders[placeIndex + numCleared] = nil; + placeIndex = placeIndex + 1; + shiftHeader = usedHeaders[placeIndex + numCleared]; + end + end + return numCleared +end + +function EncounterJournal_ClearDetails() + EncounterJournal.encounter.instance:Hide(); + EncounterJournal.encounter.infoFrame.description:SetText(""); + EncounterJournal.encounter.info.TitleFrame.encounterTitle:SetText(""); + + EncounterJournal.encounter.info.overviewScroll.ScrollBar:SetValue(0); + EncounterJournal.encounter.info.lootScroll.scrollBar:SetValue(0); + EncounterJournal.encounter.info.detailsScroll.ScrollBar:SetValue(0); + EncounterJournal.encounter.info.bossesScroll.ScrollBar:SetValue(0); + + local freeHeaders = EncounterJournal.encounter.freeHeaders; + local usedHeaders = EncounterJournal.encounter.usedHeaders; + + for key, used in pairs(usedHeaders) do + used:Hide(); + usedHeaders[key] = nil; + freeHeaders[#freeHeaders + 1] = used; + end + + local clearDisplayInfo = true; + EncounterJournal_HideCreatures(clearDisplayInfo); + EncounterJournal_SetTabEnabled(EncounterJournal.encounter.info.modelTab, false); + + local bossIndex = 1 + local bossButton = _G["EncounterJournalBossButton" .. bossIndex]; + while bossButton do + bossButton:Hide(); + bossIndex = bossIndex + 1; + bossButton = _G["EncounterJournalBossButton" .. bossIndex]; + end + + -- EncounterJournal.searchResults:Hide(); + -- EncounterJournal_HideSearchPreview(); + -- EncounterJournal.searchBox:ClearFocus(); +end + +function EncounterJournal_TabClicked(self, button) + local tabType = self:GetID(); + EncounterJournal_SetTab(tabType); + PlaySound("igAbiliityPageTurn"); +end + +function EncounterJournal_SetTab(tabType) + if not EJ_Tabs[tabType] then + tabType = 1; + end + + local info = EncounterJournal.encounter.info; + info.tab = tabType; + if info.model and tabType ~= 4 then + info.model:Hide(); + end + for key, data in pairs(EJ_Tabs) do + if key == tabType then + info[data.frame]:Show(); + if key == 4 then + EncounterJournal_ShowCreatures(); + end + info[data.button].selected:Show(); + info[data.button].unselected:Hide(); + info[data.button]:LockHighlight(); + else + info[data.frame]:Hide(); + info[data.button].selected:Hide(); + info[data.button].unselected:Show(); + info[data.button]:UnlockHighlight(); + end + end + + UpdateDifficultyVisibility(); +end + +function EncounterJournal_SetTabEnabled(tab, enabled) + tab:SetEnabled(enabled); + tab:GetDisabledTexture():SetDesaturated(not enabled); + tab.unselected:SetDesaturated(not enabled); + if not enabled then + EncounterJournal_ValidateSelectedTab(); + end +end + +function EncounterJournal_ValidateSelectedTab() + local info = EncounterJournal.encounter.info; + local selectedTab = EJ_Tabs[info.tab]; + if not selectedTab then + EncounterJournal_SetTab(1); + return; + end + + local selectedTabButton = info[selectedTab.button]; + if selectedTabButton:IsEnabled() ~= 1 then + for index, data in ipairs(EJ_Tabs) do + local tabButton = info[data.button]; + if tabButton:IsEnabled() == 1 then + EncounterJournal_SetTab(index); + break; + end + end + end +end + +function EncounterJournal_SetLootButton(item) + local itemID, encounterID, name, icon, slot, armorType, link = EJ_GetLootInfoByIndex(item.index); + + if (name) then + item.name:SetText(name); + item.icon:SetTexture(icon); + item.slot:SetText(slot); + item.armorType:SetText(armorType == ITEM_SUB_CLASS_15_0 and "" or armorType); + + item.boss:SetFormattedText(BOSS_INFO_STRING, EJ_GetEncounterInfo(encounterID)); + + local itemName, _, quality = C_Item.GetItemInfo(link or itemID) + quality = quality or LE_ITEM_QUALITY_COMMON or 1 + SetItemButtonQuality(item, quality, itemID) + + if (quality > LE_ITEM_QUALITY_COMMON and BAG_ITEM_QUALITY_COLORS[quality]) then + item.name:SetTextColor(BAG_ITEM_QUALITY_COLORS[quality].r, BAG_ITEM_QUALITY_COLORS[quality].g, + BAG_ITEM_QUALITY_COLORS[quality].b) + end + else + item.name:SetText(RETRIEVING_ITEM_INFO); + item.icon:SetTexture("Interface\\Icons\\INV_Misc_QuestionMark"); + item.slot:SetText(""); + item.armorType:SetText(""); + item.boss:SetText(""); + item:Hide(); + end + + item.encounterID = encounterID; + item.itemID = itemID; + item.link = link; + item:Show(); + + if item.showingTooltip then + EncounterJournal_SetTooltip(link); + end +end + +function EncounterJournal_LootCallback(itemID) + local scrollFrame = EncounterJournal.encounter.info.lootScroll; + + for i, item in ipairs(scrollFrame.buttons) do + if item.itemID == itemID and item:IsShown() then + EncounterJournal_SetLootButton(item, item.index); + end + end +end + +function EncounterJournal_LootUpdate() + EncounterJournal_UpdateFilterString(); + local scrollFrame = EncounterJournal.encounter.info.lootScroll; + local offset = HybridScrollFrame_GetOffset(scrollFrame); + local item, index; + + local numLoot = EJ_GetNumLoot(); + local buttonSize = BOSS_LOOT_BUTTON_HEIGHT; + local buttons = scrollFrame.buttons; + + for i = 1, #buttons do + local button = buttons[i]; + index = offset + i; + if index <= numLoot then + if (EncounterJournal.encounterID) then + button:SetHeight(BOSS_LOOT_BUTTON_HEIGHT); + button.boss:Hide(); + button.bossTexture:Hide(); + button.bosslessTexture:Show(); + else + buttonSize = INSTANCE_LOOT_BUTTON_HEIGHT; + button:SetHeight(INSTANCE_LOOT_BUTTON_HEIGHT); + button.boss:Show(); + button.bossTexture:Show(); + button.bosslessTexture:Hide(); + end + button.index = index; + EncounterJournal_SetLootButton(button); + button.glow.flashAnim:Stop() + else + button:Hide(); + end + end + + local totalHeight = numLoot * buttonSize; + HybridScrollFrame_Update(scrollFrame, totalHeight, scrollFrame:GetHeight()); +end + +function EncounterJournal_LootCalcScroll(offset) + local buttonHeight = BOSS_LOOT_BUTTON_HEIGHT; + + if (not EncounterJournal.encounterID) then + buttonHeight = INSTANCE_LOOT_BUTTON_HEIGHT; + end + + local index = floor(offset / buttonHeight) + return index, offset - (index * buttonHeight); +end + +function EncounterJournal_Loot_OnUpdate(self) + if GameTooltip:IsOwned(self) then + if IsModifiedClick("DRESSUP") then + ShowInspectCursor(); + else + ResetCursor(); + end + end +end + +function EncounterJournal_Loot_OnClick(self) + local encounterID = self.encounterID; + if self.index then + local _, lootEncounterID = EJ_GetLootInfoByIndex(self.index); + encounterID = lootEncounterID or encounterID; + end + + if encounterID and EncounterJournal.encounterID ~= encounterID then + PlaySound("igSpellBookOpen"); + EncounterJournal_DisplayEncounter(encounterID); + end +end + +function EncounterJournal_SetTooltip(link) + if (not link) then + return; + end + + GameTooltip:SetAnchorType("ANCHOR_RIGHT"); + GameTooltip:SetHyperlink(link); +end + +function EncounterJournal_SetFlagIcon(texture, index) + local iconSize = 32; + local columns = 256 / iconSize; + local rows = 64 / iconSize; + + -- Mythic flag should use heroic Icon + if (index == 12) then + index = 3; + end + + local l = mod(index, columns) / columns; + local r = l + (1 / columns); + local t = floor(index / columns) / rows; + local b = t + (1 / rows); + texture:SetTexCoord(l, r, t, b); +end + +function EncounterJournal_Refresh(self) + EncounterJournal_LootUpdate(); + + if EncounterJournal.encounterID then + EncounterJournal_DisplayEncounter(EncounterJournal.encounterID, true) + elseif EncounterJournal.instanceID then + EncounterJournal_DisplayInstance(EncounterJournal.instanceID, true); + end +end + +function EncounterJournal_ToggleTutorial() + if not HelpPlate_IsShowing(EncounterJournal.helpPlate) then + HelpPlate_Show(EncounterJournal.helpPlate, EncounterJournal, EncounterJournal.TutorialButton) + else + HelpPlate_Hide(true) + end +end + +function EncounterJournal_UpdateScrollPos(self, visibleIndex) + local buttons = self.buttons + local height = math.max(0, math.floor(self.buttonHeight * (visibleIndex - (#buttons) / 2))) + HybridScrollFrame_SetOffset(self, height) + self.scrollBar:SetValue(height) +end + +function EncounterJournal_GetSearchDisplay(index) + local name, icon, path, typeText, displayInfo, itemID, _; + local id, stype, _, instanceID, encounterID, itemLink = EJ_GetSearchResult(index); + if stype == EJ_STYPE_INSTANCE then + name, _, _, icon = EJ_GetInstanceInfo(id); + typeText = ENCOUNTER_JOURNAL_INSTANCE; + elseif stype == EJ_STYPE_ENCOUNTER then + name = EJ_GetEncounterInfo(id); + typeText = ENCOUNTER_JOURNAL_ENCOUNTER; + path = EJ_GetInstanceInfo(instanceID); + icon = "Interface\\EncounterJournal\\UI-EJ-GenericSearchCreature" + --_, _, _, displayInfo = EJ_GetCreatureInfo(1, encounterID) + elseif stype == EJ_STYPE_SECTION then + name, _, _, icon, displayInfo = EJ_GetSectionInfo(id) + if displayInfo and displayInfo > 0 then + typeText = ENCOUNTER_JOURNAL_ENCOUNTER_ADD; + displayInfo = nil; + icon = "Interface\\EncounterJournal\\UI-EJ-GenericSearchCreature"; + else + typeText = ENCOUNTER_JOURNAL_ABILITY; + end + path = EJ_GetInstanceInfo(instanceID) .. " > " .. EJ_GetEncounterInfo(encounterID); + elseif stype == EJ_STYPE_ITEM then + itemID, _, name, icon = EJ_GetLootInfo(id) + typeText = ENCOUNTER_JOURNAL_ITEM; + path = EJ_GetInstanceInfo(instanceID) .. " > " .. EJ_GetEncounterInfo(encounterID); + elseif stype == EJ_STYPE_CREATURE then + for i = 1, MAX_CREATURES_PER_ENCOUNTER do + local cId, cName, _, cDisplayInfo = EJ_GetCreatureInfo(i, encounterID); + if cId == id then + name = cName + displayInfo = cDisplayInfo + break; + end + end + icon = "Interface\\EncounterJournal\\UI-EJ-GenericSearchCreature" + typeText = CREATURE + path = EJ_GetInstanceInfo(instanceID) .. " > " .. EJ_GetEncounterInfo(encounterID); + end + return name, icon, path, typeText, displayInfo, itemID, stype, itemLink; +end + +function EncounterJournal_SelectSearch(index) + local _; + local id, stype, difficultyMask, instanceID, encounterID = EJ_GetSearchResult(index); + local sectionID, creatureID, itemID; + if stype == EJ_STYPE_INSTANCE then + instanceID = id; + elseif stype == EJ_STYPE_SECTION then + sectionID = id; + elseif stype == EJ_STYPE_ITEM then + itemID = id; + elseif stype == EJ_STYPE_CREATURE then + creatureID = id; + end + + local difficultyID = difficultyMask and EJ_GetDifficultyByMask(difficultyMask, instanceID) or 1 + if not EJ_IsValidInstanceDifficulty(difficultyID, instanceID) then + difficultyID = EJ_GetValidationDifficulty(1) + end + + EncounterJournal_OpenJournal(difficultyID, instanceID, encounterID, sectionID, creatureID, itemID); + EncounterJournal.searchResults:Hide(); + EncounterJournal_HideSearchPreview() + EncounterJournal.searchBox:ClearFocus() +end + +function EncounterJournal_SearchUpdate() + local scrollFrame = EncounterJournal.searchResults.scrollFrame; + local offset = HybridScrollFrame_GetOffset(scrollFrame); + local results = scrollFrame.buttons; + local result, index; + + local numResults = EJ_GetNumSearchResults(); + + for i = 1, #results do + result = results[i]; + index = offset + i; + if index <= numResults then + local name, icon, path, typeText, displayInfo, itemID, stype, itemLink = EncounterJournal_GetSearchDisplay( + index); + if stype == EJ_STYPE_INSTANCE then + result.icon:SetTexCoord(0.16796875, 0.51171875, 0.03125, 0.71875); + else + result.icon:SetTexCoord(0, 1, 0, 1); + end + + result.name:SetText(name); + result.resultType:SetText(typeText); + result.path:SetText(path); + result.icon:SetTexture(icon); + result.link = itemLink; + if displayInfo and displayInfo > 0 then + -- SetPortraitTexture(result.icon, displayInfo); + result.icon:SetPortrait(displayInfo) + end + result:SetID(index); + result:Show(); + + if result.showingTooltip then + if itemLink then + GameTooltip:SetOwner(result, "ANCHOR_RIGHT"); + GameTooltip:SetHyperlink(itemLink); + GameTooltip_ShowCompareItem(); + else + GameTooltip:Hide(); + end + end + else + result:Hide(); + end + end + + local totalHeight = numResults * 49; + HybridScrollFrame_Update(scrollFrame, totalHeight, 370); +end + +function EncounterJournal_ShowFullSearch() + local numResults = EJ_GetNumSearchResults(); + if numResults == 0 then + EncounterJournal.searchResults:Hide(); + return; + end + + EncounterJournal.searchResults.TitleText:SetFormattedText(ENCOUNTER_JOURNAL_SEARCH_RESULTS, + EncounterJournal.searchBox:GetText(), numResults); + EncounterJournal.searchResults:Show(); + EncounterJournal_SearchUpdate(); + EncounterJournal.searchResults.scrollFrame.scrollBar:SetValue(0); + EncounterJournal_HideSearchPreview(); + EncounterJournal.searchBox:ClearFocus(); +end + +function EncounterJournal_RestartSearchTracking() + if EJ_IsSearchFinished() then + EncounterJournal_ShowSearch(); + else + EncounterJournal.searchBox.searchPreviewUpdateDelay = 0; + EncounterJournal.searchBox:SetScript("OnUpdate", EncounterJournalSearchBox_OnUpdate); + + --Since we just restarted the search we hide the progress bar until the search delay is done. + EncounterJournal.searchBox.searchProgress:Hide(); + EncounterJournal_FixSearchPreviewBottomBorder(); + end +end + +function EncounterJournal_ShowSearch() + if EncounterJournal.searchResults:IsShown() then + EncounterJournal_ShowFullSearch(); + else + EncounterJournal_UpdateSearchPreview(); + end +end + +-- There is a delay before the search is updated to avoid a search progress bar if the search +-- completes within the grace period. +local ENCOUNTER_JOURNAL_SEARCH_PREVIEW_UPDATE_DELAY = 0.6; +function EncounterJournalSearchBox_OnUpdate(self, elapsed) + if EJ_IsSearchFinished() then + EncounterJournal_ShowSearch(); + self.searchPreviewUpdateDelay = nil; + self:SetScript("OnUpdate", nil); + return; + end + + self.searchPreviewUpdateDelay = (self.searchPreviewUpdateDelay or 0) + elapsed; + + if self.searchPreviewUpdateDelay > ENCOUNTER_JOURNAL_SEARCH_PREVIEW_UPDATE_DELAY then + self.searchPreviewUpdateDelay = nil; + self:SetScript("OnUpdate", nil); + EncounterJournal_UpdateSearchPreview(); + return; + end +end + +function EncounterJournalSearchBoxSearchProgressBar_OnLoad(self) + self:SetStatusBarColor(0, .6, 0, 1); + self:SetMinMaxValues(0, 1000); + self:SetValue(0); + self:GetStatusBarTexture():SetDrawLayer("BORDER"); +end + +function EncounterJournalSearchBoxSearchProgressBar_OnShow(self) + self:SetScript("OnUpdate", EncounterJournalSearchBoxSearchProgressBar_OnUpdate); +end + +function EncounterJournalSearchBoxSearchProgressBar_OnHide(self) + self:SetScript("OnUpdate", nil); + self:SetValue(0); + self.previousResults = nil; +end + +-- If the searcher does not finish within the update delay then a search progress bar is displayed that +-- will fill until the search is finished and then display the search preview results. +function EncounterJournalSearchBoxSearchProgressBar_OnUpdate(self, elapsed) + if EJ_GetSearchSize() == 0 then + self:SetValue(0); + return; + end + + local _, maxValue = self:GetMinMaxValues(); + self:SetValue((EJ_GetSearchProgress() / EJ_GetSearchSize()) * maxValue); + + --If we don't already have the max number of search previews keep checking if + --we have new results we can display (unless we are delaying updates). + if (self.previousResults == nil) or (self.previousResults < EJ_NUM_SEARCH_PREVIEWS) and + (EncounterJournal.searchBox.searchPreviewUpdateDelay == nil) then + local numResults = EJ_GetNumSearchResults(); + if (self.previousResults == nil and numResults > 0) or (numResults ~= self.previousResults) then + EncounterJournal_UpdateSearchPreview(); + end + + self.previousResults = numResults; + end + + if self:GetValue() >= maxValue then + self:SetScript("OnUpdate", nil); + self:SetValue(0); + EncounterJournal.searchBox.searchProgress:Hide(); + EncounterJournal_ShowSearch(); + end +end + +function EncounterJournal_UpdateSearchPreview() + if strlen(EncounterJournal.searchBox:GetText()) < MIN_CHARACTER_SEARCH then + EncounterJournal_HideSearchPreview(); + EncounterJournal.searchResults:Hide(); + return; + end + + local numResults = EJ_GetNumSearchResults(); + + if numResults == 0 and EJ_IsSearchFinished() then + EncounterJournal_HideSearchPreview(); + return; + end + + local lastShown = EncounterJournal.searchBox; + for index = 1, EJ_NUM_SEARCH_PREVIEWS do + local button = EncounterJournal.searchBox.searchPreview[index]; + if index <= numResults then + local name, icon, path, typeText, displayInfo, itemID, stype, itemLink = EncounterJournal_GetSearchDisplay( + index); + if stype == EJ_STYPE_INSTANCE then + button.icon:SetTexCoord(0.16796875, 0.51171875, 0.03125, 0.71875) + else + button.icon:SetTexCoord(0, 1, 0, 1) + end + + button.name:SetText(name); + button.icon:SetTexture(icon); + button.link = itemLink; + if displayInfo and displayInfo > 0 then + -- SetPortraitTexture(button.icon, displayInfo); + button.icon:SetPortrait(displayInfo) + end + button:SetID(index); + button:Show(); + lastShown = button; + else + button:Hide(); + end + end + + EncounterJournal.searchBox.showAllResults:Hide(); + EncounterJournal.searchBox.searchProgress:Hide(); + if not EJ_IsSearchFinished() then + EncounterJournal.searchBox.searchProgress:SetPoint("TOP", lastShown, "BOTTOM", 0, 0); + + -- If there are no items to search then the search DB isn't loaded yet. + if EJ_GetSearchSize() == 0 then + EncounterJournal.searchBox.searchProgress.loading:Show(); + EncounterJournal.searchBox.searchProgress.bar:Hide(); + else + EncounterJournal.searchBox.searchProgress.loading:Hide(); + EncounterJournal.searchBox.searchProgress.bar:Show(); + end + + EncounterJournal.searchBox.searchProgress:Show(); + elseif numResults > EJ_NUM_SEARCH_PREVIEWS then + EncounterJournal.searchBox.showAllResults.text:SetFormattedText(ENCOUNTER_JOURNAL_SHOW_SEARCH_RESULTS, numResults); + EncounterJournal.searchBox.showAllResults:Show(); + end + + EncounterJournal_FixSearchPreviewBottomBorder(); + EncounterJournal.searchBox.searchPreviewContainer:Show(); +end + +function EncounterJournal_FixSearchPreviewBottomBorder() + -- EncounterJournal.searchBox.showAllResults:SetShown(EJ_GetNumSearchResults() >= EJ_SHOW_ALL_SEARCH_RESULTS_INDEX) + + local lastShownButton = nil; + if EncounterJournal.searchBox.showAllResults:IsShown() then + lastShownButton = EncounterJournal.searchBox.showAllResults; + elseif EncounterJournal.searchBox.searchProgress:IsShown() then + lastShownButton = EncounterJournal.searchBox.searchProgress; + else + for index = 1, EJ_NUM_SEARCH_PREVIEWS do + local button = EncounterJournal.searchBox.searchPreview[index]; + if button:IsShown() then + lastShownButton = button; + end + end + end + + if lastShownButton ~= nil then + EncounterJournal.searchBox.searchPreviewContainer.botRightCorner:SetPoint("BOTTOM", lastShownButton, "BOTTOM", 0, + -8); + EncounterJournal.searchBox.searchPreviewContainer.botLeftCorner:SetPoint("BOTTOM", lastShownButton, "BOTTOM", 0, + -8); + else + EncounterJournal_HideSearchPreview(); + end +end + +function EncounterJouranl_IsSearchPreviewShown() + return EncounterJournal.searchBox.searchPreviewContainer:IsShown(); +end + +function EncounterJournal_HideSearchPreview() + EncounterJournal.searchBox.showAllResults:Hide(); + EncounterJournal.searchBox.searchProgress:Hide(); + + local index = 1; + local unusedButton = EncounterJournal.searchBox.searchPreview[index]; + while unusedButton do + unusedButton:Hide(); + index = index + 1; + unusedButton = EncounterJournal.searchBox.searchPreview[index]; + end + + EncounterJournal.searchBox.searchPreviewContainer:Hide(); +end + +function EncounterJournal_ClearSearch() + EncounterJournal.searchResults:Hide(); + EncounterJournal_HideSearchPreview(); +end + +function EncounterJournalSearchBox_OnLoad(self) + SearchBoxTemplate_OnLoad(self); + self.HasStickyFocus = function() + local ancestry = EncounterJournal.searchBox; + return DoesAncestryInclude(ancestry, GetMouseFocus()); + end + self.selectedIndex = 1; +end + +function EncounterJournalSearchBox_OnShow(self) + self:SetFrameLevel(self:GetParent():GetFrameLevel() + 10); +end + +function EncounterJournalSearchBox_OnHide(self) + self.searchPreviewUpdateDelay = nil; + self:SetScript("OnUpdate", nil); +end + +function EncounterJournalSearchBox_OnTextChanged(self) + SearchBoxTemplate_OnTextChanged(self); + + local text = self:GetText(); + if strlen(text) < MIN_CHARACTER_SEARCH then + EJ_ClearSearch(); + EncounterJournal_HideSearchPreview(); + EncounterJournal.searchResults:Hide(); + return; + end + + EncounterJournal_SetSearchPreviewSelection(1); + EJ_SetSearch(text); + EncounterJournal_RestartSearchTracking(); +end + +function EncounterJournalSearchBox_OnEnterPressed(self) + if self.selectedIndex > EJ_SHOW_ALL_SEARCH_RESULTS_INDEX or self.selectedIndex < 0 then + return; + elseif self.selectedIndex == EJ_SHOW_ALL_SEARCH_RESULTS_INDEX then + if EncounterJournal.searchBox.showAllResults:IsShown() then + EncounterJournal.searchBox.showAllResults:Click(); + end + else + local preview = EncounterJournal.searchBox.searchPreview[self.selectedIndex]; + if preview:IsShown() then + preview:Click(); + end + end + + EncounterJournal_HideSearchPreview(); +end + +function EncounterJournalSearchBox_OnTabPressed(self) + if IsShiftKeyDown() then + EncounterJournal_SetSearchPreviewSelection(EncounterJournal.searchBox.selectedIndex - 1); + else + EncounterJournal_SetSearchPreviewSelection(EncounterJournal.searchBox.selectedIndex + 1); + end +end + +function EncounterJournalSearchBox_OnFocusLost(self) + SearchBoxTemplate_OnEditFocusLost(self); + EncounterJournal_HideSearchPreview(); +end + +function EncounterJournalSearchBox_OnFocusGained(self) + SearchBoxTemplate_OnEditFocusGained(self); + EncounterJournal.searchResults:Hide(); + EncounterJournal_SetSearchPreviewSelection(1); + EncounterJournal_UpdateSearchPreview(); +end + +function EncounterJournalSearchBoxShowAllResults_OnEnter(self) + EncounterJournal_SetSearchPreviewSelection(EJ_SHOW_ALL_SEARCH_RESULTS_INDEX); +end + +function EncounterJournal_SetSearchPreviewSelection(selectedIndex) + local searchBox = EncounterJournal.searchBox; + local numShown = 0; + for index = 1, EJ_NUM_SEARCH_PREVIEWS do + searchBox.searchPreview[index].selectedTexture:Hide(); + + if searchBox.searchPreview[index]:IsShown() then + numShown = numShown + 1; + end + end + + if searchBox.showAllResults:IsShown() then + numShown = numShown + 1; + end + + searchBox.showAllResults.selectedTexture:Hide(); + + if numShown == 0 then + selectedIndex = 1; + elseif selectedIndex > numShown then + -- Wrap under to the beginning. + selectedIndex = 1; + elseif selectedIndex < 1 then + -- Wrap over to the end; + selectedIndex = numShown; + end + + searchBox.selectedIndex = selectedIndex; + + if selectedIndex == EJ_SHOW_ALL_SEARCH_RESULTS_INDEX then + searchBox.showAllResults.selectedTexture:Show(); + else + searchBox.searchPreview[selectedIndex].selectedTexture:Show(); + end +end + +function EncounterJournal_OpenJournalLink(tag, jtype, id, difficultyID) + jtype = tonumber(jtype); + id = tonumber(id); + difficultyID = tonumber(difficultyID); + local instanceID, encounterID, sectionID, tierIndex = EJ_HandleLinkPath(jtype, id); + EncounterJournal_OpenJournal(difficultyID, instanceID, encounterID, sectionID, nil, nil, tierIndex); +end + +function EncounterJournal_OpenJournal(difficultyID, instanceID, encounterID, sectionID, creatureID, itemID, tierIndex) + ShowUIPanel(EncounterJournal); + EJ_HideNonInstancePanels(); + if instanceID then + NavBar_Reset(EncounterJournal.navBar); + EJ_ContentTab_SelectAppropriateInstanceTab(instanceID); + + EncounterJournal_DisplayInstance(instanceID); + if not difficultyID or difficultyID == -1 then + EJ_SetValidationDifficulty(1) + else + EJ_SetDifficulty(difficultyID); + end + + if encounterID then + if sectionID then + if (EncounterJournal_CheckForOverview(sectionID)) then + EncounterJournal.encounter.overviewFrame.linkSection = sectionID; + else + local sectionPath = { EJ_GetSectionPath(sectionID) }; + for _, id in pairs(sectionPath) do + EJ_section_openTable[id] = true; + end + end + end + EncounterJournal_DisplayEncounter(encounterID, nil, true); + if sectionID then + if (EncounterJournal_CheckForOverview(sectionID) or not EncounterJournal_SearchForOverview(instanceID)) then + EncounterJournal.encounter.info.overviewTab:Click(); + else + EncounterJournal.encounter.info.bossTab:Click(); + end + EncounterJournal_FocusSection(sectionID); + elseif itemID then + local itemIndex = EJ_GetLootInfoIndexByItemID(itemID) + if not itemIndex then + if not EJ_IsItemAllowedByClassFilter(itemID) + or not EJ_IsItemAllowedBySlotFilter(itemID) + then + EncounterJournal_UpdateScrollPos(EncounterJournal.encounter.info.lootScroll, 1) + EJ_SetLootFilter(0) + EncounterJournal_LootUpdate() + end + itemIndex = EJ_GetLootInfoIndexByItemID(itemID) + end + + EncounterJournal.encounter.info.lootTab:Click(); + + if itemIndex then + EncounterJournal_UpdateScrollPos(EncounterJournal.encounter.info.lootScroll, itemIndex) + local buttons = EncounterJournal.encounter.info.lootScroll.buttons + for i = 1, #buttons do + local button = buttons[i] + if button.itemID == itemID then + button.glow.flashAnim:Play() + break + end + end + end + end + end + elseif tierIndex then + EncounterJournal_TierDropDown_Select(EncounterJournal, tierIndex + 1); + else + EncounterJournal_ListInstances(); + end +end + +function EncounterJournal_SelectDifficulty(self, value) + EJ_SetDifficulty(value); +end + +function EncounterJournal_DifficultyInit(self, level) + local currDifficulty = EJ_GetDifficulty(); + local info = UIDropDownMenu_CreateInfo(); + for i, entry in ipairs(EJ_DIFFICULTIES) do + if EJ_IsValidInstanceDifficulty(entry.difficultyID) and (entry.size ~= "5" == EJ_InstanceIsRaidByID(EncounterJournal.instanceID)) then + info.func = EncounterJournal_SelectDifficulty; + if (entry.size ~= "5") then + info.text = string.format("(%s) %s", entry.size, entry.prefix) + else + info.text = entry.prefix; + end + info.arg1 = entry.difficultyID; + info.checked = currDifficulty == entry.difficultyID; + UIDropDownMenu_AddButton(info); + end + end +end + +function EJ_HideInstances(index) + if (not index) then + index = 1; + end + + local scrollChild = EncounterJournal.instanceSelect.scroll.child; + local instanceButton = scrollChild["instance" .. index]; + while instanceButton do + instanceButton:Hide(); + index = index + 1; + instanceButton = scrollChild["instance" .. index]; + end +end + +function EJSuggestTab_GetPlayerTierIndex() + local playerLevel = UnitLevel("player"); + local expansionId = LE_EXPANSION_LEVEL_CURRENT; + local minDiff = MAX_PLAYER_LEVEL_TABLE[LE_EXPANSION_LEVEL_CURRENT]; + for tierId, tierLevel in pairs(MAX_PLAYER_LEVEL_TABLE) do + local diff = tierLevel - playerLevel; + if (diff > 0 and diff < minDiff) then + expansionId = tierId; + minDiff = diff; + end + end + return GetEJTierDataTableID(expansionId); +end + +function EJ_ContentTab_OnClick(self) + EJ_ContentTab_Select(self.id); +end + +local function EJ_ContentTab_RaiseTabsAbovePlayerGuide() + local instanceSelect = EncounterJournal and EncounterJournal.instanceSelect; + if not instanceSelect then + return; + end + + local baseLevel = instanceSelect:GetFrameLevel(); + if PlayerGuideFrame then + PlayerGuideFrame:SetFrameLevel(baseLevel + 1); + end + + local tabLevel = baseLevel + 12; + if instanceSelect.Tabs then + for _, tab in ipairs(instanceSelect.Tabs) do + tab:SetFrameLevel(tabLevel); + if tab.grayBox then + tab.grayBox:SetFrameLevel(tabLevel + 1); + end + end + end + + if instanceSelect.tierDropDown then + instanceSelect.tierDropDown:SetFrameLevel(tabLevel); + end +end + +function EJ_ContentTab_Select(id) + local instanceSelect = EncounterJournal.instanceSelect; + + local selectedTab = nil; + for i = 1, #instanceSelect.Tabs do + local tab = instanceSelect.Tabs[i]; + if (tab.id ~= id) then + tab:Enable(); + tab:GetFontString():SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); + tab.selectedGlow:Hide(); + else + tab:GetFontString():SetTextColor(NORMAL_FONT_COLOR.r, NORMAL_FONT_COLOR.g, NORMAL_FONT_COLOR.b); + tab:Disable(); + selectedTab = tab; + end + end + + EncounterJournal.instanceSelect.selectedTab = id; + + -- Setup background + local tierData; + if (id == instanceSelect.suggestTab.id) then + tierData = GetEJTierData(EJSuggestTab_GetPlayerTierIndex()); + elseif id == instanceSelect.LootJournalTab.id then + tierData = GetEJTierData(1) + else + tierData = GetEJTierData(EJ_GetCurrentTier()); + end + selectedTab.selectedGlow:Hide(); + instanceSelect.bg:SetAtlas(tierData.backgroundAtlas, true); + EncounterJournal.encounter:Hide(); + EncounterJournal.instanceSelect:Show(); + + if (id == instanceSelect.suggestTab.id) then + EJ_HideInstances(); + EJ_HideLootJournalPanel(); + EJ_HidePlayerGuidePanel(); + instanceSelect.scroll:Hide(); + EncounterJournal.suggestFrame:Show(); + if (not instanceSelect.dungeonsTab.grayBox:IsShown() or not instanceSelect.raidsTab.grayBox:IsShown()) then + EncounterJournal_DisableTierDropDown(true); + else + EncounterJournal_EnableTierDropDown(); + end + elseif (id == instanceSelect.guideTab.id) then + EJ_HideInstances(); + EJ_HideSuggestPanel(); + EJ_HideLootJournalPanel(); + instanceSelect.scroll:Hide(); + EncounterJournal_DisableTierDropDown(true); + instanceSelect.tierDropDown:Hide(); + if PlayerGuideFrame then + EJ_ContentTab_RaiseTabsAbovePlayerGuide(); + PlayerGuideFrame:Show(); + EJ_ContentTab_RaiseTabsAbovePlayerGuide(); + end + elseif (id == instanceSelect.LootJournalTab.id) then + EJ_HideInstances(); + EJ_HideSuggestPanel(); + EJ_HidePlayerGuidePanel(); + instanceSelect.scroll:Hide(); + EncounterJournal_DisableTierDropDown(true); + EJ_ShowLootJournalPanel(); + elseif (id == instanceSelect.dungeonsTab.id or id == instanceSelect.raidsTab.id) then + EJ_HideNonInstancePanels(); + instanceSelect.scroll:Show(); + EncounterJournal_ListInstances(); + EncounterJournal_EnableTierDropDown(); + end + PlaySound("igMainMenuOptionCheckBoxOn"); + EncounterJournal.TutorialButton:SetShown(id == instanceSelect.suggestTab.id or id == instanceSelect.dungeonsTab.id or + id == instanceSelect.raidsTab.id) + + EventRegistry:TriggerEvent("EncounterJournal.SetTab", id) +end + +function EJ_ContentTab_SelectAppropriateInstanceTab(instanceID) + local isRaid = EJ_InstanceIsRaidByID(instanceID); + local desiredTabID = isRaid and EncounterJournal.instanceSelect.raidsTab:GetID() or + EncounterJournal.instanceSelect.dungeonsTab:GetID(); + EJ_ContentTab_Select(desiredTabID); +end + +function EJ_HideSuggestPanel() + local instanceSelect = EncounterJournal.instanceSelect; + local suggestTab = instanceSelect.suggestTab; + if (not suggestTab:IsEnabled() == 1 or EncounterJournal.suggestFrame:IsShown()) then + suggestTab:Enable(); + suggestTab:GetFontString():SetTextColor(HIGHLIGHT_FONT_COLOR.r, HIGHLIGHT_FONT_COLOR.g, HIGHLIGHT_FONT_COLOR.b); + suggestTab.selectedGlow:Hide(); + EncounterJournal.suggestFrame:Hide(); + + EncounterJournal_EnableTierDropDown(); + + local tierData = GetEJTierData(EJ_GetCurrentTier()); + instanceSelect.bg:SetAtlas(tierData.backgroundAtlas, true); + instanceSelect.raidsTab.selectedGlow:SetVertexColor(tierData.r, tierData.g, tierData.b); + instanceSelect.dungeonsTab.selectedGlow:SetVertexColor(tierData.r, tierData.g, tierData.b); + instanceSelect.scroll:Show(); + + EncounterJournal.suggestFrame:Hide(); + end +end + +function EJ_HideLootJournalPanel() + if (EncounterJournal.LootJournal) then + EncounterJournal.LootJournal:Hide(); + end + if (EncounterJournal.LootJournalItems) then + EncounterJournal.LootJournalItems:Hide(); + end +end + +function EJ_ShowLootJournalPanel() + local activeLootPanel = EncounterJournal_GetLootJournalPanels(); + activeLootPanel:Show(); +end + +function EJ_HidePlayerGuidePanel() + if PlayerGuideFrame then + PlayerGuideFrame:Hide() + end + if EncounterJournal and EncounterJournal.instanceSelect and EncounterJournal.instanceSelect.tierDropDown then + EncounterJournal.instanceSelect.tierDropDown:Show() + end +end + +function EJ_HideNonInstancePanels() + EJ_HideSuggestPanel(); + EJ_HideLootJournalPanel(); + EJ_HidePlayerGuidePanel(); +end + +function EJTierDropDown_Initialize(self, level) + local info = UIDropDownMenu_CreateInfo(); + local numTiers = EJ_GetNumTiers(); + + local currTier = EJ_GetCurrentTier(); + for i = 1, numTiers do + info.text = EJ_GetTierInfo(i); + info.func = EncounterJournal_TierDropDown_Select + info.checked = i == currTier; + info.arg1 = i; + UIDropDownMenu_AddButton(info, level) + end +end + +function EncounterJournal_TierDropDown_Select(_, tier) + EJ_SelectTier(tier); + + local instanceSelect = EncounterJournal.instanceSelect; + instanceSelect.dungeonsTab.grayBox:Hide(); + instanceSelect.raidsTab.grayBox:Hide(); + + local tierData = GetEJTierData(tier); + instanceSelect.bg:SetAtlas(tierData.backgroundAtlas, true); + instanceSelect.raidsTab.selectedGlow:SetVertexColor(tierData.r, tierData.g, tierData.b); + instanceSelect.dungeonsTab.selectedGlow:SetVertexColor(tierData.r, tierData.g, tierData.b); + + UIDropDownMenu_SetText(instanceSelect.tierDropDown, EJ_GetTierInfo(EJ_GetCurrentTier())); + + EncounterJournal_ListInstances(); +end + +function EncounterJournal_OnFilterChanged(self) + CloseDropDownMenus(1); + EncounterJournal_LootUpdate(); +end + +function EncounterJournal_SetClassAndSpecFilter(self, classID) + EncounterJournal_UpdateScrollPos(EncounterJournal.encounter.info.lootScroll, 1) + EJ_SetLootFilter(classID); + EncounterJournal_OnFilterChanged(self); +end + +function EncounterJournal_RefreshSlotFilterText(self) + local text = ALL_INVENTORY_SLOTS; + local slotFilter = C_EncounterJournal.GetSlotFilter(); + if slotFilter ~= NO_INV_TYPE_FILTER then + for slotIndex = 1, C_EncounterJournal.GetNumSlotFilters() do + local invType, invTypeName, equipSlot = C_EncounterJournal.GetSlotFilterInfo(slotIndex) + if (invType == slotFilter) then + text = invTypeName; + break; + end + end + end + + EncounterJournal.encounter.info.lootScroll.slotFilter:SetText(text); +end + +function EncounterJournal_SetSlotFilter(self, slot) + EncounterJournal_UpdateScrollPos(EncounterJournal.encounter.info.lootScroll, 1) + C_EncounterJournal.SetSlotFilter(slot); + EncounterJournal_RefreshSlotFilterText(self); + EncounterJournal_OnFilterChanged(self); +end + +function EncounterJournal_UpdateFilterString() + local name; + local classID = EJ_GetLootFilter(); + if (classID > 0) then + name = GetClassInfo(classID); + end + + if name then + EncounterJournal.encounter.info.lootScroll.classClearFilter.text:SetFormattedText(EJ_CLASS_FILTER, name); + EncounterJournal.encounter.info.lootScroll.classClearFilter:Show(); + EncounterJournal.encounter.info.lootScroll:SetHeight(360); + else + EncounterJournal.encounter.info.lootScroll.classClearFilter:Hide(); + EncounterJournal.encounter.info.lootScroll:SetHeight(382); + end +end + +function EncounterJournal_InitLootFilter(self, level) + local filterClassID = EJ_GetLootFilter(); + local classDisplayName, classTag, classID; + local info = UIDropDownMenu_CreateInfo(); + info.keepShownOnClick = nil; + --[[ + info.text = EJ_FILTER_ALL_CLASS; + info.checked = (filterClassID == NO_CLASS_FILTER); + info.arg1 = NO_CLASS_FILTER; + info.func = EncounterJournal_SetClassAndSpecFilter; + UIDropDownMenu_AddButton(info, level); +--]] + + local numClasses = GetNumClasses(); + for i = 1, numClasses do + classDisplayName, classTag, classID = GetClassInfo(i); + if classID ~= CLASS_ID_DEMONHUNTER then + info.text = classDisplayName; + info.checked = (filterClassID == classID); + info.arg1 = classID; + info.func = EncounterJournal_SetClassAndSpecFilter; + UIDropDownMenu_AddButton(info, level); + end + end +end + +function EncounterJournal_InitLootSlotFilter(self, level) + local slotFilter = C_EncounterJournal.GetSlotFilter(); + + local info = UIDropDownMenu_CreateInfo(); + info.text = ALL_INVENTORY_SLOTS; + info.checked = slotFilter == NO_INV_TYPE_FILTER; + info.arg1 = NO_INV_TYPE_FILTER; + info.func = EncounterJournal_SetSlotFilter; + UIDropDownMenu_AddButton(info); + + for slotIndex = 1, C_EncounterJournal.GetNumSlotFilters() do + local invType, invTypeName, equipSlot = C_EncounterJournal.GetSlotFilterInfo(slotIndex) + info.text = invTypeName; + info.checked = slotFilter == invType; + info.arg1 = invType; + UIDropDownMenu_AddButton(info); + end +end + +---------------------------------------- +--------------Nav Bar Func-------------- +---------------------------------------- +function EJNAV_RefreshInstance() + EncounterJournal_DisplayInstance(EncounterJournal.instanceID, true); +end + +function EJNAV_SelectInstance(self, index, navBar) + local instanceID = EJ_GetInstanceByIndex(index, EJ_InstanceIsRaid()); + + --Clear any previous selection. + NavBar_Reset(navBar); + + EncounterJournal_DisplayInstance(instanceID); +end + +function EJNAV_ListInstance(self, index) + local _, name = EJ_GetInstanceByIndex(index, EJ_InstanceIsRaid()) + return name, EJNAV_SelectInstance +end + +function EJNAV_RefreshEncounter() + EncounterJournal_DisplayInstance(EncounterJournal.encounterID); +end + +function EJNAV_SelectEncounter(self, index, navBar) + local _, _, bossID = EJ_GetEncounterInfoByIndex(index); + EncounterJournal_DisplayEncounter(bossID); +end + +function EJNAV_ListEncounter(self, index) + local name = EJ_GetEncounterInfoByIndex(index) + return name, EJNAV_SelectEncounter +end + +------------------------------------------------- +--------------Suggestion Panel Func-------------- +------------------------------------------------- +function EJSuggestFrame_OnLoad(self) + self.suggestions = {}; + + self:RegisterCustomEvent("AJ_REWARD_DATA_RECEIVED"); + self:RegisterCustomEvent("AJ_REFRESH_DISPLAY"); +end + +function EJSuggestFrame_OnEvent(self, event, ...) + if (event == "AJ_REFRESH_DISPLAY") then + if self:GetParent().selectedTab == EncounterJournal.instanceSelect.suggestTab.id then + EJSuggestFrame_RefreshDisplay(); + local newAdventureNotice = ...; + if (newAdventureNotice) then + -- EncounterJournalMicroButton:UpdateNewAdventureNotice(); + end + end + elseif (event == "AJ_REWARD_DATA_RECEIVED") then + EJSuggestFrame_RefreshRewards() + end +end + +function EJSuggestFrame_OnShow(self) + SetParentFrameLevel(self) + -- EncounterJournalMicroButton:ClearNewAdventureNotice(); + + C_AdventureJournal.UpdateSuggestions(); + EJSuggestFrame_RefreshDisplay(); + EncounterJournal_RefreshSlotFilterText(); +end + +function EJSuggestFrame_NextSuggestion() + if (C_AdventureJournal.GetPrimaryOffset() < C_AdventureJournal.GetNumAvailableSuggestions() - 1) then + C_AdventureJournal.SetPrimaryOffset(C_AdventureJournal.GetPrimaryOffset() + 1); + PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN); + end +end + +function EJSuggestFrame_PrevSuggestion() + if (C_AdventureJournal.GetPrimaryOffset() > 0) then + C_AdventureJournal.SetPrimaryOffset(C_AdventureJournal.GetPrimaryOffset() - 1); + PlaySound(SOUNDKIT.IG_ABILITY_PAGE_TURN); + end +end + +function EJSuggestFrame_OnMouseWheel(self, value) + if (value > 0) then + EJSuggestFrame_PrevSuggestion(); + else + EJSuggestFrame_NextSuggestion() + end +end + +function EJSuggestFrame_OpenFrame() + EJ_ContentTab_Select(EncounterJournal.instanceSelect.suggestTab.id); + NavBar_Reset(EncounterJournal.navBar); +end + +function EJPlayerGuide_OpenFrame() + EJ_ContentTab_Select(EncounterJournal.instanceSelect.guideTab.id); + NavBar_Reset(EncounterJournal.navBar); +end + +function EJSuggestFrame_UpdateRewards(suggestion) + local rewardData = C_AdventureJournal.GetReward(suggestion.index); + suggestion.reward.data = rewardData; + if (rewardData) then + if rewardData.isRewardList then + local numRewards = 0 + + for index = 1, #suggestion.rewardFrames do + local itemRewardData = rewardData[index] + if itemRewardData then + local texture = itemRewardData.itemIcon or "Interface\\Icons\\achievement_guildperk_mobilebanking"; + local rewardFrame = suggestion.rewardFrames[index] + -- rewardFrame.icon:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask"); + -- rewardFrame.icon:SetTexture(texture); + SetPortraitToTexture(rewardFrame.icon, texture) + rewardFrame.data = rewardData + rewardFrame:Show() + numRewards = numRewards + 1 + else + suggestion.rewardFrames[index].data = nil + suggestion.rewardFrames[index]:Hide() + end + end + + if suggestion.index == 1 then + if numRewards > 1 then + local offsetX = 0 + if numRewards == 2 then + offsetX = 4 + elseif numRewards > 2 then + offsetX = 4 + 11 * (numRewards - 2) + end + suggestion.reward:SetPoint("BOTTOM", + -((numRewards - 1) * suggestion.rewardFrames[2]:GetWidth() + offsetX) / 2, 53) + else + suggestion.reward:SetPoint("BOTTOM", 0, 53) + end + end + + return + end + + local texture = rewardData.itemIcon or rewardData.currencyIcon or + "Interface\\Icons\\achievement_guildperk_mobilebanking"; + if (rewardData.isRewardTable) then + texture = "Interface\\Icons\\achievement_guildperk_mobilebanking"; + end + -- suggestion.reward.icon:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask"); + -- suggestion.reward.icon:SetTexture(texture); + SetPortraitToTexture(suggestion.reward.icon, texture) + suggestion.reward:Show(); + + if suggestion.index == 1 then + suggestion.reward:SetPoint("BOTTOM", 0, 53) + end + + for index = 2, #suggestion.rewardFrames do + suggestion.rewardFrames[index].data = nil + suggestion.rewardFrames[index]:Hide() + end + end +end + +AdventureJournal_LeftTitleFonts = { + "DestinyFontHuge", -- 32pt font + "QuestFont_Enormous", -- 30pt font + "QuestFont_Super_Huge", -- 24pt font + "QuestFont22", -- 24pt font +}; + +local AdventureJournal_RightTitleFonts = { + "QuestFont_Huge", -- 18pt font + "Fancy16Font", -- 16pt font +}; + +local AdventureJournal_RightDescriptionFonts = { + "SystemFont_Med1", -- 12pt font + -- "SystemFont_Small", -- 10pt font +}; + +function EJSuggestFrame_RefreshDisplay() + local instanceSelect = EncounterJournal.instanceSelect; + local tab = EncounterJournal.instanceSelect.suggestTab; + local tierData = GetEJTierData(EJSuggestTab_GetPlayerTierIndex()); + tab.selectedGlow:SetVertexColor(tierData.r, tierData.g, tierData.b); + tab.selectedGlow:Show(); + instanceSelect.bg:SetAtlas(tierData.backgroundAtlas, true); + + local self = EncounterJournal.suggestFrame; + C_AdventureJournal.GetSuggestions(self.suggestions); + + -- hide all the display info + for i = 1, AJ_MAX_NUM_SUGGESTIONS do + local suggestion = self["Suggestion" .. i]; + suggestion.centerDisplay:Hide(); + if (i == 1) then + -- the left suggestion's button isn't on the centerDisplay frame + suggestion.button:Hide(); + else + suggestion.centerDisplay.button:Hide(); + end + -- suggestion.reward:Hide(); + suggestion.icon:Hide(); + suggestion.iconRing:Hide(); + + for index, rewardFrame in ipairs(suggestion.rewardFrames) do + rewardFrame:Hide() + end + end + + -- setup the primary suggestion display + if (#self.suggestions > 0) then + local suggestion = self.Suggestion1; + local data = self.suggestions[1]; + + local centerDisplay = suggestion.centerDisplay; + local titleText = centerDisplay.title.text; + local descText = centerDisplay.description.text; + + centerDisplay:SetHeight(suggestion:GetHeight()); + centerDisplay:Show(); + -- centerDisplay.title:SetHeight(0); + -- centerDisplay.description:SetHeight(0); + titleText:SetText(data.title); + descText:SetText(data.description); + + -- find largest font that will not go past 2 lines + --[[ + for i = 1, #AdventureJournal_LeftTitleFonts do + titleText:SetFontObject(AdventureJournal_LeftTitleFonts[i]); + local numLines = titleText:GetNumLines(); + if ( numLines <= 2 and not titleText:IsTruncated() ) then + break; + end + end + + -- resize the title to be 2 lines at most + local numLines = min(2, titleText:GetNumLines()); + local fontHeight = select(2, titleText:GetFont()); + centerDisplay.title:SetHeight(numLines * fontHeight + 2); + centerDisplay.description:SetHeight(descText:GetStringHeight()); + + -- adjust the center display to keep the text centered + local top = centerDisplay.title:GetTop(); + local bottom = centerDisplay.description:GetBottom(); + centerDisplay:SetHeight(top - bottom); +--]] + + centerDisplay.title:SetHeight(centerDisplay.title.text:GetHeight()) + centerDisplay.description:SetHeight(centerDisplay.description.text:GetHeight()) + + centerDisplay:SetHeight(math.min(180, + centerDisplay.title:GetHeight() + 10 + centerDisplay.description:GetHeight())) + + if (data.buttonText and #data.buttonText > 0) then + suggestion.button:SetText(data.buttonText); + + local btnWidth = max(suggestion.button:GetTextWidth() + 42, 150); + btnWidth = min(btnWidth, centerDisplay:GetWidth()); + suggestion.button:SetWidth(btnWidth); + suggestion.button:Show(); + end + + suggestion.icon:Show(); + suggestion.iconRing:Show(); + if (data.iconPath) then + -- suggestion.icon:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask"); + -- suggestion.icon:SetTexture(data.iconPath); + SetPortraitToTexture(suggestion.icon, data.iconPath) + else + -- suggestion.icon:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask"); + -- suggestion.icon:SetTexture(QUESTION_MARK_ICON); + SetPortraitToTexture(suggestion.icon, QUESTION_MARK_ICON) + end + + suggestion.prevButton:SetEnabled(C_AdventureJournal.GetPrimaryOffset() > 0); + suggestion.nextButton:SetEnabled(C_AdventureJournal.GetPrimaryOffset() < + C_AdventureJournal.GetNumAvailableSuggestions() - 1); + + if (titleText:IsTruncated()) then + centerDisplay.title:SetScript("OnEnter", EJSuggestFrame_SuggestionTextOnEnter); + centerDisplay.title:SetScript("OnLeave", GameTooltip_Hide); + else + centerDisplay.title:SetScript("OnEnter", nil); + centerDisplay.title:SetScript("OnLeave", nil); + end + + EJSuggestFrame_UpdateRewards(suggestion); + else + local suggestion = self.Suggestion1; + suggestion.prevButton:SetEnabled(false); + suggestion.nextButton:SetEnabled(false); + end + + -- setup secondary suggestions display + if (#self.suggestions > 1) then + local minTitleIndex = 1; + local minDescIndex = 1; + + for i = 2, #self.suggestions do + local suggestion = self["Suggestion" .. i]; + if (not suggestion) then + break; + end + + suggestion.centerDisplay:Show(); + + local data = self.suggestions[i]; + suggestion.centerDisplay.title.text:SetText(data.title); + suggestion.centerDisplay.description.text:SetText(data.description ~= "" and data.description or " "); + + -- find largest font that will not truncate the title + suggestion.centerDisplay.title.text:SetFontObject(AdventureJournal_RightTitleFonts[2]); + minTitleIndex = 2 + --[[ + for fontIndex = minTitleIndex, #AdventureJournal_RightTitleFonts do + suggestion.centerDisplay.title.text:SetFontObject(AdventureJournal_RightTitleFonts[fontIndex]); + minTitleIndex = fontIndex + if (not suggestion.centerDisplay.title.text:IsTruncated()) then + break; + end + end +--]] + + -- find largest font that will not go past 4 lines + suggestion.centerDisplay.description.text:SetFontObject(AdventureJournal_RightDescriptionFonts[1]); + minDescIndex = 1; + --[[ + for fontIndex = minDescIndex, #AdventureJournal_RightDescriptionFonts do + suggestion.centerDisplay.description.text:SetFontObject(AdventureJournal_RightDescriptionFonts[fontIndex]); + minDescIndex = fontIndex; + if ( suggestion.centerDisplay.description.text:GetNumLines() <= 4 and + not suggestion.centerDisplay.description.text:IsTruncated() ) then + break; + end + end +--]] + + if (data.buttonText and #data.buttonText > 0) then + suggestion.centerDisplay.button:SetText(data.buttonText); + + local btnWidth = max(suggestion.centerDisplay.button:GetTextWidth() + 42, 116); + btnWidth = min(btnWidth, suggestion.centerDisplay:GetWidth()); + suggestion.centerDisplay.button:SetWidth(btnWidth); + suggestion.centerDisplay.button:Show(); + end + + suggestion.icon:Show(); + suggestion.iconRing:Show(); + if (data.iconPath) then + -- suggestion.icon:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask"); + -- suggestion.icon:SetTexture(data.iconPath); + SetPortraitToTexture(suggestion.icon, data.iconPath) + else + -- suggestion.icon:SetMask("Interface\\CharacterFrame\\TempPortraitAlphaMask"); + -- suggestion.icon:SetTexture(QUESTION_MARK_ICON); + SetPortraitToTexture(suggestion.icon, QUESTION_MARK_ICON) + end + + EJSuggestFrame_UpdateRewards(suggestion); + end + -- set the fonts to be the same for both right side sections + -- adjust the center display to keep the text centered + for i = 2, #self.suggestions do + local suggestion = self["Suggestion" .. i]; + suggestion.centerDisplay:SetHeight(suggestion:GetHeight()); + + local title = suggestion.centerDisplay.title; + local description = suggestion.centerDisplay.description; + title.text:SetFontObject(AdventureJournal_RightTitleFonts[minTitleIndex]); + description.text:SetFontObject(AdventureJournal_RightDescriptionFonts[minDescIndex]); + local fontHeight = select(2, title.text:GetFont()); + title:SetHeight(fontHeight); + --[[ + local numLines = min(4, description.text:GetNumLines()); + fontHeight = select(2, description.text:GetFont()); + description:SetHeight(numLines * fontHeight); +--]] + local numLines = 4 + fontHeight = select(2, description.text:GetFont()); + description:SetHeight(numLines * fontHeight); + + -- adjust the center display to keep the text centered + local top = title:GetTop(); + local bottom = description:GetBottom(); + if (suggestion.centerDisplay.button:IsShown()) then + bottom = suggestion.centerDisplay.button:GetBottom(); + end + + if (title.text:IsTruncated()) then + title:SetScript("OnEnter", EJSuggestFrame_SuggestionTextOnEnter); + title:SetScript("OnLeave", GameTooltip_Hide); + else + title:SetScript("OnEnter", nil); + title:SetScript("OnLeave", nil); + end + --[[ + if ( description.text:IsTruncated() ) then + description:SetScript("OnEnter", EJSuggestFrame_SuggestionTextOnEnter); + description:SetScript("OnLeave", GameTooltip_Hide); + else + description:SetScript("OnEnter", nil); + description:SetScript("OnLeave", nil); + end +--]] + + suggestion.centerDisplay:SetHeight(top - bottom); + end + end + + -- fix SimpleHTML hyperlinks positions + for i = 1, AJ_MAX_NUM_SUGGESTIONS do + local suggestion = self["Suggestion" .. i]; + suggestion:Hide() + suggestion:Show() + end +end + +function EJSuggestFrame_SuggestionTextOnEnter(self) + GameTooltip:SetOwner(self, "ANCHOR_RIGHT"); + GameTooltip:SetText(self.text:GetText(), 1, 1, 1, 1, true); + GameTooltip:Show(); +end + +function EJSuggestFrame_RefreshRewards() + for i = 1, AJ_MAX_NUM_SUGGESTIONS do + local suggestion = EncounterJournal.suggestFrame["Suggestion" .. i]; + suggestion.reward:Hide(); + EJSuggestFrame_UpdateRewards(suggestion); + end +end + +function EJSuggestFrame_OnClick(self) + C_AdventureJournal.ActivateEntry(self.index); + PlaySound(SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON); +end + +function AdventureJournal_Reward_OnEnter(self) + local rewardData = self.data; + if (rewardData) then + if rewardData.isRewardList then + local reward = rewardData[self:GetID()] + if reward and reward.itemLink then + GameTooltip:SetOwner(self, "ANCHOR_RIGHT") + GameTooltip:SetHyperlink(reward.itemLink) + GameTooltip:Show() + end + self.isRewardList = true + return + else + self.isRewardList = nil + end + + local frame = EncounterJournalTooltip; + frame:SetPoint("BOTTOMLEFT", self, "TOPRIGHT", 0, 0); + frame.clickText:Hide(); + + local suggestion = EncounterJournal.suggestFrame.suggestions[self:GetParent().index]; + + local rewardHeaderText = ""; + if (rewardData.rewardDesc) then + rewardHeaderText = rewardData.rewardDesc; + elseif (rewardData.isRewardTable) then + if (not suggestion.hideDifficulty and suggestion.difficultyID and suggestion.difficultyID > 1) then + local difficultyStr = EJ_DIFFICULTIES[suggestion.difficultyID] and + EJ_DIFFICULTIES[suggestion.difficultyID].prefix or "" + if (rewardData.itemLevel) then + rewardHeaderText = format(AJ_LFG_REWARD_DIFFICULTY_TEXT, suggestion.title, difficultyStr, + rewardData.itemLevel); + elseif (rewardData.minItemLevel) then + rewardHeaderText = format(AJ_LFG_REWARD_DIFFICULTY_IRANGE_TEXT, suggestion.title, difficultyStr, + rewardData.minItemLevel, rewardData.maxItemLevel); + end + else + if (rewardData.itemLevel) then + rewardHeaderText = format(AJ_LFG_REWARD_DEFAULT_TEXT, suggestion.title, rewardData.itemLevel); + elseif (rewardData.minItemLevel) then + rewardHeaderText = format(AJ_LFG_REWARD_DEFAULT_IRANGE_TEXT, suggestion.title, + rewardData.minItemLevel, rewardData.maxItemLevel); + end + end + + if (rewardData.itemLink) then + rewardHeaderText = rewardHeaderText .. AJ_SAMPLE_REWARD_TEXT; + end + end + + if (rewardData.itemLink and rewardData.currencyType) then + local itemName, _, quality = C_Item.GetItemInfo(rewardData.itemLink); + frame.Item1.text:SetText(itemName); + frame.Item1.text:Show(); + frame.Item1.icon:SetTexture(rewardData.itemIcon); + frame.Item1.tooltip:Hide(); + frame.Item1:SetSize(256, 28); + frame.Item1:Show(); + + if (rewardData.itemQuantity and rewardData.itemQuantity > 1) then + frame.Item1.Count:SetText(rewardData.itemQuantity); + frame.Item1.Count:Show(); + else + frame.Item1.Count:Hide(); + end + + SetItemButtonQuality(frame.Item1, quality, rewardData.itemLink); + + if (quality > Enum.ItemQuality.Common and BAG_ITEM_QUALITY_COLORS[quality]) then + frame.Item1.text:SetTextColor(BAG_ITEM_QUALITY_COLORS[quality].r, BAG_ITEM_QUALITY_COLORS[quality].g, + BAG_ITEM_QUALITY_COLORS[quality].b); + end + + local currencyName, _, quality, _, _, _, _, _, _, currencyIcon = C_Item.GetItemInfo(rewardData.currencyType, + nil, nil, true) + frame.Item2.icon:SetTexture(currencyIcon); + frame.Item2.text:SetText(currencyName); + frame.Item2:Show(); + + SetItemButtonQuality(frame.Item2, quality); + if (quality > Enum.ItemQuality.Common and BAG_ITEM_QUALITY_COLORS[quality]) then + frame.Item2.text:SetTextColor(BAG_ITEM_QUALITY_COLORS[quality].r, BAG_ITEM_QUALITY_COLORS[quality].g, + BAG_ITEM_QUALITY_COLORS[quality].b); + end + + if (rewardData.currencyQuantity and rewardData.currencyQuantity > 1) then + frame.Item2.Count:SetText(rewardData.currencyQuantity); + frame.Item2.Count:Show(); + else + frame.Item2.Count:Hide(); + end + local height = 100; + + frame:SetWidth(256); + + if (rewardHeaderText and rewardHeaderText ~= "") then + frame.headerText:SetText(rewardHeaderText); + frame.Item1:SetPoint("TOPLEFT", frame.headerText, "BOTTOMLEFT", 0, -16); + height = height + frame.headerText:GetHeight(); + frame.headerText:Show(); + else + frame.headerText:Hide(); + frame.Item1:SetPoint("TOPLEFT", 11, -10); + end + + frame:SetHeight(height); + elseif (rewardData.itemLink or rewardData.currencyType) then + frame.Item2:Hide(); + frame.Item1:Show(); + frame.Item1.text:Hide(); + + local tooltip = frame.Item1.tooltip; + tooltip:SetOwner(frame.Item1, "ANCHOR_NONE"); + frame.Item1.UpdateTooltip = function() AdventureJournal_Reward_OnEnter(self) end; + if (rewardData.itemLink) then + tooltip:SetHyperlink(rewardData.itemLink); + GameTooltip_ShowCompareItem(tooltip, frame.Item1.tooltip); + + local quality = select(3, C_Item.GetItemInfo(rewardData.itemLink)); + SetItemButtonQuality(frame.Item1, quality, rewardData.itemLink); + + if (rewardData.itemQuantity and rewardData.itemQuantity > 1) then + frame.Item1.Count:SetText(rewardData.itemQuantity); + frame.Item1.Count:Show(); + else + frame.Item1.Count:Hide(); + end + + self:SetScript("OnUpdate", EncounterJournal_AJ_OnUpdate); + frame.Item1.icon:SetTexture(rewardData.itemIcon); + elseif (rewardData.currencyType) then + tooltip:SetHyperlink(strconcat("item:", rewardData.currencyType)); + + local _, _, quality = C_Item.GetItemInfo(rewardData.currencyType, nil, nil, true); + + SetItemButtonQuality(frame.Item1, quality); + + if (rewardData.currencyQuantity and rewardData.currencyQuantity > 1) then + frame.Item1.Count:SetText(rewardData.currencyQuantity); + frame.Item1.Count:Show(); + else + frame.Item1.Count:Hide(); + end + + frame.Item1.icon:SetTexture(rewardData.currencyIcon); + end + + frame:SetWidth(tooltip:GetWidth() + 54); + + if (rewardHeaderText and rewardHeaderText ~= "") then + frame.headerText:SetText(rewardHeaderText); + frame.headerText:Show(); + frame.Item1:SetPoint("TOPLEFT", frame.headerText, "BOTTOMLEFT", 0, -16); + else + frame.headerText:Hide(); + frame.Item1:SetPoint("TOPLEFT", 11, -10); + end + + tooltip:SetPoint("TOPLEFT", frame.Item1.icon, "TOPRIGHT", 0, 10); + tooltip:Show(); + + frame.Item1:SetSize(tooltip:GetWidth() + 44, tooltip:GetHeight()); + + local height = tooltip:GetHeight() + 6; + if (frame.headerText:IsShown()) then + height = height + frame.headerText:GetHeight() + 14; + end + if (rewardData.isRewardTable) then + frame.clickText:Show(); + self.iconRingHighlight:Show(); + height = height + 24; + end + + frame:SetHeight(height); + elseif (rewardHeaderText and rewardHeaderText ~= "") then + -- frame:SetWidth(256); + frame.Item1:Hide(); + frame.Item2:Hide(); + + frame.headerText:SetText(rewardHeaderText); + frame:SetWidth(frame.headerText:GetStringWidth() + 22); -- add padding for tooltip border + frame:SetHeight(frame.headerText:GetStringHeight() + 20); -- add padding for tooltip border + frame.headerText:Show(); + else + return; + end + frame:Show(); + end +end + +function EncounterJournal_AJ_OnUpdate(self) + local frame = EncounterJournalTooltip; + local tooltip = frame.Item1.tooltip; +end + +function AdventureJournal_Reward_OnLeave(self) + if self.isRewardList then + GameTooltip:Hide() + return + end + + EncounterJournalTooltip:Hide(); + self:SetScript("OnUpdate", nil); + ResetCursor(); + + self.iconRingHighlight:Hide(); +end + +function AdventureJournal_Reward_OnMouseDown(self) + local index = self:GetParent().index; + local data = EncounterJournal.suggestFrame.suggestions[index]; + if (data.ej_instanceID) then + EncounterJournal_DisplayInstance(data.ej_instanceID); + -- try to set difficulty to current instance difficulty + if (EJ_IsValidInstanceDifficulty(data.difficultyID)) then + EJ_SetDifficulty(data.difficultyID); + end + + -- select the loot tab + EncounterJournal.encounter.info[EJ_Tabs[2].button]:Click(); + elseif (data.isRandomDungeon) then + EJ_ContentTab_Select(EncounterJournal.instanceSelect.dungeonsTab.id); + EncounterJournal_TierDropDown_Select(nil, data.expansionLevel); + end +end + +function EncounterJournalBossButton_OnClick(self) + if IsModifiedClick("CHATLINK") and ChatEdit_GetActiveWindow() then + if self.link then + ChatEdit_InsertLink(self.link); + end + return; + end + local _, _, _, rootSectionID = EJ_GetEncounterInfo(self.encounterID); + if (rootSectionID == 0) then + EncounterJournal_SetTab(EncounterJournal.encounter.info.lootTab:GetID()); + end + EncounterJournal_DisplayEncounter(self.encounterID); + PlaySound("igAbiliityPageTurn"); +end + +function EncounterInstanceButtonTemplate_OnClick(self) + if not ChatEdit_TryInsertChatLink(self.link) then + local targetInstanceID = self.instanceID; + if EJ_GetCurrentInstance() ~= targetInstanceID then + if C_EncounterJournal.HasTierForcedMythicDifficulty(EJ_GetCurrentTier()) then + EJ_SetValidationDifficulty(3) + else + EJ_SetValidationDifficulty(1) + end + end + EncounterJournal_DisplayInstance(targetInstanceID); + PlaySound("igSpellBookOpen"); + end +end + +function EncounterInstanceButtonRequirements_OnLoad(self) + EncounterJournal_SetFlagIcon(self.Icon, 3) + self.awaitQuestCache = {} +end + +function EncounterInstanceButtonRequirements_OnEvent(self, event, ...) + if event == "QUEST_DATA_LOAD_RESULT" then + if self:IsVisible() and GameTooltip:GetOwner() == self then + local success, questID = ... + if self.awaitQuestCache[questID] then + self.awaitQuestCache[questID] = true + + if success then + if self:IsMouseOverEx() then + EncounterInstanceButtonRequirements_OnEnter(self) + end + end + end + end + end +end + +function EncounterInstanceButtonRequirements_OnEnter(self) + if self:GetParent():IsMouseOverEx() then + self:GetParent():LockHighlight() + end + + GameTooltip:SetOwner(self, "ANCHOR_RIGHT") + GameTooltip_AddNormalLine(GameTooltip, EJ_INSTANCE_REQUIREMENT_LABLE, true) + + local parent = self:GetParent() + if self.isRaid and (parent.mapID ~= 1 and parent.mapID ~= 10009) then + GameTooltip_AddHighlightLine(GameTooltip, EJ_INSTANCE_REQUIREMENT_RAID_GROUP, true) + else + GameTooltip_AddHighlightLine(GameTooltip, EJ_INSTANCE_REQUIREMENT_NONE, true) + end + + if self.requirements then + for index, requirement in ipairs(self.requirements) do + GameTooltip_AddBlankLineToTooltip(GameTooltip) + + local difficultyPrefix, difficultySize, difficultyMask = EJ_GetDifficultyInfo(requirement.difficultyID, + requirement.isRaid) + local difficultyStr + if difficultyPrefix then + difficultyStr = string.format("(%s) %s", difficultySize, difficultyPrefix) + else + difficultyStr = requirement.difficultyID + end + + GameTooltip_AddNormalLine(GameTooltip, + string.format(EJ_INSTANCE_REQUIREMENT_DIFFICULTY, HIGHLIGHT_FONT_COLOR:WrapTextInColorCode(difficultyStr)), + true) + + if requirement.minLevel and requirement.maxLevel then + local completed = WithinRange(UnitLevel("player"), requirement.minLevel or 1, + requirement.maxLevel or MAX_PLAYER_LEVEL) + local color = completed and GREEN_FONT_COLOR or HIGHLIGHT_FONT_COLOR + if requirement.minLevel == requirement.maxLevel then + GameTooltip_AddNormalLine(GameTooltip, + string.format(EJ_INSTANCE_REQUIREMENT_LEVEL, color:WrapTextInColorCode(requirement.maxLevel)), + true) + else + GameTooltip_AddNormalLine(GameTooltip, + string.format(EJ_INSTANCE_REQUIREMENT_LEVEL_RANGE, + color:WrapTextInColorCode(requirement.minLevel), + color:WrapTextInColorCode(requirement.maxLevel)), true) + end + end + + if requirement.itemLevel then + local avgItemLevelEquipped = GetAverageItemLevel() + local completed = avgItemLevelEquipped >= requirement.itemLevel + local color = completed and GREEN_FONT_COLOR or HIGHLIGHT_FONT_COLOR + GameTooltip_AddNormalLine(GameTooltip, + string.format(EJ_INSTANCE_REQUIREMENT_ITEM_LEVEL, color:WrapTextInColorCode(requirement.itemLevel)), + true) + end + + if requirement.quests then + self:RegisterCustomEvent("QUEST_DATA_LOAD_RESULT") + + GameTooltip_AddNormalLine(GameTooltip, EJ_INSTANCE_REQUIREMENT_QUESTS, true) + for questIndex, questID in ipairs(requirement.quests) do + local completed = IsQuestCompleted(questID) + local name = GetTitleForQuestID(questID) + if not name and not self.awaitQuestCache[questID] then + self.awaitQuestCache[questID] = true + RequestQuestCacheByID(questID) + end + if IsGMAccount() then + name = string.format("%s [%d]", name or UNKNOWN, questID) + end + local color = completed and GREEN_FONT_COLOR or HIGHLIGHT_FONT_COLOR + GameTooltip_AddColoredLine(GameTooltip, name, color, true) + end + end + + if requirement.achievements then + GameTooltip_AddNormalLine(GameTooltip, EJ_INSTANCE_REQUIREMENT_ACHIEVEMENTS, true) + for achievementIndex, achievementID in ipairs(requirement.achievements) do + local id, name, points, completed, month, day, year, description, flags, icon = GetAchievementInfo( + achievementID) + if IsGMAccount() then + name = string.format("%s [%d]", name, achievementID) + end + local color = completed and GREEN_FONT_COLOR or HIGHLIGHT_FONT_COLOR + GameTooltip_AddColoredLine(GameTooltip, name, color, true) + end + end + end + end + + GameTooltip:Show() +end + +function EncounterInstanceButtonRequirements_OnLeave(self) + self:GetParent():UnlockHighlight() + GameTooltip:Hide() + self:UnregisterCustomEvent("QUEST_DATA_LOAD_RESULT") +end + +function EncounterTabTemplate_OnClick(self, button) + EncounterJournal_TabClicked(self, button); + if (not EncounterJournal.encounterID and EncounterJournal.instanceID) then + EncounterJournal_DisplayInstance(EncounterJournal.instanceID, true); + end +end + +function EncounterItemTemplate_OnClick(self) + if (not HandleModifiedItemClick(self.link)) then + EncounterJournal_Loot_OnClick(self); + else + PlaySound("igMainMenuOption"); + end +end + +function EncounterItemTemplate_OnEnter(self) + GameTooltip:SetOwner(self, "ANCHOR_LEFT"); + EncounterJournal_SetTooltip(self.link); + self.showingTooltip = true; + self:SetScript("OnUpdate", EncounterJournal_Loot_OnUpdate); +end + +function EncounterItemTemplate_OnLeave(self) + GameTooltip:Hide(); + self.showingTooltip = false; + self:SetScript("OnUpdate", nil); + ResetCursor(); +end + +local factionData = { + [PLAYER_FACTION_GROUP.Horde] = -3, + [PLAYER_FACTION_GROUP.Alliance] = -2, + [PLAYER_FACTION_GROUP.Renegade] = -4, + [PLAYER_FACTION_GROUP.Neutral] = -1, +} + +function LootJournal_CanOpenItemByEntry(itemID, checkFaction) + local _itemID, encounterID, name, icon, equipSlot, itemSubType, link, itemType, difficultyID, factionID = + EJ_GetLootInfo(itemID) + local canOpened = false + + if encounterID then + canOpened = true + end + + if checkFaction then + local playerFactionID = C_Unit.GetFactionID("player") + local convertedFactionID = factionData[playerFactionID] + + if factionID ~= convertedFactionID and factionID ~= -1 then + canOpened = false + end + end + + return canOpened +end + +function LootJournal_OpenItemByEntry(itemID) + if not itemID then + return + end + + local _itemID, encounterID, name, icon, equipSlot, itemSubType, link, itemType, difficultyID, factionID = + EJ_GetLootInfo(itemID) + if encounterID then + local _, _, _, _, _, instanceID = EJ_GetEncounterInfo(encounterID) + if instanceID then + EncounterJournal_OpenJournal(difficultyID, instanceID, encounterID, nil, nil, itemID) + end + end +end diff --git a/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/Custom_EncounterJournal/Custom_EncounterJournal.xml b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/Custom_EncounterJournal/Custom_EncounterJournal.xml new file mode 100644 index 0000000..5bfc537 --- /dev/null +++ b/src/Data/ruRU/patch-ruRU-5/Interface/AddOns/MoonWellClient/EncounterJournal/Custom_EncounterJournal/Custom_EncounterJournal.xml @@ -0,0 +1,3380 @@ + +