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
--]]