--Automatically add Dreamseed locations to Super Track --Waypoints Priority: 1.Growing (haven't contributed) 2.Chest Available 3.Growing (contributed) local _, addon = ... local API = addon.API; local WIDGET_UPDATE_INTERVAL = 2; local WAYPOINT_MIN_DISTANCE = 10; --Don't add waypoint if it's closeby local WAYPOINT_PRIOTIRY_DISTANCE = 180; --Prioritize location that is within x yd away from player --253 yd is where Dreamseed Chest shown on WorldMap local VIGID_BOUNTY = 5971; local MAPID_EMRALD_DREAM = 2200; local DreamseedUtil = API.DreamseedUtil; --Defined in Dreamseed.lua local GetCreatureIDFromGUID = API.GetCreatureIDFromGUID; local GetPlayerMapCoord = API.GetPlayerMapCoord; local SuperTrackFrame; local C_VignetteInfo = C_VignetteInfo; local ClearUserWaypoint = C_Map.ClearUserWaypoint; local tinsert = table.insert; local tsort = table.sort; local EL; local MODULE_ENABLED = false; local DREAMSEED_FLAGS = {}; --key: creatureID local CHEST_VIGNETTE_X_CREATURE = {}; local NAME_DREAMSEED_CHEST = nil; --Localized later by API local FOCUSED_CREATURE; --Plant shown on the Arrow local PRIORITIZE_CHEST = false; --if false, don't add new waypoints so player can go back and collect rewards --Flags --0: not spawned or not growing --1: growing, contributed --2: finished growing, has rewards (chest) --3: growing, haven't contributed local FLAG_ICON = { [0] = "Dreamseed-Active", [1] = "Dreamseed-Active-Visited", [2] = "Dreamseed-Chest", [3] = "Dreamseed-Active-New", }; local function SetDreamseedFlag(creatureID, flag) if DREAMSEED_FLAGS[creatureID] then if DREAMSEED_FLAGS[creatureID] ~= flag then DREAMSEED_FLAGS[creatureID] = flag; return true end end end local function GetPlantPosition(creatureID) local pos = DreamseedUtil:GetBackupLocation(creatureID); return pos[1], pos[2] end function DreamseedUtil:SetNavigatorPrioritizingReward(state) PRIORITIZE_CHEST = state; end function DreamseedUtil:IsNavigatorPrioritizingReward() return PRIORITIZE_CHEST end local function SortFunc_Generic(loc1, loc2) --locationData: creatureID, x, y, flag, remainingTime, distance --Prioritize nearyby spawned chest if loc1[4] == 2 and loc1[6] < WAYPOINT_PRIOTIRY_DISTANCE then return true elseif loc2[4] == 2 and loc2[6] < WAYPOINT_PRIOTIRY_DISTANCE then return false end --If there are two uncontributed plants, prioritize the one whose time is running out if loc1[4] == 3 and loc2[4] == 3 then if loc1[5] + 60 < loc2[5] then return true elseif loc2[5] + 60 < loc1[5] then return false end end if loc1[4] ~= loc2[4] then return loc1[4] > loc2[4] elseif loc1[6] ~= loc2[6] then return loc1[6] < loc2[6] end return false end local function SortFunc_RewardFirst(loc1, loc2) --Prioritize nearyby spawned chest if loc1[4] == 2 then if loc2[4] == 2 then return loc1[6] < loc2[6] else return true end elseif loc2[4] == 2 then return false end if loc1[4] == 1 then if loc2[4] == 1 then --prioritize time return loc1[5] < loc2[5] else return true end elseif loc2[4] == 1 then return false end if loc1[6] ~= loc2[6] then return loc1[6] < loc2[6] end return false end local function UpdateWaypoints() if not (SuperTrackFrame and SuperTrackFrame:CanReceiveDataFromNavigator()) then return end; local playerX, playerY = GetPlayerMapCoord(MAPID_EMRALD_DREAM); if not (playerX and playerY) then return end; local vignetteGUIDs = C_VignetteInfo.GetVignettes(); local info; local uiMapID = MAPID_EMRALD_DREAM; local creatureID; local x, y; local remainingTime, fullTime; local isActive; local hasReward, distance; local flag; local locations; local processedCreatures = {}; for i, vignetteGUID in ipairs(vignetteGUIDs) do info = C_VignetteInfo.GetVignetteInfo(vignetteGUID); if info then if info.vignetteID == VIGID_BOUNTY then --Soil creatureID = GetCreatureIDFromGUID(info.objectGUID); elseif CHEST_VIGNETTE_X_CREATURE[info.vignetteID] then --Dreamseed Chest if not NAME_DREAMSEED_CHEST then NAME_DREAMSEED_CHEST = info.name or "Dreamseed Chest"; NAME_DREAMSEED_CHEST = "|cff19ff19"..(NAME_DREAMSEED_CHEST or "Dreamseed Chest").."|r"; end flag = 2; creatureID = CHEST_VIGNETTE_X_CREATURE[info.vignetteID]; if not processedCreatures[creatureID] then processedCreatures[creatureID] = true; SetDreamseedFlag(creatureID, flag); local vignettePosition, vignetteFacing = C_VignetteInfo.GetVignettePosition(info.vignetteGUID, uiMapID); x, y = vignettePosition:GetXY(); distance = DreamseedUtil:GetPlayerDistanceToTarget(playerX, playerY, x, y); if distance >= WAYPOINT_MIN_DISTANCE then if not locations then locations = {}; end tinsert(locations, {creatureID, x, y, flag, 0, distance}); end DreamseedUtil:SetPlantContributedByCreatureID(creatureID, true); end end end end for creatureID in pairs(DREAMSEED_FLAGS) do if not processedCreatures[creatureID] then processedCreatures[creatureID] = true; remainingTime, fullTime = DreamseedUtil:GetGrowthTimesByCreatureID(creatureID); isActive = remainingTime and remainingTime > 0; if DreamseedUtil:HasAnyRewardByCreatureID(creatureID) then if isActive then flag = 1; else flag = 2; end else if isActive then if remainingTime > 5 then --We hide the uncontributed plant that is about to despawn flag = 3; else flag = 0; end else flag = 0; end end SetDreamseedFlag(creatureID, flag) hasReward = flag == 1 or flag == 2; if isActive then x, y = GetPlantPosition(creatureID); distance = DreamseedUtil:GetPlayerDistanceToTarget(playerX, playerY, x, y); if distance >= WAYPOINT_MIN_DISTANCE then if not locations then locations = {}; end tinsert(locations, {creatureID, x, y, flag, remainingTime, distance}); end elseif hasReward then if not locations then locations = {}; end x, y = GetPlantPosition(creatureID); distance = DreamseedUtil:GetPlayerDistanceToTarget(playerX, playerY, x, y); if distance >= WAYPOINT_MIN_DISTANCE then if not locations then locations = {}; end tinsert(locations, {creatureID, x, y, flag, 0, distance}); end end end end if locations then if PRIORITIZE_CHEST then tsort(locations, SortFunc_RewardFirst); else tsort(locations, SortFunc_Generic); end end local bestCreatureID = locations and locations[1] and locations[1][1]; if bestCreatureID ~= FOCUSED_CREATURE or true then FOCUSED_CREATURE = bestCreatureID; if bestCreatureID then local data = locations[1]; flag = data[4]; creatureID = data[1]; local plantName; if flag == 2 then plantName = NAME_DREAMSEED_CHEST; else plantName = DreamseedUtil:GetPlantNameByCreatureID(data[1]); if flag == 3 then --haven't contributed --plantName = plantName.."|TInterface/AddOns/Plumber/Art/MapPin/RedDot:8:8:4:4|t"; elseif flag == 1 then --has reward but still growing plantName = "|cffcccccc"..plantName.."|r"; end end if flag == 0 then ClearUserWaypoint(); return end local hasTimer = flag == 3 or flag == 1; SuperTrackFrame:SetTimerTarget(plantName, uiMapID, data[2], data[3], FLAG_ICON[flag], hasTimer, data[5]); else ClearUserWaypoint(); end end end local function EL_UpdateNow_OnUpdate(self, elapsed) self.t = self.t + elapsed; if self.t > WIDGET_UPDATE_INTERVAL then self.t = 0; self:SetScript("OnUpdate", nil); if MODULE_ENABLED then self:RegisterEvent("VIGNETTES_UPDATED"); self:RegisterEvent("UPDATE_UI_WIDGET"); end end end local function EL_UpdateAfter_OnUpdate(self, elapsed) self.t = self.t + elapsed; if self.t > 1 then self.t = 0; self:SetScript("OnUpdate", nil); if MODULE_ENABLED then UpdateWaypoints(); self:RegisterEvent("VIGNETTES_UPDATED"); self:RegisterEvent("UPDATE_UI_WIDGET"); end end end local function EL_OnEvent(self, event) if event == "VIGNETTES_UPDATED" then self.t = 0; self:SetScript("OnUpdate", EL_UpdateAfter_OnUpdate); self:UnregisterEvent(event); elseif event == "UPDATE_UI_WIDGET" then self.t = 0; UpdateWaypoints(); self:SetScript("OnUpdate", EL_UpdateNow_OnUpdate); self:UnregisterEvent(event); end end local function EnableEventListener(state) if EL then MODULE_ENABLED = state; if state then for creatureID in pairs(DREAMSEED_FLAGS) do DREAMSEED_FLAGS[creatureID] = 0; end EL:RegisterEvent("UPDATE_UI_WIDGET"); EL:RegisterEvent("VIGNETTES_UPDATED"); if not SuperTrackFrame then SuperTrackFrame = addon.GetSuperTrackFrame(); end SuperTrackFrame:TryEnableByModule(); else EL:UnregisterEvent("UPDATE_UI_WIDGET"); EL:UnregisterEvent("VIGNETTES_UPDATED"); EL:SetScript("OnUpdate", nil); EL.t = 0; FOCUSED_CREATURE = nil; if SuperTrackFrame then SuperTrackFrame:EnableSuperTracking(false); end end end end local ZoneTriggerModule; local function EnableModule(state) if state then if not EL then EL = CreateFrame("Frame"); EL:SetScript("OnEvent", EL_OnEvent); DREAMSEED_FLAGS = DreamseedUtil:GetPlantCreatureIDs(); CHEST_VIGNETTE_X_CREATURE = DreamseedUtil:GetChestOwnerCreatureIDs(); end if not ZoneTriggerModule then local module = API.CreateZoneTriggeredModule("navigator-dreamseed"); ZoneTriggerModule = module; module:SetValidZones(MAPID_EMRALD_DREAM); local function OnEnterZoneCallback() EnableEventListener(true); end local function OnLeaveZoneCallback() EnableEventListener(false); end module:SetEnterZoneCallback(OnEnterZoneCallback); module:SetLeaveZoneCallback(OnLeaveZoneCallback); end ZoneTriggerModule:SetEnabled(true); ZoneTriggerModule:Update(); else if ZoneTriggerModule then ZoneTriggerModule:SetEnabled(false); end EnableEventListener(false); end end do local moduleData = { name = addon.L["ModuleName Navigator_Dreamseed"], dbKey = "Navigator_Dreamseed", --WorldMapPinSeedPlanting description = addon.L["ModuleDescription Navigator_Dreamseed"], toggleFunc = EnableModule, moduleAddedTime = 1702258000, categoryID = 10020000, uiOrder = 4, }; addon.ControlCenter:AddModule(moduleData); end