You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1247 lines
40 KiB

local _, addon = ...
local API = addon.API;
local TomTomUtil = addon.TomTomUtil; --Send location to TomTom
local HIDE_INACTIVE_PIN = false;
local DATA_PROVIDER_ADDED = false;
local ENABLE_MAP_PIN = false;
local PIN_ICON_PRIORITIZE_REWARD = false; --If the plant is active and has unclaimed reward, show Seed or Flower icon
local VIGID_BOUNTY = 5971;
local MAPID_EMRALD_DREAM = 2200;
local PIN_SIZE_DORMANT = 12;
local PIN_SIZE_ACTIVE = 18;
local PIN_TINY_BAR_HEIGHT = 2;
local PIN_TEMPLATE_NAME = "PlumberWorldMapPinTemplate";
local PIN_DORMANT_TEXTURE = "Interface/AddOns/Plumber/Art/MapPin/SeedPlanting-Empty-Distant"; --optional postfix: -HC, High Contrast
local FORMAT_TIME_LEFT = BONUS_OBJECTIVE_TIME_LEFT or "Time Left: %s";
local DB_KEY_MASTER_SWITCH = "WorldMapPinSeedPlanting"; --This is the key that enable/disable our entire Map Pin Module. Since we only have one type of pins for now, we use the same key
local DB_KEY_DREAMSEED = "WorldMapPinSeedPlanting"; --Control Dreamseed Pins (Show spawned soils, unclaimed chests, timer below active one)
local MapFrame = WorldMapFrame;
local MapScrollContainer = WorldMapFrame.ScrollContainer;
local QuestDetailsFrame = QuestMapFrame and QuestMapFrame.DetailsFrame or nil; --Hide our pins when viewing quest details
local TooltipFrame = GameTooltip;
local PinController = CreateFrame("Frame");
local WorldMapDataProvider = CreateFromMixins(MapCanvasDataProviderMixin);
--As a solution to the potential taint caused by MapDataProvider
--We use this child frame of WorldMapFrame to check its mapID every 1/60 seconds
local MapTracker = CreateFrame("Frame");
MapTracker:Hide();
local C_VignetteInfo = C_VignetteInfo;
local GetVignetteInfo = C_VignetteInfo.GetVignetteInfo;
local GetVignettePosition = C_VignetteInfo.GetVignettePosition;
local IsWorldQuest = C_QuestLog.IsWorldQuest;
local After = C_Timer.After;
local InCombatLockdown = InCombatLockdown;
local format = string.format;
local pairs = pairs;
local ipairs = ipairs;
local _G = _G;
local SecondsToTime = API.SecondsToTime;
local DreamseedUtil = API.DreamseedUtil; --Defined in Dreamseed.lua
local GetCreatureIDFromGUID = API.GetCreatureIDFromGUID;
local GetVignetteIDFromGUID = API.GetVignetteIDFromGUID; --this is a string method, not using C_VignetteInfo
PinController.pins = {};
PinController.isRelavantVignetteGUID = {};
PinController.chestOwnerCreatureID = nil; --Construct when required
local function Debug_SaveCreatureLocation(objectGUID, x, y)
if not PlumberDevOutput then
PlumberDevOutput = {};
end
if not PlumberDevOutput.CreatureLocations then
PlumberDevOutput.CreatureLocations = {};
end
local creatureID = API.GetCreatureIDFromGUID(objectGUID);
if not PlumberDevOutput.CreatureLocations[creatureID] then
local total = 0;
for k, v in pairs(PlumberDevOutput.CreatureLocations) do
total = total + 1;
end
print(string.format("#%d NEW POSITION ADDED", total + 1));
PlumberDevOutput.CreatureLocations[creatureID] = {x, y};
end
end
local function IsViewingQuestDetails()
return QuestDetailsFrame and QuestDetailsFrame:IsVisible();
end
function PinController:AddPin(pin)
table.insert(self.pins, pin);
end
function PinController:UpdatePins()
self.pinDirty = false;
for _, pin in pairs(self.pins) do
if not pin.cachedCreatureID then
--Do not update cached (not-spawned) pins
pin:UpdateState();
end
end
end
function PinController:AddTinyBar(tinybar)
if not self.tinybars then
self.tinybars = {};
end
table.insert(self.tinybars, tinybar);
end
function PinController:UpdateTinyBarSize()
self.tinybarDirty = false;
if self.tinybars then
for i, tinybar in ipairs(self.tinybars) do
if tinybar:IsShown() then
tinybar:Init();
end
end
end
end
function PinController:UpdatePinSize()
local tempIndex;
for _, pin in ipairs(self.pins) do
tempIndex = pin.visualIndex;
pin.visualIndex = nil;
pin:SetVisual(tempIndex);
end
end
function PinController:UpdateTinyBarHeight()
self.tinybarDirty = false;
if self.tinybars then
for i, tinybar in ipairs(self.tinybars) do
tinybar:SetWidth(PIN_SIZE_ACTIVE);
tinybar:SetBarHeight(PIN_TINY_BAR_HEIGHT);
end
end
end
function PinController:RequestUpdatePins()
self.pinDirty = true;
self:SetScript("OnUpdate", self.OnUpdate);
end
function PinController:RequestUpdateTinyBarSize()
self.tinybarDirty = true;
self:SetScript("OnUpdate", self.OnUpdate);
end
function PinController:RequestUpdateAllData()
self.vignetteDirty = true;
self:SetScript("OnUpdate", self.OnUpdate);
end
function PinController:OnUpdate(elapsed)
self:SetScript("OnUpdate", nil);
if self.tinybarDirty then
self:UpdateTinyBarSize();
end
if self.vignetteDirty then
self.vignetteDirty = false;
self.pinDirty = false;
WorldMapDataProvider:RefreshAllData();
end
if self.pinDirty then
self:UpdatePins(); --60 KB
end
end
function PinController:ListenEvents(state)
if state then
self:RegisterEvent("UPDATE_UI_WIDGET");
self:RegisterEvent("VIGNETTES_UPDATED");
self.mapOpened = true;
--self:RegisterEvent("VIGNETTE_MINIMAP_UPDATED");
else
self:UnregisterEvent("UPDATE_UI_WIDGET");
self:UnregisterEvent("VIGNETTES_UPDATED");
self.mapOpened = false;
--self:UnregisterEvent("VIGNETTE_MINIMAP_UPDATED");
end
end
function PinController:OnEvent(event, ...)
if event == "UPDATE_UI_WIDGET" then
local widgetInfo = ...
if (not self.pinDirty) and DreamseedUtil:IsValuableWidget(widgetInfo.widgetID) then
self:RequestUpdatePins();
end
elseif event == "VIGNETTES_UPDATED" then
self:RequestUpdateAllData();
elseif event == "VIGNETTE_MINIMAP_UPDATED" then
local vignetteGUID, onMinimap = ...
if not onMinimap then
local vignetteID = GetVignetteIDFromGUID(vignetteGUID);
if self.chestOwnerCreatureID[vignetteID] then
--if the removed minimap icon is a Dreamseed Chest
After(0.5, function()
local owner = self.chestOwnerCreatureID[vignetteID];
if not GetVignetteInfo(vignetteGUID) then
DreamseedUtil:SetChestStateByCreatureID(owner, false);
end
end)
end
end
if self.mapOpened and self.isRelavantVignetteGUID[vignetteGUID] then
self:RequestUpdateAllData();
end
end
end
function PinController:ResetAllCreatureSpawnStates()
if not self.creatureIDXPin then
self.creatureIDXPin = DreamseedUtil:GetPlantCreatureIDs();
end
for creatureID in pairs(self.creatureIDXPin) do
self.creatureIDXPin[creatureID] = false;
end
end
function PinController:SetCreatureSpawnState(creatureID, hasSpawned)
self.creatureIDXPin[creatureID] = hasSpawned;
end
function PinController:ProcessNotSpawnedCreatures(mapFrame)
--Show pin that is not spawned but has an unlooted chest
local pin;
for creatureID, state in pairs(self.creatureIDXPin) do
if not state then
if DreamseedUtil:HasAnyRewardByCreatureID(creatureID) then
local chestInfo = DreamseedUtil:TryGetChestInfoByCreatureID(creatureID);
local objectGUID, x, y;
if chestInfo then
objectGUID, x, y = chestInfo[1], chestInfo[2], chestInfo[3];
else
local position = DreamseedUtil:GetBackupLocation(creatureID);
if position then
x, y = position[1], position[2];
end
end
if x and y then
pin = mapFrame:AcquirePin(PIN_TEMPLATE_NAME, nil, objectGUID);
pin.cachedCreatureID = creatureID;
pin:SetPosition(x, y);
pin:SetVisual(0);
if pin.TinyBar then
pin.TinyBar:Hide();
end
end
end
end
end
end
function PinController:EnableModule(state)
if state then
if not self.chestOwnerCreatureID then
self.chestOwnerCreatureID = DreamseedUtil:GetChestOwnerCreatureIDs();
end
self:ResetAllCreatureSpawnStates();
self:RegisterEvent("VIGNETTE_MINIMAP_UPDATED"); --This event will be registered all the time while in Emerald Dream, we need it to track if the player loots a Dreamseed Chest
self:SetScript("OnEvent", self.OnEvent);
--DreamseedUtil:Debug_ConstructWidgetID();
else
self:UnregisterEvent("VIGNETTE_MINIMAP_UPDATED");
self:ListenEvents(false);
self:SetScript("OnEvent", nil);
end
end
local function RemoveDefaultVignettePins()
local pool = MapFrame.pinPools["VignettePinTemplate"];
if pool then
for pin in pool:EnumerateActive() do
if pin:GetVignetteID() == VIGID_BOUNTY then
--This will make the RAM usage of Blizzard VignetteDataProvider count towards our addon
--But it doesn't really increase the overall RAM usage
--Users might wonder why this addon uses 500 KB RAM per second when the WorldMapFrame is open in Emerald Dream
pin.vignetteGUID = 0;
end
end
end
end
local function Dummy_SetPassThroughButtons()
end
PlumberWorldMapPinMixin = CreateFromMixins(MapCanvasPinMixin);
function PlumberWorldMapPinMixin:OnCreated()
--When frame being created
self.originalSetPassThroughButtons = self.SetPassThroughButtons;
self.SetPassThroughButtons = Dummy_SetPassThroughButtons;
self:AllowPassThroughRightButton(true);
end
function PlumberWorldMapPinMixin:OnLoad()
--newPin (see MapCanvasMixin:AcquirePin)
self:SetScalingLimits(1, 1.0, 1.2);
self.pinFrameLevelType = "PIN_FRAME_LEVEL_GROUP_MEMBER"; --PIN_FRAME_LEVEL_VIGNETTE PIN_FRAME_LEVEL_AREA_POI PIN_FRAME_LEVEL_WAYPOINT_LOCATION PIN_FRAME_LEVEL_GROUP_MEMBER
self.pinFrameLevelIndex = 1;
self:SetTexture("Interface/AddOns/Plumber/Art/MapPin/SeedPlanting-Empty-Distant");
PinController:AddPin(self);
end
function PlumberWorldMapPinMixin:IsMouseClickEnabled()
return true
end
function PlumberWorldMapPinMixin:AllowPassThroughRightButton(unpackedPrimitiveType)
--Original "SetPassThroughButtons" (see SimpleScriptRegionAPI for details) has chance to taint when called
--So we overwrite it
if (not self.isRightButtonAllowed) and (not InCombatLockdown()) then
self.isRightButtonAllowed = true;
if self.originalSetPassThroughButtons then
self.originalSetPassThroughButtons(self, "RightButton");
end
end
end
function PlumberWorldMapPinMixin:SetTexture(texture)
self.Texture:SetTexture(texture, nil, nil, "LINEAR");
self.HighlightTexture:SetTexture(texture, nil, nil, "LINEAR");
self.HighlightTexture:SetVertexColor(0.4, 0.4, 0.4);
end
function PlumberWorldMapPinMixin:OnMouseLeave()
--BaseMapPoiPinMixin.OnMouseLeave(self);
TooltipFrame:Hide();
end
local function MapPin_UpdateTooltip(self)
if self.objectGUID then
local remainingTime, fullTime = DreamseedUtil:GetGrowthTimes(self.objectGUID);
if remainingTime and remainingTime > 0 then
if remainingTime ~= self.remainingTime then
self.remainingTime = remainingTime;
local timeText = format(FORMAT_TIME_LEFT, SecondsToTime(remainingTime, true));
if TooltipFrame.TextLeft2 and TooltipFrame.TextLeft2:GetText() then
TooltipFrame.TextLeft2:SetText(timeText);
else
TooltipFrame:AddLine(timeText, 1, 0.82, 0, false);
end
local progressText = DreamseedUtil:GetNurtureProgress(self.objectGUID, true);
if GameTooltipTextLeft3 and GameTooltipTextLeft3:GetText() then
GameTooltipTextLeft3:SetText(progressText);
else
TooltipFrame:AddLine(progressText, 1, 1, 1, false);
end
TooltipFrame:Show();
end
end
end
end
function PlumberWorldMapPinMixin:OnMouseEnter()
local name, hasReward, isFromCache;
if self.objectGUID then
name = DreamseedUtil:GetPlantNameAndProgress(self.objectGUID);
hasReward = DreamseedUtil:HasAnyReward(self.objectGUID);
elseif self.cachedCreatureID then
--This is when the pin doesn't spawn but has a possible loot
name = DreamseedUtil:GetPlantNameByCreatureID(self.cachedCreatureID);
hasReward = true;
isFromCache = true;
end
self.name = name;
if name then
TooltipFrame:Hide();
TooltipFrame:SetOwner(self, "ANCHOR_RIGHT");
TooltipFrame:AddLine(name, 1, 1, 1, true);
TooltipFrame:Show();
else
return
end
if self.isActive then
self.remainingTime = nil;
MapPin_UpdateTooltip(self);
end
local resourceText = DreamseedUtil:GetResourcesText();
if resourceText then
TooltipFrame:AddLine(resourceText, 1, 1, 1, false);
end
if hasReward then
TooltipFrame:AddLine(WEEKLY_REWARDS_UNCLAIMED_TITLE, 0.098, 1.000, 0.098, false); --GREEN_FONT_COLOR
end
if TomTomUtil:IsTomTomAvailable() then
TooltipFrame:AddLine(addon.L["Click To Track In TomTom"], 1, 0.82, 0, true);
self:SetClickable(true);
else
if (hasReward or self.isActive) and addon.ControlCenter:ShouldShowNavigatorOnDreamseedPins() then
TooltipFrame:AddLine(addon.L["Click To Track Location"], 1, 0.82, 0, true);
self:SetClickable(true);
else
self:SetClickable(false);
end
end
TooltipFrame:Show();
self:AllowPassThroughRightButton(true);
end
function PlumberWorldMapPinMixin:OnMouseClickAction(mouseButton)
if mouseButton == "LeftButton" then
if TomTomUtil:IsTomTomAvailable() then
local x, y = self:GetPosition();
local desc = self.name;
TomTomUtil:AddWaypoint(MAPID_EMRALD_DREAM, x, y, desc);
else
if addon.ControlCenter:ShouldShowNavigatorOnDreamseedPins() then
addon.ControlCenter:EnableSuperTracking();
self:OnMouseEnter();
end
end
end
end
function PlumberWorldMapPinMixin:SetClickable(state)
if state ~= self.isClickable then
self.isClickable = state;
end
self:SetMouseClickEnabled(state);
end
function PlumberWorldMapPinMixin:OnAcquired(vignetteGUID, objectGUID)
self.vignetteGUID = vignetteGUID;
self.Texture:SetTexCoord(0.21875, 0.78125, 0.21875, 0.78125);
self.HighlightTexture:SetTexCoord(0.21875, 0.78125, 0.21875, 0.78125);
self.remainingTime = nil;
self.objectGUID = objectGUID;
self.isActive = nil;
self.hasReawrd = nil;
self.cachedCreatureID = nil;
end
function PlumberWorldMapPinMixin:UpdateReward(creatureID)
local hasReawrd, hasLocation = DreamseedUtil:HasAnyRewardByCreatureID(creatureID);
if hasReawrd then
self.hasReawrd = true;
if not hasLocation then
local x, y = self:GetPosition();
DreamseedUtil:SetChestStateByCreatureID(creatureID, true, self.objectGUID, x, y);
end
end
end
function PlumberWorldMapPinMixin:UpdateState()
if not self.objectGUID then
self:Hide();
return
end
local creatureID = GetCreatureIDFromGUID(self.objectGUID);
local remainingTime, fullTime = DreamseedUtil:GetGrowthTimesByCreatureID(creatureID);
local isActive = remainingTime and remainingTime > 0;
PinController:SetCreatureSpawnState(creatureID, true);
if isActive then
if not self.isActive then
self.isActive = true;
self:SetVisual(3);
self.UpdateTooltip = MapPin_UpdateTooltip;
if not self.TinyBar then
self.TinyBar = addon.CreateTinyStatusBar(self);
self.TinyBar:SetPoint("TOP", self, "BOTTOM", 0, -2);
self.TinyBar:SetWidth(PIN_SIZE_ACTIVE);
self.TinyBar:SetBarHeight(PIN_TINY_BAR_HEIGHT);
PinController:AddTinyBar(self.TinyBar);
end
self.TinyBar:Show();
self.TinyBar:SetReverse(true);
self.TinyBar:Init();
self:UpdateReward(creatureID);
end
self.TinyBar:SetTimes(fullTime - remainingTime, fullTime);
else
if self.isActive or self.isActive == nil then
self.isActive = false;
self:SetVisual(1);
self.UpdateTooltip = nil;
if self.TinyBar then
self.TinyBar:Hide();
end
end
self:UpdateReward(creatureID);
if self.hasReawrd then
self:SetVisual(0);
elseif HIDE_INACTIVE_PIN then
self:Hide();
end
end
end
function PlumberWorldMapPinMixin:SetVisual(index)
if index ~= self.visualIndex then
self.visualIndex = index;
else
return
end
if index == 1 or index == 0 then
--EmptySoil, far away
self:SetSize(PIN_SIZE_DORMANT, PIN_SIZE_DORMANT);
self.Texture:SetSize(PIN_SIZE_ACTIVE, PIN_SIZE_ACTIVE); --We changed the icon size in the file
if index == 1 then
self:SetTexture(PIN_DORMANT_TEXTURE);
elseif index == 0 then
self:SetTexture("Interface/AddOns/Plumber/Art/MapPin/SeedPlanting-Bud"); --Unlooted
end
else
self:SetSize(PIN_SIZE_ACTIVE, PIN_SIZE_ACTIVE);
self.Texture:SetSize(PIN_SIZE_ACTIVE, PIN_SIZE_ACTIVE);
if index == 2 then
--EmptySoil, nearby
self:SetTexture("Interface/AddOns/Plumber/Art/MapPin/SeedPlanting-Empty-Nearby");
elseif index == 3 then
--Small
self:SetTexture("Interface/AddOns/Plumber/Art/MapPin/SeedPlanting-Full"); --Green
elseif index == 4 then
--Plump
self:SetTexture("Interface/AddOns/Plumber/Art/MapPin/SeedPlanting-Full"); --Blue
elseif index == 5 then
--Gigantic
self:SetTexture("Interface/AddOns/Plumber/Art/MapPin/SeedPlanting-Full"); --Purple
end
end
end
function WorldMapDataProvider:GetPinTemplate()
return PIN_TEMPLATE_NAME
end
function WorldMapDataProvider:OnShow()
end
function WorldMapDataProvider:OnHide()
PinController:ListenEvents(false);
end
function WorldMapDataProvider:OnEvent(event, ...)
--This significantly increase RAM usage count
--So we monitor Events using another frame (PinController)
end
function WorldMapDataProvider:RemoveAllIfNeeded()
if self.anyPins then
self:RemoveAllData();
end
end
function WorldMapDataProvider:RemoveAllData()
self.anyPins = false;
PinController:ResetAllCreatureSpawnStates();
MapFrame:RemoveAllPinsByTemplate(self:GetPinTemplate());
end
function WorldMapDataProvider:RefreshAllData(fromOnShow)
self:RemoveAllIfNeeded();
self:ShowAllPins();
end
function WorldMapDataProvider:RefreshAllDataIfPossible()
if DATA_PROVIDER_ADDED then
self:RemoveAllIfNeeded();
if not IsViewingQuestDetails() then
self:ShowAllPins();
end
end
end
function WorldMapDataProvider:ShowAllPins()
if not ENABLE_MAP_PIN then return end;
local uiMapID = MapTracker:GetMapID() --self:GetMap():GetMapID();
if uiMapID ~= MAPID_EMRALD_DREAM then
PinController:ListenEvents(false);
return
end
local vignetteGUIDs = C_VignetteInfo.GetVignettes();
local pin;
local info, vignettePosition, vignetteFacing;
local mapFrame = MapFrame;
local relavantVignetteGUIDs = {};
local total = 0;
local pins = {};
PinController.isRelavantVignetteGUID = {};
for i, vignetteGUID in ipairs(vignetteGUIDs) do
info = GetVignetteInfo(vignetteGUID);
if info and info.vignetteID == VIGID_BOUNTY then
vignettePosition, vignetteFacing = GetVignettePosition(info.vignetteGUID, uiMapID);
if vignettePosition then
pin = mapFrame:AcquirePin(PIN_TEMPLATE_NAME, vignetteGUID, info.objectGUID);
pin:SetPosition(vignettePosition:GetXY());
pin:UpdateState();
total = total + 1;
relavantVignetteGUIDs[total] = vignetteGUID;
PinController.isRelavantVignetteGUID[vignetteGUID] = true;
pins[total] = pin;
--Debug_SaveCreatureLocation(info.objectGUID, vignettePosition:GetXY());
end
end
end
PinController:ProcessNotSpawnedCreatures(mapFrame);
local bestUniqueVignetteIndex = C_VignetteInfo.FindBestUniqueVignette(relavantVignetteGUIDs) or 0;
for i, pin in ipairs(pins) do
if pin.isActive then
if PIN_ICON_PRIORITIZE_REWARD and pin.hasReawrd then
pin:SetVisual(0);
else
pin:SetVisual(3);
end
elseif pin.hasReawrd then
pin:SetVisual(0);
elseif i == bestUniqueVignetteIndex then
pin:SetVisual(2);
else
pin:SetVisual(1);
end
end
PinController:ListenEvents(true);
self.anyPins = true;
RemoveDefaultVignettePins();
end
function WorldMapDataProvider:OnCanvasScaleChanged()
--Fires multiple times when opening WorldMapFrame
PinController:RequestUpdateTinyBarSize();
end
if not addon.IsGame_10_2_0 then
return
end
local function OnPingQuestID(f, questID)
--TODO? Hide pins when checking quest detail?
if not ENABLE_MAP_PIN then return end;
if questID and IsWorldQuest(questID) then
else
local uiMapID = MapFrame:GetMapID();
if uiMapID == MAPID_EMRALD_DREAM then
--Temporarily mutes our pin when viewing quest details
WorldMapDataProvider:RemoveAllIfNeeded();
PinController:ListenEvents(false);
end
end
end
local function HookQuestDetailBackButton()
if QuestMapFrame_ReturnFromQuestDetails then
local function OnReturnFromQuestDetails()
if not ENABLE_MAP_PIN then return end;
WorldMapDataProvider:RefreshAllDataIfPossible();
end
hooksecurefunc("QuestMapFrame_ReturnFromQuestDetails", OnReturnFromQuestDetails);
end
end
local FilterFrame = CreateFrame("Frame", nil, UIParent);
FilterFrame:Hide();
FilterFrame:SetFrameStrata("TOOLTIP");
FilterFrame:SetFixedFrameStrata(true);
FilterFrame:SetIgnoreParentScale(true);
function MapTracker:Attach()
if not self.attached then
self.attached = true;
self:SetParent(MapFrame);
self:EnableScripts();
self:Show();
end
end
function MapTracker:Detach()
if self.attached then
self.attached = nil;
self.mapID = nil;
self:SetParent(nil);
self:DisableScripts();
self:Hide();
WorldMapDataProvider:RemoveAllIfNeeded();
WorldMapDataProvider:OnHide();
end
end
function MapTracker:OnUpdate(elapsed)
self.t1 = self.t1 + elapsed;
self.t2 = self.t2 + elapsed;
if self.t1 > 0.016 then
self.t1 = 0;
self.newMapID = MapFrame.mapID;
if self.newMapID ~= self.mapID then
self.mapID = self.newMapID;
self:OnMapChanged();
end
self.newScale = MapScrollContainer.targetScale;
if self.newScale ~= self.mapScale then
self.mapScale = self.newScale;
self:OnCanvasScaleChanged();
end
end
if self.t2 > 0.1 then
self.t2 = 0;
self.detailsVisiblity = IsViewingQuestDetails();
if self.detailsVisiblity ~= self.isViewingDetails then
self.isViewingDetails = self.detailsVisiblity;
self:OnViewingQuestDetailsChanged();
end
end
end
function MapTracker:OnShow()
self.mapID = nil;
self.mapScale = nil;
self.isViewingDetails = IsViewingQuestDetails();
self.t1 = 1;
--self:OnUpdate(1);
end
function MapTracker:OnHide()
WorldMapDataProvider:OnHide();
end
function MapTracker:EnableScripts()
self.t1 = 0;
self.t2 = 0;
self:SetScript("OnShow", self.OnShow);
self:SetScript("OnHide", self.OnHide);
self:SetScript("OnUpdate", self.OnUpdate);
end
function MapTracker:DisableScripts()
self:SetScript("OnShow", nil);
self:SetScript("OnHide", nil);
self:SetScript("OnUpdate", nil);
end
function MapTracker:GetMapID()
return self.mapID
end
function MapTracker:OnMapChanged()
WorldMapDataProvider:RefreshAllDataIfPossible();
end
function MapTracker:OnCanvasScaleChanged()
WorldMapDataProvider:OnCanvasScaleChanged();
--PinController:UpdateTinyBarSize();
end
function MapTracker:OnViewingQuestDetailsChanged()
if self.isViewingDetails then
else
if ENABLE_MAP_PIN then
WorldMapDataProvider:RefreshAllDataIfPossible();
end
end
end
local function LoadOptionalSettings()
--Settings that are controlled by command, no UI (due to specific user request)
--Requires /reload
if not PlumberDB then return end;
PIN_ICON_PRIORITIZE_REWARD = (PlumberDB.PinIconPrioritizeReward and true) or false;
end
local ZoneTriggerModule;
local function EnableModule(state)
if state then
ENABLE_MAP_PIN = true;
if not ZoneTriggerModule then
local module = API.CreateZoneTriggeredModule("mappin");
ZoneTriggerModule = module;
module:SetValidZones(MAPID_EMRALD_DREAM);
local function OnEnterZoneCallback()
if not DATA_PROVIDER_ADDED then
--We register our module when the player is in Emerald Dream
DATA_PROVIDER_ADDED = true;
--MapFrame:AddDataProvider(WorldMapDataProvider); --Potential taint!
MapFrame:RegisterCallback("PingQuestID", OnPingQuestID, PinController);
--HookQuestDetailBackButton();
end
MapTracker:Attach();
PinController:EnableModule(true);
DreamseedUtil:RequestScanChests();
end
local function OnLeaveZoneCallback()
MapTracker:Detach();
PinController:EnableModule(false);
DreamseedUtil:PauseScanner();
end
module:SetEnterZoneCallback(OnEnterZoneCallback);
module:SetLeaveZoneCallback(OnLeaveZoneCallback);
LoadOptionalSettings();
end
ZoneTriggerModule:SetEnabled(true);
ZoneTriggerModule:Update();
else
if ENABLE_MAP_PIN then
if DATA_PROVIDER_ADDED then
WorldMapDataProvider:RemoveAllData();
end
PinController:ListenEvents(false);
PinController:SetScript("OnUpdate", nil);
end
if ZoneTriggerModule then
ZoneTriggerModule:SetEnabled(false);
end
ENABLE_MAP_PIN = false;
end
end
local function GetMapPinSizeSetting()
local id = PlumberDB and PlumberDB.MapPinSize;
if not id then
id = 1;
end
return id
end
local function SetPinSizeByID(id, update)
if (not id) or (id ~= 1 and id ~= 2) then return end;
if id == 1 then
PIN_SIZE_DORMANT = 12;
PIN_SIZE_ACTIVE = 18;
PIN_TINY_BAR_HEIGHT = 2;
PIN_DORMANT_TEXTURE = "Interface/AddOns/Plumber/Art/MapPin/SeedPlanting-Empty-Distant";
elseif id == 2 then
PIN_SIZE_DORMANT = 18;
PIN_SIZE_ACTIVE = 22;
PIN_TINY_BAR_HEIGHT = 4;
PIN_DORMANT_TEXTURE = "Interface/AddOns/Plumber/Art/MapPin/SeedPlanting-Empty-Distant-HC";
end
if update then
PinController:UpdatePinSize();
PinController:UpdateTinyBarHeight();
end
if PlumberDB then
PlumberDB.MapPinSize = id;
end
end
local LABEL_EMERALD_BOUNTY;
local DropDownButtonMixin = {}; --Shared Template
function DropDownButtonMixin:OnClick()
end
function DropDownButtonMixin:Setup()
--Show checkmark, button text, icon, etc.
end
function DropDownButtonMixin:SetTitle(text)
--Title / Dummy button does nothing when clicked
self.CheckedTexture:Hide();
self.Text:SetText(text);
self.Icon:SetTexture(nil);
self.clickable = false;
self.dbKey = nil;
self.Text:ClearAllPoints();
self.Text:SetPoint("LEFT", self, "LEFT", 5, 0);
self.Text:SetFontObject("GameFontNormalSmallLeft");
end
function DropDownButtonMixin:SetClickable()
self.clickable = true;
self.Reference:SetPoint("LEFT", 0, 0);
self.Text:ClearAllPoints();
self.Text:SetPoint("LEFT", self.Reference, "LEFT", 20, 0);
self.Text:SetFontObject("GameFontHighlightSmallLeft");
end
function DropDownButtonMixin:OnEnter()
if self.clickable then
self.Highlight:Show();
else
--Header or Divider
end
end
function DropDownButtonMixin:OnLeave()
self.Highlight:Hide();
end
function DropDownButtonMixin:OnMouseDown()
if self.clickable then
self.Reference:SetPoint("LEFT", 1, -1);
end
end
function DropDownButtonMixin:OnMouseUp()
self.Reference:SetPoint("LEFT", 0, 0);
end
local DropDownButtonMixin_Dreamseed = {};
function DropDownButtonMixin_Dreamseed:OnClick()
if not self.dbKey then return end;
local newState = not PlumberDB[self.dbKey];
PlumberDB[self.dbKey] = newState;
EnableModule(newState);
if newState and MapFrame:IsShown() and not IsViewingQuestDetails() then
WorldMapDataProvider:RefreshAllDataIfPossible();
end
DropDownButtonMixin_Dreamseed.Setup(self);
end
function DropDownButtonMixin_Dreamseed:Setup()
local dbKey = DB_KEY_DREAMSEED;
local state = PlumberDB[dbKey];
if state then
self.CheckedTexture:Show();
else
self.CheckedTexture:Hide();
end
if self.dbKey ~= dbKey then
self.dbKey = dbKey;
if not LABEL_EMERALD_BOUNTY then
LABEL_EMERALD_BOUNTY = API.GetCreatureName(211123);
end
self.Text:SetText(LABEL_EMERALD_BOUNTY or "Emerald Bounty");
self.Icon:SetTexture("Interface/AddOns/Plumber/Art/MapPin/DopdownIcon/Dreamseed");
self.Icon:Show();
end
end
local MAP_FILTER_OPTIONS = {
[MAPID_EMRALD_DREAM] = {DropDownButtonMixin_Dreamseed},
};
function FilterFrame:HookWorldFilterFrameButton()
--Find WorldMapTrackingOptionsButtonMixin (Map Filter)
if self.hasHooked then return end;
self.hasHooked = true; --Assert it true no matter we find the button or not
if not MapFrame.overlayFrames then return end;
local objType;
for i, obj in ipairs(MapFrame.overlayFrames) do
objType = obj:GetObjectType();
if objType == "Button" then
if obj.IsTrackingFilter ~= nil and obj.DropDown ~= nil then
obj:HookScript("OnMouseDown", function(_, button)
self:BlizzardMapFilter_OnMouseDown();
end);
end
end
end
end
function FilterFrame:AcquireOptionButton(i)
local button = self.buttons[i];
if not button then
button = CreateFrame("Button", nil, self);
self.buttons[i] = button;
button:SetSize(100, 16);
if i ~= 1 then
button:SetPoint("TOPLEFT", self.buttons[i - 1], "BOTTOMLEFT", 0, 0);
end
button.Reference = button:CreateTexture(nil, "BACKGROUND");
button.Reference:SetSize(16, 16);
button.Reference:SetPoint("LEFT", button, "LEFT", 0, 0);
button.Text = button:CreateFontString(nil, "OVERLAY", "GameFontNormalSmallLeft");
button.Text:SetJustifyH("LEFT");
button.Text:SetPoint("LEFT", button.Reference, "LEFT", 20, 0);
button.CheckedTexture = button:CreateTexture(nil, "OVERLAY");
button.CheckedTexture:SetTexture("Interface/AddOns/Plumber/Art/Button/Checkbox");
button.CheckedTexture:SetTexCoord(0.5, 0.75, 0.5, 0.75);
button.CheckedTexture:SetSize(16, 16);
button.CheckedTexture:SetPoint("LEFT", button, "LEFT", 0, 0);
button.Icon = button:CreateTexture(nil, "OVERLAY");
button.Icon:SetSize(16, 16);
button.Icon:SetPoint("RIGHT", button, "RIGHT", 0, 0);
button.Highlight = button:CreateTexture(nil, "BACKGROUND");
button.Highlight:Hide();
button.Highlight:SetAllPoints(true);
button.Highlight:SetTexture("Interface/QuestFrame/UI-QuestTitleHighlight");
button.Highlight:SetBlendMode("ADD");
button:SetScript("OnEnter", DropDownButtonMixin.OnEnter);
button:SetScript("OnLeave", DropDownButtonMixin.OnLeave);
button:SetScript("OnMouseDown", DropDownButtonMixin.OnMouseDown);
button:SetScript("OnMouseUp", DropDownButtonMixin.OnMouseUp);
end
button:Show();
return button
end
function FilterFrame:CreateOptionList(dropdownWidth)
local buttonWidth = (dropdownWidth or 120) - 22;
if not self.buttons then
self.buttons = {};
end
local numButtons = #self.buttonList;
local numDummies = 2; --add a Divider and a Title
numButtons = numButtons + numDummies;
local button, buttonMixin, dataIndex;
for i = 1, numButtons do
button = self:AcquireOptionButton(i);
if i <= numDummies then
if i == 1 then
DropDownButtonMixin.SetTitle(button, nil);
elseif i == 2 then
--[[
if not self.mapName then
local info = C_Map.GetMapInfo(self.uiMapID);
self.mapName = info and info.name or nil;
end
--]]
DropDownButtonMixin.SetTitle(button, "Plumber");
end
button:SetScript("OnClick", nil);
else
buttonMixin = self.buttonList[i - numDummies];
DropDownButtonMixin.SetClickable(button);
buttonMixin.Setup(button);
button:SetScript("OnClick", buttonMixin.OnClick);
end
button:SetWidth(buttonWidth);
end
return self.buttons[1], numButtons
end
function FilterFrame:CloseUI()
if self.buttons then
for i, button in ipairs(self.buttons) do
if i == 1 then
button:ClearAllPoints();
end
button:Hide();
end
end
self:SetScript("OnUpdate", nil);
self:SetScript("OnEvent", nil);
self:Hide();
self:UnregisterEvent("GLOBAL_MOUSE_DOWN");
self.targetDropdown = nil;
end
function FilterFrame:ShowUI()
self:RegisterEvent("GLOBAL_MOUSE_DOWN");
self.t = 0;
self:SetScript("OnUpdate", self.OnUpdate_CheckVisibility);
self:SetScript("OnEvent", self.OnEvent);
self:Show();
end
function FilterFrame:OnEvent(event, ...)
if not (self.targetDropdown and self.targetDropdown:IsMouseOver()) then
self:CloseUI();
end
end
function FilterFrame:OnUpdate_CheckVisibility(elapsed)
if not (self.targetDropdown and self.targetDropdown:IsShown()) then
self:CloseUI();
end
end
function FilterFrame:OnUpdate_UpdateAfter(elapsed)
--We update on the next n frame
self.n = self.n + 1;
if self.n < 2 then return end;
self:SetScript("OnUpdate", nil);
if self.targetDropdown and self.targetDropdown:IsShown() then
self:SetupDropDown(self.targetDropdown);
end
end
function FilterFrame:RequestUpdateDropdown(targetDropdown, uiMapID)
self.n = 0;
self.targetDropdown = targetDropdown;
if uiMapID ~= self.uiMapID then
self.uiMapID = uiMapID;
self.mapName = nil;
end
self.buttonList = MAP_FILTER_OPTIONS[uiMapID];
self:Show();
self:SetScript("OnUpdate", self.OnUpdate_UpdateAfter);
end
function FilterFrame:GetBestDropDownHeight(dropdown)
local backgroundFrame = _G["DropDownList1MenuBackdrop"];
local height1 = dropdown:GetHeight();
local height2;
local diffHeight = 0;
if backgroundFrame then
height2 = backgroundFrame:GetHeight();
if height2 - height1 > 1 then
diffHeight = height2 - height1;
end
end
return math.max(height1, height2), diffHeight
end
function FilterFrame:SetupDropDown(dropdown)
local scale = dropdown:GetEffectiveScale();
local top = dropdown:GetTop();
local left = dropdown:GetLeft();
local width = dropdown:GetWidth();
local height, diffHeight = self:GetBestDropDownHeight(dropdown);
local firstButton, numButtons = self:CreateOptionList(width);
local extraHeight = (UIDROPDOWNMENU_BUTTON_HEIGHT or 16) * numButtons - diffHeight;
local xPos = 11;
self:SetScale(scale);
firstButton:ClearAllPoints();
firstButton:SetPoint("TOPLEFT", UIParent, "BOTTOMLEFT", left + xPos, top - height + (UIDROPDOWNMENU_BORDER_HEIGHT or 15));
dropdown:SetHeight(height + extraHeight);
self:ShowUI();
if not self.SizeSelectFrame then
local SizeSelectFrame = addon.CreateSimpleSizeSelect(self);
self.SizeSelectFrame = SizeSelectFrame;
SizeSelectFrame:ClearAllPoints();
SizeSelectFrame:SetPoint("TOPRIGHT", firstButton, "BOTTOMRIGHT", 0, 0); --firstButton is a blank line
SizeSelectFrame:SetNumChoices(2);
SizeSelectFrame:SelectSize( GetMapPinSizeSetting() );
SizeSelectFrame:SetOnSizeChangedCallback(SetPinSizeByID);
SizeSelectFrame:Show();
end
end
function FilterFrame:BlizzardMapFilter_OnMouseDown()
local uiMapID = MapFrame:GetMapID();
if not (uiMapID and MAP_FILTER_OPTIONS[uiMapID]) then return end;
local dropdown = _G["DropDownList1"];
if dropdown and dropdown:IsShown() then
self:RequestUpdateDropdown(dropdown, uiMapID);
else
self:CloseUI();
end
end
FilterFrame:SetScript("OnHide", function(self)
self:CloseUI();
end);
do
--Map Filter is independent from Map Pin Settings
FilterFrame:RegisterEvent("PLAYER_ENTERING_WORLD");
FilterFrame:SetScript("OnEvent", function(self, event)
self:UnregisterEvent(event);
self:SetScript("OnEvent", nil);
self:HookWorldFilterFrameButton();
LABEL_EMERALD_BOUNTY = API.GetCreatureName(211123);
SetPinSizeByID( GetMapPinSizeSetting() );
end);
end
do
local moduleData = {
name = addon.L["ModuleName WorldMapPinSeedPlanting"],
dbKey = DB_KEY_MASTER_SWITCH, --WorldMapPinSeedPlanting
description = addon.L["ModuleDescription WorldMapPinSeedPlanting"],
toggleFunc = EnableModule,
categoryID = 10020000,
uiOrder = 2,
};
addon.ControlCenter:AddModule(moduleData);
end
--[[
The map pin for Ringing Rose overlays with zone text "Lushdream Crags", players may find it annoying
Superbloom
Bloom: /dump C_UIWidgetManager.GetStatusBarWidgetVisualizationInfo(4969)
Scenario Progess: /dump C_UIWidgetManager.GetScenarioHeaderTimerWidgetVisualizationInfo(4997) --4990, 4947
Next Superbloom: /dump C_UIWidgetManager.GetTextWithStateWidgetVisualizationInfo(5328)
C_UIWidgetManager.GetScenarioHeaderTimerWidgetVisualizationInfo
--]]