HarvestRoute = {} HarvestRoute.name = "HarvestRoute" HarvestRoute.displayName = 'HarvestRoute for Harvestmap' HarvestRoute.version = "1.0.2" HarvestRoute.author = "generic" HarvestRoute.settingsVersion = 1 HarvestRoute.defaultSettings = { trackerRange = 5 } local LibAddonMenu2 = LibAddonMenu2 local Farm = Harvest.farm local Editor = Farm.editor local Path = Harvest.path local MapCache = nil local Helper = Farm.helper local HarvestRouteButton = nil local isActive = false local currentZoneId = nil local lastNodeId = nil local pathNodeId = nil local pathNodes = {} local function initialize( eventCode, addOnName ) if ( addOnName ~= HarvestRoute.name ) then return end local padding = 30 local control = WINDOW_MANAGER:CreateControl(nil, HarvestFarmGenerator, CT_LABEL) control:SetFont("ZoFontGame") control:SetText(HarvestRoute.GetLocalization( "tourtrackerdescription" )) control:SetAnchor(TOPLEFT, Harvest.farm.generator.generatorBar , BOTTOMLEFT, 0, 10) control:SetWidth(HarvestFarmGenerator:GetWidth() - padding) local lastControl = control local control = WINDOW_MANAGER:CreateControlFromVirtual('HarvestRouteButton', HarvestFarmGenerator, "ZO_DefaultButton") control:SetText(HarvestRoute.GetLocalization( "buttonstarttracker" )) control:SetAnchor(TOPLEFT, lastControl, BOTTOMLEFT, 0, 20) control:SetWidth(HarvestFarmGenerator:GetWidth() - padding) control:SetClickSound("Click") control:SetHandler("OnClicked", HarvestRoute.OnButton ) HarvestRouteButton = control HarvestRoute.savedVars = ZO_SavedVars:NewAccountWide("HarvestRoute", HarvestRoute.settingsVersion, nil, HarvestRoute.defaultSettings) HarvestRoute.InitializeSettingsMenu() EVENT_MANAGER:RegisterForEvent("HarvestRoutePlayerActivated", EVENT_PLAYER_ACTIVATED, HarvestRoute.OnPlayerLoaded ) end function HarvestRoute:InitializeSettingsMenu() local panel = { type = "panel", name = HarvestRoute.name, displayName = HarvestRoute.displayName, author = HarvestRoute.author, version = HarvestRoute.version, registerForRefresh = true, registerForDefaults = true, } local options = { { type = "description", text = HarvestRoute.GetLocalization("addonsettingstext"), }, { type = "slider", name = HarvestRoute.GetLocalization("routerangemultiplier"), tooltip = HarvestRoute.GetLocalization("routerangemultipliertooltip"), min = 3, max = 20, getFunc = function () return HarvestRoute.savedVars.trackerRange end, setFunc = function (value) HarvestRoute.savedVars.trackerRange = value end, default = HarvestRoute.defaultSettings.trackerRange, } } LibAddonMenu2:RegisterAddonPanel(HarvestRoute.name.."OptionsMenu", panel) LibAddonMenu2:RegisterOptionControls(HarvestRoute.name.."OptionsMenu", options) end function HarvestRoute:OnButton() if isActive then EVENT_MANAGER:UnregisterForUpdate("HarvestRouteUpdatePosition") HarvestRouteButton:SetText(HarvestRoute.GetLocalization( "buttonstarttracker" )) isActive = false else EVENT_MANAGER:RegisterForUpdate("HarvestRouteUpdatePosition", 50, HarvestRoute.OnUpdate) HarvestRouteButton:SetText(HarvestRoute.GetLocalization( "buttonstoptracker" )) local mapMetaData = Harvest.mapTools:GetViewedMapMetaData() MapCache = Harvest.Data:GetMapCache( mapMetaData ) isActive = true currentZoneId = GetUnitZoneIndex("player") end end function HarvestRoute:OnPlayerLoaded() local newZoneId = GetUnitZoneIndex("player") if currentZoneId and currentZoneId == newZoneId then return end lastNodeId = nil pathNodeId = nil pathNodes = {} currentZoneId = newZoneId if isActive then HarvestRoute:OnButton() end end function HarvestRoute:OnUpdate (time) if isActive then local nodeId = HarvestRoute:GetClosestNode() if nodeId and nodeId ~= lastNodeId then lastNodeId = nodeId local x, y = MapCache:GetLocal(nodeId) if Farm.path then local index = Farm.path:GetIndex(nodeId) if index then pathNodeId = nodeId else if pathNodeId then Farm.path:InsertAfter(pathNodeId, nodeId) pathNodeId = nodeId Harvest.farm.display:Refresh(Farm.path, Harvest.farm.display.selectedPins, Harvest.farm.display.selectedMapCache) --Harvest.callbackManager:FireCallbacks(Harvest.events.TOUR_CHANGED, Farm.path) -- if we are farming, update the next pin so we can actually finish the loop if we want to if Farm.helper:IsRunning() then index = Farm.path:GetIndex(pathNodeId) Farm.helper.nextPathIndex = index Farm.helper:UpdateToNextTarget() end end end else --create a new path pathNodes[#pathNodes + 1] = nodeId if #pathNodes > 2 then path = Harvest.path:New(Harvest.mapPins.mapCache) path:GenerateFromNodeIds(pathNodes, 1, #pathNodes) Farm:SetPath(path) pathNodeId = nodeId pathNodes = {} end end end end end -- get the closest node to the player, using HarvestMap MapCache Divisions (and only check 4 divisions, from -50 to +50 from current position) function HarvestRoute:GetClosestNode() local bestNodeId = nil if not MapCache then --yeah, no cache no cookies. return end local x, y, z = Harvest.GetPlayer3DPosition() local halfDivisionInMeters = zo_floor(MapCache.DivisionWidthInMeters / 2) --should be 50 most of the time, but lets keep it dynamic local numDivisions = MapCache.numDivisions local totalNumDivisions = MapCache.TotalNumDivisions local half_before_x = x - halfDivisionInMeters local half_before_y = y - halfDivisionInMeters local index = (zo_floor(half_before_x / MapCache.DivisionWidthInMeters) + zo_floor(half_before_y / MapCache.DivisionWidthInMeters) * numDivisions) % MapCache.TotalNumDivisions local bestDistance = halfDivisionInMeters * halfDivisionInMeters local divisions = MapCache.divisions -- check all pintypes, and the 4 divisions that contain the 100 x 100 square around the player if divisions then for _, pinTypeId in pairs(Harvest.PINTYPES) do local pinDivision = MapCache.divisions[pinTypeId] if pinDivision then for i = index, index + 1 do for j = 0, 1 do division = pinDivision[(i + j * numDivisions) % totalNumDivisions] or {} if division then -- check all node in current division, if there are closer nodes to the player for _, nodeId in pairs(division) do if MapCache.worldX then dx = MapCache.worldX[nodeId] - x dy = MapCache.worldY[nodeId] - y distance = dx * dx + dy * dy if distance < bestDistance then bestNodeId = nodeId bestDistance = distance end end end end end -- for j end -- for i end -- if pinDivision end --for pinType if bestNodeId then local realDistance = bestDistance ^ 0.5 if realDistance < self.savedVars.trackerRange then return bestNodeId end end end return nil end EVENT_MANAGER:RegisterForEvent("HarvestRoute", EVENT_ADD_ON_LOADED, initialize)